feat(instance): the basics say when GitHub sign-in ends
ADR 0017, D2: GitHub sign-in is deprecated. Where the operator set `GITHUB_SIGN_IN_ENDS`, `instance.basics()` names the day until it has come, so apps can tell people who sign in with GitHub to add an address, a password and an authenticator before then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
d00da1f24a
commit
1daa1b649a
4 changed files with 85 additions and 6 deletions
|
|
@ -27,6 +27,7 @@ abstract class InstanceBasics
|
|||
this.dataLocation,
|
||||
this.backupLocation,
|
||||
bool? passwordSignIn,
|
||||
this.gitHubSignInEnds,
|
||||
}) : passwordSignIn = passwordSignIn ?? false;
|
||||
|
||||
factory InstanceBasics({
|
||||
|
|
@ -38,6 +39,7 @@ abstract class InstanceBasics
|
|||
String? dataLocation,
|
||||
String? backupLocation,
|
||||
bool? passwordSignIn,
|
||||
DateTime? gitHubSignInEnds,
|
||||
}) = _InstanceBasicsImpl;
|
||||
|
||||
factory InstanceBasics.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
|
|
@ -54,6 +56,11 @@ abstract class InstanceBasics
|
|||
passwordSignIn: jsonSerialization['passwordSignIn'] == null
|
||||
? null
|
||||
: _is.BoolJsonExtension.fromJson(jsonSerialization['passwordSignIn']),
|
||||
gitHubSignInEnds: jsonSerialization['gitHubSignInEnds'] == null
|
||||
? null
|
||||
: _is.DateTimeJsonExtension.fromJson(
|
||||
jsonSerialization['gitHubSignInEnds'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +98,12 @@ abstract class InstanceBasics
|
|||
/// operator set the keys it needs.
|
||||
bool passwordSignIn;
|
||||
|
||||
/// When GitHub sign-in ends here (ADR 0017: it is deprecated), as its
|
||||
/// operator set it (GITHUB_SIGN_IN_ENDS), in UTC; null while no end is set,
|
||||
/// or once it has ended. People who sign in with GitHub add an address, a
|
||||
/// password and an authenticator before then.
|
||||
DateTime? gitHubSignInEnds;
|
||||
|
||||
/// Returns a shallow copy of this [InstanceBasics]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
|
|
@ -103,6 +116,7 @@ abstract class InstanceBasics
|
|||
String? dataLocation,
|
||||
String? backupLocation,
|
||||
bool? passwordSignIn,
|
||||
DateTime? gitHubSignInEnds,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
|
|
@ -116,6 +130,8 @@ abstract class InstanceBasics
|
|||
if (dataLocation != null) 'dataLocation': dataLocation,
|
||||
if (backupLocation != null) 'backupLocation': backupLocation,
|
||||
'passwordSignIn': passwordSignIn,
|
||||
if (gitHubSignInEnds != null)
|
||||
'gitHubSignInEnds': gitHubSignInEnds?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +147,8 @@ abstract class InstanceBasics
|
|||
if (dataLocation != null) 'dataLocation': dataLocation,
|
||||
if (backupLocation != null) 'backupLocation': backupLocation,
|
||||
'passwordSignIn': passwordSignIn,
|
||||
if (gitHubSignInEnds != null)
|
||||
'gitHubSignInEnds': gitHubSignInEnds?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +170,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
|
|||
String? dataLocation,
|
||||
String? backupLocation,
|
||||
bool? passwordSignIn,
|
||||
DateTime? gitHubSignInEnds,
|
||||
}) : super._(
|
||||
app: app,
|
||||
gitHubClientId: gitHubClientId,
|
||||
|
|
@ -161,6 +180,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
|
|||
dataLocation: dataLocation,
|
||||
backupLocation: backupLocation,
|
||||
passwordSignIn: passwordSignIn,
|
||||
gitHubSignInEnds: gitHubSignInEnds,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [InstanceBasics]
|
||||
|
|
@ -176,6 +196,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
|
|||
Object? dataLocation = _Undefined,
|
||||
Object? backupLocation = _Undefined,
|
||||
bool? passwordSignIn,
|
||||
Object? gitHubSignInEnds = _Undefined,
|
||||
}) {
|
||||
return InstanceBasics(
|
||||
app: app ?? this.app,
|
||||
|
|
@ -190,6 +211,9 @@ class _InstanceBasicsImpl extends InstanceBasics {
|
|||
? backupLocation
|
||||
: this.backupLocation,
|
||||
passwordSignIn: passwordSignIn ?? this.passwordSignIn,
|
||||
gitHubSignInEnds: gitHubSignInEnds is DateTime?
|
||||
? gitHubSignInEnds
|
||||
: this.gitHubSignInEnds,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,3 +30,8 @@ fields:
|
|||
### Whether people sign in with a password and TOTP here (ADR 0017): the
|
||||
### operator set the keys it needs.
|
||||
passwordSignIn: bool, default=false
|
||||
### When GitHub sign-in ends here (ADR 0017: it is deprecated), as its
|
||||
### operator set it (GITHUB_SIGN_IN_ENDS), in UTC; null while no end is set,
|
||||
### or once it has ended. People who sign in with GitHub add an address, a
|
||||
### password and an authenticator before then.
|
||||
gitHubSignInEnds: DateTime?
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@ class InstanceEndpoint extends Endpoint {
|
|||
/// operator's OAuth app and until it ends (ADR 0017), email sign-in only
|
||||
/// where the register can mail codes (this server, or on a member the
|
||||
/// register, ADR 0016), password sign-in where the register holds its
|
||||
/// keys, where its
|
||||
/// source is, the oldest app build it works with, and where it keeps
|
||||
/// people's data and its backups.
|
||||
/// keys, when GitHub sign-in ends, where its source is, the oldest app
|
||||
/// build it works with, and where it keeps people's data and its backups.
|
||||
Future<InstanceBasics> basics(Session session) async {
|
||||
final pod = session.serverpod;
|
||||
final base = HalkyonBase.of(pod);
|
||||
|
|
@ -42,6 +41,7 @@ class InstanceEndpoint extends Endpoint {
|
|||
minimumAppBuild: base.minimumAppBuild,
|
||||
dataLocation: dataLocation(),
|
||||
backupLocation: backupLocation(),
|
||||
gitHubSignInEnds: gitHubSignInEnded(pod) ? null : gitHubSignInEnds(pod),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:clock/clock.dart';
|
||||
import 'package:halkyon_base_server/base.dart';
|
||||
import 'package:serverpod/serverpod.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
|
@ -68,6 +69,32 @@ void main() {
|
|||
expect(basics.gitHubClientId, isNull);
|
||||
});
|
||||
|
||||
test('says when GitHub sign-in ends, until it has', () async {
|
||||
final pod = sessionBuilder.build().serverpod;
|
||||
final unauthenticated = sessionBuilder.copyWith(
|
||||
authentication: AuthenticationOverride.unauthenticated(),
|
||||
);
|
||||
addTearDown(() => useGitHubSignInEnds(pod, null));
|
||||
expect(basics.gitHubSignInEnds, isNull);
|
||||
|
||||
final ends = DateTime.utc(2027, 1, 22);
|
||||
useGitHubSignInEnds(pod, ends);
|
||||
expect(
|
||||
(await withClock(
|
||||
Clock.fixed(DateTime.utc(2026, 10, 22)),
|
||||
() => endpoints.instance.basics(unauthenticated),
|
||||
)).gitHubSignInEnds,
|
||||
ends,
|
||||
);
|
||||
expect(
|
||||
(await withClock(
|
||||
Clock.fixed(ends),
|
||||
() => endpoints.instance.basics(unauthenticated),
|
||||
)).gitHubSignInEnds,
|
||||
isNull,
|
||||
);
|
||||
});
|
||||
|
||||
test('offers email sign-in only where it can mail codes', () async {
|
||||
final codes = EmailCodes.of(sessionBuilder.build().serverpod);
|
||||
final unauthenticated = sessionBuilder.copyWith(
|
||||
|
|
|
|||
Loading…
Reference in a new issue