diff --git a/go.mod b/go.mod index 41d8362..f679c08 100644 --- a/go.mod +++ b/go.mod @@ -10,4 +10,7 @@ require ( github.com/go-sql-driver/mysql v1.6.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/stripe/stripe-go/v76 v76.12.0 + github.com/xhit/go-simple-mail/v2 v2.16.0 ) + +require github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect diff --git a/go.sum b/go.sum index a2f35a0..d3a70d9 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stripe/stripe-go/v76 v76.12.0 h1:TzkkQ1yXEZqO8+WS4Qun/mYKRLFQpPX8bti3VUEoe30= github.com/stripe/stripe-go/v76 v76.12.0/go.mod h1:rw1MxjlAKKcZ+3FOXgTHgwiOa2ya6CPq6ykpJ0Q6Po4= +github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM= +github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns= +github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA= +github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/migrations/0_29092022_setup_tables.sql b/migrations/0_29092022_setup_tables.sql index 7efddf0..14956eb 100644 --- a/migrations/0_29092022_setup_tables.sql +++ b/migrations/0_29092022_setup_tables.sql @@ -73,7 +73,7 @@ CREATE TABLE subscription ( 'active', 'past_due', 'canceled', - 'unpaid'), + 'unpaid') DEFAULT 'incomplete', payment_status VARCHAR(50) NOT NULL, current_period_end INT DEFAULT 0, current_period_start INT DEFAULT 0, diff --git a/skouter.go b/skouter.go index ad330c8..b332e3e 100644 --- a/skouter.go +++ b/skouter.go @@ -16,7 +16,7 @@ import ( "net/http/httputil" "net/mail" "net/url" - "net/smtp" + mailer "github.com/xhit/go-simple-mail/v2" "os" "os/exec" "regexp" @@ -24,7 +24,6 @@ import ( "strings" "sync" "time" - // pdf "github.com/SebastiaanKlippert/go-wkhtmltopdf" "github.com/brianvoe/gofakeit/v6" "github.com/disintegration/gift" "github.com/dustin/go-humanize" @@ -32,8 +31,6 @@ import ( "github.com/stripe/stripe-go/v76" "github.com/stripe/stripe-go/v76/customer" "github.com/stripe/stripe-go/v76/subscription" - // "github.com/stripe/stripe-go/v76/invoice" - // "github.com/stripe/stripe-go/v76/paymentintent" "github.com/stripe/stripe-go/v76/webhook" "image" _ "image/jpeg" @@ -251,8 +248,8 @@ type HookKeys struct { var ( regexen = make(map[string]*regexp.Regexp) relock sync.Mutex - address = "localhost:8001" - mainAddress = "localhost:8002" + address = os.Getenv("SKOUTER_API_PORT") + mainAddress = os.Getenv("SKOUTER_MAIN_PORT") ) var paths = map[string]string{ @@ -1040,11 +1037,7 @@ func insertAddress(db *sql.DB, address Address) (int, error) { city, region, country, - zip - ) - VALUES (?, ?, ?, ?, ?, ?) - RETURNING id - ` + zip) VALUES (?, ?, ?, ?, ?, ?) RETURNING id` row = db.QueryRow(query, address.Full, @@ -1077,8 +1070,7 @@ func insertBranch(db *sql.DB, branch Branch) (int, error) { address ) VALUES (?, ?, ?, ?, ?, ?) - RETURNING id - ` + RETURNING id` row = db.QueryRow(query, branch.Name, @@ -1108,7 +1100,7 @@ func insertLicense(db *sql.DB, license License) (int, error) { num ) VALUES (?, ?, ?) - RETURNING id + RETURNING id ` row = db.QueryRow(query, @@ -3146,6 +3138,7 @@ func ( user *User ) SyncSub( sub *stripe.Subscription, db *sql.DB ) error { // existing instance if possible. It's main purpose is to supply a // client secret used for sending billing information to stripe. func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) { + stripe.Key = os.Getenv("STRIPE_SECRET_KEY") claims, err := getClaims(r) user, err := queryUser(db, claims.Id) @@ -3187,13 +3180,15 @@ func subscribe(w http.ResponseWriter, db *sql.DB, r *http.Request) { user.Sub.Start = int(s.CurrentPeriodStart) user.Sub.ClientSecret = s.LatestInvoice.PaymentIntent.ClientSecret user.Sub.PaymentStatus = string(s.LatestInvoice.PaymentIntent.Status) + user.Sub.Status = string(s.Status) // Inserting from here is unnecessary and confusing because // new subs are already handled by the stripe hook. It remains for // easier testing of the endpoint. err = user.Sub.insertSub(db) if err != nil { - http.Error(w, err.Error(), 500) + // http.Error(w, err.Error(), 500) + json.NewEncoder(w).Encode(s) return } } else { @@ -3521,34 +3516,54 @@ func verifyUser(w http.ResponseWriter, db *sql.DB, r *http.Request) { } func (user *User) sendVerificationEmail() { - auth := smtp.PlainAuth("", - os.Getenv("SMTP_USERNAME"), - os.Getenv("SMTP_PASSWORD"), - os.Getenv("SMTP_HOST")) + server := mailer.NewSMTPClient() + + // SMTP Server + server.Host = os.Getenv("SMTP_HOST") + server.Port, _ = strconv.Atoi(os.Getenv("SMTP_PORT")) + server.Username = os.Getenv("SMTP_USERNAME") + server.Password = os.Getenv("SMTP_PASSWORD") + server.Encryption = mailer.EncryptionSSLTLS + server.Authentication = mailer.AuthPlain - address := os.Getenv("SMTP_HOST") + ":" + os.Getenv("SMTP_PORT") - - message := `Subject: Email Verification + // SMTP client + smtpClient,err := server.Connect() + + if err != nil{ + log.Println("Error sending mail:", err) + return + } + + email := mailer.NewMSG() + email.SetFrom("Skouter "). + AddTo(user.Email). + SetSubject("Email Verification") + + message := `To: %s + Subject: Email Verification + Welcome %s, Click the link below to verify your email address https://skouter.net?verification_token=%s` t, err := verificationToken(user.Id) - if err != nil { return } + + message = fmt.Sprintf(message, user.Email, user.FirstName, t) - message = fmt.Sprintf(message, user.FirstName, t) + email.SetBody(mailer.TextPlain, message) - err = smtp.SendMail(address, - auth, - os.Getenv("SMTP_EMAIL"), - []string{user.Email}, - []byte(message)) - if err != nil { - fmt.Println(err) + if email.Error != nil { + log.Println("Error composing verification email: ", email.Error) return } - log.Println("Email Sent Successfully!") + err = email.Send(smtpClient) + if err != nil { + log.Println(err) + } else { + log.Println("Verification Email sent to: ", user.Email) + } + } func api(w http.ResponseWriter, r *http.Request) { @@ -3710,7 +3725,7 @@ func api(w http.ResponseWriter, r *http.Request) { // with backend so the user's login status must be represented by a // query parameter during proxy. func setupProxy(r *httputil.ProxyRequest) { - proxyURL, err := url.Parse("http://localhost:8002") + proxyURL, err := url.Parse("http://localhost:" + mainAddress) if err != nil { log.Fatal("Invalid origin server URL") } @@ -3730,7 +3745,6 @@ func setupProxy(r *httputil.ProxyRequest) { } func serve() { - files := http.FileServer(http.Dir("")) proxy := &httputil.ReverseProxy{ @@ -3740,7 +3754,7 @@ func serve() { http.Handle("/assets/", files) http.HandleFunc("/api/", api) http.Handle("/", proxy) - log.Fatal(http.ListenAndServe(address, nil)) + log.Fatal(http.ListenAndServe("localhost:" + address, nil)) } func dbReset(db *sql.DB) { @@ -4024,9 +4038,6 @@ func dbSeed(db *sql.DB) { } func dev(args []string) { - os.Setenv("DB_NAME", "skouter_dev") - os.Setenv("DB_USER", "tester") - os.Setenv("DB_PASSWORD", "test123") stripe.Key = os.Getenv("STRIPE_SECRET_KEY") standardPriceId = "price_1OZLK9BPMoXn2pf9kuTAf8rs" hookKeys = HookKeys{ @@ -4076,7 +4087,7 @@ func check(args []string) { http.Handle("/assets/", files) http.HandleFunc("/", checkPdf) - log.Fatal(http.ListenAndServe(address, nil)) + log.Fatal(http.ListenAndServe("localhost:" + address, nil)) } func main() {