Преглед изворни кода

Adopt API to update file if already uploaded

Vishnu Mohandas пре 4 година
родитељ
комит
51f083d290
2 измењених фајлова са 137 додато и 50 уклоњено
  1. 5 3
      lib/utils/crypto_util.dart
  2. 132 47
      lib/utils/file_uploader.dart

+ 5 - 3
lib/utils/crypto_util.dart

@@ -38,7 +38,7 @@ EncryptionResult chachaEncryptFile(Map<String, dynamic> args) {
   logger.info("Encrypting file of size " + sourceFileLength.toString());
 
   final inputFile = sourceFile.openSync(mode: io.FileMode.read);
-  final key = Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
+  final key = args["key"] ?? Sodium.cryptoSecretstreamXchacha20poly1305Keygen();
   final initPushResult =
       Sodium.cryptoSecretstreamXchacha20poly1305InitPush(key);
   var bytesRead = 0;
@@ -155,11 +155,13 @@ class CryptoUtil {
 
   static Future<EncryptionResult> encryptFile(
     String sourceFilePath,
-    String destinationFilePath,
-  ) {
+    String destinationFilePath, {
+    Uint8List key,
+  }) {
     final args = Map<String, dynamic>();
     args["sourceFilePath"] = sourceFilePath;
     args["destinationFilePath"] = destinationFilePath;
+    args["key"] = key;
     return Computer().compute(chachaEncryptFile, param: args);
   }
 

+ 132 - 47
lib/utils/file_uploader.dart

@@ -4,13 +4,13 @@ import 'dart:convert';
 import 'dart:io' as io;
 import 'package:connectivity/connectivity.dart';
 import 'package:dio/dio.dart';
-import 'package:flutter_image_compress/flutter_image_compress.dart';
 import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/network.dart';
 import 'package:photos/db/files_db.dart';
+import 'package:photos/models/encryption_result.dart';
 import 'package:photos/models/file.dart';
 import 'package:photos/models/location.dart';
 import 'package:photos/models/upload_url.dart';
@@ -152,13 +152,26 @@ class FileUploader {
     final encryptedThumbnailPath =
         tempDirectory + file.generatedID.toString() + "_thumbnail.encrypted";
     final sourceFile = (await (await file.getAsset()).originFile);
+
     try {
+      var key;
+      var isAlreadyUploadedFile = file.uploadedFileID != null;
+      if (isAlreadyUploadedFile) {
+        key = decryptFileKey(file);
+      } else {
+        key = null;
+      }
+
       if (io.File(encryptedFilePath).existsSync()) {
         io.File(encryptedFilePath).deleteSync();
       }
       final encryptedFile = io.File(encryptedFilePath);
-      final fileAttributes =
-          await CryptoUtil.encryptFile(sourceFile.path, encryptedFilePath);
+
+      final fileAttributes = await CryptoUtil.encryptFile(
+        sourceFile.path,
+        encryptedFilePath,
+        key: key,
+      );
 
       var thumbnailData = (await (await file.getAsset()).thumbDataWithSize(
         THUMBNAIL_LARGE_SIZE,
@@ -201,15 +214,6 @@ class FileUploader {
 
       final encryptedMetadataData = CryptoUtil.encryptChaCha(
           utf8.encode(jsonEncode(file.getMetadata())), fileAttributes.key);
-
-      final encryptedFileKeyData = CryptoUtil.encryptSync(
-        fileAttributes.key,
-        CollectionsService.instance.getCollectionKey(collectionID),
-      );
-
-      final encryptedKey =
-          Sodium.bin2base64(encryptedFileKeyData.encryptedData);
-      final keyDecryptionNonce = Sodium.bin2base64(encryptedFileKeyData.nonce);
       final fileDecryptionHeader = Sodium.bin2base64(fileAttributes.header);
       final thumbnailDecryptionHeader =
           Sodium.bin2base64(encryptedThumbnailData.header);
@@ -217,41 +221,29 @@ class FileUploader {
           Sodium.bin2base64(encryptedMetadataData.encryptedData);
       final metadataDecryptionHeader =
           Sodium.bin2base64(encryptedMetadataData.header);
-
-      final request = {
-        "collectionID": collectionID,
-        "encryptedKey": encryptedKey,
-        "keyDecryptionNonce": keyDecryptionNonce,
-        "file": {
-          "objectKey": fileObjectKey,
-          "decryptionHeader": fileDecryptionHeader,
-        },
-        "thumbnail": {
-          "objectKey": thumbnailObjectKey,
-          "decryptionHeader": thumbnailDecryptionHeader,
-        },
-        "metadata": {
-          "encryptedData": encryptedMetadata,
-          "decryptionHeader": metadataDecryptionHeader,
-        }
-      };
-      final response = await _dio.post(
-        Configuration.instance.getHttpEndpoint() + "/files",
-        options: Options(
-            headers: {"X-Auth-Token": Configuration.instance.getToken()}),
-        data: request,
-      );
-      final data = response.data;
-      file.uploadedFileID = data["id"];
-      file.collectionID = collectionID;
-      file.updationTime = data["updationTime"];
-      file.ownerID = data["ownerID"];
-      file.encryptedKey = encryptedKey;
-      file.keyDecryptionNonce = keyDecryptionNonce;
-      file.fileDecryptionHeader = fileDecryptionHeader;
-      file.thumbnailDecryptionHeader = thumbnailDecryptionHeader;
-      file.metadataDecryptionHeader = metadataDecryptionHeader;
-      return file;
+      if (isAlreadyUploadedFile) {
+        return await _updateFile(
+          file,
+          fileObjectKey,
+          fileDecryptionHeader,
+          thumbnailObjectKey,
+          thumbnailDecryptionHeader,
+          encryptedMetadata,
+          metadataDecryptionHeader,
+        );
+      } else {
+        return await _uploadFile(
+          file,
+          collectionID,
+          fileAttributes,
+          fileObjectKey,
+          fileDecryptionHeader,
+          thumbnailObjectKey,
+          thumbnailDecryptionHeader,
+          encryptedMetadata,
+          metadataDecryptionHeader,
+        );
+      }
     } catch (e, s) {
       _logger.severe(
           "File upload failed for " + file.generatedID.toString(), e, s);
@@ -269,6 +261,99 @@ class FileUploader {
     }
   }
 
+  Future<File> _uploadFile(
+    File file,
+    int collectionID,
+    EncryptionResult fileAttributes,
+    String fileObjectKey,
+    String fileDecryptionHeader,
+    String thumbnailObjectKey,
+    String thumbnailDecryptionHeader,
+    String encryptedMetadata,
+    String metadataDecryptionHeader,
+  ) async {
+    final encryptedFileKeyData = CryptoUtil.encryptSync(
+      fileAttributes.key,
+      CollectionsService.instance.getCollectionKey(collectionID),
+    );
+    final encryptedKey = Sodium.bin2base64(encryptedFileKeyData.encryptedData);
+    final keyDecryptionNonce = Sodium.bin2base64(encryptedFileKeyData.nonce);
+    final request = {
+      "collectionID": collectionID,
+      "encryptedKey": encryptedKey,
+      "keyDecryptionNonce": keyDecryptionNonce,
+      "file": {
+        "objectKey": fileObjectKey,
+        "decryptionHeader": fileDecryptionHeader,
+      },
+      "thumbnail": {
+        "objectKey": thumbnailObjectKey,
+        "decryptionHeader": thumbnailDecryptionHeader,
+      },
+      "metadata": {
+        "encryptedData": encryptedMetadata,
+        "decryptionHeader": metadataDecryptionHeader,
+      }
+    };
+    final response = await _dio.post(
+      Configuration.instance.getHttpEndpoint() + "/files",
+      options:
+          Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
+      data: request,
+    );
+    final data = response.data;
+    file.uploadedFileID = data["id"];
+    file.collectionID = collectionID;
+    file.updationTime = data["updationTime"];
+    file.ownerID = data["ownerID"];
+    file.encryptedKey = encryptedKey;
+    file.keyDecryptionNonce = keyDecryptionNonce;
+    file.fileDecryptionHeader = fileDecryptionHeader;
+    file.thumbnailDecryptionHeader = thumbnailDecryptionHeader;
+    file.metadataDecryptionHeader = metadataDecryptionHeader;
+    return file;
+  }
+
+  Future<File> _updateFile(
+    File file,
+    String fileObjectKey,
+    String fileDecryptionHeader,
+    String thumbnailObjectKey,
+    String thumbnailDecryptionHeader,
+    String encryptedMetadata,
+    String metadataDecryptionHeader,
+  ) async {
+    final request = {
+      "id": file.uploadedFileID,
+      "file": {
+        "objectKey": fileObjectKey,
+        "decryptionHeader": fileDecryptionHeader,
+      },
+      "thumbnail": {
+        "objectKey": thumbnailObjectKey,
+        "decryptionHeader": thumbnailDecryptionHeader,
+      },
+      "metadata": {
+        "encryptedData": encryptedMetadata,
+        "decryptionHeader": metadataDecryptionHeader,
+      }
+    };
+    final response = await _dio.post(
+      Configuration.instance.getHttpEndpoint() + "/files",
+      options:
+          Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
+      data: request,
+    );
+    final data = response.data;
+    file.uploadedFileID = data["id"];
+    file.updationTime = data["updationTime"];
+    file.ownerID = data["ownerID"];
+    file.fileDecryptionHeader = fileDecryptionHeader;
+    file.thumbnailDecryptionHeader = thumbnailDecryptionHeader;
+    file.metadataDecryptionHeader = metadataDecryptionHeader;
+    return file;
+  }
+
   Future<UploadURL> _getUploadURL() async {
     if (_uploadURLs.isEmpty) {
       await _fetchUploadURLs();