Skip to content

Commit

Permalink
OpenAPI: Describe authentication requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
Turbo87 committed Dec 27, 2024
1 parent 63e4378 commit 6214f36
Show file tree
Hide file tree
Showing 17 changed files with 282 additions and 3 deletions.
2 changes: 1 addition & 1 deletion crates/crates_io_session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;

static COOKIE_NAME: &str = "cargo_session";
pub static COOKIE_NAME: &str = "cargo_session";
static MAX_AGE_DAYS: i64 = 90;

#[derive(Clone, FromRequestParts)]
Expand Down
6 changes: 6 additions & 0 deletions src/controllers/crate_owner_invitation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use std::collections::{HashMap, HashSet};
#[utoipa::path(
get,
path = "/api/v1/me/crate_owner_invitations",
security(("cookie" = [])),
tag = "owners",
responses((status = 200, description = "Successful Response")),
)]
Expand Down Expand Up @@ -90,6 +91,7 @@ pub struct ListQueryParams {
get,
path = "/api/private/crate_owner_invitations",
params(ListQueryParams, PaginationQueryParams),
security(("cookie" = [])),
tag = "owners",
responses((status = 200, description = "Successful Response")),
)]
Expand Down Expand Up @@ -316,6 +318,10 @@ pub struct OwnerInvitation {
params(
("crate_id" = i32, Path, description = "ID of the crate"),
),
security(
("api_token" = []),
("cookie" = []),
),
tag = "owners",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
1 change: 1 addition & 0 deletions src/controllers/krate/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const AVAILABLE_AFTER: TimeDelta = TimeDelta::hours(24);
delete,
path = "/api/v1/crates/{name}",
params(CratePath),
security(("cookie" = [])),
tag = "crates",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
9 changes: 9 additions & 0 deletions src/controllers/krate/follow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ async fn follow_target(
put,
path = "/api/v1/crates/{name}/follow",
params(CratePath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "crates",
responses((status = 200, description = "Successful Response")),
)]
Expand All @@ -55,6 +59,10 @@ pub async fn follow_crate(app: AppState, path: CratePath, req: Parts) -> AppResu
delete,
path = "/api/v1/crates/{name}/follow",
params(CratePath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "crates",
responses((status = 200, description = "Successful Response")),
)]
Expand All @@ -72,6 +80,7 @@ pub async fn unfollow_crate(app: AppState, path: CratePath, req: Parts) -> AppRe
get,
path = "/api/v1/crates/{name}/following",
params(CratePath),
security(("cookie" = [])),
tag = "crates",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
8 changes: 8 additions & 0 deletions src/controllers/krate/owners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ pub async fn get_user_owners(state: AppState, path: CratePath) -> AppResult<Eras
put,
path = "/api/v1/crates/{name}/owners",
params(CratePath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "owners",
responses((status = 200, description = "Successful Response")),
)]
Expand All @@ -105,6 +109,10 @@ pub async fn add_owners(
delete,
path = "/api/v1/crates/{name}/owners",
params(CratePath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "owners",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
4 changes: 4 additions & 0 deletions src/controllers/krate/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ const MAX_DESCRIPTION_LENGTH: usize = 1000;
#[utoipa::path(
put,
path = "/api/v1/crates/new",
security(
("api_token" = []),
("cookie" = []),
),
tag = "publish",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
5 changes: 5 additions & 0 deletions src/controllers/krate/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ use crate::util::RequestUtils;
get,
path = "/api/v1/crates",
params(ListQueryParams, PaginationQueryParams),
security(
(),
("api_token" = []),
("cookie" = []),
),
tag = "crates",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
1 change: 1 addition & 0 deletions src/controllers/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ async fn find_user_by_gh_id(conn: &mut AsyncPgConnection, gh_id: i32) -> QueryRe
#[utoipa::path(
delete,
path = "/api/private/session",
security(("cookie" = [])),
tag = "session",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
11 changes: 11 additions & 0 deletions src/controllers/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl GetParams {
#[utoipa::path(
get,
path = "/api/v1/me/tokens",
security(("cookie" = [])),
tag = "api_tokens",
responses((status = 200, description = "Successful Response")),
)]
Expand Down Expand Up @@ -86,6 +87,7 @@ pub struct NewApiTokenRequest {
#[utoipa::path(
put,
path = "/api/v1/me/tokens",
security(("cookie" = [])),
tag = "api_tokens",
responses((status = 200, description = "Successful Response")),
)]
Expand Down Expand Up @@ -184,6 +186,10 @@ pub async fn create_api_token(
params(
("id" = i32, Path, description = "ID of the API token"),
),
security(
("api_token" = []),
("cookie" = []),
),
tag = "api_tokens",
responses((status = 200, description = "Successful Response")),
)]
Expand Down Expand Up @@ -211,6 +217,10 @@ pub async fn find_api_token(
params(
("id" = i32, Path, description = "ID of the API token"),
),
security(
("api_token" = []),
("cookie" = []),
),
tag = "api_tokens",
responses((status = 200, description = "Successful Response")),
)]
Expand All @@ -237,6 +247,7 @@ pub async fn revoke_api_token(
#[utoipa::path(
delete,
path = "/api/v1/tokens/current",
security(("api_token" = [])),
tag = "api_tokens",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
4 changes: 4 additions & 0 deletions src/controllers/user/email_notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ pub struct CrateEmailNotifications {
#[utoipa::path(
put,
path = "/api/v1/me/email_notifications",
security(
("api_token" = []),
("cookie" = []),
),
tag = "users",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
4 changes: 4 additions & 0 deletions src/controllers/user/email_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ pub async fn confirm_user_email(state: AppState, Path(token): Path<String>) -> A
params(
("id" = i32, Path, description = "ID of the user"),
),
security(
("api_token" = []),
("cookie" = []),
),
tag = "users",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
2 changes: 2 additions & 0 deletions src/controllers/user/me.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::views::{EncodableMe, EncodablePrivateUser, EncodableVersion, OwnedCra
#[utoipa::path(
get,
path = "/api/v1/me",
security(("cookie" = [])),
tag = "users",
responses((status = 200, description = "Successful Response")),
)]
Expand Down Expand Up @@ -68,6 +69,7 @@ pub async fn get_authenticated_user(app: AppState, req: Parts) -> AppResult<Json
#[utoipa::path(
get,
path = "/api/v1/me/updates",
security(("cookie" = [])),
tag = "versions",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
4 changes: 4 additions & 0 deletions src/controllers/user/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ pub struct User {
params(
("user" = i32, Path, description = "ID of the user"),
),
security(
("api_token" = []),
("cookie" = []),
),
tag = "users",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
4 changes: 4 additions & 0 deletions src/controllers/version/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ pub struct VersionUpdateRequest {
patch,
path = "/api/v1/crates/{name}/{version}",
params(CrateVersionPath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "versions",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
8 changes: 8 additions & 0 deletions src/controllers/version/yank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ use http::request::Parts;
delete,
path = "/api/v1/crates/{name}/{version}/yank",
params(CrateVersionPath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "versions",
responses((status = 200, description = "Successful Response")),
)]
Expand All @@ -40,6 +44,10 @@ pub async fn yank_version(
put,
path = "/api/v1/crates/{name}/{version}/unyank",
params(CrateVersionPath),
security(
("api_token" = []),
("cookie" = []),
),
tag = "versions",
responses((status = 200, description = "Successful Response")),
)]
Expand Down
24 changes: 23 additions & 1 deletion src/openapi.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use utoipa::OpenApi;
use crates_io_session::COOKIE_NAME;
use http::header;
use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme};
use utoipa::{Modify, OpenApi};
use utoipa_axum::router::OpenApiRouter;

#[derive(OpenApi)]
Expand All @@ -11,6 +14,7 @@ use utoipa_axum::router::OpenApiRouter;
license(),
version = "0.0.0",
),
modifiers(&SecurityAddon),
servers(
(url = "https://crates.io"),
(url = "https://staging.crates.io"),
Expand All @@ -27,6 +31,24 @@ impl BaseOpenApi {
}
}

struct SecurityAddon;

impl Modify for SecurityAddon {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
let components = openapi.components.get_or_insert_default();

let description = "The session cookie is used by the web UI to authenticate users.";
let cookie = ApiKey::Cookie(ApiKeyValue::with_description(COOKIE_NAME, description));
components.add_security_scheme("cookie", SecurityScheme::ApiKey(cookie));

let name = header::AUTHORIZATION.as_str();
let description =
"The API token is used to authenticate requests from cargo and other clients.";
let api_token = ApiKey::Header(ApiKeyValue::with_description(name, description));
components.add_security_scheme("api_token", SecurityScheme::ApiKey(api_token));
}
}

#[cfg(test)]
mod tests {
use crate::tests::util::{RequestHelper, TestApp};
Expand Down
Loading

0 comments on commit 6214f36

Please sign in to comment.