Removed devices: DeviceRevoked, identity reset and one retry with the ticket
kv-sync: SyncError::DeviceRevoked for 403 device_revoked (drops the session); the test server answers it after OPAQUE (before the ticket) and for valid signatures by a revoked device's key. kv-ffi: CoreError::DeviceRevoked; the foreign DeviceSigner gains reset() (new key and id). On device_revoked the core resets the identity, forgets the session and the kept OPAQUE input (no silent re-enrolment) and keeps the vault data; a login carrying a ticket retries once as the new device. reset_device_identity() runs the reset on demand. Signed calls (sync, devices, tickets, join) reset too. kv-wasm: DeviceRevoked; the browser binding replaces the WebCrypto key and id in IndexedDB (same name and platform), loginWithSetup retries once with a ticket; resetDeviceIdentity(). Tests: end to end revoked -> reset -> re-enrol with the same ticket (kv-ffi and web core), no-ticket path, in-browser IndexedDB reset. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -439,6 +439,23 @@ async fn auth_errors() {
|
||||
// The account endpoint gives a new device what it needs to unlock.
|
||||
let info = c.api.account().await.unwrap();
|
||||
assert_eq!(info.sig_pk, a.keyset.sig_public().to_vec());
|
||||
|
||||
// Removed device (docs/03 "Removed devices"): its signed calls and its logins say DeviceRevoked, but only with
|
||||
// the right password, and the refused login leaves the ticket unused.
|
||||
assert!(a.login().await != LoginOutcome::PendingApproval);
|
||||
a.api.revoke_device(c.signer.device_id()).await.unwrap();
|
||||
assert!(matches!(c.sync().await, Err(SyncError::DeviceRevoked)));
|
||||
assert!(c.api.session().is_none());
|
||||
let err = c.api.login(c.keyset.account_id, &[0u8; 32], enroll(&c.signer), None).await.unwrap_err();
|
||||
assert!(matches!(err, SyncError::BadCredentials), "{err}");
|
||||
let ticket = a.api.create_ticket(None).await.unwrap();
|
||||
let err = c
|
||||
.api
|
||||
.login_with_ticket(c.keyset.account_id, &AUTH, enroll(&c.signer), None, Some(ticket.ticket.clone()))
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, SyncError::DeviceRevoked), "{err}");
|
||||
assert_eq!(a.api.tickets().await.unwrap().len(), 1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- TLS pinning
|
||||
|
||||
Reference in New Issue
Block a user