You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.6 KiB
Markdown
121 lines
3.6 KiB
Markdown
+++
|
|
title = "quotesdb/api: POST /api/admin/reset-auth-code endpoint"
|
|
priority = 6
|
|
status = "done"
|
|
ticket_type = "feature"
|
|
dependencies = ["69a2c5"]
|
|
+++
|
|
## POST /api/admin/reset-auth-code endpoint
|
|
|
|
Add the admin-protected endpoint that replaces the stored admin auth code. The caller must supply the current code via `X-Admin-Code`. A new code may be provided in the request body; if omitted, the server generates a fresh 4-word passphrase.
|
|
|
|
---
|
|
|
|
## Files to modify
|
|
|
|
- `src/bin/api/db/mod.rs` — add `update_admin_auth_code` to the `QuoteRepository` trait
|
|
- `src/bin/api/db/d1.rs` — implement `update_admin_auth_code` for D1
|
|
- `src/bin/api/db/native.rs` — implement `update_admin_auth_code` for native SQLite
|
|
- `src/bin/api/handlers/mod.rs` (or a new `src/bin/api/handlers/admin.rs`) — add the `reset_auth_code` handler
|
|
- `src/bin/api/main.rs` — register the new route
|
|
|
|
---
|
|
|
|
## New trait method (src/bin/api/db/mod.rs)
|
|
|
|
Add to the `QuoteRepository` trait:
|
|
|
|
```rust
|
|
/// Replace the admin auth code if `current` matches the stored value.
|
|
/// If `new_code` is `None`, generates a fresh 4-word passphrase.
|
|
/// Returns the new auth code string on success, or `DbError::Unauthorized`
|
|
/// if `current` does not match.
|
|
async fn update_admin_auth_code(
|
|
&self,
|
|
current: &str,
|
|
new_code: Option<&str>,
|
|
) -> Result<String, DbError>;
|
|
```
|
|
|
|
Implementation steps:
|
|
1. Fetch the stored `admin_auth_code` from `admin_config`.
|
|
2. If it does not match `current`, return `DbError::Unauthorized` (or a dedicated variant).
|
|
3. Determine the new code: use `new_code` if provided, otherwise call the existing passphrase-generation utility.
|
|
4. Write the new value to `admin_config` with `UPDATE`.
|
|
5. Return the new code string.
|
|
|
|
---
|
|
|
|
## Request / response types
|
|
|
|
```rust
|
|
#[derive(Deserialize)]
|
|
struct ResetAuthCodeRequest {
|
|
new_code: Option<String>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct ResetAuthCodeResponse {
|
|
auth_code: String,
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Handler
|
|
|
|
```rust
|
|
/// POST /api/admin/reset-auth-code
|
|
/// Requires X-Admin-Code header matching the stored admin passphrase.
|
|
/// Body: { "new_code": "optional-string" }
|
|
/// Response: 200 { "auth_code": "new-code" } or 403 on mismatch.
|
|
pub async fn reset_auth_code(
|
|
State(repo): State<Arc<dyn QuoteRepository>>,
|
|
headers: HeaderMap,
|
|
Json(payload): Json<ResetAuthCodeRequest>,
|
|
) -> impl IntoResponse {
|
|
let admin_code = match headers.get("x-admin-code").and_then(|v| v.to_str().ok()) {
|
|
Some(c) => c.to_owned(),
|
|
None => return StatusCode::FORBIDDEN.into_response(),
|
|
};
|
|
match repo.update_admin_auth_code(&admin_code, payload.new_code.as_deref()).await {
|
|
Ok(new_code) => Json(ResetAuthCodeResponse { auth_code: new_code }).into_response(),
|
|
Err(DbError::Unauthorized) => StatusCode::FORBIDDEN.into_response(),
|
|
Err(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Route registration (src/bin/api/main.rs)
|
|
|
|
```rust
|
|
.route("/api/admin/reset-auth-code", post(handlers::reset_auth_code))
|
|
```
|
|
|
|
---
|
|
|
|
## Tests
|
|
|
|
- `POST /api/admin/reset-auth-code` with correct `X-Admin-Code` and no body `new_code` → `200`, response contains a non-empty `auth_code`
|
|
- `POST /api/admin/reset-auth-code` with correct `X-Admin-Code` and explicit `new_code` → `200`, `auth_code` equals the supplied value
|
|
- `POST /api/admin/reset-auth-code` with wrong `X-Admin-Code` → `403`
|
|
- `POST /api/admin/reset-auth-code` with missing `X-Admin-Code` header → `403`
|
|
- After a successful reset, subsequent calls with the old code return `403` and with the new code return `200`
|
|
|
|
---
|
|
|
|
## Validation
|
|
|
|
```sh
|
|
cargo fmt && cargo check && cargo clippy && cargo test
|
|
```
|
|
|
|
---
|
|
|
|
## Commit
|
|
|
|
```
|
|
feat(quotesdb): POST /api/admin/reset-auth-code endpoint
|
|
``` |