mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
fix(auth): prompt for --with-token without echo on a terminal
With stdin on a terminal, auth login --with-token read the pasted token from the raw terminal, which echoed it in clear text without a prompt. It now asks with a hidden "Paste an access token" prompt, and refuses to read the terminal when prompting is disabled. Piped stdin is read as before. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
2 files changed
+33
-1
No files matched your search
+13
-1
@@ -185,6 +185,18 @@ func (a *application) authCommand() *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
method = settings.AuthOAuth
|
method = settings.AuthOAuth
|
||||||
|
} else if a.deps.Streams.InTTY {
|
||||||
|
if !a.policy(snapshot).CanPrompt(a.deps.Streams) {
|
||||||
|
return clierr.Wrap(clierr.Usage, errors.New("--with-token reads the token from stdin; pipe it in, for example: tea auth login --with-token < token.txt"))
|
||||||
|
}
|
||||||
|
token, err := a.deps.Prompter.SecretInput(cmd.Context(), "Paste an access token")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
credential.AccessToken = strings.TrimSpace(token)
|
||||||
|
if credential.AccessToken == "" {
|
||||||
|
return clierr.Wrap(clierr.Usage, errors.New("access token cannot be empty"))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data, err := io.ReadAll(io.LimitReader(a.deps.Streams.In, 65537))
|
data, err := io.ReadAll(io.LimitReader(a.deps.Streams.In, 65537))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -214,7 +226,7 @@ func (a *application) authCommand() *cobra.Command {
|
|||||||
login.Flags().BoolVar(&oauth, "oauth", false, "Authorize through a browser using OAuth PKCE")
|
login.Flags().BoolVar(&oauth, "oauth", false, "Authorize through a browser using OAuth PKCE")
|
||||||
login.Flags().StringVar(&clientID, "client-id", "", "OAuth client ID registered on the instance (default: the instance's stored ID, then tea's)")
|
login.Flags().StringVar(&clientID, "client-id", "", "OAuth client ID registered on the instance (default: the instance's stored ID, then tea's)")
|
||||||
login.Flags().BoolVar(&insecure, "insecure", false, "Skip TLS certificate verification for this instance")
|
login.Flags().BoolVar(&insecure, "insecure", false, "Skip TLS certificate verification for this instance")
|
||||||
login.Flags().BoolVar(&withToken, "with-token", false, "Read a personal access token from stdin")
|
login.Flags().BoolVar(&withToken, "with-token", false, "Read a personal access token from stdin, or prompt for it on a terminal")
|
||||||
login.Flags().StringVar(&sshKey, "ssh-key", "", "Authenticate with an SSH private key via HTTP signatures")
|
login.Flags().StringVar(&sshKey, "ssh-key", "", "Authenticate with an SSH private key via HTTP signatures")
|
||||||
login.Flags().StringVar(&sshAgentPrincipal, "ssh-agent-principal", "", "Authenticate with an ssh-agent certificate principal via HTTP signatures")
|
login.Flags().StringVar(&sshAgentPrincipal, "ssh-agent-principal", "", "Authenticate with an ssh-agent certificate principal via HTTP signatures")
|
||||||
login.Flags().StringVar(&sshAgentKey, "ssh-agent-key", "", "Authenticate with an ssh-agent public key fingerprint via HTTP signatures")
|
login.Flags().StringVar(&sshAgentKey, "ssh-agent-key", "", "Authenticate with an ssh-agent public key fingerprint via HTTP signatures")
|
||||||
|
|||||||
@@ -87,6 +87,26 @@ func TestLoginValidatesUserEnvironmentWithFlagPrecedence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoginWithTokenPromptsWithoutEchoOnATerminal(t *testing.T) {
|
||||||
|
server := newAuthenticatedServer(http.NotFoundHandler())
|
||||||
|
defer server.Close()
|
||||||
|
args := []string{"auth", "login", "--host", server.URL, "--with-token", "--credential-store", "file"}
|
||||||
|
deps, _, _ := testDeps(t)
|
||||||
|
deps.Streams.In = strings.NewReader("echoed-token\n")
|
||||||
|
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||||
|
prompt := &scriptedPrompter{secret: " private-login-token "}
|
||||||
|
deps.Prompter = prompt
|
||||||
|
err := Execute(context.Background(), deps, append(args, "--no-input"))
|
||||||
|
require.Equal(t, clierr.Usage, clierr.ExitCode(err), "%v", err)
|
||||||
|
require.ErrorContains(t, err, "tea auth login --with-token < token.txt")
|
||||||
|
require.Empty(t, prompt.secrets)
|
||||||
|
require.NoError(t, Execute(context.Background(), deps, args))
|
||||||
|
require.Equal(t, []string{"Paste an access token"}, prompt.secrets)
|
||||||
|
credential, err := deps.Credentials.Load(server.URL, "alice", settings.StoreFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "private-login-token", credential.AccessToken)
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoginInsecureInstance(t *testing.T) {
|
func TestLoginInsecureInstance(t *testing.T) {
|
||||||
server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||||
_, _ = w.Write([]byte(`{"login":"alice"}`))
|
_, _ = w.Write([]byte(`{"login":"alice"}`))
|
||||||
|
|||||||
Reference in new issue
Block a user