Skip to content

Commit

Permalink
Merge pull request #56 from theskyblockman/master
Browse files Browse the repository at this point in the history
Update to 1.3.0
  • Loading branch information
helomri authored Jul 23, 2023
2 parents 8ecb3aa + 743367b commit d41fa7b
Show file tree
Hide file tree
Showing 44 changed files with 751 additions and 397 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/flutter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ jobs:
channel: 'stable'
cache: true
- run: flutter pub get
- run: flutter analyze
- run: flutter analyze --no-fatal-infos --no-fatal-warnings
- run: flutter test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ app.*.map.json
/android/app/release

# For missing translations
/missingTranslations.json
/missingTranslations.json
/test/assets/*
2 changes: 1 addition & 1 deletion PRIVACY.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
The application, Life Chest does not collect, use or receive any user data. The user's privacy is our priority. All possible data we harvest is how many people have downloaded our application.
The application, Life Chest does not collect, use nor store any user personal data. The user's privacy is our priority. All possible data we harvest is provided by Google LLC and only monitors the application growth (installation success rate, total downloads, impressions and other metrics all in this same scope) for statistical purpose.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Life chest

An app to securely store your data locally
An app to securely store your data locally.

## Legal disclamer (MIT License)
## Legal disclaimer (MIT License)
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

## Features

- Singlethreaded ChaCha20 encryption/decryption (Natively implemented)
- Chest/Vault system (name to determine)
- Chest system
- See images
- View documents
- On-boarding
- Localization
- Remaking file cards in the ``GridView``
- Chaining file players with a ``PageView``
- File explorer in ``GridView``
- File explorer in ``PageView``
- File renaming
- Lazy loading
- Export files/vaults to their original file or to a new file format (.lcef or Life Chest Encrypted
Expand All @@ -23,10 +23,10 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
- Audio playing

## Credits
- Thanks to Syncfusion to let us use their software with their Open Source Community License.
- Thanks to Syncfusion for letting us use their software with their Open Source Community License. (NOTE: We are not using their software anymore because of their proprietary license)

## Support
I develop the Life Chest application ib my free time, if you want me to work more on it, you can buy me a coffee!
I develop the Life Chest application in my free time, to support what I am doing, you can buy me a coffee!

[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/N4N6N222N)

Expand Down
Binary file added android/app/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions android/app/src/main/res/drawable/ic_launcher_foreground.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="12.7"
android:viewportHeight="12.7">
<group android:scaleX="0.5"
android:scaleY="0.5"
android:translateX="3.175"
android:translateY="3.175">
<path
android:pathData="M6.35,8.229C7.135,7.514 7.64,7.014 7.865,6.727c0.225,-0.287 0.337,-0.575 0.337,-0.867 0,-0.282 -0.099,-0.523 -0.298,-0.721 -0.198,-0.198 -0.439,-0.298 -0.721,-0.298 -0.168,0 -0.324,0.033 -0.47,0.099 -0.146,0.066 -0.267,0.157 -0.364,0.271 -0.097,-0.115 -0.218,-0.205 -0.364,-0.271 -0.146,-0.066 -0.302,-0.099 -0.47,-0.099 -0.282,0 -0.523,0.099 -0.721,0.298 -0.198,0.198 -0.298,0.439 -0.298,0.721 0,0.141 0.02,0.276 0.06,0.403 0.04,0.128 0.126,0.276 0.258,0.443 0.132,0.168 0.32,0.37 0.562,0.609 0.243,0.238 0.567,0.542 0.972,0.913z"
android:strokeWidth="0.0132292"
android:fillColor="#d93235"/>
<path
android:pathData="m6.35,11.628c-1.235,-0.309 -2.249,-1.025 -3.043,-2.15 -0.794,-1.124 -1.191,-2.357 -1.191,-3.698v-3.149l4.233,-1.587 4.233,1.587v3.149c0,1.341 -0.397,2.573 -1.191,3.698 -0.794,1.124 -1.808,1.841 -3.043,2.15zM6.35,10.808c1.014,-0.335 1.841,-0.968 2.48,-1.898C9.47,7.979 9.79,6.936 9.79,5.781v-2.593l-3.44,-1.296 -3.44,1.296v2.593c0,1.155 0.32,2.198 0.959,3.129 0.639,0.93 1.466,1.563 2.48,1.898z"
android:strokeWidth="0.0132292"
android:fillColor="#000000"/>
</group>
</vector>
5 changes: 5 additions & 0 deletions android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
Binary file modified android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions android/app/src/main/res/values/ic_launcher_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFD8D9</color>
</resources>
1 change: 1 addition & 0 deletions fastlane/metadata/android/en-US/changelogs/10300.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fixed bugs and improved stability. The video viewer is now stable although less secure but secure enough to be used.
1 change: 1 addition & 0 deletions fastlane/metadata/android/fr-FR/changelogs/10300.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Bugs reglés et amelioration générale de la stabilité. Le lecteur vidéo est maintenant stable même si il est moins sécurisé mais assez pour être utilisé.
131 changes: 92 additions & 39 deletions lib/file_explorer/file_explorer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ import 'package:life_chest/vault.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';

typedef FileExportArgs = (String thumbnailFilePath, List<int> encryptionKey, Map<String, dynamic> data, List<int> fileContent, String unlockMechanismType, Map<String, dynamic> additionalUnlockData);
typedef FileExportArgs = (
String thumbnailFilePath,
List<int> encryptionKey,
Map<String, dynamic> data,
List<int> fileContent,
String unlockMechanismType,
Map<String, dynamic> additionalUnlockData
);

/// The file reader, this enable the user to see file and to browse between them while keeping a cache of them
class FileReader extends StatefulWidget {
Expand Down Expand Up @@ -440,20 +447,24 @@ class FileExplorerState extends State<FileExplorer> {

final receivePort = ReceivePort();

List<FileExportArgs> dataToExport = [];

for(FileThumbnail fileToExport in filesToExport) {
String unsafeData = (await VaultsManager.nonceStorage.read(key: fileToExport.localPath))!;
Map<String, dynamic> unsafeDataClone = Map.from(fileToExport.data);
unsafeDataClone['nonce'] = unsafeData;
dataToExport.add((
fileToExport.localPath,
encryptionKey,
unsafeDataClone,
fileToExport.file.readAsBytesSync(),
widget.vault.unlockMechanismType,
widget.vault.additionalUnlockData
));
}

Isolate.spawn(exportEncryptedThumbnails,
(receivePort.sendPort, List<FileExportArgs>.generate(filesToExport.length,
(index) {
FileThumbnail fileToExport =
filesToExport[index];
return (
fileToExport.localPath,
encryptionKey,
fileToExport.data,
fileToExport.file.readAsBytesSync(),
widget.vault.unlockMechanismType,
widget.vault.additionalUnlockData
);
})));
(receivePort.sendPort, dataToExport));

List<Uint8List> decryptedFiles = [];

Expand All @@ -480,7 +491,7 @@ class FileExplorerState extends State<FileExplorer> {
.showSnackBar(SnackBar(
content: Text(S
.of(context)
.savedToFolder)));
.savedToFolderWarning, style: const TextStyle(color: Colors.amber))));
}
});
}
Expand Down Expand Up @@ -536,9 +547,10 @@ class FileExplorerState extends State<FileExplorer> {

for (FileThumbnail thumbnail in filesToExport) {
Stream<List<int>> exportedFile =
SingleThreadedRecovery.loadAndDecryptFile(
await SingleThreadedRecovery.loadAndDecryptFile(
widget.vault.encryptionKey!,
thumbnail.file);
thumbnail.file,
Mac(thumbnail.data['mac']));

File fileToSaveTo =
File(join(saveLocation.path, thumbnail.name));
Expand All @@ -555,34 +567,74 @@ class FileExplorerState extends State<FileExplorer> {
child: Text(S.of(context).exportAsCleartext)),
PopupMenuItem(
onTap: () async {
List<FileThumbnail> filesToDelete = [];

for (FileThumbnail thumbnail in thumbnails) {
if (thumbnail.isSelected) {
if (thumbnail.file.existsSync()) {
thumbnail.file.deleteSync();
}
if(thumbnail.placeholder == FileThumbnailsPlaceholder.folder) {
for (MapEntry<String, dynamic> innerRawThumbnail in List.from(map.entries)) {
if(isWithin(thumbnail.fullLocalPath, innerRawThumbnail.value['name'])) {
File innerRawThumbnailFile = File(join(widget.vault.path, innerRawThumbnail.key));
if(innerRawThumbnailFile.existsSync()) {
innerRawThumbnailFile.deleteSync();
filesToDelete.add(thumbnail);
}
}

WidgetsBinding.instance
.addPostFrameCallback((timeStamp) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(S
.of(context)
.areYouSureDeleteFiles(
filesToDelete.length)),
content: Text(S
.of(context)
.lostDataContBeRecovered),
actions: [
TextButton(
onPressed: () => Navigator.pop(
context, false),
child: Text(S.of(context).no)),
TextButton(
onPressed: () => Navigator.pop(
context, true),
child: Text(S.of(context).yes))
])).then((value) async {
if (value == true) {
for (FileThumbnail thumbnail
in filesToDelete) {
if (thumbnail.file.existsSync()) {
thumbnail.file.deleteSync();
}
if (thumbnail.placeholder ==
FileThumbnailsPlaceholder.folder) {
for (MapEntry<String,
dynamic> innerRawThumbnail
in List.from(map.entries)) {
if (isWithin(thumbnail.fullLocalPath,
innerRawThumbnail.value['name'])) {
File innerRawThumbnailFile = File(
join(widget.vault.path,
innerRawThumbnail.key));
if (innerRawThumbnailFile
.existsSync()) {
innerRawThumbnailFile.deleteSync();
}
map.remove(innerRawThumbnail.key);
}
}
map.remove(innerRawThumbnail.key);
}
map.remove(thumbnail.localPath);
}
List<int> encryptedMap =
(await VaultsManager.encryptMap(
widget.vault, map))!;
setState(() {
// TODO: Forensic should be made to see if iOS/Android keeps any of the file data in storage, if yes fill the file with null bytes and then delete it.
File(join(widget.vault.path, '.map'))
.writeAsBytesSync(encryptedMap);
isSelectionMode = false;
thumbnailCollector = reloadThumbnails();
});
}
map.remove(thumbnail.localPath);
}
}
List<int> encryptedMap =
(await VaultsManager.encryptMap(
widget.vault, map))!;
setState(() {
// TODO: Forensic should be made to see if iOS/Android keeps any of the file data in storage, if yes fill the file with null bytes and then delete it.
File(join(widget.vault.path, '.map'))
.writeAsBytesSync(encryptedMap);
isSelectionMode = false;
thumbnailCollector = reloadThumbnails();
});
});
},
child: Text(S.of(context).delete)),
Expand Down Expand Up @@ -943,6 +995,7 @@ class FileExplorerState extends State<FileExplorer> {
return;
}
}

/// A helper method to know if an entity is 1 level deeper in the tree than a local path so that whe can know if the UI should draw it
static bool shouldThumbnailBeShown(
String fileLocalPath, String currentLocalPath) {
Expand Down
8 changes: 6 additions & 2 deletions lib/file_explorer/file_thumbnail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,12 @@ class FileThumbnail extends StatelessWidget {
return Column(
children: [
placeholder.gridIcon,
Text(name),
],
Expanded(child:
Center(
child: Text(name),
)
)
]
);
} else {
return Column(
Expand Down
5 changes: 3 additions & 2 deletions lib/file_explorer/file_unlock_wizard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ class FileUnlockWizardState extends State<FileUnlockWizard> {

Future<(Map<String, dynamic> metadata, List<int> data)> getOrUnlockFile(
List<int> fileToUnlock, SecretKey key) async {
print(unlockedMap);
for (List<int> unlockedFile in List.from(unlockedMap.keys)) {
if (listEquals(fileToUnlock, unlockedFile)) {
return unlockedMap[unlockedFile]!;
}
}

print(unlockedMap);
unlockedMap[fileToUnlock] =
(await FileExporter.importFile(fileToUnlock, key))!;

print(unlockedMap);
return unlockedMap[fileToUnlock]!;
}

Expand Down
Loading

0 comments on commit d41fa7b

Please sign in to comment.