Skip to content

Commit

Permalink
Add Unsigned Identity Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
neekolas committed Apr 7, 2024
1 parent 4068715 commit 63ef357
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 30 deletions.
11 changes: 6 additions & 5 deletions xmtp_id/src/associations/association_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ impl IdentityAction for CreateInbox {

/// AddAssociation Action
pub struct AddAssociation {
pub client_timestamp_ns: u64,
pub new_member_signature: Box<dyn Signature>,
pub new_member_identifier: MemberIdentifier,
pub existing_member_signature: Box<dyn Signature>,
Expand Down Expand Up @@ -187,7 +186,6 @@ impl IdentityAction for AddAssociation {

/// RevokeAssociation Action
pub struct RevokeAssociation {
pub client_timestamp_ns: u64,
pub recovery_address_signature: Box<dyn Signature>,
pub revoked_member: MemberIdentifier,
}
Expand Down Expand Up @@ -240,7 +238,6 @@ impl IdentityAction for RevokeAssociation {

/// ChangeRecoveryAddress Action
pub struct ChangeRecoveryAddress {
pub client_timestamp_ns: u64,
pub recovery_address_signature: Box<dyn Signature>,
pub new_recovery_address: String,
}
Expand Down Expand Up @@ -306,12 +303,16 @@ impl IdentityAction for Action {

/// An `IdentityUpdate` contains one or more Actions that can be applied to the AssociationState
pub struct IdentityUpdate {
pub client_timestamp_ns: u64,
pub actions: Vec<Action>,
}

impl IdentityUpdate {
pub fn new(actions: Vec<Action>) -> Self {
Self { actions }
pub fn new(actions: Vec<Action>, client_timestamp_ns: u64) -> Self {
Self {
actions,
client_timestamp_ns,
}
}
}

Expand Down
64 changes: 39 additions & 25 deletions xmtp_id/src/associations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod signature;
mod state;
#[cfg(test)]
mod test_utils;
mod unsigned_actions;

pub use self::association_log::*;
pub use self::member::{Member, MemberIdentifier, MemberKind};
Expand Down Expand Up @@ -46,6 +47,12 @@ mod tests {
signature_nonce: u64,
}

impl IdentityUpdate {
pub fn new_test(actions: Vec<Action>) -> Self {
Self::new(actions, rand_u64())
}
}

impl MockSignature {
pub fn new_boxed(
is_valid: bool,
Expand Down Expand Up @@ -88,7 +95,6 @@ mod tests {
let existing_member = rand_string();
let new_member = rand_vec();
return Self {
client_timestamp_ns: rand_u64(),
existing_member_signature: MockSignature::new_boxed(
true,
existing_member.into(),
Expand Down Expand Up @@ -127,7 +133,6 @@ mod tests {
fn default() -> Self {
let signer = rand_string();
return Self {
client_timestamp_ns: rand_u64(),
recovery_address_signature: MockSignature::new_boxed(
true,
signer.into(),
Expand All @@ -141,7 +146,7 @@ mod tests {

fn new_test_inbox() -> AssociationState {
let create_request = CreateInbox::default();
let identity_update = IdentityUpdate::new(vec![Action::CreateInbox(create_request)]);
let identity_update = IdentityUpdate::new_test(vec![Action::CreateInbox(create_request)]);

get_state(vec![identity_update]).unwrap()
}
Expand All @@ -161,14 +166,14 @@ mod tests {
..Default::default()
});

apply_update(initial_state, IdentityUpdate::new(vec![update])).unwrap()
apply_update(initial_state, IdentityUpdate::new_test(vec![update])).unwrap()
}

#[test]
fn test_create_inbox() {
let create_request = CreateInbox::default();
let account_address = create_request.account_address.clone();
let identity_update = IdentityUpdate::new(vec![Action::CreateInbox(create_request)]);
let identity_update = IdentityUpdate::new_test(vec![Action::CreateInbox(create_request)]);
let state = get_state(vec![identity_update]).unwrap();
assert_eq!(state.members().len(), 1);

Expand Down Expand Up @@ -199,7 +204,8 @@ mod tests {
..Default::default()
});

let new_state = apply_update(initial_state, IdentityUpdate::new(vec![update])).unwrap();
let new_state =
apply_update(initial_state, IdentityUpdate::new_test(vec![update])).unwrap();
assert_eq!(new_state.members().len(), 2);

let new_member = new_state.get(&new_installation_identifier).unwrap();
Expand Down Expand Up @@ -228,7 +234,7 @@ mod tests {
new_member_identifier: new_member_identifier.clone(),
..Default::default()
};
let identity_update = IdentityUpdate::new(vec![
let identity_update = IdentityUpdate::new_test(vec![
Action::CreateInbox(create_action),
Action::AddAssociation(add_action),
]);
Expand All @@ -253,7 +259,7 @@ mod tests {
Some(0),
),
};
let state = get_state(vec![IdentityUpdate::new(vec![Action::CreateInbox(
let state = get_state(vec![IdentityUpdate::new_test(vec![Action::CreateInbox(
create_action,
)])])
.unwrap();
Expand All @@ -270,7 +276,7 @@ mod tests {
),
..Default::default()
});
let update_result = apply_update(state, IdentityUpdate::new(vec![update]));
let update_result = apply_update(state, IdentityUpdate::new_test(vec![update]));
assert!(update_result.is_err());
assert_eq!(update_result.err().unwrap(), AssociationError::Replay);
}
Expand Down Expand Up @@ -303,8 +309,11 @@ mod tests {
..Default::default()
});

let new_state = apply_update(initial_state, IdentityUpdate::new(vec![add_association]))
.expect("expected update to succeed");
let new_state = apply_update(
initial_state,
IdentityUpdate::new_test(vec![add_association]),
)
.expect("expected update to succeed");
assert_eq!(new_state.members().len(), 3);
}

Expand All @@ -317,7 +326,9 @@ mod tests {
..Default::default()
};

let state_result = get_state(vec![IdentityUpdate::new(vec![Action::CreateInbox(action)])]);
let state_result = get_state(vec![IdentityUpdate::new_test(vec![Action::CreateInbox(
action,
)])]);
assert!(state_result.is_err());
assert_eq!(
state_result.err().unwrap(),
Expand All @@ -338,7 +349,7 @@ mod tests {

let update_result = apply_update(
initial_state.clone(),
IdentityUpdate::new(vec![update_with_bad_existing_member]),
IdentityUpdate::new_test(vec![update_with_bad_existing_member]),
);
assert!(update_result.is_err());
assert_eq!(
Expand All @@ -359,7 +370,7 @@ mod tests {

let update_result_2 = apply_update(
initial_state,
IdentityUpdate::new(vec![update_with_bad_new_member]),
IdentityUpdate::new_test(vec![update_with_bad_new_member]),
);
assert!(update_result_2.is_err());
assert_eq!(
Expand All @@ -383,7 +394,7 @@ mod tests {
..Default::default()
});

let state_result = get_state(vec![IdentityUpdate::new(vec![create_request, update])]);
let state_result = get_state(vec![IdentityUpdate::new_test(vec![create_request, update])]);
assert!(state_result.is_err());
assert_eq!(
state_result.err().unwrap(),
Expand Down Expand Up @@ -415,7 +426,7 @@ mod tests {
..Default::default()
});

let update_result = apply_update(existing_state, IdentityUpdate::new(vec![update]));
let update_result = apply_update(existing_state, IdentityUpdate::new_test(vec![update]));
assert!(update_result.is_err());
assert_eq!(
update_result.err().unwrap(),
Expand Down Expand Up @@ -446,7 +457,7 @@ mod tests {
..Default::default()
});

let new_state = apply_update(initial_state, IdentityUpdate::new(vec![update]))
let new_state = apply_update(initial_state, IdentityUpdate::new_test(vec![update]))
.expect("expected update to succeed");
assert!(new_state.get(&installation_id).is_none());
}
Expand All @@ -473,7 +484,7 @@ mod tests {

let new_state = apply_update(
initial_state,
IdentityUpdate::new(vec![add_second_installation]),
IdentityUpdate::new_test(vec![add_second_installation]),
)
.expect("expected update to succeed");
assert_eq!(new_state.members().len(), 3);
Expand All @@ -490,7 +501,7 @@ mod tests {
});

// With this revocation the original wallet + both installations should be gone
let new_state = apply_update(new_state, IdentityUpdate::new(vec![revocation]))
let new_state = apply_update(new_state, IdentityUpdate::new_test(vec![revocation]))
.expect("expected update to succeed");
assert_eq!(new_state.members().len(), 0);
}
Expand Down Expand Up @@ -536,7 +547,7 @@ mod tests {

let state_after_remove = apply_update(
initial_state,
IdentityUpdate::new(vec![add_second_wallet, revoke_second_wallet]),
IdentityUpdate::new_test(vec![add_second_wallet, revoke_second_wallet]),
)
.expect("expected update to succeed");
assert_eq!(state_after_remove.members().len(), 1);
Expand All @@ -560,7 +571,7 @@ mod tests {

let state_after_re_add = apply_update(
state_after_remove,
IdentityUpdate::new(vec![add_second_wallet_again]),
IdentityUpdate::new_test(vec![add_second_wallet_again]),
)
.expect("expected update to succeed");
assert_eq!(state_after_re_add.members().len(), 2);
Expand All @@ -573,7 +584,6 @@ mod tests {
initial_state.recovery_address().clone().into();
let new_recovery_address = rand_string();
let update_recovery = Action::ChangeRecoveryAddress(ChangeRecoveryAddress {
client_timestamp_ns: rand_u64(),
new_recovery_address: new_recovery_address.clone(),
recovery_address_signature: MockSignature::new_boxed(
true,
Expand All @@ -583,8 +593,11 @@ mod tests {
),
});

let new_state = apply_update(initial_state, IdentityUpdate::new(vec![update_recovery]))
.expect("expected update to succeed");
let new_state = apply_update(
initial_state,
IdentityUpdate::new_test(vec![update_recovery]),
)
.expect("expected update to succeed");
assert_eq!(new_state.recovery_address(), &new_recovery_address);

let attempted_revoke = Action::RevokeAssociation(RevokeAssociation {
Expand All @@ -598,7 +611,8 @@ mod tests {
..Default::default()
});

let revoke_result = apply_update(new_state, IdentityUpdate::new(vec![attempted_revoke]));
let revoke_result =
apply_update(new_state, IdentityUpdate::new_test(vec![attempted_revoke]));
assert!(revoke_result.is_err());
assert_eq!(
revoke_result.err().unwrap(),
Expand Down
Loading

0 comments on commit 63ef357

Please sign in to comment.