add fingerprinting configuration
This commit is contained in:
@@ -43,6 +43,7 @@ import 'package:weblibre/features/settings/presentation/screens/addon_collection
|
||||
import 'package:weblibre/features/settings/presentation/screens/bang_settings.dart';
|
||||
import 'package:weblibre/features/settings/presentation/screens/developer_settings.dart';
|
||||
import 'package:weblibre/features/settings/presentation/screens/doh_settings.dart';
|
||||
import 'package:weblibre/features/settings/presentation/screens/fingerprint_settings.dart';
|
||||
import 'package:weblibre/features/settings/presentation/screens/general_settings.dart';
|
||||
import 'package:weblibre/features/settings/presentation/screens/settings.dart';
|
||||
import 'package:weblibre/features/settings/presentation/screens/web_engine_hardening.dart';
|
||||
|
||||
@@ -111,6 +111,11 @@ RouteBase get $settingsRoute => GoRouteData.$route(
|
||||
name: 'DohSettingsRoute',
|
||||
factory: $DohSettingsRoute._fromState,
|
||||
),
|
||||
GoRouteData.$route(
|
||||
path: 'fingerprint',
|
||||
name: 'FingerprintSettingsRoute',
|
||||
factory: $FingerprintSettingsRoute._fromState,
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRouteData.$route(
|
||||
@@ -279,6 +284,28 @@ mixin $DohSettingsRoute on GoRouteData {
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
mixin $FingerprintSettingsRoute on GoRouteData {
|
||||
static FingerprintSettingsRoute _fromState(GoRouterState state) =>
|
||||
FingerprintSettingsRoute();
|
||||
|
||||
@override
|
||||
String get location =>
|
||||
GoRouteData.$location('/settings/web_engine/fingerprint');
|
||||
|
||||
@override
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@override
|
||||
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
|
||||
|
||||
@override
|
||||
void pushReplacement(BuildContext context) =>
|
||||
context.pushReplacement(location);
|
||||
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
mixin $DeveloperSettingsRoute on GoRouteData {
|
||||
static DeveloperSettingsRoute _fromState(GoRouterState state) =>
|
||||
DeveloperSettingsRoute();
|
||||
|
||||
@@ -43,6 +43,10 @@ part of 'routes.dart';
|
||||
],
|
||||
),
|
||||
TypedGoRoute<DohSettingsRoute>(name: 'DohSettingsRoute', path: 'doh'),
|
||||
TypedGoRoute<FingerprintSettingsRoute>(
|
||||
name: 'FingerprintSettingsRoute',
|
||||
path: 'fingerprint',
|
||||
),
|
||||
],
|
||||
),
|
||||
TypedGoRoute<DeveloperSettingsRoute>(
|
||||
@@ -85,6 +89,14 @@ class DohSettingsRoute extends GoRouteData with $DohSettingsRoute {
|
||||
}
|
||||
}
|
||||
|
||||
class FingerprintSettingsRoute extends GoRouteData
|
||||
with $FingerprintSettingsRoute {
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
return const FingerprintSettingsScreen();
|
||||
}
|
||||
}
|
||||
|
||||
class WebEngineSettingsRoute extends GoRouteData with $WebEngineSettingsRoute {
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
|
||||
+6
@@ -128,6 +128,12 @@ class EngineSettingsReplicationService
|
||||
if (previous.value?.dohSettings != settings.dohSettings) {
|
||||
await _service.dohSettings(settings.dohSettings);
|
||||
}
|
||||
if (previous.value?.fingerprintingProtectionOverrides !=
|
||||
settings.fingerprintingProtectionOverrides) {
|
||||
await _service.fingerprintingProtectionOverrides(
|
||||
settings.fingerprintingProtectionOverrides,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await _service.setDefaultSettings(settings);
|
||||
initialSettingsSent = true;
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ final class EngineSettingsReplicationServiceProvider
|
||||
}
|
||||
|
||||
String _$engineSettingsReplicationServiceHash() =>
|
||||
r'0bbc80fe0cff79f9e419ffa8c486d232f9eac2ee';
|
||||
r'3c96e6e45537399582fdf6e8b1fafc44c613b89d';
|
||||
|
||||
abstract class _$EngineSettingsReplicationService extends $Notifier<void> {
|
||||
void build();
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart';
|
||||
import 'package:weblibre/features/user/data/models/engine_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/entities/fingerprint_overrides.dart';
|
||||
import 'package:weblibre/features/user/domain/providers.dart';
|
||||
import 'package:weblibre/features/user/domain/services/fingerprinting.dart';
|
||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||
|
||||
class FingerprintSettingsScreen extends HookConsumerWidget {
|
||||
const FingerprintSettingsScreen();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final targetsAsync = ref.watch(fingerprintTargetsProvider);
|
||||
final settingsAsync = ref.watch(fingerprintOverrideSettingsProvider);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Fingerprint Protection'),
|
||||
actions: [
|
||||
MenuAnchor(
|
||||
builder: (context, controller, child) {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
controller.open();
|
||||
},
|
||||
icon: const Icon(Icons.more_vert),
|
||||
);
|
||||
},
|
||||
menuChildren: [
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(MdiIcons.restore),
|
||||
child: const Text('Load Defaults'),
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(saveEngineSettingsControllerProvider.notifier)
|
||||
.save(
|
||||
(currentSettings) => currentSettings.copyWith
|
||||
.fingerprintingProtectionOverrides(
|
||||
FingerprintOverrides.defaults().toString(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
MenuItemButton(
|
||||
leadingIcon: const Icon(MdiIcons.restore),
|
||||
child: const Text('Load Hardened Defaults'),
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(saveEngineSettingsControllerProvider.notifier)
|
||||
.save(
|
||||
(currentSettings) => currentSettings.copyWith
|
||||
.fingerprintingProtectionOverrides(
|
||||
FingerprintOverrides.hardenedDefaults()
|
||||
.toString(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: settingsAsync.when(
|
||||
data: (result) {
|
||||
return result.fold(
|
||||
(overrides) {
|
||||
return targetsAsync.when(
|
||||
data: (targets) {
|
||||
return ListView.builder(
|
||||
itemCount: targets.length,
|
||||
itemBuilder: (context, index) {
|
||||
final target = targets[index];
|
||||
final state = overrides.targets[target.name];
|
||||
|
||||
return CheckboxListTile.adaptive(
|
||||
value:
|
||||
(overrides.allTargets == true &&
|
||||
state != false) ||
|
||||
state == true,
|
||||
onChanged: (value) async {
|
||||
if (value != null) {
|
||||
final newOverrides = overrides
|
||||
.copyWithTarget(target.name, value)
|
||||
.toString();
|
||||
|
||||
await ref
|
||||
.read(
|
||||
saveEngineSettingsControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) => currentSettings
|
||||
.copyWith
|
||||
.fingerprintingProtectionOverrides(
|
||||
newOverrides,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
title: Text(target.name),
|
||||
subtitle: target.description.mapNotNull(
|
||||
(desc) => Text(desc),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) {
|
||||
return Center(
|
||||
child: FailureWidget(
|
||||
exception: error,
|
||||
onRetry: () {
|
||||
ref.invalidate(fingerprintTargetsProvider);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
loading: () =>
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
},
|
||||
onFailure: (errorMessage) {
|
||||
return Center(
|
||||
child: FailureWidget(
|
||||
title: errorMessage.message,
|
||||
exception: errorMessage.details,
|
||||
onRetry: () {
|
||||
ref.invalidate(fingerprintOverrideSettingsProvider);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
error: (error, stackTrace) {
|
||||
return Center(
|
||||
child: FailureWidget(
|
||||
exception: error,
|
||||
onRetry: () {
|
||||
ref.invalidate(fingerprintOverrideSettingsProvider);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -475,6 +475,18 @@ class WebEngineSettingsScreen extends HookConsumerWidget {
|
||||
await WebEngineHardeningRoute().push(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Fingerprint Protection'),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
horizontal: 16.0,
|
||||
),
|
||||
leading: const Icon(MdiIcons.fingerprint),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () async {
|
||||
await FingerprintSettingsRoute().push(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -24,6 +24,7 @@ import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:weblibre/features/user/domain/entities/fingerprint_overrides.dart';
|
||||
|
||||
part 'engine_settings.g.dart';
|
||||
|
||||
@@ -125,6 +126,7 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
|
||||
required this.dohProviderUrl,
|
||||
required this.dohDefaultProviderUrl,
|
||||
required this.dohExceptionsList,
|
||||
required super.fingerprintingProtectionOverrides,
|
||||
});
|
||||
|
||||
EngineSettings.withDefaults({
|
||||
@@ -147,6 +149,7 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
|
||||
String? dohProviderUrl,
|
||||
String? dohDefaultProviderUrl,
|
||||
List<String>? dohExceptionsList,
|
||||
String? fingerprintingProtectionOverrides,
|
||||
}) : queryParameterStripping =
|
||||
queryParameterStripping ?? QueryParameterStripping.disabled,
|
||||
bounceTrackingProtectionMode =
|
||||
@@ -177,6 +180,9 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
|
||||
webContentIsolationStrategy ??
|
||||
WebContentIsolationStrategy.isolateHighValue,
|
||||
enterpriseRootsEnabled: enterpriseRootsEnabled ?? false,
|
||||
fingerprintingProtectionOverrides:
|
||||
fingerprintingProtectionOverrides ??
|
||||
FingerprintOverrides.defaults().toString(),
|
||||
);
|
||||
|
||||
static AddonCollection? _addonCollectionFromJson(String? json) =>
|
||||
@@ -201,5 +207,6 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
|
||||
dohProviderUrl,
|
||||
dohDefaultProviderUrl,
|
||||
dohExceptionsList,
|
||||
fingerprintingProtectionOverrides,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ abstract class _$EngineSettingsCWProxy {
|
||||
|
||||
EngineSettings dohExceptionsList(List<String> dohExceptionsList);
|
||||
|
||||
EngineSettings fingerprintingProtectionOverrides(
|
||||
String? fingerprintingProtectionOverrides,
|
||||
);
|
||||
|
||||
/// Creates a new instance with the provided field values.
|
||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `EngineSettings(...).copyWith.fieldName(value)`.
|
||||
///
|
||||
@@ -88,6 +92,7 @@ abstract class _$EngineSettingsCWProxy {
|
||||
String dohProviderUrl,
|
||||
String dohDefaultProviderUrl,
|
||||
List<String> dohExceptionsList,
|
||||
String? fingerprintingProtectionOverrides,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -188,6 +193,13 @@ class _$EngineSettingsCWProxyImpl implements _$EngineSettingsCWProxy {
|
||||
EngineSettings dohExceptionsList(List<String> dohExceptionsList) =>
|
||||
call(dohExceptionsList: dohExceptionsList);
|
||||
|
||||
@override
|
||||
EngineSettings fingerprintingProtectionOverrides(
|
||||
String? fingerprintingProtectionOverrides,
|
||||
) => call(
|
||||
fingerprintingProtectionOverrides: fingerprintingProtectionOverrides,
|
||||
);
|
||||
|
||||
@override
|
||||
/// Creates a new instance with the provided field values.
|
||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `EngineSettings(...).copyWith.fieldName(value)`.
|
||||
@@ -218,6 +230,7 @@ class _$EngineSettingsCWProxyImpl implements _$EngineSettingsCWProxy {
|
||||
Object? dohProviderUrl = const $CopyWithPlaceholder(),
|
||||
Object? dohDefaultProviderUrl = const $CopyWithPlaceholder(),
|
||||
Object? dohExceptionsList = const $CopyWithPlaceholder(),
|
||||
Object? fingerprintingProtectionOverrides = const $CopyWithPlaceholder(),
|
||||
}) {
|
||||
return EngineSettings(
|
||||
javascriptEnabled: javascriptEnabled == const $CopyWithPlaceholder()
|
||||
@@ -319,6 +332,11 @@ class _$EngineSettingsCWProxyImpl implements _$EngineSettingsCWProxy {
|
||||
? _value.dohExceptionsList
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: dohExceptionsList as List<String>,
|
||||
fingerprintingProtectionOverrides:
|
||||
fingerprintingProtectionOverrides == const $CopyWithPlaceholder()
|
||||
? _value.fingerprintingProtectionOverrides
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: fingerprintingProtectionOverrides as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -388,12 +406,16 @@ EngineSettings _$EngineSettingsFromJson(Map<String, dynamic> json) =>
|
||||
dohExceptionsList: (json['dohExceptionsList'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList(),
|
||||
fingerprintingProtectionOverrides:
|
||||
json['fingerprintingProtectionOverrides'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$EngineSettingsToJson(
|
||||
EngineSettings instance,
|
||||
) => <String, dynamic>{
|
||||
'userAgent': instance.userAgent,
|
||||
'fingerprintingProtectionOverrides':
|
||||
instance.fingerprintingProtectionOverrides,
|
||||
'javascriptEnabled': instance.javascriptEnabled,
|
||||
'trackingProtectionPolicy':
|
||||
_$TrackingProtectionPolicyEnumMap[instance.trackingProtectionPolicy]!,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'rfp_target.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class RFPTarget with FastEquatable {
|
||||
final String name;
|
||||
final int id;
|
||||
final String? description;
|
||||
final List<String> keywords;
|
||||
|
||||
RFPTarget({
|
||||
required this.name,
|
||||
required this.id,
|
||||
this.description,
|
||||
required this.keywords,
|
||||
});
|
||||
|
||||
factory RFPTarget.fromJson(Map<String, dynamic> json) =>
|
||||
_$RFPTargetFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$RFPTargetToJson(this);
|
||||
|
||||
@override
|
||||
List<Object?> get hashParameters => [name, id, description, keywords];
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'rfp_target.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
RFPTarget _$RFPTargetFromJson(Map<String, dynamic> json) => RFPTarget(
|
||||
name: json['name'] as String,
|
||||
id: (json['id'] as num).toInt(),
|
||||
description: json['description'] as String?,
|
||||
keywords: (json['keywords'] as List<dynamic>)
|
||||
.map((e) => e as String)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$RFPTargetToJson(RFPTarget instance) => <String, dynamic>{
|
||||
'name': instance.name,
|
||||
'id': instance.id,
|
||||
'description': instance.description,
|
||||
'keywords': instance.keywords,
|
||||
};
|
||||
@@ -0,0 +1,174 @@
|
||||
import 'package:exceptions/exceptions.dart';
|
||||
import 'package:fast_equatable/fast_equatable.dart';
|
||||
|
||||
class FingerprintOverrides with FastEquatable {
|
||||
static final pattern = RegExp('([+-])([a-zA-Z_][a-zA-Z0-9_]{1,64})');
|
||||
|
||||
final bool? allTargets;
|
||||
final Map<String, bool> targets;
|
||||
|
||||
FingerprintOverrides(this.allTargets, this.targets);
|
||||
|
||||
//Monitor https://searchfox.org/firefox-main/source/toolkit/components/resistfingerprinting/RFPTargetsDefault.inc
|
||||
FingerprintOverrides.defaults()
|
||||
: this(false, {
|
||||
'CanvasRandomization': true,
|
||||
'EfficientCanvasRandomization': true,
|
||||
'FontVisibilityLangPack': true,
|
||||
'JSMathFdlibm': true,
|
||||
'ScreenAvailToResolution': true,
|
||||
'NavigatorHWConcurrencyTiered': true,
|
||||
'MaxTouchPointsCollapse': true,
|
||||
});
|
||||
|
||||
FingerprintOverrides.hardenedDefaults()
|
||||
: this(false, {
|
||||
'TouchEvents': true,
|
||||
'PointerEvents': true,
|
||||
'KeyboardEvents': true,
|
||||
'ScreenOrientation': true,
|
||||
'SpeechSynthesis': true,
|
||||
'CSSPrefersReducedMotion': true,
|
||||
'CSSPrefersContrast': true,
|
||||
'CanvasRandomization': true,
|
||||
'CanvasExtractionFromThirdPartiesIsBlocked': true,
|
||||
'JSLocale': true,
|
||||
'NavigatorAppVersion': true,
|
||||
'NavigatorBuildID': true,
|
||||
'NavigatorHWConcurrency': true,
|
||||
'NavigatorOscpu': true,
|
||||
'NavigatorPlatform': true,
|
||||
'NavigatorUserAgent': true,
|
||||
'PointerId': true,
|
||||
'StreamVideoFacingMode': true,
|
||||
'JSDateTimeUTC': true,
|
||||
'JSMathFdlibm': true,
|
||||
'Gamepad': true,
|
||||
'HttpUserAgent': true,
|
||||
'WindowOuterSize': true,
|
||||
'WindowScreenXY': true,
|
||||
'WindowInnerScreenXY': true,
|
||||
'ScreenPixelDepth': true,
|
||||
'ScreenRect': true,
|
||||
'ScreenAvailRect': true,
|
||||
'VideoElementMozFrames': true,
|
||||
'VideoElementMozFrameDelay': true,
|
||||
'VideoElementPlaybackQuality': true,
|
||||
'ReduceTimerPrecision': true,
|
||||
'WidgetEvents': true,
|
||||
'MediaDevices': true,
|
||||
'MediaCapabilities': true,
|
||||
'AudioSampleRate': true,
|
||||
'NetworkConnection': true,
|
||||
'WindowDevicePixelRatio': true,
|
||||
'MouseEventScreenPoint': true,
|
||||
'FontVisibilityBaseSystem': true,
|
||||
'FontVisibilityLangPack': true,
|
||||
'DeviceSensors': true,
|
||||
'RoundWindowSize': true,
|
||||
'UseStandinsForNativeColors': true,
|
||||
'AudioContext': true,
|
||||
'MediaError': true,
|
||||
'DOMStyleOsxFontSmoothing': true,
|
||||
'CSSDeviceSize': true,
|
||||
'CSSColorInfo': true,
|
||||
'CSSResolution': true,
|
||||
'CSSPrefersReducedTransparency': true,
|
||||
'CSSInvertedColors': true,
|
||||
'CSSVideoDynamicRange': true,
|
||||
'CSSPointerCapabilities': true,
|
||||
'WebGLRenderCapability': true,
|
||||
'WebGLRenderInfo': true,
|
||||
'SiteSpecificZoom': true,
|
||||
'FontVisibilityRestrictGenerics': true,
|
||||
'WebVTT': true,
|
||||
'WebGPULimits': true,
|
||||
'WebGPUIsFallbackAdapter': true,
|
||||
'WebGPUSubgroupSizes': true,
|
||||
'JSLocalePrompt': true,
|
||||
'ScreenAvailToResolution': true,
|
||||
'UseHardcodedFontSubstitutes': true,
|
||||
'DiskStorageLimit': true,
|
||||
'WebCodecs': true,
|
||||
'MaxTouchPoints': true,
|
||||
'MaxTouchPointsCollapse': true,
|
||||
'NavigatorHWConcurrencyTiered': true,
|
||||
});
|
||||
|
||||
static Result<FingerprintOverrides> parse(
|
||||
String input,
|
||||
Set<String> availableTargets,
|
||||
) {
|
||||
final cleaned = input.replaceAll(RegExp(r'\s'), '');
|
||||
if (cleaned.isEmpty) return Result.success(FingerprintOverrides(null, {}));
|
||||
|
||||
bool? allTargets;
|
||||
final targets = <String, bool>{};
|
||||
|
||||
for (final word in cleaned.split(',')) {
|
||||
final match = pattern.firstMatch(word);
|
||||
if (match == null) {
|
||||
return Result.failure(
|
||||
const ErrorMessage(source: 'FpParser', message: 'Invalid Override'),
|
||||
);
|
||||
}
|
||||
|
||||
final enabled = match.group(1) != '-';
|
||||
final name = match.group(2)!;
|
||||
|
||||
if (name == 'AllTargets') {
|
||||
allTargets = enabled;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!availableTargets.contains(name)) {
|
||||
return Result.failure(
|
||||
const ErrorMessage(
|
||||
source: 'FpParser',
|
||||
message: 'Invalid target name',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
targets[name] = enabled;
|
||||
}
|
||||
|
||||
return Result.success(FingerprintOverrides(allTargets, targets));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final sb = StringBuffer();
|
||||
|
||||
if (allTargets != null) {
|
||||
sb.write('${allTargets! ? '+' : '-'}AllTargets');
|
||||
if (targets.isNotEmpty) {
|
||||
sb.write(',');
|
||||
}
|
||||
}
|
||||
|
||||
sb.write(
|
||||
targets.entries.map((e) => (e.value ? '+' : '-') + e.key).join(','),
|
||||
);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
FingerprintOverrides copyWithAllTargetsEnabled(bool value) {
|
||||
return FingerprintOverrides(
|
||||
value,
|
||||
Map.fromEntries(targets.entries.where((e) => e.value != value)),
|
||||
);
|
||||
}
|
||||
|
||||
FingerprintOverrides copyWithTarget(String name, bool value) {
|
||||
if (value && allTargets == true) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return FingerprintOverrides(allTargets, {...targets, name: value});
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get hashParameters => [allTargets, targets];
|
||||
}
|
||||
@@ -17,11 +17,16 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'package:exceptions/exceptions.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/features/user/data/providers.dart';
|
||||
import 'package:weblibre/features/user/domain/entities/fingerprint_overrides.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/engine_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/services/fingerprinting.dart';
|
||||
|
||||
part 'providers.g.dart';
|
||||
|
||||
@@ -47,3 +52,24 @@ bool incognitoModeEnabled(Ref ref) {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
Future<Result<FingerprintOverrides>> fingerprintOverrideSettings(
|
||||
Ref ref,
|
||||
) async {
|
||||
final fingerprintTargets = await ref.watch(fingerprintTargetsProvider.future);
|
||||
final fingerprintTargetSet = fingerprintTargets.map((e) => e.name).toSet();
|
||||
|
||||
final overrides = ref.watch(
|
||||
engineSettingsWithDefaultsProvider.select(
|
||||
(settings) =>
|
||||
settings.fingerprintingProtectionOverrides.mapNotNull(
|
||||
(settings) =>
|
||||
FingerprintOverrides.parse(settings, fingerprintTargetSet),
|
||||
) ??
|
||||
Result.success(FingerprintOverrides.defaults()),
|
||||
),
|
||||
);
|
||||
|
||||
return overrides;
|
||||
}
|
||||
|
||||
@@ -117,3 +117,46 @@ final class IncognitoModeEnabledProvider
|
||||
|
||||
String _$incognitoModeEnabledHash() =>
|
||||
r'36957b70a5261f9d3ad228e07cc8dd5c8f616082';
|
||||
|
||||
@ProviderFor(fingerprintOverrideSettings)
|
||||
const fingerprintOverrideSettingsProvider =
|
||||
FingerprintOverrideSettingsProvider._();
|
||||
|
||||
final class FingerprintOverrideSettingsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<Result<FingerprintOverrides>>,
|
||||
Result<FingerprintOverrides>,
|
||||
FutureOr<Result<FingerprintOverrides>>
|
||||
>
|
||||
with
|
||||
$FutureModifier<Result<FingerprintOverrides>>,
|
||||
$FutureProvider<Result<FingerprintOverrides>> {
|
||||
const FingerprintOverrideSettingsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'fingerprintOverrideSettingsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$fingerprintOverrideSettingsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<Result<FingerprintOverrides>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<Result<FingerprintOverrides>> create(Ref ref) {
|
||||
return fingerprintOverrideSettings(ref);
|
||||
}
|
||||
}
|
||||
|
||||
String _$fingerprintOverrideSettingsHash() =>
|
||||
r'd4d40ec425098fb1f5a2f0c4944f058829a41a0a';
|
||||
|
||||
@@ -114,6 +114,11 @@ class EngineSettingsRepository extends _$EngineSettingsRepository {
|
||||
DriftSqlType.string,
|
||||
db.typeMapping,
|
||||
),
|
||||
'fingerprintingProtectionOverrides':
|
||||
settings['fingerprintingProtectionOverrides']?.readAs(
|
||||
DriftSqlType.string,
|
||||
db.typeMapping,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ final class EngineSettingsRepositoryProvider
|
||||
}
|
||||
|
||||
String _$engineSettingsRepositoryHash() =>
|
||||
r'5e403757036edb4ef964b01cdcf96cbcbdc4d809';
|
||||
r'33acd89e783d8d91b9b56e86411fdfcab24a2c54';
|
||||
|
||||
abstract class _$EngineSettingsRepository
|
||||
extends $StreamNotifier<EngineSettings> {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/features/user/data/models/rfp_target.dart';
|
||||
|
||||
part 'fingerprinting.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future<List<RFPTarget>> fingerprintTargets(Ref ref) async {
|
||||
final json =
|
||||
await rootBundle
|
||||
.loadString('assets/preferences/rfp_targets.json')
|
||||
.then(jsonDecode)
|
||||
as List<dynamic>;
|
||||
|
||||
return json
|
||||
.map((e) => RFPTarget.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'fingerprinting.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(fingerprintTargets)
|
||||
const fingerprintTargetsProvider = FingerprintTargetsProvider._();
|
||||
|
||||
final class FingerprintTargetsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<List<RFPTarget>>,
|
||||
List<RFPTarget>,
|
||||
FutureOr<List<RFPTarget>>
|
||||
>
|
||||
with $FutureModifier<List<RFPTarget>>, $FutureProvider<List<RFPTarget>> {
|
||||
const FingerprintTargetsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'fingerprintTargetsProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$fingerprintTargetsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<List<RFPTarget>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<List<RFPTarget>> create(Ref ref) {
|
||||
return fingerprintTargets(ref);
|
||||
}
|
||||
}
|
||||
|
||||
String _$fingerprintTargetsHash() =>
|
||||
r'1ec5933a82941b84fdad2130ccf1ba2156ddc33a';
|
||||
+6
-6
@@ -33,7 +33,7 @@ dependencies:
|
||||
google_fonts: ^6.3.2
|
||||
graphview: ^1.5.0
|
||||
home_widget: ^0.8.0
|
||||
hooks_riverpod: ^3.0.2
|
||||
hooks_riverpod: ^3.0.3
|
||||
html: ^0.15.6
|
||||
http: ^1.5.0
|
||||
http_parser: ^4.1.2
|
||||
@@ -55,8 +55,8 @@ dependencies:
|
||||
path: ../packages/pluggable_transports_proxy
|
||||
pretty_qr_code: ^3.5.0
|
||||
quick_actions: ^1.1.0
|
||||
riverpod: ^3.0.2
|
||||
riverpod_annotation: ^3.0.2
|
||||
riverpod: ^3.0.3
|
||||
riverpod_annotation: ^3.0.3
|
||||
rss_dart: ^1.0.13
|
||||
rxdart: ^0.28.0
|
||||
share_plus: ^12.0.0
|
||||
@@ -69,7 +69,7 @@ dependencies:
|
||||
speech_to_text_google_dialog:
|
||||
git:
|
||||
url: https://github.com/FaFre/speech_to_text_google_dialog.git
|
||||
sqlite3: ^2.9.1
|
||||
sqlite3: ^2.9.2
|
||||
sqlite3_flutter_libs: ^0.5.40
|
||||
synchronized: ^3.4.0
|
||||
text_scroll: ^0.2.1
|
||||
@@ -96,8 +96,8 @@ dev_dependencies:
|
||||
go_router_builder: ^4.1.0
|
||||
json_serializable: ^6.11.1
|
||||
lint: ^2.8.0
|
||||
riverpod_generator: ^3.0.2
|
||||
riverpod_lint: ^3.0.2
|
||||
riverpod_generator: ^3.0.3
|
||||
riverpod_lint: ^3.0.3
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
+6
@@ -144,6 +144,9 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
|
||||
components.core.engineSettings.dohDefaultProviderUrl = settings.dohSettings.dohDefaultProviderUrl
|
||||
components.core.engineSettings.dohExceptionsList = settings.dohSettings.dohExceptionsList
|
||||
}
|
||||
if(settings.fingerprintingProtectionOverrides != null) {
|
||||
components.core.engineSettings.fingerprintingProtectionOverrides = settings.fingerprintingProtectionOverrides
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateRuntimeSettings(settings: GeckoEngineSettings) {
|
||||
@@ -227,6 +230,9 @@ class GeckoEngineSettingsApiImpl : GeckoEngineSettingsApi {
|
||||
components.core.engine.settings.dohDefaultProviderUrl = settings.dohSettings.dohDefaultProviderUrl
|
||||
components.core.engine.settings.dohExceptionsList = settings.dohSettings.dohExceptionsList
|
||||
}
|
||||
if(settings.fingerprintingProtectionOverrides != null) {
|
||||
components.core.engine.settings.fingerprintingProtectionOverrides = settings.fingerprintingProtectionOverrides
|
||||
}
|
||||
|
||||
if(reloadSession) {
|
||||
components.useCases.sessionUseCases.reload()
|
||||
|
||||
+5
-2
@@ -1677,7 +1677,8 @@ data class GeckoEngineSettings (
|
||||
val userAgent: String? = null,
|
||||
val contentBlocking: ContentBlocking? = null,
|
||||
val enterpriseRootsEnabled: Boolean? = null,
|
||||
val dohSettings: DohSettings? = null
|
||||
val dohSettings: DohSettings? = null,
|
||||
val fingerprintingProtectionOverrides: String? = null
|
||||
)
|
||||
{
|
||||
companion object {
|
||||
@@ -1696,7 +1697,8 @@ data class GeckoEngineSettings (
|
||||
val contentBlocking = pigeonVar_list[11] as ContentBlocking?
|
||||
val enterpriseRootsEnabled = pigeonVar_list[12] as Boolean?
|
||||
val dohSettings = pigeonVar_list[13] as DohSettings?
|
||||
return GeckoEngineSettings(javascriptEnabled, trackingProtectionPolicy, httpsOnlyMode, globalPrivacyControlEnabled, preferredColorScheme, cookieBannerHandlingMode, cookieBannerHandlingModePrivateBrowsing, cookieBannerHandlingGlobalRules, cookieBannerHandlingGlobalRulesSubFrames, webContentIsolationStrategy, userAgent, contentBlocking, enterpriseRootsEnabled, dohSettings)
|
||||
val fingerprintingProtectionOverrides = pigeonVar_list[14] as String?
|
||||
return GeckoEngineSettings(javascriptEnabled, trackingProtectionPolicy, httpsOnlyMode, globalPrivacyControlEnabled, preferredColorScheme, cookieBannerHandlingMode, cookieBannerHandlingModePrivateBrowsing, cookieBannerHandlingGlobalRules, cookieBannerHandlingGlobalRulesSubFrames, webContentIsolationStrategy, userAgent, contentBlocking, enterpriseRootsEnabled, dohSettings, fingerprintingProtectionOverrides)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
@@ -1715,6 +1717,7 @@ data class GeckoEngineSettings (
|
||||
contentBlocking,
|
||||
enterpriseRootsEnabled,
|
||||
dohSettings,
|
||||
fingerprintingProtectionOverrides,
|
||||
)
|
||||
}
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
||||
@@ -94,4 +94,10 @@ class GeckoEngineSettingsService {
|
||||
Future<void> dohSettings(DohSettings state) {
|
||||
return _api.updateRuntimeSettings(GeckoEngineSettings(dohSettings: state));
|
||||
}
|
||||
|
||||
Future<void> fingerprintingProtectionOverrides(String? state) {
|
||||
return _api.updateRuntimeSettings(
|
||||
GeckoEngineSettings(fingerprintingProtectionOverrides: state),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2043,6 +2043,7 @@ class GeckoEngineSettings {
|
||||
this.contentBlocking,
|
||||
this.enterpriseRootsEnabled,
|
||||
this.dohSettings,
|
||||
this.fingerprintingProtectionOverrides,
|
||||
});
|
||||
|
||||
bool? javascriptEnabled;
|
||||
@@ -2073,6 +2074,8 @@ class GeckoEngineSettings {
|
||||
|
||||
DohSettings? dohSettings;
|
||||
|
||||
String? fingerprintingProtectionOverrides;
|
||||
|
||||
List<Object?> _toList() {
|
||||
return <Object?>[
|
||||
javascriptEnabled,
|
||||
@@ -2089,6 +2092,7 @@ class GeckoEngineSettings {
|
||||
contentBlocking,
|
||||
enterpriseRootsEnabled,
|
||||
dohSettings,
|
||||
fingerprintingProtectionOverrides,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2112,6 +2116,7 @@ class GeckoEngineSettings {
|
||||
contentBlocking: result[11] as ContentBlocking?,
|
||||
enterpriseRootsEnabled: result[12] as bool?,
|
||||
dohSettings: result[13] as DohSettings?,
|
||||
fingerprintingProtectionOverrides: result[14] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -666,6 +666,7 @@ class GeckoEngineSettings {
|
||||
final ContentBlocking? contentBlocking;
|
||||
final bool? enterpriseRootsEnabled;
|
||||
final DohSettings? dohSettings;
|
||||
final String? fingerprintingProtectionOverrides;
|
||||
|
||||
GeckoEngineSettings(
|
||||
this.javascriptEnabled,
|
||||
@@ -682,6 +683,7 @@ class GeckoEngineSettings {
|
||||
this.contentBlocking,
|
||||
this.enterpriseRootsEnabled,
|
||||
this.dohSettings,
|
||||
this.fingerprintingProtectionOverrides,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user