From 1cf675b23a586f08bf522403f3926e3cdd8abffe Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 24 Jun 2024 23:06:20 +0800 Subject: [PATCH 1/8] :rewind: Pick up the single-page application as frontend --- .idea/workspace.xml | 121 ++++++-- go.mod | 4 - go.sum | 8 - pkg/internal/embed.go | 6 - pkg/internal/grpc/server.go | 26 +- pkg/internal/server/api/index.go | 4 + pkg/internal/server/server.go | 54 ++-- pkg/internal/server/ui/accounts.go | 55 ---- pkg/internal/server/ui/index.go | 34 --- pkg/internal/server/ui/mfa.go | 194 ------------- pkg/internal/server/ui/oauth.go | 166 ----------- pkg/internal/server/ui/signin.go | 93 ------ pkg/internal/server/ui/signup.go | 87 ------ pkg/internal/views/authorize.gohtml | 56 ---- pkg/internal/views/favicon.png | Bin 76090 -> 0 bytes pkg/internal/views/index.gohtml | 10 - pkg/internal/views/layouts/auth.gohtml | 115 -------- pkg/internal/views/layouts/user-center.gohtml | 128 --------- pkg/internal/views/mfa-apply.gohtml | 43 --- pkg/internal/views/mfa.gohtml | 59 ---- pkg/internal/views/partials/header.gohtml | 56 ---- pkg/internal/views/signin.gohtml | 27 -- pkg/internal/views/signup.gohtml | 47 ---- pkg/internal/views/users/me.gohtml | 153 ---------- pkg/main.go | 6 +- settings.toml | 2 + web/.eslintrc.cjs | 18 ++ web/.gitignore | 30 ++ web/.prettierrc.json | 8 + web/README.md | 39 +++ web/bun.lockb | Bin 0 -> 155500 bytes web/env.d.ts | 1 + web/index.html | 13 + web/package.json | 45 +++ web/public/favicon.png | Bin 0 -> 77150 bytes web/src/assets/utils.css | 14 + web/src/components/Copyright.vue | 6 + web/src/components/NotificationList.vue | 70 +++++ web/src/components/UserMenu.vue | 43 +++ web/src/components/auth/AccountLocator.vue | 61 ++++ web/src/components/auth/CallbackNotify.vue | 16 ++ web/src/components/auth/FactorApplicator.vue | 129 +++++++++ web/src/components/auth/FactorPicker.vue | 75 +++++ web/src/index.vue | 5 + web/src/layouts/master.vue | 46 +++ web/src/layouts/user-center.vue | 22 ++ web/src/main.ts | 54 ++++ web/src/router/index.ts | 96 +++++++ web/src/scripts/request.ts | 3 + web/src/stores/notifications.ts | 64 +++++ web/src/stores/userinfo.ts | 54 ++++ web/src/views/auth/claims.ts | 13 + web/src/views/auth/connect.vue | 192 +++++++++++++ web/src/views/auth/sign-in.vue | 76 +++++ web/src/views/auth/sign-up.vue | 162 +++++++++++ web/src/views/confirm.vue | 104 +++++++ web/src/views/dashboard.vue | 77 +++++ web/src/views/personal-page.vue | 71 +++++ web/src/views/personalize.vue | 170 +++++++++++ web/src/views/security.vue | 266 ++++++++++++++++++ web/tsconfig.app.json | 14 + web/tsconfig.json | 11 + web/tsconfig.node.json | 13 + web/uno.config.ts | 5 + web/vite.config.ts | 27 ++ 65 files changed, 2257 insertions(+), 1410 deletions(-) delete mode 100644 pkg/internal/embed.go delete mode 100644 pkg/internal/server/ui/accounts.go delete mode 100644 pkg/internal/server/ui/index.go delete mode 100644 pkg/internal/server/ui/mfa.go delete mode 100644 pkg/internal/server/ui/oauth.go delete mode 100644 pkg/internal/server/ui/signin.go delete mode 100644 pkg/internal/server/ui/signup.go delete mode 100644 pkg/internal/views/authorize.gohtml delete mode 100644 pkg/internal/views/favicon.png delete mode 100644 pkg/internal/views/index.gohtml delete mode 100644 pkg/internal/views/layouts/auth.gohtml delete mode 100644 pkg/internal/views/layouts/user-center.gohtml delete mode 100644 pkg/internal/views/mfa-apply.gohtml delete mode 100644 pkg/internal/views/mfa.gohtml delete mode 100644 pkg/internal/views/partials/header.gohtml delete mode 100644 pkg/internal/views/signin.gohtml delete mode 100644 pkg/internal/views/signup.gohtml delete mode 100644 pkg/internal/views/users/me.gohtml create mode 100755 web/.eslintrc.cjs create mode 100755 web/.gitignore create mode 100755 web/.prettierrc.json create mode 100755 web/README.md create mode 100755 web/bun.lockb create mode 100755 web/env.d.ts create mode 100755 web/index.html create mode 100755 web/package.json create mode 100755 web/public/favicon.png create mode 100755 web/src/assets/utils.css create mode 100755 web/src/components/Copyright.vue create mode 100755 web/src/components/NotificationList.vue create mode 100755 web/src/components/UserMenu.vue create mode 100755 web/src/components/auth/AccountLocator.vue create mode 100755 web/src/components/auth/CallbackNotify.vue create mode 100755 web/src/components/auth/FactorApplicator.vue create mode 100755 web/src/components/auth/FactorPicker.vue create mode 100755 web/src/index.vue create mode 100755 web/src/layouts/master.vue create mode 100755 web/src/layouts/user-center.vue create mode 100755 web/src/main.ts create mode 100755 web/src/router/index.ts create mode 100755 web/src/scripts/request.ts create mode 100755 web/src/stores/notifications.ts create mode 100755 web/src/stores/userinfo.ts create mode 100755 web/src/views/auth/claims.ts create mode 100755 web/src/views/auth/connect.vue create mode 100755 web/src/views/auth/sign-in.vue create mode 100755 web/src/views/auth/sign-up.vue create mode 100755 web/src/views/confirm.vue create mode 100755 web/src/views/dashboard.vue create mode 100755 web/src/views/personal-page.vue create mode 100755 web/src/views/personalize.vue create mode 100755 web/src/views/security.vue create mode 100755 web/tsconfig.app.json create mode 100755 web/tsconfig.json create mode 100755 web/tsconfig.node.json create mode 100755 web/uno.config.ts create mode 100755 web/vite.config.ts diff --git a/.idea/workspace.xml b/.idea/workspace.xml index f857090..72a6cdd 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,9 +4,71 @@ - @@ -168,7 +230,8 @@ - true diff --git a/go.mod b/go.mod index 6a499cc..3d5a56e 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,7 @@ require ( github.com/go-playground/validator/v10 v10.17.0 github.com/gofiber/contrib/websocket v1.3.0 github.com/gofiber/fiber/v2 v2.52.4 - github.com/gofiber/template/html/v2 v2.1.1 github.com/golang-jwt/jwt/v5 v5.2.0 - github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 github.com/google/uuid v1.6.0 github.com/hashicorp/consul/api v1.29.1 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible @@ -57,8 +55,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect - github.com/gofiber/template v1.8.3 // indirect - github.com/gofiber/utils v1.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/go.sum b/go.sum index 4522a2e..a1c5a95 100644 --- a/go.sum +++ b/go.sum @@ -100,12 +100,6 @@ github.com/gofiber/contrib/websocket v1.3.0/go.mod h1:xguaOzn2ZZ759LavtosEP+rcxI github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ= github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM= github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= -github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= -github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= -github.com/gofiber/template/html/v2 v2.1.1 h1:QEy3O3EBkvwDthy5bXVGUseOyO6ldJoiDxlF4+MJiV8= -github.com/gofiber/template/html/v2 v2.1.1/go.mod h1:2G0GHHOUx70C1LDncoBpe4T6maQbNa4x1CVNFW0wju0= -github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= -github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -135,8 +129,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 h1:yEt5djSYb4iNtmV9iJGVday+i4e9u6Mrn5iP64HH5QM= -github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= diff --git a/pkg/internal/embed.go b/pkg/internal/embed.go deleted file mode 100644 index 7a0136b..0000000 --- a/pkg/internal/embed.go +++ /dev/null @@ -1,6 +0,0 @@ -package pkg - -import "embed" - -//go:embed all:views/* -var FS embed.FS diff --git a/pkg/internal/grpc/server.go b/pkg/internal/grpc/server.go index c4163a9..f143759 100644 --- a/pkg/internal/grpc/server.go +++ b/pkg/internal/grpc/server.go @@ -17,27 +17,31 @@ type Server struct { proto.UnimplementedFriendshipsServer proto.UnimplementedRealmsServer health.UnimplementedHealthServer + + srv *grpc.Server } -var S *grpc.Server +func NewServer() *Server { + server := &Server{ + srv: grpc.NewServer(), + } -func NewGRPC() { - S = grpc.NewServer() + proto.RegisterAuthServer(server.srv, &Server{}) + proto.RegisterNotifyServer(server.srv, &Server{}) + proto.RegisterFriendshipsServer(server.srv, &Server{}) + proto.RegisterRealmsServer(server.srv, &Server{}) + health.RegisterHealthServer(server.srv, &Server{}) - proto.RegisterAuthServer(S, &Server{}) - proto.RegisterNotifyServer(S, &Server{}) - proto.RegisterFriendshipsServer(S, &Server{}) - proto.RegisterRealmsServer(S, &Server{}) - health.RegisterHealthServer(S, &Server{}) + reflection.Register(server.srv) - reflection.Register(S) + return server } -func ListenGRPC() error { +func (v *Server) Listen() error { listener, err := net.Listen("tcp", viper.GetString("grpc_bind")) if err != nil { return err } - return S.Serve(listener) + return v.srv.Serve(listener) } diff --git a/pkg/internal/server/api/index.go b/pkg/internal/server/api/index.go index 9bcb2e7..d4d9201 100644 --- a/pkg/internal/server/api/index.go +++ b/pkg/internal/server/api/index.go @@ -85,5 +85,9 @@ func MapAPIs(app *fiber.App) { } return c.Next() }).Get("/ws", websocket.New(listenWebsocket)) + + api.All("/*", func(c *fiber.Ctx) error { + return fiber.ErrNotFound + }) } } diff --git a/pkg/internal/server/server.go b/pkg/internal/server/server.go index 1f14ef0..870d027 100644 --- a/pkg/internal/server/server.go +++ b/pkg/internal/server/server.go @@ -1,32 +1,31 @@ package server import ( + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/admin" "git.solsynth.dev/hydrogen/passport/pkg/internal/server/api" "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" + "github.com/gofiber/fiber/v2/middleware/filesystem" "net/http" + "path/filepath" "strings" - "git.solsynth.dev/hydrogen/passport/pkg/internal" "git.solsynth.dev/hydrogen/passport/pkg/internal/i18n" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/admin" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/ui" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/favicon" "github.com/gofiber/fiber/v2/middleware/idempotency" "github.com/gofiber/fiber/v2/middleware/logger" - "github.com/gofiber/template/html/v2" jsoniter "github.com/json-iterator/go" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) -var A *fiber.App +type HTTPApp struct { + app *fiber.App +} -func NewServer() { - templates := html.NewFileSystem(http.FS(pkg.FS), ".gohtml") - - A = fiber.New(fiber.Config{ +func NewServer() *HTTPApp { + app := fiber.New(fiber.Config{ DisableStartupMessage: true, EnableIPValidation: true, ServerHeader: "Hydrogen.Passport", @@ -35,12 +34,10 @@ func NewServer() { JSONEncoder: jsoniter.ConfigCompatibleWithStandardLibrary.Marshal, JSONDecoder: jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal, EnablePrintRoutes: viper.GetBool("debug.print_routes"), - Views: templates, - ViewsLayout: "views/index", }) - A.Use(idempotency.New()) - A.Use(cors.New(cors.Config{ + app.Use(idempotency.New()) + app.Use(cors.New(cors.Config{ AllowCredentials: true, AllowMethods: strings.Join([]string{ fiber.MethodGet, @@ -56,27 +53,34 @@ func NewServer() { }, })) - A.Use(logger.New(logger.Config{ + app.Use(logger.New(logger.Config{ Format: "${status} | ${latency} | ${method} ${path}\n", Output: log.Logger, })) - A.Use(exts.AuthMiddleware) - A.Use(i18n.I18nMiddleware) + app.Use(exts.AuthMiddleware) + app.Use(i18n.I18nMiddleware) - A.Use(favicon.New(favicon.Config{ - FileSystem: http.FS(pkg.FS), - File: "views/favicon.png", - URL: "/favicon.png", + api.MapAPIs(app) + admin.MapAdminEndpoints(app) + + app.Use(filesystem.New(filesystem.Config{ + Root: http.Dir(viper.GetString("frontend_app")), + Index: "index.html", + NotFoundFile: "index.html", + MaxAge: 3600, })) - api.MapAPIs(A) - admin.MapAdminEndpoints(A) - ui.MapUserInterface(A) + app.Use(favicon.New(favicon.Config{ + File: filepath.Join(viper.GetString("frontend_app"), "favicon.png"), + URL: "/favicon.png", + })) + + return &HTTPApp{app} } -func Listen() { - if err := A.Listen(viper.GetString("bind")); err != nil { +func (v *HTTPApp) Listen() { + if err := v.app.Listen(viper.GetString("bind")); err != nil { log.Fatal().Err(err).Msg("An error occurred when starting server...") } } diff --git a/pkg/internal/server/ui/accounts.go b/pkg/internal/server/ui/accounts.go deleted file mode 100644 index e4ec045..0000000 --- a/pkg/internal/server/ui/accounts.go +++ /dev/null @@ -1,55 +0,0 @@ -package ui - -import ( - "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" - "html/template" - "time" - - "git.solsynth.dev/hydrogen/passport/pkg/internal/database" - "git.solsynth.dev/hydrogen/passport/pkg/internal/models" - "github.com/gofiber/fiber/v2" - "github.com/gomarkdown/markdown" - "github.com/gomarkdown/markdown/html" - "github.com/gomarkdown/markdown/parser" - "github.com/sujit-baniya/flash" -) - -func selfUserinfoPage(c *fiber.Ctx) error { - if err := exts.EnsureAuthenticated(c); err != nil { - return DoAuthRedirect(c) - } - user := c.Locals("user").(models.Account) - - var data models.Account - if err := database.C. - Where(&models.Account{BaseModel: models.BaseModel{ID: user.ID}}). - Preload("Profile"). - Preload("PersonalPage"). - Preload("Contacts"). - First(&data).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - birthday := "Unknown" - if data.Profile.Birthday != nil { - birthday = data.Profile.Birthday.Format(time.RFC822) - } - - doc := parser. - NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock). - Parse([]byte(data.PersonalPage.Content)) - - renderer := html.NewRenderer(html.RendererOptions{Flags: html.CommonFlags | html.HrefTargetBlank}) - - return c.Render("views/users/me", fiber.Map{ - "info": flash.Get(c)["message"], - "uid": fmt.Sprintf("%08d", data.ID), - "joined_at": data.CreatedAt.Format(time.RFC822), - "birthday_at": birthday, - "personal_page": template.HTML(markdown.Render(doc, renderer)), - "userinfo": data, - "avatar": data.GetAvatar(), - "banner": data.GetBanner(), - }, "views/layouts/user-center") -} diff --git a/pkg/internal/server/ui/index.go b/pkg/internal/server/ui/index.go deleted file mode 100644 index 9b1027e..0000000 --- a/pkg/internal/server/ui/index.go +++ /dev/null @@ -1,34 +0,0 @@ -package ui - -import ( - "fmt" - - "github.com/gofiber/fiber/v2" -) - -func DoAuthRedirect(c *fiber.Ctx) error { - uri := c.Request().URI().FullURI() - return c.Redirect(fmt.Sprintf("/sign-in?redirect_uri=%s", string(uri))) -} - -func MapUserInterface(app *fiber.App) { - pages := app.Group("/").Name("Pages") - - pages.Get("/", func(c *fiber.Ctx) error { - return c.Redirect("/users/me") - }) - - pages.Get("/sign-up", signupPage) - pages.Get("/sign-in", signinPage) - pages.Get("/mfa", mfaRequestPage) - pages.Get("/mfa/apply", mfaApplyPage) - pages.Get("/authorize", authorizePage) - - pages.Post("/sign-up", signupAction) - pages.Post("/sign-in", signinAction) - pages.Post("/mfa", mfaRequestAction) - pages.Post("/mfa/apply", mfaApplyAction) - pages.Post("/authorize", authorizeAction) - - pages.Get("/users/me", selfUserinfoPage) -} diff --git a/pkg/internal/server/ui/mfa.go b/pkg/internal/server/ui/mfa.go deleted file mode 100644 index 4fd8e24..0000000 --- a/pkg/internal/server/ui/mfa.go +++ /dev/null @@ -1,194 +0,0 @@ -package ui - -import ( - "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/models" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "github.com/gofiber/fiber/v2" - "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/samber/lo" - "github.com/sujit-baniya/flash" -) - -func mfaRequestPage(c *fiber.Ctx) error { - ticketId := c.QueryInt("ticket", 0) - - ticket, err := services.GetTicket(uint(ticketId)) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": "you must provide ticket id to perform multi-factor authenticate", - }).Redirect("/sign-in") - } - user, err := services.GetAccount(ticket.AccountID) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": "ticket related user just weirdly disappear", - }).Redirect("/sign-in") - } - factors, err := services.ListUserFactor(user.ID) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("unable to get your factors: %v", err.Error()), - }).Redirect("/sign-in") - } - - factors = lo.Filter(factors, func(item models.AuthFactor, index int) bool { - return item.Type != models.PasswordAuthFactor - }) - - localizer := c.Locals("localizer").(*i18n.Localizer) - - next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"}) - title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaTitle"}) - caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaCaption"}) - - return c.Render("views/mfa", fiber.Map{ - "info": flash.Get(c)["message"], - "redirect_uri": flash.Get(c)["redirect_uri"], - "ticket_id": ticket.ID, - "factors": lo.Map(factors, func(item models.AuthFactor, index int) fiber.Map { - return fiber.Map{ - "name": services.GetFactorName(item.Type, localizer), - "id": item.ID, - } - }), - "i18n": fiber.Map{ - "next": next, - "title": title, - "caption": caption, - }, - }, "views/layouts/auth") -} - -func mfaRequestAction(c *fiber.Ctx) error { - var data struct { - TicketID uint `form:"ticket_id" validate:"required"` - FactorID uint `form:"factor_id" validate:"required"` - } - - redirectBackUri := "/sign-in" - err := exts.BindAndValidate(c, &data) - - if data.TicketID > 0 { - redirectBackUri = fmt.Sprintf("/mfa?ticket=%d", data.TicketID) - } - - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": err.Error(), - }).Redirect(redirectBackUri) - } - - factor, err := services.GetFactor(data.FactorID) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("factor was not found: %v", err.Error()), - }).Redirect(redirectBackUri) - } - - _, err = services.GetFactorCode(factor) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("unable to get factor code: %v", err.Error()), - }).Redirect(redirectBackUri) - } - - return flash.WithData(c, fiber.Map{ - "redirect_uri": exts.GetRedirectUri(c), - }).Redirect(fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, factor.ID)) -} - -func mfaApplyPage(c *fiber.Ctx) error { - ticketId := c.QueryInt("ticket", 0) - factorId := c.QueryInt("factor", 0) - - ticket, err := services.GetTicket(uint(ticketId)) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("unable to find your ticket: %v", err.Error()), - }).Redirect("/sign-in") - } - factor, err := services.GetFactor(uint(factorId)) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("unable to find your factors: %v", err.Error()), - }).Redirect("/sign-in") - } - - localizer := c.Locals("localizer").(*i18n.Localizer) - - next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"}) - password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"}) - title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaTitle"}) - caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaCaption"}) - - return c.Render("views/mfa-apply", fiber.Map{ - "info": flash.Get(c)["message"], - "label": services.GetFactorName(factor.Type, localizer), - "ticket_id": ticket.ID, - "factor_id": factor.ID, - "i18n": fiber.Map{ - "next": next, - "password": password, - "title": title, - "caption": caption, - }, - }, "views/layouts/auth") -} - -func mfaApplyAction(c *fiber.Ctx) error { - var data struct { - TicketID uint `form:"ticket_id" validate:"required"` - FactorID uint `form:"factor_id" validate:"required"` - Code string `form:"code" validate:"required"` - } - - redirectBackUri := "/sign-in" - err := exts.BindAndValidate(c, &data) - - if data.TicketID > 0 { - redirectBackUri = fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, data.FactorID) - } - - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": err.Error(), - }).Redirect(redirectBackUri) - } - - ticket, err := services.GetTicket(data.TicketID) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("unable to find your ticket: %v", err.Error()), - }).Redirect("/sign-in") - } - factor, err := services.GetFactor(data.FactorID) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("factor was not found: %v", err.Error()), - }).Redirect(redirectBackUri) - } - - ticket, err = services.ActiveTicketWithMFA(ticket, factor, data.Code) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("invalid multi-factor authenticate code: %v", err.Error()), - }).Redirect(redirectBackUri) - } else if ticket.IsAvailable() != nil { - return flash.WithInfo(c, fiber.Map{ - "message": "ticket weirdly still unavailable after multi-factor authenticate", - }).Redirect("/sign-in") - } - - access, refresh, err := services.ExchangeToken(*ticket.GrantToken) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("failed to exchange token: %v", err.Error()), - }).Redirect("/sign-in") - } else { - exts.SetAuthCookies(c, access, refresh) - } - - return c.Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/users/me"))) -} diff --git a/pkg/internal/server/ui/oauth.go b/pkg/internal/server/ui/oauth.go deleted file mode 100644 index 946a17c..0000000 --- a/pkg/internal/server/ui/oauth.go +++ /dev/null @@ -1,166 +0,0 @@ -package ui - -import ( - "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/database" - "git.solsynth.dev/hydrogen/passport/pkg/internal/models" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "github.com/gofiber/fiber/v2" - "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/samber/lo" - "github.com/sujit-baniya/flash" - "html/template" - "strings" - "time" -) - -func authorizePage(c *fiber.Ctx) error { - localizer := c.Locals("localizer").(*i18n.Localizer) - - if err := exts.EnsureAuthenticated(c); err != nil { - return DoAuthRedirect(c) - } - user := c.Locals("user").(models.Account) - - id := c.Query("client_id") - redirect := c.Query("redirect_uri") - - var message string - if len(id) <= 0 || len(redirect) <= 0 { - message = "invalid request, missing query parameters" - } - - var client models.ThirdClient - if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil { - message = fmt.Sprintf("unable to find client: %v", err) - } else if !client.IsDraft && !lo.Contains(client.Callbacks, strings.Split(redirect, "?")[0]) { - message = "invalid callback url" - } - - var ticket models.AuthTicket - if err := database.C.Where(&models.AuthTicket{ - AccountID: user.ID, - ClientID: &client.ID, - }).Where("last_grant_at IS NULL").First(&ticket).Error; err == nil { - if !(ticket.ExpiredAt != nil && ticket.ExpiredAt.Unix() < time.Now().Unix()) { - ticket, err = services.RegenSession(ticket) - if c.Query("response_type") == "code" { - return c.Redirect(fmt.Sprintf( - "%s?code=%s&state=%s", - redirect, - *ticket.GrantToken, - c.Query("state"), - )) - } else if c.Query("response_type") == "token" { - if access, refresh, err := services.GetToken(ticket); err == nil { - return c.Redirect(fmt.Sprintf("%s?access_token=%s&refresh_token=%s&state=%s", - redirect, - access, - refresh, c.Query("state"), - )) - } - } - } - } - - decline, _ := localizer.LocalizeMessage(&i18n.Message{ID: "decline"}) - approve, _ := localizer.LocalizeMessage(&i18n.Message{ID: "approve"}) - title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "authorizeTitle"}) - caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "authorizeCaption"}) - - qs := "/authorize?" + string(c.Request().URI().QueryString()) - - return c.Render("views/authorize", fiber.Map{ - "info": lo.Ternary[any](len(message) > 0, message, flash.Get(c)["message"]), - "client": client, - "scopes": strings.Split(c.Query("scope"), " "), - "action_url": template.URL(qs), - "i18n": fiber.Map{ - "approve": approve, - "decline": decline, - "title": title, - "caption": caption, - }, - }, "views/layouts/auth") -} - -func authorizeAction(c *fiber.Ctx) error { - if err := exts.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - id := c.Query("client_id") - response := c.Query("response_type") - redirect := c.Query("redirect_uri") - scope := c.Query("scope") - - if err := exts.EnsureAuthenticated(c); err != nil { - return DoAuthRedirect(c) - } - - redirectBackUri := "/authorize?" + string(c.Request().URI().QueryString()) - - if len(scope) <= 0 { - return flash.WithInfo(c, fiber.Map{ - "message": "invalid request parameters", - }).Redirect(redirectBackUri) - } - - var client models.ThirdClient - if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - - switch response { - case "code": - // OAuth Authorization Mode - ticket, err := services.NewOauthTicket( - user, - client, - strings.Split(scope, " "), - []string{"passport", client.Alias}, - c.IP(), - c.Get(fiber.HeaderUserAgent), - ) - - if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } else { - services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent)) - return c.Redirect(fmt.Sprintf( - "%s?code=%s&state=%s", - redirect, - *ticket.GrantToken, - c.Query("state"), - )) - } - case "token": - // OAuth Implicit Mode - ticket, err := services.NewOauthTicket( - user, - client, - strings.Split(scope, " "), - []string{"passport", client.Alias}, - c.IP(), - c.Get(fiber.HeaderUserAgent), - ) - - if err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } else if access, refresh, err := services.GetToken(ticket); err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } else { - services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent)) - return c.Redirect(fmt.Sprintf("%s?access_token=%s&refresh_token=%s&state=%s", - redirect, - access, - refresh, c.Query("state"), - )) - } - default: - return flash.WithInfo(c, fiber.Map{ - "message": "unsupported response type", - }).Redirect(redirectBackUri) - } -} diff --git a/pkg/internal/server/ui/signin.go b/pkg/internal/server/ui/signin.go deleted file mode 100644 index df87970..0000000 --- a/pkg/internal/server/ui/signin.go +++ /dev/null @@ -1,93 +0,0 @@ -package ui - -import ( - "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "github.com/gofiber/fiber/v2" - "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/samber/lo" - "github.com/sujit-baniya/flash" -) - -func signinPage(c *fiber.Ctx) error { - localizer := c.Locals("localizer").(*i18n.Localizer) - - next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"}) - username, _ := localizer.LocalizeMessage(&i18n.Message{ID: "username"}) - password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"}) - signup, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupTitle"}) - title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinTitle"}) - caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinCaption"}) - requiredNotify, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinRequired"}) - - var info any - if flash.Get(c)["message"] != nil { - info = flash.Get(c)["message"] - } else { - info = requiredNotify - } - - return c.Render("views/signin", fiber.Map{ - "info": info, - "i18n": fiber.Map{ - "next": next, - "username": username, - "password": password, - "signup": signup, - "title": title, - "caption": caption, - }, - }, "views/layouts/auth") -} - -func signinAction(c *fiber.Ctx) error { - var data struct { - Username string `form:"username" validate:"required"` - Password string `form:"password" validate:"required"` - } - - if err := exts.BindAndValidate(c, &data); err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": err.Error(), - }).Redirect("/sign-in") - } - - user, err := services.LookupAccount(data.Username) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("account was not found: %v", err.Error()), - }).Redirect("/sign-in") - } - - ticket, err := services.NewTicket(user, c.IP(), c.Get(fiber.HeaderUserAgent)) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("unable setup ticket: %v", err.Error()), - }).Redirect("/sign-in") - } - - ticket, err = services.ActiveTicketWithPassword(ticket, data.Password) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("invalid password: %v", err.Error()), - }).Redirect("/sign-in") - } - - if ticket.IsAvailable() != nil { - return flash.WithData(c, fiber.Map{ - "redirect_uri": exts.GetRedirectUri(c), - }).Redirect(fmt.Sprintf("/mfa?ticket=%d", ticket.ID)) - } - - access, refresh, err := services.ExchangeToken(*ticket.GrantToken) - if err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("failed to exchange token: %v", err.Error()), - }).Redirect("/sign-in") - } else { - exts.SetAuthCookies(c, access, refresh) - } - - return c.Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/users/me"))) -} diff --git a/pkg/internal/server/ui/signup.go b/pkg/internal/server/ui/signup.go deleted file mode 100644 index 28867a2..0000000 --- a/pkg/internal/server/ui/signup.go +++ /dev/null @@ -1,87 +0,0 @@ -package ui - -import ( - "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/database" - "git.solsynth.dev/hydrogen/passport/pkg/internal/models" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "github.com/gofiber/fiber/v2" - "github.com/nicksnyder/go-i18n/v2/i18n" - "github.com/samber/lo" - "github.com/spf13/viper" - "github.com/sujit-baniya/flash" -) - -func signupPage(c *fiber.Ctx) error { - localizer := c.Locals("localizer").(*i18n.Localizer) - - next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"}) - email, _ := localizer.LocalizeMessage(&i18n.Message{ID: "email"}) - nickname, _ := localizer.LocalizeMessage(&i18n.Message{ID: "nickname"}) - username, _ := localizer.LocalizeMessage(&i18n.Message{ID: "username"}) - password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"}) - magicToken, _ := localizer.LocalizeMessage(&i18n.Message{ID: "magicToken"}) - signin, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinTitle"}) - title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupTitle"}) - caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupCaption"}) - - return c.Render("views/signup", fiber.Map{ - "info": flash.Get(c)["message"], - "use_magic_token": viper.GetBool("use_registration_magic_token"), - "i18n": fiber.Map{ - "next": next, - "email": email, - "username": username, - "nickname": nickname, - "password": password, - "magic_token": magicToken, - "signin": signin, - "title": title, - "caption": caption, - }, - }, "views/layouts/auth") -} - -func signupAction(c *fiber.Ctx) error { - var data struct { - Name string `form:"name" validate:"required,lowercase,alphanum,min=4,max=16"` - Nick string `form:"nick" validate:"required,min=4,max=24"` - Email string `form:"email" validate:"required,email"` - Password string `form:"password" validate:"required,min=4,max=32"` - MagicToken string `form:"magic_token"` - } - - if err := exts.BindAndValidate(c, &data); err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": err.Error(), - }).Redirect("/sign-up") - } else if viper.GetBool("use_registration_magic_token") && len(data.MagicToken) <= 0 { - return flash.WithInfo(c, fiber.Map{ - "message": "magic token was required", - }).Redirect("/sign-up") - } else if viper.GetBool("use_registration_magic_token") { - if tk, err := services.ValidateMagicToken(data.MagicToken, models.RegistrationMagicToken); err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": fmt.Sprintf("magic token was invalid: %v", err.Error()), - }).Redirect("/sign-up") - } else { - database.C.Delete(&tk) - } - } - - if _, err := services.CreateAccount( - data.Name, - data.Nick, - data.Email, - data.Password, - ); err != nil { - return flash.WithInfo(c, fiber.Map{ - "message": err.Error(), - }).Redirect("/sign-up") - } else { - return flash.WithInfo(c, fiber.Map{ - "message": "account has been created. now you can sign in!", - }).Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/sign-in"))) - } -} diff --git a/pkg/internal/views/authorize.gohtml b/pkg/internal/views/authorize.gohtml deleted file mode 100644 index c98e6a4..0000000 --- a/pkg/internal/views/authorize.gohtml +++ /dev/null @@ -1,56 +0,0 @@ -
- - -

{{.i18n.title}} {{.client.Name}}

-

{{.i18n.caption}}

-
- -
-
- -
-
-
Description
-
{{.client.Description}}
-
- -
-
Requested scopes
-
    - {{range $_, $element := .scopes}} -
  • - {{$element}} -
  • - {{end}} -
-
- -
- - -
-
-
- - - - diff --git a/pkg/internal/views/favicon.png b/pkg/internal/views/favicon.png deleted file mode 100644 index f044b34df84073636a051563b640ecd96ba03af7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76090 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 z 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 D2aOqE diff --git a/pkg/internal/views/index.gohtml b/pkg/internal/views/index.gohtml deleted file mode 100644 index c0c265f..0000000 --- a/pkg/internal/views/index.gohtml +++ /dev/null @@ -1,10 +0,0 @@ - - - -{{template "views/partials/header"}} - - -{{embed}} - - - \ No newline at end of file diff --git a/pkg/internal/views/layouts/auth.gohtml b/pkg/internal/views/layouts/auth.gohtml deleted file mode 100644 index 94815ea..0000000 --- a/pkg/internal/views/layouts/auth.gohtml +++ /dev/null @@ -1,115 +0,0 @@ - - - -{{template "views/partials/header"}} - - -

-
- {{if ne .info nil}} - - {{end}} - -
- {{embed}} -
-
-
- - - - - diff --git a/pkg/internal/views/layouts/user-center.gohtml b/pkg/internal/views/layouts/user-center.gohtml deleted file mode 100644 index 4828bd7..0000000 --- a/pkg/internal/views/layouts/user-center.gohtml +++ /dev/null @@ -1,128 +0,0 @@ - - - -{{template "views/partials/header"}} - - -
-
- {{if ne .info nil}} - - {{end}} - -
- {{embed}} -
-
-
- - - - - diff --git a/pkg/internal/views/mfa-apply.gohtml b/pkg/internal/views/mfa-apply.gohtml deleted file mode 100644 index 187ce82..0000000 --- a/pkg/internal/views/mfa-apply.gohtml +++ /dev/null @@ -1,43 +0,0 @@ -
- - -

{{.i18n.title}}

-

{{.i18n.caption}}

-
- -
-
- -
- - - -
{{.label}}
- -
- - -
- -
- -
-
-
- - diff --git a/pkg/internal/views/mfa.gohtml b/pkg/internal/views/mfa.gohtml deleted file mode 100644 index 8372c07..0000000 --- a/pkg/internal/views/mfa.gohtml +++ /dev/null @@ -1,59 +0,0 @@ -
- - -

{{.i18n.title}}

-

{{.i18n.caption}}

-
- -
-
- -
- - {{if ne .redirect_uri nil}} - - {{end}} - -
- {{range $_, $element := .factors}} -
-
- - -
-
- {{end}} -
- -
- -
-
-
- - diff --git a/pkg/internal/views/partials/header.gohtml b/pkg/internal/views/partials/header.gohtml deleted file mode 100644 index 09202f3..0000000 --- a/pkg/internal/views/partials/header.gohtml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - Solarpass - - - diff --git a/pkg/internal/views/signin.gohtml b/pkg/internal/views/signin.gohtml deleted file mode 100644 index beef18e..0000000 --- a/pkg/internal/views/signin.gohtml +++ /dev/null @@ -1,27 +0,0 @@ -
- - -

{{.i18n.title}}

-

{{.i18n.caption}}

-
- -
diff --git a/pkg/internal/views/signup.gohtml b/pkg/internal/views/signup.gohtml deleted file mode 100644 index 2f88f97..0000000 --- a/pkg/internal/views/signup.gohtml +++ /dev/null @@ -1,47 +0,0 @@ -
- - -

{{.i18n.title}}

-

{{.i18n.caption}}

-
- -
-
- -
-
-
- - -
- -
- - -
-
- - -
- - -
- -
- - -
- - {{if eq .use_magic_token true}} -
- - -
- {{end}} - -
- {{.i18n.signin}} - -
-
-
diff --git a/pkg/internal/views/users/me.gohtml b/pkg/internal/views/users/me.gohtml deleted file mode 100644 index 63c8be1..0000000 --- a/pkg/internal/views/users/me.gohtml +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - -
- {{if ne .userinfo.Avatar nil}} - Avatar - {{else}} -
- account_circle -
- {{end}} - -
-

{{.userinfo.Nick}}

-
@{{.userinfo.Name}}
-
- {{if gt (len .userinfo.Description) 0}} -
{{.userinfo.Description}}
- {{else}} -
No description yet.
- {{end}} -
#{{.uid}}
-
- -
-
- {{.personal_page}} -
-
- - diff --git a/pkg/main.go b/pkg/main.go index e6026f5..636fc1f 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -58,12 +58,10 @@ func main() { } // Server - server.NewServer() - go server.Listen() + go server.NewServer().Listen() // Grpc Server - grpc.NewGRPC() - go grpc.ListenGRPC() + go grpc.NewServer().Listen() // Configure timed tasks quartz := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(&log.Logger))) diff --git a/settings.toml b/settings.toml index 7c60c2a..5344981 100644 --- a/settings.toml +++ b/settings.toml @@ -1,5 +1,7 @@ id = "passport01" +frontend_app = "web/dist" + bind = "0.0.0.0:8444" grpc_bind = "0.0.0.0:7444" domain = "localhost" diff --git a/web/.eslintrc.cjs b/web/.eslintrc.cjs new file mode 100755 index 0000000..11cf3e4 --- /dev/null +++ b/web/.eslintrc.cjs @@ -0,0 +1,18 @@ +/* eslint-env node */ +require("@rushstack/eslint-patch/modern-module-resolution") + +module.exports = { + root: true, + extends: [ + "plugin:vue/vue3-essential", + "eslint:recommended", + "@vue/eslint-config-typescript", + "@vue/eslint-config-prettier/skip-formatting", + ], + parserOptions: { + ecmaVersion: "latest", + }, + rules: { + "vue/multi-word-component-names": "off", + } +} diff --git a/web/.gitignore b/web/.gitignore new file mode 100755 index 0000000..8ee54e8 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/web/.prettierrc.json b/web/.prettierrc.json new file mode 100755 index 0000000..6404b10 --- /dev/null +++ b/web/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": false, + "printWidth": 120, + "trailingComma": "all" +} diff --git a/web/README.md b/web/README.md new file mode 100755 index 0000000..bdb10ae --- /dev/null +++ b/web/README.md @@ -0,0 +1,39 @@ +# views + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/web/bun.lockb b/web/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..9a924394fcc1a6c65fb50797bf7370075c9eb345 GIT binary patch literal 155500 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

J^q6>e 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 diff --git a/web/index.html b/web/index.html new file mode 100755 index 0000000..c61a7b4 --- /dev/null +++ b/web/index.html @@ -0,0 +1,13 @@ + + + + + + + Solarpass + + +

+ + + diff --git a/web/package.json b/web/package.json new file mode 100755 index 0000000..098325b --- /dev/null +++ b/web/package.json @@ -0,0 +1,45 @@ +{ + "name": "passport-web", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "@fontsource/roboto": "^5.0.13", + "@mdi/font": "^7.4.47", + "@unocss/reset": "^0.58.9", + "dompurify": "^3.1.5", + "marked": "^12.0.2", + "pinia": "^2.1.7", + "universal-cookie": "^7.1.4", + "unocss": "^0.58.9", + "vue": "^3.4.30", + "vue-router": "^4.4.0", + "vuetify": "^3.6.10" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.10.3", + "@tsconfig/node20": "^20.1.4", + "@types/dompurify": "^3.0.5", + "@types/node": "^20.14.8", + "@vitejs/plugin-vue": "^5.0.5", + "@vitejs/plugin-vue-jsx": "^3.1.0", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/tsconfig": "^0.5.1", + "eslint": "^8.57.0", + "eslint-plugin-vue": "^9.26.0", + "npm-run-all2": "^6.2.0", + "prettier": "^3.3.2", + "typescript": "^5.4.5", + "vite": "^5.3.1", + "vue-tsc": "^2.0.22" + } +} diff --git a/web/public/favicon.png b/web/public/favicon.png new file mode 100755 index 0000000000000000000000000000000000000000..2ca2d074c6ca4713375dd395ae7153a1b99a9239 GIT binary patch literal 77150 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 + diff --git a/web/src/components/NotificationList.vue b/web/src/components/NotificationList.vue new file mode 100755 index 0000000..7f3cfd8 --- /dev/null +++ b/web/src/components/NotificationList.vue @@ -0,0 +1,70 @@ + + + diff --git a/web/src/components/UserMenu.vue b/web/src/components/UserMenu.vue new file mode 100755 index 0000000..10a1c28 --- /dev/null +++ b/web/src/components/UserMenu.vue @@ -0,0 +1,43 @@ + + + diff --git a/web/src/components/auth/AccountLocator.vue b/web/src/components/auth/AccountLocator.vue new file mode 100755 index 0000000..2a45c90 --- /dev/null +++ b/web/src/components/auth/AccountLocator.vue @@ -0,0 +1,61 @@ + + + diff --git a/web/src/components/auth/CallbackNotify.vue b/web/src/components/auth/CallbackNotify.vue new file mode 100755 index 0000000..d63c6d6 --- /dev/null +++ b/web/src/components/auth/CallbackNotify.vue @@ -0,0 +1,16 @@ + + + diff --git a/web/src/components/auth/FactorApplicator.vue b/web/src/components/auth/FactorApplicator.vue new file mode 100755 index 0000000..8d92c0e --- /dev/null +++ b/web/src/components/auth/FactorApplicator.vue @@ -0,0 +1,129 @@ + + + diff --git a/web/src/components/auth/FactorPicker.vue b/web/src/components/auth/FactorPicker.vue new file mode 100755 index 0000000..b107398 --- /dev/null +++ b/web/src/components/auth/FactorPicker.vue @@ -0,0 +1,75 @@ + + + diff --git a/web/src/index.vue b/web/src/index.vue new file mode 100755 index 0000000..4f21c35 --- /dev/null +++ b/web/src/index.vue @@ -0,0 +1,5 @@ + diff --git a/web/src/layouts/master.vue b/web/src/layouts/master.vue new file mode 100755 index 0000000..4b1d5c9 --- /dev/null +++ b/web/src/layouts/master.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/web/src/layouts/user-center.vue b/web/src/layouts/user-center.vue new file mode 100755 index 0000000..ddb0690 --- /dev/null +++ b/web/src/layouts/user-center.vue @@ -0,0 +1,22 @@ + + \ No newline at end of file diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100755 index 0000000..b3665d3 --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,54 @@ +import "virtual:uno.css" + +import "./assets/utils.css" + +import { createApp } from "vue" +import { createPinia } from "pinia" + +import "vuetify/styles" +import { createVuetify } from "vuetify" +import { md3 } from "vuetify/blueprints" +import * as components from "vuetify/components" +import * as labsComponents from "vuetify/labs/components" +import * as directives from "vuetify/directives" + +import "@mdi/font/css/materialdesignicons.min.css" +import "@fontsource/roboto/latin.css" +import "@unocss/reset/tailwind.css" + +import index from "./index.vue" +import router from "./router" + +const app = createApp(index) + +app.use( + createVuetify({ + directives, + components: { + ...components, + ...labsComponents, + }, + blueprint: md3, + theme: { + defaultTheme: "original", + themes: { + original: { + colors: { + primary: "#4a5099", + secondary: "#2196f3", + accent: "#009688", + error: "#f44336", + warning: "#ff9800", + info: "#03a9f4", + success: "#4caf50", + }, + }, + }, + }, + }), +) + +app.use(createPinia()) +app.use(router) + +app.mount("#app") diff --git a/web/src/router/index.ts b/web/src/router/index.ts new file mode 100755 index 0000000..e9eea4b --- /dev/null +++ b/web/src/router/index.ts @@ -0,0 +1,96 @@ +import { createRouter, createWebHistory } from "vue-router" +import { useUserinfo } from "@/stores/userinfo" +import MasterLayout from "@/layouts/master.vue" +import UserCenterLayout from "@/layouts/user-center.vue" + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: "/", + component: MasterLayout, + children: [ + { + path: "/", + component: UserCenterLayout, + children: [ + { + path: "/", + name: "dashboard", + component: () => import("@/views/dashboard.vue"), + meta: { title: "Your account" }, + }, + { + path: "/me/personalize", + name: "personalize", + component: () => import("@/views/personalize.vue"), + meta: { title: "Your personality" }, + }, + { + path: "/me/personal-page", + name: "personal-page", + component: () => import("@/views/personal-page.vue"), + meta: { title: "Your personal page" }, + }, + { + path: "/me/security", + name: "security", + component: () => import("@/views/security.vue"), + meta: { title: "Your security" }, + }, + ], + }, + ], + }, + { + path: "/auth", + children: [ + { + path: "sign-in", + name: "auth.sign-in", + component: () => import("@/views/auth/sign-in.vue"), + meta: { public: true, title: "Sign in" }, + }, + { + path: "sign-up", + name: "auth.sign-up", + component: () => import("@/views/auth/sign-up.vue"), + meta: { public: true, title: "Sign up" }, + }, + { + path: "o/connect", + name: "openid.connect", + component: () => import("@/views/auth/connect.vue"), + }, + + { + path: "/me/confirm", + name: "callback.confirm", + component: () => import("@/views/confirm.vue"), + meta: { public: true, title: "Confirm registration" }, + }, + ], + }, + ], +}) + +router.beforeEach(async (to, from, next) => { + const id = useUserinfo() + if (!id.isReady) { + await id.readProfiles() + } + + if (to.meta.title) { + document.title = `Solarpass | ${to.meta.title}` + } else { + document.title = "Solarpass" + } + + if (!to.meta.public && !id.userinfo.isLoggedIn) { + next({ name: "auth.sign-in", query: { redirect_uri: to.fullPath } }) + } else { + next() + } +}) + +export default router diff --git a/web/src/scripts/request.ts b/web/src/scripts/request.ts new file mode 100755 index 0000000..3384bc4 --- /dev/null +++ b/web/src/scripts/request.ts @@ -0,0 +1,3 @@ +export async function request(input: string, init?: RequestInit) { + return await fetch(input, init) +} diff --git a/web/src/stores/notifications.ts b/web/src/stores/notifications.ts new file mode 100755 index 0000000..974b64c --- /dev/null +++ b/web/src/stores/notifications.ts @@ -0,0 +1,64 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { checkLoggedIn, getAtk } from "@/stores/userinfo"; +import { request } from "@/scripts/request"; + +export const useNotifications = defineStore("notifications", () => { + let socket: WebSocket; + + const loading = ref(false); + + const notifications = ref([]); + const total = ref(0) + + async function list() { + loading.value = true; + const res = await request( + "/api/notifications?" + + new URLSearchParams({ + take: (25).toString(), + offset: (0).toString() + }), + { + headers: { Authorization: `Bearer ${getAtk()}` } + } + ); + if (res.status === 200) { + const data = await res.json(); + notifications.value = data["data"]; + total.value = data["count"]; + } + loading.value = false; + } + + function remove(idx: number) { + notifications.value.splice(idx, 1) + total.value--; + } + + async function connect() { + if (!(checkLoggedIn())) return; + + const uri = `ws://${window.location.host}/api/notifications/listen`; + + socket = new WebSocket(uri + `?tk=${getAtk() as string}`); + + socket.addEventListener("open", (event) => { + console.log("[NOTIFICATIONS] The listen websocket has been established... ", event.type); + }); + socket.addEventListener("close", (event) => { + console.warn("[NOTIFICATIONS] The listen websocket is disconnected... ", event.reason, event.code); + }); + socket.addEventListener("message", (event) => { + const data = JSON.parse(event.data); + notifications.value.push(data); + total.value++; + }); + } + + function disconnect() { + socket.close(); + } + + return { loading, notifications, total, list, remove, connect, disconnect }; +}); \ No newline at end of file diff --git a/web/src/stores/userinfo.ts b/web/src/stores/userinfo.ts new file mode 100755 index 0000000..642e3f1 --- /dev/null +++ b/web/src/stores/userinfo.ts @@ -0,0 +1,54 @@ +import Cookie from "universal-cookie" +import { defineStore } from "pinia" +import { ref } from "vue" +import { request } from "@/scripts/request" + +export interface Userinfo { + isLoggedIn: boolean + displayName: string + data: any +} + +const defaultUserinfo: Userinfo = { + isLoggedIn: false, + displayName: "Citizen", + data: null, +} + +export function getAtk(): string { + return new Cookie().get("__hydrogen_atk") +} + +export function checkLoggedIn(): boolean { + return new Cookie().get("__hydrogen_rtk") +} + +export const useUserinfo = defineStore("userinfo", () => { + const userinfo = ref(defaultUserinfo) + const isReady = ref(false) + + async function readProfiles() { + if (!checkLoggedIn()) { + isReady.value = true + } + + const res = await request("/api/users/me", { + headers: { Authorization: `Bearer ${getAtk()}` }, + }) + + if (res.status !== 200) { + return + } + + const data = await res.json() + + isReady.value = true + userinfo.value = { + isLoggedIn: true, + displayName: data["nick"], + data: data, + } + } + + return { userinfo, isReady, readProfiles } +}) diff --git a/web/src/views/auth/claims.ts b/web/src/views/auth/claims.ts new file mode 100755 index 0000000..6ca79e5 --- /dev/null +++ b/web/src/views/auth/claims.ts @@ -0,0 +1,13 @@ +export interface ClaimType { + icon: string + name: string + description: string +} + +export const claims: { [id: string]: ClaimType } = { + openid: { + icon: "mdi-identifier", + name: "Open Identity", + description: "Allow them to read your personal information.", + }, +} diff --git a/web/src/views/auth/connect.vue b/web/src/views/auth/connect.vue new file mode 100755 index 0000000..e7285e3 --- /dev/null +++ b/web/src/views/auth/connect.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/web/src/views/auth/sign-in.vue b/web/src/views/auth/sign-in.vue new file mode 100755 index 0000000..dfa9fe8 --- /dev/null +++ b/web/src/views/auth/sign-in.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/web/src/views/auth/sign-up.vue b/web/src/views/auth/sign-up.vue new file mode 100755 index 0000000..a206dc3 --- /dev/null +++ b/web/src/views/auth/sign-up.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/web/src/views/confirm.vue b/web/src/views/confirm.vue new file mode 100755 index 0000000..c16b984 --- /dev/null +++ b/web/src/views/confirm.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/web/src/views/dashboard.vue b/web/src/views/dashboard.vue new file mode 100755 index 0000000..750e1c4 --- /dev/null +++ b/web/src/views/dashboard.vue @@ -0,0 +1,77 @@ + + + + + + + diff --git a/web/src/views/personal-page.vue b/web/src/views/personal-page.vue new file mode 100755 index 0000000..782b1df --- /dev/null +++ b/web/src/views/personal-page.vue @@ -0,0 +1,71 @@ + + + diff --git a/web/src/views/personalize.vue b/web/src/views/personalize.vue new file mode 100755 index 0000000..220a185 --- /dev/null +++ b/web/src/views/personalize.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/web/src/views/security.vue b/web/src/views/security.vue new file mode 100755 index 0000000..979527f --- /dev/null +++ b/web/src/views/security.vue @@ -0,0 +1,266 @@ + + + + + diff --git a/web/tsconfig.app.json b/web/tsconfig.app.json new file mode 100755 index 0000000..e14c754 --- /dev/null +++ b/web/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100755 index 0000000..66b5e57 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/web/tsconfig.node.json b/web/tsconfig.node.json new file mode 100755 index 0000000..2c669ee --- /dev/null +++ b/web/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "nightwatch.conf.*", "playwright.config.*"], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/web/uno.config.ts b/web/uno.config.ts new file mode 100755 index 0000000..2d323f7 --- /dev/null +++ b/web/uno.config.ts @@ -0,0 +1,5 @@ +import { defineConfig, presetAttributify, presetTypography, presetUno } from "unocss" + +export default defineConfig({ + presets: [presetAttributify(), presetTypography(), presetUno({ preflight: false })], +}) diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100755 index 0000000..41b2b40 --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,27 @@ +import { fileURLToPath, URL } from "node:url"; + +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import vueJsx from "@vitejs/plugin-vue-jsx"; +import unocss from "unocss/vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), vueJsx(), unocss()], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)) + } + }, + server: { + proxy: { + "/api/ws": { + target: "ws://localhost:8444", + ws: true + }, + + "/api": "http://localhost:8444", + "/.well-known": "http://localhost:8444" + } + } +}); -- 2.45.2 From 3f6474783927a686fe1fd24e16fda071d1efc5ae Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 24 Jun 2024 23:54:45 +0800 Subject: [PATCH 2/8] :recycle: Update the sign in web page to the latest API --- .idea/codeStyles/Project.xml | 59 +++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++ .idea/workspace.xml | 73 +++---------------- pkg/internal/server/api/auth_api.go | 4 +- pkg/internal/server/api/factors_api.go | 19 +++++ pkg/internal/server/api/index.go | 3 + web/src/components/Copyright.vue | 2 +- .../{AccountLocator.vue => Authenticate.vue} | 20 +++-- .../components/auth/AuthenticateCompleted.vue | 68 +++++++++++++++++ web/src/components/auth/FactorApplicator.vue | 62 ++++------------ web/src/components/auth/FactorPicker.vue | 31 +++++--- web/src/router/index.ts | 33 +++++---- .../views/auth/{connect.vue => authorize.vue} | 0 web/src/views/auth/sign-in.vue | 31 +++----- web/src/views/confirm.vue | 2 +- 15 files changed, 245 insertions(+), 167 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml rename web/src/components/auth/{AccountLocator.vue => Authenticate.vue} (65%) create mode 100644 web/src/components/auth/AuthenticateCompleted.vue rename web/src/views/auth/{connect.vue => authorize.vue} (100%) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..c0eeaef --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 72a6cdd..fca4e41 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,70 +5,19 @@

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 +

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - + - - + + + - - - - + - - - + - { + "keyToString": { + "DefaultGoTemplateProperty": "Go File", + "Go Build.Backend.executor": "Run", + "Go 构建.Backend.executor": "Run", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.go.formatter.settings.were.checked": "true", + "RunOnceActivity.go.migrated.go.modules.settings": "true", + "RunOnceActivity.go.modules.automatic.dependencies.download": "true", + "RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true", + "git-widget-placeholder": "refactor/v2", + "go.import.settings.migrated": "true", + "go.sdk.automatically.set": "true", + "last_opened_file_path": "/Users/littlesheep/Documents/Projects/Hydrogen/Passport/web", + "node.js.detected.package.eslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "run.code.analysis.last.selected.profile": "pProject Default", + "settings.editor.selected.configurable": "preferences.pluginManager", + "ts.external.directory.path": "/Users/littlesheep/Documents/Projects/Hydrogen/Passport/web/node_modules/typescript/lib", + "vue.rearranger.settings.migration": "true" }, - "keyToStringList": { - "DatabaseDriversLRU": [ - "postgresql" + "keyToStringList": { + "DatabaseDriversLRU": [ + "postgresql" ] } -}]]> +} @@ -155,7 +150,6 @@ - @@ -180,7 +174,8 @@ - true diff --git a/pkg/internal/database/migrator.go b/pkg/internal/database/migrator.go index febeaf2..61592eb 100644 --- a/pkg/internal/database/migrator.go +++ b/pkg/internal/database/migrator.go @@ -9,7 +9,6 @@ var AutoMaintainRange = []any{ &models.Account{}, &models.AuthFactor{}, &models.AccountProfile{}, - &models.AccountPage{}, &models.AccountContact{}, &models.AccountFriendship{}, &models.Badge{}, diff --git a/pkg/internal/models/accounts.go b/pkg/internal/models/accounts.go index 49bff98..df188a8 100644 --- a/pkg/internal/models/accounts.go +++ b/pkg/internal/models/accounts.go @@ -21,7 +21,6 @@ type Account struct { PermNodes datatypes.JSONMap `json:"perm_nodes"` Profile AccountProfile `json:"profile"` - PersonalPage AccountPage `json:"personal_page"` Badges []Badge `json:"badges"` Contacts []AccountContact `json:"contacts"` RealmIdentities []RealmMember `json:"realm_identities"` diff --git a/pkg/internal/models/profiles.go b/pkg/internal/models/profiles.go index 1800953..1aa5452 100644 --- a/pkg/internal/models/profiles.go +++ b/pkg/internal/models/profiles.go @@ -1,7 +1,6 @@ package models import ( - "gorm.io/datatypes" "time" ) @@ -14,18 +13,3 @@ type AccountProfile struct { Birthday *time.Time `json:"birthday"` AccountID uint `json:"account_id"` } - -type AccountPage struct { - BaseModel - - Content string `json:"content"` - Script string `json:"script"` - Style string `json:"style"` - Links datatypes.JSONSlice[AccountPageLinks] `json:"links"` - AccountID uint `json:"account_id"` -} - -type AccountPageLinks struct { - Label string `json:"label"` - Url string `json:"url"` -} diff --git a/pkg/internal/server/api/index.go b/pkg/internal/server/api/index.go index 9dbbcc1..71a28f5 100644 --- a/pkg/internal/server/api/index.go +++ b/pkg/internal/server/api/index.go @@ -26,9 +26,7 @@ func MapAPIs(app *fiber.App) { me.Put("/banner", setBanner) me.Get("/", getUserinfo) - me.Get("/page", getOwnPersonalPage) me.Put("/", editUserinfo) - me.Put("/page", editPersonalPage) me.Get("/events", getEvents) me.Get("/tickets", getTickets) me.Delete("/tickets/:ticketId", killSession) @@ -49,7 +47,6 @@ func MapAPIs(app *fiber.App) { directory := api.Group("/users/:alias").Name("User Directory") { directory.Get("/", getOtherUserinfo) - directory.Get("/page", getPersonalPage) } api.Post("/users", doRegister) diff --git a/pkg/internal/server/api/page_api.go b/pkg/internal/server/api/page_api.go deleted file mode 100644 index 77c7c43..0000000 --- a/pkg/internal/server/api/page_api.go +++ /dev/null @@ -1,76 +0,0 @@ -package api - -import ( - "git.solsynth.dev/hydrogen/passport/pkg/internal/database" - "git.solsynth.dev/hydrogen/passport/pkg/internal/models" - "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" - "github.com/gofiber/fiber/v2" -) - -func getPersonalPage(c *fiber.Ctx) error { - alias := c.Params("alias") - - var account models.Account - if err := database.C. - Where(&models.Account{Name: alias}). - First(&account).Error; err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - var page models.AccountPage - if err := database.C. - Where(&models.AccountPage{AccountID: account.ID}). - First(&page).Error; err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - return c.JSON(page) -} - -func getOwnPersonalPage(c *fiber.Ctx) error { - if err := exts.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - - var page models.AccountPage - if err := database.C. - Where(&models.AccountPage{AccountID: user.ID}). - FirstOrCreate(&page, &models.AccountPage{AccountID: user.ID}).Error; err != nil { - return fiber.NewError(fiber.StatusBadRequest, err.Error()) - } - - return c.JSON(page) -} - -func editPersonalPage(c *fiber.Ctx) error { - if err := exts.EnsureAuthenticated(c); err != nil { - return err - } - user := c.Locals("user").(models.Account) - - var data struct { - Content string `json:"content"` - Links []models.AccountPageLinks `json:"links"` - } - - if err := exts.BindAndValidate(c, &data); err != nil { - return err - } - - var page models.AccountPage - if err := database.C. - Where(&models.AccountPage{AccountID: user.ID}). - FirstOrInit(&page).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - page.Content = data.Content - page.Links = data.Links - - if err := database.C.Save(&page).Error; err != nil { - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - return c.SendStatus(fiber.StatusOK) -} diff --git a/web/src/layouts/user-center.vue b/web/src/layouts/user-center.vue index ddb0690..ca74d7e 100755 --- a/web/src/layouts/user-center.vue +++ b/web/src/layouts/user-center.vue @@ -6,7 +6,6 @@ - diff --git a/web/src/router/index.ts b/web/src/router/index.ts index c31653d..f652ab3 100755 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -30,12 +30,6 @@ const router = createRouter({ component: () => import("@/views/personalize.vue"), meta: { title: "Your personality" }, }, - { - path: "/me/personal-page", - name: "personal-page", - component: () => import("@/views/personal-page.vue"), - meta: { title: "Your personal page" }, - }, { path: "/me/security", name: "security", diff --git a/web/src/views/personal-page.vue b/web/src/views/personal-page.vue deleted file mode 100755 index 782b1df..0000000 --- a/web/src/views/personal-page.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - -- 2.45.2 From 21d3d719361ec6d82d49f84289ad2c9721e33325 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 26 Jun 2024 14:47:34 +0800 Subject: [PATCH 4/8] :recycle: OAuth authenticate --- .../723637bc-6ce3-4bbe-afb3-d88730c75a1b.xml | 1 + .idea/workspace.xml | 69 +++++----- pkg/internal/server/api/accounts_api.go | 2 +- pkg/internal/server/api/index.go | 18 ++- pkg/internal/server/api/oauth_api.go | 128 ++++++++++++++++++ pkg/internal/services/ticket.go | 2 +- web/src/components/Copyright.vue | 2 +- web/src/components/NotificationList.vue | 34 +++-- web/src/components/navigation/AppBar.vue | 49 +++++++ web/src/layouts/master.vue | 28 +--- web/src/layouts/user-center.vue | 43 +++--- web/src/router/index.ts | 43 +++--- web/src/stores/notifications.ts | 2 +- web/src/views/auth/authorize.vue | 26 ++-- web/src/views/security.vue | 121 ++++------------- 15 files changed, 328 insertions(+), 240 deletions(-) create mode 100755 pkg/internal/server/api/oauth_api.go create mode 100644 web/src/components/navigation/AppBar.vue diff --git a/.idea/dataSources/723637bc-6ce3-4bbe-afb3-d88730c75a1b.xml b/.idea/dataSources/723637bc-6ce3-4bbe-afb3-d88730c75a1b.xml index 308becf..79223f4 100644 --- a/.idea/dataSources/723637bc-6ce3-4bbe-afb3-d88730c75a1b.xml +++ b/.idea/dataSources/723637bc-6ce3-4bbe-afb3-d88730c75a1b.xml @@ -5024,6 +5024,7 @@ true posixrules 16445 + 1257512postgres diff --git a/.idea/workspace.xml b/.idea/workspace.xml index db8f3bf..0e0051e 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,15 +4,8 @@ - - @@ -175,7 +166,9 @@ - true diff --git a/pkg/internal/server/api/accounts_api.go b/pkg/internal/server/api/accounts_api.go index 8fbcc84..d2531aa 100644 --- a/pkg/internal/server/api/accounts_api.go +++ b/pkg/internal/server/api/accounts_api.go @@ -123,7 +123,7 @@ func editUserinfo(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusOK) } -func killSession(c *fiber.Ctx) error { +func killTicket(c *fiber.Ctx) error { if err := exts.EnsureAuthenticated(c); err != nil { return err } diff --git a/pkg/internal/server/api/index.go b/pkg/internal/server/api/index.go index 71a28f5..cb828b3 100644 --- a/pkg/internal/server/api/index.go +++ b/pkg/internal/server/api/index.go @@ -29,7 +29,7 @@ func MapAPIs(app *fiber.App) { me.Put("/", editUserinfo) me.Get("/events", getEvents) me.Get("/tickets", getTickets) - me.Delete("/tickets/:ticketId", killSession) + me.Delete("/tickets/:ticketId", killTicket) me.Post("/confirm", doRegisterConfirm) @@ -51,12 +51,18 @@ func MapAPIs(app *fiber.App) { api.Post("/users", doRegister) - api.Post("/auth", doAuthenticate) - api.Post("/auth/mfa", doMultiFactorAuthenticate) - api.Post("/auth/token", getToken) + auth := api.Group("/auth").Name("Auth") + { + auth.Post("/", doAuthenticate) + auth.Post("/mfa", doMultiFactorAuthenticate) + auth.Post("/token", getToken) - api.Get("/auth/factors", getAvailableFactors) - api.Post("/auth/factors/:factorId", requestFactorToken) + auth.Get("/factors", getAvailableFactors) + auth.Post("/factors/:factorId", requestFactorToken) + + auth.Get("/o/authorize", tryAuthorizeThirdClient) + auth.Post("/o/authorize", authorizeThirdClient) + } realms := api.Group("/realms").Name("Realms API") { diff --git a/pkg/internal/server/api/oauth_api.go b/pkg/internal/server/api/oauth_api.go new file mode 100755 index 0000000..4872d97 --- /dev/null +++ b/pkg/internal/server/api/oauth_api.go @@ -0,0 +1,128 @@ +package api + +import ( + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" + "strings" + "time" + + "git.solsynth.dev/hydrogen/passport/pkg/internal/database" + "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/services" + "github.com/gofiber/fiber/v2" + "github.com/samber/lo" +) + +func tryAuthorizeThirdClient(c *fiber.Ctx) error { + id := c.Query("client_id") + redirect := c.Query("redirect_uri") + + if len(id) <= 0 || len(redirect) <= 0 { + return fiber.NewError(fiber.StatusBadRequest, "invalid request, missing query parameters") + } + + var client models.ThirdClient + if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil { + return fiber.NewError(fiber.StatusNotFound, err.Error()) + } else if !client.IsDraft && !lo.Contains(client.Callbacks, strings.Split(redirect, "?")[0]) { + return fiber.NewError(fiber.StatusBadRequest, "invalid callback url") + } + + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) + + var ticket models.AuthTicket + if err := database.C.Where(&models.AuthTicket{ + AccountID: user.ID, + ClientID: &client.ID, + }).Where("last_grant_at IS NULL").First(&ticket).Error; err == nil { + if ticket.ExpiredAt != nil && ticket.ExpiredAt.Unix() < time.Now().Unix() { + return c.JSON(fiber.Map{ + "client": client, + "ticket": nil, + }) + } else { + ticket, err = services.RegenSession(ticket) + } + + return c.JSON(fiber.Map{ + "client": client, + "ticket": ticket, + }) + } + + return c.JSON(fiber.Map{ + "client": client, + "ticket": nil, + }) +} + +func authorizeThirdClient(c *fiber.Ctx) error { + id := c.Query("client_id") + response := c.Query("response_type") + redirect := c.Query("redirect_uri") + scope := c.Query("scope") + if len(scope) <= 0 { + return fiber.NewError(fiber.StatusBadRequest, "invalid request params") + } + + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) + + var client models.ThirdClient + if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil { + return fiber.NewError(fiber.StatusNotFound, err.Error()) + } + + switch response { + case "code": + // OAuth Authorization Mode + ticket, err := services.NewOauthTicket( + user, + client, + strings.Split(scope, " "), + []string{"passport", client.Alias}, + c.IP(), + c.Get(fiber.HeaderUserAgent), + ) + + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } else { + services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent)) + return c.JSON(fiber.Map{ + "ticket": ticket, + "redirect_uri": redirect, + }) + } + case "token": + // OAuth Implicit Mode + ticket, err := services.NewOauthTicket( + user, + client, + strings.Split(scope, " "), + []string{"passport", client.Alias}, + c.IP(), + c.Get(fiber.HeaderUserAgent), + ) + + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } else if access, refresh, err := services.GetToken(ticket); err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } else { + services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent)) + return c.JSON(fiber.Map{ + "access_token": access, + "refresh_token": refresh, + "redirect_uri": redirect, + "ticket": ticket, + }) + } + default: + return fiber.NewError(fiber.StatusBadRequest, "unsupported response type") + } +} diff --git a/pkg/internal/services/ticket.go b/pkg/internal/services/ticket.go index 7039e0c..e2b9c15 100644 --- a/pkg/internal/services/ticket.go +++ b/pkg/internal/services/ticket.go @@ -81,7 +81,7 @@ func NewOauthTicket( AccessToken: lo.ToPtr(uuid.NewString()), RefreshToken: lo.ToPtr(uuid.NewString()), AvailableAt: lo.ToPtr(time.Now()), - ExpiredAt: lo.ToPtr(time.Now()), + ExpiredAt: lo.ToPtr(time.Now().Add(7 * 24 * time.Hour)), ClientID: &client.ID, AccountID: user.ID, } diff --git a/web/src/components/Copyright.vue b/web/src/components/Copyright.vue index 8bca377..873ab83 100755 --- a/web/src/components/Copyright.vue +++ b/web/src/components/Copyright.vue @@ -1,6 +1,6 @@ diff --git a/web/src/components/NotificationList.vue b/web/src/components/NotificationList.vue index 7f3cfd8..2c5b79d 100755 --- a/web/src/components/NotificationList.vue +++ b/web/src/components/NotificationList.vue @@ -1,23 +1,17 @@ - + Something went wrong... {{ error }} @@ -39,8 +34,11 @@ + + diff --git a/web/src/layouts/master.vue b/web/src/layouts/master.vue index 4b1d5c9..6c8ef89 100755 --- a/web/src/layouts/master.vue +++ b/web/src/layouts/master.vue @@ -1,22 +1,5 @@