file_upload_manager.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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/file.dart';
  8. import 'package:photos/models/upload_url.dart';
  9. import 'package:photos/utils/crypto_util.dart';
  10. import 'package:photos/utils/file_name_util.dart';
  11. import 'package:photos/utils/file_util.dart';
  12. class FileUploadManager {
  13. final _logger = Logger("FileUploadManager");
  14. final _dio = Dio();
  15. Future<UploadURL> getUploadURL() {
  16. return Dio()
  17. .get(
  18. Configuration.instance.getHttpEndpoint() +
  19. "/encrypted-files/upload-url",
  20. options: Options(
  21. headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  22. )
  23. .then((response) => UploadURL.fromMap(response.data));
  24. }
  25. Future<String> putFile(UploadURL uploadURL, io.File file) async {
  26. _logger.info("Putting file to " + uploadURL.url);
  27. return Dio()
  28. .put(uploadURL.url,
  29. data: file.openRead(),
  30. options: Options(headers: {
  31. Headers.contentLengthHeader: await file.length(),
  32. }))
  33. .catchError((e) {
  34. _logger.severe(e);
  35. }).then((value) {
  36. return uploadURL.objectKey;
  37. });
  38. }
  39. Future<File> encryptAndUploadFile(File file) async {
  40. final key = CryptoUtil.getSecureRandomBytes(length: 32);
  41. final base64EncodedKey = base64.encode(key);
  42. final iv = CryptoUtil.getSecureRandomBytes(length: 16);
  43. final base64EncodedIV = base64.encode(iv);
  44. final encryptedKey =
  45. CryptoUtil.aesEncrypt(key, Configuration.instance.getKey(), iv);
  46. final base64EncodedEncryptedKey = base64.encode(encryptedKey);
  47. final encryptedFileName = file.generatedID.toString() + ".aes";
  48. final tempDirectory = Configuration.instance.getTempDirectory();
  49. final encryptedFilePath = tempDirectory + encryptedFileName;
  50. await CryptoUtil.encryptDataToFile(
  51. await getBytesFromDisk(file), encryptedFilePath, base64EncodedKey);
  52. final fileUploadURL = await getUploadURL();
  53. String fileObjectKey =
  54. await putFile(fileUploadURL, io.File(encryptedFilePath));
  55. final thumbnailData = (await (await file.getAsset())
  56. .thumbDataWithSize(THUMBNAIL_LARGE_SIZE, THUMBNAIL_LARGE_SIZE));
  57. final encryptedThumbnailName =
  58. file.generatedID.toString() + "_thumbnail.aes";
  59. final encryptedThumbnailPath = tempDirectory + encryptedThumbnailName;
  60. await CryptoUtil.encryptDataToFile(
  61. thumbnailData, encryptedThumbnailPath, base64EncodedKey);
  62. final thumbnailUploadURL = await getUploadURL();
  63. String thumbnailObjectKey =
  64. await putFile(thumbnailUploadURL, io.File(encryptedThumbnailPath));
  65. final metadata = jsonEncode(file.getMetadata());
  66. final encryptedMetadata = await CryptoUtil.encryptDataToData(
  67. utf8.encode(metadata), base64EncodedKey);
  68. final data = {
  69. "fileObjectKey": fileObjectKey,
  70. "thumbnailObjectKey": thumbnailObjectKey,
  71. "metadata": encryptedMetadata,
  72. "encryptedKey": base64EncodedEncryptedKey,
  73. "encryptedKeyIV": base64EncodedIV,
  74. };
  75. return _dio
  76. .post(
  77. Configuration.instance.getHttpEndpoint() + "/encrypted-files",
  78. options:
  79. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  80. data: data,
  81. )
  82. .then((response) {
  83. io.File(encryptedFilePath).deleteSync();
  84. io.File(encryptedThumbnailPath).deleteSync();
  85. final data = response.data;
  86. file.uploadedFileID = data["id"];
  87. file.updationTime = data["updationTime"];
  88. file.ownerID = data["ownerID"];
  89. file.encryptedKey = base64EncodedEncryptedKey;
  90. file.encryptedKeyIV = base64EncodedIV;
  91. return file;
  92. });
  93. }
  94. Future<File> uploadFile(File localPhoto) async {
  95. final title = getJPGFileNameForHEIC(localPhoto);
  96. final formData = FormData.fromMap({
  97. "file": MultipartFile.fromBytes(await getBytesFromDisk(localPhoto),
  98. filename: title),
  99. "deviceFileID": localPhoto.localID,
  100. "deviceFolder": localPhoto.deviceFolder,
  101. "title": title,
  102. "creationTime": localPhoto.creationTime,
  103. "modificationTime": localPhoto.modificationTime,
  104. });
  105. return _dio
  106. .post(
  107. Configuration.instance.getHttpEndpoint() + "/files",
  108. options:
  109. Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
  110. data: formData,
  111. )
  112. .then((response) {
  113. return File.fromJson(response.data);
  114. });
  115. }
  116. }