1. 23 Feb, 2026 5 commits
    • 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
  2. 22 Feb, 2026 7 commits
  3. 14 Feb, 2026 1 commit
  4. 12 Feb, 2026 3 commits
  5. 11 Feb, 2026 3 commits
  6. 10 Feb, 2026 5 commits
  7. 09 Feb, 2026 3 commits
    • Steven's avatar
      fix(tests): update PAT tests to accept both custom and SQL errors · 2b19d8a9
      Steven authored
      The PostgreSQL implementation returns 'PAT not found' when no rows match,
      while SQLite/MySQL return 'sql: no rows in result set' from QueryRowContext.
      
      Both behaviors are correct - the key fix is that PostgreSQL no longer
      throws JSONB errors on missing/malformed data.
      
      Changes:
      - Update test assertions to accept either error type
      - Fix comment punctuation for godot linter
      - Maintain backward compatibility across all database drivers
      2b19d8a9
    • Steven's avatar
      fix(postgres): handle missing PAT data gracefully and add comprehensive tests · d9e8387d
      Steven authored
      Fixes #5612, #5611
      
      Root cause: PostgreSQL's jsonb_array_elements() throws errors when the
      'tokens' key is missing or malformed, while SQLite/MySQL return NULL
      gracefully. This caused:
      - 502 errors when creating admin after v0.25.3 → v0.26.0 upgrade
      - Settings not persisting and users unable to stay logged in
      
      Changes to store/db/postgres/user_setting.go:
      - Remove strict JSONB operations from GetUserByPATHash query
      - Fetch all PERSONAL_ACCESS_TOKENS rows and filter in Go
      - Skip malformed/invalid JSON rows with continue (error recovery)
      - Match SQLite/MySQL's forgiving error handling
      
      New integration tests (store/test/user_setting_test.go):
      - TestUserSettingGetUserByPATHashNoTokensKey
      - TestUserSettingGetUserByPATHashEmptyTokensArray
      - TestUserSettingGetUserByPATHashWithOtherUsers
      
      New PostgreSQL-specific tests (store/db/postgres/user_setting_test.go):
      - TestGetUserByPATHashWithMissingData (comprehensive edge cases)
      - TestGetUserByPATHashPerformance (100+ users)
      - TestUpsertUserSetting (basic upsert)
      
      Test coverage:
       Missing PERSONAL_ACCESS_TOKENS key
       Empty/malformed JSON data
       Multiple users with mixed valid/invalid data
       Performance with 100+ users
       Error recovery without crashes
      
      Benefits:
      - No database migration required (TEXT column works fine)
      - Backward compatible with v0.25.3 upgrades
      - Handles missing/corrupt data gracefully
      - Consistent behavior across all database drivers
      d9e8387d
    • MuLingQwQ's avatar
  8. 08 Feb, 2026 6 commits
  9. 07 Feb, 2026 1 commit
  10. 05 Feb, 2026 2 commits
    • Steven's avatar
      fix: prevent 401 errors on window focus when token expires · 81ef53b3
      Steven authored
      Fixes #5589
      
      When the page returns from background to foreground after the JWT
      token expires (~15 min), React Query's automatic refetch-on-focus
      triggers multiple API calls simultaneously. These all fail with 401
      Unauthorized, leaving the user with empty content.
      
      Solution:
      - Add useTokenRefreshOnFocus hook that listens to visibilitychange
      - Proactively refresh token BEFORE React Query refetches
      - Uses 2-minute buffer to catch expiring tokens early
      - Graceful error handling - logs error but doesn't block
      
      Changes:
      - Created web/src/hooks/useTokenRefreshOnFocus.ts
      - Updated isTokenExpired() to accept optional buffer parameter
      - Exported refreshAccessToken() for use by the hook
      - Integrated hook into AppInitializer (only when user authenticated)
      81ef53b3
    • Steven's avatar
      chore: tweak security report email · 86f780d1
      Steven authored
      86f780d1
  11. 04 Feb, 2026 4 commits
    • Steven's avatar
      refactor: remove hide-scrollbar utility · cf65f086
      Steven authored
      Removed the hide-scrollbar CSS class and all its usages throughout the
      codebase. Hiding scrollbars can hurt UX by making it unclear when
      content is scrollable.
      
      Changes:
      - Removed hide-scrollbar CSS definition from index.css
      - Removed hide-scrollbar class from Navigation component (2 instances)
      - Removed hide-scrollbar class from MemoDetailSidebar (2 instances)
      - Removed hide-scrollbar class from TagsSection
      - Removed hide-scrollbar class from ShortcutsSection
      
      Components now use standard browser scrollbar behavior, which provides
      better visual feedback to users about scrollable content. Modern
      browsers already handle scrollbar appearance elegantly.
      cf65f086
    • Steven's avatar
      perf: disable tooltips in year calendar to fix lag · 74b63b27
      Steven authored
      Fixed issue #5579 where the calendar selection dialog was very laggy.
      
      The root cause was rendering ~365 individual Tooltip components when
      opening the year calendar view (one per day with activity). This created
      a huge number of DOM nodes and event listeners that caused significant
      performance issues.
      
      Changes:
      - Added disableTooltips prop to MonthCalendar and CalendarCell components
      - Disabled tooltips in YearCalendar's small month views
      - Removed unnecessary TooltipProvider wrapper in YearCalendar
      - Tooltips remain enabled in the default month calendar view
      
      Performance improvements:
      - Eliminates ~365 tooltip instances when dialog opens
      - Reduces initial render time significantly
      - Makes dialog interactions smooth and responsive
      
      Users can still click on dates to drill down for details if needed.
      74b63b27
    • Steven's avatar
      fix: shortcut edit button opens create dialog instead of edit dialog · e7605d90
      Steven authored
      Fixed issue #5576 where clicking the edit button on a shortcut would
      incorrectly open a create dialog instead of an edit dialog.
      
      The root cause was an incorrect useEffect that was watching the shortcut
      state itself instead of the initialShortcut prop. When the dialog was
      opened for editing, the state wasn't properly reinitializing with the
      existing shortcut data.
      
      Changed the useEffect to:
      - Watch initialShortcut as the dependency
      - Reinitialize the shortcut state when initialShortcut changes
      - Properly distinguishes between create (initialShortcut undefined) and
        edit (initialShortcut has data) modes
      e7605d90
    • memory_clear's avatar