From ea6a7fb028527ce1ee7e5a20203e417ebaa5755f Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Tue, 2 Jul 2024 16:06:40 +0200 Subject: [PATCH] http: Remove session and all read-write endpoints Updates API version to 2.0.0 and crate to 0.13.0 --- radicle-httpd/Cargo.lock | 13 - radicle-httpd/Cargo.toml | 1 - radicle-httpd/src/api.rs | 28 +- radicle-httpd/src/api/auth.rs | 44 - radicle-httpd/src/api/error.rs | 5 - radicle-httpd/src/api/json.rs | 14 - radicle-httpd/src/api/v1.rs | 2 - radicle-httpd/src/api/v1/node.rs | 53 +- radicle-httpd/src/api/v1/projects.rs | 2070 +------------------------- radicle-httpd/src/api/v1/sessions.rs | 201 --- radicle-httpd/src/test.rs | 95 +- src/views/session/Index.svelte | 57 - 12 files changed, 20 insertions(+), 2563 deletions(-) delete mode 100644 radicle-httpd/src/api/auth.rs delete mode 100644 radicle-httpd/src/api/v1/sessions.rs delete mode 100644 src/views/session/Index.svelte diff --git a/radicle-httpd/Cargo.lock b/radicle-httpd/Cargo.lock index f85128e05..7018e48d7 100644 --- a/radicle-httpd/Cargo.lock +++ b/radicle-httpd/Cargo.lock @@ -209,18 +209,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "axum-auth" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8169113a185f54f68614fcfc3581df585d30bf8542bcb99496990e1025e4120a" -dependencies = [ - "async-trait", - "axum-core", - "base64 0.21.7", - "http", -] - [[package]] name = "axum-core" version = "0.4.3" @@ -1724,7 +1712,6 @@ version = "0.12.1" dependencies = [ "anyhow", "axum", - "axum-auth", "axum-server", "base64 0.21.7", "chrono", diff --git a/radicle-httpd/Cargo.toml b/radicle-httpd/Cargo.toml index 6bc9f971c..9b79f9289 100644 --- a/radicle-httpd/Cargo.toml +++ b/radicle-httpd/Cargo.toml @@ -23,7 +23,6 @@ path = "src/main.rs" [dependencies] anyhow = { version = "1" } axum = { version = "0.7.2", default-features = false, features = ["json", "query", "tokio", "http1"] } -axum-auth = { version= "0.7.0", default-features = false, features = ["auth-bearer"] } axum-server = { version = "0.6.0", default-features = false } base64 = "0.21.3" chrono = { version = "0.4.22", default-features = false, features = ["clock"] } diff --git a/radicle-httpd/src/api.rs b/radicle-httpd/src/api.rs index 8ab7edfa4..9be1a358a 100644 --- a/radicle-httpd/src/api.rs +++ b/radicle-httpd/src/api.rs @@ -1,6 +1,3 @@ -pub mod auth; - -use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; @@ -14,17 +11,15 @@ use radicle::patch::cache::Patches as _; use radicle::storage::git::Repository; use serde::{Deserialize, Serialize}; use serde_json::json; -use tokio::sync::RwLock; use tower_http::cors::{self, CorsLayer}; use radicle::cob::{issue, patch, Author}; use radicle::identity::{DocAt, RepoId}; use radicle::node::policy::Scope; use radicle::node::routing::Store; -use radicle::node::AliasStore; -use radicle::node::{Handle, NodeId}; +use radicle::node::{AliasStore, NodeId}; use radicle::storage::{ReadRepository, ReadStorage}; -use radicle::{Node, Profile}; +use radicle::Profile; mod error; mod json; @@ -38,13 +33,9 @@ pub const RADICLE_VERSION: &str = env!("RADICLE_VERSION"); // This version has to be updated on every breaking change to the radicle-httpd API. pub const API_VERSION: &str = "1.2.0"; -/// Identifier for sessions -type SessionId = String; - #[derive(Clone)] pub struct Context { profile: Arc, - sessions: Arc>>, cache: Option, } @@ -52,7 +43,6 @@ impl Context { pub fn new(profile: Arc, options: &Options) -> Self { Self { profile, - sessions: Default::default(), cache: options.cache.map(Cache::new), } } @@ -106,11 +96,6 @@ impl Context { pub fn profile(&self) -> &Arc { &self.profile } - - #[cfg(test)] - pub fn sessions(&self) -> &Arc>> { - &self.sessions - } } pub fn router(ctx: Context) -> Router { @@ -342,12 +327,3 @@ mod project { pub seeding: usize, } } - -/// Announce refs to the network for the given RID. -pub fn announce_refs(mut node: Node, rid: RepoId) -> Result<(), Error> { - match node.announce_refs(rid) { - Ok(_) => Ok(()), - Err(e) if e.is_connection_err() => Ok(()), - Err(e) => Err(e.into()), - } -} diff --git a/radicle-httpd/src/api/auth.rs b/radicle-httpd/src/api/auth.rs deleted file mode 100644 index 255de7753..000000000 --- a/radicle-httpd/src/api/auth.rs +++ /dev/null @@ -1,44 +0,0 @@ -use serde::{Deserialize, Serialize}; -use time::serde::timestamp; -use time::{Duration, OffsetDateTime}; - -use radicle::crypto::PublicKey; -use radicle::node::Alias; - -use crate::api::error::Error; -use crate::api::Context; - -pub const UNAUTHORIZED_SESSIONS_EXPIRATION: Duration = Duration::seconds(60); -pub const AUTHORIZED_SESSIONS_EXPIRATION: Duration = Duration::weeks(1); - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum AuthState { - Authorized, - Unauthorized, -} - -#[derive(Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Session { - pub status: AuthState, - pub public_key: PublicKey, - pub alias: Alias, - #[serde(with = "timestamp")] - pub issued_at: OffsetDateTime, - #[serde(with = "timestamp")] - pub expires_at: OffsetDateTime, -} - -pub async fn validate(ctx: &Context, token: &str) -> Result<(), Error> { - let sessions_store = ctx.sessions.read().await; - let session = sessions_store - .get(token) - .ok_or(Error::Auth("Unauthorized"))?; - - if session.status != AuthState::Authorized || session.expires_at <= OffsetDateTime::now_utc() { - return Err(Error::Auth("Unauthorized")); - } - - Ok(()) -} diff --git a/radicle-httpd/src/api/error.rs b/radicle-httpd/src/api/error.rs index da1005663..378c634c8 100644 --- a/radicle-httpd/src/api/error.rs +++ b/radicle-httpd/src/api/error.rs @@ -97,10 +97,6 @@ pub enum Error { /// Node error. #[error(transparent)] Node(#[from] radicle::node::Error), - - /// Invalid update to issue or patch. - #[error("{0}")] - BadRequest(String), } impl IntoResponse for Error { @@ -135,7 +131,6 @@ impl IntoResponse for Error { Error::StorageRef(err) if err.is_not_found() => { (StatusCode::NOT_FOUND, Some(err.to_string())) } - Error::BadRequest(msg) => (StatusCode::BAD_REQUEST, Some(msg)), other => { tracing::error!("Error: {message}"); tracing::debug!("Error Debug: {:?}", other); diff --git a/radicle-httpd/src/api/json.rs b/radicle-httpd/src/api/json.rs index 2686d3069..9eab0277a 100644 --- a/radicle-httpd/src/api/json.rs +++ b/radicle-httpd/src/api/json.rs @@ -21,8 +21,6 @@ use radicle_surf::blob::Blob; use radicle_surf::tree::{EntryKind, Tree}; use radicle_surf::{Commit, Oid}; -use crate::api::auth::Session; - /// Returns JSON of a commit. pub(crate) fn commit(commit: &Commit) -> Value { json!({ @@ -42,18 +40,6 @@ pub(crate) fn commit(commit: &Commit) -> Value { }) } -/// Returns JSON of a session. -pub(crate) fn session(session_id: String, session: &Session) -> Value { - json!({ - "sessionId": session_id, - "status": session.status, - "publicKey": session.public_key, - "alias": session.alias, - "issuedAt": session.issued_at.unix_timestamp(), - "expiresAt": session.expires_at.unix_timestamp() - }) -} - /// Returns JSON for a blob with a given `path`. pub(crate) fn blob>(blob: &Blob, path: &str) -> Value { json!({ diff --git a/radicle-httpd/src/api/v1.rs b/radicle-httpd/src/api/v1.rs index 3815091b5..c827b8cf4 100644 --- a/radicle-httpd/src/api/v1.rs +++ b/radicle-httpd/src/api/v1.rs @@ -2,7 +2,6 @@ mod delegates; mod node; mod profile; mod projects; -mod sessions; mod stats; use axum::extract::State; @@ -22,7 +21,6 @@ pub fn router(ctx: Context) -> Router { .merge(root_router) .merge(node::router(ctx.clone())) .merge(profile::router(ctx.clone())) - .merge(sessions::router(ctx.clone())) .merge(delegates::router(ctx.clone())) .merge(projects::router(ctx.clone())) .merge(stats::router(ctx)); diff --git a/radicle-httpd/src/api/v1/node.rs b/radicle-httpd/src/api/v1/node.rs index 6d9c12ef7..605ae2049 100644 --- a/radicle-httpd/src/api/v1/node.rs +++ b/radicle-httpd/src/api/v1/node.rs @@ -1,31 +1,24 @@ use axum::extract::State; use axum::response::IntoResponse; -use axum::routing::{get, put}; +use axum::routing::get; use axum::{Json, Router}; -use axum_auth::AuthBearer; -use hyper::StatusCode; use serde_json::json; use radicle::identity::RepoId; use radicle::node::address::Store as AddressStore; use radicle::node::routing::Store; -use radicle::node::{AliasStore, Handle, NodeId, DEFAULT_TIMEOUT}; +use radicle::node::{AliasStore, Handle, NodeId}; use radicle::Node; use crate::api::error::Error; -use crate::api::{self, Context, PoliciesQuery}; -use crate::axum_extra::{Path, Query}; +use crate::api::Context; +use crate::axum_extra::Path; pub fn router(ctx: Context) -> Router { Router::new() .route("/node", get(node_handler)) .route("/node/policies/repos", get(node_policies_repos_handler)) - .route( - "/node/policies/repos/:rid", - put(node_policies_seed_handler) - .delete(node_policies_unseed_handler) - .get(node_policies_repo_handler), - ) + .route("/node/policies/repos/:rid", get(node_policies_repo_handler)) .route("/nodes/:nid", get(nodes_handler)) .route("/nodes/:nid/inventory", get(nodes_inventory_handler)) .with_state(ctx) @@ -106,42 +99,6 @@ async fn node_policies_repo_handler( Ok::<_, Error>(Json(*policy)) } -/// Seed a new repo. -/// `PUT /node/policies/repos/:rid` -async fn node_policies_seed_handler( - State(ctx): State, - AuthBearer(token): AuthBearer, - Path(project): Path, - Query(qs): Query, -) -> impl IntoResponse { - api::auth::validate(&ctx, &token).await?; - let mut node = Node::new(ctx.profile.socket()); - node.seed(project, qs.scope.unwrap_or_default())?; - - if let Some(from) = qs.from { - let results = node.fetch(project, from, DEFAULT_TIMEOUT)?; - return Ok::<_, Error>(( - StatusCode::OK, - Json(json!({ "success": true, "results": results })), - )); - } - Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true })))) -} - -/// Unseed a repo. -/// `DELETE /node/policies/repos/:rid` -async fn node_policies_unseed_handler( - State(ctx): State, - AuthBearer(token): AuthBearer, - Path(project): Path, -) -> impl IntoResponse { - api::auth::validate(&ctx, &token).await?; - let mut node = Node::new(ctx.profile.socket()); - node.unseed(project)?; - - Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true })))) -} - #[cfg(test)] mod routes { use std::net::SocketAddr; diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index c1b44d049..626aeb73d 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -3,28 +3,24 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; use axum::extract::{DefaultBodyLimit, State}; use axum::http::header; use axum::response::IntoResponse; -use axum::routing::{get, patch, post}; +use axum::routing::get; use axum::{Json, Router}; -use axum_auth::AuthBearer; use hyper::StatusCode; use radicle_surf::blob::BlobRef; use radicle_surf::{diff, Glob, Oid, Repository}; use serde::{Deserialize, Serialize}; use serde_json::json; -use radicle::cob::{ - issue, issue::cache::Issues as _, patch, patch::cache::Patches as _, resolve_embed, Author, - Embed, Label, Uri, -}; -use radicle::identity::{Did, RepoId}; +use radicle::cob::{issue::cache::Issues as _, patch::cache::Patches as _, Author}; +use radicle::identity::RepoId; use radicle::node::routing::Store; -use radicle::node::{AliasStore, Node, NodeId}; -use radicle::storage::{ReadRepository, ReadStorage, RemoteRepository, WriteRepository}; +use radicle::node::{AliasStore, NodeId}; +use radicle::storage::{ReadRepository, ReadStorage, RemoteRepository}; use crate::api::error::Error; use crate::api::project::Info; use crate::api::search::{SearchQueryString, SearchResult}; -use crate::api::{self, announce_refs, CobsQuery, Context, PaginationQuery, ProjectQuery}; +use crate::api::{self, CobsQuery, Context, PaginationQuery, ProjectQuery}; use crate::axum_extra::{cached_response, immutable_response, Path, Query}; const MAX_BODY_LIMIT: usize = 4_194_304; @@ -48,22 +44,10 @@ pub fn router(ctx: Context) -> Router { .route("/projects/:project/remotes/:peer", get(remote_handler)) .route("/projects/:project/blob/:sha/*path", get(blob_handler)) .route("/projects/:project/readme/:sha", get(readme_handler)) - .route( - "/projects/:project/issues", - post(issue_create_handler).get(issues_handler), - ) - .route( - "/projects/:project/issues/:id", - patch(issue_update_handler).get(issue_handler), - ) - .route( - "/projects/:project/patches", - post(patch_create_handler).get(patches_handler), - ) - .route( - "/projects/:project/patches/:id", - patch(patch_update_handler).get(patch_handler), - ) + .route("/projects/:project/issues", get(issues_handler)) + .route("/projects/:project/issues/:id", get(issue_handler)) + .route("/projects/:project/patches", get(patches_handler)) + .route("/projects/:project/patches/:id", get(patch_handler)) .with_state(ctx) .layer(DefaultBodyLimit::max(MAX_BODY_LIMIT)) } @@ -654,113 +638,6 @@ async fn issues_handler( Ok::<_, Error>(Json(issues)) } -#[derive(Debug, Deserialize, Serialize)] -pub struct IssueCreate { - pub title: String, - pub description: String, - pub labels: Vec