diff --git a/codec/src/communication_value.rs b/codec/src/communication_value.rs index 95b0cf0..1e48422 100644 --- a/codec/src/communication_value.rs +++ b/codec/src/communication_value.rs @@ -916,9 +916,19 @@ mod tests { let mut signer_public_keys = recipient.public_key_bundle(); signer_public_keys.sig_cl_public_key = signer_public_key; - signed.verify(SENDER_ID, &signer_public_keys, ProtectionPurpose::from(1))?; + signed.verify_with_policy( + SENDER_ID, + &signer_public_keys, + ProtectionPurpose::from(1), + crate::ProtectionPolicy::any_supported(), + )?; assert_eq!( - signed.into_verified(SENDER_ID, &signer_public_keys, ProtectionPurpose::from(1))?, + signed.into_verified_with_policy( + SENDER_ID, + &signer_public_keys, + ProtectionPurpose::from(1), + crate::ProtectionPolicy::any_supported(), + )?, clear_payload ); Ok(()) diff --git a/codec/src/data_value.rs b/codec/src/data_value.rs index 36065f8..6eb7c1b 100644 --- a/codec/src/data_value.rs +++ b/codec/src/data_value.rs @@ -2391,10 +2391,11 @@ mod tests { assert_eq!(&encoded[15 + signature_len..], inner); let decoded = DataValue::from_bytes(&encoded).ok_or("signed value did not decode")?; - decoded.verify( + decoded.verify_with_policy( 0x0102_0304_0506_0708, &public_keys, ProtectionPurpose::from(0xA5), + ProtectionPolicy::any_supported(), )?; assert!(matches!( decoded.clone().into_verified_with_policy( @@ -2406,16 +2407,18 @@ mod tests { Err(ProtectionError::SignaturePolicyMismatch { .. }) )); // Verification is non-consuming, so it can safely be repeated. - decoded.verify( + decoded.verify_with_policy( 0x0102_0304_0506_0708, &public_keys, ProtectionPurpose::from(0xA5), + ProtectionPolicy::any_supported(), )?; assert_eq!( - decoded.clone().into_verified( + decoded.clone().into_verified_with_policy( 0x0102_0304_0506_0708, &public_keys, ProtectionPurpose::from(0xA5), + ProtectionPolicy::any_supported(), )?, original ); @@ -2424,10 +2427,11 @@ mod tests { return Err("expected signed value".into()); }; assert_eq!( - wrapper.into_verified( + wrapper.into_verified_with_policy( 0x0102_0304_0506_0708, &public_keys, ProtectionPurpose::from(0xA5), + ProtectionPolicy::any_supported(), )?, original ); @@ -2503,7 +2507,12 @@ mod tests { }; wrong_purpose.purpose ^= 1; assert!(matches!( - wrong_purpose.verify(41, &public_keys, ProtectionPurpose::from(7)), + wrong_purpose.verify_with_policy( + 41, + &public_keys, + ProtectionPurpose::from(7), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::PurposeMismatch { .. }) )); @@ -2512,7 +2521,12 @@ mod tests { }; wrong_signer_id.signer_id ^= 1; assert!(matches!( - wrong_signer_id.verify(41, &public_keys, ProtectionPurpose::from(7)), + wrong_signer_id.verify_with_policy( + 41, + &public_keys, + ProtectionPurpose::from(7), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::SignerIdMismatch { .. }) )); @@ -2521,7 +2535,12 @@ mod tests { }; wrong_signature.signature[0] ^= 1; assert!(matches!( - wrong_signature.verify(41, &public_keys, ProtectionPurpose::from(7)), + wrong_signature.verify_with_policy( + 41, + &public_keys, + ProtectionPurpose::from(7), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::InvalidSignature) )); @@ -2530,7 +2549,12 @@ mod tests { }; *wrong_value.value = DataValue::Str("replacement".into()); assert!(matches!( - wrong_value.verify(41, &public_keys, ProtectionPurpose::from(7)), + wrong_value.verify_with_policy( + 41, + &public_keys, + ProtectionPurpose::from(7), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::InvalidSignature) )); Ok(()) @@ -2593,9 +2617,19 @@ mod tests { let opened = decoded.decrypt(&keyring, ProtectionPurpose::from(2))?; let mut public_keys = keyring.public_key_bundle(); public_keys.sig_cl_public_key = signer_public; - opened.verify(7, &public_keys, ProtectionPurpose::from(1))?; + opened.verify_with_policy( + 7, + &public_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + )?; assert_eq!( - opened.into_verified(7, &public_keys, ProtectionPurpose::from(1))?, + opened.into_verified_with_policy( + 7, + &public_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + )?, value ); Ok(()) @@ -2629,8 +2663,18 @@ mod tests { return Err("expected signed outer wrapper".into()); }; assert_eq!(signed.signer_id, 7); - signed.verify(7, &public_keys, ProtectionPurpose::from(1))?; - let encrypted = signed.into_verified(7, &public_keys, ProtectionPurpose::from(1))?; + signed.verify_with_policy( + 7, + &public_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + )?; + let encrypted = signed.into_verified_with_policy( + 7, + &public_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + )?; assert!(matches!(encrypted, DataValue::Encrypted(_))); assert_eq!( encrypted.decrypt(&keyring, ProtectionPurpose::from(2))?, @@ -2680,10 +2724,11 @@ mod tests { let mut signer_keys = outer_recipient.public_key_bundle(); signer_keys.sig_cl_public_key = signer_public; - let middle = outer_signed.into_verified( + let middle = outer_signed.into_verified_with_policy( OUTER_SIGNER_ID, &signer_keys, ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), )?; let DataValue::Container(entries) = middle else { return Err("expected container inside outer signature".into()); @@ -2700,10 +2745,11 @@ mod tests { }; assert_eq!(inner_wrapper.signer_id, INNER_SIGNER_ID); assert_eq!( - inner_signed.into_verified( + inner_signed.into_verified_with_policy( INNER_SIGNER_ID, &signer_keys, ProtectionPurpose::from(3), + ProtectionPolicy::any_supported(), )?, leaf ); @@ -2861,11 +2907,21 @@ mod tests { let public_keys = keyring.public_key_bundle(); assert!(matches!( - DataValue::Null.verify(1, &public_keys, ProtectionPurpose::from(1)), + DataValue::Null.verify_with_policy( + 1, + &public_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::NotSigned) )); assert!(matches!( - DataValue::Null.into_verified(1, &public_keys, ProtectionPurpose::from(1)), + DataValue::Null.into_verified_with_policy( + 1, + &public_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::NotSigned) )); assert!(matches!( @@ -2909,7 +2965,12 @@ mod tests { }; signed.signature[0] ^= 1; assert!(matches!( - DataValue::Signed(signed).verify(1, &signing_keys, ProtectionPurpose::from(1)), + DataValue::Signed(signed).verify_with_policy( + 1, + &signing_keys, + ProtectionPurpose::from(1), + ProtectionPolicy::any_supported(), + ), Err(ProtectionError::InvalidSignature) )); diff --git a/codec/src/protected.rs b/codec/src/protected.rs index cd8ee0f..dd4f1c2 100644 --- a/codec/src/protected.rs +++ b/codec/src/protected.rs @@ -133,6 +133,10 @@ impl InMemoryReplayGuard { pub fn len(&self) -> usize { self.accepted.len() } + + pub fn is_empty(&self) -> bool { + self.accepted.is_empty() + } } impl ReplayGuard for InMemoryReplayGuard { diff --git a/codec/src/relay.rs b/codec/src/relay.rs index a09ef4f..8633a75 100644 --- a/codec/src/relay.rs +++ b/codec/src/relay.rs @@ -1022,6 +1022,18 @@ mod tests { Ed25519Signer::new(&keyring.sig_cl_secret_key).expect("Ed25519 signer") } + fn content_open_options( + metadata: &VerifiedRelayMetadata, + policy: ProtectionPolicy, + ) -> RelayOpenOptions { + RelayOpenOptions { + policy, + decode_limits: metadata.decode_limits, + encode_limits: metadata.encode_limits, + protected_limits: metadata.protected_limits, + } + } + // Test-only compatibility shims keep older fixture setup readable while // routing every invocation to an explicit replay choice in production. fn open_relay_metadata( @@ -1345,12 +1357,12 @@ mod tests { ) .expect("final recipient metadata"); assert_eq!(final_metadata.metadata(), Some(&application_metadata)); - let final_content = open_relay_content( + let final_content = open_relay_content_with_limits_without_replay( &final_metadata, - &final_recipient, - &sender.public_key_bundle(), - 42, - policy, + &[&final_recipient], + std::slice::from_ref(&sender.public_key_bundle()), + Some(42), + content_open_options(&final_metadata, policy), ) .expect("final recipient content"); assert_eq!(final_content.content, DataValue::Str("hello".into())); @@ -1393,22 +1405,22 @@ mod tests { )); assert!( - open_relay_content( + open_relay_content_with_limits_without_replay( &metadata, - &metadata_recipient, - &sender.public_key_bundle(), - 42, - policy, + &[&metadata_recipient], + std::slice::from_ref(&sender.public_key_bundle()), + Some(42), + content_open_options(&metadata, policy), ) .is_err() ); - let content = open_relay_content( + let content = open_relay_content_with_limits_without_replay( &metadata, - &final_recipient, - &sender.public_key_bundle(), - 42, - policy, + &[&final_recipient], + std::slice::from_ref(&sender.public_key_bundle()), + Some(42), + content_open_options(&metadata, policy), ) .expect("content"); assert_eq!(content.signer_id, 7); @@ -1416,12 +1428,12 @@ mod tests { assert_eq!(content.message_type, "ProtectedMessage"); assert_eq!(content.content, DataValue::Str("hello".into())); assert!(matches!( - open_relay_content( + open_relay_content_with_limits_without_replay( &metadata, - &final_recipient, - &sender.public_key_bundle(), - 43, - policy, + &[&final_recipient], + std::slice::from_ref(&sender.public_key_bundle()), + Some(43), + content_open_options(&metadata, policy), ), Err(RelayError::NotFinalRecipient) )); @@ -1512,7 +1524,12 @@ mod tests { .expect("relay frame"); assert_eq!( - relay_metadata_claimed_signer_id(&frame, &[&recipient]).expect("signer ID"), + relay_metadata_claimed_signer_id_with_limits( + &frame, + &[&recipient], + DecodeLimits::default(), + ) + .expect("signer ID"), 7 ); let metadata = open_relay_metadata_with_keys( @@ -1523,12 +1540,15 @@ mod tests { ProtectionPolicy::from(crate::SignaturePolicy::Ed25519), ) .expect("relay metadata"); - let content = open_relay_content_with_keyrings( + let content = open_relay_content_with_limits_without_replay( &metadata, &[&recipient], &[sender.public_key_bundle()], Some(42), - ProtectionPolicy::from(crate::SignaturePolicy::Ed25519), + content_open_options( + &metadata, + ProtectionPolicy::from(crate::SignaturePolicy::Ed25519), + ), ) .expect("relay content"); @@ -1571,12 +1591,12 @@ mod tests { ) .expect("relay metadata"); - let content = open_relay_content_with_keyrings( + let content = open_relay_content_with_limits_without_replay( &metadata, &[¤t_content_recipient, &previous_content_recipient], &[sender.public_key_bundle()], Some(42), - policy, + content_open_options(&metadata, policy), ) .expect("previous content recipient key should decrypt"); @@ -1680,12 +1700,12 @@ mod tests { ) .expect("metadata signed by a previous key should verify"); assert_eq!(metadata.matched_signer_key_index(), 1); - let content = open_relay_content_with_keys( + let content = open_relay_content_with_limits_without_replay( &metadata, - &recipient, + &[&recipient], &[current_signer_public, old_signer_public], - 42, - policy, + Some(42), + content_open_options(&metadata, policy), ) .expect("content signed by a previous key should verify"); assert_eq!(content.message_type, "ProtectedMessage"); diff --git a/create-web-release.mjs b/create-web-release.mjs new file mode 100644 index 0000000..690fa5c --- /dev/null +++ b/create-web-release.mjs @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +import { execFile, spawn } from "node:child_process"; +import { access, cp, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { promisify } from "node:util"; +import { fileURLToPath } from "node:url"; + +const execFileAsync = promisify(execFile); +const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "."); +const packageJsonPath = path.join(repositoryRoot, "package.json"); + +function usage() { + return `Usage: node create-web-release.mjs [options] + +Build and pack the browser package using the version of the root Cargo package. + +Options: + --skip-build Pack the existing dist/ and wasm/pkg/ artifacts + --output-dir Write the archive to this directory (default: repository root) + --help Show this help +`; +} + +function parseArguments(arguments_) { + const options = { + outputDir: repositoryRoot, + skipBuild: false, + }; + + for (let index = 0; index < arguments_.length; index += 1) { + const argument = arguments_[index]; + if (argument === "--help") { + options.help = true; + } else if (argument === "--skip-build") { + options.skipBuild = true; + } else if (argument === "--output-dir") { + const outputDir = arguments_[index + 1]; + if (!outputDir || outputDir.startsWith("--")) { + throw new Error("--output-dir requires a directory path"); + } + options.outputDir = path.resolve(repositoryRoot, outputDir); + index += 1; + } else if (argument.startsWith("--output-dir=")) { + const outputDir = argument.slice("--output-dir=".length); + if (!outputDir) { + throw new Error("--output-dir requires a directory path"); + } + options.outputDir = path.resolve(repositoryRoot, outputDir); + } else { + throw new Error(`Unknown option: ${argument}`); + } + } + + return options; +} + +async function readJson(filePath) { + const source = await readFile(filePath, "utf8"); + try { + return JSON.parse(source); + } catch (error) { + throw new Error(`Invalid JSON in ${path.relative(repositoryRoot, filePath)}`, { + cause: error, + }); + } +} + +async function run(command, arguments_, options = {}) { + const renderedArguments = arguments_.map((argument) => JSON.stringify(argument)).join(" "); + console.log(`\n> ${command}${renderedArguments ? ` ${renderedArguments}` : ""}`); + + await new Promise((resolve, reject) => { + const child = spawn(command, arguments_, { + cwd: options.cwd ?? repositoryRoot, + env: options.env ?? process.env, + stdio: "inherit", + }); + + child.once("error", (error) => { + reject(new Error(`Failed to run ${command}: ${error.message}`, { cause: error })); + }); + child.once("exit", (code, signal) => { + if (code === 0) { + resolve(); + return; + } + + const reason = signal ? `signal ${signal}` : `exit code ${code}`; + reject(new Error(`${command} failed with ${reason}`)); + }); + }); +} + +async function readCargoVersion() { + let stdout; + try { + ({ stdout } = await execFileAsync( + "cargo", + [ + "metadata", + "--no-deps", + "--format-version", + "1", + "--manifest-path", + path.join(repositoryRoot, "Cargo.toml"), + ], + { cwd: repositoryRoot, maxBuffer: 1024 * 1024 }, + )); + } catch (error) { + throw new Error(`Unable to read the root Cargo package version: ${error.message}`, { + cause: error, + }); + } + + let metadata; + try { + metadata = JSON.parse(stdout); + } catch (error) { + throw new Error("cargo metadata returned invalid JSON", { cause: error }); + } + + const rootPackage = metadata.packages?.find((packageMetadata) => packageMetadata.name === "mtp"); + if (!rootPackage || typeof rootPackage.version !== "string") { + throw new Error("The root Cargo package named 'mtp' was not found"); + } + + return rootPackage.version; +} + +function packageRelativePath(entry) { + if (typeof entry !== "string" || entry.length === 0) { + throw new Error("package.json files entries must be non-empty strings"); + } + + const relativePath = entry.replace(/\/$/, ""); + if ( + !relativePath || + path.isAbsolute(relativePath) || + relativePath.split(/[\\/]/u).includes("..") || + relativePath.includes("*") + ) { + throw new Error(`Unsupported package file entry: ${entry}`); + } + + return relativePath; +} + +async function copyPackageFiles(stageRoot, packageJson) { + if (!Array.isArray(packageJson.files)) { + throw new Error("package.json must declare a files array for Web releases"); + } + + for (const entry of packageJson.files) { + const relativePath = packageRelativePath(entry); + const sourcePath = path.join(repositoryRoot, relativePath); + const destinationPath = path.join(stageRoot, relativePath); + + try { + await access(sourcePath); + } catch (error) { + throw new Error(`Release file is missing: ${relativePath}`, { cause: error }); + } + + await mkdir(path.dirname(destinationPath), { recursive: true }); + await cp(sourcePath, destinationPath, { recursive: true }); + } +} + +async function createRelease({ outputDir, packageJson, version }) { + const stageRoot = await mkdtemp(path.join(os.tmpdir(), "mtp-web-release-")); + const stagedPackageJson = { + ...packageJson, + version, + }; + + try { + await writeFile( + path.join(stageRoot, "package.json"), + `${JSON.stringify(stagedPackageJson, null, 2)}\n`, + ); + await copyPackageFiles(stageRoot, packageJson); + + const stagedWasmPackagePath = path.join(stageRoot, "wasm", "pkg", "package.json"); + const stagedWasmPackageJson = await readJson(stagedWasmPackagePath); + stagedWasmPackageJson.version = version; + await writeFile( + stagedWasmPackagePath, + `${JSON.stringify(stagedWasmPackageJson, null, 2)}\n`, + ); + + await mkdir(outputDir, { recursive: true }); + const archiveName = `${packageJson.name}-${version}.tgz`; + const archivePath = path.join(outputDir, archiveName); + await rm(archivePath, { force: true }); + + await run("npm", ["pack", "--pack-destination", outputDir], { cwd: stageRoot }); + + try { + await access(archivePath); + } catch (error) { + throw new Error(`npm pack did not create ${archiveName}`, { cause: error }); + } + + return archivePath; + } finally { + await rm(stageRoot, { recursive: true, force: true }); + } +} + +async function main() { + const options = parseArguments(process.argv.slice(2)); + if (options.help) { + console.log(usage()); + return; + } + + const packageJson = await readJson(packageJsonPath); + if (packageJson.name !== "mtp") { + throw new Error("package.json must describe the 'mtp' Web package"); + } + + const version = await readCargoVersion(); + console.log(`Using Cargo package version ${version}`); + + if (!options.skipBuild) { + await run("pnpm", ["run", "clean"]); + await run("pnpm", ["run", "build"]); + } + + const archivePath = await createRelease({ + outputDir: options.outputDir, + packageJson, + version, + }); + console.log(`\nCreated ${path.relative(repositoryRoot, archivePath) || archivePath}`); +} + +main().catch((error) => { + console.error(`\n${error.message}`); + process.exitCode = 1; +}); diff --git a/crypto/src/helper.rs b/crypto/src/helper.rs index 018f0cd..6254cd8 100644 --- a/crypto/src/helper.rs +++ b/crypto/src/helper.rs @@ -129,7 +129,7 @@ impl<'a> MultiEncryptedMessageRef<'a> { &self.bytes[self.ciphertext_start..] } - pub fn to_owned(&self) -> MultiEncryptedMessage { + pub fn to_owned(self) -> MultiEncryptedMessage { let recipients = (0..self.count) .filter_map(|index| { let (kem_ciphertext, encrypted_key) = self.recipient(index)?; diff --git a/example/client/src/protected.rs b/example/client/src/protected.rs index 74214b8..e9c2981 100644 --- a/example/client/src/protected.rs +++ b/example/client/src/protected.rs @@ -3,7 +3,7 @@ use std::time::{Duration, Instant}; use mtp::client::MTPConnection; use mtp::codec::{ CommunicationType, DataType, DataValue, ProtectionPolicy, ProtectedMessageBuilder, - ProtectionPurpose, SealedRelayBuilder, SignaturePolicy, TypeMap, + ProtectionPurpose, RelayOpenOptions, SealedRelayBuilder, SignaturePolicy, TypeMap, open_relay_content_with_limits_without_replay, open_relay_metadata_without_replay, }; @@ -165,17 +165,17 @@ pub async fn send_sealed_relay( &final_recipient_keyring, signer_id, &signer_keyring.public_key_bundle(), - RELAY_SIGNATURE_POLICY, + RelayOpenOptions::new(RELAY_SIGNATURE_POLICY), )?; let application_metadata = metadata .metadata() .ok_or("forwarded relay metadata was missing")?; let content = open_relay_content_with_limits_without_replay( &metadata, - &final_recipient_keyring, - &signer_keyring.public_key_bundle(), - FINAL_RECIPIENT_ID, - RELAY_SIGNATURE_POLICY, + &[&final_recipient_keyring], + &[signer_keyring.public_key_bundle()], + Some(FINAL_RECIPIENT_ID), + RelayOpenOptions::new(RELAY_SIGNATURE_POLICY), )?; if content.message_type != "ProtectedMessage" { return Err(format!("unexpected relay message type: {}", content.message_type).into()); diff --git a/example/server/src/handlers.rs b/example/server/src/handlers.rs index 2d9d0cd..13a2990 100644 --- a/example/server/src/handlers.rs +++ b/example/server/src/handlers.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use mtp::codec::{ CommunicationType, CommunicationValue, DataType, DataTypeId, DataValue, InMemoryReplayGuard, - ProtectedOpenOptions, ProtectionPolicy, ProtectionPurpose, SignaturePolicy, TypeMap, + ProtectedOpenOptions, ProtectionPolicy, ProtectionPurpose, RelayOpenOptions, SignaturePolicy, + TypeMap, forward_relay_frame, open_protected_with_checked, open_relay_content_with_limits_without_replay, open_relay_metadata_with_checked, @@ -142,7 +143,7 @@ fn process_sealed_relay( |signer_id| { resolve_signer_key(signer_id, registered_clients).map(|key| vec![key]) }, - SIGNATURE_POLICY, + RelayOpenOptions::new(SIGNATURE_POLICY), accepted_messages, ) .map_err(|e| format!("metadata relay could not authenticate metadata: {e}"))?; @@ -164,11 +165,11 @@ fn process_sealed_relay( let content_result = open_relay_content_with_limits_without_replay( &metadata, - host_keyring, - &resolve_signer_key(metadata.signer_id(), registered_clients) - .ok_or("metadata signer key disappeared")?, - FINAL_RECIPIENT_ID, - SIGNATURE_POLICY, + &[host_keyring], + &[resolve_signer_key(metadata.signer_id(), registered_clients) + .ok_or("metadata signer key disappeared")?], + Some(FINAL_RECIPIENT_ID), + RelayOpenOptions::new(SIGNATURE_POLICY), ); if content_result.is_ok() { return Err("metadata relay unexpectedly decrypted final-recipient content".into()); @@ -309,12 +310,22 @@ pub fn process_and_respond( let signer_id = sig.as_signed().map(|signed| signed.signer_id); if let Some(signer_id) = signer_id && sig - .verify(signer_id, pk_bundle, mtp::codec::ProtectionPurpose::from(2)) + .verify_with_policy( + signer_id, + pk_bundle, + mtp::codec::ProtectionPurpose::from(2), + SIGNATURE_POLICY, + ) .is_ok() { let dv = sig .clone() - .into_verified(signer_id, pk_bundle, mtp::codec::ProtectionPurpose::from(2)) + .into_verified_with_policy( + signer_id, + pk_bundle, + mtp::codec::ProtectionPurpose::from(2), + SIGNATURE_POLICY, + ) .ok(); if let Some(entries) = dv.and_then(|value| value.as_container()) { println!(" Verified SignedPayload: {:?}", entries); @@ -335,16 +346,22 @@ pub fn process_and_respond( if let Ok(opened) = secure.decrypt(host_keyring, mtp::codec::ProtectionPurpose::from(4)) && let Some(signed) = opened.as_signed() && opened - .verify( + .verify_with_policy( signed.signer_id, pk_bundle, mtp::codec::ProtectionPurpose::from(3), + SIGNATURE_POLICY, ) .is_ok() { let signer_id = signed.signer_id; let dv = opened - .into_verified(signer_id, pk_bundle, mtp::codec::ProtectionPurpose::from(3)) + .into_verified_with_policy( + signer_id, + pk_bundle, + mtp::codec::ProtectionPurpose::from(3), + SIGNATURE_POLICY, + ) .ok(); if let Some(entries) = dv.and_then(|value| value.as_container()) { println!(" Verified SecurePayload: {:?}", entries); diff --git a/flake.nix b/flake.nix index b03cd18..7951305 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,5 @@ { description = "MTP - Methanium Transport Protocol"; - inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; rust-overlay.url = "github:oxalica/rust-overlay"; diff --git a/host/src/config.rs b/host/src/config.rs index 6ab4c36..0cef52a 100644 --- a/host/src/config.rs +++ b/host/src/config.rs @@ -227,10 +227,11 @@ impl AuthenticationAttemptLimiter for InMemoryAuthenticationAttemptLimiter { } for key in keys { - if !attempts.contains_key(&key) && attempts.len() >= self.max_keys { - if let Some(oldest) = attempts.keys().next().cloned() { - attempts.remove(&oldest); - } + if !attempts.contains_key(&key) + && attempts.len() >= self.max_keys + && let Some(oldest) = attempts.keys().next().cloned() + { + attempts.remove(&oldest); } attempts.entry(key).or_default().push_back(now); } diff --git a/package.json b/package.json index b05b6ec..f4fef0d 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "build:wasm": "MTP_TYPE_MAPS=$PWD/example-type-maps.yaml wasm-pack build wasm --target web --out-dir pkg --release && rm -f wasm/pkg/.gitignore", "build:ts": "rm -rf dist && tsc", "build": "pnpm run build:wasm && pnpm run build:ts", - "pack": "pnpm run clean && pnpm run build && pnpm pack", + "pack": "pnpm run release:web", + "release:web": "node create-web-release.mjs", "build:all": "nix run .#build-all", "dup": "jscpd --pattern '**/*.{rs,ts}' --ignore 'target/**' --ignore 'wasm/pkg/**' --ignore '.git/**' --min-lines 8 --min-tokens 80 --threshold 4 --reporters console --noTips .", "test:e2e": "tsc && node test/e2ee.mjs", diff --git a/transport/src/connection.rs b/transport/src/connection.rs index 3e30b93..dece604 100644 --- a/transport/src/connection.rs +++ b/transport/src/connection.rs @@ -1460,9 +1460,11 @@ mod tests { #[test] fn runtime_policy_normalizes_zero_channel_and_task_limits() { - let mut policy = Policy::default(); - policy.receiver_queue_capacity = 0; - policy.max_concurrent_stream_tasks = 0; + let policy = Policy { + receiver_queue_capacity: 0, + max_concurrent_stream_tasks: 0, + ..Policy::default() + }; let runtime = RuntimePolicy::from_public(&policy);