Bläddra i källkod

Decrypt, save and display encrypted thumbnails

Vishnu Mohandas 5 år sedan
förälder
incheckning
f6d3a7e6bd

+ 26 - 3
lib/core/configuration.dart

@@ -1,3 +1,5 @@
+import 'dart:io' as io;
+import 'package:path_provider/path_provider.dart';
 import 'package:photos/utils/crypto_util.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 
@@ -14,9 +16,17 @@ class Configuration {
   static const keyKey = "key";
 
   SharedPreferences _preferences;
+  String _documentsDirectory;
+  String _tempDirectory;
+  String _thumbnailsDirectory;
 
   Future<void> init() async {
     _preferences = await SharedPreferences.getInstance();
+    _documentsDirectory = (await getApplicationDocumentsDirectory()).path;
+    _tempDirectory = _documentsDirectory + "/temp/";
+    _thumbnailsDirectory = _documentsDirectory + "/thumbnails/";
+    new io.Directory(_tempDirectory).createSync(recursive: true);
+    new io.Directory(_thumbnailsDirectory).createSync(recursive: true);
   }
 
   String getEndpoint() {
@@ -71,7 +81,8 @@ class Configuration {
   }
 
   bool hasOptedForE2E() {
-    return _preferences.getBool(hasOptedForE2EKey);
+    return true;
+    // return _preferences.getBool(hasOptedForE2EKey);
   }
 
   Future<void> generateAndSaveKey(String passphrase) async {
@@ -81,8 +92,20 @@ class Configuration {
 
   // TODO: Encrypt with a passphrase and store in secure storage
   String getKey() {
-    // return "hello";
-    return _preferences.getString(keyKey);
+    return "8qD++K3xkgjIl3dIsGiTze5PhYtxiS5AtOeZw+Bl1z0=";
+    // return _preferences.getString(keyKey);
+  }
+
+  String getDocumentsDirectory() {
+    return _documentsDirectory;
+  }
+
+  String getThumbnailsDirectory() {
+    return _thumbnailsDirectory;
+  }
+
+  String getTempDirectory() {
+    return _tempDirectory;
   }
 
   bool hasConfiguredAccount() {

+ 8 - 2
lib/models/file.dart

@@ -125,8 +125,11 @@ class File {
   }
 
   String getDownloadUrl() {
+    final api = isEncrypted ? "encrypted-files" : "files";
     return Configuration.instance.getHttpEndpoint() +
-        "/files/download/" +
+        "/" +
+        api +
+        "/download/" +
         uploadedFileID.toString() +
         "?token=" +
         Configuration.instance.getToken();
@@ -143,8 +146,11 @@ class File {
   }
 
   String getThumbnailUrl() {
+    final api = isEncrypted ? "encrypted-files" : "files";
     return Configuration.instance.getHttpEndpoint() +
-        "/files/preview/" +
+        "/" +
+        api +
+        "/preview/" +
         uploadedFileID.toString() +
         "?token=" +
         Configuration.instance.getToken();

+ 3 - 12
lib/photo_sync_manager.dart

@@ -10,7 +10,6 @@ import 'package:photos/db/files_db.dart';
 import 'package:photos/events/photo_upload_event.dart';
 import 'package:photos/events/user_authenticated_event.dart';
 import 'package:photos/file_repository.dart';
-import 'package:path_provider/path_provider.dart';
 import 'package:photo_manager/photo_manager.dart';
 import 'package:photos/models/file_type.dart';
 import 'package:photos/utils/crypto_util.dart';
@@ -29,7 +28,6 @@ class PhotoSyncManager {
   bool _isSyncInProgress = false;
   Future<void> _existingSync;
   SharedPreferences _prefs;
-  String _encryptedFilesDirectory;
 
   static final _syncTimeKey = "sync_time";
   static final _encryptedFilesSyncTimeKey = "encrypted_files_sync_time";
@@ -82,7 +80,6 @@ class PhotoSyncManager {
     if (lastDBUpdationTime == null) {
       lastDBUpdationTime = 0;
     }
-    await _initializeDirectories();
 
     final pathEntities =
         await _getGalleryList(lastDBUpdationTime, syncStartTime);
@@ -303,15 +300,15 @@ class PhotoSyncManager {
 
     final filePath = (await (await file.getAsset()).originFile).path;
     final encryptedFileName = file.generatedID.toString() + ".aes";
-    final encryptedFilePath = _encryptedFilesDirectory + encryptedFileName;
+    final tempDirectory = Configuration.instance.getTempDirectory();
+    final encryptedFilePath = tempDirectory + encryptedFileName;
     await CryptoUtil.encryptFileToFile(filePath, encryptedFilePath, key);
 
     final thumbnailData = (await (await file.getAsset())
         .thumbDataWithSize(THUMBNAIL_LARGE_SIZE, THUMBNAIL_LARGE_SIZE));
     final encryptedThumbnailName =
         file.generatedID.toString() + "_thumbnail.aes";
-    final encryptedThumbnailPath =
-        _encryptedFilesDirectory + encryptedThumbnailName;
+    final encryptedThumbnailPath = tempDirectory + encryptedThumbnailName;
     await CryptoUtil.encryptDataToFile(
         thumbnailData, encryptedThumbnailPath, key);
 
@@ -392,12 +389,6 @@ class PhotoSyncManager {
         .catchError((e) => _logger.severe(e));
   }
 
-  Future _initializeDirectories() async {
-    final externalPath = (await getApplicationDocumentsDirectory()).path;
-    _encryptedFilesDirectory = externalPath + "/encrypted/files/";
-    new io.Directory(_encryptedFilesDirectory).createSync(recursive: true);
-  }
-
   Future<bool> _insertFilesToDB(List<File> files, int timestamp) async {
     await _db.insertMultiple(files);
     _logger.info("Inserted " + files.length.toString() + " files.");

+ 52 - 6
lib/ui/thumbnail_widget.dart

@@ -1,12 +1,16 @@
 import 'package:cached_network_image/cached_network_image.dart';
+import 'package:dio/dio.dart';
 import 'package:flutter/material.dart';
+import 'dart:io' as io;
 import 'package:photos/core/cache/thumbnail_cache.dart';
+import 'package:photos/core/configuration.dart';
 import 'package:photos/file_repository.dart';
 import 'package:photos/models/file.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/models/file_type.dart';
 import 'package:photos/ui/loading_widget.dart';
+import 'package:photos/utils/crypto_util.dart';
 import 'package:photos/utils/file_util.dart';
 
 class ThumbnailWidget extends StatefulWidget {
@@ -109,12 +113,54 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
   }
 
   Widget _getNetworkImage() {
-    return CachedNetworkImage(
-      imageUrl: widget.file.getThumbnailUrl(),
-      placeholder: (context, url) => loadWidget,
-      errorWidget: (context, url, error) => Icon(Icons.error),
-      fit: BoxFit.cover,
-    );
+    if (!widget.file.isEncrypted) {
+      return CachedNetworkImage(
+        imageUrl: widget.file.getThumbnailUrl(),
+        placeholder: (context, url) => loadWidget,
+        errorWidget: (context, url, error) => Icon(Icons.error),
+        fit: BoxFit.cover,
+      );
+    } else {
+      final thumbnailPath = Configuration.instance.getThumbnailsDirectory() +
+          widget.file.generatedID.toString() +
+          ".jpg";
+      final thumbnailFile = io.File(thumbnailPath);
+      if (thumbnailFile.existsSync()) {
+        return Image.file(
+          thumbnailFile,
+          fit: widget.fit,
+        );
+      } else {
+        final temporaryPath = Configuration.instance.getTempDirectory() +
+            widget.file.generatedID.toString() +
+            "_thumbnail.aes";
+        final decryptedFileFuture = Dio()
+            .download(widget.file.getThumbnailUrl(), temporaryPath)
+            .then((_) async {
+          await CryptoUtil.decryptFileToFile(
+              temporaryPath, thumbnailPath, Configuration.instance.getKey());
+          io.File(temporaryPath).deleteSync();
+          return io.File(thumbnailPath);
+        });
+        return FutureBuilder<io.File>(
+          future: decryptedFileFuture,
+          builder: (context, snapshot) {
+            if (snapshot.hasData) {
+              // TODO: Cache data
+              return Image.file(
+                snapshot.data,
+                fit: widget.fit,
+              );
+            } else if (snapshot.hasError) {
+              _logger.warning(snapshot.error);
+              return Text(snapshot.error.toString());
+            } else {
+              return loadingWidget;
+            }
+          },
+        );
+      }
+    }
   }
 
   @override

+ 10 - 4
lib/utils/crypto_util.dart

@@ -1,3 +1,4 @@
+import 'dart:developer';
 import 'dart:typed_data';
 
 import 'package:aes_crypt/aes_crypt.dart';
@@ -33,23 +34,28 @@ class CryptoUtil {
 
   static Future<void> encryptFileToFile(
       String sourcePath, String destinationPath, String key) async {
-    final encrypter = _getEncrypter(key);
+    final encrypter = getEncrypter(key);
     await encrypter.encryptFile(sourcePath, destinationPath);
   }
 
   static Future<void> encryptDataToFile(
       Uint8List source, String destinationPath, String key) async {
-    final encrypter = _getEncrypter(key);
+    final encrypter = getEncrypter(key);
     await encrypter.encryptDataToFile(source, destinationPath);
   }
 
   static Future<void> decryptFileToFile(
       String sourcePath, String destinationPath, String key) async {
-    final encrypter = _getEncrypter(key);
+    final encrypter = getEncrypter(key);
     await encrypter.decryptFile(sourcePath, destinationPath);
   }
 
-  static AesCrypt _getEncrypter(String key) {
+  static Future<Uint8List> decryptFileToData(String sourcePath, String key) {
+    final encrypter = getEncrypter(key);
+    return encrypter.decryptDataFromFile(sourcePath);
+  }
+
+  static AesCrypt getEncrypter(String key) {
     final encrypter = AesCrypt(key);
     encrypter.aesSetMode(AesMode.cbc);
     encrypter.setOverwriteMode(AesCryptOwMode.on);