fork of indigo with slightly nicer lexgen

goat account service-auth-local: create service auth token via locally-held signing key

Changed files
+83 -1
cmd
goat
+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 }