fix(app): no state logs an authenticator's key, codes or the address

Equatable's own text lists every field, and a debug build's bloc observer
logs every state, so an authenticator's otpauth URI with its secret, the
recovery codes and the address went into the log. The password states
(signing in, getting back in, adding an authenticator, a step of the
account section) and AuthenticatorSetup now say only where they stand, as
the setup and new-phrase states did; Learn's observer takes a writer so
its test holds what it logs to that.

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 14:46:35 +02:00
commit 5067d11c18
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -2,13 +2,25 @@ import 'dart:developer';
import 'package:flutter_bloc/flutter_bloc.dart';
/// Writes [message] under [name]: `dart:developer`'s [log], or what a test
/// collects.
typedef BlocLogWriter = void Function(String message, {required String name});
void _log(String message, {required String name}) => log(message, name: name);
/// The one observer of all blocs: logs every state change and error, so bloc
/// behaviour can be followed without adding logging to each bloc.
class const AppBlocObserver() extends BlocObserver {
///
/// A state's text is what it says of itself: states holding secrets (an
/// authenticator's key, recovery codes, a recovery phrase, an address) say
/// only where they stand (halkyon_app's password states, ADR 0017), which
/// `app_bloc_observer_test.dart` holds them to.
class const AppBlocObserver({final BlocLogWriter write = _log})
extends BlocObserver {
@override
void onChange(BlocBase<dynamic> bloc, Change<dynamic> change) {
super.onChange(bloc, change);
log(
write(
'${change.currentState} → ${change.nextState}',
name: '${bloc.runtimeType}',
);