legacy_repository.dart 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import 'dart:async' show Future;
  2. import 'dart:convert' show json;
  3. import 'package:pb_authenticator_state/file_storage_base.dart';
  4. import 'package:pb_authenticator_totp/totp.dart';
  5. import './legacy_authenticator_item.dart';
  6. import '../repository/repository_base.dart' show RepositoryBase;
  7. /// Is used to load/save state to JSON file.
  8. ///
  9. /// Currently uses FileStorage to do so.
  10. class LegacyRepository implements RepositoryBase<LegacyAuthenticatorItem> {
  11. LegacyRepository(this._fileStorage);
  12. // Current file version
  13. static const _currentVersion = 1;
  14. // Filename of JSON
  15. static const _stateFilename = "items.json";
  16. // Used for loading/saving files
  17. final FileStorageBase _fileStorage;
  18. // Items
  19. List<LegacyAuthenticatorItem> _items = [];
  20. Future<bool> hasState() {
  21. return _fileStorage.hasFile(_stateFilename);
  22. }
  23. /// Loads state from storage.
  24. @override
  25. Future<List<LegacyAuthenticatorItem>> loadItems() async {
  26. // If file doesn't exist, then initialise empty state
  27. // Load/decode file
  28. var str = await _fileStorage.readFile(_stateFilename);
  29. if (str == null) {
  30. return [];
  31. }
  32. Map<String, dynamic> decoded = json.decode(str);
  33. var version = decoded['version'];
  34. // If version is not current, bring it up to current
  35. if (version != _currentVersion) {
  36. throw Exception("Unknown file version");
  37. }
  38. // Decode and return items
  39. // Adapted from: https://stackoverflow.com/questions/50360443
  40. var itemsDecoded = decoded['items'];
  41. var items = (itemsDecoded as List)
  42. .map((i) => LegacyAuthenticatorItem.fromMap(i))
  43. .toList();
  44. _items = items;
  45. return items;
  46. }
  47. /// Saves [state] to storage.
  48. @override
  49. Future replaceItems(List<LegacyAuthenticatorItem> state) async {
  50. return await _saveItems(state);
  51. }
  52. @override
  53. Future<LegacyAuthenticatorItem> addItem(TotpItem item) async {
  54. var legacyAuthenticatorItem =
  55. LegacyAuthenticatorItem.newAuthenticatorItem(item);
  56. _items.add(legacyAuthenticatorItem);
  57. await _saveItems(_items);
  58. return legacyAuthenticatorItem;
  59. }
  60. Future _saveItems(List<LegacyAuthenticatorItem> items) async {
  61. // Encode
  62. var itemsMapped = items.map((i) => i.toMap()).toList();
  63. var version = _currentVersion;
  64. var str = json.encode({'items': itemsMapped, 'version': version});
  65. // Save to file
  66. return await _fileStorage.writeFile(_stateFilename, str).then((_) => {});
  67. }
  68. }