diff --git a/api/shortcut.go b/api/shortcut.go index 373db21..80054f5 100644 --- a/api/shortcut.go +++ b/api/shortcut.go @@ -4,6 +4,8 @@ package api type Visibility string const ( + // VisibilityPublic is the PUBLIC visibility. + VisibilityPublic Visibility = "PUBLIC" // VisibilityWorkspace is the WORKSPACE visibility. VisibilityWorkspace Visibility = "WORKSPACE" // VisibilityPrivite is the PRIVATE visibility. @@ -12,6 +14,8 @@ const ( func (e Visibility) String() string { switch e { + case VisibilityPublic: + return "PUBLIC" case VisibilityWorkspace: return "WORKSPACE" case VisibilityPrivite: diff --git a/server/acl.go b/server/acl.go index dae7933..11c0aba 100644 --- a/server/acl.go +++ b/server/acl.go @@ -60,7 +60,9 @@ func aclMiddleware(s *Server, next echo.HandlerFunc) echo.HandlerFunc { return next(c) } - if common.HasPrefixes(path, "/api/ping", "/api/status", "/api/user/:id") && c.Request().Method == http.MethodGet { + println("path", path) + + if common.HasPrefixes(path, "/api/ping", "/api/status", "/api/user/:id", "/api/workspace/:workspaceName/shortcut/:shortcutName") && c.Request().Method == http.MethodGet { return next(c) } diff --git a/server/workspace.go b/server/workspace.go index 48be091..e8d2539 100644 --- a/server/workspace.go +++ b/server/workspace.go @@ -92,11 +92,6 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) { g.GET("/workspace/:workspaceName/shortcut/:shortcutName", func(c echo.Context) error { ctx := c.Request().Context() - userID, ok := c.Get(getUserIDContextKey()).(int) - if !ok { - return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") - } - workspaceName := c.Param("workspaceName") shortcutName := c.Param("shortcutName") if workspaceName == "" || shortcutName == "" { @@ -113,20 +108,6 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find workspace with name %s", workspaceName)).SetInternal(err) } - workspaceUser, err := s.Store.FindWordspaceUser(ctx, &api.WorkspaceUserFind{ - WorkspaceID: &workspace.ID, - UserID: &userID, - }) - if err != nil { - if common.ErrorCode(err) == common.NotFound { - return echo.NewHTTPError(http.StatusNotFound, "workspace user not found") - } - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace user").SetInternal(err) - } - if workspaceUser == nil { - return echo.NewHTTPError(http.StatusUnauthorized, "not workspace user") - } - shortcut, err := s.Store.FindShortcut(ctx, &api.ShortcutFind{ WorkspaceID: &workspace.ID, Name: &shortcutName, @@ -138,6 +119,27 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find shortcut with name %s", shortcutName)).SetInternal(err) } + if shortcut.Visibility != api.VisibilityPublic { + userID, ok := c.Get(getUserIDContextKey()).(int) + if !ok { + return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") + } + + workspaceUser, err := s.Store.FindWordspaceUser(ctx, &api.WorkspaceUserFind{ + WorkspaceID: &workspace.ID, + UserID: &userID, + }) + if err != nil { + if common.ErrorCode(err) == common.NotFound { + return echo.NewHTTPError(http.StatusNotFound, "workspace user not found") + } + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace user").SetInternal(err) + } + if workspaceUser == nil { + return echo.NewHTTPError(http.StatusUnauthorized, "not workspace user") + } + } + c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8) if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(shortcut)); err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode shortcut response").SetInternal(err) diff --git a/store/db/migration/dev/LATEST__SCHEMA.sql b/store/db/migration/dev/LATEST__SCHEMA.sql index 3c2b2f1..c646c7b 100644 --- a/store/db/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/migration/dev/LATEST__SCHEMA.sql @@ -116,7 +116,7 @@ CREATE TABLE shortcut ( name TEXT NOT NULL, link TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', - visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE')) DEFAULT 'PRIVATE', + visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE', 'PUBLIC')) DEFAULT 'PRIVATE', FOREIGN KEY(creator_id) REFERENCES user(id) ON DELETE CASCADE, FOREIGN KEY(workspace_id) REFERENCES workspace(id) ON DELETE CASCADE ); diff --git a/store/db/seed/10002__workspace.sql b/store/db/seed/10002__workspace.sql index 0ca0b8a..09e6950 100644 --- a/store/db/seed/10002__workspace.sql +++ b/store/db/seed/10002__workspace.sql @@ -9,6 +9,6 @@ VALUES ( 11, 101, - 'Demo', + 'demo', '' ); diff --git a/store/db/seed/10004__shortcut.sql b/store/db/seed/10004__shortcut.sql index dfa0457..43d0fa6 100644 --- a/store/db/seed/10004__shortcut.sql +++ b/store/db/seed/10004__shortcut.sql @@ -16,3 +16,22 @@ VALUES '百度搜索', 'WORKSPACE' ); + +INSERT INTO + shortcut ( + `creator_id`, + `workspace_id`, + `name`, + `link`, + `description`, + `visibility` + ) +VALUES + ( + 102, + 11, + 'bl', + 'https://bilibili.com', + 'B站', + 'PUBLIC' + ); diff --git a/web/src/App.tsx b/web/src/App.tsx index 8f5fe84..7ddd805 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { Route, Routes, useNavigate } from "react-router-dom"; +import { Route, Routes, useLocation, useNavigate } from "react-router-dom"; import { userService, workspaceService } from "./services"; import useLoading from "./hooks/useLoading"; import Only from "./components/common/OnlyWhen"; @@ -9,11 +9,27 @@ import WorkspaceDetail from "./pages/WorkspaceDetail"; import UserDetail from "./pages/UserDetail"; import ShortcutRedirector from "./pages/ShortcutRedirector"; +const pathnameWhitelist = [/\/.+?\/go\/.+/]; + function App() { const navigate = useNavigate(); + const location = useLocation(); const pageLoadingStatus = useLoading(); useEffect(() => { + let needAuth = true; + + for (const regexp of pathnameWhitelist) { + if (regexp.test(location.pathname)) { + needAuth = false; + break; + } + } + if (!needAuth) { + pageLoadingStatus.setFinish(); + return; + } + userService.initialState().finally(() => { if (!userService.getState().user) { pageLoadingStatus.setFinish(); diff --git a/web/src/components/CreateShortcutDialog.tsx b/web/src/components/CreateShortcutDialog.tsx index db44e69..98a77ab 100644 --- a/web/src/components/CreateShortcutDialog.tsx +++ b/web/src/components/CreateShortcutDialog.tsx @@ -148,7 +148,7 @@ const CreateShortcutDialog: React.FC = (props: Props) => { checked={state.shortcutCreate.visibility === "PRIVATE"} /> = (props: Props) => { onChange={handleVisibilityInputChange} checked={state.shortcutCreate.visibility === "WORKSPACE"} /> -