mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-11-03 22:07:23 +01:00 
			
		
		
		
	feat: Implement hive
This commit is contained in:
		
							parent
							
								
									a48d84fe27
								
							
						
					
					
						commit
						6ee4ca73cb
					
				@ -38,8 +38,8 @@ class ChatDetailsView extends StatelessWidget {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    controller.members.removeWhere((u) => u.membership == Membership.leave);
 | 
			
		||||
    final actualMembersCount =
 | 
			
		||||
        room.mInvitedMemberCount + room.mJoinedMemberCount;
 | 
			
		||||
    final actualMembersCount = (room.summary?.mInvitedMemberCount ?? 0) +
 | 
			
		||||
        (room.summary?.mJoinedMemberCount ?? 0);
 | 
			
		||||
    final canRequestMoreMembers =
 | 
			
		||||
        controller.members.length < actualMembersCount;
 | 
			
		||||
    return StreamBuilder(
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										148
									
								
								lib/utils/database/flutter_famedly_sdk_hive_database.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								lib/utils/database/flutter_famedly_sdk_hive_database.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,148 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
import 'dart:typed_data';
 | 
			
		||||
 | 
			
		||||
import 'package:famedlysdk/famedlysdk.dart';
 | 
			
		||||
import 'package:famedlysdk/src/utils/crypto/encrypted_file.dart';
 | 
			
		||||
import 'package:fluffychat/utils/platform_infos.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 | 
			
		||||
import 'package:hive/hive.dart';
 | 
			
		||||
import 'package:hive_flutter/hive_flutter.dart';
 | 
			
		||||
import 'package:path_provider/path_provider.dart';
 | 
			
		||||
 | 
			
		||||
class FlutterFamedlySdkHiveDatabase extends FamedlySdkHiveDatabase {
 | 
			
		||||
  FlutterFamedlySdkHiveDatabase(String name, {HiveCipher encryptionCipher})
 | 
			
		||||
      : super(
 | 
			
		||||
          name,
 | 
			
		||||
          encryptionCipher: encryptionCipher,
 | 
			
		||||
        ) {
 | 
			
		||||
    _clearOldFiles();
 | 
			
		||||
    Hive.registerAdapter(EncryptedFileAdapter());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static bool _hiveInitialized = false;
 | 
			
		||||
  static const String _hiveCipherStorageKey = 'hive_encryption_key';
 | 
			
		||||
 | 
			
		||||
  static Future<FamedlySdkHiveDatabase> hiveDatabaseBuilder(
 | 
			
		||||
      Client client) async {
 | 
			
		||||
    if (!kIsWeb && !_hiveInitialized) {
 | 
			
		||||
      Logs().i('Init Hive database...');
 | 
			
		||||
      await Hive.initFlutter();
 | 
			
		||||
      _hiveInitialized = true;
 | 
			
		||||
    }
 | 
			
		||||
    HiveCipher hiverCipher;
 | 
			
		||||
    try {
 | 
			
		||||
      final secureStorage = const FlutterSecureStorage();
 | 
			
		||||
      final containsEncryptionKey =
 | 
			
		||||
          await secureStorage.containsKey(key: _hiveCipherStorageKey);
 | 
			
		||||
      if (!containsEncryptionKey) {
 | 
			
		||||
        final key = Hive.generateSecureKey();
 | 
			
		||||
        await secureStorage.write(
 | 
			
		||||
          key: _hiveCipherStorageKey,
 | 
			
		||||
          value: base64UrlEncode(key),
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      final encryptionKey = base64Url.decode(
 | 
			
		||||
        await secureStorage.read(key: _hiveCipherStorageKey),
 | 
			
		||||
      );
 | 
			
		||||
      hiverCipher = HiveAesCipher(encryptionKey);
 | 
			
		||||
    } on MissingPluginException catch (_) {
 | 
			
		||||
      Logs()
 | 
			
		||||
          .i('Hive encryption is not supported on ${Platform.operatingSystem}');
 | 
			
		||||
    }
 | 
			
		||||
    final db = FamedlySdkHiveDatabase(
 | 
			
		||||
      client.clientName,
 | 
			
		||||
      encryptionCipher: hiverCipher,
 | 
			
		||||
    );
 | 
			
		||||
    Logs().i('Open Hive database...');
 | 
			
		||||
    await db.open();
 | 
			
		||||
    Logs().i('Hive database is ready!');
 | 
			
		||||
    return db;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  int get maxFileSize => PlatformInfos.isMobile ? 100 * 1024 * 1024 : 0;
 | 
			
		||||
  @override
 | 
			
		||||
  bool get supportsFileStoring => PlatformInfos.isMobile;
 | 
			
		||||
 | 
			
		||||
  LazyBox<EncryptedFile> _fileEncryptionKeysBox;
 | 
			
		||||
  static const String __fileEncryptionKeysBoxName = 'box.file_encryption_keys';
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<void> open() async {
 | 
			
		||||
    await super.open();
 | 
			
		||||
    _fileEncryptionKeysBox ??= await Hive.openLazyBox<EncryptedFile>(
 | 
			
		||||
      __fileEncryptionKeysBoxName,
 | 
			
		||||
      encryptionCipher: encryptionCipher,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<Uint8List> getFile(String mxcUri) async {
 | 
			
		||||
    if (!PlatformInfos.isMobile) return null;
 | 
			
		||||
    final tempDirectory = (await getTemporaryDirectory()).path;
 | 
			
		||||
    final file = File('$tempDirectory/$mxcUri');
 | 
			
		||||
    if (await file.exists() == false) return null;
 | 
			
		||||
    final bytes = await file.readAsBytes();
 | 
			
		||||
    final encryptedFile = await _fileEncryptionKeysBox.get(mxcUri);
 | 
			
		||||
    encryptedFile.data = bytes;
 | 
			
		||||
    return await decryptFile(encryptedFile);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future storeFile(String mxcUri, Uint8List bytes, int time) async {
 | 
			
		||||
    if (!PlatformInfos.isMobile) return null;
 | 
			
		||||
    final tempDirectory = (await getTemporaryDirectory()).path;
 | 
			
		||||
    final file = File('$tempDirectory/$mxcUri');
 | 
			
		||||
    if (await file.exists()) return;
 | 
			
		||||
    final encryptedFile = await encryptFile(bytes);
 | 
			
		||||
    await _fileEncryptionKeysBox.put(mxcUri, encryptedFile);
 | 
			
		||||
    await file.writeAsBytes(encryptedFile.data);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static const int _maxAllowedFileAge = 1000 * 60 * 60 * 24 * 30;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<void> clear(int clientId) async {
 | 
			
		||||
    await super.clear(clientId);
 | 
			
		||||
    await _clearOldFiles(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> _clearOldFiles([bool clearAll = false]) async {
 | 
			
		||||
    if (!PlatformInfos.isMobile) return null;
 | 
			
		||||
    final tempDirectory = (await getTemporaryDirectory());
 | 
			
		||||
    final entities = tempDirectory.listSync();
 | 
			
		||||
    for (final entity in entities) {
 | 
			
		||||
      final file = File(entity.path);
 | 
			
		||||
      final createdAt = await file.lastModified();
 | 
			
		||||
      final age = DateTime.now().millisecondsSinceEpoch -
 | 
			
		||||
          createdAt.millisecondsSinceEpoch;
 | 
			
		||||
      if (clearAll || age > _maxAllowedFileAge) {
 | 
			
		||||
        final mxcUri = file.path.split('/').last;
 | 
			
		||||
        Logs().v('Delete old cashed file: $mxcUri');
 | 
			
		||||
        await file.delete();
 | 
			
		||||
        await _fileEncryptionKeysBox.delete(mxcUri);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class EncryptedFileAdapter extends TypeAdapter<EncryptedFile> {
 | 
			
		||||
  @override
 | 
			
		||||
  final typeId = 0;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  EncryptedFile read(BinaryReader reader) {
 | 
			
		||||
    final map = reader.read();
 | 
			
		||||
    return EncryptedFile(k: map['k'], iv: map['iv'], sha256: map['sha256']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void write(BinaryWriter writer, EncryptedFile obj) {
 | 
			
		||||
    writer.write({'k': obj.k, 'iv': obj.iv, 'sha256': obj.sha256});
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import 'package:famedlysdk/famedlysdk.dart';
 | 
			
		||||
import 'package:famedlysdk/encryption.dart';
 | 
			
		||||
import 'package:fluffychat/utils/database/flutter_famedly_sdk_hive_database.dart';
 | 
			
		||||
import 'package:matrix_api_lite/fake_matrix_api.dart';
 | 
			
		||||
import '../platform_infos.dart';
 | 
			
		||||
import '../famedlysdk_store.dart';
 | 
			
		||||
@ -25,7 +26,10 @@ class FluffyClient extends Client {
 | 
			
		||||
          importantStateEvents: <String>{
 | 
			
		||||
            'im.ponies.room_emotes', // we want emotes to work properly
 | 
			
		||||
          },
 | 
			
		||||
          databaseBuilder: testMode ? null : getDatabase,
 | 
			
		||||
          databaseBuilder: testMode
 | 
			
		||||
              ? null
 | 
			
		||||
              : FlutterFamedlySdkHiveDatabase.hiveDatabaseBuilder,
 | 
			
		||||
          legacyDatabaseBuilder: testMode ? null : getDatabase,
 | 
			
		||||
          supportedLoginTypes: {
 | 
			
		||||
            AuthenticationTypes.password,
 | 
			
		||||
            if (PlatformInfos.isMobile || PlatformInfos.isWeb)
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,8 @@ extension RoomStatusExtension on Room {
 | 
			
		||||
      }
 | 
			
		||||
      return L10n.of(context).lastSeenLongTimeAgo;
 | 
			
		||||
    }
 | 
			
		||||
    return L10n.of(context).countParticipants(mJoinedMemberCount.toString());
 | 
			
		||||
    return L10n.of(context)
 | 
			
		||||
        .countParticipants(summary.mJoinedMemberCount.toString());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String getLocalizedTypingText(BuildContext context) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								pubspec.lock
									
									
									
									
									
								
							@ -222,8 +222,8 @@ packages:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
    description:
 | 
			
		||||
      path: "."
 | 
			
		||||
      ref: main
 | 
			
		||||
      resolved-ref: "6fae2e1426fa440b09bafb9bc23e8791037c6efe"
 | 
			
		||||
      ref: "krille/hive"
 | 
			
		||||
      resolved-ref: bc9672d82489cdaf058c9ac00183a4611b443573
 | 
			
		||||
      url: "https://gitlab.com/famedly/famedlysdk.git"
 | 
			
		||||
    source: git
 | 
			
		||||
    version: "0.1.0"
 | 
			
		||||
@ -459,6 +459,20 @@ packages:
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "0.7.0"
 | 
			
		||||
  hive:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
      name: hive
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "2.0.4"
 | 
			
		||||
  hive_flutter:
 | 
			
		||||
    dependency: "direct main"
 | 
			
		||||
    description:
 | 
			
		||||
      name: hive_flutter
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "1.0.0"
 | 
			
		||||
  html:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
@ -584,7 +598,7 @@ packages:
 | 
			
		||||
      name: matrix_api_lite
 | 
			
		||||
      url: "https://pub.dartlang.org"
 | 
			
		||||
    source: hosted
 | 
			
		||||
    version: "0.3.1"
 | 
			
		||||
    version: "0.3.3"
 | 
			
		||||
  matrix_link_text:
 | 
			
		||||
    dependency: transitive
 | 
			
		||||
    description:
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ dependencies:
 | 
			
		||||
  famedlysdk:
 | 
			
		||||
    git:
 | 
			
		||||
      url: https://gitlab.com/famedly/famedlysdk.git
 | 
			
		||||
      ref: main
 | 
			
		||||
      ref: krille/hive
 | 
			
		||||
  fcm_shared_isolate:
 | 
			
		||||
    git:
 | 
			
		||||
      url: https://gitlab.com/famedly/libraries/fcm_shared_isolate.git
 | 
			
		||||
@ -41,6 +41,7 @@ dependencies:
 | 
			
		||||
  flutter_svg: ^0.21.0+1
 | 
			
		||||
  flutter_typeahead: ^3.1.1
 | 
			
		||||
  future_loading_dialog: ^0.1.2
 | 
			
		||||
  hive_flutter: ^1.0.0
 | 
			
		||||
  image_picker: ^0.7.4
 | 
			
		||||
  intl: any
 | 
			
		||||
  localstorage: ^4.0.0+1
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user