1. 03 Mar, 2026 4 commits
  2. 02 Mar, 2026 5 commits
    • Steven's avatar
      737acbba
    • boojack's avatar
      chore: tweak sponsor assets · ec3ab350
      boojack authored
      Signed-off-by: 's avatarboojack <stevenlgtm@gmail.com>
      ec3ab350
    • Steven's avatar
      dfab67f0
    • Steven's avatar
      6b37fcc0
    • Steven's avatar
      refactor(theme): consolidate theme system and polish dark mode colors · 7f753bf6
      Steven authored
      - Reduce themes from 6 to 4: system, light, dark, paper
        - Remove midnight (too similar to dark) and whitewall (too similar to light)
        - Drop all unused tokens: chart-*, sidebar-primary, sidebar-border,
          sidebar-ring, shadow-2xs, tracking-normal, spacing
        - Remove redundant @theme inline blocks from dynamic theme files
          (Tailwind only processes them at compile time, not at runtime)
        - Move shared tokens (fonts, radius) to default.css only
      
      - Polish dark mode color palette
        - Consistent cool-slate hue (h265) across all surfaces
        - Proper surface layering: sidebar(0.07) → bg(0.09) → card(0.13) →
          popover(0.17) → secondary(0.19) → muted(0.21) → accent(0.22)
        - Foreground softened to 0.82 (from 0.9) — comfortable off-white
        - Accent more chromatic than muted (0.012 vs 0.008) — hover feels interactive
        - Popover elevated above card (0.17 vs 0.13) — floating elements visible
        - Destructive more vivid (0.62/c0.20) — clearly red on dark surfaces
        - Input border (0.25) more distinct than layout border (0.21)
        - Sidebar foreground (0.68) dimmer than content foreground (0.82)
      
      - Fix inline code background invisible in dark mode (#5674)
        - Muted was same lightness as card — increased to 0.21 for clear contrast
      7f753bf6
  3. 01 Mar, 2026 10 commits
  4. 26 Feb, 2026 4 commits
  5. 25 Feb, 2026 2 commits
  6. 24 Feb, 2026 3 commits
    • Steven's avatar
      fix(web): use BroadcastChannel to sync token refreshes across tabs · bbdc9986
      Steven authored
      When multiple tabs are open and a token expires, each tab independently
      attempts a refresh. With server-side token rotation this causes all but
      the first tab to fail, logging the user out.
      
      Add a BroadcastChannel (memos_token_sync) so that when any tab
      successfully refreshes, it broadcasts the new token to all other tabs.
      Receiving tabs adopt the token in-memory immediately, skipping their own
      refresh request and avoiding conflicts with token rotation.
      
      Falls back gracefully when BroadcastChannel is unavailable (e.g. some
      privacy modes).
      bbdc9986
    • Steven's avatar
      refactor: consolidate duplicated auth logic into auth package · 26d10212
      Steven authored
      Add ApplyToContext and AuthenticateToUser helpers to the auth package,
      then remove the duplicated auth code spread across the MCP middleware,
      file server, Connect interceptor, and gRPC-Gateway middleware.
      
      - auth.ApplyToContext: single place to set claims/user into context after Authenticate()
      - auth.AuthenticateToUser: resolves any credential (bearer token or refresh cookie) to a *store.User
      - MCP middleware: replaced manual PAT DB lookup + expiry check with Authenticator.AuthenticateByPAT
      - File server: replaced authenticateByBearerToken/authenticateByRefreshToken with AuthenticateToUser
      - Connect interceptor + Gateway middleware: replaced duplicated context-setting block with ApplyToContext
      - MCPService now accepts secret to construct its own Authenticator
      26d10212
    • Steven's avatar
      feat: add MCP server with PAT authentication · 47d94147
      Steven authored
      Embeds a Model Context Protocol (MCP) server into the Memos HTTP
      process, exposing memo operations as MCP tools at POST/GET /mcp using
      Streamable HTTP transport.
      
      Authentication is PAT-only — requests without a valid personal access
      token receive HTTP 401. Six tools are exposed: list_memos, get_memo,
      create_memo, update_memo, delete_memo, and search_memos, all scoped to the authenticated user.
      47d94147
  7. 23 Feb, 2026 8 commits
    • Steven's avatar
      chore: fix codeowners · 71263736
      Steven authored
      71263736
    • Mudkip's avatar
      ff3e4c5c
    • Steven's avatar
      fix(web): fix spurious logout on page reload with expired access token · 9ecd7b87
      Steven authored
      Two bugs caused users to be redirected to /auth too frequently:
      
      1. Race condition in Promise.all([initInstance(), initAuth()]):
         initInstance() makes a gRPC request whose auth interceptor calls
         getAccessToken() synchronously. When the access token was expired,
         getAccessToken() eagerly deleted it from localStorage as a "cleanup"
         side-effect. By the time initAuth() ran and checked hasStoredToken(),
         localStorage was already empty, so it skipped the getCurrentUser()
         call and the token refresh cycle entirely — logging the user out even
         when the refresh-token cookie was still valid. Fix: remove the
         localStorage deletion from getAccessToken(); clearAccessToken()
         (called on confirmed auth failure and logout) handles proper cleanup.
      
      2. React Query retry: 1 caused a second refresh+redirect attempt after
         auth failures. The auth interceptor already handles token refresh and
         request retry internally. If it still throws Unauthenticated, the
         redirect is already in flight — a React Query retry only fires another
         failed refresh and a redundant redirectOnAuthFailure() call. Fix: use
         a shouldRetry function that skips retries for Unauthenticated errors
         while keeping the existing once-retry behaviour for other errors.
      9ecd7b87
    • Steven's avatar
      fix(web): fix explore page showing private tags and improve stats hook · 03c30b8c
      Steven authored
      The explore page sidebar was showing tags from the current user's private
      memos because the default ListMemos query applies a server-side OR filter
      (creator_id == X || visibility in [...]), mixing private content in.
      
      Fix by using a visibility-scoped ListMemos request in the explore context
      so private memos are always excluded via the AND'd server auth filter.
      
      Also consolidate two always-firing useMemos calls into one context-aware
      query, unify activity stats computation with countBy across all branches,
      and extract a toDateString helper to remove duplicated formatting logic.
      03c30b8c
    • Steven's avatar
      fix(web): make MonthNavigator month label reactive to language changes · 1cea9b0a
      Steven authored
      Use useTranslation() hook instead of the static i18n import so that
      the month label re-computes when the language changes.
      1cea9b0a
    • Steven's avatar
      fix(store): allow memo/attachment deletion when local file is missing · 704503e5
      Steven authored
      Fixes two bugs reported in #5603:
      
      1. store/attachment.go: ignore os.ErrNotExist when removing a local
         attachment file so that a missing file on disk (broken state from
         failed uploads) no longer blocks deletion of the DB record, allowing
         memos referencing corrupt attachments to be deleted normally.
      
      2. memo_attachment_service.go: add nil guard on GetAttachment result
         before dereferencing it in SetMemoAttachments, preventing a nil
         pointer panic when an attachment UID no longer exists in the DB.
      704503e5
    • Steven's avatar
    • Steven's avatar
      fix(webhook): remediate SSRF vulnerability in webhook dispatcher · 150371d2
      Steven authored
      - Add plugin/webhook/validate.go as single source of truth for SSRF
        protection: reserved CIDR list parsed once at init(), isReservedIP(),
        and exported ValidateURL() used at registration/update time
      - Replace unguarded http.Client in webhook.go with safeClient whose
        Transport uses a custom DialContext that re-resolves hostnames at
        dial time, defeating DNS rebinding attacks
      - Call webhook.ValidateURL() in CreateUserWebhook and both
        UpdateUserWebhook paths to reject non-http/https schemes and
        reserved/private IP targets before persisting
      - Strip internal service response body from non-2xx error log messages
        to prevent data leakage via application logs
      150371d2
  8. 22 Feb, 2026 4 commits
    • Steven's avatar
      chore: bump version · f43965de
      Steven authored
      f43965de
    • Steven's avatar
      fix(web): persist auth token in localStorage for cross-tab sessions · c3061002
      Steven authored
      Switch from sessionStorage to localStorage so the auth token survives
      across tabs and browser restarts, matching standard platform behavior.
      Also guard the signup redirect in App.tsx behind profileLoaded to avoid
      a false redirect when the instance profile fetch fails.
      c3061002
    • Steven's avatar
      fix(web): skip GetCurrentUser on init when no token is stored · 4aaebc50
      Steven authored
      When no token exists in sessionStorage, AuthContext.initialize() was
      still calling GetCurrentUser, triggering the auth interceptor to attempt
      RefreshToken and retry — producing a burst of 5+ auth API calls in under
      a second that reverse proxies with rate limiting (e.g. CrowdSec) flag as
      brute force.
      
      Add hasStoredToken() to auth-state and bail out of initialize() early
      when there is definitively no session to restore. The refresh flow for
      expired tokens is preserved since hasStoredToken() checks for presence
      regardless of expiry.
      
      Fixes #5647
      4aaebc50
    • Steven's avatar
      fix(web): scope task list item index to memo content container · b8bca6ba
      Steven authored
      The closest() selector was targeting a CSS class that never existed on
      the container, causing fallback to document.body and collecting task
      items across all visible memos. This caused index collisions when
      multiple memos with todo lists were on the page.
      
      Adds data-memo-content attribute to the container and updates the
      selector accordingly.
      
      Fixes #5635
      b8bca6ba