import 'dart:async' show Future; import 'dart:convert' show json; import 'package:pb_authenticator_state/file_storage_base.dart'; import 'package:pb_authenticator_totp/totp.dart'; import './legacy_authenticator_item.dart'; import '../repository/repository_base.dart' show RepositoryBase; /// Is used to load/save state to JSON file. /// /// Currently uses FileStorage to do so. class LegacyRepository implements RepositoryBase { LegacyRepository(this._fileStorage); // Current file version static const _currentVersion = 1; // Filename of JSON static const _stateFilename = "items.json"; // Used for loading/saving files final FileStorageBase _fileStorage; // Items List _items = []; Future hasState() { return _fileStorage.hasFile(_stateFilename); } /// Loads state from storage. @override Future> loadItems() async { // If file doesn't exist, then initialise empty state // Load/decode file var str = await _fileStorage.readFile(_stateFilename); if (str == null) { return []; } Map decoded = json.decode(str); var version = decoded['version']; // If version is not current, bring it up to current if (version != _currentVersion) { throw Exception("Unknown file version"); } // Decode and return items // Adapted from: https://stackoverflow.com/questions/50360443 var itemsDecoded = decoded['items']; var items = (itemsDecoded as List) .map((i) => LegacyAuthenticatorItem.fromMap(i)) .toList(); _items = items; return items; } /// Saves [state] to storage. @override Future replaceItems(List state) async { return await _saveItems(state); } @override Future addItem(TotpItem item) async { var legacyAuthenticatorItem = LegacyAuthenticatorItem.newAuthenticatorItem(item); _items.add(legacyAuthenticatorItem); await _saveItems(_items); return legacyAuthenticatorItem; } Future _saveItems(List items) async { // Encode var itemsMapped = items.map((i) => i.toMap()).toList(); var version = _currentVersion; var str = json.encode({'items': itemsMapped, 'version': version}); // Save to file return await _fileStorage.writeFile(_stateFilename, str).then((_) => {}); } }