diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index d3d33a8f..3e4e0d02 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -69,6 +69,7 @@ async fn main() -> std::io::Result<()> { Commands::Domain(command) => command.exec(client).await, Commands::List(command) => command.exec(client).await, Commands::Group(command) => command.exec(client).await,*/ + Commands::Dkim(command) => command.exec(client).await, Commands::Queue(command) => command.exec(client).await, Commands::Report(command) => command.exec(client).await, } diff --git a/crates/cli/src/modules/cli.rs b/crates/cli/src/modules/cli.rs index cd63070d..82413591 100644 --- a/crates/cli/src/modules/cli.rs +++ b/crates/cli/src/modules/cli.rs @@ -4,6 +4,7 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ +use super::dkim::Algorithm; use clap::{Parser, Subcommand, ValueEnum}; use jmap_client::client::Credentials; use mail_parser::DateTime; @@ -44,6 +45,11 @@ pub enum Commands { #[clap(subcommand)] Group(GroupCommands), */ + + /// Manage DKIM signatures + #[clap(subcommand)] + Dkim(DkimCommands), + /// Import JMAP accounts and Maildir/mbox mailboxes #[clap(subcommand)] Import(ImportCommands), @@ -345,6 +351,27 @@ pub enum DomainCommands { }, } +#[derive(Subcommand)] +pub enum DkimCommands { + /// Create DKIM signature + Create { + /// Algorithm to use + algorithm: Algorithm, + /// Domain name for which to create + domain: String, + /// Id + signature_id: Option, + /// Selector + selector: Option, + }, + + /// Get DKIM public key + GetPublicKey { + /// Signature id + signature_id: String, + }, +} + #[derive(Subcommand)] pub enum ImportCommands { /// Import messages and folders diff --git a/crates/cli/src/modules/dkim.rs b/crates/cli/src/modules/dkim.rs new file mode 100644 index 00000000..ce113802 --- /dev/null +++ b/crates/cli/src/modules/dkim.rs @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL + */ + +use super::cli::{Client, DkimCommands}; +use clap::ValueEnum; +use reqwest::Method; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)] +pub enum Algorithm { + /// RSA + #[default] + Rsa, + /// ED25519 + Ed25519, +} + +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)] +struct DkimSignature { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + + pub algorithm: Algorithm, + + pub domain: String, + + #[serde(skip_serializing_if = "Option::is_none")] + pub selector: Option, +} + +impl DkimCommands { + pub async fn exec(self, client: Client) { + match self { + DkimCommands::Create { + signature_id, + algorithm, + domain, + selector, + } => { + let signature_req = DkimSignature { + id: signature_id, + algorithm, + domain: domain.clone(), + selector, + }; + client + .http_request::(Method::POST, "/api/dkim", Some(signature_req)) + .await; + eprintln!("Successfully created {algorithm:?} signature for domain {domain:?}"); + } + DkimCommands::GetPublicKey { signature_id } => { + let response = client + .http_request::( + Method::GET, + &format!("/api/dkim/{signature_id}"), + None, + ) + .await; + + eprintln!(); + eprintln!("Public DKIM key for signature {signature_id}: {response}"); + eprintln!(); + } + } + } +} diff --git a/crates/cli/src/modules/mod.rs b/crates/cli/src/modules/mod.rs index e0a390ee..c7073fa3 100644 --- a/crates/cli/src/modules/mod.rs +++ b/crates/cli/src/modules/mod.rs @@ -15,6 +15,7 @@ use serde::{Deserialize, Serialize}; pub mod account; pub mod cli; pub mod database; +pub mod dkim; pub mod domain; pub mod export; pub mod group;