diff --git a/cmd/lavender/serve.go b/cmd/lavender/serve.go index b721687..f904638 100644 --- a/cmd/lavender/serve.go +++ b/cmd/lavender/serve.go @@ -11,9 +11,9 @@ import ( "flag" "github.com/1f349/lavender/server" "github.com/1f349/lavender/server/pages" + "github.com/1f349/mjwt" "github.com/1f349/violet/utils" exit_reload "github.com/MrMelon54/exit-reload" - "github.com/1f349/mjwt" "github.com/google/subcommands" "log" "os" @@ -75,7 +75,7 @@ func normalLoad(startUp server.Conf, wd string) { if err != nil { log.Fatal("[Lavender] Failed to load or create MJWT signer:", err) } - saveMjwtPubKey(mSign) + saveMjwtPubKey(mSign, wd) if err := pages.LoadPages(wd); err != nil { log.Fatal("[Lavender] Failed to load page templates:", err) @@ -91,14 +91,14 @@ func normalLoad(startUp server.Conf, wd string) { }) } -func saveMjwtPubKey(mSign mjwt.Signer) { +func saveMjwtPubKey(mSign mjwt.Signer, wd string) { pubKey := x509.MarshalPKCS1PublicKey(mSign.PublicKey()) b := new(bytes.Buffer) err := pem.Encode(b, &pem.Block{Type: "RSA PUBLIC KEY", Bytes: pubKey}) if err != nil { log.Fatal("[Lavender] Failed to encode MJWT public key:", err) } - err = os.WriteFile("lavender.public.key", b.Bytes(), 0600) + err = os.WriteFile(filepath.Join(wd, "lavender.public.key"), b.Bytes(), 0600) if err != nil && !errors.Is(err, os.ErrExist) { log.Fatal("[Lavender] Failed to save MJWT public key:", err) } diff --git a/server/flow.go b/server/flow.go index af3f9e1..6ce455a 100644 --- a/server/flow.go +++ b/server/flow.go @@ -15,6 +15,7 @@ import ( "golang.org/x/oauth2" "net/http" "net/mail" + "net/url" "strings" "time" ) @@ -33,6 +34,15 @@ var testOa2UserInfo = func(oidc *issuer.WellKnownOIDC, ctx context.Context, exch } func (h *HttpServer) flowPopup(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { + cookie, err := req.Cookie("lavender-login-name") + if err == nil && cookie.Valid() == nil { + pages.RenderPageTemplate(rw, "flow-popup-memory", map[string]any{ + "ServiceName": h.conf.ServiceName, + "Origin": req.URL.Query().Get("origin"), + "LoginName": cookie.Value, + }) + return + } pages.RenderPageTemplate(rw, "flow-popup", map[string]any{ "ServiceName": h.conf.ServiceName, "Origin": req.URL.Query().Get("origin"), @@ -40,6 +50,23 @@ func (h *HttpServer) flowPopup(rw http.ResponseWriter, req *http.Request, _ http } func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { + if req.PostFormValue("not-you") == "1" { + http.SetCookie(rw, &http.Cookie{ + Name: "lavender-login-name", + Value: "", + Path: "/", + MaxAge: -1, + Secure: true, + SameSite: http.SameSiteStrictMode, + }) + http.Redirect(rw, req, (&url.URL{ + Path: "/popup", + RawQuery: url.Values{ + "origin": []string{req.PostFormValue("origin")}, + }.Encode(), + }).String(), http.StatusFound) + return + } loginName := req.PostFormValue("loginname") login := h.manager.FindServiceFromLogin(loginName) if login == nil { @@ -50,6 +77,18 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _ n := strings.IndexByte(loginName, '@') loginUn := loginName[:n] + now := time.Now() + future := now.AddDate(1, 0, 0) + http.SetCookie(rw, &http.Cookie{ + Name: "lavender-login-name", + Value: loginName, + Path: "/", + Expires: future, + MaxAge: int(future.Sub(now).Seconds()), + Secure: true, + SameSite: http.SameSiteStrictMode, + }) + targetOrigin := req.PostFormValue("origin") allowedService, found := h.services[targetOrigin] if !found { diff --git a/server/pages/flow-callback.go.html b/server/pages/flow-callback.go.html index 4a90d66..88717c5 100644 --- a/server/pages/flow-callback.go.html +++ b/server/pages/flow-callback.go.html @@ -13,6 +13,9 @@ }; window.addEventListener("load", function () { window.opener.postMessage(loginData, loginData.target); + setTimeout(function () { + window.close(); + }, 500); }); diff --git a/server/pages/flow-popup-memory.go.html b/server/pages/flow-popup-memory.go.html new file mode 100644 index 0000000..4661af7 --- /dev/null +++ b/server/pages/flow-popup-memory.go.html @@ -0,0 +1,27 @@ + + +
+