From f597ceed0d13f1ea649bcbf88d1756480f0c3444 Mon Sep 17 00:00:00 2001 From: Frederik Rothenberger Date: Fri, 17 Feb 2023 10:26:37 +0100 Subject: [PATCH] Collect origin information on device registration (#1243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds origin information to newly registered devices, which can be used to facilitate the upcoming domain migration. * 🤖 npm run generate auto-update * Add origin to front-end calls * Fix tests --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- src/archive/archive.did | 2 + src/archive/tests/tests.rs | 24 ++- src/canister_tests/src/api/archive.rs | 146 +++++++++++++++++- src/canister_tests/src/framework.rs | 8 + .../generated/internet_identity_idl.js | 1 + .../generated/internet_identity_types.d.ts | 1 + src/frontend/src/showcase.ts | 4 + src/frontend/src/utils/iiConnection.ts | 3 + src/internet_identity/internet_identity.did | 1 + src/internet_identity/src/archive.rs | 5 + src/internet_identity/src/storage/anchor.rs | 25 ++- .../src/storage/anchor/tests.rs | 14 +- src/internet_identity/src/storage/tests.rs | 5 +- .../tests/archive_integration_tests_pull.rs | 2 + .../tests/archive_integration_tests_push.rs | 2 + src/internet_identity/tests/tests.rs | 20 ++- .../src/archive.rs | 3 + src/internet_identity_interface/src/lib.rs | 1 + 18 files changed, 249 insertions(+), 18 deletions(-) diff --git a/src/archive/archive.did b/src/archive/archive.did index 28a2b1b9b5..81c785a6aa 100644 --- a/src/archive/archive.did +++ b/src/archive/archive.did @@ -56,6 +56,7 @@ type DeviceDataWithoutAlias = record { purpose: Purpose; key_type: KeyType; protection: DeviceProtection; + origin: opt text; }; type DeviceDataUpdate = record { @@ -64,6 +65,7 @@ type DeviceDataUpdate = record { purpose: opt Purpose; key_type: opt KeyType; protection: opt DeviceProtection; + origin: opt opt text; }; type Private = variant { diff --git a/src/archive/tests/tests.rs b/src/archive/tests/tests.rs index f75e505a3c..613e8d5a53 100644 --- a/src/archive/tests/tests.rs +++ b/src/archive/tests/tests.rs @@ -5,6 +5,7 @@ use ic_test_state_machine_client::ErrorCode::CanisterCalledTrap; use internet_identity_interface::archive::*; use internet_identity_interface::*; use regex::Regex; +use serde_bytes::ByteBuf; use std::time::{Duration, SystemTime}; /// Verifies that the canister can be installed successfully. @@ -113,10 +114,16 @@ mod rollback_tests { // rollback upgrade_archive_canister(&env, canister_id, ARCHIVE_WASM_PREVIOUS.clone()); - let logs = api::get_entries(&env, canister_id, None, None)?; + let logs = api::compat::get_entries(&env, canister_id, None, None)?; assert_eq!(logs.entries.len(), 2); - assert_eq!(logs.entries.get(0).unwrap().as_ref().unwrap(), &entry1); - assert_eq!(logs.entries.get(1).unwrap().as_ref().unwrap(), &entry2); + assert_eq!( + logs.entries.get(0).unwrap().as_ref().unwrap(), + &api::compat::Entry::from(entry1) + ); + assert_eq!( + logs.entries.get(1).unwrap().as_ref().unwrap(), + &api::compat::Entry::from(entry2) + ); Ok(()) } } @@ -729,6 +736,7 @@ mod stable_memory_tests { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }, }, timestamp: TIMESTAMP, @@ -743,7 +751,14 @@ mod stable_memory_tests { let add_entry = Entry { anchor: ANCHOR, operation: Operation::AddDevice { - device: DeviceDataWithoutAlias::from(device_data_2()), + device: DeviceDataWithoutAlias { + pubkey: ByteBuf::from(PUBKEY_2), + credential_id: None, + purpose: Purpose::Authentication, + key_type: KeyType::Unknown, + protection: DeviceProtection::Unprotected, + origin: None, + }, }, timestamp: TIMESTAMP, caller: principal_1(), @@ -764,6 +779,7 @@ mod stable_memory_tests { purpose: Some(Purpose::Recovery), key_type: None, protection: None, + origin: None, }, }, timestamp: TIMESTAMP, diff --git a/src/canister_tests/src/api/archive.rs b/src/canister_tests/src/api/archive.rs index 331ecd6a85..693d93011e 100644 --- a/src/canister_tests/src/api/archive.rs +++ b/src/canister_tests/src/api/archive.rs @@ -53,4 +53,148 @@ pub fn status(env: &StateMachine, canister_id: CanisterId) -> Result for Entry { + fn from(value: archive::Entry) -> Self { + Self { + anchor: value.anchor, + operation: Operation::from(value.operation), + timestamp: value.timestamp, + caller: value.caller, + sequence_number: value.sequence_number, + } + } + } + + #[derive(Eq, PartialEq, Clone, Debug, CandidType, Deserialize)] + pub enum Operation { + #[serde(rename = "register_anchor")] + RegisterAnchor { device: DeviceDataWithoutAlias }, + #[serde(rename = "add_device")] + AddDevice { device: DeviceDataWithoutAlias }, + #[serde(rename = "update_device")] + UpdateDevice { + device: PublicKey, + new_values: DeviceDataUpdate, + }, + #[serde(rename = "replace_device")] + ReplaceDevice { + old_device: PublicKey, + new_device: DeviceDataWithoutAlias, + }, + #[serde(rename = "remove_device")] + RemoveDevice { device: PublicKey }, + } + + impl From for Operation { + fn from(value: archive::Operation) -> Self { + match value { + archive::Operation::RegisterAnchor { device } => Operation::RegisterAnchor { + device: DeviceDataWithoutAlias::from(device), + }, + archive::Operation::AddDevice { device } => Operation::AddDevice { + device: DeviceDataWithoutAlias::from(device), + }, + archive::Operation::UpdateDevice { device, new_values } => { + Operation::UpdateDevice { + device, + new_values: DeviceDataUpdate::from(new_values), + } + } + archive::Operation::ReplaceDevice { + old_device, + new_device, + } => Operation::ReplaceDevice { + old_device, + new_device: DeviceDataWithoutAlias::from(new_device), + }, + archive::Operation::RemoveDevice { device } => Operation::RemoveDevice { device }, + } + } + } + + #[derive(Eq, PartialEq, Clone, Debug, CandidType, Deserialize)] + pub struct DeviceDataWithoutAlias { + pub pubkey: DeviceKey, + pub credential_id: Option, + pub purpose: Purpose, + pub key_type: KeyType, + pub protection: DeviceProtection, + } + + impl From for DeviceDataWithoutAlias { + fn from(value: archive::DeviceDataWithoutAlias) -> Self { + Self { + pubkey: value.pubkey, + credential_id: value.credential_id, + purpose: value.purpose, + key_type: value.key_type, + protection: value.protection, + } + } + } + + impl From for DeviceDataWithoutAlias { + fn from(device_data: DeviceData) -> Self { + Self { + pubkey: device_data.pubkey, + credential_id: device_data.credential_id, + purpose: device_data.purpose, + key_type: device_data.key_type, + protection: device_data.protection, + } + } + } + + // If present, the attribute has been changed to the value given. + // Does not include the pubkey because it cannot be changed. + #[derive(Eq, PartialEq, Clone, Debug, CandidType, Deserialize)] + pub struct DeviceDataUpdate { + pub alias: Option, + pub credential_id: Option, + pub purpose: Option, + pub key_type: Option, + pub protection: Option, + } + + impl From for DeviceDataUpdate { + fn from(value: archive::DeviceDataUpdate) -> Self { + Self { + alias: value.alias, + credential_id: value.credential_id, + purpose: value.purpose, + key_type: value.key_type, + protection: value.protection, + } + } + } + + #[derive(Clone, Debug, CandidType, Deserialize)] + pub struct Entries { + // make this a vec of options to keep Entry extensible + pub entries: Vec>, + } + + pub fn get_entries( + env: &StateMachine, + canister_id: CanisterId, + idx: Option, + limit: Option, + ) -> Result { + query_candid(env, canister_id, "get_entries", (idx, limit)).map(|(x,)| x) + } +} diff --git a/src/canister_tests/src/framework.rs b/src/canister_tests/src/framework.rs index e170120d64..274c46d545 100644 --- a/src/canister_tests/src/framework.rs +++ b/src/canister_tests/src/framework.rs @@ -259,6 +259,7 @@ pub fn device_data_1() -> DeviceData { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: Some("https://identity.internetcomputer.org".to_string()), } } @@ -270,6 +271,7 @@ pub fn device_data_2() -> DeviceData { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: Some("https://identity.ic0.app".to_string()), } } @@ -281,6 +283,7 @@ pub fn max_size_device() -> DeviceData { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: Some("https://rdmx6-jaaaa-aaaaa-aaadq-cai.foobar.icp0.io".to_string()), } } @@ -292,6 +295,7 @@ pub fn recovery_device_data_1() -> DeviceData { purpose: Purpose::Recovery, key_type: KeyType::SeedPhrase, protection: DeviceProtection::Unprotected, + origin: None, } } @@ -303,6 +307,7 @@ pub fn recovery_device_data_2() -> DeviceData { purpose: Purpose::Recovery, key_type: KeyType::SeedPhrase, protection: DeviceProtection::Unprotected, + origin: None, } } @@ -526,6 +531,7 @@ pub fn log_entry_1() -> Entry { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }, }, sequence_number: 0, @@ -544,6 +550,7 @@ pub fn log_entry_2() -> Entry { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: Some("foo.bar".to_string()), }, }, sequence_number: 1, @@ -563,6 +570,7 @@ pub fn log_entry(idx: u64, timestamp: u64, anchor: AnchorNumber) -> Entry { purpose: Some(Purpose::Authentication), key_type: None, protection: Some(DeviceProtection::Unprotected), + origin: Some(Some("foo.bar".to_string())), }, }, sequence_number: idx, diff --git a/src/frontend/generated/internet_identity_idl.js b/src/frontend/generated/internet_identity_idl.js index 2c408e9a57..057e1d1600 100644 --- a/src/frontend/generated/internet_identity_idl.js +++ b/src/frontend/generated/internet_identity_idl.js @@ -34,6 +34,7 @@ export const idlFactory = ({ IDL }) => { const CredentialId = IDL.Vec(IDL.Nat8); const DeviceData = IDL.Record({ 'alias' : IDL.Text, + 'origin' : IDL.Opt(IDL.Text), 'protection' : DeviceProtection, 'pubkey' : DeviceKey, 'key_type' : KeyType, diff --git a/src/frontend/generated/internet_identity_types.d.ts b/src/frontend/generated/internet_identity_types.d.ts index 3cf41c33e7..de581fe983 100644 --- a/src/frontend/generated/internet_identity_types.d.ts +++ b/src/frontend/generated/internet_identity_types.d.ts @@ -43,6 +43,7 @@ export type DeployArchiveResult = { 'creation_in_progress' : null } | { 'failed' : string }; export interface DeviceData { 'alias' : string, + 'origin' : [] | [string], 'protection' : DeviceProtection, 'pubkey' : DeviceKey, 'key_type' : KeyType, diff --git a/src/frontend/src/showcase.ts b/src/frontend/src/showcase.ts index d7fb7179d2..1d1c3d4a8b 100644 --- a/src/frontend/src/showcase.ts +++ b/src/frontend/src/showcase.ts @@ -58,6 +58,7 @@ const recoveryPhrase: DeviceData = { key_type: { seed_phrase: null }, purpose: { recovery: null }, credential_id: [], + origin: [], }; const recoveryPhraseText = @@ -70,6 +71,7 @@ const recoveryDevice: DeviceData = { key_type: { unknown: null }, purpose: { recovery: null }, credential_id: [], + origin: [], }; const simpleDevices: [DeviceData, DeviceData] = [ @@ -80,6 +82,7 @@ const simpleDevices: [DeviceData, DeviceData] = [ key_type: { unknown: null }, purpose: { authentication: null }, credential_id: [], + origin: [], }, { @@ -89,6 +92,7 @@ const simpleDevices: [DeviceData, DeviceData] = [ key_type: { unknown: null }, purpose: { authentication: null }, credential_id: [], + origin: [], }, ]; diff --git a/src/frontend/src/utils/iiConnection.ts b/src/frontend/src/utils/iiConnection.ts index 223d529962..e204bb1ecb 100644 --- a/src/frontend/src/utils/iiConnection.ts +++ b/src/frontend/src/utils/iiConnection.ts @@ -142,6 +142,7 @@ export class Connection { key_type: { unknown: null }, purpose: { authentication: null }, protection: { unprotected: null }, + origin: window?.origin === undefined ? [] : [window.origin], }, challengeResult ); @@ -380,6 +381,7 @@ export class Connection { key_type: keyType, purpose, protection: { unprotected: null }, + origin: window?.origin === undefined ? [] : [window.origin], }); }; @@ -496,6 +498,7 @@ export class AuthenticatedConnection extends Connection { key_type: keyType, purpose, protection, + origin: window?.origin === undefined ? [] : [window.origin], }); }; diff --git a/src/internet_identity/internet_identity.did b/src/internet_identity/internet_identity.did index 39e0385044..fc7d2c4315 100644 --- a/src/internet_identity/internet_identity.did +++ b/src/internet_identity/internet_identity.did @@ -72,6 +72,7 @@ type DeviceData = record { purpose: Purpose; key_type: KeyType; protection: DeviceProtection; + origin: opt text; }; type RegisterResponse = variant { diff --git a/src/internet_identity/src/archive.rs b/src/internet_identity/src/archive.rs index 76d11012a2..f339bd3188 100644 --- a/src/internet_identity/src/archive.rs +++ b/src/internet_identity/src/archive.rs @@ -430,5 +430,10 @@ pub fn device_diff(old: &Device, new: &Device) -> DeviceDataUpdate { } else { Some(new.protection.clone()) }, + origin: if old.origin == new.origin { + None + } else { + Some(new.origin.clone()) + }, } } diff --git a/src/internet_identity/src/storage/anchor.rs b/src/internet_identity/src/storage/anchor.rs index 9ec1bd08d9..c4b9052451 100644 --- a/src/internet_identity/src/storage/anchor.rs +++ b/src/internet_identity/src/storage/anchor.rs @@ -24,6 +24,7 @@ impl From for Device { purpose: device_data.purpose, key_type: device_data.key_type, protection: device_data.protection, + origin: device_data.origin, } } } @@ -37,6 +38,7 @@ impl From for DeviceData { purpose: device.purpose, key_type: device.key_type, protection: device.protection, + origin: device.origin, } } } @@ -49,6 +51,7 @@ impl From for DeviceDataWithoutAlias { purpose: device_data.purpose, key_type: device_data.key_type, protection: device_data.protection, + origin: device_data.origin, } } } @@ -150,6 +153,7 @@ pub struct Device { pub purpose: Purpose, pub key_type: KeyType, pub protection: DeviceProtection, + pub origin: Option, } impl Device { @@ -157,6 +161,7 @@ impl Device { self.alias.len() + self.pubkey.len() + self.credential_id.as_ref().map(|id| id.len()).unwrap_or(0) + + self.origin.as_ref().map(|origin| origin.len()).unwrap_or(0) } } @@ -211,9 +216,9 @@ fn check_anchor_invariants(devices: &Vec<&Device>) -> Result<(), AnchorError> { /// or change anchors in the future. /// The value 2048 was chosen because it is the max anchor size before the stable memory migration. /// This means that all pre-existing anchors are below this limit. And after the migration, the - /// candid encoded `vec devices` will stay far below 4KB in size (testing showed anchors of up to - /// 2259 bytes). - const VARIABLE_FIELDS_LIMIT: usize = 2048; + /// candid encoded `vec devices` will stay far below 4KB in size (testing showed anchors of + /// ~2500 bytes). + const VARIABLE_FIELDS_LIMIT: usize = 2348; if devices.len() > MAX_DEVICES_PER_ANCHOR { return Err(AnchorError::TooManyDevices { @@ -266,6 +271,7 @@ fn check_device_invariants(device: &Device) -> Result<(), AnchorError> { } fn check_device_limits(device: &Device) -> Result<(), AnchorError> { + const ORIGIN_LEN_LIMIT: usize = 50; const ALIAS_LEN_LIMIT: usize = 64; const PK_LEN_LIMIT: usize = 300; const CREDENTIAL_ID_LEN_LIMIT: usize = 200; @@ -300,6 +306,19 @@ fn check_device_limits(device: &Device) -> Result<(), AnchorError> { limit: CREDENTIAL_ID_LEN_LIMIT, }); } + + let n = device + .origin + .as_ref() + .map(|bytes| bytes.len()) + .unwrap_or_default(); + if n > ORIGIN_LEN_LIMIT { + return Err(AnchorError::DeviceLimitExceeded { + field: "origin".to_string(), + length: n, + limit: ORIGIN_LEN_LIMIT, + }); + } Ok(()) } diff --git a/src/internet_identity/src/storage/anchor/tests.rs b/src/internet_identity/src/storage/anchor/tests.rs index 2f7676be79..b28d28c4f8 100644 --- a/src/internet_identity/src/storage/anchor/tests.rs +++ b/src/internet_identity/src/storage/anchor/tests.rs @@ -114,16 +114,17 @@ fn should_enforce_cumulative_device_limit() { for i in 0..4 { anchor.add_device(large_device(i)).unwrap(); } - let minimal_device = Device { + let device = Device { pubkey: Default::default(), - alias: "a".to_string(), - credential_id: None, + alias: "a".repeat(64), + credential_id: Some(ByteBuf::from([0; 100])), purpose: Purpose::Recovery, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; - let result = anchor.add_device(minimal_device); + let result = anchor.add_device(device); assert!(matches!( result, @@ -159,6 +160,7 @@ fn should_allow_protection_only_on_recovery_phrases() { purpose: Purpose::Recovery, key_type: KeyType::Unknown, protection: DeviceProtection::Protected, + origin: None, }); assert!(matches!( @@ -319,6 +321,7 @@ fn sample_device() -> Device { purpose: Purpose::Authentication, key_type: KeyType::Platform, protection: DeviceProtection::Unprotected, + origin: Some("https://fooo.bar".to_string()), } } @@ -330,6 +333,7 @@ fn device(n: u8) -> Device { purpose: Purpose::Authentication, key_type: KeyType::Platform, protection: DeviceProtection::Unprotected, + origin: Some(format!("https://foo{n}.bar")), } } @@ -342,6 +346,7 @@ fn large_device(n: u8) -> Device { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: Some("https://rdmx6-jaaaa-aaaaa-aaadq-cai.foobar.icp0.io".to_string()), } } @@ -353,6 +358,7 @@ fn recovery_phrase(n: u8, protection: DeviceProtection) -> Device { purpose: Purpose::Recovery, key_type: KeyType::SeedPhrase, protection, + origin: None, } } diff --git a/src/internet_identity/src/storage/tests.rs b/src/internet_identity/src/storage/tests.rs index 1f6c3d4181..9a38f2428c 100644 --- a/src/internet_identity/src/storage/tests.rs +++ b/src/internet_identity/src/storage/tests.rs @@ -68,7 +68,7 @@ fn should_read_previous_write() { #[test] fn should_serialize_first_record() { - const EXPECTED_LENGTH: usize = 191; + const EXPECTED_LENGTH: usize = 200; let memory = VectorMemory::default(); let mut storage = Storage::new((123, 456), memory.clone()); let (anchor_number, mut anchor) = storage.allocate_anchor().unwrap(); @@ -85,7 +85,7 @@ fn should_serialize_first_record() { #[test] fn should_serialize_subsequent_record_to_expected_memory_location() { - const EXPECTED_LENGTH: usize = 191; + const EXPECTED_LENGTH: usize = 200; const EXPECTED_RECORD_OFFSET: u64 = 409_600; // 100 * max anchor size let memory = VectorMemory::default(); let mut storage = Storage::new((123, 456), memory.clone()); @@ -327,6 +327,7 @@ fn sample_device() -> Device { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, } } diff --git a/src/internet_identity/tests/archive_integration_tests_pull.rs b/src/internet_identity/tests/archive_integration_tests_pull.rs index a84612e459..76cbc9f5d3 100644 --- a/src/internet_identity/tests/archive_integration_tests_pull.rs +++ b/src/internet_identity/tests/archive_integration_tests_pull.rs @@ -268,6 +268,7 @@ mod pull_entries_tests { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: device_data_1().origin, }, }, timestamp, @@ -303,6 +304,7 @@ mod pull_entries_tests { purpose: Some(Purpose::Recovery), key_type: None, protection: None, + origin: None, }, }, timestamp, diff --git a/src/internet_identity/tests/archive_integration_tests_push.rs b/src/internet_identity/tests/archive_integration_tests_push.rs index 37c0c9d618..80b97e3cc7 100644 --- a/src/internet_identity/tests/archive_integration_tests_push.rs +++ b/src/internet_identity/tests/archive_integration_tests_push.rs @@ -214,6 +214,7 @@ fn should_record_anchor_operations() -> Result<(), CallError> { purpose: Purpose::Authentication, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: device_data_1().origin, }, }, timestamp, @@ -249,6 +250,7 @@ fn should_record_anchor_operations() -> Result<(), CallError> { purpose: Some(Purpose::Recovery), key_type: None, protection: None, + origin: None, }, }, timestamp, diff --git a/src/internet_identity/tests/tests.rs b/src/internet_identity/tests/tests.rs index 3f32a615e5..11b6b5242d 100644 --- a/src/internet_identity/tests/tests.rs +++ b/src/internet_identity/tests/tests.rs @@ -50,7 +50,9 @@ mod upgrade_tests { let retrieved_device_data = api::lookup(&env, canister_id, user_number).expect("lookup failed"); - assert_eq!(retrieved_device_data, vec![device_data_1()]); + let mut device_no_origin = device_data_1(); + device_no_origin.origin = None; + assert_eq!(retrieved_device_data, vec![device_no_origin]); } /// Test to verify that anchors number range cannot be changed on upgrade. @@ -166,7 +168,9 @@ mod rollback_tests { // use anchor let devices = api::lookup(&env, canister_id, user_number)?; - assert_eq!(devices, [device_data_1()]); + let mut device_without_origin = device_data_1(); + device_without_origin.origin = None; + assert_eq!(devices, [device_without_origin]); let (user_key, _) = api::prepare_delegation( &env, @@ -425,6 +429,7 @@ mod stable_memory_tests { credential_id: Some(ByteBuf::from(hex::decode(CREDENTIAL_ID_1).unwrap())), key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; let device2 = DeviceData { pubkey: ByteBuf::from(hex::decode(PUB_KEY_2).unwrap()), @@ -433,6 +438,7 @@ mod stable_memory_tests { credential_id: Some(ByteBuf::from(hex::decode(CREDENTIAL_ID_2).unwrap())), key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; let device3 = DeviceData { pubkey: ByteBuf::from(hex::decode(PUB_KEY_3).unwrap()), @@ -441,6 +447,7 @@ mod stable_memory_tests { credential_id: Some(ByteBuf::from(hex::decode(CREDENTIAL_ID_3).unwrap())), key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; let device4 = DeviceData { pubkey: ByteBuf::from(hex::decode(PUB_KEY_4).unwrap()), @@ -449,6 +456,7 @@ mod stable_memory_tests { credential_id: Some(ByteBuf::from(hex::decode(CREDENTIAL_ID_4).unwrap())), key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; let device5 = DeviceData { pubkey: ByteBuf::from(hex::decode(PUB_KEY_5).unwrap()), @@ -457,6 +465,7 @@ mod stable_memory_tests { credential_id: None, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; let device6 = DeviceData { pubkey: ByteBuf::from(hex::decode(PUB_KEY_6).unwrap()), @@ -465,6 +474,7 @@ mod stable_memory_tests { credential_id: None, key_type: KeyType::Unknown, protection: DeviceProtection::Unprotected, + origin: None, }; (device1, device2, device3, device4, device5, device6) } @@ -1273,6 +1283,8 @@ mod device_management_tests { let env = env(); let canister_id = install_ii_canister(&env, II_WASM_PREVIOUS.clone()); let user_number = flows::register_anchor(&env, canister_id); + let mut device_no_origin = device_data_2(); + device_no_origin.origin = None; api::add( &env, @@ -1282,7 +1294,7 @@ mod device_management_tests { device_data_2(), )?; let devices = api::lookup(&env, canister_id, user_number)?; - assert!(devices.iter().any(|device| device == &device_data_2())); + assert!(devices.iter().any(|device| device == &device_no_origin)); upgrade_ii_canister(&env, canister_id, II_WASM.clone()); @@ -1296,7 +1308,7 @@ mod device_management_tests { let devices = api::lookup(&env, canister_id, user_number)?; assert_eq!(devices.len(), 1); - assert!(!devices.iter().any(|device| device == &device_data_2())); + assert!(!devices.iter().any(|device| device == &device_no_origin)); Ok(()) } diff --git a/src/internet_identity_interface/src/archive.rs b/src/internet_identity_interface/src/archive.rs index 90b31c6fcf..067e336368 100644 --- a/src/internet_identity_interface/src/archive.rs +++ b/src/internet_identity_interface/src/archive.rs @@ -44,6 +44,7 @@ pub struct DeviceDataWithoutAlias { pub purpose: Purpose, pub key_type: KeyType, pub protection: DeviceProtection, + pub origin: Option, } impl From for DeviceDataWithoutAlias { @@ -54,6 +55,7 @@ impl From for DeviceDataWithoutAlias { purpose: device_data.purpose, key_type: device_data.key_type, protection: device_data.protection, + origin: device_data.origin, } } } @@ -67,6 +69,7 @@ pub struct DeviceDataUpdate { pub purpose: Option, pub key_type: Option, pub protection: Option, + pub origin: Option>, } // Placeholder for information that has been hidden for privacy reasons. diff --git a/src/internet_identity_interface/src/lib.rs b/src/internet_identity_interface/src/lib.rs index 209a22001b..a2706cdb07 100644 --- a/src/internet_identity_interface/src/lib.rs +++ b/src/internet_identity_interface/src/lib.rs @@ -27,6 +27,7 @@ pub struct DeviceData { pub purpose: Purpose, pub key_type: KeyType, pub protection: DeviceProtection, + pub origin: Option, } #[derive(Eq, PartialEq, Clone, Debug, CandidType, Deserialize)]