From 7ea84a221b2c846419b0107e32c8919291c2b83b Mon Sep 17 00:00:00 2001 From: FingerLeader <43462394+FingerLeader@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:21:08 +0800 Subject: [PATCH] add whoami (#216) --------- Signed-off-by: FingerLeader --- docs/generate_doc/ticloud_auth.md | 1 + docs/generate_doc/ticloud_auth_whoami.md | 33 ++++++ .../generate_doc/ticloud_serverless_create.md | 1 + .../generate_doc/ticloud_serverless_update.md | 19 ++-- internal/cli/auth/auth.go | 8 +- internal/cli/auth/whoami.go | 101 ++++++++++++++++++ 6 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 docs/generate_doc/ticloud_auth_whoami.md create mode 100644 internal/cli/auth/whoami.go diff --git a/docs/generate_doc/ticloud_auth.md b/docs/generate_doc/ticloud_auth.md index d61f6f0a..412e0d8d 100644 --- a/docs/generate_doc/ticloud_auth.md +++ b/docs/generate_doc/ticloud_auth.md @@ -21,4 +21,5 @@ Login and logout via TiDB Cloud API * [ticloud](ticloud.md) - CLI tool to manage TiDB Cloud * [ticloud auth login](ticloud_auth_login.md) - Authenticate with TiDB Cloud * [ticloud auth logout](ticloud_auth_logout.md) - Log out of TiDB Cloud +* [ticloud auth whoami](ticloud_auth_whoami.md) - Display information about the current user diff --git a/docs/generate_doc/ticloud_auth_whoami.md b/docs/generate_doc/ticloud_auth_whoami.md new file mode 100644 index 00000000..f188bd7f --- /dev/null +++ b/docs/generate_doc/ticloud_auth_whoami.md @@ -0,0 +1,33 @@ +## ticloud auth whoami + +Display information about the current user + +``` +ticloud auth whoami [flags] +``` + +### Examples + +``` + To display information about the current user: + $ ticloud auth whoami +``` + +### Options + +``` + -h, --help help for whoami +``` + +### Options inherited from parent commands + +``` + -D, --debug Enable debug mode + --no-color Disable color output + -P, --profile string Profile to use from your configuration file +``` + +### SEE ALSO + +* [ticloud auth](ticloud_auth.md) - Login and logout via TiDB Cloud API + diff --git a/docs/generate_doc/ticloud_serverless_create.md b/docs/generate_doc/ticloud_serverless_create.md index 9c18229e..9508a160 100644 --- a/docs/generate_doc/ticloud_serverless_create.md +++ b/docs/generate_doc/ticloud_serverless_create.md @@ -22,6 +22,7 @@ ticloud serverless create [flags] ### Options ``` + --disable-public-endpoint Whether the public endpoint is disabled. (optional) -n, --display-name string Display name of the cluster to de created. --encryption Whether Enhanced Encryption at Rest is enabled. (optional) -h, --help help for create diff --git a/docs/generate_doc/ticloud_serverless_update.md b/docs/generate_doc/ticloud_serverless_update.md index 303f1370..0517ea05 100644 --- a/docs/generate_doc/ticloud_serverless_update.md +++ b/docs/generate_doc/ticloud_serverless_update.md @@ -22,15 +22,16 @@ ticloud serverless update [flags] ### Options ``` - --annotations string The annotations of the cluster to be added or updated. - Interactive example: {"annotation1":"value1","annotation2":"value2"}. - NonInteractive example: "{\"annotation1\":\"value1\",\"annotation2\":\"value2\"}". - -c, --cluster-id string The ID of the cluster to be updated. - -n, --display-name string The new displayName of the cluster to be updated. - -h, --help help for update - --labels string The labels of the cluster to be added or updated. - Interactive example: {"label1":"value1","label2":"value2"}. - NonInteractive example: "{\"label1\":\"value1\",\"label2\":\"value2\"}". + --annotations string The annotations of the cluster to be added or updated. + Interactive example: {"annotation1":"value1","annotation2":"value2"}. + NonInteractive example: "{\"annotation1\":\"value1\",\"annotation2\":\"value2\"}". + -c, --cluster-id string The ID of the cluster to be updated. + --disable-public-endpoint Disable the public endpoint of the cluster. + -n, --display-name string The new displayName of the cluster to be updated. + -h, --help help for update + --labels string The labels of the cluster to be added or updated. + Interactive example: {"label1":"value1","label2":"value2"}. + NonInteractive example: "{\"label1\":\"value1\",\"label2\":\"value2\"}". ``` ### Options inherited from parent commands diff --git a/internal/cli/auth/auth.go b/internal/cli/auth/auth.go index 7c0147ee..e3cbfdd8 100644 --- a/internal/cli/auth/auth.go +++ b/internal/cli/auth/auth.go @@ -24,9 +24,10 @@ const ( tokenTypeHint = "access_token" grantType = "urn:ietf:params:oauth:grant-type:device_code" - authPath = "/v1/device_authorization" - accessPath = "/v1/token" - revokePath = "/v1/revoke" + authPath = "/v1/device_authorization" + accessPath = "/v1/token" + revokePath = "/v1/revoke" + userInfoPath = "/v1/userinfo" errSlowDown = "slow_down" errPending = "authorization_pending" @@ -40,5 +41,6 @@ func AuthCmd(h *internal.Helper) *cobra.Command { authCmd.AddCommand(LoginCmd(h)) authCmd.AddCommand(LogoutCmd(h)) + authCmd.AddCommand(WhoamiCmd(h)) return authCmd } diff --git a/internal/cli/auth/whoami.go b/internal/cli/auth/whoami.go new file mode 100644 index 00000000..5a971c15 --- /dev/null +++ b/internal/cli/auth/whoami.go @@ -0,0 +1,101 @@ +// Copyright 2024 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package auth + +import ( + "encoding/json" + "fmt" + + "tidbcloud-cli/internal" + "tidbcloud-cli/internal/config" + "tidbcloud-cli/internal/config/store" + "tidbcloud-cli/internal/flag" + ver "tidbcloud-cli/internal/version" + + "github.com/fatih/color" + "github.com/go-resty/resty/v2" + "github.com/juju/errors" + "github.com/spf13/cobra" + _ "github.com/xo/usql/drivers/mysql" + "github.com/zalando/go-keyring" +) + +type WhoamiOpts struct { + client *resty.Client +} + +func WhoamiCmd(h *internal.Helper) *cobra.Command { + opts := WhoamiOpts{ + client: resty.New(), + } + var whoamiCmd = &cobra.Command{ + Use: "whoami", + Short: "Display information about the current user", + Args: cobra.NoArgs, + Example: fmt.Sprintf(` To display information about the current user: + $ %[1]s auth whoami`, config.CliName), + PreRunE: func(cmd *cobra.Command, args []string) error { + debug, err := cmd.Flags().GetBool(flag.Debug) + if err != nil { + return err + } + opts.client.SetDebug(debug) + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + token, err := config.GetAccessToken() + if err != nil { + if errors.Is(err, keyring.ErrNotFound) || errors.Is(err, store.ErrNotSupported) { + fmt.Fprintln(h.IOStreams.Out, color.YellowString("You are not logged in.")) + return nil + } + return err + } + + resp, err := opts.client.R(). + SetContext(ctx). + SetHeader("Authorization", "Bearer "+token). + SetHeader("user-agent", fmt.Sprintf("%s/%s", config.CliName, ver.Version)). + Get(fmt.Sprintf("%s%s", config.GetOAuthEndpoint(), userInfoPath)) + + if err != nil { + return err + } + + if !resp.IsSuccess() { + return errors.Errorf("Failed to get user info, code: %s", resp.Status()) + } + + var userInfo UserInfo + err = json.Unmarshal(resp.Body(), &userInfo) + if err != nil { + return err + } + + fmt.Fprintln(h.IOStreams.Out, "Email:", userInfo.Email) + fmt.Fprintln(h.IOStreams.Out, "Username:", userInfo.Username) + + return nil + }, + } + + return whoamiCmd +} + +type UserInfo struct { + Email string `json:"email"` + Username string `json:"username"` +}