feat(base): the changes of SimpleLogin accounts' keys, each with the password and a fresh sign-in (ADR 0020, D20)
Every change takes the password's proof by its own proof key (the recovery phrase's for a lost password) and a SimpleLogin sign-in of the last ten minutes on the device (`KeysOwnerProof`, its attempt), as ADR 0017's take the password and a code. The sign-in is checked before the proof and taken with the change, so a wrong proof leaves it standing and each sign-in serves one change. - `keys.set(attempt, setup, handle?)`: the first keys of an account that SimpleLogin was added to (anonymous before, or signing in with GitHub or a code), with the handle where it has none; the sign-in alone, as there is no password to prove yet. - `keys.changePassword`, `keys.beginPhrase` and `keys.resetPassword` (a lost password, with the phrase): every other session ends, in every service, as ADR 0017's change has it. - `keys.setRecoveryKeys`: a new phrase. - `account.delete(keysProof)`: an account without SRP's verifier deletes itself with the proof and the sign-in; `requireOwnerToDelete` no longer asks such an account for SRP. - `newKeysPasswordDigest` on both sides, held to each other by a test; a challenge purpose of its own for the phrase's proof while signed in. - Members ask the register for all of it; `RemoteRegister` and the instance API carry the five new operations and the deletion's proof. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
090d901e92
commit
7c58d23424
1 changed files with 3163 additions and 78 deletions
|
|
@ -179,6 +179,54 @@ void main() {
|
|||
expect(authenticatorDigest(id), device.authenticatorDigest(id.toBytes()));
|
||||
});
|
||||
|
||||
test('digests a new password for keys without SRP as devices do, '
|
||||
'apart from what ADR 0017 digests', () {
|
||||
final password = KeysPassword(
|
||||
salt: ByteData.sublistView(Uint8List.fromList([1, 2, 3])),
|
||||
costs: PasswordCosts(
|
||||
algorithm: 'argon2id13',
|
||||
opsLimit: 3,
|
||||
memLimit: 64 * 1024 * 1024,
|
||||
),
|
||||
passwordProofKey: ByteData.sublistView(Uint8List.fromList([4, 5])),
|
||||
passwordKeys: WrappedKeys(
|
||||
nonce: ByteData.sublistView(Uint8List.fromList([6])),
|
||||
cipherText: ByteData.sublistView(Uint8List.fromList([7, 8, 9])),
|
||||
),
|
||||
);
|
||||
|
||||
final digest = newKeysPasswordDigest(password);
|
||||
|
||||
expect(
|
||||
digest,
|
||||
device.newKeysPasswordDigest(
|
||||
salt: [1, 2, 3],
|
||||
algorithm: 'argon2id13',
|
||||
opsLimit: 3,
|
||||
memLimit: 64 * 1024 * 1024,
|
||||
proofKey: [4, 5],
|
||||
keysNonce: [6],
|
||||
keysCipherText: [7, 8, 9],
|
||||
),
|
||||
);
|
||||
// The same bytes as a password that signs in: the label tells them
|
||||
// apart.
|
||||
expect(
|
||||
digest,
|
||||
isNot(
|
||||
device.newPasswordDigest(
|
||||
salt: [1, 2, 3],
|
||||
algorithm: 'argon2id13',
|
||||
opsLimit: 3,
|
||||
memLimit: 64 * 1024 * 1024,
|
||||
verifier: [4, 5],
|
||||
keysNonce: [6],
|
||||
keysCipherText: [7, 8, 9],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('writes base URLs as devices do', () {
|
||||
for (final url in [
|
||||
'https://learn.halkyon.eu/',
|
||||
|
|
|
|||
Loading…
Reference in a new issue