diff --git a/.gitignore b/.gitignore
index e5111619..60a8e47a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,4 +84,7 @@ config.json
**/*.AppImage*
-.fvm
\ No newline at end of file
+.fvm
+
+# Rust stuff
+native/target
diff --git a/android/app/build.gradle b/android/app/build.gradle
index b387ab31..7f420591 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -33,6 +33,7 @@ if (keystorePropertiesFile.exists()) {
android {
compileSdkVersion 31
+ ndkVersion "22.1.7171670"
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@@ -64,7 +65,7 @@ android {
productFlavors {
def debugSigning = signingConfigs.debug
def releaseSigning = signingConfigs.release
-
+
dev {
signingConfig debugSigning
applicationId = "com.potatoproject.notes.dev"
@@ -73,7 +74,7 @@ android {
label: "Leaflet Dev",
]
}
-
+
ci {
signingConfig debugSigning
applicationId = "com.potatoproject.notes.ci"
@@ -82,7 +83,7 @@ android {
label: "Leaflet CI",
]
}
-
+
production {
signingConfig releaseSigning
applicationId = "com.potatoproject.notes"
@@ -103,3 +104,26 @@ dependencies {
implementation 'androidx.core:core-ktx:1.6.0-alpha02'
implementation 'androidx.annotation:annotation:1.2.0'
}
+
+[
+ new Tuple2('Debug', 'debug'),
+ new Tuple2('Profile', 'release'),
+ new Tuple2('Release', 'release')
+].each {
+ def taskPostfix = it.first
+ def profileMode = it.second
+
+ tasks.whenTaskAdded { task ->
+ if (task.name == "javaPreCompileDev$taskPostfix"
+ || task.name == "javaPreCompileCi$taskPostfix"
+ || task.name == "javaPreCompileProduction$taskPostfix") {
+ task.dependsOn "cargoBuild$taskPostfix"
+ }
+ }
+
+ tasks.register("cargoBuild$taskPostfix", Exec) {
+ // Until https://github.com/bbqsrc/cargo-ndk/pull/13 is merged,
+ // this workaround is necessary.
+ commandLine 'just', '-d', '../..', '--justfile', '../../justfile', "android-native-$profileMode"
+ }
+}
diff --git a/android/app/src/main/.gitignore b/android/app/src/main/.gitignore
new file mode 100644
index 00000000..34a6ddce
--- /dev/null
+++ b/android/app/src/main/.gitignore
@@ -0,0 +1 @@
+jniLibs
diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
index 9f484785..0eb5e903 100644
--- a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
+++ b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
@@ -105,10 +105,5 @@ public static void registerWith(@NonNull FlutterEngine flutterEngine) {
} catch(Exception e) {
Log.e(TAG, "Error registering plugin url_launcher_android, io.flutter.plugins.urllauncher.UrlLauncherPlugin", e);
}
- try {
- flutterEngine.getPlugins().add(new com.example.webcrypto.WebcryptoPlugin());
- } catch(Exception e) {
- Log.e(TAG, "Error registering plugin webcrypto, com.example.webcrypto.WebcryptoPlugin", e);
- }
}
}
diff --git a/android/build.gradle b/android/build.gradle
index 70b0efdb..da967c45 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,12 +1,12 @@
buildscript {
- ext.kotlin_version = '1.4.32'
+ ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.2.0'
+ classpath 'com.android.tools.build:gradle:7.3.0-alpha02'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 344a490b..9d9047b7 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
diff --git a/android/local.properties b/android/local.properties
index 97073040..6ed3a2f2 100644
--- a/android/local.properties
+++ b/android/local.properties
@@ -1,5 +1,5 @@
-sdk.dir=C:\\bin
+sdk.dir=C:\\Users\\akshi\\AppData\\Local\\Android\\sdk
flutter.sdk=C:\\Users\\akshi\\fvm\\versions\\stable
-flutter.buildMode=debug
+flutter.buildMode=release
flutter.versionName=2.0.1
flutter.versionCode=21
\ No newline at end of file
diff --git a/docs/how-it-works.md b/docs/how-it-works.md
new file mode 100644
index 00000000..00cc6b25
--- /dev/null
+++ b/docs/how-it-works.md
@@ -0,0 +1,10 @@
+# How it works
+
+## File format
+
+| 2 bytes | JSON metadata | 16 bytes | 12 bytes | 16 bytes | Payload |
+| --------------------------------------- | ------------- | ------------ | ------------------------- | ----------- | ------- |
+| length of JSON metadata (little endian) | string | PBKDF2 nonce | AES initialization vector | AES-GCM tag | binary |
+
+The binary payload is a zip encrypted with AES-256-GCM using a key derived using
+PBKDF2 with 100,000 iterations and SHA-512 hash.
diff --git a/docs/how-to-build.md b/docs/how-to-build.md
new file mode 100644
index 00000000..1a787faf
--- /dev/null
+++ b/docs/how-to-build.md
@@ -0,0 +1,33 @@
+# How to build
+
+## Requirements
+
+- [Flutter](https://flutter.dev) with its dependencies for the respective platform
+- [just](https://just.systems), our build system
+- [rustup](https://rustup.sh) with its nightly toolchain
+- [flutter_rust_bridge](https://fzyzcjy.github.io/flutter_rust_bridge/)'s dependencies for your platform
+
+## Windows
+
+Run `flutter build windows`. This will automatically compile the rust
+project and generate the bridge bindings.
+
+## Android
+
+Run `flutter build apk`. This will automatically compile the rust project and
+generate the bridge bindings.
+
+## Linux
+
+Run `flutter build linux`. This will automatically compile the rust
+project and generate the bridge bindings.
+
+## macOS
+
+Run `flutter build macos`. This will compile the rust project but won't generate
+the bridge bindings. Manually run `just gen` to generate the bindings.
+
+## iOS
+
+Run `flutter build ios`. This will compile the rust project but won't generate
+the bridge bindings. Manually run `just gen` to generate the bindings.
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 6b4c0f78..f2872cf4 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 8.0
+ 9.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 87e01ca5..723465b7 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -51,7 +51,7 @@ PODS:
- Flutter
- package_info_plus (0.4.5):
- Flutter
- - path_provider (0.0.1):
+ - path_provider_ios (0.0.1):
- Flutter
- quick_actions (0.0.1):
- Flutter
@@ -60,21 +60,21 @@ PODS:
- SDWebImage/Core (5.8.1)
- share_plus (0.0.1):
- Flutter
- - shared_preferences (0.0.1):
+ - shared_preferences_ios (0.0.1):
- Flutter
- sqflite (0.0.2):
- Flutter
- FMDB (>= 2.7.5)
- - SQLCipher (4.4.3):
- - SQLCipher/standard (= 4.4.3)
- - SQLCipher/common (4.4.3)
- - SQLCipher/standard (4.4.3):
+ - SQLCipher (4.5.1):
+ - SQLCipher/standard (= 4.5.1)
+ - SQLCipher/common (4.5.1)
+ - SQLCipher/standard (4.5.1):
- SQLCipher/common
- sqlcipher_flutter_libs (0.0.1):
- Flutter
- - SQLCipher (~> 4.4.3)
+ - SQLCipher (~> 4.5.0)
- SwiftyGif (5.4.0)
- - url_launcher (0.0.1):
+ - url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
@@ -87,13 +87,13 @@ DEPENDENCIES:
- local_auth (from `.symlinks/plugins/local_auth/ios`)
- loggy (from `.symlinks/plugins/loggy/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- - path_provider (from `.symlinks/plugins/path_provider/ios`)
+ - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- quick_actions (from `.symlinks/plugins/quick_actions/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
+ - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- sqlcipher_flutter_libs (from `.symlinks/plugins/sqlcipher_flutter_libs/ios`)
- - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
+ - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
@@ -123,44 +123,44 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/loggy/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
- path_provider:
- :path: ".symlinks/plugins/path_provider/ios"
+ path_provider_ios:
+ :path: ".symlinks/plugins/path_provider_ios/ios"
quick_actions:
:path: ".symlinks/plugins/quick_actions/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
- shared_preferences:
- :path: ".symlinks/plugins/shared_preferences/ios"
+ shared_preferences_ios:
+ :path: ".symlinks/plugins/shared_preferences_ios/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
sqlcipher_flutter_libs:
:path: ".symlinks/plugins/sqlcipher_flutter_libs/ios"
- url_launcher:
- :path: ".symlinks/plugins/url_launcher/ios"
+ url_launcher_ios:
+ :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
biometric_storage: 1400f1382af3a4cc2bf05340e13c3d8de873ceb9
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
- Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
+ Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
- image_picker: 50e7c7ff960e5f58faa4d1f4af84a771c671bc4a
- local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd
+ image_picker: 541dcbb3b9cf32d87eacbd957845d8651d6c62c3
+ local_auth: ef62030a2731330b95df7ef1331bd15f6a64b8a6
loggy: 3dc4ef725f5bbe5961a7515c079385f8e9f21b80
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
- path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
- quick_actions: 6cb2390c4dab0e737c94573c27e18d9666710720
+ path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
+ quick_actions: cd83314083fa994182e6cd9e7516167a215a4f83
SDWebImage: e3eae2eda88578db0685a0c88597fdadd9433f05
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
- shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
+ shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
- SQLCipher: 155ffeafc9ac102e5c9b68e3e9a1297a98a27096
- sqlcipher_flutter_libs: eae301083f1a44f7afea4c4593dd546ca6f16651
+ SQLCipher: 712e8416685e8e575b9b0706ffee71678b2fdcf8
+ sqlcipher_flutter_libs: 87686ab669dda991b2f384e4bcbb04b93e19c8fe
SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7
- url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
+ url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
PODFILE CHECKSUM: 3efef3e4c4241ddf19165efb8229df7447127bfd
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 2c7ca4f7..c53cc751 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -10,12 +10,38 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 7C01879B27D7B2D8004154F9 /* libnative_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C01879627D7B2A5004154F9 /* libnative_static.a */; };
+ 7C01879D27D7B42E004154F9 /* bridge_generated.h in Resources */ = {isa = PBXBuildFile; fileRef = 7C01879C27D7B423004154F9 /* bridge_generated.h */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
AC6F6326FAFB54BE2380D47A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22BB535E4226D2D51F4708EF /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
+/* Begin PBXContainerItemProxy section */
+ 7C01879527D7B2A5004154F9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 7C01878827D7B2A0004154F9 /* native.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = CA60AD08325E2969E816930C;
+ remoteInfo = "native-staticlib";
+ };
+ 7C01879727D7B2A5004154F9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 7C01878827D7B2A0004154F9 /* native.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = CA604B1163E6EAC3B2E0A336;
+ remoteInfo = "native-cdylib";
+ };
+ 7C01879927D7B2C8004154F9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 7C01878827D7B2A0004154F9 /* native.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = CA60AD08325E35B1519BA4B0;
+ remoteInfo = "native-staticlib";
+ };
+/* End PBXContainerItemProxy section */
+
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
@@ -39,6 +65,8 @@
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 7C01878827D7B2A0004154F9 /* native.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = native.xcodeproj; path = ../../native/native.xcodeproj; sourceTree = ""; };
+ 7C01879C27D7B423004154F9 /* bridge_generated.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bridge_generated.h; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -56,6 +84,7 @@
buildActionMask = 2147483647;
files = (
AC6F6326FAFB54BE2380D47A /* Pods_Runner.framework in Frameworks */,
+ 7C01879B27D7B2D8004154F9 /* libnative_static.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -80,6 +109,15 @@
path = Pods;
sourceTree = "";
};
+ 7C01879127D7B2A5004154F9 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 7C01879627D7B2A5004154F9 /* libnative_static.a */,
+ 7C01879827D7B2A5004154F9 /* native.dylib */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -113,6 +151,8 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ 7C01879C27D7B423004154F9 /* bridge_generated.h */,
+ 7C01878827D7B2A0004154F9 /* native.xcodeproj */,
AF15965825B626F400B02D98 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
@@ -145,6 +185,7 @@
buildRules = (
);
dependencies = (
+ 7C01879A27D7B2C8004154F9 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
@@ -157,7 +198,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1020;
+ LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -177,6 +218,12 @@
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 7C01879127D7B2A5004154F9 /* Products */;
+ ProjectRef = 7C01878827D7B2A0004154F9 /* native.xcodeproj */;
+ },
+ );
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
@@ -184,6 +231,23 @@
};
/* End PBXProject section */
+/* Begin PBXReferenceProxy section */
+ 7C01879627D7B2A5004154F9 /* libnative_static.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libnative_static.a;
+ remoteRef = 7C01879527D7B2A5004154F9 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ 7C01879827D7B2A5004154F9 /* native.dylib */ = {
+ isa = PBXReferenceProxy;
+ fileType = "compiled.mach-o.dylib";
+ path = native.dylib;
+ remoteRef = 7C01879727D7B2A5004154F9 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
@@ -193,6 +257,7 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ 7C01879D27D7B42E004154F9 /* bridge_generated.h in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -280,6 +345,14 @@
};
/* End PBXSourcesBuildPhase section */
+/* Begin PBXTargetDependency section */
+ 7C01879A27D7B2C8004154F9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = "native-staticlib";
+ targetProxy = 7C01879927D7B2C8004154F9 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a28140cf..3db53b6e 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
Bool {
+ dummy_method_to_enforce_bundling()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h
index 308a2a56..ffb33c60 100644
--- a/ios/Runner/Runner-Bridging-Header.h
+++ b/ios/Runner/Runner-Bridging-Header.h
@@ -1 +1,2 @@
#import "GeneratedPluginRegistrant.h"
+#import "bridge_generated.h"
diff --git a/ios/Runner/bridge_generated.h b/ios/Runner/bridge_generated.h
new file mode 100644
index 00000000..26a6b674
--- /dev/null
+++ b/ios/Runner/bridge_generated.h
@@ -0,0 +1,47 @@
+#include
+#include
+#include
+
+typedef struct wire_uint_8_list {
+ uint8_t *ptr;
+ int32_t len;
+} wire_uint_8_list;
+
+typedef struct WireSyncReturnStruct {
+ uint8_t *ptr;
+ int32_t len;
+ bool success;
+} WireSyncReturnStruct;
+
+typedef int64_t DartPort;
+
+typedef bool (*DartPostCObjectFnType)(DartPort port_id, void *message);
+
+void wire_derive_key(int64_t port_,
+ struct wire_uint_8_list *password,
+ struct wire_uint_8_list *nonce);
+
+void wire_encrypt(int64_t port_,
+ struct wire_uint_8_list *data,
+ struct wire_uint_8_list *password,
+ struct wire_uint_8_list *key_nonce,
+ struct wire_uint_8_list *aes_nonce);
+
+void wire_decrypt(int64_t port_, struct wire_uint_8_list *data, struct wire_uint_8_list *password);
+
+struct wire_uint_8_list *new_uint_8_list(int32_t len);
+
+void free_WireSyncReturnStruct(struct WireSyncReturnStruct val);
+
+void store_dart_post_cobject(DartPostCObjectFnType ptr);
+
+static int64_t dummy_method_to_enforce_bundling(void) {
+ int64_t dummy_var = 0;
+ dummy_var ^= ((int64_t) (void*) wire_derive_key);
+ dummy_var ^= ((int64_t) (void*) wire_encrypt);
+ dummy_var ^= ((int64_t) (void*) wire_decrypt);
+ dummy_var ^= ((int64_t) (void*) new_uint_8_list);
+ dummy_var ^= ((int64_t) (void*) free_WireSyncReturnStruct);
+ dummy_var ^= ((int64_t) (void*) store_dart_post_cobject);
+ return dummy_var;
+}
\ No newline at end of file
diff --git a/justfile b/justfile
new file mode 100644
index 00000000..87d85eef
--- /dev/null
+++ b/justfile
@@ -0,0 +1,35 @@
+# Homebrew installs LLVM in a place that is not visible to ffigen.
+# This explicitly specifies the place where the LLVM dylibs are kept.
+llvm_path := if os() == "macos" {
+ "--llvm-path /usr/local/opt/llvm"
+} else {
+ ""
+}
+
+set windows-powershell := true
+
+default: gen
+
+gen:
+ flutter_rust_bridge_codegen {{llvm_path}} \
+ --rust-input native/src/api.rs \
+ --dart-output lib/bridge_generated.dart \
+ --c-output ios/Runner/bridge_generated.h
+ cp ios/Runner/bridge_generated.h macos/Runner/bridge_generated.h
+ flutter pub run build_runner build --delete-conflicting-outputs
+
+lint:
+ cd native ; cargo fmt
+ dart format .
+
+clean:
+ flutter clean
+ cd native ; cargo clean
+
+android-native-release: gen
+ cd native ; cargo ndk -t armeabi-v7a -t arm64-v8a -t x86_64 -o ../android/app/src/main/jniLibs build --release
+
+android-native-debug: gen
+ cd native ; cargo ndk -t armeabi-v7a -t arm64-v8a -t x86_64 -o ../android/app/src/main/jniLibs build
+
+# vim:expandtab:sw=4:ts=4
\ No newline at end of file
diff --git a/lib/bridge_generated.dart b/lib/bridge_generated.dart
new file mode 100644
index 00000000..fca27f9d
--- /dev/null
+++ b/lib/bridge_generated.dart
@@ -0,0 +1,277 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+// Generated by `flutter_rust_bridge`.
+
+// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, prefer_single_quotes
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'dart:convert';
+import 'dart:typed_data';
+import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';
+import 'dart:ffi' as ffi;
+
+abstract class Native {
+ Future deriveKey(
+ {required String password, required Uint8List nonce, dynamic hint});
+
+ Future encrypt(
+ {required Uint8List data,
+ required String password,
+ required Uint8List keyNonce,
+ required Uint8List aesNonce,
+ dynamic hint});
+
+ Future decrypt(
+ {required Uint8List data, required String password, dynamic hint});
+}
+
+class NativeImpl extends FlutterRustBridgeBase implements Native {
+ factory NativeImpl(ffi.DynamicLibrary dylib) =>
+ NativeImpl.raw(NativeWire(dylib));
+
+ NativeImpl.raw(NativeWire inner) : super(inner);
+
+ Future deriveKey(
+ {required String password, required Uint8List nonce, dynamic hint}) =>
+ executeNormal(FlutterRustBridgeTask(
+ callFfi: (port_) => inner.wire_derive_key(
+ port_,
+ _api2wire_String(password),
+ _api2wire_ZeroCopyBuffer_Uint8List(nonce)),
+ parseSuccessData: _wire2api_ZeroCopyBuffer_Uint8List,
+ constMeta: const FlutterRustBridgeTaskConstMeta(
+ debugName: "derive_key",
+ argNames: ["password", "nonce"],
+ ),
+ argValues: [password, nonce],
+ hint: hint,
+ ));
+
+ Future encrypt(
+ {required Uint8List data,
+ required String password,
+ required Uint8List keyNonce,
+ required Uint8List aesNonce,
+ dynamic hint}) =>
+ executeNormal(FlutterRustBridgeTask(
+ callFfi: (port_) => inner.wire_encrypt(
+ port_,
+ _api2wire_ZeroCopyBuffer_Uint8List(data),
+ _api2wire_String(password),
+ _api2wire_ZeroCopyBuffer_Uint8List(keyNonce),
+ _api2wire_ZeroCopyBuffer_Uint8List(aesNonce)),
+ parseSuccessData: _wire2api_opt_ZeroCopyBuffer_Uint8List,
+ constMeta: const FlutterRustBridgeTaskConstMeta(
+ debugName: "encrypt",
+ argNames: ["data", "password", "keyNonce", "aesNonce"],
+ ),
+ argValues: [data, password, keyNonce, aesNonce],
+ hint: hint,
+ ));
+
+ Future decrypt(
+ {required Uint8List data, required String password, dynamic hint}) =>
+ executeNormal(FlutterRustBridgeTask(
+ callFfi: (port_) => inner.wire_decrypt(
+ port_,
+ _api2wire_ZeroCopyBuffer_Uint8List(data),
+ _api2wire_String(password)),
+ parseSuccessData: _wire2api_opt_ZeroCopyBuffer_Uint8List,
+ constMeta: const FlutterRustBridgeTaskConstMeta(
+ debugName: "decrypt",
+ argNames: ["data", "password"],
+ ),
+ argValues: [data, password],
+ hint: hint,
+ ));
+
+ // Section: api2wire
+ ffi.Pointer _api2wire_String(String raw) {
+ return _api2wire_uint_8_list(utf8.encoder.convert(raw));
+ }
+
+ ffi.Pointer _api2wire_ZeroCopyBuffer_Uint8List(
+ Uint8List raw) {
+ return _api2wire_uint_8_list(raw);
+ }
+
+ int _api2wire_u8(int raw) {
+ return raw;
+ }
+
+ ffi.Pointer _api2wire_uint_8_list(Uint8List raw) {
+ final ans = inner.new_uint_8_list(raw.length);
+ ans.ref.ptr.asTypedList(raw.length).setAll(0, raw);
+ return ans;
+ }
+
+ // Section: api_fill_to_wire
+
+}
+
+// Section: wire2api
+Uint8List _wire2api_ZeroCopyBuffer_Uint8List(dynamic raw) {
+ return raw as Uint8List;
+}
+
+Uint8List? _wire2api_opt_ZeroCopyBuffer_Uint8List(dynamic raw) {
+ return raw == null ? null : _wire2api_ZeroCopyBuffer_Uint8List(raw);
+}
+
+int _wire2api_u8(dynamic raw) {
+ return raw as int;
+}
+
+Uint8List _wire2api_uint_8_list(dynamic raw) {
+ return raw as Uint8List;
+}
+
+// ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+
+/// generated by flutter_rust_bridge
+class NativeWire implements FlutterRustBridgeWireBase {
+ /// Holds the symbol lookup function.
+ final ffi.Pointer Function(String symbolName)
+ _lookup;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ NativeWire(ffi.DynamicLibrary dynamicLibrary)
+ : _lookup = dynamicLibrary.lookup;
+
+ /// The symbols are looked up with [lookup].
+ NativeWire.fromLookup(
+ ffi.Pointer Function(String symbolName)
+ lookup)
+ : _lookup = lookup;
+
+ void wire_derive_key(
+ int port_,
+ ffi.Pointer password,
+ ffi.Pointer nonce,
+ ) {
+ return _wire_derive_key(
+ port_,
+ password,
+ nonce,
+ );
+ }
+
+ late final _wire_derive_keyPtr = _lookup<
+ ffi.NativeFunction<
+ ffi.Void Function(ffi.Int64, ffi.Pointer,
+ ffi.Pointer)>>('wire_derive_key');
+ late final _wire_derive_key = _wire_derive_keyPtr.asFunction<
+ void Function(
+ int, ffi.Pointer, ffi.Pointer)>();
+
+ void wire_encrypt(
+ int port_,
+ ffi.Pointer data,
+ ffi.Pointer password,
+ ffi.Pointer key_nonce,
+ ffi.Pointer aes_nonce,
+ ) {
+ return _wire_encrypt(
+ port_,
+ data,
+ password,
+ key_nonce,
+ aes_nonce,
+ );
+ }
+
+ late final _wire_encryptPtr = _lookup<
+ ffi.NativeFunction<
+ ffi.Void Function(
+ ffi.Int64,
+ ffi.Pointer,
+ ffi.Pointer,
+ ffi.Pointer,
+ ffi.Pointer)>>('wire_encrypt');
+ late final _wire_encrypt = _wire_encryptPtr.asFunction<
+ void Function(
+ int,
+ ffi.Pointer,
+ ffi.Pointer,
+ ffi.Pointer,
+ ffi.Pointer)>();
+
+ void wire_decrypt(
+ int port_,
+ ffi.Pointer data,
+ ffi.Pointer password,
+ ) {
+ return _wire_decrypt(
+ port_,
+ data,
+ password,
+ );
+ }
+
+ late final _wire_decryptPtr = _lookup<
+ ffi.NativeFunction<
+ ffi.Void Function(ffi.Int64, ffi.Pointer,
+ ffi.Pointer)>>('wire_decrypt');
+ late final _wire_decrypt = _wire_decryptPtr.asFunction<
+ void Function(
+ int, ffi.Pointer, ffi.Pointer)>();
+
+ ffi.Pointer new_uint_8_list(
+ int len,
+ ) {
+ return _new_uint_8_list(
+ len,
+ );
+ }
+
+ late final _new_uint_8_listPtr = _lookup<
+ ffi.NativeFunction<
+ ffi.Pointer Function(
+ ffi.Int32)>>('new_uint_8_list');
+ late final _new_uint_8_list = _new_uint_8_listPtr
+ .asFunction Function(int)>();
+
+ void free_WireSyncReturnStruct(
+ WireSyncReturnStruct val,
+ ) {
+ return _free_WireSyncReturnStruct(
+ val,
+ );
+ }
+
+ late final _free_WireSyncReturnStructPtr =
+ _lookup>(
+ 'free_WireSyncReturnStruct');
+ late final _free_WireSyncReturnStruct = _free_WireSyncReturnStructPtr
+ .asFunction();
+
+ void store_dart_post_cobject(
+ DartPostCObjectFnType ptr,
+ ) {
+ return _store_dart_post_cobject(
+ ptr,
+ );
+ }
+
+ late final _store_dart_post_cobjectPtr =
+ _lookup>(
+ 'store_dart_post_cobject');
+ late final _store_dart_post_cobject = _store_dart_post_cobjectPtr
+ .asFunction();
+}
+
+class wire_uint_8_list extends ffi.Struct {
+ external ffi.Pointer ptr;
+
+ @ffi.Int32()
+ external int len;
+}
+
+typedef DartPostCObjectFnType = ffi.Pointer<
+ ffi.NativeFunction)>>;
+typedef DartPort = ffi.Int64;
diff --git a/lib/ffi.dart b/lib/ffi.dart
new file mode 100644
index 00000000..90e5b59a
--- /dev/null
+++ b/lib/ffi.dart
@@ -0,0 +1,24 @@
+// This file initializes the dynamic library and connects it with the stub
+// generated by flutter_rust_bridge_codegen.
+
+import 'dart:ffi';
+import 'dart:io' as io;
+
+import 'package:potato_notes/bridge_generated.dart';
+
+// Re-export the bridge so it is only necessary to import this file.
+export 'bridge_generated.dart';
+
+const _base = 'native';
+
+// On MacOS, the dynamic library is not bundled with the binary,
+// but rather directly **linked** against the binary.
+final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so';
+
+// The late modifier delays initializing the value until it is actually needed,
+// leaving precious little time for the program to quickly start up.
+late final Native api = NativeImpl(
+ io.Platform.isIOS || io.Platform.isMacOS
+ ? DynamicLibrary.executable()
+ : DynamicLibrary.open(_dylib),
+);
diff --git a/lib/generated_plugin_registrant.dart b/lib/generated_plugin_registrant.dart
index aad24ef2..537578bc 100644
--- a/lib/generated_plugin_registrant.dart
+++ b/lib/generated_plugin_registrant.dart
@@ -14,7 +14,6 @@ import 'package:package_info_plus_web/package_info_plus_web.dart';
import 'package:share_plus_web/share_plus_web.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
import 'package:url_launcher_web/url_launcher_web.dart';
-import 'package:webcrypto/src/flutter/webcrypto_plugin.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
@@ -29,6 +28,5 @@ void registerPlugins(Registrar registrar) {
SharePlusPlugin.registerWith(registrar);
SharedPreferencesPlugin.registerWith(registrar);
UrlLauncherPlugin.registerWith(registrar);
- WebcryptoPlugin.registerWith(registrar);
registrar.registerMessageHandler();
}
diff --git a/lib/internal/backup_delegate.dart b/lib/internal/backup_delegate.dart
index 4df1dfa8..09793fdb 100644
--- a/lib/internal/backup_delegate.dart
+++ b/lib/internal/backup_delegate.dart
@@ -14,7 +14,7 @@ import 'package:potato_notes/data/model/id_list.dart';
import 'package:potato_notes/data/model/list_content.dart';
import 'package:potato_notes/data/model/reminder_list.dart';
import 'package:potato_notes/internal/encryption/base.dart';
-import 'package:potato_notes/internal/encryption/dart.dart';
+import 'package:potato_notes/internal/encryption/rust.dart';
import 'package:potato_notes/internal/extensions.dart';
import 'package:potato_notes/internal/file_system_helper.dart';
import 'package:potato_notes/internal/logger_provider.dart';
@@ -89,7 +89,7 @@ class BackupDelegate with LoggerProvider {
final ZipByteEncoder encoder = ZipByteEncoder()
..create()
..addDirectory(noteDir, includeDirName: false);
- final List fileBytes = encoder.close();
+ final Uint8List fileBytes = encoder.close();
await noteDir.delete(recursive: true);
final NoteBackupMetadata metadata = NoteBackupMetadata(
name: name,
@@ -115,6 +115,7 @@ class BackupDelegate with LoggerProvider {
required String name,
ValueChanged? onProgress,
}) async {
+ final DateTime startTime = DateTime.now();
final ReceivePort progressPort = ReceivePort();
final ReceivePort returnPort = ReceivePort();
final String outDir = appDirectories.backupDirectory.path;
@@ -141,6 +142,10 @@ class BackupDelegate with LoggerProvider {
});
final String finalBackupName = await returnPort.first as String;
+
+ // TODO: BKP: remove the time log
+ logger.v('Backup took ${DateTime.now().difference(startTime)}');
+
return p.join(outDir, finalBackupName);
}
@@ -186,7 +191,7 @@ class BackupDelegate with LoggerProvider {
..create()
..addDirectory(baseDir, includeDirName: false)
..close();
- final List fileBytes = encoder.close();
+ final Uint8List fileBytes = encoder.close();
await baseDir.delete(recursive: true);
final String backupPath = p.join(outDir, name);
File(backupPath).writeAsBytes(
@@ -254,7 +259,7 @@ class BackupDelegate with LoggerProvider {
final Map data =
json.decode(payload) as Map;
- final List fileData = Utils.asList(data['data']);
+ final Uint8List fileData = Utils.asUint8List(data['data']);
final List tags =
_decodeTags(Utils.asList