(ctx context.Context, in *createAPIKeyInput)
| 110 | } |
| 111 | |
| 112 | func (s *Server) handleCreateAPIKey(ctx context.Context, in *createAPIKeyInput) (*createAPIKeyOutput, error) { |
| 113 | user, err := s.requireAccountUser(ctx) |
| 114 | if err != nil { |
| 115 | return nil, err |
| 116 | } |
| 117 | if s.deps.CreateScopedAPIKey == nil { |
| 118 | return nil, NewError(http.StatusNotImplemented, "not_implemented", "API keys are not available on this deployment") |
| 119 | } |
| 120 | |
| 121 | // Optional expiry: RFC 3339, must be in the future. Empty = never expires. |
| 122 | var expiresAt *time.Time |
| 123 | if in.Body.ExpiresAt != "" { |
| 124 | t, perr := time.Parse(time.RFC3339, in.Body.ExpiresAt) |
| 125 | if perr != nil { |
| 126 | return nil, NewError(http.StatusBadRequest, "invalid_expires_at", "expires_at must be an RFC 3339 timestamp") |
| 127 | } |
| 128 | if !t.After(time.Now()) { |
| 129 | return nil, NewError(http.StatusBadRequest, "invalid_expires_at", "expires_at must be in the future") |
| 130 | } |
| 131 | expiresAt = &t |
| 132 | } |
| 133 | |
| 134 | scope := in.Body.Scope |
| 135 | if scope == "" { |
| 136 | scope = identity.ScopeAccount |
| 137 | } |
| 138 | if !identity.ValidScope(scope) { |
| 139 | return nil, NewError(http.StatusBadRequest, "invalid_scope", "scope must be 'account' or 'agent'") |
| 140 | } |
| 141 | |
| 142 | // For an agent-scoped key, resolve the named inbox to its id (ownership |
| 143 | // re-checked by resolveOwnedAgent) so a wrong/foreign agent is rejected |
| 144 | // rather than minting an over-broad or cross-tenant key. |
| 145 | var agentID string |
| 146 | if scope == identity.ScopeAgent { |
| 147 | if in.Body.Agent == "" { |
| 148 | return nil, NewError(http.StatusBadRequest, "agent_required", "agent (inbox email) is required when scope=agent") |
| 149 | } |
| 150 | ag, aerr := s.resolveOwnedAgent(ctx, in.Body.Agent) |
| 151 | if aerr != nil { |
| 152 | return nil, aerr |
| 153 | } |
| 154 | agentID = ag.ID |
| 155 | } |
| 156 | |
| 157 | key, err := s.deps.CreateScopedAPIKey(ctx, user.ID, in.Body.Name, scope, agentID, expiresAt) |
| 158 | if err != nil { |
| 159 | return nil, NewError(http.StatusInternalServerError, "internal_error", "failed to create API key") |
| 160 | } |
| 161 | return &createAPIKeyOutput{Body: CreateAPIKeyResponse{ |
| 162 | APIKeyView: apiKeyView(*key), |
| 163 | Key: key.PlaintextKey, |
| 164 | }}, nil |
| 165 | } |
| 166 | |
| 167 | func (s *Server) handleDeleteAPIKey(ctx context.Context, in *deleteAPIKeyInput) (*deleteAPIKeyOutput, error) { |
| 168 | user, err := s.requireAccountUser(ctx) |
nothing calls this directly
no test coverage detected