diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml new file mode 100644 index 0000000..22fdd5c --- /dev/null +++ b/.github/workflows/build_and_test.yml @@ -0,0 +1,54 @@ +name: Build, Test, Publish Coverage + +on: + push: + branches: ["main"] + pull_request: + branches: ["main", "dev"] + +env: + CARGO_TERM_COLOR: always + +jobs: + linux: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "linux" + - name: Build, Test and Publish Coverage + run: | + if [ -n "${{ secrets.COVERALLS_REPO_TOKEN }}" ]; then + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm cargo-tarpaulin --force + cargo tarpaulin --all-features --avoid-cfg-tarpaulin --tests --examples --verbose --skip-clean --coveralls ${{ secrets.COVERALLS_REPO_TOKEN }} --timeout 120 + else + echo "Code Coverage step is skipped on forks!" + cargo build --verbose --all-features + cargo test --verbose --all-features --tests --examples + fi + wasm: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + with: + cache-all-crates: "true" + prefix-key: "macos" + - name: Run WASM tests with Safari, Firefox, Chrome + run: | + rustup target add wasm32-unknown-unknown + curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force + cargo binstall --no-confirm wasm-pack --force + wasm-pack test --node -- --features wasm --examples + wasm-pack test --firefox -- --features wasm --examples + wasm-pack test --chrome -- --features wasm --examples + wasm-pack test --safari -- --features wasm --examples + wasm-pack test --node -- --features wasm + wasm-pack test --firefox -- --features wasm + wasm-pack test --chrome -- --features wasm + wasm-pack test --safari -- --features wasm diff --git a/Cargo.toml b/Cargo.toml index 10d0ac9..c800c5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,12 @@ repository = "https://github.com/polyphony-chat/polyproto" [lib] crate-type = ["rlib", "cdylib", "staticlib"] +[features] +wasm = ["dep:getrandom", "getrandom/js"] + [dependencies] der = { version = "0.7.8", features = ["pem"] } +getrandom = { version = "0.2.12", optional = true } spki = "0.7.3" thiserror = "1.0.57" x509-cert = { version = "0.2.5", default-features = false } @@ -19,3 +23,7 @@ x509-cert = { version = "0.2.5", default-features = false } ed25519-dalek = { version = "2.1.1", features = ["rand_core", "signature"] } rand = "0.8.5" polyproto = { path = "./" } + +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = "0.3.39" +wasm-bindgen = "0.2.89" diff --git a/README.md b/README.md index 628eab0..0178ee7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ +
+ +[![Discord]][Discord-invite] +[![Matrix]][Matrix-invite] +[![Build][build-shield]][build-url] +[![Coverage][coverage-shield]][coverage-url] +Blue status badge, reading 'Early Development' + +
+ # polyproto -(Generic) Rust types and traits to quickly get a +Crate supplying (generic) Rust types and traits to quickly get a [polyproto](https://docs.polyphony.chat/Protocol%20Specifications/core/) implementation up and running. @@ -21,9 +31,21 @@ choice. Popular crates for cryptography and signature algorithms supply their ow You can then use the [crate::certs] types to build certificates using your implementations of the aforementioned traits. +View the [examples](./examples/) directory for a simple example on how to implement and use this +crate. + ## Cryptography This crate provides no cryptographic functionality whatsoever; its sole purpose is to aid in implementing polyproto by transforming the [polyproto specification](https://docs.polyphony.chat/Protocol%20Specifications/core/) into well-defined yet adaptable Rust types. + +[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/polyproto/build_and_test.yml?style=flat +[build-url]: https://github.com/polyphony-chat/polyproto/blob/main/.github/workflows/build_and_test.yml +[coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/polyproto/badge.svg?branch=main +[coverage-url]: https://coveralls.io/github/polyphony-chat/polyproto?branch=main +[Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat +[Discord-invite]: https://discord.com/invite/m3FpcapGDD +[Matrix]: https://img.shields.io/matrix/polyproto%3Atu-dresden.de?server_fqdn=matrix.tu-dresden.de&style=flat&label=Matrix%20Room +[Matrix-invite]: https://matrix.to/#/#polyproto:tu-dresden.de \ No newline at end of file diff --git a/examples/ed25519_basic.rs b/examples/ed25519_basic.rs index 7d5a60c..ede19c9 100644 --- a/examples/ed25519_basic.rs +++ b/examples/ed25519_basic.rs @@ -17,6 +17,7 @@ use rand::rngs::OsRng; use spki::{AlgorithmIdentifierOwned, ObjectIdentifier, SignatureBitStringEncoding}; use thiserror::Error; +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn main() { let mut csprng = rand::rngs::OsRng; // Generate a key pair diff --git a/examples/ed25519_csr.rs b/examples/ed25519_csr.rs index 0d709d7..2b666dd 100644 --- a/examples/ed25519_csr.rs +++ b/examples/ed25519_csr.rs @@ -27,6 +27,7 @@ use x509_cert::request::CertReq; /// openssl req -in cert.csr -verify /// ``` +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn main() { let mut csprng = rand::rngs::OsRng; let priv_key = Ed25519PrivateKey::gen_keypair(&mut csprng); @@ -45,6 +46,7 @@ fn main() { println!("Certrequest der bytes: {:?}", certrequest.to_der().unwrap()); let data = certrequest.to_der().unwrap(); let file_name_with_extension = "cert.csr"; + #[cfg(not(target_arch = "wasm32"))] std::fs::write(file_name_with_extension, &data).unwrap(); // TODO: The attributes are still missing. CA Certificates and Actor Certificates should have diff --git a/src/lib.rs b/src/lib.rs index af7ada7..54d2b96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,7 +155,8 @@ mod test { } } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn test_convert_serial_number() { let biguint = Uint::new(&[10u8, 240u8]).unwrap(); assert_eq!(biguint.as_bytes(), &[10u8, 240u8]); diff --git a/src/value_constraints.rs b/src/value_constraints.rs index 5204a47..50e36a5 100644 --- a/src/value_constraints.rs +++ b/src/value_constraints.rs @@ -109,7 +109,8 @@ mod name_constraints { use crate::Constrained; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn correct() { let name = Name::from_str( "cn=flori,dc=localhost,uid=h3g2jt4dhfgj8hjs,uniqueIdentifier=flori@localhost", @@ -120,19 +121,22 @@ mod name_constraints { name.validate().unwrap(); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn no_domain_component() { let name = Name::from_str("CN=flori").unwrap(); assert!(name.validate().is_err()); } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn two_cns() { let name = Name::from_str("CN=flori,CN=xenia,DC=localhost").unwrap(); assert!(name.validate().is_err()) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn two_uid_or_uniqueid() { let name = Name::from_str("CN=flori,CN=xenia,uid=numbaone,uid=numbatwo").unwrap(); assert!(name.validate().is_err()); @@ -142,7 +146,8 @@ mod name_constraints { assert!(name.validate().is_err()) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn uid_and_no_uniqueid_or_uniqueid_and_no_uid() { let name = Name::from_str("CN=flori,CN=xenia,uid=numbaone").unwrap(); assert!(name.validate().is_err()); @@ -157,17 +162,20 @@ mod session_id_constraints { use crate::certs::SessionId; - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn zero_long_session_id_fails() { assert!(SessionId::new(Ia5String::new("").unwrap()).is_err()) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn thirtytwo_length_session_id_is_ok() { assert!(SessionId::new(Ia5String::new("11111111111111111111111111222222").unwrap()).is_ok()) } - #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + #[cfg_attr(not(target_arch = "wasm32"), test)] fn thirtythree_length_session_id_fails() { assert!( SessionId::new(Ia5String::new("111111111111111111111111112222223").unwrap()).is_err()