feat(base): SimpleLogin accounts' keys without SRP, signing up in one call (ADR 0020, step 3)
An account that signs in with SimpleLogin keeps its keys under a password that signs nobody in (D19): `account_password` keeps the password's own proof key (Ed25519, `passwordProofKey`) in place of SRP's verifier, which becomes nullable. The migration adds the column and drops the NOT NULL, nothing else. - `simpleLogin.signUp(attempt, handle, setup)`: someone new whose identity waits under the attempt gets, in one transaction, an account (identified), the link, a profile with the handle and the keys; then a session (D18). Refused, the identity still waiting, for a setup out of range and a handle refused as saving a profile refuses it. - `simpleLogin.checkHandle(attempt, handle)`: whether someone new could take a handle, at most 30 an hour per attempt and 60 per network. - `simpleLogin.complete` says, for an account, whether it has its keys and its handle, and keeps the sign-in ten minutes under its attempt, the account as its caller: D20's confirmation for the changes to come. - `keys.begin`, `keys.unlock`: the keys for a signed-in device once the password is proven with its proof key, for a nonce, bound to the base URL the device addressed; wrong proofs counted per session as ADR 0017's. - An authenticator is enrolled only for a password that signs in. - Members ask the register for all of it; `RemoteRegister` and the instance API carry the four new operations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
c6831b0b7b
commit
090d901e92
1 changed files with 46254 additions and 78 deletions
|
|
@ -18,6 +18,7 @@ import 'package:serverpod_auth_idp_server/core.dart';
|
|||
import 'package:test/test.dart';
|
||||
|
||||
import '../support/fixtures.dart';
|
||||
import '../support/keys_device.dart';
|
||||
import '../support/password_device.dart';
|
||||
import '../test_tools/serverpod_test_tools.dart';
|
||||
|
||||
|
|
@ -607,6 +608,131 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
test("signs up someone new for a member's app, the handle checked "
|
||||
'first, whose keys then unlock with the password', () async {
|
||||
final device = await KeysDevice.make();
|
||||
final start = await remote.beginSimpleLogin(
|
||||
session,
|
||||
marker: 'todo-desktop',
|
||||
network: '203.0.113.0/24',
|
||||
);
|
||||
await remote.completeSimpleLogin(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
code: simpleLogin.authorize(
|
||||
start.authorizationUrl,
|
||||
subject: 'sl-carla',
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
await remote.checkSimpleLoginHandle(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
handle: 'carla',
|
||||
network: '203.0.113.0/24',
|
||||
),
|
||||
isNull,
|
||||
);
|
||||
final carla = await remote.signUpWithSimpleLogin(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
handle: 'carla',
|
||||
setup: device.setup(),
|
||||
);
|
||||
|
||||
expect(
|
||||
(await AuthUser.db.findById(session, carla))!.scopeNames,
|
||||
{identified.name},
|
||||
);
|
||||
final ways = await remote.signInWaysOf(session, carla);
|
||||
expect(
|
||||
(ways.simpleLogin, ways.keys, ways.password),
|
||||
(
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
);
|
||||
final keys = await remote.unlockKeys(
|
||||
session,
|
||||
carla,
|
||||
await device.prove(
|
||||
await remote.beginPasswordKeyProof(session, carla),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
Uint8List.sublistView(keys.signingPublicKey),
|
||||
device.signingPublicKey,
|
||||
);
|
||||
});
|
||||
|
||||
test('refuses a sign-up and keys as the register refuses, a '
|
||||
"handle's refusals crossing whole", () async {
|
||||
final device = await KeysDevice.make();
|
||||
final start = await remote.beginSimpleLogin(
|
||||
session,
|
||||
marker: 'todo-desktop',
|
||||
network: '203.0.113.0/24',
|
||||
);
|
||||
await remote.completeSimpleLogin(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
code: simpleLogin.authorize(
|
||||
start.authorizationUrl,
|
||||
subject: 'sl-carla',
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
await remote.checkSimpleLoginHandle(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
handle: 'admin',
|
||||
network: '203.0.113.0/24',
|
||||
),
|
||||
ProfileRefusal.handleReserved,
|
||||
);
|
||||
await expectLater(
|
||||
remote.signUpWithSimpleLogin(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
handle: 'admin',
|
||||
setup: device.setup(),
|
||||
),
|
||||
refused(ProfileRefusal.handleReserved),
|
||||
);
|
||||
await expectLater(
|
||||
remote.signUpWithSimpleLogin(
|
||||
session,
|
||||
attempt: const Uuid().v7obj(),
|
||||
handle: 'carla',
|
||||
setup: device.setup(),
|
||||
),
|
||||
refused(OidcRefusal.unknownAttempt),
|
||||
);
|
||||
await expectLater(
|
||||
remote.beginPasswordKeyProof(session, ben),
|
||||
refused(PasswordRefusal.noPassword),
|
||||
);
|
||||
final carla = await remote.signUpWithSimpleLogin(
|
||||
session,
|
||||
attempt: start.attempt,
|
||||
handle: 'carla',
|
||||
setup: device.setup(),
|
||||
);
|
||||
await expectLater(
|
||||
remote.unlockKeys(
|
||||
session,
|
||||
carla,
|
||||
await (await KeysDevice.make(seed: 5)).prove(
|
||||
await remote.beginPasswordKeyProof(session, carla),
|
||||
),
|
||||
),
|
||||
refused(PasswordRefusal.wrongCredentials),
|
||||
);
|
||||
});
|
||||
|
||||
test('refuses where the register has no SimpleLogin app', () async {
|
||||
useSimpleLogin(sessionBuilder, null);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue