package main import ( "bytes" "encoding/json" "fmt" "html/template" "log" "net/mail" "os" "strings" _ "leadsform/migrations" altcha "github.com/altcha-org/altcha-lib-go" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/plugins/migratecmd" "github.com/pocketbase/pocketbase/tools/mailer" ) var altchaHMACKey = os.Getenv("ALTCHA_HMAC_KEY") func mapToString(m map[string]string) string { t, _ := template.New("body").Parse("Details \n\n{{.}}") tr, _ := template.New("tr").Parse("{{.Key}} : {{.Value}} \n") trString := "" type TR struct { Key string Value string } for k, v := range m { data := TR{ Key: k, Value: v, } var buf bytes.Buffer _ = tr.Execute(&buf, data) trString = trString + buf.String() } var buf bytes.Buffer _ = t.Execute(&buf, trString) return buf.String() } func main() { app := pocketbase.New() app.OnServe().BindFunc(func(se *core.ServeEvent) error { se.Router.GET("/altcha", func(e *core.RequestEvent) error { orginH := e.Request.Header["Origin"] if len(orginH) != 1 { return e.Error(400, "Origin header is required", nil) } origin := orginH[0] website, err := app.FindFirstRecordByData("websites", "url", origin) if err != nil || website == nil { return e.Error(400, "Invalid origin", nil) } challenge, err := altcha.CreateChallenge(altcha.ChallengeOptions{ HMACKey: altchaHMACKey, MaxNumber: 50000, }) if err != nil { return e.Error(400, "Unable to create challenge", nil) } return e.JSON(200, challenge) }) se.Router.POST("/lead", func(e *core.RequestEvent) error { orginH := e.Request.Header["Origin"] if len(orginH) != 1 { return e.Error(400, "Origin header is required", nil) } origin := orginH[0] website, err := app.FindFirstRecordByData("websites", "url", origin) if err != nil { return e.Error(400, "Invalid origin", nil) } info, err := e.RequestInfo() if err != nil || info.Body == nil { return e.Error(400, "Unable to parse request", err) } payload := info.Body["altcha"].(string) if payload == "" { return e.Error(400, "Altcha payload is required", nil) } formData := map[string][]string{} for k, v := range info.Body { formData[k] = []string{v.(string)} } fmt.Println(payload) fmt.Println(altchaHMACKey) verified, err := altcha.VerifySolution(payload, altchaHMACKey, true) if err != nil || !verified { return e.Error(400, "Invalid Altcha payload", nil) } collection, err := app.FindCollectionByNameOrId("leads") if err != nil { app.Logger().Error("Unable to find collection ~ leads", nil) } record := core.NewRecord(collection) delete(info.Body, "altcha") data, err := json.Marshal(info.Body) if err != nil { app.Logger().Warn("Unable to marshal data", nil) return e.Error(400, "Unable to marshal data", nil) } record.Set("data", data) record.Set("website", website.Id) if err := app.Save(record); err != nil { return e.Error(500, "Unable to save record", err) } return e.String(201, "Submitted") }) return se.Next() }) app.OnRecordAfterCreateSuccess("leads").BindFunc(func(e *core.RecordEvent) error { go func() { e.App.ExpandRecord(e.Record, []string{"website"}, nil) website := e.Record.ExpandedOne("website") subject := fmt.Sprintf("New lead from %s", website.GetString("url")) data := make(map[string]string) _ = json.Unmarshal([]byte(e.Record.GetString("data")), &data) message := &mailer.Message{ From: mail.Address{ Address: e.App.Settings().Meta.SenderAddress, Name: e.App.Settings().Meta.SenderName, }, To: []mail.Address{{Address: website.GetString("notification_email")}}, Subject: subject, Text: mapToString(data), } _ = e.App.NewMailClient().Send(message) }() return e.Next() }) // loosely check if it was executed using "go run" isGoRun := strings.HasPrefix(os.Args[0], os.TempDir()) migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{ // enable auto creation of migration files when making collection changes in the Dashboard // (the isGoRun check is to enable it only during development) Automigrate: isGoRun, }) if err := app.Start(); err != nil { log.Fatal(err) } }