Merge branch 'encrypt-collection-name' into ui_refresh
This commit is contained in:
commit
013c1576be
7 changed files with 254 additions and 93 deletions
|
@ -5,24 +5,35 @@ import 'package:path/path.dart';
|
|||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:photos/models/collection.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:sqflite_migration/sqflite_migration.dart';
|
||||
|
||||
class CollectionsDB {
|
||||
static final _databaseName = "ente.collections.db";
|
||||
static final _databaseVersion = 1;
|
||||
|
||||
static final collectionsTable = 'collections';
|
||||
static final table = 'collections';
|
||||
static final tempTable = 'temp_collections';
|
||||
|
||||
static final columnID = 'collection_id';
|
||||
static final columnOwner = 'owner';
|
||||
static final columnEncryptedKey = 'encrypted_key';
|
||||
static final columnKeyDecryptionNonce = 'key_decryption_nonce';
|
||||
static final columnName = 'name';
|
||||
static final columnEncryptedName = 'encrypted_name';
|
||||
static final columnNameDecryptionNonce = 'name_decryption_nonce';
|
||||
static final columnType = 'type';
|
||||
static final columnEncryptedPath = 'encrypted_path';
|
||||
static final columnPathDecryptionNonce = 'path_decryption_nonce';
|
||||
static final columnSharees = 'sharees';
|
||||
static final columnUpdationTime = 'updation_time';
|
||||
|
||||
static final intitialScript = [...createTable(table)];
|
||||
static final migrationScripts = [
|
||||
...alterNameToAllowNULL(),
|
||||
...addEncryptedName(),
|
||||
];
|
||||
|
||||
final dbConfig = MigrationConfig(
|
||||
initializationScript: intitialScript, migrationScripts: migrationScripts);
|
||||
|
||||
CollectionsDB._privateConstructor();
|
||||
static final CollectionsDB instance = CollectionsDB._privateConstructor();
|
||||
|
||||
|
@ -36,35 +47,61 @@ class CollectionsDB {
|
|||
_initDatabase() async {
|
||||
Directory documentsDirectory = await getApplicationDocumentsDirectory();
|
||||
String path = join(documentsDirectory.path, _databaseName);
|
||||
return await openDatabase(
|
||||
path,
|
||||
version: _databaseVersion,
|
||||
onCreate: _onCreate,
|
||||
);
|
||||
return await openDatabaseWithMigration(path, dbConfig);
|
||||
}
|
||||
|
||||
Future _onCreate(Database db, int version) async {
|
||||
await db.execute('''
|
||||
CREATE TABLE $collectionsTable (
|
||||
$columnID INTEGER PRIMARY KEY NOT NULL,
|
||||
$columnOwner TEXT NOT NULL,
|
||||
$columnEncryptedKey TEXT NOT NULL,
|
||||
$columnKeyDecryptionNonce TEXT,
|
||||
$columnName TEXT NOT NULL,
|
||||
$columnType TEXT NOT NULL,
|
||||
$columnEncryptedPath TEXT,
|
||||
$columnPathDecryptionNonce TEXT,
|
||||
$columnSharees TEXT,
|
||||
$columnUpdationTime TEXT NOT NULL
|
||||
)
|
||||
''');
|
||||
static List<String> createTable(String tableName) {
|
||||
return [
|
||||
'''
|
||||
CREATE TABLE $tableName (
|
||||
$columnID INTEGER PRIMARY KEY NOT NULL,
|
||||
$columnOwner TEXT NOT NULL,
|
||||
$columnEncryptedKey TEXT NOT NULL,
|
||||
$columnKeyDecryptionNonce TEXT,
|
||||
$columnName TEXT,
|
||||
$columnType TEXT NOT NULL,
|
||||
$columnEncryptedPath TEXT,
|
||||
$columnPathDecryptionNonce TEXT,
|
||||
$columnSharees TEXT,
|
||||
$columnUpdationTime TEXT NOT NULL
|
||||
);
|
||||
'''
|
||||
];
|
||||
}
|
||||
|
||||
static List<String> alterNameToAllowNULL() {
|
||||
return [
|
||||
...createTable(tempTable),
|
||||
'''
|
||||
INSERT INTO $tempTable
|
||||
SELECT *
|
||||
FROM $table;
|
||||
|
||||
DROP TABLE $table;
|
||||
|
||||
ALTER TABLE $tempTable
|
||||
RENAME TO $table;
|
||||
'''
|
||||
];
|
||||
}
|
||||
|
||||
static List<String> addEncryptedName() {
|
||||
return [
|
||||
'''
|
||||
ALTER TABLE $table
|
||||
ADD COLUMN $columnEncryptedName TEXT;
|
||||
''',
|
||||
'''ALTER TABLE $table
|
||||
ADD COLUMN $columnNameDecryptionNonce TEXT;
|
||||
'''
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<dynamic>> insert(List<Collection> collections) async {
|
||||
final db = await instance.database;
|
||||
var batch = db.batch();
|
||||
for (final collection in collections) {
|
||||
batch.insert(collectionsTable, _getRowForCollection(collection),
|
||||
batch.insert(table, _getRowForCollection(collection),
|
||||
conflictAlgorithm: ConflictAlgorithm.replace);
|
||||
}
|
||||
return await batch.commit();
|
||||
|
@ -72,7 +109,7 @@ class CollectionsDB {
|
|||
|
||||
Future<List<Collection>> getAllCollections() async {
|
||||
final db = await instance.database;
|
||||
final rows = await db.query(collectionsTable);
|
||||
final rows = await db.query(table);
|
||||
final collections = List<Collection>();
|
||||
for (final row in rows) {
|
||||
collections.add(_convertToCollection(row));
|
||||
|
@ -83,7 +120,7 @@ class CollectionsDB {
|
|||
Future<int> getLastCollectionUpdationTime() async {
|
||||
final db = await instance.database;
|
||||
final rows = await db.query(
|
||||
collectionsTable,
|
||||
table,
|
||||
orderBy: '$columnUpdationTime DESC',
|
||||
limit: 1,
|
||||
);
|
||||
|
@ -97,7 +134,7 @@ class CollectionsDB {
|
|||
Future<int> deleteCollection(int collectionID) async {
|
||||
final db = await instance.database;
|
||||
return db.delete(
|
||||
collectionsTable,
|
||||
table,
|
||||
where: '$columnID = ?',
|
||||
whereArgs: [collectionID],
|
||||
);
|
||||
|
@ -110,6 +147,8 @@ class CollectionsDB {
|
|||
row[columnEncryptedKey] = collection.encryptedKey;
|
||||
row[columnKeyDecryptionNonce] = collection.keyDecryptionNonce;
|
||||
row[columnName] = collection.name;
|
||||
row[columnEncryptedName] = collection.encryptedName;
|
||||
row[columnNameDecryptionNonce] = collection.nameDecryptionNonce;
|
||||
row[columnType] = Collection.typeToString(collection.type);
|
||||
row[columnEncryptedPath] = collection.attributes.encryptedPath;
|
||||
row[columnPathDecryptionNonce] = collection.attributes.pathDecryptionNonce;
|
||||
|
@ -126,6 +165,8 @@ class CollectionsDB {
|
|||
row[columnEncryptedKey],
|
||||
row[columnKeyDecryptionNonce],
|
||||
row[columnName],
|
||||
row[columnEncryptedName],
|
||||
row[columnNameDecryptionNonce],
|
||||
Collection.typeFromString(row[columnType]),
|
||||
CollectionAttributes(
|
||||
encryptedPath: row[columnEncryptedPath],
|
||||
|
|
|
@ -7,14 +7,15 @@ import 'package:photos/models/file.dart';
|
|||
import 'package:path/path.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:sqflite_migration/sqflite_migration.dart';
|
||||
|
||||
class FilesDB {
|
||||
static final _databaseName = "ente.files.db";
|
||||
static final _databaseVersion = 1;
|
||||
|
||||
static final Logger _logger = Logger("FilesDB");
|
||||
|
||||
static final table = 'files';
|
||||
static final tempTable = 'temp_files';
|
||||
|
||||
static final columnGeneratedID = '_id';
|
||||
static final columnUploadedFileID = 'uploaded_file_id';
|
||||
|
@ -37,6 +38,11 @@ class FilesDB {
|
|||
static final columnThumbnailDecryptionHeader = 'thumbnail_decryption_header';
|
||||
static final columnMetadataDecryptionHeader = 'metadata_decryption_header';
|
||||
|
||||
static final intitialScript = [...createTable(table), ...addIndex()];
|
||||
static final migrationScripts = [...alterDeviceFolderToAllowNULL()];
|
||||
|
||||
final dbConfig = MigrationConfig(
|
||||
initializationScript: intitialScript, migrationScripts: migrationScripts);
|
||||
// make this a singleton class
|
||||
FilesDB._privateConstructor();
|
||||
static final FilesDB instance = FilesDB._privateConstructor();
|
||||
|
@ -54,42 +60,65 @@ class FilesDB {
|
|||
_initDatabase() async {
|
||||
Directory documentsDirectory = await getApplicationDocumentsDirectory();
|
||||
String path = join(documentsDirectory.path, _databaseName);
|
||||
return await openDatabase(path,
|
||||
version: _databaseVersion, onCreate: _onCreate);
|
||||
return await openDatabaseWithMigration(path, dbConfig);
|
||||
}
|
||||
|
||||
// SQL code to create the database table
|
||||
Future _onCreate(Database db, int version) async {
|
||||
await db.execute('''
|
||||
CREATE TABLE $table (
|
||||
$columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
$columnLocalID TEXT,
|
||||
$columnUploadedFileID INTEGER,
|
||||
$columnOwnerID INTEGER,
|
||||
$columnCollectionID INTEGER,
|
||||
$columnTitle TEXT NOT NULL,
|
||||
$columnDeviceFolder TEXT NOT NULL,
|
||||
$columnLatitude REAL,
|
||||
$columnLongitude REAL,
|
||||
$columnFileType INTEGER,
|
||||
$columnIsEncrypted INTEGER DEFAULT 1,
|
||||
$columnModificationTime TEXT NOT NULL,
|
||||
$columnEncryptedKey TEXT,
|
||||
$columnKeyDecryptionNonce TEXT,
|
||||
$columnFileDecryptionHeader TEXT,
|
||||
$columnThumbnailDecryptionHeader TEXT,
|
||||
$columnMetadataDecryptionHeader TEXT,
|
||||
$columnIsDeleted INTEGER DEFAULT 0,
|
||||
$columnCreationTime TEXT NOT NULL,
|
||||
$columnUpdationTime TEXT,
|
||||
UNIQUE($columnUploadedFileID, $columnCollectionID)
|
||||
);
|
||||
static List<String> createTable(String tableName) {
|
||||
return [
|
||||
'''
|
||||
CREATE TABLE $tableName (
|
||||
$columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
$columnLocalID TEXT,
|
||||
$columnUploadedFileID INTEGER,
|
||||
$columnOwnerID INTEGER,
|
||||
$columnCollectionID INTEGER,
|
||||
$columnTitle TEXT NOT NULL,
|
||||
$columnDeviceFolder TEXT,
|
||||
$columnLatitude REAL,
|
||||
$columnLongitude REAL,
|
||||
$columnFileType INTEGER,
|
||||
$columnIsEncrypted INTEGER DEFAULT 1,
|
||||
$columnModificationTime TEXT NOT NULL,
|
||||
$columnEncryptedKey TEXT,
|
||||
$columnKeyDecryptionNonce TEXT,
|
||||
$columnFileDecryptionHeader TEXT,
|
||||
$columnThumbnailDecryptionHeader TEXT,
|
||||
$columnMetadataDecryptionHeader TEXT,
|
||||
$columnIsDeleted INTEGER DEFAULT 0,
|
||||
$columnCreationTime TEXT NOT NULL,
|
||||
$columnUpdationTime TEXT,
|
||||
UNIQUE($columnUploadedFileID, $columnCollectionID)
|
||||
);
|
||||
''',
|
||||
];
|
||||
}
|
||||
|
||||
CREATE INDEX collection_id_index ON $table($columnCollectionID);
|
||||
CREATE INDEX device_folder_index ON $table($columnDeviceFolder);
|
||||
CREATE INDEX creation_time_index ON $table($columnCreationTime);
|
||||
CREATE INDEX updation_time_index ON $table($columnUpdationTime);
|
||||
''');
|
||||
static List<String> addIndex() {
|
||||
return [
|
||||
'''
|
||||
CREATE INDEX collection_id_index ON $table($columnCollectionID);
|
||||
CREATE INDEX device_folder_index ON $table($columnDeviceFolder);
|
||||
CREATE INDEX creation_time_index ON $table($columnCreationTime);
|
||||
CREATE INDEX updation_time_index ON $table($columnUpdationTime);
|
||||
'''
|
||||
];
|
||||
}
|
||||
|
||||
static List<String> alterDeviceFolderToAllowNULL() {
|
||||
return [
|
||||
...createTable(tempTable),
|
||||
'''
|
||||
INSERT INTO $tempTable
|
||||
SELECT *
|
||||
FROM $table;
|
||||
|
||||
DROP TABLE $table;
|
||||
|
||||
ALTER TABLE $tempTable
|
||||
RENAME TO $table;
|
||||
'''
|
||||
];
|
||||
}
|
||||
|
||||
Future<int> insert(File file) async {
|
||||
|
@ -427,16 +456,30 @@ class FilesDB {
|
|||
int creationTime,
|
||||
) async {
|
||||
final db = await instance.database;
|
||||
final rows = await db.query(
|
||||
table,
|
||||
where: '''$columnTitle=? AND $columnDeviceFolder=? AND
|
||||
var query;
|
||||
if (deviceFolder != null) {
|
||||
query = db.query(
|
||||
table,
|
||||
where: '''$columnTitle=? AND $columnDeviceFolder=? AND
|
||||
$columnCreationTime=?''',
|
||||
whereArgs: [
|
||||
title,
|
||||
deviceFolder,
|
||||
creationTime,
|
||||
],
|
||||
);
|
||||
whereArgs: [
|
||||
title,
|
||||
deviceFolder,
|
||||
creationTime,
|
||||
],
|
||||
);
|
||||
} else {
|
||||
query = db.query(
|
||||
table,
|
||||
where: '''$columnTitle=? AND
|
||||
$columnCreationTime=?''',
|
||||
whereArgs: [
|
||||
title,
|
||||
creationTime,
|
||||
],
|
||||
);
|
||||
}
|
||||
final rows = await query;
|
||||
if (rows.isNotEmpty) {
|
||||
return _convertToFiles(rows);
|
||||
} else {
|
||||
|
|
|
@ -8,6 +8,8 @@ class Collection {
|
|||
final String encryptedKey;
|
||||
final String keyDecryptionNonce;
|
||||
final String name;
|
||||
final String encryptedName;
|
||||
final String nameDecryptionNonce;
|
||||
final CollectionType type;
|
||||
final CollectionAttributes attributes;
|
||||
final List<User> sharees;
|
||||
|
@ -20,6 +22,8 @@ class Collection {
|
|||
this.encryptedKey,
|
||||
this.keyDecryptionNonce,
|
||||
this.name,
|
||||
this.encryptedName,
|
||||
this.nameDecryptionNonce,
|
||||
this.type,
|
||||
this.attributes,
|
||||
this.sharees,
|
||||
|
@ -54,6 +58,8 @@ class Collection {
|
|||
String encryptedKey,
|
||||
String keyDecryptionNonce,
|
||||
String name,
|
||||
String encryptedName,
|
||||
String nameDecryptionNonce,
|
||||
CollectionType type,
|
||||
CollectionAttributes attributes,
|
||||
List<User> sharees,
|
||||
|
@ -66,6 +72,8 @@ class Collection {
|
|||
encryptedKey ?? this.encryptedKey,
|
||||
keyDecryptionNonce ?? this.keyDecryptionNonce,
|
||||
name ?? this.name,
|
||||
encryptedName ?? this.encryptedName,
|
||||
nameDecryptionNonce ?? this.nameDecryptionNonce,
|
||||
type ?? this.type,
|
||||
attributes ?? this.attributes,
|
||||
sharees ?? this.sharees,
|
||||
|
@ -81,6 +89,8 @@ class Collection {
|
|||
'encryptedKey': encryptedKey,
|
||||
'keyDecryptionNonce': keyDecryptionNonce,
|
||||
'name': name,
|
||||
'encryptedName': encryptedName,
|
||||
'nameDecryptionNonce': nameDecryptionNonce,
|
||||
'type': typeToString(type),
|
||||
'attributes': attributes?.toMap(),
|
||||
'sharees': sharees?.map((x) => x?.toMap())?.toList(),
|
||||
|
@ -100,6 +110,8 @@ class Collection {
|
|||
map['encryptedKey'],
|
||||
map['keyDecryptionNonce'],
|
||||
map['name'],
|
||||
map['encryptedName'],
|
||||
map['nameDecryptionNonce'],
|
||||
typeFromString(map['type']),
|
||||
CollectionAttributes.fromMap(map['attributes']),
|
||||
sharees,
|
||||
|
@ -115,7 +127,7 @@ class Collection {
|
|||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Collection(id: $id, owner: $owner, encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce, name: $name, type: $type, attributes: $attributes, sharees: $sharees, updationTime: $updationTime, isDeleted: $isDeleted)';
|
||||
return 'Collection(id: $id, owner: $owner, encryptedKey: $encryptedKey, keyDecryptionNonce: $keyDecryptionNonce, name: $name, encryptedName: $encryptedName, nameDecryptionNonce: $nameDecryptionNonce, type: $type, attributes: $attributes, sharees: $sharees, updationTime: $updationTime, isDeleted: $isDeleted)';
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -128,6 +140,8 @@ class Collection {
|
|||
o.encryptedKey == encryptedKey &&
|
||||
o.keyDecryptionNonce == keyDecryptionNonce &&
|
||||
o.name == name &&
|
||||
o.encryptedName == encryptedName &&
|
||||
o.nameDecryptionNonce == nameDecryptionNonce &&
|
||||
o.type == type &&
|
||||
o.attributes == attributes &&
|
||||
listEquals(o.sharees, sharees) &&
|
||||
|
@ -142,6 +156,8 @@ class Collection {
|
|||
encryptedKey.hashCode ^
|
||||
keyDecryptionNonce.hashCode ^
|
||||
name.hashCode ^
|
||||
encryptedName.hashCode ^
|
||||
nameDecryptionNonce.hashCode ^
|
||||
type.hashCode ^
|
||||
attributes.hashCode ^
|
||||
sharees.hashCode ^
|
||||
|
@ -159,19 +175,23 @@ enum CollectionType {
|
|||
class CollectionAttributes {
|
||||
final String encryptedPath;
|
||||
final String pathDecryptionNonce;
|
||||
final int version;
|
||||
|
||||
CollectionAttributes({
|
||||
this.encryptedPath,
|
||||
this.pathDecryptionNonce,
|
||||
this.version,
|
||||
});
|
||||
|
||||
CollectionAttributes copyWith({
|
||||
String encryptedPath,
|
||||
String pathDecryptionNonce,
|
||||
int version,
|
||||
}) {
|
||||
return CollectionAttributes(
|
||||
encryptedPath: encryptedPath ?? this.encryptedPath,
|
||||
pathDecryptionNonce: pathDecryptionNonce ?? this.pathDecryptionNonce,
|
||||
version: version ?? this.version,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -183,6 +203,7 @@ class CollectionAttributes {
|
|||
if (pathDecryptionNonce != null) {
|
||||
map['pathDecryptionNonce'] = pathDecryptionNonce;
|
||||
}
|
||||
if (version != null) map['version'] = version;
|
||||
return map;
|
||||
}
|
||||
|
||||
|
@ -192,6 +213,7 @@ class CollectionAttributes {
|
|||
return CollectionAttributes(
|
||||
encryptedPath: map['encryptedPath'],
|
||||
pathDecryptionNonce: map['pathDecryptionNonce'],
|
||||
version: map['version'] ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -202,7 +224,7 @@ class CollectionAttributes {
|
|||
|
||||
@override
|
||||
String toString() =>
|
||||
'CollectionAttributes(encryptedPath: $encryptedPath, pathDecryptionNonce: $pathDecryptionNonce)';
|
||||
'CollectionAttributes(encryptedPath: $encryptedPath, pathDecryptionNonce: $pathDecryptionNonce, version: $version)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object o) {
|
||||
|
@ -210,11 +232,13 @@ class CollectionAttributes {
|
|||
|
||||
return o is CollectionAttributes &&
|
||||
o.encryptedPath == encryptedPath &&
|
||||
o.pathDecryptionNonce == pathDecryptionNonce;
|
||||
o.pathDecryptionNonce == pathDecryptionNonce &&
|
||||
o.version == version;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => encryptedPath.hashCode ^ pathDecryptionNonce.hashCode;
|
||||
int get hashCode =>
|
||||
encryptedPath.hashCode ^ pathDecryptionNonce.hashCode ^ version.hashCode;
|
||||
}
|
||||
|
||||
class User {
|
||||
|
|
|
@ -160,20 +160,24 @@ class CollectionsService {
|
|||
Uint8List getCollectionKey(int collectionID) {
|
||||
if (!_cachedKeys.containsKey(collectionID)) {
|
||||
final collection = _collectionIDToCollections[collectionID];
|
||||
final encryptedKey = Sodium.base642bin(collection.encryptedKey);
|
||||
if (collection.owner.id == _config.getUserID()) {
|
||||
_cachedKeys[collectionID] = CryptoUtil.decryptSync(encryptedKey,
|
||||
_config.getKey(), Sodium.base642bin(collection.keyDecryptionNonce));
|
||||
} else {
|
||||
_cachedKeys[collectionID] = CryptoUtil.openSealSync(
|
||||
encryptedKey,
|
||||
Sodium.base642bin(_config.getKeyAttributes().publicKey),
|
||||
_config.getSecretKey());
|
||||
}
|
||||
_cachedKeys[collectionID] = _getDecryptedKey(collection);
|
||||
}
|
||||
return _cachedKeys[collectionID];
|
||||
}
|
||||
|
||||
Uint8List _getDecryptedKey(Collection collection) {
|
||||
final encryptedKey = Sodium.base642bin(collection.encryptedKey);
|
||||
if (collection.owner.id == _config.getUserID()) {
|
||||
return CryptoUtil.decryptSync(encryptedKey, _config.getKey(),
|
||||
Sodium.base642bin(collection.keyDecryptionNonce));
|
||||
} else {
|
||||
return CryptoUtil.openSealSync(
|
||||
encryptedKey,
|
||||
Sodium.base642bin(_config.getKeyAttributes().publicKey),
|
||||
_config.getSecretKey());
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<Collection>> _fetchCollections(int sinceTime) {
|
||||
return _dio
|
||||
.get(
|
||||
|
@ -203,12 +207,15 @@ class CollectionsService {
|
|||
Future<Collection> createAlbum(String albumName) async {
|
||||
final key = CryptoUtil.generateKey();
|
||||
final encryptedKeyData = CryptoUtil.encryptSync(key, _config.getKey());
|
||||
final encryptedName = CryptoUtil.encryptSync(utf8.encode(albumName), key);
|
||||
final collection = await createAndCacheCollection(Collection(
|
||||
null,
|
||||
null,
|
||||
Sodium.bin2base64(encryptedKeyData.encryptedData),
|
||||
Sodium.bin2base64(encryptedKeyData.nonce),
|
||||
albumName,
|
||||
null,
|
||||
Sodium.bin2base64(encryptedName.encryptedData),
|
||||
Sodium.bin2base64(encryptedName.nonce),
|
||||
CollectionType.album,
|
||||
CollectionAttributes(),
|
||||
null,
|
||||
|
@ -223,18 +230,20 @@ class CollectionsService {
|
|||
}
|
||||
final key = CryptoUtil.generateKey();
|
||||
final encryptedKeyData = CryptoUtil.encryptSync(key, _config.getKey());
|
||||
final encryptedPath =
|
||||
CryptoUtil.encryptSync(utf8.encode(path), _config.getKey());
|
||||
final encryptedPath = CryptoUtil.encryptSync(utf8.encode(path), key);
|
||||
final collection = await createAndCacheCollection(Collection(
|
||||
null,
|
||||
null,
|
||||
Sodium.bin2base64(encryptedKeyData.encryptedData),
|
||||
Sodium.bin2base64(encryptedKeyData.nonce),
|
||||
path,
|
||||
null,
|
||||
Sodium.bin2base64(encryptedPath.encryptedData),
|
||||
Sodium.bin2base64(encryptedPath.nonce),
|
||||
CollectionType.folder,
|
||||
CollectionAttributes(
|
||||
encryptedPath: Sodium.bin2base64(encryptedPath.encryptedData),
|
||||
pathDecryptionNonce: Sodium.bin2base64(encryptedPath.nonce)),
|
||||
pathDecryptionNonce: Sodium.bin2base64(encryptedPath.nonce),
|
||||
version: 1),
|
||||
null,
|
||||
null,
|
||||
));
|
||||
|
@ -308,18 +317,49 @@ class CollectionsService {
|
|||
}
|
||||
|
||||
void _cacheCollectionAttributes(Collection collection) {
|
||||
final collectionWithDecryptedName =
|
||||
_getCollectionWithDecryptedName(collection);
|
||||
if (collection.attributes.encryptedPath != null) {
|
||||
_localCollections[decryptCollectionPath(collection)] = collection;
|
||||
_localCollections[decryptCollectionPath(collection)] =
|
||||
collectionWithDecryptedName;
|
||||
}
|
||||
_collectionIDToCollections[collection.id] = collection;
|
||||
_collectionIDToCollections[collection.id] = collectionWithDecryptedName;
|
||||
}
|
||||
|
||||
String decryptCollectionPath(Collection collection) {
|
||||
final key = collection.attributes.version == 1
|
||||
? getCollectionKey(collection.id)
|
||||
: _config.getKey();
|
||||
return utf8.decode(CryptoUtil.decryptSync(
|
||||
Sodium.base642bin(collection.attributes.encryptedPath),
|
||||
_config.getKey(),
|
||||
key,
|
||||
Sodium.base642bin(collection.attributes.pathDecryptionNonce)));
|
||||
}
|
||||
|
||||
Collection _getCollectionWithDecryptedName(Collection collection) {
|
||||
var name;
|
||||
if (collection.encryptedName != null &&
|
||||
collection.encryptedName.isNotEmpty) {
|
||||
name = utf8.decode(CryptoUtil.decryptSync(
|
||||
Sodium.base642bin(collection.encryptedName),
|
||||
_getDecryptedKey(collection),
|
||||
Sodium.base642bin(collection.nameDecryptionNonce)));
|
||||
return Collection(
|
||||
collection.id,
|
||||
collection.owner,
|
||||
collection.encryptedKey,
|
||||
collection.keyDecryptionNonce,
|
||||
name,
|
||||
collection.encryptedName,
|
||||
collection.nameDecryptionNonce,
|
||||
collection.type,
|
||||
collection.attributes,
|
||||
collection.sharees,
|
||||
collection.updationTime,
|
||||
);
|
||||
} else
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
class AddFilesRequest {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_sodium/flutter_sodium.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/event_bus.dart';
|
||||
|
@ -74,13 +76,16 @@ class FavoritesService {
|
|||
}
|
||||
final key = CryptoUtil.generateKey();
|
||||
final encryptedKeyData = CryptoUtil.encryptSync(key, _config.getKey());
|
||||
final encryptedName = CryptoUtil.encryptSync(utf8.encode("Favorites"), key);
|
||||
final collection =
|
||||
await _collectionsService.createAndCacheCollection(Collection(
|
||||
null,
|
||||
null,
|
||||
Sodium.bin2base64(encryptedKeyData.encryptedData),
|
||||
Sodium.bin2base64(encryptedKeyData.nonce),
|
||||
"Favorites",
|
||||
null,
|
||||
Sodium.bin2base64(encryptedName.encryptedData),
|
||||
Sodium.bin2base64(encryptedName.nonce),
|
||||
CollectionType.favorites,
|
||||
CollectionAttributes(),
|
||||
null,
|
||||
|
|
|
@ -728,6 +728,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
sqflite_migration:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite_migration
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -14,7 +14,7 @@ description: ente photos application
|
|||
version: 0.0.20+20
|
||||
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -27,6 +27,7 @@ dependencies:
|
|||
path: thirdparty/flutter_photo_manager
|
||||
provider: ^3.1.0
|
||||
sqflite: ^1.3.0
|
||||
sqflite_migration: ^0.2.0
|
||||
path_provider: ^1.6.5
|
||||
shared_preferences: ^0.5.6
|
||||
dio: ^3.0.9
|
||||
|
|
Loading…
Add table
Reference in a new issue