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>(data['tags'])); final String password = data['password']! as String; @@ -289,6 +294,18 @@ class BackupDelegate with LoggerProvider { Utils.asMap(json.decode(content)); final Map noteJson = Utils.asMap(decodedContent); + + // TODO: @hrx03 fix this + if (!noteJson.containsKey('folder')) { + noteJson['folder'] = 'default'; + } + + if (!noteJson.containsKey('last_changed') || + !noteJson.containsKey('lastChanged')) { + noteJson['last_changed'] = DateTime.now().millisecondsSinceEpoch; + noteJson['lastChanged'] = noteJson['last_changed']; + } + final Note note = Note.fromJson( noteJson, serializer: const _TypeAwareValueSerializer(), @@ -369,10 +386,11 @@ class BackupDelegate with LoggerProvider { .toList(); } - static EncryptionUtilsBase _figureOutEncryptionUtils(int version) { - // For now use only the dart encryption utils - return DartEncryptionUtils(); - } + static final EncryptionUtilsBase _encryptionUtils = RustEncryptionUtils(); + + // For now use only the rust encryption utils + static EncryptionUtilsBase _figureOutEncryptionUtils(int version) => + _encryptionUtils; } class _BackupPayload { @@ -657,8 +675,8 @@ class ZipByteEncoder { _encoder.addFile(file); } - List close() { + Uint8List close() { _encoder.endEncode(); - return _output.getBytes(); + return Uint8List.fromList(_output.getBytes()); } } diff --git a/lib/internal/encryption/base.dart b/lib/internal/encryption/base.dart index e5ad2a9c..6b04cfa2 100644 --- a/lib/internal/encryption/base.dart +++ b/lib/internal/encryption/base.dart @@ -1,14 +1,14 @@ import 'dart:math'; +import 'dart:typed_data'; abstract class EncryptionUtilsBase { - static List generateNonce([int length = 16]) => List.generate( - length, - (index) => Random.secure().nextInt(255), + static Uint8List generateNonce([int length = 16]) => Uint8List.fromList( + List.generate(length, (index) => Random.secure().nextInt(255)), ); - Future> deriveKey(String password, List nonce); + Future deriveKey(String password, Uint8List nonce); - Future> encryptBytes(List origin, String password); + Future encryptBytes(Uint8List origin, String password); - Future> decryptBytes(List origin, String password); + Future decryptBytes(Uint8List origin, String password); } diff --git a/lib/internal/encryption/boringssl.dart b/lib/internal/encryption/boringssl.dart deleted file mode 100644 index f2b0c8fe..00000000 --- a/lib/internal/encryption/boringssl.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:potato_notes/internal/encryption/base.dart'; -import 'package:webcrypto/webcrypto.dart'; - -class BoringSSLEncryptionUtils extends EncryptionUtilsBase { - @override - Future> deriveKey(String password, List nonce) async { - final key = await Pbkdf2SecretKey.importRawKey(password.codeUnits); - - return key.deriveBits(256, Hash.sha512, nonce, 100000); - } - - @override - Future> encryptBytes(List origin, String password) async { - final keySalt = EncryptionUtilsBase.generateNonce(); - final key = await deriveKey(password, keySalt); - - final aes = await AesGcmSecretKey.importRawKey(key); - final ciphertext = await aes.encryptBytes(origin, keySalt); - - return [ - ...keySalt, - ...ciphertext, - ]; - } - - @override - Future> decryptBytes(List origin, String password) async { - final keySalt = origin.sublist(0, 16); - final payload = origin.sublist(16); - - final key = await deriveKey(password, keySalt); - final aes = await AesGcmSecretKey.importRawKey(key); - final plaintext = await aes.decryptBytes(payload, keySalt); - - return plaintext; - } -} diff --git a/lib/internal/encryption/dart.dart b/lib/internal/encryption/dart.dart index e5aa2332..87e338d4 100644 --- a/lib/internal/encryption/dart.dart +++ b/lib/internal/encryption/dart.dart @@ -1,9 +1,11 @@ +import 'dart:typed_data'; + import 'package:cryptography/cryptography.dart'; import 'package:potato_notes/internal/encryption/base.dart'; class DartEncryptionUtils extends EncryptionUtilsBase { @override - Future> decryptBytes(List origin, String password) async { + Future decryptBytes(Uint8List origin, String password) async { final keySalt = origin.sublist(0, 16); final aesNonce = origin.sublist(16, 28); final macBytes = origin.sublist(28, 44); @@ -21,11 +23,11 @@ class DartEncryptionUtils extends EncryptionUtilsBase { secretKey: SecretKey(key), ); - return plaintext; + return Uint8List.fromList(plaintext); } @override - Future> deriveKey(String password, List nonce) async { + Future deriveKey(String password, Uint8List nonce) async { final kdf = Pbkdf2( bits: 256, iterations: 100000, @@ -36,22 +38,22 @@ class DartEncryptionUtils extends EncryptionUtilsBase { nonce: nonce, ); - return key.extractBytes(); + return Uint8List.fromList(await key.extractBytes()); } @override - Future> encryptBytes(List origin, String password) async { + Future encryptBytes(Uint8List origin, String password) async { final keySalt = EncryptionUtilsBase.generateNonce(); final key = await deriveKey(password, keySalt); final aes = AesGcm.with256bits(); final ciphertext = await aes.encrypt(origin, secretKey: SecretKey(key)); - return [ + return Uint8List.fromList([ ...keySalt, ...ciphertext.nonce, ...ciphertext.mac.bytes, ...ciphertext.cipherText, - ]; + ]); } } diff --git a/lib/internal/encryption/rust.dart b/lib/internal/encryption/rust.dart new file mode 100644 index 00000000..244ca730 --- /dev/null +++ b/lib/internal/encryption/rust.dart @@ -0,0 +1,37 @@ +import 'dart:typed_data'; + +import 'package:potato_notes/ffi.dart'; +import 'package:potato_notes/internal/encryption/base.dart'; + +class RustEncryptionUtils implements EncryptionUtilsBase { + @override + Future decryptBytes(Uint8List origin, String password) async { + final res = await api.decrypt(data: origin, password: password); + + if (res != null) { + return res; + } + + throw Exception(); + } + + @override + Future deriveKey(String password, Uint8List nonce) => + api.deriveKey(password: password, nonce: nonce); + + @override + Future encryptBytes(Uint8List origin, String password) async { + final res = await api.encrypt( + data: origin, + password: password, + keyNonce: EncryptionUtilsBase.generateNonce(), + aesNonce: EncryptionUtilsBase.generateNonce(12), + ); + + if (res != null) { + return res; + } + + throw Exception(); + } +} diff --git a/lib/internal/utils.dart b/lib/internal/utils.dart index 360192c9..ebcc88c7 100644 --- a/lib/internal/utils.dart +++ b/lib/internal/utils.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'dart:typed_data'; import 'dart:ui'; import 'package:collection/collection.dart'; @@ -857,6 +858,10 @@ class Utils { return List.from(obj as List); } + static Uint8List asUint8List(dynamic obj) { + return Uint8List.fromList(asList(obj)); + } + static Map asMap(dynamic obj) { return Map.from(obj as Map); } diff --git a/lib/main.dart b/lib/main.dart index 571605fc..cd640432 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,9 +12,8 @@ import 'package:potato_notes/internal/locales/locale_strings.g.dart'; import 'package:potato_notes/internal/locales/locales.g.dart'; import 'package:potato_notes/internal/providers.dart'; import 'package:potato_notes/internal/utils.dart'; -import 'package:potato_notes/routes/base_page.dart'; -import 'package:potato_notes/routes/splash_page.dart'; import 'package:potato_notes/routes/home_page.dart'; +import 'package:potato_notes/routes/splash_page.dart'; import 'package:potato_notes/widget/notes_app.dart'; import 'package:potato_notes/widget/window_frame.dart'; import 'package:quick_actions/quick_actions.dart'; diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 356c9bea..f90c6c63 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -68,6 +68,9 @@ set_target_properties(${BINARY_NAME} # them to the application. include(flutter/generated_plugins.cmake) +include(./cmake/gen.cmake) +include(./cmake/rust.cmake) + # === Installation === # By default, "installing" just makes a relocatable bundle in the build @@ -115,5 +118,4 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") COMPONENT Runtime) endif() -install(FILES "libs/libsqlcipher.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) -install(FILES "libs/libwebcrypto.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) \ No newline at end of file +install(FILES "libs/libsqlcipher.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) \ No newline at end of file diff --git a/linux/cmake/gen.cmake b/linux/cmake/gen.cmake new file mode 100644 index 00000000..0f246053 --- /dev/null +++ b/linux/cmake/gen.cmake @@ -0,0 +1,10 @@ +# Runs the bridge codegen script + +message("Performing bridge codegen") + +execute_process(COMMAND just RESULT_VARIABLE CMD_ERROR OUTPUT_VARIABLE CMD_OUTPUT) + +message("Codegen exit code: ${CMD_ERROR}") +message("Codegen output: ${CMD_OUTPUT}") + +message("Done performing bridge codegen") diff --git a/linux/cmake/rust.cmake b/linux/cmake/rust.cmake new file mode 100644 index 00000000..0c6db342 --- /dev/null +++ b/linux/cmake/rust.cmake @@ -0,0 +1,25 @@ +# We include Corrosion inline here, but ideally in a project with +# many dependencies we would need to install Corrosion on the system. +# See instructions on https://github.com/AndrewGaspar/corrosion#cmake-install +# Once done, uncomment this line: +# find_package(Corrosion REQUIRED) + +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/AndrewGaspar/corrosion.git + GIT_TAG origin/master # Optionally specify a version tag or branch here +) + +FetchContent_MakeAvailable(Corrosion) + +corrosion_import_crate(MANIFEST_PATH ../native/Cargo.toml) + +# Flutter-specific + +set(CRATE_NAME "native") + +target_link_libraries(${BINARY_NAME} PRIVATE ${CRATE_NAME}) + +list(APPEND PLUGIN_BUNDLED_LIBRARIES $) diff --git a/linux/libs/libwebcrypto.so b/linux/libs/libwebcrypto.so deleted file mode 100644 index 3e1355ee..00000000 Binary files a/linux/libs/libwebcrypto.so and /dev/null differ diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 877ce716..c0dd826a 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -22,14 +22,14 @@ PODS: - sqflite (0.0.2): - FlutterMacOS - 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): - FlutterMacOS - - SQLCipher (~> 4.4.3) + - SQLCipher (~> 4.5.0) - url_launcher_macos (0.0.1): - FlutterMacOS @@ -86,13 +86,13 @@ SPEC CHECKSUMS: FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c - path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b + path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4 - shared_preferences_macos: 480ce071d0666e37cef23fe6c702293a3d21799e + shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea - SQLCipher: 155ffeafc9ac102e5c9b68e3e9a1297a98a27096 - sqlcipher_flutter_libs: 7f2d4c5254fda54a9beaa27132663879440aaf26 - url_launcher_macos: 45af3d61de06997666568a7149c1be98b41c95d4 + SQLCipher: 712e8416685e8e575b9b0706ffee71678b2fdcf8 + sqlcipher_flutter_libs: 38ad87bfba1bc2f3813513b7d3996fb6bd49fed6 + url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index f495cf30..5c123835 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -26,10 +26,11 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 6BC079F3269E455800BFA311 /* libwebcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 6BC079F2269E455800BFA311 /* libwebcrypto.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; 6BC079F4269E459E00BFA311 /* libwebcrypto.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 6BC079F2269E455800BFA311 /* libwebcrypto.dylib */; }; - 6BC079F5269E45D600BFA311 /* libwebcrypto.dylib in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 6BC079F2269E455800BFA311 /* libwebcrypto.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 75A2F025844D41ADA8F479A6 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1914D3DF6EF84F457635516E /* Pods_Runner.framework */; }; + 7C067C7A27D7BFAF0043B7C9 /* native.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C067C7727D7BF910043B7C9 /* native.dylib */; }; + 7C067C7B27D7BFBD0043B7C9 /* native.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 7C067C7727D7BF910043B7C9 /* native.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 7C067C8327D7C2F50043B7C9 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C067C8227D7C2F50043B7C9 /* libc++.tbd */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,18 +41,39 @@ remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; + 7C067C7427D7BF910043B7C9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 7C067C6F27D7BF910043B7C9 /* native.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = CA60AD08325E2969E816930C; + remoteInfo = "native-staticlib"; + }; + 7C067C7627D7BF910043B7C9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 7C067C6F27D7BF910043B7C9 /* native.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = CA604B1163E6EAC3B2E0A336; + remoteInfo = "native-cdylib"; + }; + 7C067C7827D7BF9F0043B7C9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 7C067C6F27D7BF910043B7C9 /* native.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = CA604B1163E63AEEE34191F5; + remoteInfo = "native-cdylib"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { + 7C067C7C27D7BFBD0043B7C9 /* Embed Libraries */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - 6BC079F5269E45D600BFA311 /* libwebcrypto.dylib in Bundle Framework */, + 7C067C7B27D7BFBD0043B7C9 /* native.dylib in Embed Libraries */, ); - name = "Bundle Framework"; + name = "Embed Libraries"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -75,6 +97,9 @@ 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 6BC079F2269E455800BFA311 /* libwebcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libwebcrypto.dylib; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 7C067C6F27D7BF910043B7C9 /* native.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = native.xcodeproj; path = ../../native/native.xcodeproj; sourceTree = ""; }; + 7C067C7E27D7C17B0043B7C9 /* bridge_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bridge_generated.h; sourceTree = ""; }; + 7C067C8227D7C2F50043B7C9 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; D365DBA1626786BD42A77EC8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; EE100A25E87338E92F32A510 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; @@ -85,8 +110,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7C067C8327D7C2F50043B7C9 /* libc++.tbd in Frameworks */, + 7C067C7A27D7BFAF0043B7C9 /* native.dylib in Frameworks */, 75A2F025844D41ADA8F479A6 /* Pods_Runner.framework in Frameworks */, - 6BC079F3269E455800BFA311 /* libwebcrypto.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -148,6 +174,8 @@ 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( + 7C067C7E27D7C17B0043B7C9 /* bridge_generated.h */, + 7C067C6F27D7BF910043B7C9 /* native.xcodeproj */, 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, @@ -158,6 +186,15 @@ path = Runner; sourceTree = ""; }; + 7C067C7027D7BF910043B7C9 /* Products */ = { + isa = PBXGroup; + children = ( + 7C067C7527D7BF910043B7C9 /* libnative_static.a */, + 7C067C7727D7BF910043B7C9 /* native.dylib */, + ); + name = Products; + sourceTree = ""; + }; BE11626A1C8AB7701D478DA4 /* Pods */ = { isa = PBXGroup; children = ( @@ -171,6 +208,7 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 7C067C8227D7C2F50043B7C9 /* libc++.tbd */, 6BC079F2269E455800BFA311 /* libwebcrypto.dylib */, 1914D3DF6EF84F457635516E /* Pods_Runner.framework */, ); @@ -188,13 +226,14 @@ 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, F3A41A24920B7A9C419DF78F /* [CP] Embed Pods Frameworks */, + 7C067C7C27D7BFBD0043B7C9 /* Embed Libraries */, ); buildRules = ( ); dependencies = ( + 7C067C7927D7BF9F0043B7C9 /* PBXTargetDependency */, 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; @@ -239,6 +278,12 @@ mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 7C067C7027D7BF910043B7C9 /* Products */; + ProjectRef = 7C067C6F27D7BF910043B7C9 /* native.xcodeproj */; + }, + ); projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, @@ -247,6 +292,23 @@ }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + 7C067C7527D7BF910043B7C9 /* libnative_static.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libnative_static.a; + remoteRef = 7C067C7427D7BF910043B7C9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 7C067C7727D7BF910043B7C9 /* native.dylib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = native.dylib; + remoteRef = 7C067C7627D7BF910043B7C9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -381,6 +443,11 @@ target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; + 7C067C7927D7BF9F0043B7C9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "native-cdylib"; + targetProxy = 7C067C7827D7BF9F0043B7C9 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -466,6 +533,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 10.12; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = Runner/bridge_generated.h; SWIFT_VERSION = 5.0; }; name = Profile; @@ -601,6 +669,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 10.12; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = Runner/bridge_generated.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; @@ -630,6 +699,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 10.12; PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = Runner/bridge_generated.h; SWIFT_VERSION = 5.0; }; name = Release; diff --git a/macos/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/macos/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef643..0307d4fc 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -6,4 +6,8 @@ class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } + + func dummy() { + dummy_method_to_enforce_bundling() + } } diff --git a/macos/Runner/bridge_generated.h b/macos/Runner/bridge_generated.h new file mode 100644 index 00000000..26a6b674 --- /dev/null +++ b/macos/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/macos/libwebcrypto.dylib b/macos/libwebcrypto.dylib deleted file mode 100644 index c007ee76..00000000 Binary files a/macos/libwebcrypto.dylib and /dev/null differ diff --git a/native/.cargo/config.toml b/native/.cargo/config.toml new file mode 100644 index 00000000..27763493 --- /dev/null +++ b/native/.cargo/config.toml @@ -0,0 +1,16 @@ +# Enable SIMD and hardware AES on supported targets + +# Windows x86_64 +[target.x86_64-pc-msvc-windows] +rustc-flags = ["-Ctarget-cpu=sandybridge", "-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"] + +# iOS x86_64 (sim) +# [target.x86_64-apple-ios] +# rustc-flags = ["-Ctarget-cpu=sandybridge", "-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"] + +# macOS x86_64 +# [target.x86_64-apple-darwin] +# rustc-flags = ["-Ctarget-cpu=sandybridge", "-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"] + +# rustc-flags for targets other than windows are commented out due to build +# issues. It should still pick AES-NI intrinsics during runtime diff --git a/native/Cargo.lock b/native/Cargo.lock new file mode 100644 index 00000000..a60d42e2 --- /dev/null +++ b/native/Cargo.lock @@ -0,0 +1,522 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "allo-isolate" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31644a919a9e4b0188e4569e55bbf5a78b5588ea645acffc15c29240407261bc" +dependencies = [ + "atomic", +] + +[[package]] +name = "anyhow" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" + +[[package]] +name = "atomic" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "flutter_rust_bridge" +version = "1.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af88edd96d662cee27b683c389516f22a65d9bed6fe51857b474d5e982aa15a9" +dependencies = [ + "allo-isolate", + "anyhow", + "flutter_rust_bridge_macros", + "lazy_static", + "parking_lot", + "threadpool", +] + +[[package]] +name = "flutter_rust_bridge_macros" +version = "1.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06b75afcce280dc87a329216586211c95eb7ac6045ed855f0791a3256da52936" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "native" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "flutter_rust_bridge", + "ring", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" diff --git a/native/Cargo.toml b/native/Cargo.toml new file mode 100644 index 00000000..fc8db2c9 --- /dev/null +++ b/native/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "native" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["lib", "staticlib", "cdylib"] +# lib for tests, benchmarks and all +# staticlib for iOS +# cdynlib for everything else + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aes-gcm = "0.9.4" +flutter_rust_bridge = "1" +ring = "0.16.20" + +# Release builds +[profile.release] +strip = "debuginfo" +lto = true +opt-level = 3 +debug = 0 diff --git a/native/native.xcodeproj/project.pbxproj b/native/native.xcodeproj/project.pbxproj new file mode 100644 index 00000000..da59b9e6 --- /dev/null +++ b/native/native.xcodeproj/project.pbxproj @@ -0,0 +1,315 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 53; + objects = { + +/* Begin PBXBuildFile section */ + CA605C0204D735B1519BA4B0 /* Cargo.toml in Sources */ = {isa = PBXBuildFile; fileRef = CA608FFBC1923EF4668187A5 /* Cargo.toml */; settings = {COMPILER_FLAGS = "--lib"; }; }; + CA605C0204D73AEEE34191F5 /* Cargo.toml in Sources */ = {isa = PBXBuildFile; fileRef = CA608FFBC1923EF4668187A5 /* Cargo.toml */; settings = {COMPILER_FLAGS = "--lib"; }; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + CA608FFBC192AC6C1400ACA8 /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + dependencyFile = "$(DERIVED_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME).d"; + filePatterns = "*/Cargo.toml"; + fileType = pattern.proxy; + inputFiles = ( + ); + isEditable = 0; + name = "Cargo project build"; + outputFiles = ( + "$(OBJECT_FILE_DIR)/$(CARGO_XCODE_TARGET_ARCH)-$(EXECUTABLE_NAME)", + ); + script = "# generated with cargo-xcode 1.4.1\n\nset -eu; export PATH=$PATH:~/.cargo/bin:/usr/local/bin;\nif [ \"${IS_MACCATALYST-NO}\" = YES ]; then\n CARGO_XCODE_TARGET_TRIPLE=\"${CARGO_XCODE_TARGET_ARCH}-apple-ios-macabi\"\nelse\n CARGO_XCODE_TARGET_TRIPLE=\"${CARGO_XCODE_TARGET_ARCH}-apple-${CARGO_XCODE_TARGET_OS}\"\n\n # Hack for the compilation to work with iOS simulator on x86_64 hosts\n if [ \"$CARGO_XCODE_TARGET_TRIPLE\" = \"x86_64-apple-ios-sim\" ]; then\n CARGO_XCODE_TARGET_TRIPLE=\"x86_64-apple-ios\"\n fi\nfi\nif [ \"$CARGO_XCODE_TARGET_OS\" != \"darwin\" ]; then\n PATH=\"${PATH/\\/Contents\\/Developer\\/Toolchains\\/XcodeDefault.xctoolchain\\/usr\\/bin:/xcode-provided-ld-cant-link-lSystem-for-the-host-build-script:}\"\nfi\nPATH=\"$PATH:/opt/homebrew/bin\" # Rust projects often depend on extra tools like nasm, which Xcode lacks\nif [ \"$CARGO_XCODE_BUILD_MODE\" == release ]; then\n OTHER_INPUT_FILE_FLAGS=\"${OTHER_INPUT_FILE_FLAGS} --release\"\nfi\nif command -v rustup &> /dev/null; then\n if ! rustup target list --installed | egrep -q \"${CARGO_XCODE_TARGET_TRIPLE}\"; then\n echo \"warning: this build requires rustup toolchain for $CARGO_XCODE_TARGET_TRIPLE, but it isn't installed\"\n rustup target add \"${CARGO_XCODE_TARGET_TRIPLE}\" || echo >&2 \"warning: can't install $CARGO_XCODE_TARGET_TRIPLE\"\n fi\nfi\nif [ \"$ACTION\" = clean ]; then\n ( set -x; cargo clean --manifest-path=\"$SCRIPT_INPUT_FILE\" ${OTHER_INPUT_FILE_FLAGS} --target=\"${CARGO_XCODE_TARGET_TRIPLE}\"; );\nelse\n ( set -x; cargo build --manifest-path=\"$SCRIPT_INPUT_FILE\" --features=\"${CARGO_XCODE_FEATURES:-}\" ${OTHER_INPUT_FILE_FLAGS} --target=\"${CARGO_XCODE_TARGET_TRIPLE}\"; );\nfi\n# it's too hard to explain Cargo's actual exe path to Xcode build graph, so hardlink to a known-good path instead\nBUILT_SRC=\"${CARGO_TARGET_DIR}/${CARGO_XCODE_TARGET_TRIPLE}/${CARGO_XCODE_BUILD_MODE}/${CARGO_XCODE_CARGO_FILE_NAME}\"\nln -f -- \"$BUILT_SRC\" \"$SCRIPT_OUTPUT_FILE_0\"\n\n# xcode generates dep file, but for its own path, so append our rename to it\nDEP_FILE_SRC=\"${CARGO_TARGET_DIR}/${CARGO_XCODE_TARGET_TRIPLE}/${CARGO_XCODE_BUILD_MODE}/${CARGO_XCODE_CARGO_DEP_FILE_NAME}\"\nif [ -f \"$DEP_FILE_SRC\" ]; then\n DEP_FILE_DST=\"${DERIVED_FILE_DIR}/${CARGO_XCODE_TARGET_ARCH}-${EXECUTABLE_NAME}.d\"\n cp -f \"$DEP_FILE_SRC\" \"$DEP_FILE_DST\"\n echo >> \"$DEP_FILE_DST\" \"$SCRIPT_OUTPUT_FILE_0: $BUILT_SRC\"\nfi\n\n# lipo script needs to know all the platform-specific files that have been built\n# archs is in the file name, so that paths don't stay around after archs change\n# must match input for LipoScript\nFILE_LIST=\"${DERIVED_FILE_DIR}/${ARCHS}-${EXECUTABLE_NAME}.xcfilelist\"\ntouch \"$FILE_LIST\"\nif ! egrep -q \"$SCRIPT_OUTPUT_FILE_0\" \"$FILE_LIST\" ; then\n echo >> \"$FILE_LIST\" \"$SCRIPT_OUTPUT_FILE_0\"\nfi\n"; + }; +/* End PBXBuildRule section */ + +/* Begin PBXFileReference section */ + ADDEDBA66A6E1 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; + CA604B1163E6EAC3B2E0A336 /* native.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = native.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + CA608FFBC1923EF4668187A5 /* Cargo.toml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cargo.toml; sourceTree = ""; }; + CA60AD08325E2969E816930C /* libnative_static.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnative_static.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + ADDEDBA66A6E2 /* Required for static linking */ = { + isa = PBXGroup; + children = ( + ADDEDBA66A6E1 /* libresolv.tbd */, + ); + name = "Required for static linking"; + sourceTree = ""; + }; + CA608FFBC19222869D176AE5 /* Products */ = { + isa = PBXGroup; + children = ( + CA60AD08325E2969E816930C /* libnative_static.a */, + CA604B1163E6EAC3B2E0A336 /* native.dylib */, + ); + name = Products; + sourceTree = ""; + }; + CA608FFBC19298AF0B5890DB /* Frameworks */ = { + isa = PBXGroup; + children = ( + ADDEDBA66A6E2 /* Required for static linking */, + ); + name = Frameworks; + sourceTree = ""; + }; + CA608FFBC192D65BC3C892A8 = { + isa = PBXGroup; + children = ( + CA608FFBC1923EF4668187A5 /* Cargo.toml */, + CA608FFBC19222869D176AE5 /* Products */, + CA608FFBC19298AF0B5890DB /* Frameworks */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CA604B1163E63AEEE34191F5 /* native-cdylib */ = { + isa = PBXNativeTarget; + buildConfigurationList = CA601DAB34973AEEE34191F5 /* Build configuration list for PBXNativeTarget "native-cdylib" */; + buildPhases = ( + CA60ED75A50F3AEEE34191F5 /* Sources */, + CA608FFBC192AF6EBB7F357C /* Universal Binary lipo */, + ); + buildRules = ( + CA608FFBC192AC6C1400ACA8 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = "native-cdylib"; + productName = native.dylib; + productReference = CA604B1163E6EAC3B2E0A336 /* native.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; + CA60AD08325E35B1519BA4B0 /* native-staticlib */ = { + isa = PBXNativeTarget; + buildConfigurationList = CA601DAB349735B1519BA4B0 /* Build configuration list for PBXNativeTarget "native-staticlib" */; + buildPhases = ( + CA60ED75A50F35B1519BA4B0 /* Sources */, + CA608FFBC192AF6EBB7F357C /* Universal Binary lipo */, + ); + buildRules = ( + CA608FFBC192AC6C1400ACA8 /* PBXBuildRule */, + ); + dependencies = ( + ); + name = "native-staticlib"; + productName = libnative_static.a; + productReference = CA60AD08325E2969E816930C /* libnative_static.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + CA608FFBC192E04653AD465F /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + TargetAttributes = { + CA604B1163E63AEEE34191F5 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + CA60AD08325E35B1519BA4B0 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = CA608FFBC19280E02D6C7F57 /* Build configuration list for PBXProject "native" */; + compatibilityVersion = "Xcode 11.4"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CA608FFBC192D65BC3C892A8; + productRefGroup = CA608FFBC19222869D176AE5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CA60AD08325E35B1519BA4B0 /* native-staticlib */, + CA604B1163E63AEEE34191F5 /* native-cdylib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + CA608FFBC192AF6EBB7F357C /* Universal Binary lipo */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(DERIVED_FILE_DIR)/$(ARCHS)-$(EXECUTABLE_NAME).xcfilelist", + ); + name = "Universal Binary lipo"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# generated with cargo-xcode 1.4.1\nset -eux; cat \"$DERIVED_FILE_DIR/$ARCHS-$EXECUTABLE_NAME.xcfilelist\" | tr '\\n' '\\0' | xargs -0 lipo -create -output \"$TARGET_BUILD_DIR/$EXECUTABLE_PATH\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + CA60ED75A50F35B1519BA4B0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CA605C0204D735B1519BA4B0 /* Cargo.toml in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CA60ED75A50F3AEEE34191F5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CA605C0204D73AEEE34191F5 /* Cargo.toml in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + CA607CBB44A235B1519BA4B0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CARGO_XCODE_CARGO_DEP_FILE_NAME = libnative.d; + CARGO_XCODE_CARGO_FILE_NAME = libnative.a; + INSTALL_GROUP = ""; + INSTALL_MODE_FLAG = ""; + INSTALL_OWNER = ""; + PRODUCT_NAME = native_static; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; + }; + name = Debug; + }; + CA607CBB44A23AEEE34191F5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CARGO_XCODE_CARGO_DEP_FILE_NAME = libnative.d; + CARGO_XCODE_CARGO_FILE_NAME = libnative.dylib; + PRODUCT_NAME = native; + SUPPORTED_PLATFORMS = macosx; + }; + name = Debug; + }; + CA609E075C2935B1519BA4B0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CARGO_XCODE_CARGO_DEP_FILE_NAME = libnative.d; + CARGO_XCODE_CARGO_FILE_NAME = libnative.a; + INSTALL_GROUP = ""; + INSTALL_MODE_FLAG = ""; + INSTALL_OWNER = ""; + PRODUCT_NAME = native_static; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; + }; + name = Release; + }; + CA609E075C293AEEE34191F5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CARGO_XCODE_CARGO_DEP_FILE_NAME = libnative.d; + CARGO_XCODE_CARGO_FILE_NAME = libnative.dylib; + PRODUCT_NAME = native; + SUPPORTED_PLATFORMS = macosx; + }; + name = Release; + }; + CA60BA2D1872228BE02872F8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; + CARGO_XCODE_BUILD_MODE = debug; + CARGO_XCODE_FEATURES = ""; + "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64; + "CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686; + "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64; + "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos; + "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos; + "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios; + "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; + "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = native; + SDKROOT = macosx; + SUPPORTS_MACCATALYST = YES; + }; + name = Debug; + }; + CA60BA2D18723CC16B37690B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CARGO_TARGET_DIR = "$(PROJECT_TEMP_DIR)/cargo_target"; + CARGO_XCODE_BUILD_MODE = release; + CARGO_XCODE_FEATURES = ""; + "CARGO_XCODE_TARGET_ARCH[arch=arm64*]" = aarch64; + "CARGO_XCODE_TARGET_ARCH[arch=i386]" = i686; + "CARGO_XCODE_TARGET_ARCH[arch=x86_64*]" = x86_64; + "CARGO_XCODE_TARGET_OS[sdk=appletvos*]" = tvos; + "CARGO_XCODE_TARGET_OS[sdk=appletvsimulator*]" = tvos; + "CARGO_XCODE_TARGET_OS[sdk=iphoneos*]" = ios; + "CARGO_XCODE_TARGET_OS[sdk=iphonesimulator*]" = "ios-sim"; + "CARGO_XCODE_TARGET_OS[sdk=macosx*]" = darwin; + PRODUCT_NAME = native; + SDKROOT = macosx; + SUPPORTS_MACCATALYST = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + CA601DAB349735B1519BA4B0 /* Build configuration list for PBXNativeTarget "native-staticlib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA609E075C2935B1519BA4B0 /* Release */, + CA607CBB44A235B1519BA4B0 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CA601DAB34973AEEE34191F5 /* Build configuration list for PBXNativeTarget "native-cdylib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA609E075C293AEEE34191F5 /* Release */, + CA607CBB44A23AEEE34191F5 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CA608FFBC19280E02D6C7F57 /* Build configuration list for PBXProject "native" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA60BA2D18723CC16B37690B /* Release */, + CA60BA2D1872228BE02872F8 /* Debug */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = CA608FFBC192E04653AD465F /* Project object */; +} diff --git a/native/native.xcodeproj/xcuserdata/akshitgarg.xcuserdatad/xcschemes/xcschememanagement.plist b/native/native.xcodeproj/xcuserdata/akshitgarg.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..b061f9a7 --- /dev/null +++ b/native/native.xcodeproj/xcuserdata/akshitgarg.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SchemeUserState + + native-cdylib.xcscheme_^#shared#^_ + + orderHint + 16 + + native-staticlib.xcscheme_^#shared#^_ + + orderHint + 18 + + + + diff --git a/native/rustfmt.toml b/native/rustfmt.toml new file mode 100644 index 00000000..c599a855 --- /dev/null +++ b/native/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80 diff --git a/native/src/api.rs b/native/src/api.rs new file mode 100644 index 00000000..78668777 --- /dev/null +++ b/native/src/api.rs @@ -0,0 +1,92 @@ +use std::{num::NonZeroU32, vec}; + +use aes_gcm::{ + aead::{ + generic_array::{typenum, GenericArray}, + Aead, NewAead, + }, + Aes256Gcm, Key, Nonce, +}; +use flutter_rust_bridge::ZeroCopyBuffer; +use ring::{digest, pbkdf2}; + +static PBKDF2_ALGO: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA512; +const OUTPUT_LENGTH: usize = digest::SHA256_OUTPUT_LEN; + +pub fn derive_key( + password: String, + nonce: ZeroCopyBuffer>, +) -> ZeroCopyBuffer> { + let mut key = vec![0u8; OUTPUT_LENGTH]; + + pbkdf2::derive( + PBKDF2_ALGO, + NonZeroU32::new(100000).unwrap(), + nonce.0.as_ref(), + password.as_bytes(), + &mut key, + ); + + ZeroCopyBuffer(key) +} + +pub fn encrypt( + data: ZeroCopyBuffer>, + password: String, + // Password nonce + key_nonce: ZeroCopyBuffer>, + // AES nonce + aes_nonce: ZeroCopyBuffer>, +) -> Option>> { + let key = derive_key(password, key_nonce.clone()); + + let cipher = Aes256Gcm::new(Key::from_slice(&key.0)); + let nonce: &GenericArray = + Nonce::from_slice(&aes_nonce.0); + + cipher + .encrypt(nonce, &*data.0) + .and_then(|ciphertext| { + let ciphertext_len = ciphertext.len(); + + let mut result = + vec![ + 0u8; + key_nonce.0.len() + aes_nonce.0.len() + ciphertext.len() + ]; + + result[0..16].copy_from_slice(&key_nonce.0); + result[16..28].copy_from_slice(&aes_nonce.0); + result[28..44].copy_from_slice( + &ciphertext[(ciphertext_len - 16)..(ciphertext_len)], + ); + result[44..].copy_from_slice(&ciphertext[..(ciphertext_len - 16)]); + + Ok(ZeroCopyBuffer(result)) + }) + .ok() +} + +pub fn decrypt( + data: ZeroCopyBuffer>, + password: String, +) -> Option>> { + let key_nonce = &data.0[0..16]; + let aes_nonce = &data.0[16..28]; + let mac = &data.0[28..44]; + let ciphertext = &data.0[44..]; + + let mut ciphertext_mac = vec![0u8; ciphertext.len() + mac.len()]; + ciphertext_mac[..(ciphertext.len())].copy_from_slice(ciphertext); + ciphertext_mac[(ciphertext.len())..].copy_from_slice(mac); + + let key = derive_key(password, ZeroCopyBuffer(key_nonce.to_vec())); + + let cipher = Aes256Gcm::new(Key::from_slice(&key.0)); + let nonce: &GenericArray = Nonce::from_slice(aes_nonce); + + cipher + .decrypt(nonce, ciphertext_mac.as_ref()) + .and_then(|plaintext| Ok(ZeroCopyBuffer(plaintext))) + .ok() +} diff --git a/native/src/bridge_generated.rs b/native/src/bridge_generated.rs new file mode 100644 index 00000000..f22be1ae --- /dev/null +++ b/native/src/bridge_generated.rs @@ -0,0 +1,190 @@ +#![allow( + non_camel_case_types, + unused, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + non_snake_case +)] +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`. + +use crate::api::*; +use flutter_rust_bridge::*; + +// Section: imports + +// Section: wire functions + +#[no_mangle] +pub extern "C" fn wire_derive_key( + port_: i64, + password: *mut wire_uint_8_list, + nonce: *mut wire_uint_8_list, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap( + WrapInfo { + debug_name: "derive_key", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_password = password.wire2api(); + let api_nonce = nonce.wire2api(); + move |task_callback| Ok(derive_key(api_password, api_nonce)) + }, + ) +} + +#[no_mangle] +pub extern "C" fn wire_encrypt( + port_: i64, + data: *mut wire_uint_8_list, + password: *mut wire_uint_8_list, + key_nonce: *mut wire_uint_8_list, + aes_nonce: *mut wire_uint_8_list, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap( + WrapInfo { + debug_name: "encrypt", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_data = data.wire2api(); + let api_password = password.wire2api(); + let api_key_nonce = key_nonce.wire2api(); + let api_aes_nonce = aes_nonce.wire2api(); + move |task_callback| { + Ok(encrypt( + api_data, + api_password, + api_key_nonce, + api_aes_nonce, + )) + } + }, + ) +} + +#[no_mangle] +pub extern "C" fn wire_decrypt( + port_: i64, + data: *mut wire_uint_8_list, + password: *mut wire_uint_8_list, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap( + WrapInfo { + debug_name: "decrypt", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_data = data.wire2api(); + let api_password = password.wire2api(); + move |task_callback| Ok(decrypt(api_data, api_password)) + }, + ) +} + +// Section: wire structs + +#[repr(C)] +#[derive(Clone)] +pub struct wire_uint_8_list { + ptr: *mut u8, + len: i32, +} + +// Section: wrapper structs + +// Section: static checks + +// Section: allocate functions + +#[no_mangle] +pub extern "C" fn new_uint_8_list(len: i32) -> *mut wire_uint_8_list { + let ans = wire_uint_8_list { + ptr: support::new_leak_vec_ptr(Default::default(), len), + len, + }; + support::new_leak_box_ptr(ans) +} + +// Section: impl Wire2Api + +pub trait Wire2Api { + fn wire2api(self) -> T; +} + +impl Wire2Api> for *mut S +where + *mut S: Wire2Api, +{ + fn wire2api(self) -> Option { + if self.is_null() { + None + } else { + Some(self.wire2api()) + } + } +} + +impl Wire2Api for *mut wire_uint_8_list { + fn wire2api(self) -> String { + let vec: Vec = self.wire2api(); + String::from_utf8_lossy(&vec).into_owned() + } +} + +impl Wire2Api>> for *mut wire_uint_8_list { + fn wire2api(self) -> ZeroCopyBuffer> { + ZeroCopyBuffer(self.wire2api()) + } +} + +impl Wire2Api for u8 { + fn wire2api(self) -> u8 { + self + } +} + +impl Wire2Api> for *mut wire_uint_8_list { + fn wire2api(self) -> Vec { + unsafe { + let wrap = support::box_from_leak_ptr(self); + support::vec_from_leak_ptr(wrap.ptr, wrap.len) + } + } +} + +// Section: impl NewWithNullPtr + +pub trait NewWithNullPtr { + fn new_with_null_ptr() -> Self; +} + +impl NewWithNullPtr for *mut T { + fn new_with_null_ptr() -> Self { + std::ptr::null_mut() + } +} + +// Section: impl IntoDart + +// Section: executor + +support::lazy_static! { + pub static ref FLUTTER_RUST_BRIDGE_HANDLER: support::DefaultHandler = Default::default(); +} + +// Section: sync execution mode utility + +#[no_mangle] +pub extern "C" fn free_WireSyncReturnStruct( + val: support::WireSyncReturnStruct, +) { + unsafe { + let _ = support::vec_from_leak_ptr(val.ptr, val.len); + } +} diff --git a/native/src/lib.rs b/native/src/lib.rs new file mode 100644 index 00000000..dfdd872c --- /dev/null +++ b/native/src/lib.rs @@ -0,0 +1,2 @@ +mod api; +mod bridge_generated; diff --git a/pubspec.lock b/pubspec.lock index 59c4de73..a30f8945 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -484,6 +484,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.5" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + url: "https://pub.dartlang.org" + source: hosted + version: "1.22.1" flutter_staggered_grid_view: dependency: "direct main" description: @@ -501,6 +508,20 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" frontend_server_client: dependency: transitive description: @@ -1280,15 +1301,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - webcrypto: - dependency: "direct main" - description: - path: "." - ref: HEAD - resolved-ref: "98f210ab17982874af0ee885dcd5f51b064e8f73" - url: "https://github.com/gargakshit/webcrypto.dart" - source: git - version: "0.5.2" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ab5c3ebd..8a092e79 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,7 +40,9 @@ dependencies: flutter_keyboard_visibility: ^5.1.1 flutter_local_notifications: ^9.2.0 flutter_mobx: ^2.0.4 + flutter_rust_bridge: ^1.22.1 flutter_staggered_grid_view: ^0.6.1 + freezed_annotation: ^1.1.0 http: ^0.13.3 @@ -79,7 +81,7 @@ dependencies: url: https://github.com/simolus3/sqlite3.dart.git path: sqlcipher_flutter_libs sqlite3: ^1.5.1 - + toml: ^0.12.0 universal_platform: ^1.0.0+1 @@ -87,8 +89,6 @@ dependencies: uuid: ^3.0.4 waterfall_flow: ^3.0.2 - webcrypto: - git: https://github.com/gargakshit/webcrypto.dart xml: ^5.3.1 @@ -97,6 +97,7 @@ dev_dependencies: drift_dev: ^1.4.0 flutter_test: sdk: flutter + freezed: ^1.1.1 json_serializable: ^6.1.4 lint: ^1.8.2 mobx_codegen: ^2.0.5+2 @@ -117,4 +118,4 @@ flutter: dependency_overrides: path: ^1.8.1 - path_parsing: ^1.0.0 \ No newline at end of file + path_parsing: ^1.0.0 diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 8134d129..27aff77f 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -50,6 +50,9 @@ add_subdirectory("runner") # them to the application. include(flutter/generated_plugins.cmake) +include(./cmake/gen.cmake) +include(./cmake/rust.cmake) + # === Installation === # Support files are copied into place next to the executable, so that it can @@ -95,7 +98,4 @@ install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "libs/sqlcipher.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -install(FILES "libs/libwebcrypto.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) \ No newline at end of file diff --git a/windows/cmake/gen.cmake b/windows/cmake/gen.cmake new file mode 100644 index 00000000..0f246053 --- /dev/null +++ b/windows/cmake/gen.cmake @@ -0,0 +1,10 @@ +# Runs the bridge codegen script + +message("Performing bridge codegen") + +execute_process(COMMAND just RESULT_VARIABLE CMD_ERROR OUTPUT_VARIABLE CMD_OUTPUT) + +message("Codegen exit code: ${CMD_ERROR}") +message("Codegen output: ${CMD_OUTPUT}") + +message("Done performing bridge codegen") diff --git a/windows/cmake/rust.cmake b/windows/cmake/rust.cmake new file mode 100644 index 00000000..0c6db342 --- /dev/null +++ b/windows/cmake/rust.cmake @@ -0,0 +1,25 @@ +# We include Corrosion inline here, but ideally in a project with +# many dependencies we would need to install Corrosion on the system. +# See instructions on https://github.com/AndrewGaspar/corrosion#cmake-install +# Once done, uncomment this line: +# find_package(Corrosion REQUIRED) + +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/AndrewGaspar/corrosion.git + GIT_TAG origin/master # Optionally specify a version tag or branch here +) + +FetchContent_MakeAvailable(Corrosion) + +corrosion_import_crate(MANIFEST_PATH ../native/Cargo.toml) + +# Flutter-specific + +set(CRATE_NAME "native") + +target_link_libraries(${BINARY_NAME} PRIVATE ${CRATE_NAME}) + +list(APPEND PLUGIN_BUNDLED_LIBRARIES $) diff --git a/windows/libs/libwebcrypto.dll b/windows/libs/libwebcrypto.dll deleted file mode 100644 index e3b09a0f..00000000 Binary files a/windows/libs/libwebcrypto.dll and /dev/null differ