|
|
@ -14,6 +14,7 @@ import (
|
|
|
|
"math/rand"
|
|
|
|
"math/rand"
|
|
|
|
gogpt "github.com/sashabaranov/go-gpt3"
|
|
|
|
gogpt "github.com/sashabaranov/go-gpt3"
|
|
|
|
"github.com/stripe/stripe-go/v74"
|
|
|
|
"github.com/stripe/stripe-go/v74"
|
|
|
|
|
|
|
|
"github.com/stripe/stripe-go/v74/event"
|
|
|
|
"github.com/stripe/stripe-go/v74/webhook"
|
|
|
|
"github.com/stripe/stripe-go/v74/webhook"
|
|
|
|
"github.com/stripe/stripe-go/v74/checkout/session"
|
|
|
|
"github.com/stripe/stripe-go/v74/checkout/session"
|
|
|
|
|
|
|
|
|
|
|
@ -97,33 +98,12 @@ func clearOld(db *gorm.DB) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func webhookResponse(w http.ResponseWriter, req *http.Request) {
|
|
|
|
func handleEvent(event stripe.Event) error {
|
|
|
|
const MaxBodyBytes = int64(65536)
|
|
|
|
|
|
|
|
req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(req.Body)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Printf("Error reading request body: %v\n", err)
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
endpointSecret := webhookSecret
|
|
|
|
|
|
|
|
event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Printf("Error verifying webhook signature %s\n", err)
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if event.Type == "checkout.session.completed" {
|
|
|
|
if event.Type == "checkout.session.completed" {
|
|
|
|
var session stripe.CheckoutSession
|
|
|
|
var session stripe.CheckoutSession
|
|
|
|
err := json.Unmarshal(event.Data.Raw, &session)
|
|
|
|
err := json.Unmarshal(event.Data.Raw, &session)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error parsing webhook JSON %s", err)
|
|
|
|
return fmt.Errorf("Error parsing webhook JSON %s", err)
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
params := &stripe.CheckoutSessionParams{}
|
|
|
|
params := &stripe.CheckoutSessionParams{}
|
|
|
@ -132,7 +112,6 @@ func webhookResponse(w http.ResponseWriter, req *http.Request) {
|
|
|
|
// Retrieve the session. If you require line items in the response, you may include them by expanding line_items.
|
|
|
|
// Retrieve the session. If you require line items in the response, you may include them by expanding line_items.
|
|
|
|
// Fulfill the purchase...
|
|
|
|
// Fulfill the purchase...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var toFulfill User
|
|
|
|
var toFulfill User
|
|
|
|
found := false
|
|
|
|
found := false
|
|
|
|
for trial := 0; trial < 5; trial++ {
|
|
|
|
for trial := 0; trial < 5; trial++ {
|
|
|
@ -144,18 +123,51 @@ func webhookResponse(w http.ResponseWriter, req *http.Request) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
if !found {
|
|
|
|
log.Println("Error Failed to find user in database to fulfill: very bad! ID: " + session.ID)
|
|
|
|
return fmt.Errorf("Error Failed to find user in database to fulfill: very bad! ID: " + session.ID)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
userString, err := codes.CodeToString(toFulfill.Code)
|
|
|
|
userString, err := codes.CodeToString(toFulfill.Code)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error strange thing, saved user's code was unable to be converted to a string %s", err)
|
|
|
|
return fmt.Errorf("Error strange thing, saved user's code was unable to be converted to a string %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Printf("Fulfilling user with code %s number %d\n", userString, toFulfill.Code)
|
|
|
|
log.Printf("Fulfilling user with code %s number %d\n", userString, toFulfill.Code)
|
|
|
|
|
|
|
|
if(toFulfill.IsFulfilled) {
|
|
|
|
|
|
|
|
log.Printf("User with code %s is already fulfilled, strange\n", userString)
|
|
|
|
|
|
|
|
}
|
|
|
|
toFulfill.IsFulfilled = true
|
|
|
|
toFulfill.IsFulfilled = true
|
|
|
|
db.Save(&toFulfill)
|
|
|
|
err = db.Save(&toFulfill).Error
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return fmt.Errorf("Failed to save fulfilled flag status to database: %s", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func webhookResponse(w http.ResponseWriter, req *http.Request) {
|
|
|
|
|
|
|
|
const MaxBodyBytes = int64(65536)
|
|
|
|
|
|
|
|
req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(req.Body)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Printf("Error reading request body: %v\n", err)
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
endpointSecret := webhookSecret
|
|
|
|
|
|
|
|
event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Printf("Error verifying webhook signature %s\n", err)
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = handleEvent(event)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -285,12 +297,30 @@ func index(w http.ResponseWriter, req *http.Request) {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// now have valid user, in the database, to be rate limit checked
|
|
|
|
// now have valid user, in the database, to be rate limit checked
|
|
|
|
// rate limiting based on user token
|
|
|
|
// rate limiting based on user token
|
|
|
|
_, exists := daypassTimedOut[thisUserCode]
|
|
|
|
if !thisUser.IsFulfilled {
|
|
|
|
if exists {
|
|
|
|
log.Println("Unfulfilled user trying to play, might've been unresponded to event. Retrieving backlog of unfulfilled events...\n")
|
|
|
|
rejected = true
|
|
|
|
params := &stripe.EventListParams{}
|
|
|
|
|
|
|
|
params.Filters.AddFilter("delivery_success", "", "false")
|
|
|
|
|
|
|
|
i := event.List(params)
|
|
|
|
|
|
|
|
for i.Next() {
|
|
|
|
|
|
|
|
e := i.Event()
|
|
|
|
|
|
|
|
log.Println("Unfulfilled event! Of type %s. Handling...\n", e.Type)
|
|
|
|
|
|
|
|
err := handleEvent(*e)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Println("Failed to fulfill unfulfilled event: %s\n", err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if thisUser.IsFulfilled {
|
|
|
|
|
|
|
|
_, exists := daypassTimedOut[thisUserCode]
|
|
|
|
|
|
|
|
if exists {
|
|
|
|
|
|
|
|
rejected = true
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
rejected = false
|
|
|
|
|
|
|
|
daypassTimedOut[thisUserCode] = currentTime()
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
rejected = false
|
|
|
|
log.Println("User with code and existing entry in database was not fulfilled, and wanted to play... Very bad. Usercode: %s\n", thisUserCode)
|
|
|
|
daypassTimedOut[thisUserCode] = currentTime()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|