updateCipher method

Future<void> updateCipher({
  1. String? path,
  2. String? oldPw,
  3. String? newPw,
})

Implementation

Future<void> updateCipher({
  String? path,
  String? oldPw,
  String? newPw,
}) async {
  try {
    final HiveCipher? oldCipher = cipherFromKey(key: oldPw);
    final HiveCipher? newCipher = cipherFromKey(key: newPw);

    /// only change the db if the new password is different from the old one
    if (oldCipher != newCipher) {
      await _ensureInit(pw: oldPw);

      /// The types box contains only a single entry, which is a list of all of the
      /// resource types that have been saved to the database
      final Box<List<String>> typesBox = await Hive.openBox<List<String>>(
          'types',
          encryptionCipher: oldCipher);

      /// get that list of types
      final List<String> types = typesBox.get('types') ?? <String>[];

      _types.map((R5ResourceType e) => resourceTypeToStringMap[e]!).toList();

      /// Create a new temporary box to store resources while we are updating the boxes
      /// with a new password
      final Box<Map<dynamic, dynamic>> tempBox =
          await Hive.openBox<Map<dynamic, dynamic>>('temp',
              encryptionCipher: newCipher);

      /// for each type in the list
      for (final String type in types) {
        /// Retrieve all resources currently in the box
        final Box<Map<dynamic, dynamic>> oldBox =
            await Hive.openBox<Map<dynamic, dynamic>>(type,
                encryptionCipher: oldCipher);

        /// for each map in the box
        for (final Map<dynamic, dynamic> value in oldBox.values) {
          /// Cast map to correct type
          final Map<String, dynamic> newValue =
              jsonDecode(jsonEncode(value)) as Map<String, dynamic>;

          /// convert it to a resource
          final Resource resource = Resource.fromJson(newValue);

          /// Save it in the temporary box as we're changing over to the new password, so
          /// in case something goes wrong, we don't lose the data
          await tempBox.put(resource.fhirId, newValue);
        }

        /// after we have saved all of the resources in the temporary box, we can
        /// delete the old box
        await oldBox.deleteFromDisk();

        /// Create the new box with the new password
        final Box<Map<dynamic, dynamic>> newBox =
            await Hive.openBox<Map<dynamic, dynamic>>(type,
                encryptionCipher: newCipher);

        /// for each map in the temp box
        for (final Map<dynamic, dynamic> value in tempBox.values) {
          /// Cast map to correct type
          final Map<String, dynamic> newValue =
              Map<String, dynamic>.from(value);

          /// convert it to a resource
          final Resource resource = Resource.fromJson(newValue);

          /// Save it to the new box with the new password
          await newBox.put(resource.fhirId, newValue);
        }

        /// clear everything from the tempBox so we can use it again
        await tempBox.clear();
      }

      /// After we've been through all of the types, delete the tempBox.
      await tempBox.deleteFromDisk();

      /// Delete the typesBox because we need to replace it too using the new password
      await typesBox.deleteFromDisk();

      /// Recreate the types box
      final Box<List<String>> newTypesBox = await Hive.openBox<List<String>>(
          'types',
          encryptionCipher: newCipher);
      await newTypesBox.put('types', types);
      await Hive.close();
    }
  } catch (e) {
    print(e);
  }
}