file_uploader.dart 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import 'dart:convert';
  2. import 'dart:io' as io;
  3. import 'package:dio/dio.dart';
  4. import 'package:logging/logging.dart';
  5. import 'package:photos/core/configuration.dart';
  6. import 'package:photos/core/constants.dart';
  7. import 'package:photos/models/decryption_params.dart';
  8. import 'package:photos/models/file.dart';
  9. import 'package:photos/models/upload_url.dart';
  10. import 'package:photos/utils/crypto_util.dart';
  11. import 'package:photos/utils/file_name_util.dart';
  12. import 'package:photos/utils/file_util.dart';
  13. class FileUploader {
  14. final _logger = Logger("FileUploader");
  15. final _dio = Dio();
  16. Future<UploadURL> getUploadURL() {
  17. return Dio()
  18. .get(
  19. Configuration.instance.getHttpEndpoint() +
  20. "/encrypted-files/upload-url",
  21. options: Options(
  22. headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  23. )
  24. .then((response) => UploadURL.fromMap(response.data));
  25. }
  26. Future<String> putFile(UploadURL uploadURL, io.File file) async {
  27. _logger.info("Putting file to " + uploadURL.url);
  28. return Dio()
  29. .put(uploadURL.url,
  30. data: file.openRead(),
  31. options: Options(headers: {
  32. Headers.contentLengthHeader: await file.length(),
  33. }))
  34. .catchError((e) {
  35. _logger.severe(e);
  36. }).then((value) {
  37. return uploadURL.objectKey;
  38. });
  39. }
  40. Future<File> encryptAndUploadFile(File file) async {
  41. _logger.info("Uploading " + file.toString());
  42. final encryptedFileName = file.generatedID.toString() + ".encrypted";
  43. final tempDirectory = Configuration.instance.getTempDirectory();
  44. final encryptedFilePath = tempDirectory + encryptedFileName;
  45. final sourceFile = (await (await file.getAsset()).originFile);
  46. final encryptedFile = io.File(encryptedFilePath);
  47. final fileAttributes =
  48. await CryptoUtil.chachaEncrypt(sourceFile, encryptedFile);
  49. final fileUploadURL = await getUploadURL();
  50. String fileObjectKey = await putFile(fileUploadURL, encryptedFile);
  51. final encryptedFileKey = await CryptoUtil.encrypt(
  52. fileAttributes.key.bytes,
  53. key: Configuration.instance.getKey(),
  54. );
  55. final fileDecryptionParams = DecryptionParams(
  56. encryptedKey: encryptedFileKey.encryptedData.base64,
  57. keyDecryptionNonce: encryptedFileKey.nonce.base64,
  58. header: fileAttributes.header.base64,
  59. );
  60. final thumbnailData = (await (await file.getAsset()).thumbDataWithSize(
  61. THUMBNAIL_LARGE_SIZE,
  62. THUMBNAIL_LARGE_SIZE,
  63. quality: 50,
  64. ));
  65. final encryptedThumbnailName =
  66. file.generatedID.toString() + "_thumbnail.encrypted";
  67. final encryptedThumbnailPath = tempDirectory + encryptedThumbnailName;
  68. final encryptedThumbnail = await CryptoUtil.encrypt(thumbnailData);
  69. io.File(encryptedThumbnailPath)
  70. .writeAsBytesSync(encryptedThumbnail.encryptedData.bytes);
  71. final thumbnailUploadURL = await getUploadURL();
  72. String thumbnailObjectKey =
  73. await putFile(thumbnailUploadURL, io.File(encryptedThumbnailPath));
  74. final encryptedThumbnailKey = await CryptoUtil.encrypt(
  75. encryptedThumbnail.key.bytes,
  76. key: Configuration.instance.getKey(),
  77. );
  78. final thumbnailDecryptionParams = DecryptionParams(
  79. encryptedKey: encryptedThumbnailKey.encryptedData.base64,
  80. keyDecryptionNonce: encryptedThumbnailKey.nonce.base64,
  81. nonce: encryptedThumbnail.nonce.base64,
  82. );
  83. final metadata = jsonEncode(file.getMetadata());
  84. final encryptedMetadata = await CryptoUtil.encrypt(utf8.encode(metadata));
  85. final encryptedMetadataKey = await CryptoUtil.encrypt(
  86. encryptedMetadata.key.bytes,
  87. key: Configuration.instance.getKey(),
  88. );
  89. final metadataDecryptionParams = DecryptionParams(
  90. encryptedKey: encryptedMetadataKey.encryptedData.base64,
  91. keyDecryptionNonce: encryptedMetadataKey.nonce.base64,
  92. nonce: encryptedMetadata.nonce.base64,
  93. );
  94. final data = {
  95. "file": {
  96. "objectKey": fileObjectKey,
  97. "decryptionParams": fileDecryptionParams.toMap(),
  98. },
  99. "thumbnail": {
  100. "objectKey": thumbnailObjectKey,
  101. "decryptionParams": thumbnailDecryptionParams,
  102. },
  103. "metadata": {
  104. "encryptedData": encryptedMetadata.encryptedData.base64,
  105. "decryptionParams": metadataDecryptionParams,
  106. }
  107. };
  108. return _dio
  109. .post(
  110. Configuration.instance.getHttpEndpoint() + "/encrypted-files",
  111. options:
  112. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  113. data: data,
  114. )
  115. .then((response) {
  116. encryptedFile.deleteSync();
  117. io.File(encryptedThumbnailPath).deleteSync();
  118. final data = response.data;
  119. file.uploadedFileID = data["id"];
  120. file.updationTime = data["updationTime"];
  121. file.ownerID = data["ownerID"];
  122. file.fileDecryptionParams = fileDecryptionParams;
  123. file.thumbnailDecryptionParams = thumbnailDecryptionParams;
  124. file.metadataDecryptionParams = metadataDecryptionParams;
  125. return file;
  126. });
  127. }
  128. Future<File> uploadFile(File localPhoto) async {
  129. final title = getJPGFileNameForHEIC(localPhoto);
  130. final formData = FormData.fromMap({
  131. "file": MultipartFile.fromBytes(await getBytesFromDisk(localPhoto),
  132. filename: title),
  133. "deviceFileID": localPhoto.localID,
  134. "deviceFolder": localPhoto.deviceFolder,
  135. "title": title,
  136. "creationTime": localPhoto.creationTime,
  137. "modificationTime": localPhoto.modificationTime,
  138. });
  139. return _dio
  140. .post(
  141. Configuration.instance.getHttpEndpoint() + "/files",
  142. options:
  143. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  144. data: formData,
  145. )
  146. .then((response) {
  147. return File.fromJson(response.data);
  148. });
  149. }
  150. }