|
| 1 | +package org.genspectrum.dashboardsbackend.controller |
| 2 | + |
| 3 | +import io.swagger.v3.oas.annotations.Operation |
| 4 | +import org.genspectrum.dashboardsbackend.api.ApiKeyMetadata |
| 5 | +import org.genspectrum.dashboardsbackend.api.GeneratedApiKey |
| 6 | +import org.genspectrum.dashboardsbackend.api.ValidateApiKeyRequest |
| 7 | +import org.genspectrum.dashboardsbackend.api.ValidateApiKeyResponse |
| 8 | +import org.genspectrum.dashboardsbackend.model.apikey.ApiKeyModel |
| 9 | +import org.springframework.http.HttpStatus |
| 10 | +import org.springframework.http.MediaType |
| 11 | +import org.springframework.web.bind.annotation.DeleteMapping |
| 12 | +import org.springframework.web.bind.annotation.GetMapping |
| 13 | +import org.springframework.web.bind.annotation.PostMapping |
| 14 | +import org.springframework.web.bind.annotation.RequestBody |
| 15 | +import org.springframework.web.bind.annotation.RequestParam |
| 16 | +import org.springframework.web.bind.annotation.ResponseStatus |
| 17 | +import org.springframework.web.bind.annotation.RestController |
| 18 | + |
| 19 | +@RestController |
| 20 | +class ApiKeyController(private val apiKeyModel: ApiKeyModel) { |
| 21 | + @GetMapping("/api-keys", produces = [MediaType.APPLICATION_JSON_VALUE]) |
| 22 | + @Operation( |
| 23 | + summary = "Get API key metadata", |
| 24 | + description = "Returns metadata for the user's current API key. Returns 404 if no key exists.", |
| 25 | + ) |
| 26 | + fun getApiKey(@RequestParam userId: Long): ApiKeyMetadata = apiKeyModel.getApiKey(userId) |
| 27 | + |
| 28 | + @PostMapping("/api-keys", produces = [MediaType.APPLICATION_JSON_VALUE]) |
| 29 | + @ResponseStatus(HttpStatus.CREATED) |
| 30 | + @Operation( |
| 31 | + summary = "Generate a new API key", |
| 32 | + description = "Generates a new API key for the user. Returns the raw key once - it is never stored. " + |
| 33 | + "Returns 409 if a key already exists.", |
| 34 | + ) |
| 35 | + fun generateApiKey(@RequestParam userId: Long): GeneratedApiKey = apiKeyModel.generateApiKey(userId) |
| 36 | + |
| 37 | + @DeleteMapping("/api-keys") |
| 38 | + @ResponseStatus(HttpStatus.NO_CONTENT) |
| 39 | + @Operation( |
| 40 | + summary = "Revoke API key", |
| 41 | + description = "Deletes the user's current API key. Returns 404 if no key exists.", |
| 42 | + ) |
| 43 | + fun revokeApiKey(@RequestParam userId: Long) = apiKeyModel.revokeApiKey(userId) |
| 44 | + |
| 45 | + @PostMapping("/internal/api-keys/validate", produces = [MediaType.APPLICATION_JSON_VALUE]) |
| 46 | + @Operation( |
| 47 | + summary = "Validate an API key", |
| 48 | + description = """Takes a raw API key and returns the associated userId on success (200). |
| 49 | +Returns 404 if the key does not match any stored hash - the proxy treats this as an invalid |
| 50 | +credential and falls through to the session cookie check. Only reachable within the internal |
| 51 | +Docker network, so no additional access control is applied.""", |
| 52 | + ) |
| 53 | + fun validateApiKey(@RequestBody request: ValidateApiKeyRequest): ValidateApiKeyResponse { |
| 54 | + val userId = apiKeyModel.validateApiKey(request.key) |
| 55 | + return ValidateApiKeyResponse(userId = userId) |
| 56 | + } |
| 57 | +} |
0 commit comments