diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bdb8a9f8..491401a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,10 @@ on: pull_request: branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: PUB_ENVIRONMENT: bot.github @@ -38,60 +42,19 @@ jobs: sudo apt-get install -y ninja-build libgtk-3-dev flutter config --no-analytics - run: flutter pub get - - run: flutter pub run webcrypto:setup - - run: flutter test + - run: flutter test --coverage - run: flutter test --platform chrome - - run: flutter test --platform chrome --wasm + - run: dart test -p chrome -c dart2wasm + - run: xvfb-run dart test -p firefox - run: xvfb-run flutter test integration_test/webcrypto_test.dart -d linux working-directory: ./example - - uses: nanasess/setup-chromedriver@v2 - - name: Run integration_test with chromedriver - working-directory: ./example - run: | - xvfb-run ../tool/with-chromedriver.sh flutter drive \ - --driver=test_driver/integration_test.dart \ - --target=integration_test/webcrypto_test.dart \ - -d chrome - - run: xvfb-run flutter pub run test -p vm,chrome,firefox - macos-14: - name: MacOS 14 desktop / Chrome / Firefox - runs-on: macos-14 # Test with xcode 15 - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 + # Report collected coverage + - uses: coverallsapp/github-action@v2 with: - channel: 'stable' - cache: true - - name: Configure Flutter - run: | - flutter config --no-analytics - - run: flutter pub get - - run: flutter pub run webcrypto:setup - - run: flutter test - - run: flutter test --platform chrome - - run: flutter test --platform chrome --wasm - - run: flutter test integration_test/webcrypto_test.dart -d macos - working-directory: ./example - # TODO: Enable chromedriver testing on MacOS when it works reliably - #- uses: nanasess/setup-chromedriver@v2 - #- name: Run integration_test with chromedriver - # working-directory: ./example - # run: | - # ../tool/with-chromedriver.sh flutter drive \ - # --driver=test_driver/integration_test.dart \ - # --target=integration_test/webcrypto_test.dart \ - # -d chrome - - uses: browser-actions/setup-firefox@v1 - - name: flutter pub run test -p vm,chrome,firefox - shell: bash - # Remove FIREFOX_EXECUTABLE override when flutter upgrades past package:test 1.25.8 - # Issue is fixed in https://github.com/dart-lang/test/pull/2276 - run: | - export FIREFOX_EXECUTABLE="$(which firefox)" - flutter pub run test -p vm,chrome,firefox - macos-15: - name: MacOS 15 desktop / Chrome / Firefox + flag-name: linux + parallel: true + macos: + name: MacOS desktop / Chrome / Firefox runs-on: macos-15 # Test with xcode 16 timeout-minutes: 15 steps: @@ -104,21 +67,19 @@ jobs: run: | flutter config --no-analytics - run: flutter pub get - - run: flutter pub run webcrypto:setup - run: flutter test - run: flutter test --platform chrome - - run: flutter test --platform chrome --wasm - run: flutter test integration_test/webcrypto_test.dart -d macos working-directory: ./example # TODO: Enable chromedriver testing on MacOS when it works reliably - uses: browser-actions/setup-firefox@v1 - - name: flutter pub run test -p vm,chrome,firefox + - name: Run Firefox tests shell: bash # Remove FIREFOX_EXECUTABLE override when flutter upgrades past package:test 1.25.8 # Issue is fixed in https://github.com/dart-lang/test/pull/2276 run: | export FIREFOX_EXECUTABLE="$(which firefox)" - flutter pub run test -p vm,chrome,firefox + dart test -p firefox windows: name: Windows desktop / Chrome / Firefox runs-on: windows-latest @@ -134,26 +95,21 @@ jobs: run: | flutter config --no-analytics - run: flutter pub get - - run: flutter pub run webcrypto:setup - - run: flutter test - #- run: flutter test --platform chrome - #- run: flutter test --platform chrome --wasm + - run: flutter test --coverage + - run: dart test -p chrome + - run: dart test -p firefox - run: flutter test integration_test/webcrypto_test.dart -d windows working-directory: ./example - - uses: nanasess/setup-chromedriver@v2 - - name: Run integration_test with chromedriver - working-directory: ./example - shell: bash - run: | - ../tool/with-chromedriver.sh flutter drive \ - --driver=test_driver/integration_test.dart \ - --target=integration_test/webcrypto_test.dart \ - -d chrome - - run: flutter pub run test -p vm,chrome,firefox + # Report collected coverage + - uses: coverallsapp/github-action@v2 + with: + flag-name: windows + parallel: true ios: name: iOS emulator (iPhone) runs-on: macos-14 timeout-minutes: 15 + continue-on-error: true steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 @@ -173,6 +129,7 @@ jobs: name: Android emulator runs-on: ubuntu-latest timeout-minutes: 15 + continue-on-error: true steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 @@ -202,62 +159,13 @@ jobs: arch: x86_64 working-directory: ./example script: flutter test integration_test/webcrypto_test.dart -d emulator - linux-coverage: - name: Linux desktop / Chrome / Firefox (coverage) - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - cache: true - - name: Configure Flutter - run: | - sudo apt-get update -y - sudo apt-get install -y ninja-build libgtk-3-dev - flutter config --no-analytics - - run: flutter pub get - - run: flutter pub run webcrypto:setup - - run: xvfb-run flutter pub run test -p vm,chrome,firefox -c dart2js,dart2wasm --coverage ./coverage - # Report collected coverage - - name: Convert coverage to lcov - run: dart run coverage:format_coverage -i ./coverage -o ./coverage/lcov.info --lcov --report-on lib/ - - uses: coverallsapp/github-action@v2 - with: - flag-name: linux - parallel: true - windows-coverage: - name: Windows desktop / Chrome / Firefox (coverage) - runs-on: windows-latest - timeout-minutes: 15 - steps: - - uses: ilammy/setup-nasm@v1 - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - cache: true - - name: Configure Flutter - run: | - flutter config --no-analytics - - run: flutter pub get - - run: flutter pub run webcrypto:setup - - run: flutter pub run test -p vm,chrome,firefox --coverage ./coverage - # Report collected coverage - - name: Convert coverage to lcov - run: dart run coverage:format_coverage -i ./coverage -o ./coverage/lcov.info --lcov --report-on lib/ - - uses: coverallsapp/github-action@v2 - with: - flag-name: windows - parallel: true coverage: name: Report to coveralls runs-on: ubuntu-latest timeout-minutes: 15 needs: - - linux-coverage - - windows-coverage + - linux + - windows steps: - uses: coverallsapp/github-action@v2 with: diff --git a/example/pubspec.lock b/example/pubspec.lock index e619be81..da414644 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,23 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d url: "https://pub.dev" source: hosted - version: "72.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.2" + version: "91.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "8.4.1" args: dependency: transitive description: @@ -46,30 +41,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + change_case: + dependency: transitive + description: + name: change_case + sha256: e41ef3df58521194ef8d7649928954805aeb08061917cf658322305e61568003 + url: "https://pub.dev" + source: hosted + version: "2.2.0" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" convert: dependency: "direct main" description: @@ -106,10 +117,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" ffi: dependency: transitive description: @@ -163,10 +174,18 @@ packages: dependency: transitive description: name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" http_multi_server: dependency: transitive description: @@ -208,26 +227,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" logging: dependency: transitive description: @@ -236,22 +255,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" - macros: - dependency: transitive - description: - name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" - url: "https://pub.dev" - source: hosted - version: "0.1.2-main.4" matcher: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -264,10 +275,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.17.0" mime: dependency: transitive description: @@ -276,6 +287,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + native_toolchain_cmake: + dependency: transitive + description: + name: native_toolchain_cmake + sha256: fe40e8483183ced98e851e08a9cd2a547fd412cccab98277aa23f2377e43d66f + url: "https://pub.dev" + source: hosted + version: "0.2.4" node_preamble: dependency: transitive description: @@ -296,10 +315,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" platform: dependency: transitive description: @@ -328,10 +347,10 @@ packages: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" shelf: dependency: transitive description: @@ -368,7 +387,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_map_stack_trace: dependency: transitive description: @@ -397,18 +416,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: @@ -437,26 +456,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.26.3" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.7" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.12" typed_data: dependency: transitive description: @@ -469,10 +488,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -519,7 +538,7 @@ packages: path: ".." relative: true source: path - version: "0.5.7" + version: "0.6.0" webdriver: dependency: transitive description: @@ -540,10 +559,10 @@ packages: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.10.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/hook/build.dart b/hook/build.dart new file mode 100644 index 00000000..bfd73222 --- /dev/null +++ b/hook/build.dart @@ -0,0 +1,131 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'dart:ffi'; +import 'dart:io'; + +import 'package:code_assets/code_assets.dart'; +import 'package:hooks/hooks.dart'; +import 'package:native_toolchain_cmake/native_toolchain_cmake.dart'; + +const _assetName = 'webcrypto.dart'; + +Future main(List args) async { + await build(args, (input, output) async { + // Skip build for non-code targets (e.g. web builds via flutter drive). + if (!input.config.buildCodeAssets) { + stdout.writeln( + 'webcrypto: skipping native asset build (code assets not requested).', + ); + return; + } + + final targetOs = input.config.code.targetOS; + if (!_hostSupports(targetOs)) { + stdout.writeln( + 'webcrypto: skipping native asset build for unsupported target OS ' + '$targetOs on host ${Platform.operatingSystem}.', + ); + return; + } + + final targetArch = input.config.code.targetArchitecture; + if (!_hostSupportsArchitecture(targetArch)) { + stdout.writeln( + 'webcrypto: skipping native asset build for unsupported target ' + 'architecture $targetArch on host ${Abi.current()}.', + ); + return; + } + + final packageRoot = Directory.fromUri(input.packageRoot).uri; + final installDir = input.outputDirectory.resolve('install/'); + final sourceDir = packageRoot.resolve('src/'); + + final builder = CMakeBuilder.create( + name: 'webcrypto', + sourceDir: sourceDir, + buildLocal: true, + defines: { + 'CMAKE_BUILD_TYPE': 'Release', + 'CMAKE_INSTALL_PREFIX': installDir.toFilePath(), + }, + targets: ['install'], + ); + + await builder.run(input: input, output: output); + + final assets = await output.findAndAddCodeAssets( + input, + outDir: installDir, + names: {r'(lib)?webcrypto\.(dll|dylib|so)': _assetName}, + regExp: true, + ); + if (assets.isEmpty) { + throw BuildError( + message: + 'Failed to locate built webcrypto dynamic library in ' + '${installDir.toFilePath()}', + ); + } + + for (final dependency in [ + packageRoot.resolve('src/CMakeLists.txt'), + packageRoot.resolve('src/webcrypto.c'), + packageRoot.resolve('src/webcrypto.h'), + packageRoot.resolve('src/symbols.generated.c'), + packageRoot.resolve('third_party/boringssl/sources.cmake'), + ]) { + output.dependencies.add(dependency); + } + }); +} + +bool _hostSupports(OS target) { + switch (target) { + case OS.linux: + return Platform.isLinux; + case OS.macOS: + return Platform.isMacOS; + case OS.windows: + return Platform.isWindows; + default: + return false; + } +} + +bool _hostSupportsArchitecture(Architecture targetArch) { + switch (targetArch) { + case Architecture.arm64: + return const { + Abi.androidArm64, + Abi.fuchsiaArm64, + Abi.iosArm64, + Abi.linuxArm64, + Abi.macosArm64, + Abi.windowsArm64, + }.contains(Abi.current()); + case Architecture.x64: + return const { + Abi.androidX64, + Abi.fuchsiaX64, + Abi.iosX64, + Abi.linuxX64, + Abi.macosX64, + Abi.windowsX64, + }.contains(Abi.current()); + default: + return false; + } +} diff --git a/lib/src/boringssl/lookup/lookup.dart b/lib/src/boringssl/lookup/lookup.dart index 74df28f7..138144d1 100644 --- a/lib/src/boringssl/lookup/lookup.dart +++ b/lib/src/boringssl/lookup/lookup.dart @@ -26,8 +26,67 @@ import 'utils.dart'; export 'symbols.generated.dart' show Sym; -/// Dynamically load `webcrypto_lookup_symbol` function. -final Pointer Function(String symbolName) lookup = () { +const _nativeAssetId = 'package:webcrypto/webcrypto.dart'; + +typedef _VoidLookup = Pointer Function(String symbolName); + +bool _nativeAssetsAvailable = true; + +@Native Function(Int32)>( + symbol: 'webcrypto_lookup_symbol', + assetId: _nativeAssetId, +) +external Pointer _nativeWebcryptoLookupSymbol(int index); + +/// Resolve lookup from native assets first, then fall back to the legacy +/// runtime loading strategy used by `flutter pub run webcrypto:setup`. +final Pointer Function(String symbolName) lookup = + _resolveLookup(); + +Pointer Function(String symbolName) _resolveLookup() { + final nativeLookup = _createNativeAssetLookup(); + _VoidLookup? legacyLookup; + + _VoidLookup ensureLegacy() => legacyLookup ??= _createLegacyLookup(); + + if (nativeLookup != null) { + return (String symbolName) { + if (_nativeAssetsAvailable) { + try { + return nativeLookup(symbolName).cast(); + } on Object { + _nativeAssetsAvailable = false; + } + } + final fallback = ensureLegacy(); + return fallback(symbolName).cast(); + }; + } + + _nativeAssetsAvailable = false; + final fallback = ensureLegacy(); + return (String symbolName) => + fallback(symbolName).cast(); +} + +_VoidLookup? _createNativeAssetLookup() { + if (!_shouldAttemptNativeAssets()) { + return null; + } + + try { + _nativeWebcryptoLookupSymbol(Sym.BN_bin2bn.index); + } on Object { + return null; + } + + return (String symbolName) { + final sym = symFromString(symbolName); + return _nativeWebcryptoLookupSymbol(sym.index); + }; +} + +_VoidLookup _createLegacyLookup() { try { late DynamicLibrary library; if (Platform.isAndroid || Platform.isLinux) { @@ -36,11 +95,10 @@ final Pointer Function(String symbolName) lookup = () { library = DynamicLibrary.open('webcrypto.dll'); } else { library = DynamicLibrary.executable(); - // If current executable doesn't provide the symbol, then we're if (!library.providesSymbol('webcrypto_lookup_symbol')) { - final lookup = lookupLibraryInDotDartTool(); - if (lookup != null) { - return lookup; + final toolLookup = lookupLibraryInDotDartTool(); + if (toolLookup != null) { + return (String symbolName) => toolLookup(symbolName); } throw UnsupportedError( 'package:webcrypto could not find required symbols in executable. ' @@ -51,19 +109,15 @@ final Pointer Function(String symbolName) lookup = () { } } - // Try to lookup the 'webcrypto_lookup_symbol' symbol. final webcrypto = WebCrypto(library); - final webcrypto_lookup_symbol = webcrypto.webcrypto_lookup_symbol; + final webcryptoLookup = webcrypto.webcrypto_lookup_symbol; - // Return a function from Sym to lookup using `webcrypto_lookup_symbol` - Pointer lookup(String s) => - webcrypto_lookup_symbol(symFromString(s).index).cast(); - - return lookup; + return (String symbolName) => + webcryptoLookup(symFromString(symbolName).index); } on ArgumentError { - final lookup = lookupLibraryInDotDartTool(); - if (lookup != null) { - return lookup; + final toolLookup = lookupLibraryInDotDartTool(); + if (toolLookup != null) { + return (String symbolName) => toolLookup(symbolName); } throw UnsupportedError( @@ -72,7 +126,10 @@ final Pointer Function(String symbolName) lookup = () { 'root project.', ); } -}(); +} + +bool _shouldAttemptNativeAssets() => + Platform.isLinux || Platform.isMacOS || Platform.isWindows; final Pointer Function(String symbolName) _cachedLookup = lookup; diff --git a/pubspec.yaml b/pubspec.yaml index 7859a5d6..effdb058 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,9 @@ environment: dependencies: ffi: ^2.0.0 + hooks: ^1.0.0 + code_assets: ^1.0.0 + native_toolchain_cmake: ^0.2.4 meta: ^1.3.0 # Needed for `lib/src/flutter/webcrypto_plugin.dart` which allows boiler-plate # in `flutter.plugin.platforms.web` added below. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86e65e89..74c51e7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,31 +50,31 @@ include( add_definitions(-DOPENSSL_SMALL) # Logic from CMakeLists.txt in BoringSSL -if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") +if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") set(ARCH "x86_64") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "amd64") set(ARCH "x86_64") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(ARCH "x86_64") else() set(ARCH "x86") endif() -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86") set(ARCH "x86") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i386") set(ARCH "x86") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") set(ARCH "x86") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") set(ARCH "aarch64") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64") set(ARCH "aarch64") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64e") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64e") set(ARCH "aarch64") -elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*") +elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^arm*") set(ARCH "arm") -elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le") +elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") set(ARCH "ppc64le") else() set(ARCH "generic") @@ -101,6 +101,7 @@ if(MSVC) set(MSVC_DISABLED_WARNINGS_LIST "C4100" # 'exarg' : unreferenced formal parameter "C4127" # conditional expression is constant + "C4132" # const object should be initialized "C4244" # 'function' : conversion from 'int' to 'uint8_t', # possible loss of data "C4267" # conversion from 'size_t' to 'int', possible loss of data @@ -161,3 +162,10 @@ set_target_properties( C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1 ) + +install( + TARGETS webcrypto + RUNTIME DESTINATION . + LIBRARY DESTINATION . + ARCHIVE DESTINATION . +) diff --git a/test/crypto_subtle_test.dart b/test/crypto_subtle_test.dart index 3c114a08..d5434628 100644 --- a/test/crypto_subtle_test.dart +++ b/test/crypto_subtle_test.dart @@ -121,27 +121,37 @@ void main() { }); test('getRandomValues: too long', () { - try { - subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS); - } on subtle.JSDomException catch (e) { - // dart2js throws QuotaExceededError - expect(e.name, 'QuotaExceededError'); - } on Error catch (e) { - // dart2wasm throws JavaScriptError - expect(e.toString(), 'JavaScriptError'); - } + expect( + () => subtle.window.crypto.getRandomValues(Uint8List(1000000).toJS), + throwsA( + // dart2js throws JSDomException with 'QuotaExceededError' in toString. + // dart2wasm throws _JavaScriptError; toString() may be just + // 'JavaScriptError' (dart test) or include the DOM error name + // (flutter test). + isA().having( + (e) => e.toString(), + 'toString', + anyOf(contains('QuotaExceededError'), equals('JavaScriptError')), + ), + ), + ); }); test('getRandomValues: not supported type', () { - try { - subtle.window.crypto.getRandomValues(Float32List(32).toJS); - } on subtle.JSDomException catch (e) { - // dart2js throws TypeMismatchError - expect(e.name, 'TypeMismatchError'); - } on Error catch (e) { - // dart2wasm throws JavaScriptError - expect(e.toString(), 'JavaScriptError'); - } + expect( + () => subtle.window.crypto.getRandomValues(Float32List(32).toJS), + throwsA( + // dart2js throws JSDomException with 'TypeMismatchError' in toString. + // dart2wasm throws _JavaScriptError; toString() may be just + // 'JavaScriptError' (dart test) or include the DOM error name + // (flutter test). + isA().having( + (e) => e.toString(), + 'toString', + anyOf(contains('TypeMismatchError'), equals('JavaScriptError')), + ), + ), + ); }); });