Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Move `rad-web` binary to `radicle-httpd` package
Thomas Scholtes committed 2 years ago
commit 3ccb6a5fac2b7dc9d7991c5b8c5767a472c7e1f4
parent aca5cf669f537522dcd7178e6dbaa62e49be796b
13 files changed +156 -146
modified .github/workflows/build.bash
@@ -44,6 +44,7 @@ main () {

    cargo build --target="$target" --package=radicle-httpd --release
    cp target/"$target"/release/radicle-httpd "$staging"/
+
    cp target/"$target"/release/rad-web "$staging"/

    cargo build --target="$target" --package=radicle-node --release
    cp target/"$target"/release/radicle-node "$staging"/
modified Cargo.lock
@@ -1705,9 +1705,9 @@ checksum = "478ee9e62aaeaf5b140bd4138753d1f109765488581444218d3ddda43234f3e8"

[[package]]
name = "libc"
-
version = "0.2.147"
+
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"

[[package]]
name = "libgit2-sys"
@@ -2119,9 +2119,9 @@ dependencies = [

[[package]]
name = "pin-project-lite"
-
version = "0.2.10"
+
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
+
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"

[[package]]
name = "pin-utils"
@@ -2332,7 +2332,6 @@ dependencies = [
 "tree-sitter-rust",
 "tree-sitter-toml",
 "tree-sitter-typescript",
-
 "ureq",
 "zeroize",
]

@@ -2477,6 +2476,7 @@ dependencies = [
 "tracing",
 "tracing-logfmt",
 "tracing-subscriber",
+
 "ureq",
]

[[package]]
@@ -3307,18 +3307,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"

[[package]]
name = "tokio"
-
version = "1.29.1"
+
version = "1.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
+
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
dependencies = [
-
 "autocfg",
 "backtrace",
 "bytes",
 "libc",
 "mio",
 "num_cpus",
 "pin-project-lite",
-
 "socket2 0.4.9",
+
 "socket2 0.5.3",
 "tokio-macros",
 "windows-sys",
]
@@ -3667,9 +3666,9 @@ dependencies = [

[[package]]
name = "ureq"
-
version = "2.7.1"
+
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
+
checksum = "7830e33f6e25723d41a63f77e434159dad02919f18f55a512b5f16f3b1d77138"
dependencies = [
 "base64 0.21.3",
 "log",
@@ -3681,9 +3680,9 @@ dependencies = [

[[package]]
name = "url"
-
version = "2.4.0"
+
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
+
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
 "form_urlencoded",
 "idna",
modified radicle-cli/Cargo.toml
@@ -47,7 +47,6 @@ tree-sitter-ruby = { version = "0.20", optional = true }
tree-sitter-bash = { version = "0.20" }
tree-sitter-go = { version = "0.20.0" }
tree-sitter-md = { version = "0.1.5" }
-
ureq = { version = "2.6.1", default-features = false, features = ["json"] }
zeroize = { version = "1.1" }

[dependencies.radicle]
modified radicle-cli/src/commands.rs
@@ -52,5 +52,3 @@ pub mod rad_unassign;
pub mod rad_unlabel;
#[path = "commands/untrack.rs"]
pub mod rad_untrack;
-
#[path = "commands/web.rs"]
-
pub mod rad_web;
deleted radicle-cli/src/commands/web.rs
@@ -1,123 +0,0 @@
-
use std::ffi::OsString;
-

-
use anyhow::anyhow;
-
use serde::{Deserialize, Serialize};
-

-
use radicle::crypto::{PublicKey, Signature, Signer};
-

-
use crate::terminal as term;
-
use crate::terminal::args::{Args, Error, Help};
-

-
pub const HELP: Help = Help {
-
    name: "web",
-
    description: "Connect web with node",
-
    version: env!("CARGO_PKG_VERSION"),
-
    usage: r#"
-
Usage
-

-
    rad web [<option>...]
-

-
Options
-

-
    --backend, -b          httpd to bind to
-
    --frontend, -f         Web interface to bind to
-
    --verbose, -v          Verbose output
-
    --json                 Output as json
-
    --help                 Print help
-
"#,
-
};
-

-
#[derive(Debug, Clone, Deserialize, Serialize)]
-
#[serde(rename_all = "camelCase")]
-
pub struct SessionInfo {
-
    pub session_id: String,
-
    pub public_key: PublicKey,
-
}
-

-
#[derive(Debug)]
-
pub struct Options {
-
    pub backend: String,
-
    pub frontend: String,
-
    pub json: bool,
-
    pub verbose: bool,
-
}
-

-
impl Args for Options {
-
    fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
-
        use lexopt::prelude::*;
-

-
        let mut parser = lexopt::Parser::from_args(args);
-
        let mut backend = None;
-
        let mut frontend = None;
-
        let mut json = false;
-
        let mut verbose = false;
-

-
        while let Some(arg) = parser.next()? {
-
            match arg {
-
                Long("verbose") | Short('v') => verbose = true,
-
                Long("backend") | Short('b') => {
-
                    backend = Some(parser.value()?.to_string_lossy().to_string())
-
                }
-
                Long("frontend") | Short('f') => {
-
                    frontend = Some(parser.value()?.to_string_lossy().to_string())
-
                }
-
                Long("json") => json = true,
-
                Long("help") | Short('h') => {
-
                    return Err(Error::Help.into());
-
                }
-
                _ => {
-
                    return Err(anyhow!(arg.unexpected()));
-
                }
-
            }
-
        }
-

-
        Ok((
-
            Options {
-
                json,
-
                verbose,
-
                backend: backend.unwrap_or(String::from("http://0.0.0.0:8080")),
-
                frontend: frontend.unwrap_or(String::from("https://app.radicle.xyz")),
-
            },
-
            vec![],
-
        ))
-
    }
-
}
-

-
pub fn sign(signer: Box<dyn Signer>, session: &SessionInfo) -> Result<Signature, anyhow::Error> {
-
    signer
-
        .try_sign(format!("{}:{}", session.session_id, session.public_key).as_bytes())
-
        .map_err(anyhow::Error::from)
-
}
-

-
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
-
    let session: SessionInfo = ureq::post(&format!("{}/api/v1/sessions", options.backend))
-
        .call()?
-
        .into_json()?;
-
    let profile = ctx.profile()?;
-
    let signer = profile.signer()?;
-
    let signature = sign(signer, &session)?;
-

-
    if options.json {
-
        println!(
-
            "{}",
-
            serde_json::json!({
-
                "sessionId": session.session_id,
-
                "publicKey": session.public_key,
-
                "signature": signature,
-
            })
-
        )
-
    } else {
-
        term::blank();
-
        term::info!("Open the following link to authenticate:");
-
        term::info!(
-
            "  👉 {}/session/{}?pk={}&sig={}",
-
            options.frontend,
-
            session.session_id,
-
            session.public_key,
-
            signature,
-
        );
-
        term::blank();
-
    }
-

-
    Ok(())
-
}
modified radicle-cli/src/main.rs
@@ -267,11 +267,6 @@ fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyhow::Error>>
                args.to_vec(),
            );
        }
-
        "web" => term::run_command_args::<rad_web::Options, _>(
-
            rad_web::HELP,
-
            rad_web::run,
-
            args.to_vec(),
-
        ),
        "remote" => term::run_command_args::<rad_remote::Options, _>(
            rad_remote::HELP,
            rad_remote::run,
modified radicle-httpd/Cargo.toml
@@ -37,6 +37,7 @@ tower-http = { version = "0.3.4", default-features = false, features = ["trace",
tracing = { version = "0.1.37", default-features = false, features = ["std", "log"] }
tracing-logfmt = { version = "0.2", optional = true }
tracing-subscriber = { version = "0.3", default-features = false, features = ["std", "ansi", "fmt"] }
+
ureq = { version = "2.9", default-features = false, features = ["json"] }

[dependencies.radicle]
path = "../radicle"
@@ -45,6 +46,9 @@ version = "0.2.0"
[dependencies.radicle-term]
path = "../radicle-term"

+
[dependencies.radicle-cli]
+
path = "../radicle-cli"
+

[dev-dependencies]
hyper = { version = "0.14.17", default-features = false, features = ["client"] }
pretty_assertions = { version = "1.3.0" }
modified radicle-httpd/src/api/v1/sessions.rs
@@ -122,9 +122,9 @@ async fn session_delete_handler(

#[cfg(test)]
mod routes {
+
    use crate::commands::web::{sign, SessionInfo};
    use axum::body::Body;
    use axum::http::StatusCode;
-
    use radicle_cli::commands::rad_web::{self, SessionInfo};

    use crate::api::auth::{AuthState, Session};
    use crate::test::{self, get, post, put};
@@ -154,7 +154,7 @@ mod routes {

        // Create request body
        let signer = ctx.profile.signer().unwrap();
-
        let signature = rad_web::sign(signer, &session_info).unwrap();
+
        let signature = sign(signer, &session_info).unwrap();
        let body = serde_json::to_vec(&super::AuthChallenge {
            sig: signature,
            pk: session_info.public_key,
added radicle-httpd/src/bin/rad-web.rs
@@ -0,0 +1,10 @@
+
use radicle_cli::terminal as term;
+
use radicle_httpd::commands::web as rad_web;
+

+
fn main() {
+
    term::run_command_args::<rad_web::Options, _>(
+
        rad_web::HELP,
+
        rad_web::run,
+
        std::env::args_os().skip(1).collect(),
+
    )
+
}
added radicle-httpd/src/commands.rs
@@ -0,0 +1,2 @@
+
//! Extra CLI commands relating to HTTPd.
+
pub mod web;
added radicle-httpd/src/commands/web.rs
@@ -0,0 +1,123 @@
+
use std::ffi::OsString;
+

+
use anyhow::anyhow;
+
use serde::{Deserialize, Serialize};
+

+
use radicle::crypto::{PublicKey, Signature, Signer};
+

+
use radicle_cli::terminal as term;
+
use radicle_cli::terminal::args::{Args, Error, Help};
+

+
pub const HELP: Help = Help {
+
    name: "web",
+
    description: "Connect web with node",
+
    version: env!("CARGO_PKG_VERSION"),
+
    usage: r#"
+
Usage
+

+
    rad web [<option>...]
+

+
Options
+

+
    --backend, -b          httpd to bind to
+
    --frontend, -f         Web interface to bind to
+
    --verbose, -v          Verbose output
+
    --json                 Output as json
+
    --help                 Print help
+
"#,
+
};
+

+
#[derive(Debug, Clone, Deserialize, Serialize)]
+
#[serde(rename_all = "camelCase")]
+
pub struct SessionInfo {
+
    pub session_id: String,
+
    pub public_key: PublicKey,
+
}
+

+
#[derive(Debug)]
+
pub struct Options {
+
    pub backend: String,
+
    pub frontend: String,
+
    pub json: bool,
+
    pub verbose: bool,
+
}
+

+
impl Args for Options {
+
    fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
+
        use lexopt::prelude::*;
+

+
        let mut parser = lexopt::Parser::from_args(args);
+
        let mut backend = None;
+
        let mut frontend = None;
+
        let mut json = false;
+
        let mut verbose = false;
+

+
        while let Some(arg) = parser.next()? {
+
            match arg {
+
                Long("verbose") | Short('v') => verbose = true,
+
                Long("backend") | Short('b') => {
+
                    backend = Some(parser.value()?.to_string_lossy().to_string())
+
                }
+
                Long("frontend") | Short('f') => {
+
                    frontend = Some(parser.value()?.to_string_lossy().to_string())
+
                }
+
                Long("json") => json = true,
+
                Long("help") | Short('h') => {
+
                    return Err(Error::Help.into());
+
                }
+
                _ => {
+
                    return Err(anyhow!(arg.unexpected()));
+
                }
+
            }
+
        }
+

+
        Ok((
+
            Options {
+
                json,
+
                verbose,
+
                backend: backend.unwrap_or(String::from("http://0.0.0.0:8080")),
+
                frontend: frontend.unwrap_or(String::from("https://app.radicle.xyz")),
+
            },
+
            vec![],
+
        ))
+
    }
+
}
+

+
pub fn sign(signer: Box<dyn Signer>, session: &SessionInfo) -> Result<Signature, anyhow::Error> {
+
    signer
+
        .try_sign(format!("{}:{}", session.session_id, session.public_key).as_bytes())
+
        .map_err(anyhow::Error::from)
+
}
+

+
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
+
    let session: SessionInfo = ureq::post(&format!("{}/api/v1/sessions", options.backend))
+
        .call()?
+
        .into_json()?;
+
    let profile = ctx.profile()?;
+
    let signer = profile.signer()?;
+
    let signature = sign(signer, &session)?;
+

+
    if options.json {
+
        println!(
+
            "{}",
+
            serde_json::json!({
+
                "sessionId": session.session_id,
+
                "publicKey": session.public_key,
+
                "signature": signature,
+
            })
+
        )
+
    } else {
+
        term::blank();
+
        term::info!("Open the following link to authenticate:");
+
        term::info!(
+
            "  👉 {}/session/{}?pk={}&sig={}",
+
            options.frontend,
+
            session.session_id,
+
            session.public_key,
+
            signature,
+
        );
+
        term::blank();
+
    }
+

+
    Ok(())
+
}
modified radicle-httpd/src/lib.rs
@@ -1,6 +1,7 @@
#![allow(clippy::type_complexity)]
#![allow(clippy::too_many_arguments)]
#![recursion_limit = "256"]
+
pub mod commands;
pub mod error;

use std::collections::HashMap;
modified scripts/install
@@ -88,6 +88,7 @@ chmod +x \
  $RAD_PATH/radicle-node \
  $RAD_PATH/radicle-httpd \
  $RAD_PATH/rad \
+
  $RAD_PATH/rad-web \
  $RAD_PATH/git-remote-rad

# If radicle is not in $PATH, add it here.