+83
-1
cmd/goat/account.go
+83
-1
cmd/goat/account.go
···
8
"time"
9
10
comatproto "github.com/bluesky-social/indigo/api/atproto"
11
"github.com/bluesky-social/indigo/atproto/syntax"
12
"github.com/bluesky-social/indigo/xrpc"
13
···
89
},
90
&cli.Command{
91
Name: "service-auth",
92
-
Usage: "create service auth token",
93
Flags: []cli.Flag{
94
&cli.StringFlag{
95
Name: "endpoint",
···
109
},
110
},
111
Action: runAccountServiceAuth,
112
},
113
&cli.Command{
114
Name: "create",
···
365
}
366
367
fmt.Println(resp.Token)
368
369
return nil
370
}
···
8
"time"
9
10
comatproto "github.com/bluesky-social/indigo/api/atproto"
11
+
"github.com/bluesky-social/indigo/atproto/auth"
12
+
"github.com/bluesky-social/indigo/atproto/crypto"
13
"github.com/bluesky-social/indigo/atproto/syntax"
14
"github.com/bluesky-social/indigo/xrpc"
15
···
91
},
92
&cli.Command{
93
Name: "service-auth",
94
+
Usage: "ask the PDS to create a service auth token",
95
Flags: []cli.Flag{
96
&cli.StringFlag{
97
Name: "endpoint",
···
111
},
112
},
113
Action: runAccountServiceAuth,
114
+
},
115
+
&cli.Command{
116
+
Name: "service-auth-local",
117
+
Usage: "create service auth token via locally-held signing key",
118
+
Flags: []cli.Flag{
119
+
&cli.StringFlag{
120
+
Name: "atproto-signing-key",
121
+
Required: true,
122
+
Usage: "private key used to sign the token (multibase syntax)",
123
+
EnvVars: []string{"ATPROTO_SIGNING_KEY"},
124
+
},
125
+
&cli.StringFlag{
126
+
Name: "iss",
127
+
Required: true,
128
+
Usage: "the DID of the account issuing the token",
129
+
},
130
+
&cli.StringFlag{
131
+
Name: "endpoint",
132
+
Aliases: []string{"lxm"},
133
+
Usage: "restrict token to API endpoint (NSID, optional)",
134
+
},
135
+
&cli.StringFlag{
136
+
Name: "audience",
137
+
Aliases: []string{"aud"},
138
+
Required: true,
139
+
Usage: "DID of service that will receive and validate token",
140
+
},
141
+
&cli.IntFlag{
142
+
Name: "duration-sec",
143
+
Value: 60,
144
+
Usage: "validity time window of token (seconds)",
145
+
},
146
+
},
147
+
Action: runAccountServiceAuthLocal,
148
},
149
&cli.Command{
150
Name: "create",
···
401
}
402
403
fmt.Println(resp.Token)
404
+
405
+
return nil
406
+
}
407
+
408
+
func runAccountServiceAuthLocal(cctx *cli.Context) error {
409
+
privStr := cctx.String("atproto-signing-key")
410
+
if privStr == "" {
411
+
return fmt.Errorf("private key must be provided")
412
+
}
413
+
privkey, err := crypto.ParsePrivateMultibase(privStr)
414
+
if err != nil {
415
+
return err
416
+
}
417
+
418
+
issString := cctx.String("iss")
419
+
iss, err := syntax.ParseDID(issString)
420
+
if err != nil {
421
+
return fmt.Errorf("iss argument must be a valid DID: %w", err)
422
+
}
423
+
424
+
lxmString := cctx.String("endpoint")
425
+
var lxm *syntax.NSID = nil
426
+
if lxmString != "" {
427
+
lxmTmp, err := syntax.ParseNSID(lxmString)
428
+
if err != nil {
429
+
return fmt.Errorf("lxm argument must be a valid NSID: %w", err)
430
+
}
431
+
lxm = &lxmTmp
432
+
}
433
+
434
+
aud := cctx.String("audience")
435
+
// TODO: can aud DID have a fragment?
436
+
_, err = syntax.ParseDID(aud)
437
+
if err != nil {
438
+
return fmt.Errorf("aud argument must be a valid DID: %w", err)
439
+
}
440
+
441
+
durSec := cctx.Int("duration-sec")
442
+
duration := time.Duration(durSec * int(time.Second))
443
+
444
+
token, err := auth.SignServiceAuth(iss, aud, duration, lxm, privkey)
445
+
if err != nil {
446
+
return err
447
+
}
448
+
449
+
fmt.Println(token)
450
451
return nil
452
}