feat(base,app)!: GitHub signs nobody in any more (ADR 0020, D36)
Every account signs in with SimpleLogin or a password now, so GitHub goes from the module, the shared app package, Learn and Todo, ahead of ADR 0017's GITHUB_SIGN_IN_ENDS. - halkyon_base: no `gitHubSignIn` endpoint, GitHub identity provider or GitHub refusals; no `githubClientId`/`githubClientSecret`, no `GITHUB_SIGN_IN_ENDS` and no `forgetGitHubAccounts`; the register loses `account-with-github`. `SignInWays.gitHub`, the basics' `gitHubClientId` and `gitHubSignInEnds`, and `PasswordRefusal`'s `signInAgain` and `noAddress` go. A first password takes a code mailed to the person's own address; an account without one sets none (`wrongCredentials`). - Learn's server: `instance.info()` without `gitHubClientId`, the pruning without GitHub, and `minimumAppBuild` 24, as builds up to 23 (v0.20.0) require `SignInWays.gitHub`: the server deploys with the release of build 24. - halkyon_app: no GitHub button or problems on the start screen, no password offered after a GitHub sign-in, and `ServerpodAuthGateway` without the browser half only GitHub used (`(client, base:)`). The account section offers a first password only to an account with an address. `LoopbackWebAuth` and the apps' schemes stay, SimpleLogin's ways back. - Learn's Profile lists no GitHub; the texts go (English, German). - Serverpod's `serverpod_auth_idp_github_account` stays, as its migrations make it; a row goes with its account, and ADR 0020's D36 gives operators the SQL to delete those left. - deploy/: compose.yaml and .env.example without GitHub. The READMEs, AGENTS.md files and ADR 0017 amended. BREAKING CHANGE: builds up to 23 can't read the instance's answers about an account's ways in; minimumAppBuild is 24. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
ab5b7cd015
commit
4e33133733
17 changed files with 564 additions and 3570 deletions
|
|
@ -41,7 +41,7 @@
|
|||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Receives GitHub's redirect after signing in (app.halkyon.learn://github-callback). -->
|
||||
<!-- Receives the way back from SimpleLogin's sign-in (app.halkyon.learn://simplelogin-callback). -->
|
||||
<activity
|
||||
android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
|
||||
android:exported="true"
|
||||
|
|
|
|||
|
|
@ -470,7 +470,6 @@
|
|||
"profileSettingsTooltip": "Einstellungen",
|
||||
"profileIdentified": "Dein Fortschritt wird in deinem Konto gespeichert.",
|
||||
"profileSignInWays": "Anmeldewege",
|
||||
"profileWayGitHub": "GitHub",
|
||||
"profileWayEmail": "E-Mail-Adresse",
|
||||
"profileWayLinked": "Meldet dich an",
|
||||
"publicProfileTitle": "Öffentliches Profil",
|
||||
|
|
|
|||
|
|
@ -535,7 +535,6 @@
|
|||
"profileSettingsTooltip": "Settings",
|
||||
"profileIdentified": "Your progress is kept with your account.",
|
||||
"profileSignInWays": "Ways to sign in",
|
||||
"profileWayGitHub": "GitHub",
|
||||
"profileWayEmail": "Email address",
|
||||
"profileWayLinked": "Signs you in",
|
||||
"publicProfileTitle": "Public profile",
|
||||
|
|
|
|||
|
|
@ -2830,12 +2830,6 @@ abstract class AppLocalizations {
|
|||
/// **'Ways to sign in'**
|
||||
String get profileSignInWays;
|
||||
|
||||
/// No description provided for @profileWayGitHub.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'GitHub'**
|
||||
String get profileWayGitHub;
|
||||
|
||||
/// No description provided for @profileWayEmail.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -1718,9 +1718,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
@override
|
||||
String get profileSignInWays => 'Anmeldewege';
|
||||
|
||||
@override
|
||||
String get profileWayGitHub => 'GitHub';
|
||||
|
||||
@override
|
||||
String get profileWayEmail => 'E-Mail-Adresse';
|
||||
|
||||
|
|
|
|||
|
|
@ -1702,9 +1702,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get profileSignInWays => 'Ways to sign in';
|
||||
|
||||
@override
|
||||
String get profileWayGitHub => 'GitHub';
|
||||
|
||||
@override
|
||||
String get profileWayEmail => 'Email address';
|
||||
|
||||
|
|
|
|||
|
|
@ -228,10 +228,6 @@ class Dependencies({
|
|||
final authGateway = ServerpodAuthGateway(
|
||||
client,
|
||||
base: client.modules.base,
|
||||
// The scheme GitHub's sign-in returns to on Android, iOS and macOS, as
|
||||
// each platform's project registers it for the app.
|
||||
callbackScheme: 'app.halkyon.learn',
|
||||
appName: 'Halkyon Learn',
|
||||
);
|
||||
final addresses = FileSignInAddresses(device.storage.peopleOf(instance));
|
||||
final accountCrypto = SodiumAccountCrypto();
|
||||
|
|
|
|||
|
|
@ -107,9 +107,8 @@ class const _Account() extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
/// How the person signs in: GitHub where they have it (it is added to
|
||||
/// nobody any more, ADR 0020, D25), an email address, and SimpleLogin
|
||||
/// (D21), with the password and authenticators beneath.
|
||||
/// How the person signs in: an email address, and SimpleLogin (ADR 0020,
|
||||
/// D21), with the password and authenticators beneath.
|
||||
class const _SignInWays() extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -127,7 +126,6 @@ class const _SignInWays() extends StatelessWidget {
|
|||
children: [
|
||||
const SizedBox(height: 16),
|
||||
Text(l10n.profileSignInWays, style: theme.textTheme.titleSmall),
|
||||
if (ways.ways.gitHub) way(l10n.profileWayGitHub, l10n.profileWayLinked),
|
||||
if (ways.ways.email)
|
||||
way(l10n.profileWayEmail, ways.emailAddress ?? l10n.profileWayLinked),
|
||||
// SimpleLogin (ADR 0020, D21): once added, one more way in here.
|
||||
|
|
|
|||
|
|
@ -47,10 +47,13 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('an account without a password sets one up: the address, the '
|
||||
'phrase checked, the handle it lacks, the code, the authenticator', (
|
||||
tester,
|
||||
) async {
|
||||
testWidgets('an account with an address and no password sets one up: the '
|
||||
'address, the phrase checked, the handle it lacks, the code, the '
|
||||
'authenticator', (tester) async {
|
||||
passwords.addAddressOnly(
|
||||
'anna@example.org',
|
||||
person: FakeAuthGateway.person.authUserId,
|
||||
);
|
||||
await openProfile(tester);
|
||||
|
||||
await tester.tap(find.text('Set up a password'));
|
||||
|
|
@ -105,28 +108,6 @@ void main() {
|
|||
expect(find.text('Change password'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('someone who signs in with GitHub is told when it ends, and '
|
||||
'offered a password', (tester) async {
|
||||
auth = FakeAuthGateway(
|
||||
status: const SignedIn(authUserId: 'github-person', isIdentified: true),
|
||||
)..gitHubPeople.add('github-person');
|
||||
passwords = FakePasswordGateway(auth)
|
||||
..gitHubPeople.add('github-person')
|
||||
..gitHubEnds = DateTime.utc(2027, 1, 22);
|
||||
await openProfile(tester);
|
||||
|
||||
expect(find.textContaining('Sign-in with GitHub ends on'), findsOneWidget);
|
||||
// Without an address, the account goes 30 days after the end (the full
|
||||
// reading's M1, the short reading's day).
|
||||
expect(
|
||||
find.textContaining(
|
||||
'an account without one is deleted 30 days later, with everything',
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Set up a password'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('no password where the instance offers none', (tester) async {
|
||||
passwords.offered = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import '../../../support/pump_app.dart';
|
|||
import '../../../support/test_dependencies.dart';
|
||||
|
||||
// The Profile tab's account card: the ways the person signs in, SimpleLogin
|
||||
// to add (ADR 0020, D21) and nothing else to add, as GitHub is added to
|
||||
// nobody any more (D25).
|
||||
// to add (ADR 0020, D21) and nothing else to add, as GitHub signs nobody in
|
||||
// any more (D36).
|
||||
void main() {
|
||||
late FakeAuthGateway auth;
|
||||
late FakeSimpleLoginGateway simpleLogin;
|
||||
|
|
@ -33,20 +33,8 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
testWidgets('an account with GitHub sees it signs them in, with nothing to '
|
||||
'add', (tester) async {
|
||||
auth.gitHubPeople.add(FakeAuthGateway.person.authUserId);
|
||||
|
||||
await openProfile(tester);
|
||||
|
||||
expect(find.text('GitHub'), findsOneWidget);
|
||||
expect(find.text('Signs you in'), findsWidgets);
|
||||
expect(find.text('Add GitHub'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('an account without GitHub is offered none to add (D25)', (
|
||||
tester,
|
||||
) async {
|
||||
testWidgets('an account lists its address, and no GitHub to have or add '
|
||||
'(D36)', (tester) async {
|
||||
auth.addressOwners['ada@example.org'] = FakeAuthGateway.person.authUserId;
|
||||
|
||||
await openProfile(tester);
|
||||
|
|
|
|||
|
|
@ -90,47 +90,14 @@ void main() {
|
|||
expect(find.text('Start on learn.example.org:'), findsOneWidget);
|
||||
expect(find.text('Sign in'), findsOneWidget);
|
||||
expect(find.text('Create an account'), findsOneWidget);
|
||||
expect(find.text('Sign in with GitHub'), findsOneWidget);
|
||||
expect(
|
||||
find.textContaining('GitHub'),
|
||||
findsNothing,
|
||||
reason: 'GitHub signs nobody in any more (ADR 0020, D36)',
|
||||
);
|
||||
expect(find.text('Start without an account'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('from there, GitHub signs in its person', (tester) async {
|
||||
await signOut(tester);
|
||||
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
// A password is offered first (ADR 0017, D2); put off, the app.
|
||||
await tester.tap(find.text('Later'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
gateway.status,
|
||||
const SignedIn(authUserId: 'github-person', isIdentified: true),
|
||||
);
|
||||
expect(home, findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('from there, a GitHub account nobody here signs in with is said '
|
||||
'so, with an account to create in its place where passwords are '
|
||||
'offered (ADR 0017)', (tester) async {
|
||||
await signOut(tester);
|
||||
|
||||
gateway.gitHubError = const GitHubSignInFailed(
|
||||
GitHubSignInProblem.unknownAccount,
|
||||
);
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.text(
|
||||
'No account here signs in with this GitHub account. Create an '
|
||||
'account with your email address and a password instead.',
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(gateway.status, const SignedOut());
|
||||
});
|
||||
|
||||
testWidgets('where an instance offers no way to make an account, it says '
|
||||
'so', (tester) async {
|
||||
await signOut(tester, passwords: false);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ void main() {
|
|||
testDependencies(
|
||||
authGateway: FakeAuthGateway(
|
||||
status: const SignedIn(
|
||||
authUserId: 'github-person',
|
||||
authUserId: 'person-2',
|
||||
isIdentified: true,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ void main() {
|
|||
testDependencies(
|
||||
authGateway: FakeAuthGateway(
|
||||
status: const SignedIn(
|
||||
authUserId: 'github-person',
|
||||
authUserId: 'person-2',
|
||||
isIdentified: true,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ void main() {
|
|||
testDependencies(
|
||||
authGateway: FakeAuthGateway(
|
||||
status: const SignedIn(
|
||||
authUserId: 'github-person',
|
||||
authUserId: 'person-2',
|
||||
isIdentified: true,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ void main() {
|
|||
testDependencies(
|
||||
authGateway: FakeAuthGateway(
|
||||
status: const SignedIn(
|
||||
authUserId: 'github-person',
|
||||
authUserId: 'person-2',
|
||||
isIdentified: true,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ void main() {
|
|||
testDependencies(
|
||||
authGateway: FakeAuthGateway(
|
||||
status: const SignedIn(
|
||||
authUserId: 'github-person',
|
||||
authUserId: 'person-2',
|
||||
isIdentified: true,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1872,10 +1872,8 @@ void main() {
|
|||
expect(find.text('Japanese'), findsNothing);
|
||||
expect(find.text('Start on learn.example.org:'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('Sign in with GitHub'));
|
||||
await tester.pumpAndSettle();
|
||||
// A password is offered first (ADR 0017, D2); put off, the app.
|
||||
await tester.tap(find.text('Later'));
|
||||
// Another person signs in, as a sign-in's session put in place does it.
|
||||
auth.signIn('person-2');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Japanese'), findsNothing);
|
||||
|
|
|
|||
Loading…
Reference in a new issue