Herbert Poul
5 years ago
9 changed files with 161 additions and 128 deletions
@ -0,0 +1,111 @@ |
|||||||
|
import 'dart:async'; |
||||||
|
import 'dart:typed_data'; |
||||||
|
|
||||||
|
import 'package:kdbx/src/crypto/protected_value.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_format.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_group.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_header.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_object.dart'; |
||||||
|
import 'package:logging/logging.dart'; |
||||||
|
import 'package:xml/xml.dart' as xml; |
||||||
|
import 'package:kdbx/src/kdbx_dao.dart'; |
||||||
|
|
||||||
|
final _logger = Logger('kdbx_file'); |
||||||
|
|
||||||
|
class KdbxFile { |
||||||
|
KdbxFile(this.kdbxFormat, this.credentials, this.header, this.body) { |
||||||
|
for (final obj in _allObjects) { |
||||||
|
obj.file = this; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static final protectedValues = Expando<ProtectedValue>(); |
||||||
|
|
||||||
|
static ProtectedValue protectedValueForNode(xml.XmlElement node) { |
||||||
|
return protectedValues[node]; |
||||||
|
} |
||||||
|
|
||||||
|
static void setProtectedValueForNode( |
||||||
|
xml.XmlElement node, ProtectedValue value) { |
||||||
|
protectedValues[node] = value; |
||||||
|
} |
||||||
|
|
||||||
|
final KdbxFormat kdbxFormat; |
||||||
|
final Credentials credentials; |
||||||
|
final KdbxHeader header; |
||||||
|
final KdbxBody body; |
||||||
|
final Set<KdbxObject> dirtyObjects = {}; |
||||||
|
final StreamController<Set<KdbxObject>> _dirtyObjectsChanged = |
||||||
|
StreamController<Set<KdbxObject>>.broadcast(); |
||||||
|
|
||||||
|
Stream<Set<KdbxObject>> get dirtyObjectsChanged => |
||||||
|
_dirtyObjectsChanged.stream; |
||||||
|
|
||||||
|
Future<Uint8List> save() async { |
||||||
|
return kdbxFormat.save(this); |
||||||
|
} |
||||||
|
|
||||||
|
/// Marks all dirty objects as clean. Called by [KdbxFormat.save]. |
||||||
|
void onSaved() { |
||||||
|
dirtyObjects.clear(); |
||||||
|
_dirtyObjectsChanged.add(dirtyObjects); |
||||||
|
} |
||||||
|
|
||||||
|
Iterable<KdbxObject> get _allObjects => body.rootGroup |
||||||
|
.getAllGroups() |
||||||
|
.cast<KdbxObject>() |
||||||
|
.followedBy(body.rootGroup.getAllEntries()); |
||||||
|
|
||||||
|
void dirtyObject(KdbxObject kdbxObject) { |
||||||
|
dirtyObjects.add(kdbxObject); |
||||||
|
_dirtyObjectsChanged.add(dirtyObjects); |
||||||
|
} |
||||||
|
|
||||||
|
void dispose() { |
||||||
|
_dirtyObjectsChanged.close(); |
||||||
|
} |
||||||
|
|
||||||
|
KdbxGroup _recycleBin; |
||||||
|
|
||||||
|
/// Returns the recycle bin, if it exists, null otherwise. |
||||||
|
KdbxGroup get recycleBin => _recycleBin ??= _findRecycleBin(); |
||||||
|
|
||||||
|
KdbxGroup _findRecycleBin() { |
||||||
|
final uuid = body.meta.recycleBinUUID.get(); |
||||||
|
if (uuid?.isNil != false) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
try { |
||||||
|
return findGroupByUuid(uuid); |
||||||
|
} catch (e, stackTrace) { |
||||||
|
_logger.warning(() { |
||||||
|
final groupDebug = body.rootGroup |
||||||
|
.getAllGroups() |
||||||
|
.map((g) => '${g.uuid}: ${g.name}') |
||||||
|
.join('\n'); |
||||||
|
return 'All Groups: $groupDebug'; |
||||||
|
}); |
||||||
|
_logger.severe('Inconsistency error, uuid $uuid not found in groups.', e, |
||||||
|
stackTrace); |
||||||
|
rethrow; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// void _subscribeToChildren() { |
||||||
|
// final allObjects = _allObjects; |
||||||
|
// for (final obj in allObjects) { |
||||||
|
// _subscriptions.handle(obj.changes.listen((event) { |
||||||
|
// if (event.isDirty) { |
||||||
|
// isDirty = true; |
||||||
|
// if (event.object is KdbxGroup) { |
||||||
|
// Future(() { |
||||||
|
// // resubscribe, just in case some child groups/entries have changed. |
||||||
|
// _subscriptions.cancelSubscriptions(); |
||||||
|
// _subscribeToChildren(); |
||||||
|
// }); |
||||||
|
// } |
||||||
|
// } |
||||||
|
// })); |
||||||
|
// } |
||||||
|
// } |
||||||
|
} |
Loading…
Reference in new issue