feat(auth)!: codes by mail no longer sign in
ADR 0017, step 3 (D4: nobody signs in with email codes yet, so the password replaces them outright). `emailCode.verifyCode`, `emailSignIn.signIn` and the switch token go, with the register's `verifySignInCode` and `completeEmailSwitch` and their operations between services. `emailCode.sendCode` stays, now without a session (signing up and getting back in have none), as what proves an address for a password's setup, a sign-up, a setup never finished and the resets; `accountRecovery.sendCode`, which did that for the resets, goes. The `switchChallengeId` column stays: Serverpod's challenges still link a completion token, and older servers read it during a deploy. The apps: halkyon_app's email sign-in (its bloc, sheet, gateway calls and the start screen's Continue with email) goes; Learn's profile and Todo's account sheet show `AccountSecuritySection` (a password set up by someone anonymous or signing in with GitHub, whose end it names; the authenticators; changing the password; new recovery codes and phrase), which reads anew after every change the repository makes. BREAKING CHANGE: Learn's `minimumAppBuild` is 22: builds up to 21 sign in with the endpoints that went. Todo was never released and stays at build 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
735dfa892a
commit
ae57cbe864
4 changed files with 429 additions and 3835 deletions
|
|
@ -1,75 +0,0 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
|
||||
/// A code accepted: the address is now the signed-in person's (or already
|
||||
/// was), or it is another person's and [switchToken] signs in as them.
|
||||
abstract class EmailCodeAccepted
|
||||
implements _isc.SerializableModel, _isc.ProtocolSerialization {
|
||||
EmailCodeAccepted._({this.switchToken});
|
||||
|
||||
factory EmailCodeAccepted({String? switchToken}) = _EmailCodeAcceptedImpl;
|
||||
|
||||
factory EmailCodeAccepted.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return EmailCodeAccepted(
|
||||
switchToken: jsonSerialization['switchToken'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
/// Null when the address is the signed-in person's; else what signs in as
|
||||
/// the person who has it, once, within the code's 15 minutes
|
||||
/// (`EmailSignInEndpoint.signIn`).
|
||||
String? switchToken;
|
||||
|
||||
/// Returns a shallow copy of this [EmailCodeAccepted]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
EmailCodeAccepted copyWith({String? switchToken});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'halkyon_base.EmailCodeAccepted',
|
||||
if (switchToken != null) 'switchToken': switchToken,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'halkyon_base.EmailCodeAccepted',
|
||||
if (switchToken != null) 'switchToken': switchToken,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _EmailCodeAcceptedImpl extends EmailCodeAccepted {
|
||||
_EmailCodeAcceptedImpl({String? switchToken})
|
||||
: super._(switchToken: switchToken);
|
||||
|
||||
/// Returns a shallow copy of this [EmailCodeAccepted]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
EmailCodeAccepted copyWith({Object? switchToken = _Undefined}) {
|
||||
return EmailCodeAccepted(
|
||||
switchToken: switchToken is String? ? switchToken : this.switchToken,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,8 @@ enum EmailSignInRefusal implements _isc.SerializableModel {
|
|||
mailFailed,
|
||||
|
||||
/// The account signs in with its password and an authenticator (ADR
|
||||
/// 0017): a code by mail no longer signs into it.
|
||||
/// 0017): a code by mail no longer signs into it. No longer refused for
|
||||
/// since codes sign nobody in; kept, as older apps know it by name.
|
||||
usePassword;
|
||||
|
||||
static EmailSignInRefusal fromJson(String name) {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _ida;
|
||||
import 'dart:typed_data' as _idt;
|
||||
import 'package:halkyon_base_client/src/protocol/auth/email_code_accepted.dart'
|
||||
as _ioeosfv3;
|
||||
import 'package:halkyon_base_client/src/protocol/auth/sign_in_ways.dart'
|
||||
as _ifld8s4r;
|
||||
import 'package:halkyon_base_client/src/protocol/instance/instance_basics.dart'
|
||||
|
|
@ -98,12 +96,12 @@ class EndpointAnonymousIdp extends _iaic.EndpointAnonymousIdpBase {
|
|||
);
|
||||
}
|
||||
|
||||
/// Signing in with an email address, by a code mailed to it:
|
||||
/// the way to keep an anonymous account, as linking GitHub is, and a second
|
||||
/// way in for someone who signs in with GitHub. Signed in only, as every
|
||||
/// device is from its first start. The instance's register mails the codes
|
||||
/// and keeps the addresses' hashes (ADR 0016), this server's own database
|
||||
/// when it holds the register.
|
||||
/// Codes by mail (ADR 0017): what proves an address for a password's setup,
|
||||
/// a sign-up, a setup never finished and the resets. A code signs nobody in
|
||||
/// by itself. Without a session, as signing up and getting back in have
|
||||
/// none. The instance's register mails the codes and keeps the addresses'
|
||||
/// hashes (ADR 0016), this server's own database when it holds the
|
||||
/// register.
|
||||
/// {@category Endpoint}
|
||||
class EndpointEmailCode extends _isc.EndpointRef {
|
||||
EndpointEmailCode(_isc.EndpointCaller caller) : super(caller);
|
||||
|
|
@ -124,41 +122,6 @@ class EndpointEmailCode extends _isc.EndpointRef {
|
|||
'language': language,
|
||||
},
|
||||
);
|
||||
|
||||
/// Accepts [code] for [request]: the address becomes the caller's unless
|
||||
/// it is another person's, whose token then signs in as them
|
||||
/// (`EmailSignInEndpoint.signIn`); refusals as in [acceptSignInCode].
|
||||
_ida.Future<_ioeosfv3.EmailCodeAccepted> verifyCode({
|
||||
required _isc.UuidValue request,
|
||||
required String code,
|
||||
}) => caller.callServerEndpoint<_ioeosfv3.EmailCodeAccepted>(
|
||||
'halkyon_base.emailCode',
|
||||
'verifyCode',
|
||||
{
|
||||
'request': request,
|
||||
'code': code,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Signs in the person whose address a mailed code proved, when the device
|
||||
/// switches to them. Called without a session: Serverpod issues no session
|
||||
/// for another person inside a signed-in call.
|
||||
/// {@category Endpoint}
|
||||
class EndpointEmailSignIn extends _isc.EndpointRef {
|
||||
EndpointEmailSignIn(_isc.EndpointCaller caller) : super(caller);
|
||||
|
||||
@override
|
||||
String get name => 'halkyon_base.emailSignIn';
|
||||
|
||||
/// A session for the person [switchToken] names; refusals as in
|
||||
/// [completeEmailSwitch].
|
||||
_ida.Future<_iacc.AuthSuccess> signIn({required String switchToken}) =>
|
||||
caller.callServerEndpoint<_iacc.AuthSuccess>(
|
||||
'halkyon_base.emailSignIn',
|
||||
'signIn',
|
||||
{'switchToken': switchToken},
|
||||
);
|
||||
}
|
||||
|
||||
/// Signs in the person who already has a GitHub account, e.g. when they switch
|
||||
|
|
@ -250,25 +213,10 @@ class EndpointAccountRecovery extends _isc.EndpointRef {
|
|||
@override
|
||||
String get name => 'halkyon_base.accountRecovery';
|
||||
|
||||
/// Mails a code to [address], worded in [language] (`en`, `de`), as email
|
||||
/// sign-in mails it, and returns the request it answers: the proof of the
|
||||
/// address that resets take. Refusals as `sendSignInCode`'s.
|
||||
_ida.Future<_isc.UuidValue> sendCode({
|
||||
required String address,
|
||||
required String language,
|
||||
}) => caller.callServerEndpoint<_isc.UuidValue>(
|
||||
'halkyon_base.accountRecovery',
|
||||
'sendCode',
|
||||
{
|
||||
'address': address,
|
||||
'language': language,
|
||||
},
|
||||
);
|
||||
|
||||
/// Asks for the reset of the authenticators of the account at [address]:
|
||||
/// the password's proof for [challenge] (`passwordSignIn.begin`), and a
|
||||
/// [code] mailed for [request] or the recovery phrase's [signature] for
|
||||
/// [keyChallenge] ([beginKeyProof]). It takes effect 72 hours later
|
||||
/// [keyChallenge] ([beginKeyProof]); codes by mail come from `emailCode.sendCode`. It takes effect 72 hours later
|
||||
/// unless the owner signs in with a code meanwhile; a mail in [language]
|
||||
/// says so. Refusals as `resetAuthenticator`'s.
|
||||
_ida.Future<_ippuf33k.ResetPending> resetAuthenticator({
|
||||
|
|
@ -719,7 +667,6 @@ class Caller extends _isc.ModuleEndpointCaller {
|
|||
account = EndpointAccount(this);
|
||||
anonymousIdp = EndpointAnonymousIdp(this);
|
||||
emailCode = EndpointEmailCode(this);
|
||||
emailSignIn = EndpointEmailSignIn(this);
|
||||
gitHubSignIn = EndpointGitHubSignIn(this);
|
||||
gitHubUpgrade = EndpointGitHubUpgrade(this);
|
||||
instance = EndpointInstance(this);
|
||||
|
|
@ -737,8 +684,6 @@ class Caller extends _isc.ModuleEndpointCaller {
|
|||
|
||||
late final EndpointEmailCode emailCode;
|
||||
|
||||
late final EndpointEmailSignIn emailSignIn;
|
||||
|
||||
late final EndpointGitHubSignIn gitHubSignIn;
|
||||
|
||||
late final EndpointGitHubUpgrade gitHubUpgrade;
|
||||
|
|
@ -762,7 +707,6 @@ class Caller extends _isc.ModuleEndpointCaller {
|
|||
'halkyon_base.account': account,
|
||||
'halkyon_base.anonymousIdp': anonymousIdp,
|
||||
'halkyon_base.emailCode': emailCode,
|
||||
'halkyon_base.emailSignIn': emailSignIn,
|
||||
'halkyon_base.gitHubSignIn': gitHubSignIn,
|
||||
'halkyon_base.gitHubUpgrade': gitHubUpgrade,
|
||||
'halkyon_base.instance': instance,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
|
|||
import 'package:serverpod_auth_idp_client/serverpod_auth_idp_client.dart'
|
||||
as _iaic;
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
import 'auth/email_code_accepted.dart' as _iys46ui1;
|
||||
import 'auth/email_sign_in_refusal.dart' as _ieyvcag1;
|
||||
import 'auth/email_sign_in_refused_exception.dart' as _iztfgag5;
|
||||
import 'auth/github_sign_in_refusal.dart' as _ir1gd9p5;
|
||||
|
|
@ -43,7 +42,6 @@ import 'profile/profile.dart' as _ia5j8fch;
|
|||
import 'profile/profile_not_found_exception.dart' as _iim3hfcf;
|
||||
import 'profile/profile_refusal.dart' as _i6j6efd1;
|
||||
import 'profile/profile_refused_exception.dart' as _idvc5e7p;
|
||||
export 'auth/email_code_accepted.dart';
|
||||
export 'auth/email_sign_in_refusal.dart';
|
||||
export 'auth/email_sign_in_refused_exception.dart';
|
||||
export 'auth/github_sign_in_refusal.dart';
|
||||
|
|
@ -115,9 +113,6 @@ class Protocol extends _isc.SerializationManager {
|
|||
}
|
||||
}
|
||||
|
||||
if (t == _iys46ui1.EmailCodeAccepted) {
|
||||
return _iys46ui1.EmailCodeAccepted.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ieyvcag1.EmailSignInRefusal) {
|
||||
return _ieyvcag1.EmailSignInRefusal.fromJson(data) as T;
|
||||
}
|
||||
|
|
@ -190,10 +185,6 @@ class Protocol extends _isc.SerializationManager {
|
|||
if (t == _idvc5e7p.ProfileRefusedException) {
|
||||
return _idvc5e7p.ProfileRefusedException.fromJson(data) as T;
|
||||
}
|
||||
if (t == _isc.getType<_iys46ui1.EmailCodeAccepted?>()) {
|
||||
return (data != null ? _iys46ui1.EmailCodeAccepted.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ieyvcag1.EmailSignInRefusal?>()) {
|
||||
return (data != null ? _ieyvcag1.EmailSignInRefusal.fromJson(data) : null)
|
||||
as T;
|
||||
|
|
@ -333,7 +324,6 @@ class Protocol extends _isc.SerializationManager {
|
|||
|
||||
static String? getClassNameForType(Type type) {
|
||||
return switch (type) {
|
||||
_iys46ui1.EmailCodeAccepted => 'EmailCodeAccepted',
|
||||
_ieyvcag1.EmailSignInRefusal => 'EmailSignInRefusal',
|
||||
_iztfgag5.EmailSignInRefusedException => 'EmailSignInRefusedException',
|
||||
_ir1gd9p5.GitHubSignInRefusal => 'GitHubSignInRefusal',
|
||||
|
|
@ -375,8 +365,6 @@ class Protocol extends _isc.SerializationManager {
|
|||
}
|
||||
|
||||
switch (data) {
|
||||
case _iys46ui1.EmailCodeAccepted():
|
||||
return 'EmailCodeAccepted';
|
||||
case _ieyvcag1.EmailSignInRefusal():
|
||||
return 'EmailSignInRefusal';
|
||||
case _iztfgag5.EmailSignInRefusedException():
|
||||
|
|
@ -435,9 +423,6 @@ class Protocol extends _isc.SerializationManager {
|
|||
if (dataClassName is! String) {
|
||||
return super.deserializeByClassName(data);
|
||||
}
|
||||
if (dataClassName == 'EmailCodeAccepted') {
|
||||
return deserialize<_iys46ui1.EmailCodeAccepted>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'EmailSignInRefusal') {
|
||||
return deserialize<_ieyvcag1.EmailSignInRefusal>(data['data']);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue