mirror of
https://github.com/Blah-IM/blahrs.git
synced 2025-05-01 00:31:09 +00:00
refactor(blahctl)!: update to new id-desc and schema
This commit is contained in:
parent
10dcc64fe9
commit
3cc6017ae0
2 changed files with 39 additions and 55 deletions
|
@ -11,7 +11,7 @@ hex = "0.4"
|
||||||
humantime = "2"
|
humantime = "2"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
reqwest = { version = "0.12", features = ["json"] }
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
rusqlite = "0.32"
|
rusqlite = { version = "0.32", features = ["rusqlite-macros"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
tokio = { version = "1", features = ["rt", "macros"] }
|
tokio = { version = "1", features = ["rt", "macros"] }
|
||||||
|
|
||||||
|
|
|
@ -10,17 +10,13 @@ use blah_types::{
|
||||||
};
|
};
|
||||||
use ed25519_dalek::pkcs8::spki::der::pem::LineEnding;
|
use ed25519_dalek::pkcs8::spki::der::pem::LineEnding;
|
||||||
use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey};
|
use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey};
|
||||||
use ed25519_dalek::{SigningKey, VerifyingKey, PUBLIC_KEY_LENGTH};
|
use ed25519_dalek::{SigningKey, VerifyingKey};
|
||||||
use humantime::Duration;
|
use humantime::Duration;
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use rusqlite::{named_params, Connection};
|
use rusqlite::{prepare_and_bind, Connection};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
/// NB. Sync with docs of [`User::url`].
|
|
||||||
// FIXME: Remove old interface.
|
|
||||||
const KEY_URL_SUBPATH: &str = "/.well-known/blah/key";
|
|
||||||
|
|
||||||
const USER_AGENT: &str = concat!("blahctl/", env!("CARGO_PKG_VERSION"));
|
const USER_AGENT: &str = concat!("blahctl/", env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
/// Control or manage Blah Chat Server.
|
/// Control or manage Blah Chat Server.
|
||||||
|
@ -198,7 +194,7 @@ impl IdDescArgs {
|
||||||
enum DbCommand {
|
enum DbCommand {
|
||||||
/// Create and initialize database.
|
/// Create and initialize database.
|
||||||
Init,
|
Init,
|
||||||
/// Set user property, possibly adding new users.
|
/// Set property of an existing user.
|
||||||
SetUser {
|
SetUser {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
user: Box<User>,
|
user: Box<User>,
|
||||||
|
@ -241,52 +237,44 @@ enum ApiCommand {
|
||||||
// This should be an enum but clap does not support it on `Args` yet.
|
// This should be an enum but clap does not support it on `Args` yet.
|
||||||
// See: https://github.com/clap-rs/clap/issues/2621
|
// See: https://github.com/clap-rs/clap/issues/2621
|
||||||
#[derive(Debug, clap::Args)]
|
#[derive(Debug, clap::Args)]
|
||||||
#[clap(group = clap::ArgGroup::new("user").required(true).multiple(false))]
|
#[group(required = true, multiple = false)]
|
||||||
struct User {
|
struct User {
|
||||||
/// Hex-encoded public key.
|
/// Hex-encoded public key.
|
||||||
#[arg(long, group = "user", value_parser = userkey_parser)]
|
#[arg(long, group = "user")]
|
||||||
key: Option<VerifyingKey>,
|
key: Option<PubKey>,
|
||||||
|
|
||||||
/// Path to a user public key.
|
/// Path to a user public key.
|
||||||
#[arg(long, short = 'f', group = "user")]
|
#[arg(long, group = "user")]
|
||||||
public_key_file: Option<PathBuf>,
|
public_key_file: Option<PathBuf>,
|
||||||
|
|
||||||
/// User's URL where `/.well-known/blah/key` is hosted.
|
/// The identity URL to check.
|
||||||
|
///
|
||||||
|
/// It should be a HTTPS domain with a top-level path `/`.
|
||||||
#[arg(long, group = "user")]
|
#[arg(long, group = "user")]
|
||||||
url: Option<Url>,
|
id_url: Option<IdUrl>,
|
||||||
}
|
|
||||||
|
|
||||||
fn userkey_parser(s: &str) -> clap::error::Result<VerifyingKey> {
|
/// The identity description JSON path to check.
|
||||||
(|| {
|
#[arg(long, group = "user")]
|
||||||
let mut buf = [0u8; PUBLIC_KEY_LENGTH];
|
desc_file: Option<PathBuf>,
|
||||||
hex::decode_to_slice(s, &mut buf).ok()?;
|
|
||||||
VerifyingKey::from_bytes(&buf).ok()
|
|
||||||
})()
|
|
||||||
.ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidValue))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
async fn fetch_key(&self) -> Result<PubKey> {
|
fn load(&self, rt: &Runtime) -> Result<PubKey> {
|
||||||
let rawkey = if let Some(key) = &self.key {
|
if let Some(key) = &self.key {
|
||||||
return Ok(key.into());
|
Ok(key.clone())
|
||||||
} else if let Some(path) = &self.public_key_file {
|
} else if let Some(path) = &self.public_key_file {
|
||||||
fs::read_to_string(path).context("failed to read key file")?
|
let src = fs::read_to_string(path).context("failed to read key file")?;
|
||||||
} else if let Some(url) = &self.url {
|
let key = VerifyingKey::from_public_key_pem(&src)
|
||||||
let url = url.join(KEY_URL_SUBPATH)?;
|
.context("invalid key")?
|
||||||
build_client()?
|
.to_bytes();
|
||||||
.get(url)
|
Ok(PubKey(key))
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.error_for_status()?
|
|
||||||
.text()
|
|
||||||
.await?
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
let args = IdDescArgs {
|
||||||
};
|
id_url: self.id_url.clone(),
|
||||||
let key = VerifyingKey::from_public_key_pem(&rawkey)
|
desc_file: self.desc_file.clone(),
|
||||||
.context("invalid key")?
|
};
|
||||||
.to_bytes();
|
Ok(args.load(rt)?.id_key)
|
||||||
Ok(PubKey(key))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,21 +443,17 @@ fn main_db(conn: Connection, command: DbCommand) -> Result<()> {
|
||||||
match command {
|
match command {
|
||||||
DbCommand::Init => {}
|
DbCommand::Init => {}
|
||||||
DbCommand::SetUser { user, permission } => {
|
DbCommand::SetUser { user, permission } => {
|
||||||
let userkey = build_rt()?.block_on(user.fetch_key())?;
|
let rt = build_rt()?;
|
||||||
|
let id_key = user.load(&rt)?;
|
||||||
conn.execute(
|
prepare_and_bind!(
|
||||||
|
conn,
|
||||||
r"
|
r"
|
||||||
INSERT
|
UPDATE `user`
|
||||||
INTO `user` (`userkey`, `permission`)
|
SET `permission` = :permission
|
||||||
VALUES (:userkey, :permission)
|
WHERE `id_key` = :id_key
|
||||||
ON CONFLICT (`userkey`) DO UPDATE SET
|
"
|
||||||
`permission` = :permission
|
)
|
||||||
",
|
.raw_execute()?;
|
||||||
named_params! {
|
|
||||||
":userkey": userkey,
|
|
||||||
":permission": permission,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Add table
Reference in a new issue