package v1 import ( "testing" "github.com/stretchr/testify/assert" ) // TestPublicMethodsArePublic verifies that methods in PublicMethods are recognized as public. func TestPublicMethodsArePublic(t *testing.T) { publicMethods := []string{ // Auth Service "/memos.api.v1.AuthService/SignIn", "/memos.api.v1.AuthService/RefreshToken", // Instance Service "/memos.api.v1.InstanceService/GetInstanceProfile", "/memos.api.v1.InstanceService/GetInstanceSetting", "/memos.api.v1.InstanceService/BatchGetInstanceSettings", // User Service "/memos.api.v1.UserService/CreateUser", "/memos.api.v1.UserService/GetUser", "/memos.api.v1.UserService/BatchGetUsers", "/memos.api.v1.UserService/GetUserAvatar", "/memos.api.v1.UserService/GetUserStats", "/memos.api.v1.UserService/ListAllUserStats", // Identity Provider Service "/memos.api.v1.IdentityProviderService/ListIdentityProviders", // Memo Service "/memos.api.v1.MemoService/GetMemo", "/memos.api.v1.MemoService/ListMemos", "/memos.api.v1.MemoService/GetLinkMetadata", "/memos.api.v1.MemoService/BatchGetLinkMetadata", } for _, method := range publicMethods { t.Run(method, func(t *testing.T) { assert.True(t, IsPublicMethod(method), "Expected %s to be public", method) }) } } // TestProtectedMethodsRequireAuth verifies that non-public methods are recognized as protected. func TestProtectedMethodsRequireAuth(t *testing.T) { protectedMethods := []string{ // Auth Service - logout and get current user require auth "/memos.api.v1.AuthService/SignOut", "/memos.api.v1.AuthService/GetCurrentUser", // Instance Service - admin operations "/memos.api.v1.InstanceService/UpdateInstanceSetting", "/memos.api.v1.InstanceService/TestInstanceEmailSetting", // User Service - modification operations "/memos.api.v1.UserService/ListUsers", "/memos.api.v1.UserService/UpdateUser", "/memos.api.v1.UserService/DeleteUser", // Memo Service - write operations "/memos.api.v1.MemoService/CreateMemo", "/memos.api.v1.MemoService/UpdateMemo", "/memos.api.v1.MemoService/DeleteMemo", // Attachment Service - write operations "/memos.api.v1.AttachmentService/CreateAttachment", "/memos.api.v1.AttachmentService/DeleteAttachment", // Shortcut Service "/memos.api.v1.ShortcutService/CreateShortcut", "/memos.api.v1.ShortcutService/ListShortcuts", "/memos.api.v1.ShortcutService/UpdateShortcut", "/memos.api.v1.ShortcutService/DeleteShortcut", } for _, method := range protectedMethods { t.Run(method, func(t *testing.T) { assert.False(t, IsPublicMethod(method), "Expected %s to require auth", method) }) } } // TestUnknownMethodsRequireAuth verifies that unknown methods default to requiring auth. func TestUnknownMethodsRequireAuth(t *testing.T) { unknownMethods := []string{ "/unknown.Service/Method", "/memos.api.v1.UnknownService/Method", "", "invalid", } for _, method := range unknownMethods { t.Run(method, func(t *testing.T) { assert.False(t, IsPublicMethod(method), "Unknown method %q should require auth", method) }) } } // TestAuthBootstrapMethodsAreSubsetOfPublic verifies every auth-bootstrap method is // also a public method. A bootstrap method that wasn't public would be rejected before // the private-instance check runs, breaking sign-in on a private instance. func TestAuthBootstrapMethodsAreSubsetOfPublic(t *testing.T) { for method := range AuthBootstrapMethods { t.Run(method, func(t *testing.T) { assert.True(t, IsPublicMethod(method), "auth-bootstrap method %s must also be a public method", method) }) } } // TestAuthBootstrapClassification verifies which endpoints remain reachable by // anonymous callers on a private instance (no InstanceURL configured). func TestAuthBootstrapClassification(t *testing.T) { // Reachable while private: sign-in flow, instance metadata, SSO, share links. bootstrap := []string{ "/memos.api.v1.AuthService/SignIn", "/memos.api.v1.AuthService/RefreshToken", "/memos.api.v1.InstanceService/GetInstanceProfile", "/memos.api.v1.InstanceService/GetInstanceSetting", "/memos.api.v1.InstanceService/BatchGetInstanceSettings", "/memos.api.v1.IdentityProviderService/ListIdentityProviders", "/memos.api.v1.MemoService/GetMemoByShare", } for _, method := range bootstrap { t.Run("bootstrap/"+method, func(t *testing.T) { assert.True(t, IsAuthBootstrapMethod(method), "expected %s to be reachable on a private instance", method) }) } // Public on an open instance, but gated on a private one: browsing and profiles. // CreateUser is gated here too; it is allowed separately only during first-run setup. gatedWhilePrivate := []string{ "/memos.api.v1.MemoService/ListMemos", "/memos.api.v1.MemoService/GetMemo", "/memos.api.v1.MemoService/ListMemoComments", "/memos.api.v1.UserService/GetUser", "/memos.api.v1.UserService/ListAllUserStats", "/memos.api.v1.UserService/CreateUser", } for _, method := range gatedWhilePrivate { t.Run("gated/"+method, func(t *testing.T) { assert.False(t, IsAuthBootstrapMethod(method), "expected %s to be gated on a private instance", method) }) } }