Implement verified email registration and queued TLS delivery
Foundry Go checks / check (push) Successful in 1m52s
Foundry Go checks / check (pull_request) Successful in 1m53s

This commit is contained in:
2026-11-05 18:31:09 +08:00
parent 1b756d36ce
commit 0d0521f13d
8 changed files with 381 additions and 6 deletions
+13 -3
View File
@@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"golang.org/x/crypto/bcrypt"
"io"
"log"
"net/http"
@@ -26,10 +27,17 @@ type service struct {
projects map[string]*url.URL
redirectURI, clientID, secret string
google *http.Client
email *EmailConfig
passwordSlots chan struct{}
dummyPassword []byte
}
func New(db *sql.DB, callbacks map[string]string, redirectURI, id, secret string) (http.Handler, error) {
s := &service{db: db, projects: make(map[string]*url.URL), redirectURI: redirectURI, clientID: id, secret: secret,
func New(db *sql.DB, callbacks map[string]string, redirectURI, id, secret string, email *EmailConfig) (http.Handler, error) {
dummy, err := bcrypt.GenerateFromPassword([]byte("foundry-invalid-login-placeholder"), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
s := &service{db: db, email: email, passwordSlots: make(chan struct{}, 4), dummyPassword: dummy, projects: make(map[string]*url.URL), redirectURI: redirectURI, clientID: id, secret: secret,
google: &http.Client{Timeout: 10 * time.Second, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}}
for name, raw := range callbacks {
u, err := url.Parse(raw)
@@ -120,8 +128,10 @@ func (s *service) project(w http.ResponseWriter, r *http.Request) error {
switch {
case r.Method == http.MethodOptions:
w.Header().Set("Access-Control-Allow-Methods", "GET, POST")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, X-Foundry-Code, X-Foundry-Verifier")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Foundry-Code, X-Foundry-Verifier")
reply(w, 204, nil)
case r.Method == http.MethodPost && (action == "register" || action == "verify-email" || action == "login"):
return s.emailAction(w, r, project, action)
case r.Method == http.MethodPost && action == "exchange":
return s.exchange(w, r, project)
case r.Method == http.MethodGet && action == "me":