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 (this *PaypalPayment) Payment(w http.ResponseWriter, r *http.Request, frameParams lobster.FrameParams, userId int, username string, amount float64) { cfg := lobster.GetConfig() frameParams.Scripts = append(frameParams.Scripts, "paypal") params := &PaypalTemplateParams{ Frame: frameParams, Business: this.business, Amount: amount, UserId: userId, NotifyUrl: cfg.Default.UrlBase + PAYPAL_CALLBACK, ReturnUrl: this.returnUrl, Currency: cfg.Billing.Currency, } lobster.RenderTemplate(w, "panel", "paypal", params) }
func (sp *StripePayment) form(w http.ResponseWriter, r *http.Request, session *lobster.Session, frameParams lobster.FrameParams) { cents, _ := strconv.ParseInt(r.URL.Query().Get("cents"), 10, 64) user := lobster.UserDetails(session.UserId) cfg := lobster.GetConfig() params := &StripeTemplateParams{ Frame: frameParams, Token: lobster.CSRFGenerate(session), Key: sp.publishableKey, Cents: cents, Currency: cfg.Billing.Currency, Amount: float64(cents) / 100, Email: user.Email, } lobster.RenderTemplate(w, "panel", "stripe", params) }
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) }
func Setup() { decoder = lobster.GetDecoder() L = lobster.L cfg = lobster.GetConfig() db = lobster.GetDatabase() lobster.RegisterPanelHandler("/panel/support", panelSupport, false) lobster.RegisterPanelHandler("/panel/support/open", panelSupportOpen, false) lobster.RegisterPanelHandler("/panel/support/{id:[0-9]+}", panelSupportTicket, false) lobster.RegisterPanelHandler("/panel/support/{id:[0-9]+}/reply", panelSupportTicketReply, true) lobster.RegisterPanelHandler("/panel/support/{id:[0-9]+}/close", panelSupportTicketClose, true) lobster.RegisterAdminHandler("/admin/support", adminSupport, false) lobster.RegisterAdminHandler("/admin/support/open/{id:[0-9]+}", adminSupportOpen, false) lobster.RegisterAdminHandler("/admin/support/{id:[0-9]+}", adminSupportTicket, false) lobster.RegisterAdminHandler("/admin/support/{id:[0-9]+}/reply", adminSupportTicketReply, true) lobster.RegisterAdminHandler("/admin/support/{id:[0-9]+}/close", adminSupportTicketClose, true) lobster.RegisterPanelWidget("Support", lobster.PanelWidgetFunc(func(session *lobster.Session) interface{} { return TicketListActive(session.UserId) })) }
func (this *CoinbasePayment) Payment(w http.ResponseWriter, r *http.Request, frameParams lobster.FrameParams, userId int, username string, amount float64) { cfg := lobster.GetConfig() if cfg.Default.Debug { log.Printf("Creating Coinbase button for %s (id=%d) with amount $%.2f", username, userId, amount) } params := &coinbase.Button{ Name: lobster.L.T("credit_for_username", username), PriceString: fmt.Sprintf("%.2f", amount), PriceCurrencyIso: cfg.Billing.Currency, Custom: fmt.Sprintf("lobster%d", userId), Description: fmt.Sprintf("Credit %s", lobster.L.T("currency_format", fmt.Sprintf("%.2f", amount))), Type: "buy_now", Style: "buy_now_large", CallbackUrl: cfg.Default.UrlBase + "/coinbase_callback_" + this.callbackSecret, } cli := coinbase.ApiKeyClient(this.apiKey, this.apiSecret) button, err := cli.CreateButton(params) if err != nil { lobster.ReportError(err, "failed to create Coinbase button", fmt.Sprintf("username=%s, amount=%.2f", username, amount)) lobster.RedirectMessage(w, r, "/panel/billing", lobster.L.FormattedError("try_again_later")) return } http.Redirect(w, r, "https://coinbase.com/checkouts/"+button.Code, 303) }
func (this *PaypalPayment) Callback(w http.ResponseWriter, r *http.Request) { cfg := lobster.GetConfig() requestBytes, err := ioutil.ReadAll(r.Body) if err != nil { lobster.ReportError(err, "paypal callback read error", fmt.Sprintf("ip: %s", r.RemoteAddr)) w.WriteHeader(403) return } // decode the post data manually since there may be encoding issues requestParts := strings.Split(string(requestBytes), "&") myPost := make(map[string]string) for _, part := range requestParts { keyval := strings.Split(part, "=") if len(keyval) == 2 { myPost[keyval[0]], _ = url.QueryUnescape(keyval[1]) } } // post back to Paypal system to validate the IPN data validateReq := "cmd=_notify-validate" for key, value := range myPost { validateReq += fmt.Sprintf("&%s=%s", key, url.QueryEscape(value)) } resp, err := http.Post(PAYPAL_URL, "application/x-www-form-urlencoded", bytes.NewBufferString(validateReq)) if err != nil { lobster.ReportError(err, "paypal callback validation error", fmt.Sprintf("ip: %s; requestmap: %v", r.RemoteAddr, myPost)) w.WriteHeader(403) return } body, err := ioutil.ReadAll(resp.Body) if err != nil { lobster.ReportError(err, "paypal callback validation error", fmt.Sprintf("ip: %s; requestmap: %v", r.RemoteAddr, myPost)) w.WriteHeader(403) return } if string(body) != "VERIFIED" || myPost["payment_status"] == "" || myPost["mc_gross"] == "" || myPost["mc_currency"] == "" || myPost["txn_id"] == "" || myPost["receiver_email"] == "" || myPost["payment_status"] == "" || myPost["payer_email"] == "" || myPost["custom"] == "" { lobster.ReportError(errors.New("missing field or not verified"), "paypal callback bad input or validation", fmt.Sprintf("ip: %s; verify body: %s; requestmap: %v", r.RemoteAddr, body, myPost)) w.WriteHeader(403) return } w.WriteHeader(200) if myPost["payment_status"] != "Completed" { return } else if !strings.HasPrefix(myPost["custom"], "lobster") { lobster.ReportError(fmt.Errorf("invalid payment with custom=%s", myPost["custom"]), "paypal callback error", fmt.Sprintf("ip: %s; requestmap: %v", r.RemoteAddr, myPost)) return } else if strings.TrimSpace(strings.ToLower(myPost["receiver_email"])) != strings.TrimSpace(strings.ToLower(this.business)) { lobster.ReportError(fmt.Errorf("invalid payment with receiver_email=%s", myPost["receiver_email"]), "paypal callback error", fmt.Sprintf("ip: %s; requestmap: %v", r.RemoteAddr, myPost)) return } else if myPost["mc_currency"] != cfg.Billing.Currency { lobster.ReportError(fmt.Errorf("invalid payment with currency=%s", myPost["mc_currency"]), "paypal callback error", fmt.Sprintf("ip: %s; requestmap: %v", r.RemoteAddr, myPost)) return } paymentAmount, _ := strconv.ParseFloat(myPost["mc_gross"], 64) transactionId := myPost["txn_id"] userIdStr := strings.Split(myPost["custom"], "lobster")[1] userId, err := strconv.Atoi(userIdStr) if err != nil { lobster.ReportError(fmt.Errorf("invalid payment with custom=%s", myPost["custom"]), "paypal callback error", fmt.Sprintf("ip: %s; requestmap: %v", r.RemoteAddr, myPost)) return } lobster.TransactionAdd(userId, "paypal", transactionId, "Transaction "+transactionId, int64(paymentAmount*lobster.BILLING_PRECISION), 0) }