- idp_service.go: correct Scopes field alignment to col 13 (was 5 spaces,
needs 6 to match AuthUrl/TokenUrl/UserInfoUrl group); revert over-correction
from previous commit that wrongly added FieldMapping to the alignment group
- instance_service.go: add default case to switch on updateSetting.Key to
satisfy revive switch-without-default rule
- memo_service.go: fix unchecked type assertion in isSSESuppressed; use
ok && v pattern instead of discarding the ok bool
- sse_service_test.go: remove unused drainEvents helper function
https://claude.ai/code/session_01DVhwUL8RG8HVrcChv5qHdh
When credential fields (ClientSecret, AccessKeySecret) were replaced with
write-only comments in commit 9d3a74b, the remaining struct literal fields
were not re-aligned to match goimports expected column alignment.
- idp_service.go: align AuthUrl/TokenUrl/UserInfoUrl/Scopes at col 14
(longest field FieldMapping = 12 chars in post-comment group)
- instance_service.go: align AccessKeyId alone at col 13, and
Endpoint/Region/Bucket at col 14 to match UsePathStyle (longest in
post-comment group)
https://claude.ai/code/session_01DVhwUL8RG8HVrcChv5qHdh
Security fixes for credential leakage across three resources:
- NOTIFICATION setting: restrict GetInstanceSetting to admin-only
(was publicly accessible, exposing SMTP credentials)
- SMTP password: never return SmtpPassword in API responses (write-only)
- S3 secret: never return AccessKeySecret in API responses (write-only)
- OAuth2 ClientSecret: never return in API responses for any role
(was previously returned to admins); remove redactIdentityProviderResponse
in favor of omitting the field at the conversion layer
- Preserve-on-empty: when updating settings with an empty credential
field, preserve the existing stored value instead of overwriting
(applies to SmtpPassword, AccessKeySecret, and ClientSecret)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix duplicate SSE event on comment creation: CreateMemoComment now
suppresses the redundant memo.created broadcast from the inner
CreateMemo call, emitting only memo.comment.created
- Extract reaction event-building IIFEs into buildMemoReactionSSEEvent
helper, removing duplicated inline DB-fetch logic
- Promote resolveSSEAudienceCreatorID from method to free function
(resolveSSECreatorID) since it never used the receiver
- Add userID to SSE connect/disconnect log lines for traceability
- Change canReceive default from permissive (return true) to
deny-with-warning for unknown visibility types
- Add comprehensive tests covering all new helpers, visibility edge
cases, slow-client drop behavior, and the double-broadcast fix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the standalone SSE dot above UserMenu with a small badge
overlaid on the bottom-right of the user avatar. Only visible when
status is connecting (yellow) or disconnected (red) — invisible in the
normal connected state, removing constant visual noise.
- Replace PAT-only auth with optional auth supporting both PAT and JWT
via auth.Authenticator.Authenticate(); unauthenticated requests see
only public memos, matching REST API visibility semantics
- Inline auth middleware into mcp.go following fileserver pattern;
remove auth_middleware.go
- Introduce memoJSON response type that correctly serialises store.Memo
(including Payload.Tags and Payload.Property) without proto marshalling
- Add tools: list_memo_comments, create_memo_comment, list_tags
- Extend list_memos with state (NORMAL/ARCHIVED), order_by_pinned, and
page parameters
- Extend update_memo with pinned and state parameters
- Extract #tags from content on create/update via regex to pre-populate
Payload.Tags without requiring a full markdown service rebuild
- Add MCP Resources: memo://memos/{uid} template returns memo as
Markdown with YAML frontmatter, allowing clients to read memos by URI
- Add MCP Prompts: capture (save a thought) and review (search + summarise)
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
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.
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.
- 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
Defense-in-depth fix: Add missing nil check before accessing
currentUser.ID and currentUser.Role in DeleteUser function.
While the auth interceptor should block unauthenticated requests,
this check prevents potential nil pointer panic if fetchCurrentUser
returns (nil, nil).
- Add serveMediaStream() to stream video/audio without loading into memory
- Use http.ServeFile for local files (zero-copy, handles range requests)
- Redirect to S3 presigned URLs for S3-stored media files
- Refactor for better maintainability:
- Extract constants and pre-compile lookup maps
- Consolidate duplicated S3 client creation logic
- Split authentication into focused helper methods
- Group code by responsibility with section comments
- Add setSecurityHeaders() and setMediaHeaders() helpers
- Changed InstanceProfile to include admin user field
- Updated GetInstanceProfile method to retrieve admin user
- Modified related tests to reflect changes in admin user retrieval
- Removed owner cache logic and tests, introducing new admin cache tests
- Removed the owner field from InstanceProfile as it is no longer needed.
- Added an initialized field to InstanceProfile to indicate if the instance has completed first-time setup.
- Updated GetInstanceProfile method to set initialized based on the existence of an admin user.
- Modified tests to reflect changes in InstanceProfile and ensure correct behavior regarding instance initialization.
- Adjusted frontend logic to redirect users based on the initialized status instead of the owner field.
- Updated the isSuperUser function to only check for ADMIN role.
- Added SQL migration scripts for MySQL, PostgreSQL, and SQLite to change user roles from HOST to ADMIN.
- Created a new SQLite migration to alter the user table structure and ensure data integrity during the migration process.