fix(auth): a code's mail names its purpose in the subject

A notification shows a mail's subject alone, and the subject said only
"K7QX-M2PD is your Halkyon Learn code" whatever the code would do (the
third reading). The subject now says it: to create an account, finish
setting it up, switch off the authenticator, reset or delete the account.
The sign-up mail also says that the code gives a password to an account
that has the address and none yet, as signing up does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-21 10:44:10 +02:00
commit ad52da5a94
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 113 additions and 10 deletions

View file

@ -83,7 +83,9 @@ final class LogCodeMailer implements CodeMailer {
/// into, and [instance] the instance's address. The mail says what the code
/// would do ([purpose]: the re-review's seventh finding), so that whoever
/// is asked for it by another than [app] on [instance] sees what they would
/// hand over, and that only there may it be typed.
/// hand over, and that only there may it be typed; its subject names the
/// purpose too, as a notification shows the subject alone (the third
/// reading).
({String subject, String body}) codeMail({
required String code,
required EmailCodePurpose purpose,
@ -93,12 +95,21 @@ final class LogCodeMailer implements CodeMailer {
}) => switch (language) {
'de' => (
// A compound with the name, hyphenated through: Halkyon-Learn-Code.
subject: '$code ist dein ${app.replaceAll(' ', '-')}-Code',
subject:
'$code: dein ${app.replaceAll(' ', '-')}-Code, ${switch (purpose) {
EmailCodePurpose.signUp => 'um ein Konto anzulegen',
EmailCodePurpose.finishSetup => 'um dein Konto fertig einzurichten',
EmailCodePurpose.authenticatorReset => 'um deine Authenticator-App abzuschalten',
EmailCodePurpose.accountReset => 'um dein Konto zurückzusetzen',
EmailCodePurpose.deletion => 'um dein Konto zu löschen',
}}',
body:
'$code\n'
'\n'
'Gib diesen Code in $app ein, ${switch (purpose) {
EmailCodePurpose.signUp => 'um dein Konto auf $instance anzulegen',
EmailCodePurpose.signUp => 'um dein Konto auf $instance anzulegen (oder, hat '
'dort schon ein Konto diese Adresse und noch kein Passwort, '
'ihm eines zu geben)',
EmailCodePurpose.finishSetup => 'um die Einrichtung deines Kontos auf $instance abzuschließen',
EmailCodePurpose.authenticatorReset => 'um die Codes deiner Authenticator-App für dein Konto auf '
'$instance abzuschalten (72 Stunden später)',
@ -118,12 +129,20 @@ final class LogCodeMailer implements CodeMailer {
'schreibt ihr nur, wenn du einen Code anforderst.\n',
),
_ => (
subject: '$code is your $app code',
subject:
'$code: your $app code to ${switch (purpose) {
EmailCodePurpose.signUp => 'create an account',
EmailCodePurpose.finishSetup => 'finish setting up your account',
EmailCodePurpose.authenticatorReset => 'switch off your authenticator',
EmailCodePurpose.accountReset => 'reset your account',
EmailCodePurpose.deletion => 'delete your account',
}}',
body:
'$code\n'
'\n'
'Type this code in $app ${switch (purpose) {
EmailCodePurpose.signUp => 'to create your account on $instance',
EmailCodePurpose.signUp => 'to create your account on $instance (or, should an account '
'there have this address and no password yet, to give it one)',
EmailCodePurpose.finishSetup => 'to finish setting up your account on $instance',
EmailCodePurpose.authenticatorReset => "to switch off your authenticator app's codes for your account "
'on $instance (72 hours later)',

View file

@ -98,7 +98,10 @@ void main() {
purpose: EmailCodePurpose.signUp,
);
expect(mail.subject, 'K7QX-M2PD is your Halkyon Learn code');
expect(
mail.subject,
'K7QX-M2PD: your Halkyon Learn code to create an account',
);
expect(mail.body, startsWith('K7QX-M2PD\n\n'));
expect(mail.body, contains('create your account on learn.halkyon.eu'));
expect(mail.body, contains('15 minutes'));
@ -154,6 +157,75 @@ void main() {
);
});
test('names its purpose in the subject, which a notification shows '
'alone (the third reading)', () {
String subjectOf(EmailCodePurpose purpose, String language) => codeMail(
code: 'K7QX-M2PD',
language: language,
app: 'Halkyon Learn',
instance: 'learn.halkyon.eu',
purpose: purpose,
).subject;
const english = {
EmailCodePurpose.signUp:
'K7QX-M2PD: your Halkyon Learn code to create an account',
EmailCodePurpose.finishSetup:
'K7QX-M2PD: your Halkyon Learn code to finish setting up your '
'account',
EmailCodePurpose.authenticatorReset:
'K7QX-M2PD: your Halkyon Learn code to switch off your '
'authenticator',
EmailCodePurpose.accountReset:
'K7QX-M2PD: your Halkyon Learn code to reset your account',
EmailCodePurpose.deletion:
'K7QX-M2PD: your Halkyon Learn code to delete your account',
};
const german = {
EmailCodePurpose.signUp:
'K7QX-M2PD: dein Halkyon-Learn-Code, um ein Konto anzulegen',
EmailCodePurpose.finishSetup:
'K7QX-M2PD: dein Halkyon-Learn-Code, um dein Konto fertig '
'einzurichten',
EmailCodePurpose.authenticatorReset:
'K7QX-M2PD: dein Halkyon-Learn-Code, um deine Authenticator-App '
'abzuschalten',
EmailCodePurpose.accountReset:
'K7QX-M2PD: dein Halkyon-Learn-Code, um dein Konto zurückzusetzen',
EmailCodePurpose.deletion:
'K7QX-M2PD: dein Halkyon-Learn-Code, um dein Konto zu löschen',
};
for (final purpose in EmailCodePurpose.values) {
expect(subjectOf(purpose, 'en'), english[purpose]);
expect(subjectOf(purpose, 'de'), german[purpose]);
}
});
test('for signing up, says it also gives a password to an account with '
'that address and none yet', () {
({String subject, String body}) mailIn(String language) => codeMail(
code: 'K7QX-M2PD',
language: language,
app: 'Halkyon Learn',
instance: 'learn.halkyon.eu',
purpose: EmailCodePurpose.signUp,
);
expect(
mailIn('en').body,
contains(
'or, should an account there have this address and no password '
'yet, to give it one',
),
);
expect(
mailIn('de').body,
contains(
'oder, hat dort schon ein Konto diese Adresse und noch kein '
'Passwort, ihm eines zu geben',
),
);
});
test('in German for German, in English for anything else', () {
({String subject, String body}) mailIn(String language) => codeMail(
code: 'K7QX-M2PD',
@ -163,8 +235,14 @@ void main() {
purpose: EmailCodePurpose.signUp,
);
expect(mailIn('de').subject, 'K7QX-M2PD ist dein Halkyon-Learn-Code');
expect(mailIn('fr').subject, 'K7QX-M2PD is your Halkyon Learn code');
expect(
mailIn('de').subject,
'K7QX-M2PD: dein Halkyon-Learn-Code, um ein Konto anzulegen',
);
expect(
mailIn('fr').subject,
'K7QX-M2PD: your Halkyon Learn code to create an account',
);
});
test('names the app the host is, in its text too', () {
@ -176,9 +254,15 @@ void main() {
purpose: EmailCodePurpose.signUp,
);
expect(mailIn('en').subject, 'K7QX-M2PD is your Halkyon Todo code');
expect(
mailIn('en').subject,
'K7QX-M2PD: your Halkyon Todo code to create an account',
);
expect(mailIn('en').body, contains('Type this code in Halkyon Todo'));
expect(mailIn('de').subject, 'K7QX-M2PD ist dein Halkyon-Todo-Code');
expect(
mailIn('de').subject,
'K7QX-M2PD: dein Halkyon-Todo-Code, um ein Konto anzulegen',
);
expect(mailIn('de').body, contains('Gib diesen Code in Halkyon Todo'));
});
});