package main import ( "flag" "fmt" "os" "strings" ) func (t *tool) runToken(args []string) { if len(args) == 0 { fatalf("token requires a subcommand: list, revoke, revoke-all") } switch args[0] { case "list": t.tokenList(args[1:]) case "revoke": t.tokenRevoke(args[1:]) case "revoke-all": t.tokenRevokeAll(args[1:]) default: fatalf("unknown token subcommand %q", args[0]) } } func (t *tool) runPrune(args []string) { if len(args) == 0 { fatalf("prune requires a subcommand: tokens") } switch args[0] { case "tokens": t.pruneTokens() default: fatalf("unknown prune subcommand %q", args[0]) } } func (t *tool) tokenList(args []string) { fs := flag.NewFlagSet("token list", flag.ExitOnError) id := fs.String("id", "", "account UUID (required)") _ = fs.Parse(args) if *id == "" { fatalf("token list: --id is required") } a, err := t.db.GetAccountByUUID(*id) if err != nil { fatalf("get account: %v", err) } records, err := t.db.ListTokensForAccount(a.ID) if err != nil { fatalf("list tokens: %v", err) } if len(records) == 0 { fmt.Printf("no token records for account %s\n", a.Username) return } fmt.Printf("tokens for %s (%s):\n", a.Username, a.UUID) fmt.Printf("%-36s %-20s %-20s %-20s\n", "JTI", "ISSUED AT", "EXPIRES AT", "REVOKED AT") fmt.Println(strings.Repeat("-", 100)) for _, r := range records { revokedAt := "-" if r.RevokedAt != nil { revokedAt = r.RevokedAt.Format("2006-01-02T15:04:05Z") } fmt.Printf("%-36s %-20s %-20s %-20s\n", r.JTI, r.IssuedAt.Format("2006-01-02T15:04:05Z"), r.ExpiresAt.Format("2006-01-02T15:04:05Z"), revokedAt, ) } } func (t *tool) tokenRevoke(args []string) { fs := flag.NewFlagSet("token revoke", flag.ExitOnError) jti := fs.String("jti", "", "JTI of the token to revoke (required)") _ = fs.Parse(args) if *jti == "" { fatalf("token revoke: --jti is required") } if err := t.db.RevokeToken(*jti, "mciasdb"); err != nil { fatalf("revoke token: %v", err) } if err := t.db.WriteAuditEvent("token_revoked", nil, nil, "", fmt.Sprintf(`{"actor":"mciasdb","jti":%q}`, *jti)); err != nil { fmt.Fprintf(os.Stderr, "warning: write audit event: %v\n", err) } fmt.Printf("token %s revoked\n", *jti) } func (t *tool) tokenRevokeAll(args []string) { fs := flag.NewFlagSet("token revoke-all", flag.ExitOnError) id := fs.String("id", "", "account UUID (required)") _ = fs.Parse(args) if *id == "" { fatalf("token revoke-all: --id is required") } a, err := t.db.GetAccountByUUID(*id) if err != nil { fatalf("get account: %v", err) } if err := t.db.RevokeAllUserTokens(a.ID, "mciasdb"); err != nil { fatalf("revoke all tokens: %v", err) } if err := t.db.WriteAuditEvent("token_revoked", nil, &a.ID, "", `{"actor":"mciasdb","action":"revoke_all"}`); err != nil { fmt.Fprintf(os.Stderr, "warning: write audit event: %v\n", err) } fmt.Printf("all active tokens revoked for account %s\n", a.Username) } func (t *tool) pruneTokens() { count, err := t.db.PruneExpiredTokens() if err != nil { fatalf("prune expired tokens: %v", err) } fmt.Printf("pruned %d expired token record(s)\n", count) }