package handler import ( "database/sql" "net/http" "time" "git.ekzyis.com/ekzyis/delphi.market/lib" "git.ekzyis.com/ekzyis/delphi.market/server/auth" "git.ekzyis.com/ekzyis/delphi.market/server/router/context" "git.ekzyis.com/ekzyis/delphi.market/server/router/pages" "github.com/labstack/echo/v4" ) func HandleSignup(sc context.Context) echo.HandlerFunc { return func(c echo.Context) error { if c.Param("method") == "lightning" { return LnAuthSignup(sc, c) } return pages.Signup().Render(context.RenderContext(sc, c), c.Response().Writer) } } func LnAuthSignup(sc context.Context, c echo.Context) error { var ( db = sc.Db ctx = c.Request().Context() lnAuth *auth.LnAuth sessionId string // sessions expire in 30 days. TODO: refresh sessions expires = time.Now().Add(60 * 60 * 24 * 30 * time.Second) qr string err error ) if lnAuth, err = auth.NewLnAuth("signup"); err != nil { return err } if err = db.QueryRowContext( ctx, "INSERT INTO lnauth(k1, lnurl) VALUES($1, $2) RETURNING session_id", lnAuth.K1, lnAuth.LNURL).Scan(&sessionId); err != nil { return err } if qr, err = lib.ToQR(lnAuth.LNURL); err != nil { return err } c.SetCookie(&http.Cookie{ Name: "session", HttpOnly: true, Path: "/", Value: sessionId, Secure: true, Expires: expires, }) return pages.LnAuthSignup(qr, lnAuth.LNURL).Render(context.RenderContext(sc, c), c.Response().Writer) } func HandleLnAuthCallback(sc context.Context) echo.HandlerFunc { return func(c echo.Context) error { var ( db = sc.Db tx *sql.Tx ctx = c.Request().Context() query auth.LnAuthCallback sessionId string userId int ok bool err error ) if err = c.Bind(&query); err != nil { return echo.NewHTTPError(http.StatusBadRequest) } if tx, err = db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted}); err != nil { return err } err = tx.QueryRow("SELECT session_id FROM lnauth WHERE k1 = $1 LIMIT 1", query.K1).Scan(&sessionId) if err == sql.ErrNoRows { return echo.NewHTTPError(http.StatusNotFound, map[string]string{"reason": "session not found"}) } else if err != nil { return err } ok, err = auth.VerifyLNAuth(&query) if err != nil { return err } else if !ok { return echo.NewHTTPError(http.StatusBadRequest, map[string]string{"reason": "bad signature"}) } if query.Tag == "signup" { if err = tx.QueryRow("INSERT INTO users(ln_pubkey) VALUES ($1) RETURNING id").Scan(&userId); err != nil { return err } } else if query.Tag == "login" { err = tx.QueryRow("SELECT id FROM users WHERE ln_pubkey = $1", query.Key).Scan(&userId) if err == sql.ErrNoRows { return echo.NewHTTPError(http.StatusNotFound, map[string]string{"reason": "user not found"}) } else if err != nil { return err } } else { return echo.NewHTTPError(http.StatusBadRequest, map[string]string{"reason": "tag must be signup or login"}) } if _, err = tx.Exec("INSERT INTO sessions(user_id, session_id) VALUES($1, $2)", userId, sessionId); err != nil { return err } if _, err = tx.Exec("DELETE FROM lnauth WHERE k1 = $1", query.K1); err != nil { return err } return c.JSON(http.StatusOK, map[string]string{"status": "OK"}) } }