DKIM record management API
This commit is contained in:
@@ -248,11 +248,16 @@ impl ConfigManager {
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub async fn set(&self, keys: impl IntoIterator<Item = ConfigKey>) -> store::Result<()> {
|
||||
pub async fn set<I, T>(&self, keys: I) -> store::Result<()>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<ConfigKey>,
|
||||
{
|
||||
let mut batch = BatchBuilder::new();
|
||||
let mut local_batch = Vec::new();
|
||||
|
||||
for key in keys {
|
||||
let key = key.into();
|
||||
if self.cfg_local_patterns.is_local_key(&key.key) {
|
||||
local_batch.push(key);
|
||||
} else {
|
||||
|
||||
@@ -313,7 +313,7 @@ impl Scripting {
|
||||
IfBlock::new::<()>(
|
||||
"sieve.trusted.sign",
|
||||
[],
|
||||
"['rsa_' + key_get('default', 'domain'), 'ed_' + key_get('default', 'domain')]",
|
||||
"['rsa-' + key_get('default', 'domain'), 'ed25519-' + key_get('default', 'domain')]",
|
||||
)
|
||||
}),
|
||||
scripts,
|
||||
@@ -349,7 +349,7 @@ impl Default for Scripting {
|
||||
sign: IfBlock::new::<()>(
|
||||
"sieve.trusted.sign",
|
||||
[],
|
||||
"['rsa_' + key_get('default', 'domain'), 'ed_' + key_get('default', 'domain')]",
|
||||
"['rsa-' + key_get('default', 'domain'), 'ed25519-' + key_get('default', 'domain')]",
|
||||
),
|
||||
scripts: AHashMap::new(),
|
||||
bayes_cache: BayesTokenCache::new(
|
||||
|
||||
@@ -91,7 +91,7 @@ impl Default for MailAuthConfig {
|
||||
"auth.dkim.sign",
|
||||
[(
|
||||
"is_local_domain('*', sender_domain)",
|
||||
"['rsa_' + sender_domain, 'ed_' + sender_domain]",
|
||||
"['rsa-' + sender_domain, 'ed25519-' + sender_domain]",
|
||||
)],
|
||||
"false",
|
||||
),
|
||||
@@ -101,7 +101,7 @@ impl Default for MailAuthConfig {
|
||||
seal: IfBlock::new::<()>(
|
||||
"auth.arc.seal",
|
||||
[],
|
||||
"['rsa_' + key_get('default', 'domain'), 'ed_' + key_get('default', 'domain')]",
|
||||
"['rsa-' + key_get('default', 'domain'), 'ed25519-' + key_get('default', 'domain')]",
|
||||
),
|
||||
},
|
||||
spf: SpfAuthConfig {
|
||||
@@ -226,50 +226,8 @@ fn build_signature(config: &mut Config, id: &str) -> Option<(DkimSigner, ArcSeal
|
||||
(DkimSigner::RsaSha256(signer), ArcSealer::RsaSha256(sealer)).into()
|
||||
}
|
||||
Algorithm::Ed25519Sha256 => {
|
||||
let mut public_key = vec![];
|
||||
let mut private_key = vec![];
|
||||
|
||||
for (key, key_bytes) in [
|
||||
(("signature", id, "public-key"), &mut public_key),
|
||||
(("signature", id, "private-key"), &mut private_key),
|
||||
] {
|
||||
let mut contents = config.value_require(key)?.as_bytes().iter().copied();
|
||||
let mut base64 = vec![];
|
||||
|
||||
'outer: while let Some(ch) = contents.next() {
|
||||
if !ch.is_ascii_whitespace() {
|
||||
if ch == b'-' {
|
||||
for ch in contents.by_ref() {
|
||||
if ch == b'\n' {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base64.push(ch);
|
||||
}
|
||||
|
||||
for ch in contents.by_ref() {
|
||||
if ch == b'-' {
|
||||
break 'outer;
|
||||
} else if !ch.is_ascii_whitespace() {
|
||||
base64.push(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*key_bytes = base64_decode(&base64)
|
||||
.ok_or_else(|| {
|
||||
config.new_build_error(
|
||||
("signature", id),
|
||||
format!("Failed to base64 decode key for {}.", key.as_key(),),
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
let private_key = parse_pem(config, ("signature", id, "private-key"))?;
|
||||
let key = Ed25519Key::from_pkcs8_maybe_unchecked_der(&private_key)
|
||||
.or_else(|_| Ed25519Key::from_seed_and_public_key(&private_key, &public_key))
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
("signature", id),
|
||||
@@ -278,7 +236,6 @@ fn build_signature(config: &mut Config, id: &str) -> Option<(DkimSigner, ArcSeal
|
||||
})
|
||||
.ok()?;
|
||||
let key_clone = Ed25519Key::from_pkcs8_maybe_unchecked_der(&private_key)
|
||||
.or_else(|_| Ed25519Key::from_seed_and_public_key(&private_key, &public_key))
|
||||
.map_err(|err| {
|
||||
config.new_build_error(
|
||||
("signature", id),
|
||||
@@ -304,6 +261,44 @@ fn build_signature(config: &mut Config, id: &str) -> Option<(DkimSigner, ArcSeal
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pem(config: &mut Config, key: impl AsKey) -> Option<Vec<u8>> {
|
||||
if let Some(der) = simple_pem_parse(config.value_require(key.clone())?) {
|
||||
Some(der)
|
||||
} else {
|
||||
config.new_build_error(key, "Failed to base64 decode key.");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simple_pem_parse(contents: &str) -> Option<Vec<u8>> {
|
||||
let mut contents = contents.as_bytes().iter().copied();
|
||||
let mut base64 = vec![];
|
||||
|
||||
'outer: while let Some(ch) = contents.next() {
|
||||
if !ch.is_ascii_whitespace() {
|
||||
if ch == b'-' {
|
||||
for ch in contents.by_ref() {
|
||||
if ch == b'\n' {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base64.push(ch);
|
||||
}
|
||||
|
||||
for ch in contents.by_ref() {
|
||||
if ch == b'-' {
|
||||
break 'outer;
|
||||
} else if !ch.is_ascii_whitespace() {
|
||||
base64.push(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base64_decode(&base64)
|
||||
}
|
||||
|
||||
fn parse_signature<T: SigningKey, U: SigningKey<Hasher = Sha256>>(
|
||||
config: &mut Config,
|
||||
id: &str,
|
||||
|
||||
@@ -181,7 +181,7 @@ impl Default for QueueConfig {
|
||||
sign: IfBlock::new::<()>(
|
||||
"report.dsn.sign",
|
||||
[],
|
||||
"['rsa_' + key_get('default', 'domain'), 'ed_' + key_get('default', 'domain')]",
|
||||
"['rsa-' + key_get('default', 'domain'), 'ed25519-' + key_get('default', 'domain')]",
|
||||
),
|
||||
},
|
||||
timeout: QueueOutboundTimeout {
|
||||
|
||||
@@ -125,7 +125,7 @@ impl Report {
|
||||
sign: IfBlock::new::<()>(
|
||||
format!("report.{id}.sign"),
|
||||
[],
|
||||
"['rsa_' + key_get('default', 'domain'), 'ed_' + key_get('default', 'domain')]",
|
||||
"['rsa-' + key_get('default', 'domain'), 'ed25519-' + key_get('default', 'domain')]",
|
||||
),
|
||||
send: IfBlock::new::<()>(format!("report.{id}.send"), [], "[1, 1d]"),
|
||||
};
|
||||
@@ -174,7 +174,7 @@ impl AggregateReport {
|
||||
sign: IfBlock::new::<()>(
|
||||
format!("report.{id}.aggregate.sign"),
|
||||
[],
|
||||
"['rsa_' + key_get('default', 'domain'), 'ed_' + key_get('default', 'domain')]",
|
||||
"['rsa-' + key_get('default', 'domain'), 'ed25519-' + key_get('default', 'domain')]",
|
||||
),
|
||||
max_size: IfBlock::new::<()>(format!("report.{id}.aggregate.max-size"), [], "26214400"),
|
||||
};
|
||||
|
||||
@@ -86,7 +86,7 @@ impl CharUtils for char {
|
||||
|
||||
pub fn fn_cure_text<'x>(_: &'x Context<'x>, v: Vec<Variable>) -> Variable {
|
||||
decancer::cure(v[0].to_string().as_ref(), decancer::Options::default())
|
||||
.map(|s| s.into_str())
|
||||
.map(String::from)
|
||||
.unwrap_or_default()
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -587,11 +587,11 @@ mod test {
|
||||
// Test spec
|
||||
let mut text = String::new();
|
||||
for i in 0..100 {
|
||||
text += &format!("Line{i} test test test\n");
|
||||
text += format!("Line{i} test test test\n").as_str();
|
||||
}
|
||||
let mut expected = String::new();
|
||||
for i in [20, 21, 22, 60, 61, 62] {
|
||||
expected += &format!("Line{i}testtesttest");
|
||||
expected += format!("Line{i}testtesttest").as_str();
|
||||
}
|
||||
assert_eq!(
|
||||
String::from_utf8(pyzor_digest(Vec::new(), text.lines(), &psl)).unwrap(),
|
||||
|
||||
Reference in New Issue
Block a user