Skip to content

Commit 19dea9d

Browse files
marc0oloclaude
andauthored
feat(vetkeys): adopt custom_value_endpoints in password_manager_with_metadata (Rust) (#1474)
* feat(vetkeys): adopt custom_value_endpoints in password_manager_with_metadata ic-vetkeys 0.9.0 adds a `custom_value_endpoints` form to `export_encrypted_maps_canister!`, closing dfinity/vetkeys#423. It generates the stable state, the `#[init]`/`#[post_upgrade]` hooks, the 8 control-plane endpoints and the `with_encrypted_maps`/`_mut` accessors, but none of the 7 endpoints that read or write encrypted values. That is exactly what `password_manager_with_metadata` needs: it keeps a backend-authoritative metadata row per encrypted value, so the raw `insert_encrypted_value`/`remove_encrypted_value` mutators must not be exposed — they would write a value with no metadata row and desync the two stores. The backend drops to 193 lines (from 343): the hand-written EncryptedMaps thread-local, lifecycle hooks, redundant key-name cell and 8 passthrough endpoints are all generated now, leaving only the three `*_with_metadata` endpoints written against the accessors. Also hardens the metadata read path: it looked metadata up by zipping two ordered iterators, guarded only by a `debug_assert_eq!` that compiles out in release, so a divergence would have silently paired a password with the wrong metadata. It now looks up per key and reports a missing row as an error. Domain separators renamed to match their examples: the metadata example used `password_manager_app` (which reads as if it belonged to the plain example) and the plain example used the library-flavoured `encrypted_maps_app`. They are now `password_manager_with_metadata_app` and `password_manager_app`. The separator is persisted in the EncryptedMaps config cell, so an upgraded canister keeps its old value; only fresh installs pick up the new names. Bumps ic-vetkeys 0.8.1 -> 0.9.0 across all five Rust examples that pin it. The release is additive, so basic_ibe, basic_bls_signing and basic_timelock_ibe are pin-only changes. Verified: all five build for wasm32-unknown-unknown; clippy -Dwarnings clean; backend.did byte-identical for every example with committed candid (so no frontend or icp.yaml change); local icp deploy e2e on both password managers — create/read/update/remove with metadata, vault sharing to a second identity, decryption after upgrade, and `insert_encrypted_value` correctly absent from the metadata canister (IC0536). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(vetkeys): make the Rust password manager file headers module docs Review feedback on #1474: the header comment describing the canister belongs in `//!` module docs rather than a plain `//` comment. Applied to both password managers so the pair stays consistent. The same suggestion for the comment above the macro invocation does not work: `///` there triggers rustc's `unused_doc_comment` warning, because rustdoc does not document macro invocations. Left as a plain comment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 15fb083 commit 19dea9d

8 files changed

Lines changed: 90 additions & 240 deletions

File tree

rust/vetkeys/basic_bls_signing/backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ getrandom = { version = "0.2", features = ["custom"] }
1818
ic-cdk = "0.20.1"
1919
ic-cdk-management-canister = "0.1.1"
2020
ic-stable-structures = "0.6.8"
21-
ic-vetkeys = "0.8.1"
21+
ic-vetkeys = "0.9.0"
2222
serde = "1.0.217"
2323
serde_bytes = "0.11.15"
2424
serde_cbor = "0.11.2"

rust/vetkeys/basic_ibe/backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ic-cdk = "0.20.1"
1818
ic-cdk-management-canister = "0.1.1"
1919
ic-dummy-getrandom-for-wasm = "0.1.0"
2020
ic-stable-structures = "0.6.8"
21-
ic-vetkeys = "0.8.1"
21+
ic-vetkeys = "0.9.0"
2222
serde = "1.0.217"
2323
serde_bytes = "0.11.15"
2424
serde_cbor = "0.11.2"

rust/vetkeys/basic_timelock_ibe/backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ic-cdk-management-canister = "0.1.1"
2020
ic-cdk-timers = "1.0.0"
2121
ic-dummy-getrandom-for-wasm = "0.1.0"
2222
ic-stable-structures = "0.6.8"
23-
ic-vetkeys = "0.8.1"
23+
ic-vetkeys = "0.9.0"
2424
serde = "1.0.217"
2525
serde_bytes = "0.11.15"
2626
serde_cbor = "0.11.2"

rust/vetkeys/password_manager/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ resolver = "2"
66
ic-cdk = "0.20.1"
77
ic-cdk-management-canister = "0.1.1"
88
ic-stable-structures = "0.7.0"
9-
ic-vetkeys = "0.8.1"
9+
ic-vetkeys = "0.9.0"
1010

1111
[profile.release]
1212
lto = true

rust/vetkeys/password_manager/backend/src/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// This canister is a thin wrapper around the `ic-vetkeys` EncryptedMaps
2-
// library. The canister owns the single MemoryManager and hands EncryptedMaps
3-
// the four Memory instances it needs; the `#[init]`/`#[post_upgrade]` and every
4-
// `#[query]`/`#[update]` endpoint are generated by the library macro, which
5-
// guarantees the exposed Candid matches what the `@icp-sdk/vetkeys` frontend
6-
// expects.
1+
//! This canister is a thin wrapper around the `ic-vetkeys` EncryptedMaps
2+
//! library. The canister owns the single MemoryManager and hands EncryptedMaps
3+
//! the four Memory instances it needs; the `#[init]`/`#[post_upgrade]` and every
4+
//! `#[query]`/`#[update]` endpoint are generated by the library macro, which
5+
//! guarantees the exposed Candid matches what the `@icp-sdk/vetkeys` frontend
6+
//! expects.
77
use ic_stable_structures::memory_manager::{MemoryId, MemoryManager, VirtualMemory};
88
use ic_stable_structures::DefaultMemoryImpl;
99
use std::cell::RefCell;
@@ -25,7 +25,7 @@ fn memory(id: u8) -> Memory {
2525
// it expects: config (which persists the domain separator and vetKD key id),
2626
// access control, shared keys, and the encrypted values.
2727
ic_vetkeys::export_encrypted_maps_canister!(
28-
"encrypted_maps_app",
28+
"password_manager_app",
2929
[memory(0), memory(1), memory(2), memory(3)],
3030
);
3131

rust/vetkeys/password_manager_with_metadata/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ icp network stop
5757

5858
An **Encrypted Maps**-enabled Rust canister that stores encrypted passwords together with unencrypted metadata (URLs, tags) in atomic update calls.
5959

60-
> **Note.** A plain Encrypted Maps canister can be generated in one line by the `ic_vetkeys::export_encrypted_maps_canister!(...)` macro — see the [`password_manager`](../password_manager/) example. This example deliberately hand-writes its canister instead: it maintains a custom invariant (every encrypted value has a matching metadata row) and exposes metadata-aware `*_with_metadata` methods. The macro emits a fixed endpoint set — including the plain `insert_encrypted_value`/`remove_encrypted_value` mutators that would bypass and desync the metadata — and offers no way to override or omit them, so it is not a fit here. Reach for the macro when the standard Encrypted Maps interface is enough, and hand-write (as here) when you need to layer your own state on top.
60+
> **Note.** A plain Encrypted Maps canister is generated in one line by the `ic_vetkeys::export_encrypted_maps_canister!(...)` macro — see the [`password_manager`](../password_manager/) example. This example uses the macro's `custom_value_endpoints` form instead, because it maintains a custom invariant: every encrypted value has a matching metadata row. That form generates the stable state, the `#[init]`/`#[post_upgrade]` hooks and the control-plane endpoints (vetKD keys, access control, map-name enumeration), but **none** of the endpoints that read or write encrypted values — so the plain `insert_encrypted_value`/`remove_encrypted_value` mutators, which would write a value with no metadata row and desync the two stores, are never exposed. The canister writes its own `*_with_metadata` endpoints on top of the `with_encrypted_maps`/`with_encrypted_maps_mut` accessors the macro emits, reusing the library's crypto and access-control logic. Reach for the plain form when the standard Encrypted Maps interface is enough, and for `custom_value_endpoints` when you layer your own state on each value.
6161

6262
### Frontend (`frontend/`)
6363

rust/vetkeys/password_manager_with_metadata/backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ ic-cdk = "0.20.1"
1818
ic-cdk-management-canister = "0.1.1"
1919
ic-dummy-getrandom-for-wasm = "0.1.0"
2020
ic-stable-structures = "0.7.2"
21-
ic-vetkeys = "0.8.1"
21+
ic-vetkeys = "0.9.0"
2222
serde = "1.0.217"
2323
serde_cbor = "0.11.2"

0 commit comments

Comments
 (0)