func (sp *StripePayment) handle(w http.ResponseWriter, r *http.Request, session *lobster.Session, frameParams lobster.FrameParams) { if !lobster.AntifloodCheck(lobster.ExtractIP(r.RemoteAddr), "payment_stripe_handle", 5) { lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.FormattedError("try_again_later")) return } lobster.AntifloodAction(lobster.ExtractIP(r.RemoteAddr), "payment_stripe_handle") stripeToken := r.PostFormValue("stripeToken") amount, amountErr := strconv.Atoi(r.PostFormValue("amount")) currency := r.PostFormValue("currency") if stripeToken == "" || amount <= 0 || amountErr != nil || currency == "" { lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.FormatError(fmt.Errorf("credit card payment failed due to form submission error"))) return } // duplicate amount range check here since user might tamper with the amount in the form cfg := lobster.GetConfig() if amount < int(cfg.Billing.DepositMinimum*100) || amount > int(cfg.Billing.DepositMaximum*100) { lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.FormattedErrorf("amount_between", cfg.Billing.DepositMinimum, cfg.Billing.DepositMaximum)) return } chargeParams := &stripe.ChargeParams{ Amount: uint64(amount), Currency: stripe.Currency(currency), Source: &stripe.SourceParams{Token: stripeToken}, Desc: "Lobster credit", } charge, err := sp.client.Charges.New(chargeParams) if err != nil { emailParams := StripeErrorEmail{ fmt.Sprintf("error creating charge for user %d", session.UserId), err, } lobster.MailWrap(-1, "stripeError", emailParams, false) lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.FormatError(fmt.Errorf("credit card payment error; make sure that you have entered your credit card details correctly"))) return } else if !charge.Paid { emailParams := StripeErrorEmail{ fmt.Sprintf("created charge for user %d but paid is false", session.UserId), nil, } lobster.MailWrap(-1, "stripeError", emailParams, false) lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.FormatError(fmt.Errorf("credit card payment error; make sure that you have entered your credit card details correctly"))) return } transaction := charge.Tx lobster.TransactionAdd( session.UserId, "stripe", charge.ID, "Stripe payment: "+charge.ID, int64(charge.Amount)*lobster.BILLING_PRECISION/100, transaction.Fee*lobster.BILLING_PRECISION/100, ) lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.Success("payment_made")) }
func ticketOpen(userId int, name string, message string, staff bool) (int, error) { if name == "" || message == "" { return 0, L.Error("subject_message_empty") } else if len(message) > 16384 { return 0, L.Errorf("message_too_long", "15,000") } user := lobster.UserDetails(userId) if !staff && (user == nil || user.Status == "new") { return 0, L.Errorf("ticket_for_support", cfg.Default.AdminEmail) } result := db.Exec("INSERT INTO tickets (user_id, name, status, modify_time) VALUES (?, ?, 'open', NOW())", userId, name) ticketId := result.LastInsertId() db.Exec("INSERT INTO ticket_messages (ticket_id, staff, message) VALUES (?, ?, ?)", ticketId, staff, message) if staff { lobster.MailWrap(userId, "ticketOpen", TicketUpdateEmail{Id: ticketId, Subject: name, Message: message}, false) } else { lobster.MailWrap(-1, "ticketOpen", TicketUpdateEmail{Id: ticketId, Subject: name, Message: message}, false) } log.Printf("Ticket opened for user %d: %s", userId, name) return ticketId, nil }
func ticketReply(userId int, ticketId int, message string, staff bool) error { if message == "" { return L.Error("message_empty") } ticket := TicketDetails(userId, ticketId, staff) if ticket == nil { return L.Error("invalid_ticket") } db.Exec("INSERT INTO ticket_messages (ticket_id, staff, message) VALUES (?, ?, ?)", ticketId, staff, message) // update ticket status newStatus := "open" if staff { newStatus = "answered" lobster.MailWrap(userId, "ticketReply", TicketUpdateEmail{Id: ticketId, Subject: ticket.Name, Message: message}, false) } else { lobster.MailWrap(-1, "ticketReply", TicketUpdateEmail{Id: ticketId, Subject: ticket.Name, Message: message}, false) } db.Exec("UPDATE tickets SET modify_time = NOW(), status = ? WHERE id = ?", newStatus, ticketId) log.Printf("Ticket reply for user %d on ticket #%d %s", userId, ticketId, ticket.Name) return nil }
func (this *CoinbasePayment) callback(w http.ResponseWriter, r *http.Request) { cfg := lobster.GetConfig() requestBytes, err := ioutil.ReadAll(r.Body) if err != nil { lobster.ReportError(err, "coinbase callback read error", fmt.Sprintf("ip: %s", r.RemoteAddr)) w.WriteHeader(500) return } var data CoinbaseData err = json.Unmarshal(requestBytes, &data) if err != nil { lobster.ReportError(err, "coinbase callback decoding error", fmt.Sprintf("ip: %s; raw request: %s", r.RemoteAddr, requestBytes)) w.WriteHeader(400) return } if data.Order.TotalNative.CurrencyIso != cfg.Billing.Currency { lobster.ReportError(fmt.Errorf("invalid currency %s", data.Order.TotalNative.CurrencyIso), "coinbase callback error", fmt.Sprintf("ip: %s; raw request: %s", r.RemoteAddr, requestBytes)) w.WriteHeader(200) return } else if !strings.HasPrefix(data.Order.Custom, "lobster") { lobster.ReportError(fmt.Errorf("invalid payment with custom=%s", data.Order.Custom), "coinbase callback error", fmt.Sprintf("ip: %s; raw request: %s", r.RemoteAddr, requestBytes)) w.WriteHeader(200) return } userIdStr := strings.Split(data.Order.Custom, "lobster")[1] userId, err := strconv.Atoi(userIdStr) if err != nil { lobster.ReportError(fmt.Errorf("invalid payment with custom=%s", data.Order.Custom), "coinbase callback error", fmt.Sprintf("ip: %s; raw request: %s", r.RemoteAddr, requestBytes)) w.WriteHeader(200) return } if data.Order.Status == "completed" { lobster.TransactionAdd(userId, "coinbase", data.Order.Id, "Bitcoin transaction: "+data.Order.Transaction.Id, int64(data.Order.TotalNative.Cents)*lobster.BILLING_PRECISION/100, 0) } else if data.Order.Status == "mispaid" { lobster.MailWrap(-1, "coinbaseMispaid", CoinbaseMispaidEmail{OrderId: data.Order.Id}, false) } w.WriteHeader(200) }