feat(login): use account chosen on the device-approval page; stdin picker becomes fallback
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
098a2091b9
commit
2b685348c9
@ -57,9 +57,13 @@ func newLoginCmd() *cobra.Command {
|
||||
cr.Hosts = map[string]creds.HostCreds{}
|
||||
}
|
||||
hc := creds.HostCreds{Token: poll.Msg.AccessToken}
|
||||
authed := orchclient.New(host, hc.Token)
|
||||
if err := selectActiveAccount(ctx, authed, &hc); err != nil {
|
||||
return err
|
||||
if applyPolledAccount(&hc, poll.Msg.AccountId, poll.Msg.AccountSlug) {
|
||||
fmt.Printf("Active account: %s\n", hc.ActiveAccountSlug)
|
||||
} else {
|
||||
authed := orchclient.New(host, hc.Token)
|
||||
if err := selectActiveAccount(ctx, authed, &hc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cr.Hosts[host] = hc
|
||||
if err := cr.Save(); err != nil {
|
||||
@ -103,6 +107,18 @@ func newWhoamiCmd() *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// applyPolledAccount copies the account chosen on the device-approval page
|
||||
// into hc. Returns false when the server sent no account (older orchestrator,
|
||||
// or an approval without a selection) — the stdin picker should run instead.
|
||||
func applyPolledAccount(hc *creds.HostCreds, accountID, accountSlug string) bool {
|
||||
if accountID == "" {
|
||||
return false
|
||||
}
|
||||
hc.ActiveAccountID = accountID
|
||||
hc.ActiveAccountSlug = accountSlug
|
||||
return true
|
||||
}
|
||||
|
||||
// selectActiveAccount fetches the user's accounts and writes the active one
|
||||
// into hc. With 0 accounts it errors (the server contract guarantees every
|
||||
// user has at least one). With 1 it auto-selects silently. With ≥2 it
|
||||
|
||||
27
cmd/ninja/cmd/login_test.go
Normal file
27
cmd/ninja/cmd/login_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.dev.alexdunmow.com/block/cli/internal/creds"
|
||||
)
|
||||
|
||||
func TestApplyPolledAccount_Set(t *testing.T) {
|
||||
hc := creds.HostCreds{Token: "tok"}
|
||||
if !applyPolledAccount(&hc, "acct-id-1", "blockninja") {
|
||||
t.Fatal("want true when server supplies an account")
|
||||
}
|
||||
if hc.ActiveAccountID != "acct-id-1" || hc.ActiveAccountSlug != "blockninja" {
|
||||
t.Fatalf("hc = %+v, want active account set", hc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyPolledAccount_EmptyFallsThrough(t *testing.T) {
|
||||
hc := creds.HostCreds{Token: "tok"}
|
||||
if applyPolledAccount(&hc, "", "") {
|
||||
t.Fatal("want false when server sent no account (older orchestrator)")
|
||||
}
|
||||
if hc.ActiveAccountID != "" || hc.ActiveAccountSlug != "" {
|
||||
t.Fatalf("hc = %+v, want untouched", hc)
|
||||
}
|
||||
}
|
||||
@ -5326,6 +5326,8 @@ type PollDeviceResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
|
||||
Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
|
||||
AccountId string `protobuf:"bytes,3,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"`
|
||||
AccountSlug string `protobuf:"bytes,4,opt,name=account_slug,json=accountSlug,proto3" json:"account_slug,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -5374,9 +5376,24 @@ func (x *PollDeviceResponse) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PollDeviceResponse) GetAccountId() string {
|
||||
if x != nil {
|
||||
return x.AccountId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PollDeviceResponse) GetAccountSlug() string {
|
||||
if x != nil {
|
||||
return x.AccountSlug
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ApproveDeviceRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
UserCode string `protobuf:"bytes,1,opt,name=user_code,json=userCode,proto3" json:"user_code,omitempty"`
|
||||
AccountId string `protobuf:"bytes,2,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -5418,6 +5435,13 @@ func (x *ApproveDeviceRequest) GetUserCode() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ApproveDeviceRequest) GetAccountId() string {
|
||||
if x != nil {
|
||||
return x.AccountId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ApproveDeviceResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
@ -6290,12 +6314,17 @@ const file_orchestrator_v1_plugin_registry_proto_rawDesc = "" +
|
||||
"\x12expires_in_seconds\x18\x05 \x01(\x05R\x10expiresInSeconds\"4\n" +
|
||||
"\x11PollDeviceRequest\x12\x1f\n" +
|
||||
"\vdevice_code\x18\x01 \x01(\tR\n" +
|
||||
"deviceCode\"O\n" +
|
||||
"deviceCode\"\x91\x01\n" +
|
||||
"\x12PollDeviceResponse\x12!\n" +
|
||||
"\faccess_token\x18\x01 \x01(\tR\vaccessToken\x12\x16\n" +
|
||||
"\x06status\x18\x02 \x01(\tR\x06status\"3\n" +
|
||||
"\x06status\x18\x02 \x01(\tR\x06status\x12\x1d\n" +
|
||||
"\n" +
|
||||
"account_id\x18\x03 \x01(\tR\taccountId\x12!\n" +
|
||||
"\faccount_slug\x18\x04 \x01(\tR\vaccountSlug\"R\n" +
|
||||
"\x14ApproveDeviceRequest\x12\x1b\n" +
|
||||
"\tuser_code\x18\x01 \x01(\tR\buserCode\"\x17\n" +
|
||||
"\tuser_code\x18\x01 \x01(\tR\buserCode\x12\x1d\n" +
|
||||
"\n" +
|
||||
"account_id\x18\x02 \x01(\tR\taccountId\"\x17\n" +
|
||||
"\x15ApproveDeviceResponse\"0\n" +
|
||||
"\x11DenyDeviceRequest\x12\x1b\n" +
|
||||
"\tuser_code\x18\x01 \x01(\tR\buserCode\"\x14\n" +
|
||||
|
||||
@ -650,9 +650,14 @@ message PollDeviceRequest { string device_code = 1; }
|
||||
message PollDeviceResponse {
|
||||
string access_token = 1;
|
||||
string status = 2;
|
||||
string account_id = 3;
|
||||
string account_slug = 4;
|
||||
}
|
||||
|
||||
message ApproveDeviceRequest { string user_code = 1; }
|
||||
message ApproveDeviceRequest {
|
||||
string user_code = 1;
|
||||
string account_id = 2;
|
||||
}
|
||||
message ApproveDeviceResponse {}
|
||||
|
||||
message DenyDeviceRequest { string user_code = 1; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user