fix(auth): the reading of the fixes' nits
- The background delivery of session notices logs (its failure warning was never written: its session had logging off). - A sign-in's and a phrase proof's begin check the address's ceiling after the network's limits, which hold a flood back before it costs the ceiling's queries (one an UPDATE, pushing resets). - The module's README lists every pruning step a host schedules (forgetLapsedResets, deliverSessionNotices) and which mode each is for. (The check of a member's clock ahead, which counted the register's processing time as skew, went with C1's fix.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
f9880e6989
commit
8c910f8cfc
3 changed files with 21 additions and 12 deletions
|
|
@ -60,12 +60,13 @@ Endpoints, under the nickname `base` in a host's client (`client.modules.base.em
|
||||||
`tokenManagerBuilders` and `identityProviderBuilders`, the `identified` scope and
|
`tokenManagerBuilders` and `identityProviderBuilders`, the `identified` scope and
|
||||||
`grantIdentified`, `deletePerson`, the pruning (`pruneAbandonedAnonymousPeople`,
|
`grantIdentified`, `deletePerson`, the pruning (`pruneAbandonedAnonymousPeople`,
|
||||||
`forgetOldSignUpAttempts`, `forgetExpiredEmailCodes`, `forgetUnconfirmedAuthenticators`,
|
`forgetOldSignUpAttempts`, `forgetExpiredEmailCodes`, `forgetUnconfirmedAuthenticators`,
|
||||||
`forgetGitHubAccounts`), short codes, `sourceCodeUrl`,
|
`forgetGitHubAccounts`, `forgetLapsedResets`), short codes, `sourceCodeUrl`,
|
||||||
`dataLocation`, `backupLocation`, people's profiles as the host's code reads them
|
`dataLocation`, `backupLocation`, people's profiles as the host's code reads them
|
||||||
(`profileOf`, `profilesOf`, `personWithHandle`, `fixHandle`; `saveProfile` for its
|
(`profileOf`, `profilesOf`, `personWithHandle`, `fixHandle`; `saveProfile` for its
|
||||||
tests), `accountDomain`, `profilePageUrl`, `addProfilePageRoute`, the register
|
tests), `accountDomain`, `profilePageUrl`, `addProfilePageRoute`, the register
|
||||||
(`AccountRegister`, `AccountsMode`, `addInstanceRoutes`, `deliverDeletionNotices`,
|
(`AccountRegister`, `AccountsMode`, `addInstanceRoutes`, `deliverDeletionNotices`,
|
||||||
`forgetPeopleTheRegisterForgot`, `issueSession`), and the models. A host never reads
|
`deliverSessionNotices`, `forgetPeopleTheRegisterForgot`, `issueSession`), and the
|
||||||
|
models. A host never reads
|
||||||
the profiles' table itself.
|
the profiles' table itself.
|
||||||
|
|
||||||
## The instance's register (ADR 0016)
|
## The instance's register (ADR 0016)
|
||||||
|
|
@ -329,8 +330,11 @@ Built on the three parts above, on the register (members forward every step thro
|
||||||
longer signs in with GitHub (`usePassword`); where passwords are offered, no new GitHub
|
longer signs in with GitHub (`usePassword`); where passwords are offered, no new GitHub
|
||||||
account is linked (`deprecated`); from `GITHUB_SIGN_IN_ENDS` on GitHub signs nobody in
|
account is linked (`deprecated`); from `GITHUB_SIGN_IN_ENDS` on GitHub signs nobody in
|
||||||
(`ended`), the basics stop naming the day (`gitHubSignInEnds`, which apps show until
|
(`ended`), the basics stop naming the day (`gitHubSignInEnds`, which apps show until
|
||||||
then) and `forgetGitHubAccounts` deletes every GitHub ID, first deleting the accounts
|
then) and, 30 days later (`gitHubAccountsKeptAfterEnd`, so a date set wrong can be put
|
||||||
that sign in with GitHub alone (no address, never a password). `password.set` adds an
|
right first), `forgetGitHubAccounts` deletes every GitHub ID on the register, first
|
||||||
|
deleting the accounts that sign in with GitHub alone (no address, never a password),
|
||||||
|
each on its own (one failing is tried again the next day), the members told once
|
||||||
|
after all of them. `password.set` adds an
|
||||||
address without GitHub only for someone anonymous where the session lives
|
address without GitHub only for someone anonymous where the session lives
|
||||||
(`anonymousHere`, which a member tells the register).
|
(`anonymousHere`, which a member tells the register).
|
||||||
|
|
||||||
|
|
@ -386,10 +390,12 @@ Built on the three parts above, on the register (members forward every step thro
|
||||||
literal routes of its own.
|
literal routes of its own.
|
||||||
|
|
||||||
Then schedule the pruning in a future call of the host's own: daily
|
Then schedule the pruning in a future call of the host's own: daily
|
||||||
`pruneAbandonedAnonymousPeople`, `forgetGitHubAccounts` and
|
`pruneAbandonedAnonymousPeople`, `forgetGitHubAccounts` (the register's),
|
||||||
`forgetPeopleTheRegisterForgot` (a member's), hourly `forgetOldSignUpAttempts`,
|
`forgetLapsedResets` and `forgetPeopleTheRegisterForgot` (a member's), hourly
|
||||||
`forgetExpiredEmailCodes`, `forgetUnconfirmedAuthenticators` and
|
`forgetOldSignUpAttempts`, `forgetExpiredEmailCodes`,
|
||||||
`deliverDeletionNotices` (the register's). Each does nothing in the other mode.
|
`forgetUnconfirmedAuthenticators`, `deliverDeletionNotices` and
|
||||||
|
`deliverSessionNotices` (the register's). Each marked as one mode's does nothing in
|
||||||
|
the other.
|
||||||
|
|
||||||
4. A host's deletion (`PersonDataDeletion`) runs inside `deletePerson`'s transaction,
|
4. A host's deletion (`PersonDataDeletion`) runs inside `deletePerson`'s transaction,
|
||||||
after the person's sessions ended and before their identities and the person go, in
|
after the person's sessions ended and before their identities and the person go, in
|
||||||
|
|
|
||||||
|
|
@ -692,7 +692,6 @@ Future<PasswordChallenge> beginPasswordSignIn(
|
||||||
final pod = session.serverpod;
|
final pod = session.serverpod;
|
||||||
final keys = requirePasswordKeys(pod);
|
final keys = requirePasswordKeys(pod);
|
||||||
final hash = _hashOfTyped(pod, address);
|
final hash = _hashOfTyped(pod, address);
|
||||||
await _refuseAddressProvingTooOften(session, hash);
|
|
||||||
// The address first: a sign-in it can't begin takes nothing of the
|
// The address first: a sign-in it can't begin takes nothing of the
|
||||||
// network's.
|
// network's.
|
||||||
if (!await _beginsPerAddressAndNetwork.tryRecordAttempt(
|
if (!await _beginsPerAddressAndNetwork.tryRecordAttempt(
|
||||||
|
|
@ -702,6 +701,9 @@ Future<PasswordChallenge> beginPasswordSignIn(
|
||||||
!await _beginsPerNetwork.tryRecordAttempt(session, key: network)) {
|
!await _beginsPerNetwork.tryRecordAttempt(session, key: network)) {
|
||||||
throw refusedFor(PasswordRefusal.tooManyAttempts);
|
throw refusedFor(PasswordRefusal.tooManyAttempts);
|
||||||
}
|
}
|
||||||
|
// The address's ceiling after the network's limits, which hold a flood
|
||||||
|
// back before it costs the ceiling's queries (the reading of the fixes).
|
||||||
|
await _refuseAddressProvingTooOften(session, hash);
|
||||||
// Both, always: an account's sign-in takes as long as a decoy's.
|
// Both, always: an account's sign-in takes as long as a decoy's.
|
||||||
final decoy = _decoyAccount(keys.decoyKey, hash);
|
final decoy = _decoyAccount(keys.decoyKey, hash);
|
||||||
final password = await _passwordWithAddress(session, hash);
|
final password = await _passwordWithAddress(session, hash);
|
||||||
|
|
@ -1333,7 +1335,6 @@ Future<KeyProofChallenge> beginKeyProof(
|
||||||
final pod = session.serverpod;
|
final pod = session.serverpod;
|
||||||
final keys = requirePasswordKeys(pod);
|
final keys = requirePasswordKeys(pod);
|
||||||
final hash = _hashOfTyped(pod, address);
|
final hash = _hashOfTyped(pod, address);
|
||||||
await _refuseAddressProvingTooOften(session, hash);
|
|
||||||
if (!await _keyProofsPerAddressAndNetwork.tryRecordAttempt(
|
if (!await _keyProofsPerAddressAndNetwork.tryRecordAttempt(
|
||||||
session,
|
session,
|
||||||
key: '$hash|$network',
|
key: '$hash|$network',
|
||||||
|
|
@ -1341,6 +1342,7 @@ Future<KeyProofChallenge> beginKeyProof(
|
||||||
!await _beginsPerNetwork.tryRecordAttempt(session, key: network)) {
|
!await _beginsPerNetwork.tryRecordAttempt(session, key: network)) {
|
||||||
throw refusedFor(PasswordRefusal.tooManyAttempts);
|
throw refusedFor(PasswordRefusal.tooManyAttempts);
|
||||||
}
|
}
|
||||||
|
await _refuseAddressProvingTooOften(session, hash);
|
||||||
final decoy = await _decoyKeys(keys.decoyKey, hash);
|
final decoy = await _decoyKeys(keys.decoyKey, hash);
|
||||||
final password = await _passwordWithAddress(session, hash);
|
final password = await _passwordWithAddress(session, hash);
|
||||||
final nonce = _randomBytes(32);
|
final nonce = _randomBytes(32);
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,10 @@ Future<void> announceSessionsEnded(Session session, UuidValue account) async {
|
||||||
final _deliveries = <Future<void>>{};
|
final _deliveries = <Future<void>>{};
|
||||||
|
|
||||||
/// Tells the members of [account]'s ended sessions, on a session of its
|
/// Tells the members of [account]'s ended sessions, on a session of its
|
||||||
/// own: the request's may close first.
|
/// own: the request's may close first. It logs, so a failure is written
|
||||||
|
/// (persisting session logs stays off everywhere, `config/`).
|
||||||
Future<void> _deliverInBackground(Serverpod pod, UuidValue account) async {
|
Future<void> _deliverInBackground(Serverpod pod, UuidValue account) async {
|
||||||
final session = await pod.createSession(enableLogging: false);
|
final session = await pod.createSession();
|
||||||
try {
|
try {
|
||||||
await deliverSessionNotices(session, account: account);
|
await deliverSessionNotices(session, account: account);
|
||||||
} on Object catch (error) {
|
} on Object catch (error) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue