Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
luckyrat committed Feb 21, 2024
1 parent 83f86d1 commit 6c635fd
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 62 deletions.
10 changes: 7 additions & 3 deletions lib/cubit/autofill_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class AutofillCubit extends Cubit<AutofillState> {
List<KdbxEntry> _findMatchesByPackageName(AutofillMetadata androidMetadata, KdbxFile current) {
final matches = <KdbxEntry>[];
matches.addAll(current.body.rootGroup.getAllEntries(enterRecycleBin: false).values.where((entry) =>
!entry.browserSettings.hide &&
!entry.browserSettings.matcherConfigs.any((mc) => mc.matcherType == EntryMatcherType.Hide) &&
entry.androidPackageNames.any((pn) => androidMetadata.packageNames.contains(pn))));
return matches;
}
Expand Down Expand Up @@ -240,11 +240,15 @@ class AutofillCubit extends Cubit<AutofillState> {
(val) => val.name == current.body.meta.browserSettings.matchedURLAccuracyOverrides[registrableDomain]);

matches.addAll(current.body.rootGroup.getAllEntries(enterRecycleBin: false).values.where((entry) {
if (entry.browserSettings.hide) {
if (entry.browserSettings.matcherConfigs.any((mc) => mc.matcherType == EntryMatcherType.Hide)) {
return false;
}
bool isAMatch = false;
var minimumMatchAccuracy = matchAccuracyDomainOverride ?? entry.browserSettings.minimumMatchAccuracy;
var minimumMatchAccuracy = matchAccuracyDomainOverride ??
entry.browserSettings.matcherConfigs
.firstWhereOrNull((mc) => mc.matcherType == EntryMatcherType.Url)
?.urlMatchMethod ??
MatchAccuracy.Domain;

final matchPatterns = entry.browserSettings.includeUrls.toList();
final primaryUrlString = entry.getString(KdbxKeyCommon.URL)?.getText();
Expand Down
10 changes: 5 additions & 5 deletions lib/cubit/entry_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class EntryCubit extends Cubit<EntryState> {
final uniqueName = findUniqueFieldName(newList, field.fieldKey!);
field = uniqueName == field.fieldKey!
? field
: field.copyWith(browserModel: field.browserModel!.copyWith(displayName: uniqueName));
: field.copyWith(browserModel: field.browserModel!.copyWith(name: uniqueName));
newList.add(field);
final updated = entry.copyWith(fields: newList, isDirty: true);
emit(EntryLoaded(updated));
Expand Down Expand Up @@ -148,7 +148,7 @@ class EntryCubit extends Cubit<EntryState> {
return;
}
} else {
fieldIndex = entry.fields.indexWhere((f) => f.browserModel?.displayName == oldBrowserDisplayName);
fieldIndex = entry.fields.indexWhere((f) => f.browserModel?.name == oldBrowserDisplayName);
if (fieldIndex == -1) {
l.e('Field missing: $oldBrowserDisplayName (Json)');
return;
Expand All @@ -159,7 +159,7 @@ class EntryCubit extends Cubit<EntryState> {

final updatedFieldName = findUniqueFieldName(newList, newName);
final updatedField = currentField.fieldStorage == FieldStorage.JSON
? currentField.copyWith(browserModel: currentField.browserModel!.copyWith(displayName: updatedFieldName))
? currentField.copyWith(browserModel: currentField.browserModel!.copyWith(name: updatedFieldName))
: currentField.copyWith(
key: KdbxKey(updatedFieldName),
name: updatedFieldName,
Expand All @@ -182,7 +182,7 @@ class EntryCubit extends Cubit<EntryState> {
TextCapitalization? textCapitalization,
IconData? icon,
bool? showIfEmpty,
BrowserFieldModel? browserModel,
Field? browserModel,
StringValue? value,
String? newCustomFieldName,
}) {
Expand All @@ -198,7 +198,7 @@ class EntryCubit extends Cubit<EntryState> {
return;
}
} else {
fieldIndex = entry.fields.indexWhere((f) => f.browserModel?.displayName == oldBrowserDisplayName);
fieldIndex = entry.fields.indexWhere((f) => f.browserModel?.name == oldBrowserDisplayName);
if (fieldIndex == -1) {
l.e('Field missing: $oldBrowserDisplayName (Json)');
return;
Expand Down
30 changes: 15 additions & 15 deletions lib/model/entry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class EntryViewModel {
final androidPackageNames = entry.androidPackageNames;
final binaryMapEntries = entry.binaryEntries.toList();

final userBrowserField = settings.fields.firstWhereOrNull((field) => field.displayName == 'KeePass username');
final passBrowserField = settings.fields.firstWhereOrNull((field) => field.displayName == 'KeePass password');
final userBrowserField = settings.fields?.firstWhereOrNull((field) => field.valuePath == 'UserName');
final passBrowserField = settings.fields?.firstWhereOrNull((field) => field.valuePath == 'Password');

final fields = entry.stringEntries
.where((me) => !['KPRPC JSON', 'TOTP Seed', 'TOTP Settings', 'OTPAuth'].contains(me.key.key))
Expand Down Expand Up @@ -154,16 +154,16 @@ class EntryViewModel {
// from older versions of Kee Vault or other KDBX generators.
// Since we can't see a situation where there are duplicates within the JSON
// settings field list, we can keep the deduplication algorithm simple.
fields.addAll(settings.fields
.where((field) => field.displayName != 'KeePass username' && field.displayName != 'KeePass password')
.map((field) {
if (fields.any((f) => f.fieldKey == field.displayName)) {
l.w('Duplicated field key found: ${field.displayName}. Will force deduplication.');
field = field.copyWith(
displayName: '${field.displayName} - deduplicated at ${DateTime.now().millisecondsSinceEpoch}');
}
return FieldViewModel.fromCustomAndBrowser(null, null, field);
}).where((vm) => vm.localisedCommonName.isNotEmpty));
fields.addAll(
settings.fields?.where((field) => field.valuePath != 'UserName' && field.valuePath != 'Password').map((field) {
if (fields.any((f) => f.fieldKey == field.name)) {
l.w('Duplicated field key found: ${field.name}. Will force deduplication.');
field =
field.copyWith(name: '${field.name} - deduplicated at ${DateTime.now().millisecondsSinceEpoch}');
}
return FieldViewModel.fromCustomAndBrowser(null, null, field);
}).where((vm) => vm.localisedCommonName.isNotEmpty) ??
[]);

final fixedSortIndexes = [
KdbxKeyCommon.TITLE,
Expand Down Expand Up @@ -399,8 +399,8 @@ class EditEntryViewModel extends EntryViewModel {
const customIcon = null;
const color = null;
const uuid = null;
BrowserEntrySettings settings =
BrowserEntrySettings(minimumMatchAccuracy: group.file!.body.meta.browserSettings.defaultMatchAccuracy);
BrowserEntrySettings settings = BrowserEntrySettings.fromMap(null,
minimumMatchAccuracy: group.file!.body.meta.browserSettings.defaultMatchAccuracy);
final tags = <Tag>[];
final created = DateTime.now();
final modified = created;
Expand Down Expand Up @@ -430,7 +430,7 @@ class EditEntryViewModel extends EntryViewModel {

commit(KdbxEntry entry) {
final Map<KdbxKey, StringValue> newFields = {};
final List<BrowserFieldModel> jsonFields = [];
final List<Field> jsonFields = [];

for (var f in fields) {
// returns a tuple of a kdbxstring keyvalue and a string of JSON for potential addition to KPRPCJSON kdbxstring
Expand Down
40 changes: 26 additions & 14 deletions lib/model/field.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:kdbx/kdbx.dart';
import 'package:kdbx/kdbx.dart' as kdbx show FieldType;
import 'package:kdbx/kdbx.dart' hide FieldType;
import 'package:tuple/tuple.dart';
import '../generated/l10n.dart';
import '../extension_methods.dart';
Expand All @@ -16,7 +18,7 @@ class FieldViewModel {
TextCapitalization textCapitalization = TextCapitalization.none;
IconData? icon;
bool showIfEmpty = false;
BrowserFieldModel? browserModel;
Field? browserModel;

StringValue value;

Expand Down Expand Up @@ -44,7 +46,7 @@ class FieldViewModel {
this._name, //TODO:f: What is this actually for? Seems we set it to the same as localisedCommonName and then never use the value. We have the key for normal field ID purposes and have no need for localising user's own data if the name or fieldId of the browserModel is used. For new browserModel field entries, can't we use the localisedCommonName anyway (maybe via _getBrowserFieldDisplayName instead of _name?)
);

factory FieldViewModel.fromCustomAndBrowser(KdbxKey? key, StringValue? value, BrowserFieldModel? browserModel) {
factory FieldViewModel.fromCustomAndBrowser(KdbxKey? key, StringValue? value, Field? browserModel) {
if (key == null && value == null && browserModel == null) {
throw Exception('No field can be created when there is no data');
}
Expand Down Expand Up @@ -109,14 +111,24 @@ class FieldViewModel {

if (key == null && browserModel != null) {
// We might come across old bad data so make every effort to select a new displayName for such fields. Ultimately, we'll have to ignore and eventually delete any fields that contain no useful data.
localisedCommonName = browserModel.displayName?.nullIfBlank() ??
browserModel.name?.nullIfBlank() ??
browserModel.fieldId?.nullIfBlank() ??
(browserModel.type == FormFieldType.CHECKBOX || browserModel.value?.nullIfBlank() == null ? '' : '[no name]');
fieldValue = browserModel.type == FormFieldType.PASSWORD
localisedCommonName = browserModel.name?.nullIfBlank() ??
browserModel.matcherConfigs
?.firstWhereOrNull((mc) => mc.matcherType == FieldMatcherType.Custom)
?.customMatcher
?.names
.firstOrNull
?.nullIfBlank() ??
browserModel.matcherConfigs
?.firstWhereOrNull((mc) => mc.matcherType == FieldMatcherType.Custom)
?.customMatcher
?.ids
.firstOrNull
?.nullIfBlank() ??
(browserModel.type == kdbx.FieldType.Toggle || browserModel.value?.nullIfBlank() == null ? '' : '[no name]');
fieldValue = browserModel.type == kdbx.FieldType.Password
? ProtectedValue.fromString(browserModel.value ?? '')
: PlainValue(browserModel.value ?? '');
protect = browserModel.type == FormFieldType.PASSWORD;
protect = browserModel.type == kdbx.FieldType.Password;
} else {
localisedCommonName = key!.key;
}
Expand All @@ -126,13 +138,13 @@ class FieldViewModel {
}

bool get isDirty => _isDirty;
String? get name => browserModel?.displayName ?? _name ?? localisedCommonName;
String? get fieldKey => key?.key ?? browserModel?.displayName;
String? get name => browserModel?.name ?? _name ?? localisedCommonName;
String? get fieldKey => key?.key ?? browserModel?.name;

String get textValue => value.getText();

bool get isTotp => fieldStorage == FieldStorage.CUSTOM && ['otp', 'OTPAuth', 'TOTP Seed'].contains(key!.key);
bool get isCheckbox => browserModel?.type == FormFieldType.CHECKBOX;
bool get isCheckbox => browserModel?.type == kdbx.FieldType.Toggle;

bool get isStandard =>
fieldStorage != FieldStorage.JSON &&
Expand All @@ -146,7 +158,7 @@ class FieldViewModel {
bool get protectionChangeable => !isStandard && !isTotp;
bool get keyChangeable => !isTotp && !showIfEmpty;

Tuple2<MapEntry<KdbxKey, StringValue>?, BrowserFieldModel?> commit() {
Tuple2<MapEntry<KdbxKey, StringValue>?, Field?> commit() {
final customField = key != null ? MapEntry<KdbxKey, StringValue>(key!, value) : null;
return Tuple2(customField, browserModel);
}
Expand Down Expand Up @@ -210,7 +222,7 @@ class FieldViewModel {
TextCapitalization? textCapitalization,
IconData? icon,
bool? showIfEmpty,
BrowserFieldModel? browserModel,
Field? browserModel,
StringValue? value,
String? name,
}) {
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/entry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ class EntryWidget extends StatelessWidget {
final field = FieldViewModel.fromCustomAndBrowser(
null,
null,
BrowserFieldModel(
displayName: key,
Field(
name: key,
value: '',
));
cubit.addField(field);
Expand Down
19 changes: 10 additions & 9 deletions lib/widgets/entry_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import 'dart:async';
import 'package:base32/base32.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kdbx/kdbx.dart';
import 'package:kdbx/kdbx.dart' as kdbx show FieldType;
import 'package:kdbx/kdbx.dart' hide FieldType;
import 'package:keevault/cubit/entry_cubit.dart';
import 'package:keevault/logging/logger.dart';
import 'package:keevault/model/entry.dart';
Expand Down Expand Up @@ -74,7 +75,7 @@ class _SwitchEntryFieldState extends _EntryFieldState {
value: _checked,
onChanged: (bool? value) {
final cubit = BlocProvider.of<EntryCubit>(context);
cubit.updateField(null, widget.field.browserModel!.displayName,
cubit.updateField(null, widget.field.browserModel!.name,
value: value! ? PlainValue('KEEFOX_CHECKED_FLAG_TRUE') : PlainValue('KEEFOX_CHECKED_FLAG_FALSE'),
browserModel: widget.field.browserModel!
.copyWith(value: value ? 'KEEFOX_CHECKED_FLAG_TRUE' : 'KEEFOX_CHECKED_FLAG_FALSE'));
Expand Down Expand Up @@ -110,7 +111,7 @@ class _SwitchEntryFieldState extends _EntryFieldState {
initialValue: widget.field.name,
).show(context);
if (newName != null) {
cubit.renameField(widget.field.key, widget.field.browserModel?.displayName, newName);
cubit.renameField(widget.field.key, widget.field.browserModel?.name, newName);
}
break;
case EntryAction.delete:
Expand Down Expand Up @@ -270,7 +271,7 @@ class _EntryTextFieldState extends _EntryFieldState implements FieldDelegate {
initialValue: widget.field.name,
).show(context);
if (newName != null) {
cubit.renameField(widget.field.key, widget.field.browserModel?.displayName, newName);
cubit.renameField(widget.field.key, widget.field.browserModel?.name, newName);
}
}
break;
Expand All @@ -283,10 +284,10 @@ class _EntryTextFieldState extends _EntryFieldState implements FieldDelegate {
if (widget.field.fieldStorage == FieldStorage.JSON) {
cubit.updateField(
null,
widget.field.browserModel!.displayName,
widget.field.browserModel!.name,
value: PlainValue(widget.field.textValue),
browserModel:
widget.field.browserModel!.copyWith(type: FormFieldType.TEXT, value: widget.field.textValue),
widget.field.browserModel!.copyWith(type: kdbx.FieldType.Text, value: widget.field.textValue),
protect: false,
);
} else {
Expand All @@ -302,10 +303,10 @@ class _EntryTextFieldState extends _EntryFieldState implements FieldDelegate {
if (widget.field.fieldStorage == FieldStorage.JSON) {
cubit.updateField(
null,
widget.field.browserModel!.displayName,
widget.field.browserModel!.name,
value: ProtectedValue.fromString(widget.field.textValue),
browserModel:
widget.field.browserModel!.copyWith(type: FormFieldType.PASSWORD, value: widget.field.textValue),
widget.field.browserModel!.copyWith(type: kdbx.FieldType.Password, value: widget.field.textValue),
protect: true,
);
} else {
Expand Down Expand Up @@ -468,7 +469,7 @@ class _EntryTextFieldState extends _EntryFieldState implements FieldDelegate {
}
cubit.updateField(
null,
widget.field.browserModel!.displayName,
widget.field.browserModel!.name,
value: newValue,
browserModel: widget.field.browserModel!.copyWith(value: value),
);
Expand Down
12 changes: 9 additions & 3 deletions lib/widgets/entry_history.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:jiffy/jiffy.dart';
import 'package:kdbx/kdbx.dart';
import 'package:kdbx/kdbx.dart' hide FieldType;
import 'package:keevault/cubit/entry_cubit.dart';
import 'package:keevault/extension_methods.dart';
import 'package:keevault/model/entry.dart';
Expand Down Expand Up @@ -504,7 +505,8 @@ class _IntegrationSettingsHistoryWidgetState extends State<IntegrationSettingsHi
child: ListTile(
title: Text(str.showEntryInBrowsersAndApps),
leading: Switch(
value: !widget.entry.browserSettings.hide,
value: !widget.entry.browserSettings.matcherConfigs
.any((mc) => mc.matcherType == EntryMatcherType.Hide),
onChanged: null,
),
),
Expand All @@ -531,7 +533,11 @@ class _IntegrationSettingsHistoryWidgetState extends State<IntegrationSettingsHi
Expanded(
child: Text(str.minURLMatchAccuracy),
),
Text(widget.entry.browserSettings.minimumMatchAccuracy.name),
Text((widget.entry.browserSettings.matcherConfigs
.firstWhereOrNull((mc) => mc.matcherType == EntryMatcherType.Url)
?.urlMatchMethod ??
MatchAccuracy.Domain)
.name),
],
),
Divider(
Expand Down
Loading

0 comments on commit 6c635fd

Please sign in to comment.