diff --git a/api/v1/auth.go b/api/v1/auth.go index ea8dee00..a1168d3c 100644 --- a/api/v1/auth.go +++ b/api/v1/auth.go @@ -1,6 +1,7 @@ package v1 import ( + "context" "encoding/json" "fmt" "net/http" @@ -13,6 +14,7 @@ import ( "github.com/usememos/memos/common/util" "github.com/usememos/memos/plugin/idp" "github.com/usememos/memos/plugin/idp/oauth2" + storepb "github.com/usememos/memos/proto/gen/store" "github.com/usememos/memos/store" "golang.org/x/crypto/bcrypt" ) @@ -100,6 +102,9 @@ func (s *APIV1Service) SignIn(c echo.Context) error { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to generate tokens, err: %s", err)).SetInternal(err) } + if err := s.UpsertAccessTokenToStore(ctx, user, accessToken); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to upsert access token, err: %s", err)).SetInternal(err) + } if err := s.createAuthSignInActivity(c, user); err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) } @@ -198,7 +203,6 @@ func (s *APIV1Service) SignInSSO(c echo.Context) error { Role: store.RoleUser, Nickname: userInfo.DisplayName, Email: userInfo.Email, - OpenID: util.GenUUID(), } password, err := util.RandomString(20) if err != nil { @@ -222,6 +226,9 @@ func (s *APIV1Service) SignInSSO(c echo.Context) error { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to generate tokens, err: %s", err)).SetInternal(err) } + if err := s.UpsertAccessTokenToStore(ctx, user, accessToken); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to upsert access token, err: %s", err)).SetInternal(err) + } if err := s.createAuthSignInActivity(c, user); err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) } @@ -277,7 +284,6 @@ func (s *APIV1Service) SignUp(c echo.Context) error { // The new signup user should be normal user by default. Role: store.RoleUser, Nickname: signup.Username, - OpenID: util.GenUUID(), } if len(existedHostUsers) == 0 { // Change the default role to host if there is no host user. @@ -316,6 +322,9 @@ func (s *APIV1Service) SignUp(c echo.Context) error { if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to generate tokens, err: %s", err)).SetInternal(err) } + if err := s.UpsertAccessTokenToStore(ctx, user, accessToken); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to upsert access token, err: %s", err)).SetInternal(err) + } if err := s.createAuthSignUpActivity(c, user); err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) } @@ -325,6 +334,30 @@ func (s *APIV1Service) SignUp(c echo.Context) error { return c.JSON(http.StatusOK, userMessage) } +func (s *APIV1Service) UpsertAccessTokenToStore(ctx context.Context, user *store.User, accessToken string) error { + userAccessTokens, err := s.Store.GetUserAccessTokens(ctx, user.ID) + if err != nil { + return errors.Wrap(err, "failed to get user access tokens") + } + userAccessToken := storepb.AccessTokensUserSetting_AccessToken{ + AccessToken: accessToken, + Description: "Account sign in", + } + userAccessTokens = append(userAccessTokens, &userAccessToken) + if _, err := s.Store.UpsertUserSettingV1(ctx, &storepb.UserSetting{ + UserId: user.ID, + Key: storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS, + Value: &storepb.UserSetting_AccessTokens{ + AccessTokens: &storepb.AccessTokensUserSetting{ + AccessTokens: userAccessTokens, + }, + }, + }); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to upsert user setting, err: %s", err)).SetInternal(err) + } + return nil +} + func (s *APIV1Service) createAuthSignInActivity(c echo.Context, user *store.User) error { ctx := c.Request().Context() payload := ActivityUserAuthSignInPayload{ diff --git a/api/v1/docs.go b/api/v1/docs.go index b4056609..8e193487 100644 --- a/api/v1/docs.go +++ b/api/v1/docs.go @@ -209,11 +209,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -256,11 +251,6 @@ const docTemplate = `{ }, "/api/v1/idp/{idpId}": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -302,11 +292,6 @@ const docTemplate = `{ } }, "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -345,11 +330,6 @@ const docTemplate = `{ } }, "patch": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -399,11 +379,6 @@ const docTemplate = `{ }, "/api/v1/memo": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -484,11 +459,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "description": "Visibility can be PUBLIC, PROTECTED or PRIVATE\n*You should omit fields to use their default values", "consumes": [ "application/json" @@ -535,11 +505,6 @@ const docTemplate = `{ }, "/api/v1/memo/all": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "description": "This should also list protected memos if the user is logged in\nAuthentication is optional", "produces": [ "application/json" @@ -667,11 +632,6 @@ const docTemplate = `{ } }, "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -710,11 +670,6 @@ const docTemplate = `{ } }, "patch": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "description": "Visibility can be PUBLIC, PROTECTED or PRIVATE\n*You should omit fields to use their default values", "consumes": [ "application/json" @@ -768,11 +723,6 @@ const docTemplate = `{ }, "/api/v1/memo/{memoId}/organizer": { "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1004,11 +954,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1058,11 +1003,6 @@ const docTemplate = `{ }, "/api/v1/memo/{memoId}/resource/{resourceId}": { "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1129,11 +1069,6 @@ const docTemplate = `{ }, "/api/v1/resource": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1174,11 +1109,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1221,11 +1151,6 @@ const docTemplate = `{ }, "/api/v1/resource/blob": { "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "multipart/form-data" ], @@ -1266,11 +1191,6 @@ const docTemplate = `{ }, "/api/v1/resource/{resourceId}": { "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1309,11 +1229,6 @@ const docTemplate = `{ } }, "patch": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1388,11 +1303,6 @@ const docTemplate = `{ }, "/api/v1/storage": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1419,11 +1329,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1466,11 +1371,6 @@ const docTemplate = `{ }, "/api/v1/storage/{storageId}": { "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1506,11 +1406,6 @@ const docTemplate = `{ } }, "patch": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1557,11 +1452,6 @@ const docTemplate = `{ }, "/api/v1/system/setting": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1588,11 +1478,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1638,11 +1523,6 @@ const docTemplate = `{ }, "/api/v1/system/vacuum": { "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1668,11 +1548,6 @@ const docTemplate = `{ }, "/api/v1/tag": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1699,11 +1574,6 @@ const docTemplate = `{ } }, "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1746,11 +1616,6 @@ const docTemplate = `{ }, "/api/v1/tag/delete": { "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1793,11 +1658,6 @@ const docTemplate = `{ }, "/api/v1/tag/suggestion": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1894,11 +1754,6 @@ const docTemplate = `{ }, "/api/v1/user/me": { "get": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "produces": [ "application/json" ], @@ -1958,11 +1813,6 @@ const docTemplate = `{ }, "/api/v1/user/setting": { "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], "consumes": [ "application/json" ], @@ -1988,7 +1838,7 @@ const docTemplate = `{ "200": { "description": "Created user setting", "schema": { - "$ref": "#/definitions/store.UserSetting" + "$ref": "#/definitions/github_com_usememos_memos_store.UserSetting" } }, "400": { @@ -2300,6 +2150,20 @@ const docTemplate = `{ } } }, + "github_com_usememos_memos_store.UserSetting": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "userID": { + "type": "integer" + }, + "value": { + "type": "string" + } + } + }, "profile.Profile": { "type": "object", "properties": { @@ -2582,9 +2446,6 @@ const docTemplate = `{ "nickname": { "type": "string" }, - "openID": { - "type": "string" - }, "passwordHash": { "type": "string" }, @@ -2608,20 +2469,6 @@ const docTemplate = `{ } } }, - "store.UserSetting": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "userID": { - "type": "integer" - }, - "value": { - "type": "string" - } - } - }, "store.Visibility": { "type": "string", "enum": [ @@ -3205,9 +3052,6 @@ const docTemplate = `{ "password": { "type": "string" }, - "resetOpenId": { - "type": "boolean" - }, "rowStatus": { "$ref": "#/definitions/v1.RowStatus" }, @@ -3297,9 +3141,6 @@ const docTemplate = `{ "nickname": { "type": "string" }, - "openId": { - "type": "string" - }, "role": { "$ref": "#/definitions/v1.Role" }, @@ -3369,16 +3210,8 @@ const docTemplate = `{ ] } }, - "securityDefinitions": { - "ApiKeyAuth": { - "description": "Insert your Open ID API Key here.", - "type": "apiKey", - "name": "openId", - "in": "query" - } - }, "externalDocs": { - "description": "Find out more about Memos", + "description": "Find out more about Memos.", "url": "https://usememos.com/" } }` diff --git a/api/v1/idp.go b/api/v1/idp.go index 433fdb0a..def1f4b1 100644 --- a/api/v1/idp.go +++ b/api/v1/idp.go @@ -124,7 +124,6 @@ func (s *APIV1Service) GetIdentityProviderList(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 400 {object} nil "Malformatted post identity provider request" // @Failure 500 {object} nil "Failed to find user | Failed to create identity provider" -// @Security ApiKeyAuth // @Router /api/v1/idp [POST] func (s *APIV1Service) CreateIdentityProvider(c echo.Context) error { ctx := c.Request().Context() @@ -172,7 +171,6 @@ func (s *APIV1Service) CreateIdentityProvider(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 404 {object} nil "Identity provider not found" // @Failure 500 {object} nil "Failed to find identity provider list | Failed to find user" -// @Security ApiKeyAuth // @Router /api/v1/idp/{idpId} [GET] func (s *APIV1Service) GetIdentityProvider(c echo.Context) error { ctx := c.Request().Context() @@ -219,7 +217,6 @@ func (s *APIV1Service) GetIdentityProvider(c echo.Context) error { // @Failure 400 {object} nil "ID is not a number: %s | Malformatted patch identity provider request" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider" -// @Security ApiKeyAuth // @Router /api/v1/idp/{idpId} [DELETE] func (s *APIV1Service) DeleteIdentityProvider(c echo.Context) error { ctx := c.Request().Context() @@ -261,7 +258,6 @@ func (s *APIV1Service) DeleteIdentityProvider(c echo.Context) error { // @Failure 400 {object} nil "ID is not a number: %s | Malformatted patch identity provider request" // @Failure 401 {object} nil "Missing user in session | Unauthorized // @Failure 500 {object} nil "Failed to find user | Failed to patch identity provider" -// @Security ApiKeyAuth // @Router /api/v1/idp/{idpId} [PATCH] func (s *APIV1Service) UpdateIdentityProvider(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/jwt.go b/api/v1/jwt.go index 57052992..343f2179 100644 --- a/api/v1/jwt.go +++ b/api/v1/jwt.go @@ -128,7 +128,6 @@ func JWTMiddleware(server *APIV1Service, next echo.HandlerFunc, secret string) e } func (s *APIV1Service) defaultAuthSkipper(c echo.Context) bool { - ctx := c.Request().Context() path := c.Path() // Skip auth. @@ -136,21 +135,5 @@ func (s *APIV1Service) defaultAuthSkipper(c echo.Context) bool { return true } - // If there is openId in query string and related user is found, then skip auth. - openID := c.QueryParam("openId") - if openID != "" { - user, err := s.Store.GetUser(ctx, &store.FindUser{ - OpenID: &openID, - }) - if err != nil { - return false - } - if user != nil { - // Stores userID into context. - c.Set(userIDContextKey, user.ID) - return true - } - } - return false } diff --git a/api/v1/memo.go b/api/v1/memo.go index d61665ec..08ecfa24 100644 --- a/api/v1/memo.go +++ b/api/v1/memo.go @@ -139,7 +139,6 @@ func (s *APIV1Service) registerMemoRoutes(g *echo.Group) { // @Success 200 {object} []store.Memo "Memo list" // @Failure 400 {object} nil "Missing user to find memo" // @Failure 500 {object} nil "Failed to get memo display with updated ts setting value | Failed to fetch memo list | Failed to compose memo response" -// @Security ApiKeyAuth // @Router /api/v1/memo [GET] func (s *APIV1Service) GetMemoList(c echo.Context) error { ctx := c.Request().Context() @@ -239,7 +238,6 @@ func (s *APIV1Service) GetMemoList(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session" // @Failure 404 {object} nil "User not found | Memo not found: %d" // @Failure 500 {object} nil "Failed to find user setting | Failed to unmarshal user setting value | Failed to find system setting | Failed to unmarshal system setting | Failed to find user | Failed to create memo | Failed to create activity | Failed to upsert memo resource | Failed to upsert memo relation | Failed to compose memo | Failed to compose memo response" -// @Security ApiKeyAuth // @Router /api/v1/memo [POST] // // NOTES: @@ -398,7 +396,6 @@ func (s *APIV1Service) CreateMemo(c echo.Context) error { // @Param offset query int false "Offset" // @Success 200 {object} []store.Memo "Memo list" // @Failure 500 {object} nil "Failed to get memo display with updated ts setting value | Failed to fetch all memo list | Failed to compose memo response" -// @Security ApiKeyAuth // @Router /api/v1/memo/all [GET] // // NOTES: @@ -575,7 +572,6 @@ func (s *APIV1Service) GetMemo(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 404 {object} nil "Memo not found: %d" // @Failure 500 {object} nil "Failed to find memo | Failed to delete memo ID: %v" -// @Security ApiKeyAuth // @Router /api/v1/memo/{memoId} [DELETE] func (s *APIV1Service) DeleteMemo(c echo.Context) error { ctx := c.Request().Context() @@ -624,7 +620,6 @@ func (s *APIV1Service) DeleteMemo(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 404 {object} nil "Memo not found: %d" // @Failure 500 {object} nil "Failed to find memo | Failed to patch memo | Failed to upsert memo resource | Failed to delete memo resource | Failed to compose memo response" -// @Security ApiKeyAuth // @Router /api/v1/memo/{memoId} [PATCH] // // NOTES: diff --git a/api/v1/memo_organizer.go b/api/v1/memo_organizer.go index 523efd13..a3457743 100644 --- a/api/v1/memo_organizer.go +++ b/api/v1/memo_organizer.go @@ -37,7 +37,6 @@ func (s *APIV1Service) registerMemoOrganizerRoutes(g *echo.Group) { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 404 {object} nil "Memo not found: %v" // @Failure 500 {object} nil "Failed to find memo | Failed to upsert memo organizer | Failed to find memo by ID: %v | Failed to compose memo response" -// @Security ApiKeyAuth // @Router /api/v1/memo/{memoId}/organizer [POST] func (s *APIV1Service) CreateMemoOrganizer(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/memo_resource.go b/api/v1/memo_resource.go index 163c3052..7e83cfec 100644 --- a/api/v1/memo_resource.go +++ b/api/v1/memo_resource.go @@ -82,7 +82,6 @@ func (s *APIV1Service) GetMemoResourceList(c echo.Context) error { // @Failure 400 {object} nil "ID is not a number: %s | Malformatted post memo resource request | Resource not found" // @Failure 401 {object} nil "Missing user in session | Unauthorized to bind this resource" // @Failure 500 {object} nil "Failed to fetch resource | Failed to upsert memo resource" -// @Security ApiKeyAuth // @Router /api/v1/memo/{memoId}/resource [POST] // // NOTES: @@ -140,7 +139,6 @@ func (s *APIV1Service) BindMemoResource(c echo.Context) error { // @Failure 400 {object} nil "Memo ID is not a number: %s | Resource ID is not a number: %s | Memo not found" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find memo | Failed to fetch resource list" -// @Security ApiKeyAuth // @Router /api/v1/memo/{memoId}/resource/{resourceId} [DELETE] func (s *APIV1Service) UnbindMemoResource(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/resource.go b/api/v1/resource.go index ea17b1e7..7c8b1adc 100644 --- a/api/v1/resource.go +++ b/api/v1/resource.go @@ -100,7 +100,6 @@ func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) { // @Success 200 {object} []store.Resource "Resource list" // @Failure 401 {object} nil "Missing user in session" // @Failure 500 {object} nil "Failed to fetch resource list" -// @Security ApiKeyAuth // @Router /api/v1/resource [GET] func (s *APIV1Service) GetResourceList(c echo.Context) error { ctx := c.Request().Context() @@ -140,7 +139,6 @@ func (s *APIV1Service) GetResourceList(c echo.Context) error { // @Failure 400 {object} nil "Malformatted post resource request | Invalid external link | Invalid external link scheme | Failed to request %s | Failed to read %s | Failed to read mime from %s" // @Failure 401 {object} nil "Missing user in session" // @Failure 500 {object} nil "Failed to save resource | Failed to create resource | Failed to create activity" -// @Security ApiKeyAuth // @Router /api/v1/resource [POST] func (s *APIV1Service) CreateResource(c echo.Context) error { ctx := c.Request().Context() @@ -192,7 +190,6 @@ func (s *APIV1Service) CreateResource(c echo.Context) error { // @Failure 400 {object} nil "Upload file not found | File size exceeds allowed limit of %d MiB | Failed to parse upload data" // @Failure 401 {object} nil "Missing user in session" // @Failure 500 {object} nil "Failed to get uploading file | Failed to open file | Failed to save resource | Failed to create resource | Failed to create activity" -// @Security ApiKeyAuth // @Router /api/v1/resource/blob [POST] func (s *APIV1Service) UploadResource(c echo.Context) error { ctx := c.Request().Context() @@ -265,7 +262,6 @@ func (s *APIV1Service) UploadResource(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session" // @Failure 404 {object} nil "Resource not found: %d" // @Failure 500 {object} nil "Failed to find resource | Failed to delete resource" -// @Security ApiKeyAuth // @Router /api/v1/resource/{resourceId} [DELETE] func (s *APIV1Service) DeleteResource(c echo.Context) error { ctx := c.Request().Context() @@ -322,7 +318,6 @@ func (s *APIV1Service) DeleteResource(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 404 {object} nil "Resource not found: %d" // @Failure 500 {object} nil "Failed to find resource | Failed to patch resource" -// @Security ApiKeyAuth // @Router /api/v1/resource/{resourceId} [PATCH] func (s *APIV1Service) UpdateResource(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/storage.go b/api/v1/storage.go index 948528ae..e5e6efc5 100644 --- a/api/v1/storage.go +++ b/api/v1/storage.go @@ -77,7 +77,6 @@ func (s *APIV1Service) registerStorageRoutes(g *echo.Group) { // @Success 200 {object} []store.Storage "List of storages" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find user | Failed to convert storage" -// @Security ApiKeyAuth // @Router /api/v1/storage [GET] func (s *APIV1Service) GetStorageList(c echo.Context) error { ctx := c.Request().Context() @@ -124,7 +123,6 @@ func (s *APIV1Service) GetStorageList(c echo.Context) error { // @Failure 400 {object} nil "Malformatted post storage request" // @Failure 401 {object} nil "Missing user in session" // @Failure 500 {object} nil "Failed to find user | Failed to create storage | Failed to convert storage" -// @Security ApiKeyAuth // @Router /api/v1/storage [POST] func (s *APIV1Service) CreateStorage(c echo.Context) error { ctx := c.Request().Context() @@ -182,7 +180,6 @@ func (s *APIV1Service) CreateStorage(c echo.Context) error { // @Failure 400 {object} nil "ID is not a number: %s | Storage service %d is using" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find user | Failed to find storage | Failed to unmarshal storage service id | Failed to delete storage" -// @Security ApiKeyAuth // @Router /api/v1/storage/{storageId} [DELETE] // // NOTES: @@ -241,7 +238,6 @@ func (s *APIV1Service) DeleteStorage(c echo.Context) error { // @Failure 400 {object} nil "ID is not a number: %s | Malformatted patch storage request | Malformatted post storage request" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find user | Failed to patch storage | Failed to convert storage" -// @Security ApiKeyAuth // @Router /api/v1/storage/{storageId} [PATCH] func (s *APIV1Service) UpdateStorage(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/swagger.yaml b/api/v1/swagger.yaml index e7393883..52d89f43 100644 --- a/api/v1/swagger.yaml +++ b/api/v1/swagger.yaml @@ -9,6 +9,15 @@ definitions: title: type: string type: object + github_com_usememos_memos_store.UserSetting: + properties: + key: + type: string + userID: + type: integer + value: + type: string + type: object profile.Profile: properties: mode: @@ -197,8 +206,6 @@ definitions: type: integer nickname: type: string - openID: - type: string passwordHash: type: string role: @@ -213,15 +220,6 @@ definitions: description: Domain specific fields type: string type: object - store.UserSetting: - properties: - key: - type: string - userID: - type: integer - value: - type: string - type: object store.Visibility: enum: - PUBLIC @@ -624,8 +622,6 @@ definitions: type: string password: type: string - resetOpenId: - type: boolean rowStatus: $ref: '#/definitions/v1.RowStatus' username: @@ -683,8 +679,6 @@ definitions: type: integer nickname: type: string - openId: - type: string role: $ref: '#/definitions/v1.Role' rowStatus: @@ -733,7 +727,7 @@ definitions: - Protected - Private externalDocs: - description: Find out more about Memos + description: Find out more about Memos. url: https://usememos.com/ info: contact: @@ -899,8 +893,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find user | Failed to create identity provider - security: - - ApiKeyAuth: [] summary: Create Identity Provider tags: - idp @@ -928,8 +920,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find user | Failed to patch identity provider - security: - - ApiKeyAuth: [] summary: Delete an identity provider by ID tags: - idp @@ -957,8 +947,6 @@ paths: description: Identity provider not found "500": description: Failed to find identity provider list | Failed to find user - security: - - ApiKeyAuth: [] summary: Get an identity provider by ID tags: - idp @@ -991,8 +979,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find user | Failed to patch identity provider - security: - - ApiKeyAuth: [] summary: Update an identity provider by ID tags: - idp @@ -1048,8 +1034,6 @@ paths: "500": description: Failed to get memo display with updated ts setting value | Failed to fetch memo list | Failed to compose memo response - security: - - ApiKeyAuth: [] summary: Get a list of memos matching optional filters tags: - memo @@ -1086,8 +1070,6 @@ paths: | Failed to find user | Failed to create memo | Failed to create activity | Failed to upsert memo resource | Failed to upsert memo relation | Failed to compose memo | Failed to compose memo response - security: - - ApiKeyAuth: [] summary: Create a memo tags: - memo @@ -1114,8 +1096,6 @@ paths: description: 'Memo not found: %d' "500": description: 'Failed to find memo | Failed to delete memo ID: %v' - security: - - ApiKeyAuth: [] summary: Delete memo by ID tags: - memo @@ -1185,8 +1165,6 @@ paths: description: Failed to find memo | Failed to patch memo | Failed to upsert memo resource | Failed to delete memo resource | Failed to compose memo response - security: - - ApiKeyAuth: [] summary: Update a memo tags: - memo @@ -1223,8 +1201,6 @@ paths: "500": description: 'Failed to find memo | Failed to upsert memo organizer | Failed to find memo by ID: %v | Failed to compose memo response' - security: - - ApiKeyAuth: [] summary: Organize memo (pin/unpin) tags: - memo-organizer @@ -1378,8 +1354,6 @@ paths: description: Missing user in session | Unauthorized to bind this resource "500": description: Failed to fetch resource | Failed to upsert memo resource - security: - - ApiKeyAuth: [] summary: Bind resource to memo tags: - memo-resource @@ -1413,8 +1387,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find memo | Failed to fetch resource list - security: - - ApiKeyAuth: [] summary: Unbind resource from memo tags: - memo-resource @@ -1444,8 +1416,6 @@ paths: "500": description: Failed to get memo display with updated ts setting value | Failed to fetch all memo list | Failed to compose memo response - security: - - ApiKeyAuth: [] summary: Get a list of public memos matching optional filters tags: - memo @@ -1514,8 +1484,6 @@ paths: description: Missing user in session "500": description: Failed to fetch resource list - security: - - ApiKeyAuth: [] summary: Get a list of resources tags: - resource @@ -1545,8 +1513,6 @@ paths: "500": description: Failed to save resource | Failed to create resource | Failed to create activity - security: - - ApiKeyAuth: [] summary: Create resource tags: - resource @@ -1573,8 +1539,6 @@ paths: description: 'Resource not found: %d' "500": description: Failed to find resource | Failed to delete resource - security: - - ApiKeyAuth: [] summary: Delete a resource tags: - resource @@ -1606,8 +1570,6 @@ paths: description: 'Resource not found: %d' "500": description: Failed to find resource | Failed to patch resource - security: - - ApiKeyAuth: [] summary: Update a resource tags: - resource @@ -1636,8 +1598,6 @@ paths: "500": description: Failed to get uploading file | Failed to open file | Failed to save resource | Failed to create resource | Failed to create activity - security: - - ApiKeyAuth: [] summary: Upload resource tags: - resource @@ -1673,8 +1633,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find user | Failed to convert storage - security: - - ApiKeyAuth: [] summary: Get a list of storages tags: - storage @@ -1702,8 +1660,6 @@ paths: "500": description: Failed to find user | Failed to create storage | Failed to convert storage - security: - - ApiKeyAuth: [] summary: Create storage tags: - storage @@ -1729,8 +1685,6 @@ paths: "500": description: Failed to find user | Failed to find storage | Failed to unmarshal storage service id | Failed to delete storage - security: - - ApiKeyAuth: [] summary: Delete a storage tags: - storage @@ -1762,8 +1716,6 @@ paths: "500": description: Failed to find user | Failed to patch storage | Failed to convert storage - security: - - ApiKeyAuth: [] summary: Update a storage tags: - storage @@ -1782,8 +1734,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find user | Failed to find system setting list - security: - - ApiKeyAuth: [] summary: Get a list of system settings tags: - system-setting @@ -1812,8 +1762,6 @@ paths: description: Cannot disable passwords if no SSO identity provider is configured. "500": description: Failed to find user | Failed to upsert system setting - security: - - ApiKeyAuth: [] summary: Create system setting tags: - system-setting @@ -1830,8 +1778,6 @@ paths: description: Missing user in session | Unauthorized "500": description: Failed to find user | Failed to ExecVacuum database - security: - - ApiKeyAuth: [] summary: Vacuum the database tags: - system @@ -1850,8 +1796,6 @@ paths: description: Missing user id to find tag "500": description: Failed to find tag list - security: - - ApiKeyAuth: [] summary: Get a list of tags tags: - tag @@ -1878,8 +1822,6 @@ paths: description: Missing user in session "500": description: Failed to upsert tag | Failed to create activity - security: - - ApiKeyAuth: [] summary: Create a tag tags: - tag @@ -1907,8 +1849,6 @@ paths: description: Missing user in session "500": description: 'Failed to delete tag name: %v' - security: - - ApiKeyAuth: [] summary: Delete a tag tags: - tag @@ -1927,8 +1867,6 @@ paths: description: Missing user session "500": description: Failed to find memo list | Failed to find tag list - security: - - ApiKeyAuth: [] summary: Get a list of tags suggested from other memos contents tags: - tag @@ -2073,8 +2011,6 @@ paths: description: Missing auth session "500": description: Failed to find user | Failed to find userSettingList - security: - - ApiKeyAuth: [] summary: Get current user tags: - user @@ -2117,7 +2053,7 @@ paths: "200": description: Created user setting schema: - $ref: '#/definitions/store.UserSetting' + $ref: '#/definitions/github_com_usememos_memos_store.UserSetting' "400": description: Malformatted post user setting upsert request | Invalid user setting format @@ -2125,8 +2061,6 @@ paths: description: Missing auth session "500": description: Failed to upsert user setting - security: - - ApiKeyAuth: [] summary: Upsert user setting tags: - user-setting @@ -2238,10 +2172,4 @@ paths: summary: Get RSS for a user tags: - rss -securityDefinitions: - ApiKeyAuth: - description: Insert your Open ID API Key here. - in: query - name: openId - type: apiKey swagger: "2.0" diff --git a/api/v1/system.go b/api/v1/system.go index 971cf895..897ad419 100644 --- a/api/v1/system.go +++ b/api/v1/system.go @@ -163,7 +163,6 @@ func (s *APIV1Service) GetSystemStatus(c echo.Context) error { // @Success 200 {boolean} true "Database vacuumed" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find user | Failed to ExecVacuum database" -// @Security ApiKeyAuth // @Router /api/v1/system/vacuum [POST] func (s *APIV1Service) ExecVacuum(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/system_setting.go b/api/v1/system_setting.go index ca953f4d..e7090199 100644 --- a/api/v1/system_setting.go +++ b/api/v1/system_setting.go @@ -90,7 +90,6 @@ func (s *APIV1Service) registerSystemSettingRoutes(g *echo.Group) { // @Success 200 {object} []SystemSetting "System setting list" // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 500 {object} nil "Failed to find user | Failed to find system setting list" -// @Security ApiKeyAuth // @Router /api/v1/system/setting [GET] func (s *APIV1Service) GetSystemSettingList(c echo.Context) error { ctx := c.Request().Context() @@ -133,7 +132,6 @@ func (s *APIV1Service) GetSystemSettingList(c echo.Context) error { // @Failure 401 {object} nil "Missing user in session | Unauthorized" // @Failure 403 {object} nil "Cannot disable passwords if no SSO identity provider is configured." // @Failure 500 {object} nil "Failed to find user | Failed to upsert system setting" -// @Security ApiKeyAuth // @Router /api/v1/system/setting [POST] func (s *APIV1Service) CreateSystemSetting(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/tag.go b/api/v1/tag.go index 5a13d2de..8786d350 100644 --- a/api/v1/tag.go +++ b/api/v1/tag.go @@ -41,7 +41,6 @@ func (s *APIV1Service) registerTagRoutes(g *echo.Group) { // @Success 200 {object} []string "Tag list" // @Failure 400 {object} nil "Missing user id to find tag" // @Failure 500 {object} nil "Failed to find tag list" -// @Security ApiKeyAuth // @Router /api/v1/tag [GET] func (s *APIV1Service) GetTagList(c echo.Context) error { ctx := c.Request().Context() @@ -75,7 +74,6 @@ func (s *APIV1Service) GetTagList(c echo.Context) error { // @Failure 400 {object} nil "Malformatted post tag request | Tag name shouldn't be empty" // @Failure 401 {object} nil "Missing user in session" // @Failure 500 {object} nil "Failed to upsert tag | Failed to create activity" -// @Security ApiKeyAuth // @Router /api/v1/tag [POST] func (s *APIV1Service) CreateTag(c echo.Context) error { ctx := c.Request().Context() @@ -117,7 +115,6 @@ func (s *APIV1Service) CreateTag(c echo.Context) error { // @Failure 400 {object} nil "Malformatted post tag request | Tag name shouldn't be empty" // @Failure 401 {object} nil "Missing user in session" // @Failure 500 {object} nil "Failed to delete tag name: %v" -// @Security ApiKeyAuth // @Router /api/v1/tag/delete [POST] func (s *APIV1Service) DeleteTag(c echo.Context) error { ctx := c.Request().Context() @@ -152,7 +149,6 @@ func (s *APIV1Service) DeleteTag(c echo.Context) error { // @Success 200 {object} []string "Tag list" // @Failure 400 {object} nil "Missing user session" // @Failure 500 {object} nil "Failed to find memo list | Failed to find tag list" -// @Security ApiKeyAuth // @Router /api/v1/tag/suggestion [GET] func (s *APIV1Service) GetTagSuggestion(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/user.go b/api/v1/user.go index c971c28d..de33b377 100644 --- a/api/v1/user.go +++ b/api/v1/user.go @@ -43,7 +43,6 @@ type User struct { Email string `json:"email"` Nickname string `json:"nickname"` PasswordHash string `json:"-"` - OpenID string `json:"openId"` AvatarURL string `json:"avatarUrl"` UserSettingList []*UserSetting `json:"userSettingList"` } @@ -57,13 +56,12 @@ type CreateUserRequest struct { } type UpdateUserRequest struct { - RowStatus *RowStatus `json:"rowStatus"` - Username *string `json:"username"` - Email *string `json:"email"` - Nickname *string `json:"nickname"` - Password *string `json:"password"` - ResetOpenID *bool `json:"resetOpenId"` - AvatarURL *string `json:"avatarUrl"` + RowStatus *RowStatus `json:"rowStatus"` + Username *string `json:"username"` + Email *string `json:"email"` + Nickname *string `json:"nickname"` + Password *string `json:"password"` + AvatarURL *string `json:"avatarUrl"` } func (s *APIV1Service) registerUserRoutes(g *echo.Group) { @@ -96,7 +94,6 @@ func (s *APIV1Service) GetUserList(c echo.Context) error { for _, user := range list { userMessage := convertUserFromStore(user) // data desensitize - userMessage.OpenID = "" userMessage.Email = "" userMessageList = append(userMessageList, userMessage) } @@ -158,7 +155,6 @@ func (s *APIV1Service) CreateUser(c echo.Context) error { Email: userCreate.Email, Nickname: userCreate.Nickname, PasswordHash: string(passwordHash), - OpenID: util.GenUUID(), }) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err) @@ -179,7 +175,6 @@ func (s *APIV1Service) CreateUser(c echo.Context) error { // @Success 200 {object} store.User "Current user" // @Failure 401 {object} nil "Missing auth session" // @Failure 500 {object} nil "Failed to find user | Failed to find userSettingList" -// @Security ApiKeyAuth // @Router /api/v1/user/me [GET] func (s *APIV1Service) GetCurrentUser(c echo.Context) error { ctx := c.Request().Context() @@ -234,7 +229,6 @@ func (s *APIV1Service) GetUserByUsername(c echo.Context) error { userMessage := convertUserFromStore(user) // data desensitize - userMessage.OpenID = "" userMessage.Email = "" return c.JSON(http.StatusOK, userMessage) } @@ -267,7 +261,6 @@ func (s *APIV1Service) GetUserByID(c echo.Context) error { userMessage := convertUserFromStore(user) // data desensitize - userMessage.OpenID = "" userMessage.Email = "" return c.JSON(http.StatusOK, userMessage) } @@ -385,10 +378,6 @@ func (s *APIV1Service) UpdateUser(c echo.Context) error { passwordHashStr := string(passwordHash) userUpdate.PasswordHash = &passwordHashStr } - if request.ResetOpenID != nil && *request.ResetOpenID { - openID := util.GenUUID() - userUpdate.OpenID = &openID - } if request.AvatarURL != nil { userUpdate.AvatarURL = request.AvatarURL } @@ -508,7 +497,6 @@ func convertUserFromStore(user *store.User) *User { Email: user.Email, Nickname: user.Nickname, PasswordHash: user.PasswordHash, - OpenID: user.OpenID, AvatarURL: user.AvatarURL, } } diff --git a/api/v1/user_setting.go b/api/v1/user_setting.go index 4c61182b..abdd66a9 100644 --- a/api/v1/user_setting.go +++ b/api/v1/user_setting.go @@ -92,7 +92,6 @@ func (s *APIV1Service) registerUserSettingRoutes(g *echo.Group) { // @Failure 400 {object} nil "Malformatted post user setting upsert request | Invalid user setting format" // @Failure 401 {object} nil "Missing auth session" // @Failure 500 {object} nil "Failed to upsert user setting" -// @Security ApiKeyAuth // @Router /api/v1/user/setting [POST] func (s *APIV1Service) UpsertUserSetting(c echo.Context) error { ctx := c.Request().Context() diff --git a/api/v1/v1.go b/api/v1/v1.go index 1051ade8..79e7b903 100644 --- a/api/v1/v1.go +++ b/api/v1/v1.go @@ -27,12 +27,7 @@ type APIV1Service struct { // @BasePath / // // @externalDocs.url https://usememos.com/ -// @externalDocs.description Find out more about Memos -// -// @securitydefinitions.apikey ApiKeyAuth -// @in query -// @name openId -// @description Insert your Open ID API Key here. +// @externalDocs.description Find out more about Memos. func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store, telegramBot *telegram.Bot) *APIV1Service { return &APIV1Service{ Secret: secret, diff --git a/api/v2/user_service.go b/api/v2/user_service.go index e9ed71e8..6a9e3e83 100644 --- a/api/v2/user_service.go +++ b/api/v2/user_service.go @@ -9,7 +9,6 @@ import ( "github.com/labstack/echo/v4" "github.com/pkg/errors" "github.com/usememos/memos/api/auth" - "github.com/usememos/memos/common/util" apiv2pb "github.com/usememos/memos/proto/gen/api/v2" storepb "github.com/usememos/memos/proto/gen/store" "github.com/usememos/memos/store" @@ -47,12 +46,6 @@ func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserReque } userMessage := convertUserFromStore(user) - currentUser, _ := getCurrentUser(ctx, s.Store) - if currentUser == nil || currentUser.ID != user.ID { - // Data desensitization. - userMessage.OpenId = "" - } - response := &apiv2pb.GetUserResponse{ User: userMessage, } @@ -88,9 +81,6 @@ func (s *UserService) UpdateUser(ctx context.Context, request *apiv2pb.UpdateUse } else if path == "role" { role := convertUserRoleToStore(request.User.Role) update.Role = &role - } else if path == "reset_open_id" { - openID := util.GenUUID() - update.OpenID = &openID } else if path == "password" { passwordHash, err := bcrypt.GenerateFromPassword([]byte(request.User.Password), bcrypt.DefaultCost) if err != nil { @@ -283,7 +273,6 @@ func convertUserFromStore(user *store.User) *apiv2pb.User { Role: convertUserRoleFromStore(user.Role), Email: user.Email, Nickname: user.Nickname, - OpenId: user.OpenID, AvatarUrl: user.AvatarURL, } } diff --git a/cmd/setup.go b/cmd/setup.go index 9f54ae71..8b2705bc 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -101,7 +101,6 @@ func (s setupService) createUser(ctx context.Context, hostUsername, hostPassword // The new signup user should be normal user by default. Role: store.RoleHost, Nickname: hostUsername, - OpenID: util.GenUUID(), } if len(userCreate.Username) < 3 { diff --git a/docs/api/v1.md b/docs/api/v1.md index ccfa099e..6ae15d6e 100644 --- a/docs/api/v1.md +++ b/docs/api/v1.md @@ -9,16 +9,7 @@ API Support **License:** [MIT License](https://github.com/usememos/memos/blob/main/LICENSE) -[Find out more about Memos](https://usememos.com/) - -### Security -**ApiKeyAuth** - -| apiKey | *API Key* | -| ------ | --------- | -| Description | Insert your Open ID API Key here. | -| In | query | -| Name | openId | +[Find out more about Memos.](https://usememos.com/) --- ### /api/v1/auth/signin @@ -144,12 +135,6 @@ Create Identity Provider | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to create identity provider | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/idp/{idpId} #### DELETE @@ -172,12 +157,6 @@ Delete an identity provider by ID | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to patch identity provider | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### GET ##### Summary @@ -199,12 +178,6 @@ Get an identity provider by ID | 404 | Identity provider not found | | | 500 | Failed to find identity provider list \| Failed to find user | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### PATCH ##### Summary @@ -226,12 +199,6 @@ Update an identity provider by ID | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to patch identity provider | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /api/v1/memo @@ -261,12 +228,6 @@ Get a list of memos matching optional filters | 400 | Missing user to find memo | | | 500 | Failed to get memo display with updated ts setting value \| Failed to fetch memo list \| Failed to compose memo response | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### POST ##### Summary @@ -293,12 +254,6 @@ Visibility can be PUBLIC, PROTECTED or PRIVATE | 404 | User not found \| Memo not found: %d | | | 500 | Failed to find user setting \| Failed to unmarshal user setting value \| Failed to find system setting \| Failed to unmarshal system setting \| Failed to find user \| Failed to create memo \| Failed to create activity \| Failed to upsert memo resource \| Failed to upsert memo relation \| Failed to compose memo \| Failed to compose memo response | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/memo/{memoId} #### DELETE @@ -322,12 +277,6 @@ Delete memo by ID | 404 | Memo not found: %d | | | 500 | Failed to find memo \| Failed to delete memo ID: %v | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### GET ##### Summary @@ -377,12 +326,6 @@ Visibility can be PUBLIC, PROTECTED or PRIVATE | 404 | Memo not found: %d | | | 500 | Failed to find memo \| Failed to patch memo \| Failed to upsert memo resource \| Failed to delete memo resource \| Failed to compose memo response | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/memo/all #### GET @@ -409,12 +352,6 @@ Authentication is optional | 200 | Memo list | [ [store.Memo](#storememo) ] | | 500 | Failed to get memo display with updated ts setting value \| Failed to fetch all memo list \| Failed to compose memo response | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/memo/stats #### GET @@ -466,12 +403,6 @@ Organize memo (pin/unpin) | 404 | Memo not found: %v | | | 500 | Failed to find memo \| Failed to upsert memo organizer \| Failed to find memo by ID: %v \| Failed to compose memo response | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /api/v1/memo/{memoId}/relation @@ -588,12 +519,6 @@ Bind resource to memo | 401 | Missing user in session \| Unauthorized to bind this resource | | | 500 | Failed to fetch resource \| Failed to upsert memo resource | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/memo/{memoId}/resource/{resourceId} #### DELETE @@ -617,12 +542,6 @@ Unbind resource from memo | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find memo \| Failed to fetch resource list | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /api/v1/ping @@ -635,20 +554,20 @@ Ping the system | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | System profile | [profile.Profile](#profileprofile) | +| 200 | If succeed to ping the system | boolean | ### /api/v1/status #### GET ##### Summary -Get system status +Get system GetSystemStatus ##### Responses | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | System status | [v1.SystemStatus](#v1systemstatus) | +| 200 | System GetSystemStatus | [v1.SystemStatus](#v1systemstatus) | | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find host user \| Failed to find system setting list \| Failed to unmarshal system setting customized profile value | | @@ -665,13 +584,7 @@ Vacuum the database | ---- | ----------- | ------ | | 200 | Database vacuumed | boolean | | 401 | Missing user in session \| Unauthorized | | -| 500 | Failed to find user \| Failed to vacuum database | | - -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | +| 500 | Failed to find user \| Failed to ExecVacuum database | | --- ### /api/v1/resource @@ -696,12 +609,6 @@ Get a list of resources | 401 | Missing user in session | | | 500 | Failed to fetch resource list | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### POST ##### Summary @@ -722,12 +629,6 @@ Create resource | 401 | Missing user in session | | | 500 | Failed to save resource \| Failed to create resource \| Failed to create activity | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/resource/{resourceId} #### DELETE @@ -751,12 +652,6 @@ Delete a resource | 404 | Resource not found: %d | | | 500 | Failed to find resource \| Failed to delete resource | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### PATCH ##### Summary @@ -779,12 +674,6 @@ Update a resource | 404 | Resource not found: %d | | | 500 | Failed to find resource \| Failed to patch resource | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/resource/blob #### POST @@ -807,12 +696,6 @@ Upload resource | 401 | Missing user in session | | | 500 | Failed to get uploading file \| Failed to open file \| Failed to save resource \| Failed to create resource \| Failed to create activity | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /o/r/{resourceId} #### GET @@ -857,12 +740,6 @@ Get a list of storages | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to convert storage | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### POST ##### Summary @@ -883,12 +760,6 @@ Create storage | 401 | Missing user in session | | | 500 | Failed to find user \| Failed to create storage \| Failed to convert storage | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/storage/{storageId} #### DELETE @@ -911,12 +782,6 @@ Delete a storage | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to find storage \| Failed to unmarshal storage service id \| Failed to delete storage | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### PATCH ##### Summary @@ -938,12 +803,6 @@ Update a storage | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to patch storage \| Failed to convert storage | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /api/v1/system/setting @@ -960,12 +819,6 @@ Get a list of system settings | 401 | Missing user in session \| Unauthorized | | | 500 | Failed to find user \| Failed to find system setting list | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### POST ##### Summary @@ -987,12 +840,6 @@ Create system setting | 403 | Cannot disable passwords if no SSO identity provider is configured. | | | 500 | Failed to find user \| Failed to upsert system setting | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /api/v1/tag @@ -1009,12 +856,6 @@ Get a list of tags | 400 | Missing user id to find tag | | | 500 | Failed to find tag list | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - #### POST ##### Summary @@ -1035,12 +876,6 @@ Create a tag | 401 | Missing user in session | | | 500 | Failed to upsert tag \| Failed to create activity | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/tag/delete #### POST @@ -1063,12 +898,6 @@ Delete a tag | 401 | Missing user in session | | | 500 | Failed to delete tag name: %v | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/tag/suggestion #### GET @@ -1084,12 +913,6 @@ Get a list of tags suggested from other memos contents | 400 | Missing user session | | | 500 | Failed to find memo list \| Failed to find tag list | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /api/v1/user @@ -1206,12 +1029,6 @@ Get current user | 401 | Missing auth session | | | 500 | Failed to find user \| Failed to find userSettingList | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - ### /api/v1/user/name/{username} #### GET @@ -1239,7 +1056,7 @@ Get user by username #### POST ##### Summary -Create user setting +Upsert user setting ##### Parameters @@ -1251,17 +1068,11 @@ Create user setting | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Created user setting | [store.UserSetting](#storeusersetting) | +| 200 | Created user setting | [github_com_usememos_memos_store.UserSetting](#github_com_usememos_memos_storeusersetting) | | 400 | Malformatted post user setting upsert request \| Invalid user setting format | | | 401 | Missing auth session | | | 500 | Failed to upsert user setting | | -##### Security - -| Security Schema | Scopes | -| --------------- | ------ | -| ApiKeyAuth | | - --- ### /explore/rss.xml @@ -1299,7 +1110,28 @@ Get RSS for a user | 500 | Failed to get system customized profile \| Failed to find memo list \| Failed to generate rss | --- -### /o/get/httpmeta +### /o/get/GetImage + +#### GET +##### Summary + +Get GetImage from URL + +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| url | query | Image url | Yes | string | + +##### Responses + +| Code | Description | +| ---- | ----------- | +| 200 | Image | +| 400 | Missing GetImage url \| Wrong url \| Failed to get GetImage url: %s | +| 500 | Failed to write GetImage blob | + +### /o/get/GetWebsiteMetadata #### GET ##### Summary @@ -1320,27 +1152,6 @@ Get website metadata | 400 | Missing website url \| Wrong url | | | 406 | Failed to get website meta with url: %s | | -### /o/get/image - -#### GET -##### Summary - -Get image from URL - -##### Parameters - -| Name | Located in | Description | Required | Schema | -| ---- | ---------- | ----------- | -------- | ------ | -| url | query | Image url | Yes | string | - -##### Responses - -| Code | Description | -| ---- | ----------- | -| 200 | Image | -| 400 | Missing image url \| Wrong url \| Failed to get image url: %s | -| 500 | Failed to write image blob | - --- ### Models @@ -1352,6 +1163,14 @@ Get image from URL | image | string | | No | | title | string | | No | +#### github_com_usememos_memos_store.UserSetting + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| key | string | | No | +| userID | integer | | No | +| value | string | | No | + #### profile.Profile | Name | Type | Description | Required | @@ -1484,21 +1303,12 @@ Get image from URL | email | string | | No | | id | integer | | No | | nickname | string | | No | -| openID | string | | No | | passwordHash | string | | No | | role | [store.Role](#storerole) | | No | | rowStatus | [store.RowStatus](#storerowstatus) | Standard fields | No | | updatedTs | integer | | No | | username | string | Domain specific fields | No | -#### store.UserSetting - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| key | string | | No | -| userID | integer | | No | -| value | string | | No | - #### store.Visibility | Name | Type | Description | Required | @@ -1528,7 +1338,6 @@ Get image from URL | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| downloadToLocal | boolean | | No | | externalLink | string | | No | | filename | string | | No | | internalPath | string | | No | @@ -1766,7 +1575,6 @@ Get image from URL | email | string | | No | | nickname | string | | No | | password | string | | No | -| resetOpenId | boolean | | No | | rowStatus | [v1.RowStatus](#v1rowstatus) | | No | | username | string | | No | @@ -1820,7 +1628,6 @@ Get image from URL | email | string | | No | | id | integer | | No | | nickname | string | | No | -| openId | string | | No | | role | [v1.Role](#v1role) | | No | | rowStatus | [v1.RowStatus](#v1rowstatus) | Standard fields | No | | updatedTs | integer | | No | diff --git a/proto/api/v2/user_service.proto b/proto/api/v2/user_service.proto index 80d56d91..1a6a25ef 100644 --- a/proto/api/v2/user_service.proto +++ b/proto/api/v2/user_service.proto @@ -59,17 +59,15 @@ message User { string nickname = 5; - string open_id = 6; + string avatar_url = 6; - string avatar_url = 7; + string password = 7 [(google.api.field_behavior) = INPUT_ONLY]; - string password = 8 [(google.api.field_behavior) = INPUT_ONLY]; + RowStatus row_status = 8; - RowStatus row_status = 9; + google.protobuf.Timestamp create_time = 9; - google.protobuf.Timestamp create_time = 10; - - google.protobuf.Timestamp update_time = 11; + google.protobuf.Timestamp update_time = 10; } message GetUserRequest { diff --git a/proto/gen/api/v2/README.md b/proto/gen/api/v2/README.md index f28dfe17..b015bbc4 100644 --- a/proto/gen/api/v2/README.md +++ b/proto/gen/api/v2/README.md @@ -554,7 +554,6 @@ | role | [User.Role](#memos-api-v2-User-Role) | | | | email | [string](#string) | | | | nickname | [string](#string) | | | -| open_id | [string](#string) | | | | avatar_url | [string](#string) | | | | password | [string](#string) | | | | row_status | [RowStatus](#memos-api-v2-RowStatus) | | | diff --git a/proto/gen/api/v2/user_service.pb.go b/proto/gen/api/v2/user_service.pb.go index 71184b36..1534794c 100644 --- a/proto/gen/api/v2/user_service.pb.go +++ b/proto/gen/api/v2/user_service.pb.go @@ -84,12 +84,11 @@ type User struct { Role User_Role `protobuf:"varint,3,opt,name=role,proto3,enum=memos.api.v2.User_Role" json:"role,omitempty"` Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` Nickname string `protobuf:"bytes,5,opt,name=nickname,proto3" json:"nickname,omitempty"` - OpenId string `protobuf:"bytes,6,opt,name=open_id,json=openId,proto3" json:"open_id,omitempty"` - AvatarUrl string `protobuf:"bytes,7,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` - Password string `protobuf:"bytes,8,opt,name=password,proto3" json:"password,omitempty"` - RowStatus RowStatus `protobuf:"varint,9,opt,name=row_status,json=rowStatus,proto3,enum=memos.api.v2.RowStatus" json:"row_status,omitempty"` - CreateTime *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` - UpdateTime *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + AvatarUrl string `protobuf:"bytes,6,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` + Password string `protobuf:"bytes,7,opt,name=password,proto3" json:"password,omitempty"` + RowStatus RowStatus `protobuf:"varint,8,opt,name=row_status,json=rowStatus,proto3,enum=memos.api.v2.RowStatus" json:"row_status,omitempty"` + CreateTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` + UpdateTime *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` } func (x *User) Reset() { @@ -159,13 +158,6 @@ func (x *User) GetNickname() string { return "" } -func (x *User) GetOpenId() string { - if x != nil { - return x.OpenId - } - return "" -} - func (x *User) GetAvatarUrl() string { if x != nil { return x.AvatarUrl @@ -781,7 +773,7 @@ var file_api_v2_user_service_proto_rawDesc = []byte{ 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x03, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc0, 0x03, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x04, @@ -790,154 +782,153 @@ var file_api_v2_user_service_proto_rawDesc = []byte{ 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x6f, - 0x70, 0x65, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x70, - 0x65, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x5f, 0x75, - 0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, - 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x04, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, - 0x77, 0x6f, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x72, 0x6f, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x09, 0x72, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x0b, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x3b, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x14, - 0x0a, 0x10, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x53, 0x54, 0x10, 0x01, 0x12, 0x09, - 0x0a, 0x05, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, - 0x52, 0x10, 0x03, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, - 0x65, 0x22, 0x39, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, + 0x04, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x72, + 0x6f, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x17, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x52, + 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x72, 0x6f, 0x77, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x3b, 0x0a, + 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x48, + 0x4f, 0x53, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, + 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x03, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x39, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, + 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x22, 0x78, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x78, 0x0a, 0x11, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, - 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, - 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x3c, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, - 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, - 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, - 0x75, 0x73, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, - 0x62, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x42, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x49, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x65, - 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x72, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x61, 0x0a, 0x1d, 0x43, + 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x3c, 0x0a, + 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x1b, 0x4c, + 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x62, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0c, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x5d, - 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1f, 0x0a, - 0x1d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xca, - 0x01, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x32, 0xb9, 0x06, 0x0a, 0x0b, - 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x07, 0x47, - 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x2b, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x12, 0x7f, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, - 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x2e, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, + 0x6e, 0x52, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x22, 0x61, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, + 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x5d, 0x0a, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1f, 0x0a, 0x1d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xca, 0x01, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x37, + 0x0a, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x41, 0x74, 0x32, 0xb9, 0x06, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x73, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, + 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6d, 0x65, + 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0xda, 0x41, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x7f, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x12, 0x29, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6d, + 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x12, 0x26, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x12, 0xbe, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2a, 0x2e, + 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, + 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, + 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, 0x3a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x26, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x73, 0x12, 0xc7, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2a, + 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, + 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0xda, 0x41, 0x15, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x2a, 0x35, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x12, 0xa8, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x29, 0x2e, 0x6d, 0x65, 0x6d, - 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x39, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x28, 0x12, 0x26, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, - 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0xbe, 0x01, 0x0a, - 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x4c, 0xda, 0x41, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x3b, 0x3a, 0x11, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x26, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, - 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0xc7, 0x01, - 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2a, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x55, 0xda, 0x41, 0x15, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, - 0x2a, 0x35, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, - 0x7b, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2f, 0x7b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x7d, 0x42, 0xa8, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, - 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x10, 0x55, 0x73, - 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, - 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, - 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, - 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, - 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, - 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, - 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x7d, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2f, + 0x7b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x7d, 0x42, 0xa8, + 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x32, 0x42, 0x10, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, + 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, + 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, + 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, + 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, + 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/store/db/migration/dev/LATEST__SCHEMA.sql b/store/db/migration/dev/LATEST__SCHEMA.sql index 03bef88a..225eef37 100644 --- a/store/db/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/migration/dev/LATEST__SCHEMA.sql @@ -23,7 +23,6 @@ CREATE TABLE user ( email TEXT NOT NULL DEFAULT '', nickname TEXT NOT NULL DEFAULT '', password_hash TEXT NOT NULL, - open_id TEXT NOT NULL UNIQUE, avatar_url TEXT NOT NULL DEFAULT '' ); diff --git a/store/db/migration/prod/0.15/00__drop_user_open_id.sql b/store/db/migration/prod/0.15/00__drop_user_open_id.sql new file mode 100644 index 00000000..50b8c86b --- /dev/null +++ b/store/db/migration/prod/0.15/00__drop_user_open_id.sql @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS user_temp; + +CREATE TABLE user_temp ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), + updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), + row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL', + username TEXT NOT NULL UNIQUE, + role TEXT NOT NULL CHECK (role IN ('HOST', 'ADMIN', 'USER')) DEFAULT 'USER', + email TEXT NOT NULL DEFAULT '', + nickname TEXT NOT NULL DEFAULT '', + password_hash TEXT NOT NULL, + avatar_url TEXT NOT NULL DEFAULT '' +); + +INSERT INTO + user_temp (id, created_ts, updated_ts, row_status, username, role, email, nickname, password_hash, avatar_url) +SELECT + id, created_ts, updated_ts, row_status, username, role, email, nickname, password_hash, avatar_url +FROM + user; + +DROP TABLE user; + +ALTER TABLE user_temp_temp RENAME TO user_temp; diff --git a/store/db/migration/prod/LATEST__SCHEMA.sql b/store/db/migration/prod/LATEST__SCHEMA.sql index 03bef88a..225eef37 100644 --- a/store/db/migration/prod/LATEST__SCHEMA.sql +++ b/store/db/migration/prod/LATEST__SCHEMA.sql @@ -23,7 +23,6 @@ CREATE TABLE user ( email TEXT NOT NULL DEFAULT '', nickname TEXT NOT NULL DEFAULT '', password_hash TEXT NOT NULL, - open_id TEXT NOT NULL UNIQUE, avatar_url TEXT NOT NULL DEFAULT '' ); diff --git a/store/user.go b/store/user.go index e5939300..6245b0e9 100644 --- a/store/user.go +++ b/store/user.go @@ -43,7 +43,6 @@ type User struct { Email string Nickname string PasswordHash string - OpenID string AvatarURL string } @@ -59,7 +58,6 @@ type UpdateUser struct { Password *string AvatarURL *string PasswordHash *string - OpenID *string } type FindUser struct { @@ -69,7 +67,6 @@ type FindUser struct { Role *Role Email *string Nickname *string - OpenID *string } type DeleteUser struct { @@ -83,10 +80,9 @@ func (s *Store) CreateUser(ctx context.Context, create *User) (*User, error) { role, email, nickname, - password_hash, - open_id + password_hash ) - VALUES (?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?) RETURNING id, avatar_url, created_ts, updated_ts, row_status ` if err := s.db.QueryRowContext( @@ -97,7 +93,6 @@ func (s *Store) CreateUser(ctx context.Context, create *User) (*User, error) { create.Email, create.Nickname, create.PasswordHash, - create.OpenID, ).Scan( &create.ID, &create.AvatarURL, @@ -136,16 +131,13 @@ func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, erro if v := update.PasswordHash; v != nil { set, args = append(set, "password_hash = ?"), append(args, *v) } - if v := update.OpenID; v != nil { - set, args = append(set, "open_id = ?"), append(args, *v) - } args = append(args, update.ID) query := ` UPDATE user SET ` + strings.Join(set, ", ") + ` WHERE id = ? - RETURNING id, username, role, email, nickname, password_hash, open_id, avatar_url, created_ts, updated_ts, row_status + RETURNING id, username, role, email, nickname, password_hash, avatar_url, created_ts, updated_ts, row_status ` user := &User{} if err := s.db.QueryRowContext(ctx, query, args...).Scan( @@ -155,7 +147,6 @@ func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, erro &user.Email, &user.Nickname, &user.PasswordHash, - &user.OpenID, &user.AvatarURL, &user.CreatedTs, &user.UpdatedTs, @@ -186,9 +177,6 @@ func (s *Store) ListUsers(ctx context.Context, find *FindUser) ([]*User, error) if v := find.Nickname; v != nil { where, args = append(where, "nickname = ?"), append(args, *v) } - if v := find.OpenID; v != nil { - where, args = append(where, "open_id = ?"), append(args, *v) - } query := ` SELECT @@ -198,7 +186,6 @@ func (s *Store) ListUsers(ctx context.Context, find *FindUser) ([]*User, error) email, nickname, password_hash, - open_id, avatar_url, created_ts, updated_ts, @@ -223,7 +210,6 @@ func (s *Store) ListUsers(ctx context.Context, find *FindUser) ([]*User, error) &user.Email, &user.Nickname, &user.PasswordHash, - &user.OpenID, &user.AvatarURL, &user.CreatedTs, &user.UpdatedTs, diff --git a/test/store/user_test.go b/test/store/user_test.go index 6d7d93ae..29aed53d 100644 --- a/test/store/user_test.go +++ b/test/store/user_test.go @@ -42,7 +42,6 @@ func createTestingHostUser(ctx context.Context, ts *store.Store) (*store.User, e Role: store.RoleHost, Email: "test@test.com", Nickname: "test_nickname", - OpenID: "test_open_id", } passwordHash, err := bcrypt.GenerateFromPassword([]byte("test_password"), bcrypt.DefaultCost) if err != nil { diff --git a/web/src/components/Settings/MyAccountSection.tsx b/web/src/components/Settings/MyAccountSection.tsx index 38267f8a..5a2b03f2 100644 --- a/web/src/components/Settings/MyAccountSection.tsx +++ b/web/src/components/Settings/MyAccountSection.tsx @@ -1,37 +1,13 @@ -import { Button, Input, Textarea } from "@mui/joy"; +import { Button } from "@mui/joy"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { useUserV1Store } from "@/store/v1"; import { useTranslate } from "@/utils/i18n"; import showChangePasswordDialog from "../ChangePasswordDialog"; -import { showCommonDialog } from "../Dialog/CommonDialog"; -import Icon from "../Icon"; import showUpdateAccountDialog from "../UpdateAccountDialog"; import UserAvatar from "../UserAvatar"; const MyAccountSection = () => { const t = useTranslate(); - const userV1Store = useUserV1Store(); const user = useCurrentUser(); - const openAPIRoute = `${window.location.origin}/api/v1/memo?openId=${user.openId}`; - - const handleResetOpenIdBtnClick = async () => { - showCommonDialog({ - title: t("setting.account-section.openapi-reset"), - content: t("setting.account-section.openapi-reset-warning"), - style: "warning", - dialogName: "reset-openid-dialog", - onConfirm: async () => { - await userV1Store.updateUser( - { - username: user.username, - }, - ["reset_open_id"] - ); - }, - }); - }; - - const exampleWithCurl = `curl '${openAPIRoute}' -H 'Content-Type: application/json' --data-raw '{"content":"Hello world!"}'`; return ( <> @@ -52,17 +28,6 @@ const MyAccountSection = () => { -
Open ID
-Open API Example with cURL
- -