From efd3dfbde5dca7874a43266d60aed30c4693b2b5 Mon Sep 17 00:00:00 2001 From: Aliaksei Tratseuski Date: Thu, 13 Jun 2024 21:53:06 +0400 Subject: [PATCH] feat: obscure/remove auth headers from console logs --- lib/logic/models/console_log.dart | 16 ++-- .../more/console/console_log_item_dialog.dart | 79 ++++++++++++++++--- pubspec.lock | 8 ++ pubspec.yaml | 1 + 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/lib/logic/models/console_log.dart b/lib/logic/models/console_log.dart index 22e1c93e..91cef018 100644 --- a/lib/logic/models/console_log.dart +++ b/lib/logic/models/console_log.dart @@ -10,10 +10,6 @@ enum ConsoleLogSeverity { } /// Base entity for console logs. -/// -/// TODO(misterfourtytwo): should we add? -/// -/// * equality override sealed class ConsoleLog { ConsoleLog({ final String? customTitle, @@ -75,6 +71,8 @@ class RestApiRequestConsoleLog extends ConsoleLog { super.severity, }); + static const blacklistedHeaders = ['Authorization']; + final String? method; final Uri? uri; final Map? headers; @@ -82,10 +80,18 @@ class RestApiRequestConsoleLog extends ConsoleLog { @override String get title => 'Rest API Request'; + + Map get filteredHeaders => Map.fromEntries( + headers?.entries.where( + (final entry) => !blacklistedHeaders.contains(entry.key), + ) ?? + const [], + ); + @override String get content => '"method": "$method",\n' '"uri": "$uri",\n' - '"headers": ${jsonEncode(headers)},\n' + '"headers": ${jsonEncode(filteredHeaders)},\n' // censor header to not expose API keys '"data": $data'; } diff --git a/lib/ui/pages/more/console/console_log_item_dialog.dart b/lib/ui/pages/more/console/console_log_item_dialog.dart index 15310103..5cb20142 100644 --- a/lib/ui/pages/more/console/console_log_item_dialog.dart +++ b/lib/ui/pages/more/console/console_log_item_dialog.dart @@ -1,4 +1,5 @@ import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/logic/models/console_log.dart'; import 'package:selfprivacy/utils/platform_adapter.dart'; @@ -202,23 +203,81 @@ class _SectionRow extends StatelessWidget { class _KeyValueRow extends StatelessWidget { const _KeyValueRow(this.title, this.value); + static const List hideList = ['Authorization']; + final String title; final String? value; + @override + Widget build(final BuildContext context) => hideList.contains(title) + ? _ObscuredKeyValueRow(title, value) + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: SelectableText.rich( + TextSpan( + style: DefaultTextStyle.of(context).style, + children: [ + TextSpan( + text: '$title: ', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + TextSpan(text: value ?? ''), + ], + ), + ), + ); +} + +class _ObscuredKeyValueRow extends StatefulWidget { + const _ObscuredKeyValueRow(this.title, this.value); + + final String title; + final String? value; + + @override + State<_ObscuredKeyValueRow> createState() => _ObscuredKeyValueRowState(); +} + +class _ObscuredKeyValueRowState extends State<_ObscuredKeyValueRow> { + static const obscuringCharacter = '•'; + bool _obscureValue = true; + @override Widget build(final BuildContext context) => Padding( padding: const EdgeInsets.symmetric(horizontal: 12), - child: SelectableText.rich( - TextSpan( - style: DefaultTextStyle.of(context).style, - children: [ - TextSpan( - text: '$title: ', - style: const TextStyle(fontWeight: FontWeight.bold), + child: Row( + children: [ + Expanded( + child: SelectableText.rich( + TextSpan( + style: DefaultTextStyle.of(context).style, + children: [ + TextSpan( + text: '${widget.title}: ', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + TextSpan( + text: _obscureValue + ? obscuringCharacter * (widget.value?.length ?? 4) + : widget.value ?? '', + style: const TextStyle( + fontFeatures: [FontFeature.tabularFigures()], + ), + ), + ], + ), ), - TextSpan(text: value ?? ''), - ], - ), + ), + IconButton( + icon: Icon( + _obscureValue ? CupertinoIcons.eye : CupertinoIcons.eye_slash, + ), + onPressed: () { + _obscureValue ^= true; // toggle value + setState(() {}); + }, + ), + ], ), ); } diff --git a/pubspec.lock b/pubspec.lock index 7187e937..8f635adb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -257,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + cupertino_icons: + dependency: "direct dev" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" dart_style: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6c7ad7d3..3872d6e2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: dev_dependencies: auto_route_generator: ^8.0.0 build_runner: ^2.4.9 + cupertino_icons: ^1.0.8 flutter_launcher_icons: ^0.13.1 flutter_lints: ^3.0.2 flutter_test: