Skip to content

Commit f50cbe9

Browse files
authored
Merge branch 'main' into feat/linked-verifiable-presentation
2 parents d061db4 + b355b47 commit f50cbe9

File tree

17 files changed

+177
-27
lines changed

17 files changed

+177
-27
lines changed

.github/actions/iota-sandbox/tear-down/action.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ runs:
77
shell: bash
88
run: |
99
cd iota-sandbox/sandbox
10-
docker-compose down
10+
docker compose down
1111
cd ../..
1212
sudo rm -rf iota-sandbox

.github/workflows/build-and-test.yml

+9-6
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,18 @@ jobs:
126126
run: cargo clean
127127

128128
# Build the library, tests, and examples without running them to avoid recompilation in the run tests step
129-
- name: Build with all features
130-
run: cargo build --workspace --tests --examples --all-features --release
129+
- name: Build with default features
130+
run: cargo build --workspace --tests --examples --release
131131

132132
- name: Start iota sandbox
133133
if: matrix.os == 'ubuntu-latest'
134134
uses: './.github/actions/iota-sandbox/setup'
135135

136-
- name: Run tests
137-
run: cargo test --workspace --all-features --release
136+
- name: Run tests excluding `custom_time` feature
137+
run: cargo test --workspace --release
138+
139+
- name: Run tests with `custom_time` feature
140+
run: cargo test --test custom_time --features="custom_time"
138141

139142
- name: Run Rust examples
140143
# run examples only on ubuntu for now
@@ -157,7 +160,7 @@ jobs:
157160
- name: Tear down iota sandbox
158161
if: matrix.os == 'ubuntu-latest' && always()
159162
uses: './.github/actions/iota-sandbox/tear-down'
160-
163+
161164
- name: Stop sccache
162165
uses: './.github/actions/rust/sccache/stop-sccache'
163166
with:
@@ -253,7 +256,7 @@ jobs:
253256
load: true
254257

255258
- name: Run cypress
256-
run: docker run --network host cypress-test test:browser:firefox
259+
run: docker run --network host cypress-test test:browser:parallel:firefox
257260

258261
- name: Tear down iota sandbox
259262
if: always()

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ members = [
2020
exclude = ["bindings/wasm", "bindings/grpc"]
2121

2222
[workspace.dependencies]
23-
bls12_381_plus = { version = "=0.8.15" }
23+
bls12_381_plus = { version = "0.8.17" }
2424
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
2525
thiserror = { version = "1.0", default-features = false }
2626
strum = { version = "0.25", default-features = false, features = ["std", "derive"] }

bindings/wasm/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ crate-type = ["cdylib", "rlib"]
1717

1818
[dependencies]
1919
async-trait = { version = "0.1", default-features = false }
20-
bls12_381_plus = "=0.8.15"
20+
bls12_381_plus = "0.8.17"
2121
console_error_panic_hook = { version = "0.1" }
2222
futures = { version = "0.3" }
2323
identity_eddsa_verifier = { path = "../../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }

bindings/wasm/cypress.config.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@ export default defineConfig({
1010
},
1111
e2e: {
1212
supportFile: false,
13-
// Fix to make subtle crypto work in cypress firefox
14-
// https://github.com/cypress-io/cypress/issues/18217
1513
setupNodeEvents(on, config) {
1614
on("before:browser:launch", (browser, launchOptions) => {
1715
if (browser.family === "firefox") {
16+
// Fix to make subtle crypto work in cypress firefox
17+
// https://github.com/cypress-io/cypress/issues/18217
1818
launchOptions.preferences[
1919
"network.proxy.testing_localhost_is_secure_when_hijacked"
2020
] = true;
21+
// Temporary fix to allow cypress to control Firefox via CDP
22+
// https://github.com/cypress-io/cypress/issues/29713
23+
// https://fxdx.dev/deprecating-cdp-support-in-firefox-embracing-the-future-with-webdriver-bidi/
24+
launchOptions.preferences[
25+
"remote.active-protocols"
26+
] = 3;
2127
}
2228
return launchOptions;
2329
});

identity_core/Cargo.toml

+9-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ rust-version.workspace = true
1212
description = "The core traits and types for the identity-rs library."
1313

1414
[dependencies]
15-
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519", "random", "sha", "x25519", "std"] }
1615
multibase = { version = "0.9", default-features = false, features = ["std"] }
1716
serde = { workspace = true, features = ["std"] }
1817
serde_json = { workspace = true, features = ["std"] }
@@ -22,7 +21,7 @@ time = { version = "0.3.23", default-features = false, features = ["std", "serde
2221
url = { version = "2.4", default-features = false, features = ["serde"] }
2322
zeroize = { version = "1.6", default-features = false }
2423

25-
[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies]
24+
[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(feature = "custom_time")))'.dependencies]
2625
js-sys = { version = "0.3.55", default-features = false }
2726

2827
[dev-dependencies]
@@ -38,3 +37,11 @@ rustdoc-args = ["--cfg", "docsrs"]
3837

3938
[lints]
4039
workspace = true
40+
41+
[features]
42+
# Enables a macro to provide a custom time (Timestamp::now_utc) implementation, see src/custom_time.rs
43+
custom_time = []
44+
45+
[[test]]
46+
name = "custom_time"
47+
required-features = ["custom_time"]

identity_core/src/common/timestamp.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ impl Timestamp {
4242
/// fractional seconds truncated.
4343
///
4444
/// See the [`datetime` DID-core specification](https://www.w3.org/TR/did-core/#production).
45-
#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))]
45+
#[cfg(all(
46+
not(all(target_arch = "wasm32", not(target_os = "wasi"))),
47+
not(feature = "custom_time")
48+
))]
4649
pub fn now_utc() -> Self {
4750
Self(truncate_fractional_seconds(OffsetDateTime::now_utc()))
4851
}
@@ -51,14 +54,23 @@ impl Timestamp {
5154
/// fractional seconds truncated.
5255
///
5356
/// See the [`datetime` DID-core specification](https://www.w3.org/TR/did-core/#production).
54-
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
57+
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(feature = "custom_time")))]
5558
pub fn now_utc() -> Self {
5659
let milliseconds_since_unix_epoch: i64 = js_sys::Date::now() as i64;
5760
let seconds: i64 = milliseconds_since_unix_epoch / 1000;
5861
// expect is okay, we assume the current time is between 0AD and 9999AD
5962
Self::from_unix(seconds).expect("Timestamp failed to convert system datetime")
6063
}
6164

65+
/// Creates a new `Timestamp` with the current date and time, normalized to UTC+00:00 with
66+
/// fractional seconds truncated.
67+
///
68+
/// See the [`datetime` DID-core specification](https://www.w3.org/TR/did-core/#production).
69+
#[cfg(feature = "custom_time")]
70+
pub fn now_utc() -> Self {
71+
crate::custom_time::now_utc_custom()
72+
}
73+
6274
/// Returns the `Timestamp` as an [RFC 3339](https://tools.ietf.org/html/rfc3339) `String`.
6375
pub fn to_rfc3339(&self) -> String {
6476
// expect is okay, constructors ensure RFC 3339 compatible timestamps.

identity_core/src/custom_time.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2020-2024 IOTA Stiftung
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! An implementation of `now_utc` which calls out to an externally defined function.
5+
use crate::common::Timestamp;
6+
7+
/// Register a function to be invoked by `identity_core` in order to get a [Timestamp] representing
8+
/// "now".
9+
///
10+
/// ## Writing a custom `now_utc` implementation
11+
///
12+
/// The function to register must have the same signature as
13+
/// [`Timestamp::now_utc`](Timestamp::now_utc). The function can be defined
14+
/// wherever you want, either in root crate or a dependent crate.
15+
///
16+
/// For example, if we wanted a `static_now_utc` crate containing an
17+
/// implementation that always returns the same timestamp, we would first depend on `identity_core`
18+
/// (for the [`Timestamp`] type) in `static_now_utc/Cargo.toml`:
19+
/// ```toml
20+
/// [dependencies]
21+
/// identity_core = "1"
22+
/// ```
23+
/// Note that the crate containing this function does **not** need to enable the
24+
/// `"custom_time"` Cargo feature.
25+
///
26+
/// Next, in `static_now_utc/src/lib.rs`, we define our function:
27+
/// ```rust
28+
/// use identity_core::common::Timestamp;
29+
///
30+
/// // Some fixed timestamp
31+
/// const MY_FIXED_TIMESTAMP: i64 = 1724402964;
32+
/// pub fn static_now_utc() -> Timestamp {
33+
/// Timestamp::from_unix(MY_FIXED_TIMESTAMP).unwrap()
34+
/// }
35+
/// ```
36+
///
37+
/// ## Registering a custom `now_utc` implementation
38+
///
39+
/// Functions can only be registered in the root binary crate. Attempting to
40+
/// register a function in a non-root crate will result in a linker error.
41+
/// This is similar to
42+
/// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or
43+
/// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html),
44+
/// where helper crates define handlers/allocators but only the binary crate
45+
/// actually _uses_ the functionality.
46+
///
47+
/// To register the function, we first depend on `static_now_utc` _and_
48+
/// `identity_core` in `Cargo.toml`:
49+
/// ```toml
50+
/// [dependencies]
51+
/// static_now_utc = "0.1"
52+
/// identity_core = { version = "1", features = ["custom_time"] }
53+
/// ```
54+
///
55+
/// Then, we register the function in `src/main.rs`:
56+
/// ```rust
57+
/// # mod static_now_utc { pub fn static_now_utc() -> Timestamp { unimplemented!() } }
58+
///
59+
/// use identity_core::register_custom_now_utc;
60+
/// use static_now_utc::static_now_utc;
61+
///
62+
/// register_custom_now_utc!(static_now_utc);
63+
/// ```
64+
///
65+
/// Now any user of `now_utc` (direct or indirect) on this target will use the
66+
/// registered function.
67+
#[macro_export]
68+
macro_rules! register_custom_now_utc {
69+
($path:path) => {
70+
const __GET_TIME_INTERNAL: () = {
71+
// We use Rust ABI to be safe against potential panics in the passed function.
72+
#[no_mangle]
73+
unsafe fn __now_utc_custom() -> Timestamp {
74+
// Make sure the passed function has the type of `now_utc_custom`
75+
type F = fn() -> Timestamp;
76+
let f: F = $path;
77+
f()
78+
}
79+
};
80+
};
81+
}
82+
83+
pub(crate) fn now_utc_custom() -> Timestamp {
84+
extern "Rust" {
85+
fn __now_utc_custom() -> Timestamp;
86+
}
87+
unsafe { __now_utc_custom() }
88+
}

identity_core/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright 2020-2021 IOTA Stiftung
22
// SPDX-License-Identifier: Apache-2.0
33

4-
#![forbid(unsafe_code)]
54
#![doc = include_str!("./../README.md")]
65
#![allow(clippy::upper_case_acronyms)]
76
#![warn(
@@ -19,9 +18,15 @@
1918
#[doc(inline)]
2019
pub use serde_json::json;
2120

21+
#[forbid(unsafe_code)]
2222
pub mod common;
23+
#[forbid(unsafe_code)]
2324
pub mod convert;
25+
#[forbid(unsafe_code)]
2426
pub mod error;
2527

28+
#[cfg(feature = "custom_time")]
29+
pub mod custom_time;
30+
2631
pub use self::error::Error;
2732
pub use self::error::Result;

identity_core/tests/custom_time.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2020-2024 IOTA Stiftung
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use identity_core::common::Timestamp;
5+
use identity_core::register_custom_now_utc;
6+
7+
const STATIC_TIME: i64 = 1724402964; // 2024-08-23T11:33:30+00:00
8+
pub fn static_now_utc() -> Timestamp {
9+
Timestamp::from_unix(STATIC_TIME).unwrap()
10+
}
11+
12+
register_custom_now_utc!(static_now_utc);
13+
14+
#[test]
15+
fn should_use_registered_static_time() {
16+
let timestamp = Timestamp::now_utc();
17+
assert_eq!(timestamp.to_unix(), STATIC_TIME)
18+
}

identity_credential/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ zkryptium = { workspace = true, optional = true }
3939
[dev-dependencies]
4040
anyhow = "1.0.62"
4141
identity_eddsa_verifier = { path = "../identity_eddsa_verifier", default-features = false, features = ["ed25519"] }
42-
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519", "std", "random"] }
42+
iota-crypto = { version = "0.23.2", default-features = false, features = ["ed25519", "std", "random"] }
4343
proptest = { version = "1.4.0", default-features = false, features = ["std"] }
4444
tokio = { version = "1.35.0", default-features = false, features = ["rt-multi-thread", "macros"] }
4545

identity_eddsa_verifier/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ description = "JWS EdDSA signature verification for IOTA Identity"
1313

1414
[dependencies]
1515
identity_jose = { version = "=1.3.1", path = "../identity_jose", default-features = false }
16-
iota-crypto = { version = "0.23", default-features = false, features = ["std"] }
16+
iota-crypto = { version = "0.23.2", default-features = false, features = ["std"] }
1717

1818
[features]
1919
ed25519 = ["iota-crypto/ed25519"]

identity_iota_core/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ thiserror.workspace = true
3131

3232
[dev-dependencies]
3333
anyhow = { version = "1.0.57" }
34-
iota-crypto = { version = "0.23", default-features = false, features = ["bip39", "bip39-en"] }
34+
iota-crypto = { version = "0.23.2", default-features = false, features = ["bip39", "bip39-en"] }
3535
proptest = { version = "1.0.0", default-features = false, features = ["std"] }
3636
tokio = { version = "1.29.0", default-features = false, features = ["rt-multi-thread", "macros"] }
3737

identity_jose/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ description = "A library for JOSE (JSON Object Signing and Encryption)"
1414
[dependencies]
1515
bls12_381_plus.workspace = true
1616
identity_core = { version = "=1.3.1", path = "../identity_core", default-features = false }
17-
iota-crypto = { version = "0.23", default-features = false, features = ["std", "sha"] }
17+
iota-crypto = { version = "0.23.2", default-features = false, features = ["std", "sha"] }
1818
json-proof-token.workspace = true
1919
serde.workspace = true
2020
serde_json = { version = "1.0", default-features = false, features = ["std"] }
@@ -24,7 +24,7 @@ zeroize = { version = "1.6", default-features = false, features = ["std", "zeroi
2424

2525
[dev-dependencies]
2626
anyhow = "1"
27-
iota-crypto = { version = "0.23", features = ["ed25519", "random", "hmac"] }
27+
iota-crypto = { version = "0.23.2", features = ["ed25519", "random", "hmac"] }
2828
p256 = { version = "0.12.0", default-features = false, features = ["std", "ecdsa", "ecdsa-core"] }
2929
signature = { version = "2", default-features = false }
3030

identity_jose/src/tests/rfc8037.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ fn test_rfc8037_ed25519() {
5050
.and_then(|decoded| decoded.verify(&jws_verifier, &public))
5151
.unwrap();
5252

53+
assert_eq!(token.protected, header);
54+
assert_eq!(token.claims, tv.payload.as_bytes());
55+
5356
let jws_signature_verifier = JwsVerifierFn::from(|input: VerificationInput, key: &Jwk| match input.alg {
5457
JwsAlgorithm::EdDSA => ed25519::verify(input, key),
5558
other => unimplemented!("{other}"),
@@ -62,7 +65,5 @@ fn test_rfc8037_ed25519() {
6265
.unwrap();
6366

6467
assert_eq!(token, token_with_default);
65-
assert_eq!(token.protected, header);
66-
assert_eq!(token.claims, tv.payload.as_bytes());
6768
}
6869
}

identity_storage/Cargo.toml

+7-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ identity_did = { version = "=1.3.1", path = "../identity_did", default-features
2222
identity_document = { version = "=1.3.1", path = "../identity_document", default-features = false }
2323
identity_iota_core = { version = "=1.3.1", path = "../identity_iota_core", default-features = false, optional = true }
2424
identity_verification = { version = "=1.3.1", path = "../identity_verification", default-features = false }
25-
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"], optional = true }
25+
iota-crypto = { version = "0.23.2", default-features = false, features = ["ed25519", "random"], optional = true }
2626
json-proof-token = { workspace = true, optional = true }
2727
rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"], optional = true }
2828
seahash = { version = "4.1.0", default-features = false }
@@ -47,7 +47,12 @@ send-sync-storage = []
4747
# Implements the JwkStorageDocumentExt trait for IotaDocument
4848
iota-document = ["dep:identity_iota_core"]
4949
# Enables JSON Proof Token & BBS+ related features
50-
jpt-bbs-plus = ["identity_credential/jpt-bbs-plus", "dep:zkryptium", "dep:bls12_381_plus", "dep:json-proof-token"]
50+
jpt-bbs-plus = [
51+
"identity_credential/jpt-bbs-plus",
52+
"dep:zkryptium",
53+
"dep:bls12_381_plus",
54+
"dep:json-proof-token",
55+
]
5156

5257
[lints]
5358
workspace = true

identity_stronghold/Cargo.toml

+7-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ async-trait = { version = "0.1.64", default-features = false }
1616
bls12_381_plus = { workspace = true, optional = true }
1717
identity_storage = { version = "=1.3.1", path = "../identity_storage", default-features = false }
1818
identity_verification = { version = "=1.3.1", path = "../identity_verification", default-features = false }
19-
iota-crypto = { version = "0.23", default-features = false, features = ["ed25519"] }
19+
iota-crypto = { version = "0.23.2", default-features = false, features = ["ed25519"] }
2020
iota-sdk = { version = "1.1.5", default-features = false, features = ["client", "stronghold"] }
2121
iota_stronghold = { version = "2.1.0", default-features = false }
2222
json-proof-token = { workspace = true, optional = true }
@@ -38,7 +38,12 @@ zkryptium = { workspace = true }
3838
default = []
3939
# Enables `Send` + `Sync` bounds for the trait implementations on `StrongholdStorage`.
4040
send-sync-storage = ["identity_storage/send-sync-storage"]
41-
bbs-plus = ["identity_storage/jpt-bbs-plus", "dep:zkryptium", "dep:bls12_381_plus", "dep:json-proof-token"]
41+
bbs-plus = [
42+
"identity_storage/jpt-bbs-plus",
43+
"dep:zkryptium",
44+
"dep:bls12_381_plus",
45+
"dep:json-proof-token",
46+
]
4247

4348
[lints]
4449
workspace = true

0 commit comments

Comments
 (0)