getActiveFirebaseAccount method

Future<String?> getActiveFirebaseAccount()

Email of the user the Firebase CLI is logged in as (firebase login:list --json), or null when no login is stored.

Why this matters: the Firebase CLI prefers a stored login token at ~/.config/configstore/firebase-tools.json over GOOGLE_APPLICATION_ CREDENTIALS. So a user who did firebase login previously as a personal account that does NOT have firebase.admin on the configured project will hit firebase apps:list PERMISSION_DENIED even though Oracular set GOOGLE_APPLICATION_CREDENTIALS to a service-account JSON that does have the role.

Used by _logCredentialDiagnostics to surface "you're authenticated as <user>, but the SA is <other> — these don't match" so the user can firebase logout and let Oracular's SA auth take over.

Implementation

Future<String?> getActiveFirebaseAccount() async {
  final ProcessResult r = await _runner.run('firebase', <String>[
    'login:list',
    '--json',
  ]);
  if (!r.success) return null;
  try {
    final dynamic decoded = jsonDecode(_stripAnsi(r.stdout));
    if (decoded is Map<String, dynamic>) {
      final dynamic result = decoded['result'];
      if (result is List && result.isNotEmpty) {
        final dynamic first = result.first;
        if (first is Map<String, dynamic>) {
          final dynamic user = first['user'];
          if (user is Map<String, dynamic>) {
            final dynamic email = user['email'];
            if (email is String && email.trim().isNotEmpty) {
              return email.trim();
            }
          }
          // Some firebase CLI versions return the email at the top level.
          final dynamic email = first['email'];
          if (email is String && email.trim().isNotEmpty) {
            return email.trim();
          }
        } else if (first is String && first.trim().isNotEmpty) {
          return first.trim();
        }
      }
    } else if (decoded is List && decoded.isNotEmpty) {
      final dynamic first = decoded.first;
      if (first is String && first.trim().isNotEmpty) return first.trim();
    }
  } catch (_) {
    // Older firebase CLI doesn't support --json on login:list; parse
    // the text output as a fallback ("Logged in as <email>").
    final RegExp emailRe = RegExp(r'([\w.+-]+@[\w-]+\.[\w.-]+)');
    final Match? match = emailRe.firstMatch(_stripAnsi(r.stdout));
    if (match != null) return match.group(1);
  }
  return null;
}