From 0a040d29710565ffeb2cbccd5c2ca4c2ef65cb9b Mon Sep 17 00:00:00 2001 From: Hugo Pointcheval Date: Wed, 22 Feb 2023 17:27:58 +0100 Subject: [PATCH] feat(interface)!: add pigeon + add hmac + remove useless decryption method --- .../analysis_options.yaml | 7 +- .../lib/native_crypto_platform_interface.dart | 23 +- .../lib/src/core/enums/exception_code.dart | 84 ++ .../lib/src/core/enums/methods.dart | 17 + .../lib/src/core/exceptions/exception.dart | 100 +++ .../basic_message_channel_native_crypto.dart | 204 +++++ .../method_channel_native_crypto.dart | 161 ++++ .../src/interface/native_crypto_platform.dart | 120 +++ .../method_channel_native_crypto.dart | 154 ---- .../lib/src/pigeon/messages.pigeon.dart | 829 ++++++++++++++++++ .../lib/src/pigeon/test_api.dart | 316 +++++++ .../native_crypto_platform.dart | 92 -- .../lib/src/utils/exception.dart | 126 --- .../pigeons/copyright_header.txt | 6 + .../pigeons/messages.dart | 222 +++++ .../pubspec.yaml | 10 +- .../method_channel_native_crypto_test.dart | 175 ---- .../test/native_crypto_exception_test.dart | 72 ++ .../native_crypto_platform_test.dart | 170 +--- 19 files changed, 2187 insertions(+), 701 deletions(-) create mode 100644 packages/native_crypto_platform_interface/lib/src/core/enums/exception_code.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/core/enums/methods.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/core/exceptions/exception.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/implementations/basic_message_channel_native_crypto.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/implementations/method_channel_native_crypto.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/interface/native_crypto_platform.dart delete mode 100644 packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/pigeon/messages.pigeon.dart create mode 100644 packages/native_crypto_platform_interface/lib/src/pigeon/test_api.dart delete mode 100644 packages/native_crypto_platform_interface/lib/src/platform_interface/native_crypto_platform.dart delete mode 100644 packages/native_crypto_platform_interface/lib/src/utils/exception.dart create mode 100644 packages/native_crypto_platform_interface/pigeons/copyright_header.txt create mode 100644 packages/native_crypto_platform_interface/pigeons/messages.dart delete mode 100644 packages/native_crypto_platform_interface/test/method_channel/method_channel_native_crypto_test.dart create mode 100644 packages/native_crypto_platform_interface/test/native_crypto_exception_test.dart diff --git a/packages/native_crypto_platform_interface/analysis_options.yaml b/packages/native_crypto_platform_interface/analysis_options.yaml index 82177cd..224f249 100644 --- a/packages/native_crypto_platform_interface/analysis_options.yaml +++ b/packages/native_crypto_platform_interface/analysis_options.yaml @@ -1 +1,6 @@ -include: package:wyatt_analysis/analysis_options.flutter.yaml \ No newline at end of file +include: package:wyatt_analysis/analysis_options.flutter.yaml + +analyzer: + exclude: + - "**/*.pigeon.dart" + - "lib/src/pigeon/test_api.dart" \ No newline at end of file diff --git a/packages/native_crypto_platform_interface/lib/native_crypto_platform_interface.dart b/packages/native_crypto_platform_interface/lib/native_crypto_platform_interface.dart index c85bda1..5e2f256 100644 --- a/packages/native_crypto_platform_interface/lib/native_crypto_platform_interface.dart +++ b/packages/native_crypto_platform_interface/lib/native_crypto_platform_interface.dart @@ -1,14 +1,15 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: native_crypto_platform_interface.dart -// Created Date: 24/05/2022 19:39:11 -// Last Modified: 24/05/2022 19:39:58 -// ----- -// Copyright (c) 2022 +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. +/// The interface that implementations of native_crypto must implement. library native_crypto_platform_interface; -export 'src/method_channel/method_channel_native_crypto.dart'; -export 'src/platform_interface/native_crypto_platform.dart'; -export 'src/utils/exception.dart'; +export 'src/core/enums/exception_code.dart'; +export 'src/core/enums/methods.dart'; +export 'src/core/exceptions/exception.dart'; +export 'src/implementations/basic_message_channel_native_crypto.dart'; +export 'src/implementations/method_channel_native_crypto.dart'; +export 'src/interface/native_crypto_platform.dart'; diff --git a/packages/native_crypto_platform_interface/lib/src/core/enums/exception_code.dart b/packages/native_crypto_platform_interface/lib/src/core/enums/exception_code.dart new file mode 100644 index 0000000..910b9d9 --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/core/enums/exception_code.dart @@ -0,0 +1,84 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +enum NativeCryptoExceptionCode { + /// The method is not implemented on the platform side. + platformMethodNotImplemented, + + /// Platform returned invalid data. + /// Can be null, empty, or not the expected type. + platformReturnedInvalidData, // TODO(hpcl): remove this + + /// The platforms returned null. + nullError, + + /// The algorithm is not supported. + algorithmNotSupported, + + /// The key is not valid. Like a bad length or format. + invalidKey, + + /// The data is not valid. + invalidData, + + /// The parameters are not valid. Like an invalid IV. + invalidParameters, + + /// Authentication failed. Like a bad MAC or tag. + authenticationError, + + /// An I/O error occurred. + ioError, + + /// Key derivation failed. + keyDerivationError, + + /// Channel error. Like a bad channel or a bad message. + channelError, + + /// An unknown error occurred. + unknownError; + + /// Returns code of the [NativeCryptoExceptionCode]. + /// ```dart + /// print(NativeCryptoExceptionCode.platformMethodNotImplemented.code) + /// // => platform_method_not_implemented + /// ``` + String get code { + switch (name.length) { + case 0: + return name; + case 1: + return name.toLowerCase(); + default: + return name + .splitMapJoin( + RegExp('[A-Z]'), + onMatch: (m) => ' ${m[0]}', + onNonMatch: (n) => n, + ) + .trim() + .splitMapJoin( + RegExp(r'\s+|-+|_+|\.+'), + onMatch: (m) => '_', + onNonMatch: (n) => n.toLowerCase(), + ); + } + } + + /// Returns the [NativeCryptoExceptionCode] from the given [code]. + static NativeCryptoExceptionCode from(String code) { + for (final value in values) { + if (value.code == code) { + return value; + } + } + return unknownError; + } + + @override + String toString() => code; +} diff --git a/packages/native_crypto_platform_interface/lib/src/core/enums/methods.dart b/packages/native_crypto_platform_interface/lib/src/core/enums/methods.dart new file mode 100644 index 0000000..024b575 --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/core/enums/methods.dart @@ -0,0 +1,17 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +enum NativeCryptoMethod { + hash, + hmac, + generateSecureRandom, + pbkdf2, + encrypt, + decrypt, + encryptFile, + decryptFile, + encryptWithIV +} diff --git a/packages/native_crypto_platform_interface/lib/src/core/exceptions/exception.dart b/packages/native_crypto_platform_interface/lib/src/core/exceptions/exception.dart new file mode 100644 index 0000000..9143b13 --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/core/exceptions/exception.dart @@ -0,0 +1,100 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:equatable/equatable.dart'; +import 'package:flutter/services.dart'; +import 'package:native_crypto_platform_interface/src/core/enums/exception_code.dart'; + +/// An exception thrown by the native crypto plugin. +class NativeCryptoException extends Equatable implements Exception { + /// Creates a new [NativeCryptoException]. + const NativeCryptoException({ + required this.code, + this.message, + this.stackTrace, + }); + + /// Creates a new [NativeCryptoException] from a [PlatformException]. + factory NativeCryptoException.fromPlatformException( + PlatformException platformException, + StackTrace stackTrace, + ) { + final Map? details = platformException.details != null + ? Map.from( + platformException.details as Map, + ) + : null; + + String code = platformException.code.split('(').first; + String message = platformException.message ?? ''; + + if (details != null) { + code = details['code'] ?? code; + message = details['message'] ?? message; + } + + return NativeCryptoException( + code: NativeCryptoExceptionCode.from(code), + message: message, + stackTrace: stackTrace, + ); + } + + /// The standardised error code. + final NativeCryptoExceptionCode code; + + /// The long form message of the exception. + final String? message; + + /// The stack trace which provides information to the user about the call + /// sequence that triggered an exception + final StackTrace? stackTrace; + + static Never convertPlatformException( + Object exception, + StackTrace stackTrace, + ) { + // If the exception is not a PlatformException, throw it as is. + if (exception is! Exception || exception is! PlatformException) { + Error.throwWithStackTrace(exception, stackTrace); + } + + // Otherwise, throw a NativeCryptoException. + Error.throwWithStackTrace( + NativeCryptoException.fromPlatformException(exception, stackTrace), + stackTrace, + ); + } + + NativeCryptoException copyWith({ + NativeCryptoExceptionCode? code, + String? message, + StackTrace? stackTrace, + }) => + NativeCryptoException( + code: code ?? this.code, + message: message ?? this.message, + stackTrace: stackTrace ?? this.stackTrace, + ); + + @override + String toString() { + final output = StringBuffer('[NativeCrypto/$code]'); + + if (message != null) { + output.write(' $message'); + } + + if (stackTrace != null) { + output.write('\n\n$stackTrace'); + } + + return output.toString(); + } + + @override + List get props => [code, message, stackTrace]; +} diff --git a/packages/native_crypto_platform_interface/lib/src/implementations/basic_message_channel_native_crypto.dart b/packages/native_crypto_platform_interface/lib/src/implementations/basic_message_channel_native_crypto.dart new file mode 100644 index 0000000..993a000 --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/implementations/basic_message_channel_native_crypto.dart @@ -0,0 +1,204 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:flutter/foundation.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; +import 'package:native_crypto_platform_interface/src/pigeon/messages.pigeon.dart'; + +/// An implementation of [NativeCryptoPlatform] that uses Pigeon generated code. +class BasicMessageChannelNativeCrypto extends NativeCryptoPlatform { + /// The Pigeon API used to interact with the native platform. + @visibleForTesting + NativeCryptoAPI api = NativeCryptoAPI(); + + @override + Future hash(Uint8List data, {required String algorithm}) async { + try { + return api + .hash( + HashRequest( + data: data, + algorithm: algorithm, + ), + ) + .then((value) => value.hash); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future hmac( + Uint8List data, { + required Uint8List key, + required String algorithm, + }) async { + try { + return api + .hmac( + HmacRequest( + data: data, + key: key, + algorithm: algorithm, + ), + ) + .then((value) => value.hmac); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future generateSecureRandom(int length) async { + try { + return api + .generateSecureRandom( + GenerateSecureRandomRequest( + length: length, + ), + ) + .then((value) => value.random); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future pbkdf2({ + required Uint8List password, + required Uint8List salt, + required int length, + required int iterations, + required String hashAlgorithm, + }) async { + try { + return api + .pbkdf2( + Pbkdf2Request( + password: password, + salt: salt, + length: length, + iterations: iterations, + hashAlgorithm: hashAlgorithm, + ), + ) + .then((value) => value.key); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future encrypt( + Uint8List plainText, { + required Uint8List key, + required String algorithm, + }) async { + try { + return api + .encrypt( + EncryptRequest( + plainText: plainText, + key: key, + algorithm: algorithm, + ), + ) + .then((value) => value.cipherText); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future decrypt( + Uint8List cipherText, { + required Uint8List key, + required String algorithm, + }) async { + try { + return api + .decrypt( + DecryptRequest( + cipherText: cipherText, + key: key, + algorithm: algorithm, + ), + ) + .then((value) => value.plainText); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future encryptFile({ + required String plainTextPath, + required String cipherTextPath, + required Uint8List key, + required String algorithm, + }) async { + try { + return api + .encryptFile( + EncryptFileRequest( + plainTextPath: plainTextPath, + cipherTextPath: cipherTextPath, + key: key, + algorithm: algorithm, + ), + ) + .then((value) => value.success); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future decryptFile({ + required String cipherTextPath, + required String plainTextPath, + required Uint8List key, + required String algorithm, + }) async { + try { + return api + .decryptFile( + DecryptFileRequest( + cipherTextPath: cipherTextPath, + plainTextPath: plainTextPath, + key: key, + algorithm: algorithm, + ), + ) + .then((value) => value.success); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future encryptWithIV({ + required Uint8List plainText, + required Uint8List iv, + required Uint8List key, + required String algorithm, + }) async { + try { + return api + .encryptWithIV( + EncryptWithIVRequest( + plainText: plainText, + iv: iv, + key: key, + algorithm: algorithm, + ), + ) + .then((value) => value.cipherText); + } catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } +} diff --git a/packages/native_crypto_platform_interface/lib/src/implementations/method_channel_native_crypto.dart b/packages/native_crypto_platform_interface/lib/src/implementations/method_channel_native_crypto.dart new file mode 100644 index 0000000..d51f79e --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/implementations/method_channel_native_crypto.dart @@ -0,0 +1,161 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; + +/// An implementation of [NativeCryptoPlatform] that uses method channels. +class MethodChannelNativeCrypto extends NativeCryptoPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + MethodChannel channel = const MethodChannel('plugins.hugop.cl/native_crypto'); + + Future _invokeMethod( + NativeCryptoMethod method, [ + Map? arguments, + ]) async { + try { + return await channel.invokeMethod(method.name, arguments); + } on PlatformException catch (e, s) { + NativeCryptoException.convertPlatformException(e, s); + } + } + + @override + Future hash(Uint8List data, {required String algorithm}) => + _invokeMethod( + NativeCryptoMethod.hash, + { + 'data': data, + 'algorithm': algorithm, + }, + ); + + @override + Future hmac( + Uint8List data, { + required Uint8List key, + required String algorithm, + }) => + _invokeMethod( + NativeCryptoMethod.hmac, + { + 'data': data, + 'key': key, + 'algorithm': algorithm, + }, + ); + + @override + Future generateSecureRandom(int length) => + _invokeMethod( + NativeCryptoMethod.generateSecureRandom, + { + 'length': length, + }, + ); + + @override + Future pbkdf2({ + required Uint8List password, + required Uint8List salt, + required int length, + required int iterations, + required String hashAlgorithm, + }) => + _invokeMethod( + NativeCryptoMethod.pbkdf2, + { + 'password': password, + 'salt': salt, + 'length': length, + 'iterations': iterations, + 'hashAlgorithm': hashAlgorithm, + }, + ); + + @override + Future encrypt( + Uint8List plainText, { + required Uint8List key, + required String algorithm, + }) => + _invokeMethod( + NativeCryptoMethod.encrypt, + { + 'plainText': plainText, + 'key': key, + 'algorithm': algorithm, + }, + ); + + @override + Future decrypt( + Uint8List cipherText, { + required Uint8List key, + required String algorithm, + }) => + _invokeMethod( + NativeCryptoMethod.decrypt, + { + 'cipherText': cipherText, + 'key': key, + 'algorithm': algorithm, + }, + ); + + @override + Future encryptFile({ + required String plainTextPath, + required String cipherTextPath, + required Uint8List key, + required String algorithm, + }) => + _invokeMethod( + NativeCryptoMethod.encryptFile, + { + 'plainTextPath': plainTextPath, + 'cipherTextPath': cipherTextPath, + 'key': key, + 'algorithm': algorithm, + }, + ); + + @override + Future decryptFile({ + required String cipherTextPath, + required String plainTextPath, + required Uint8List key, + required String algorithm, + }) => + _invokeMethod( + NativeCryptoMethod.decryptFile, + { + 'cipherTextPath': cipherTextPath, + 'plainTextPath': plainTextPath, + 'key': key, + 'algorithm': algorithm, + }, + ); + + @override + Future encryptWithIV({ + required Uint8List plainText, + required Uint8List iv, + required Uint8List key, + required String algorithm, + }) => + _invokeMethod( + NativeCryptoMethod.encryptWithIV, + { + 'plainText': plainText, + 'iv': iv, + 'key': key, + 'algorithm': algorithm, + }, + ); +} diff --git a/packages/native_crypto_platform_interface/lib/src/interface/native_crypto_platform.dart b/packages/native_crypto_platform_interface/lib/src/interface/native_crypto_platform.dart new file mode 100644 index 0000000..6a953ad --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/interface/native_crypto_platform.dart @@ -0,0 +1,120 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:typed_data'; + +import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; +import 'package:native_crypto_platform_interface/src/implementations/method_channel_native_crypto.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +/// The interface that implementations of native_crypto must implement. +/// +/// Platform implementations should extend this class rather than implement +/// it as `NativeCrypto` does not consider newly added methods to be +/// breaking changes. Extending this class (using `extends`) ensures +/// that the subclass will get the default implementation, while platform +/// implementations that `implements` this interface will be +/// broken by newly added [NativeCryptoPlatform] methods. +abstract class NativeCryptoPlatform extends PlatformInterface { + /// Constructs a NativeCryptoPlatform. + NativeCryptoPlatform() : super(token: _token); + + static final Object _token = Object(); + + static NativeCryptoPlatform _instance = MethodChannelNativeCrypto(); + + /// The default instance of [NativeCryptoPlatform] to use. + /// + /// Defaults to [MethodChannelNativeCrypto]. + static NativeCryptoPlatform get instance => _instance; + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [NativeCryptoPlatform] when they register themselves. + static set instance(NativeCryptoPlatform instance) { + PlatformInterface.verify(instance, _token); + _instance = instance; + } + + /// Returns the hash of the given data. + Future hash(Uint8List data, {required String algorithm}) { + throw UnimplementedError('hash is not implemented'); + } + + /// Returns the hmac of the given data using the given key. + Future hmac( + Uint8List data, { + required Uint8List key, + required String algorithm, + }) { + throw UnimplementedError('hmac is not implemented'); + } + + /// Generates a secure random of the given length in bytes. + Future generateSecureRandom(int length) { + throw UnimplementedError('generateSecureRandom is not implemented'); + } + + /// Derives a key from the given password and salt using pbkdf2. + Future pbkdf2({ + required Uint8List password, + required Uint8List salt, + required int length, + required int iterations, + required String hashAlgorithm, + }) { + throw UnimplementedError('pbkdf2 is not implemented'); + } + + /// Encrypts the given data using the given key and algorithm. + Future encrypt( + Uint8List plainText, { + required Uint8List key, + required String algorithm, + }) { + throw UnimplementedError('encrypt is not implemented'); + } + + /// Decrypts the given data using the given key and algorithm. + Future decrypt( + Uint8List cipherText, { + required Uint8List key, + required String algorithm, + }) { + throw UnimplementedError('decrypt is not implemented'); + } + + /// Encrypts the given file using the given key and algorithm. + Future encryptFile({ + required String plainTextPath, + required String cipherTextPath, + required Uint8List key, + required String algorithm, + }) { + throw UnimplementedError('encryptFile is not implemented'); + } + + /// Decrypts the given file using the given key and algorithm. + Future decryptFile({ + required String cipherTextPath, + required String plainTextPath, + required Uint8List key, + required String algorithm, + }) { + throw UnimplementedError('decryptFile is not implemented'); + } + + /// Encrypts the given data using the given key, algorithm and iv. + /// + /// Users should use [encrypt] instead if they don't need to specify the iv. + Future encryptWithIV({ + required Uint8List plainText, + required Uint8List iv, + required Uint8List key, + required String algorithm, + }) { + throw UnimplementedError('encryptWithIV is not implemented'); + } +} diff --git a/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart b/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart deleted file mode 100644 index 0559ed4..0000000 --- a/packages/native_crypto_platform_interface/lib/src/method_channel/method_channel_native_crypto.dart +++ /dev/null @@ -1,154 +0,0 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: native_crypto_method_channel.dart -// Created Date: 25/12/2021 16:58:04 -// Last Modified: 25/05/2022 10:40:29 -// ----- -// Copyright (c) 2021 - -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart'; - -/// An implementation of [NativeCryptoPlatform] that uses method channels. -class MethodChannelNativeCrypto extends NativeCryptoPlatform { - /// The method channel used to interact with the native platform. - @visibleForTesting - MethodChannel channel = const MethodChannel('plugins.hugop.cl/native_crypto'); - - @override - Future digest(Uint8List data, String algorithm) async { - try { - return await channel.invokeMethod( - 'digest', - { - 'data': data, - 'algorithm': algorithm, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } - - @override - Future generateSecretKey(int bitsCount) async { - try { - return await channel.invokeMethod( - 'generateSecretKey', - { - 'bitsCount': bitsCount, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } - - @override - Future pbkdf2( - String password, - String salt, - int keyBytesCount, - int iterations, - String algorithm, - ) async { - try { - return await channel.invokeMethod( - 'pbkdf2', - { - 'password': password, - 'salt': salt, - 'keyBytesCount': keyBytesCount, - 'iterations': iterations, - 'algorithm': algorithm, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } - - @override - Future?> encryptAsList( - Uint8List data, - Uint8List key, - String algorithm, - ) async { - try { - return await channel.invokeListMethod( - 'encryptAsList', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } - - @override - Future decryptAsList( - List data, - Uint8List key, - String algorithm, - ) async { - try { - return await channel.invokeMethod( - 'decryptAsList', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } - - @override - Future encrypt( - Uint8List data, - Uint8List key, - String algorithm, - ) async { - try { - return await channel.invokeMethod( - 'encrypt', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } - - @override - Future decrypt( - Uint8List data, - Uint8List key, - String algorithm, - ) async { - try { - return await channel.invokeMethod( - 'decrypt', - { - 'data': data, - 'key': key, - 'algorithm': algorithm, - }, - ); - } catch (e, s) { - NativeCryptoException.convertPlatformException(e, s); - } - } -} diff --git a/packages/native_crypto_platform_interface/lib/src/pigeon/messages.pigeon.dart b/packages/native_crypto_platform_interface/lib/src/pigeon/messages.pigeon.dart new file mode 100644 index 0000000..7f8a4a4 --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/pigeon/messages.pigeon.dart @@ -0,0 +1,829 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. +// -- +// Autogenerated from Pigeon (v9.0.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +class HashRequest { + HashRequest({ + this.data, + this.algorithm, + }); + + Uint8List? data; + + String? algorithm; + + Object encode() { + return [ + data, + algorithm, + ]; + } + + static HashRequest decode(Object result) { + result as List; + return HashRequest( + data: result[0] as Uint8List?, + algorithm: result[1] as String?, + ); + } +} + +class HashResponse { + HashResponse({ + this.hash, + }); + + Uint8List? hash; + + Object encode() { + return [ + hash, + ]; + } + + static HashResponse decode(Object result) { + result as List; + return HashResponse( + hash: result[0] as Uint8List?, + ); + } +} + +class HmacRequest { + HmacRequest({ + this.data, + this.key, + this.algorithm, + }); + + Uint8List? data; + + Uint8List? key; + + String? algorithm; + + Object encode() { + return [ + data, + key, + algorithm, + ]; + } + + static HmacRequest decode(Object result) { + result as List; + return HmacRequest( + data: result[0] as Uint8List?, + key: result[1] as Uint8List?, + algorithm: result[2] as String?, + ); + } +} + +class HmacResponse { + HmacResponse({ + this.hmac, + }); + + Uint8List? hmac; + + Object encode() { + return [ + hmac, + ]; + } + + static HmacResponse decode(Object result) { + result as List; + return HmacResponse( + hmac: result[0] as Uint8List?, + ); + } +} + +class GenerateSecureRandomRequest { + GenerateSecureRandomRequest({ + this.length, + }); + + int? length; + + Object encode() { + return [ + length, + ]; + } + + static GenerateSecureRandomRequest decode(Object result) { + result as List; + return GenerateSecureRandomRequest( + length: result[0] as int?, + ); + } +} + +class GenerateSecureRandomResponse { + GenerateSecureRandomResponse({ + this.random, + }); + + Uint8List? random; + + Object encode() { + return [ + random, + ]; + } + + static GenerateSecureRandomResponse decode(Object result) { + result as List; + return GenerateSecureRandomResponse( + random: result[0] as Uint8List?, + ); + } +} + +class Pbkdf2Request { + Pbkdf2Request({ + this.password, + this.salt, + this.length, + this.iterations, + this.hashAlgorithm, + }); + + Uint8List? password; + + Uint8List? salt; + + int? length; + + int? iterations; + + String? hashAlgorithm; + + Object encode() { + return [ + password, + salt, + length, + iterations, + hashAlgorithm, + ]; + } + + static Pbkdf2Request decode(Object result) { + result as List; + return Pbkdf2Request( + password: result[0] as Uint8List?, + salt: result[1] as Uint8List?, + length: result[2] as int?, + iterations: result[3] as int?, + hashAlgorithm: result[4] as String?, + ); + } +} + +class Pbkdf2Response { + Pbkdf2Response({ + this.key, + }); + + Uint8List? key; + + Object encode() { + return [ + key, + ]; + } + + static Pbkdf2Response decode(Object result) { + result as List; + return Pbkdf2Response( + key: result[0] as Uint8List?, + ); + } +} + +class EncryptRequest { + EncryptRequest({ + this.plainText, + this.key, + this.algorithm, + }); + + Uint8List? plainText; + + Uint8List? key; + + String? algorithm; + + Object encode() { + return [ + plainText, + key, + algorithm, + ]; + } + + static EncryptRequest decode(Object result) { + result as List; + return EncryptRequest( + plainText: result[0] as Uint8List?, + key: result[1] as Uint8List?, + algorithm: result[2] as String?, + ); + } +} + +class EncryptResponse { + EncryptResponse({ + this.cipherText, + }); + + Uint8List? cipherText; + + Object encode() { + return [ + cipherText, + ]; + } + + static EncryptResponse decode(Object result) { + result as List; + return EncryptResponse( + cipherText: result[0] as Uint8List?, + ); + } +} + +class DecryptRequest { + DecryptRequest({ + this.cipherText, + this.key, + this.algorithm, + }); + + Uint8List? cipherText; + + Uint8List? key; + + String? algorithm; + + Object encode() { + return [ + cipherText, + key, + algorithm, + ]; + } + + static DecryptRequest decode(Object result) { + result as List; + return DecryptRequest( + cipherText: result[0] as Uint8List?, + key: result[1] as Uint8List?, + algorithm: result[2] as String?, + ); + } +} + +class DecryptResponse { + DecryptResponse({ + this.plainText, + }); + + Uint8List? plainText; + + Object encode() { + return [ + plainText, + ]; + } + + static DecryptResponse decode(Object result) { + result as List; + return DecryptResponse( + plainText: result[0] as Uint8List?, + ); + } +} + +class EncryptFileRequest { + EncryptFileRequest({ + this.plainTextPath, + this.cipherTextPath, + this.key, + this.algorithm, + }); + + String? plainTextPath; + + String? cipherTextPath; + + Uint8List? key; + + String? algorithm; + + Object encode() { + return [ + plainTextPath, + cipherTextPath, + key, + algorithm, + ]; + } + + static EncryptFileRequest decode(Object result) { + result as List; + return EncryptFileRequest( + plainTextPath: result[0] as String?, + cipherTextPath: result[1] as String?, + key: result[2] as Uint8List?, + algorithm: result[3] as String?, + ); + } +} + +class EncryptFileResponse { + EncryptFileResponse({ + this.success, + }); + + bool? success; + + Object encode() { + return [ + success, + ]; + } + + static EncryptFileResponse decode(Object result) { + result as List; + return EncryptFileResponse( + success: result[0] as bool?, + ); + } +} + +class DecryptFileRequest { + DecryptFileRequest({ + this.cipherTextPath, + this.plainTextPath, + this.key, + this.algorithm, + }); + + String? cipherTextPath; + + String? plainTextPath; + + Uint8List? key; + + String? algorithm; + + Object encode() { + return [ + cipherTextPath, + plainTextPath, + key, + algorithm, + ]; + } + + static DecryptFileRequest decode(Object result) { + result as List; + return DecryptFileRequest( + cipherTextPath: result[0] as String?, + plainTextPath: result[1] as String?, + key: result[2] as Uint8List?, + algorithm: result[3] as String?, + ); + } +} + +class DecryptFileResponse { + DecryptFileResponse({ + this.success, + }); + + bool? success; + + Object encode() { + return [ + success, + ]; + } + + static DecryptFileResponse decode(Object result) { + result as List; + return DecryptFileResponse( + success: result[0] as bool?, + ); + } +} + +class EncryptWithIVRequest { + EncryptWithIVRequest({ + this.plainText, + this.iv, + this.key, + this.algorithm, + }); + + Uint8List? plainText; + + Uint8List? iv; + + Uint8List? key; + + String? algorithm; + + Object encode() { + return [ + plainText, + iv, + key, + algorithm, + ]; + } + + static EncryptWithIVRequest decode(Object result) { + result as List; + return EncryptWithIVRequest( + plainText: result[0] as Uint8List?, + iv: result[1] as Uint8List?, + key: result[2] as Uint8List?, + algorithm: result[3] as String?, + ); + } +} + +class _NativeCryptoAPICodec extends StandardMessageCodec { + const _NativeCryptoAPICodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is DecryptFileRequest) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is DecryptFileResponse) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is DecryptRequest) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is DecryptResponse) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is EncryptFileRequest) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is EncryptFileResponse) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is EncryptRequest) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is EncryptResponse) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is EncryptWithIVRequest) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is GenerateSecureRandomRequest) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is GenerateSecureRandomResponse) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is HashRequest) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is HashResponse) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is HmacRequest) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is HmacResponse) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is Pbkdf2Request) { + buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is Pbkdf2Response) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return DecryptFileRequest.decode(readValue(buffer)!); + case 129: + return DecryptFileResponse.decode(readValue(buffer)!); + case 130: + return DecryptRequest.decode(readValue(buffer)!); + case 131: + return DecryptResponse.decode(readValue(buffer)!); + case 132: + return EncryptFileRequest.decode(readValue(buffer)!); + case 133: + return EncryptFileResponse.decode(readValue(buffer)!); + case 134: + return EncryptRequest.decode(readValue(buffer)!); + case 135: + return EncryptResponse.decode(readValue(buffer)!); + case 136: + return EncryptWithIVRequest.decode(readValue(buffer)!); + case 137: + return GenerateSecureRandomRequest.decode(readValue(buffer)!); + case 138: + return GenerateSecureRandomResponse.decode(readValue(buffer)!); + case 139: + return HashRequest.decode(readValue(buffer)!); + case 140: + return HashResponse.decode(readValue(buffer)!); + case 141: + return HmacRequest.decode(readValue(buffer)!); + case 142: + return HmacResponse.decode(readValue(buffer)!); + case 143: + return Pbkdf2Request.decode(readValue(buffer)!); + case 144: + return Pbkdf2Response.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class NativeCryptoAPI { + /// Constructor for [NativeCryptoAPI]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + NativeCryptoAPI({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _NativeCryptoAPICodec(); + + Future hash(HashRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.hash', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as HashResponse?)!; + } + } + + Future hmac(HmacRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.hmac', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as HmacResponse?)!; + } + } + + Future generateSecureRandom(GenerateSecureRandomRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.generateSecureRandom', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as GenerateSecureRandomResponse?)!; + } + } + + Future pbkdf2(Pbkdf2Request arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.pbkdf2', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as Pbkdf2Response?)!; + } + } + + Future encrypt(EncryptRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.encrypt', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as EncryptResponse?)!; + } + } + + Future decrypt(DecryptRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.decrypt', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as DecryptResponse?)!; + } + } + + Future encryptFile(EncryptFileRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.encryptFile', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as EncryptFileResponse?)!; + } + } + + Future decryptFile(DecryptFileRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.decryptFile', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as DecryptFileResponse?)!; + } + } + + Future encryptWithIV(EncryptWithIVRequest arg_request) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.encryptWithIV', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_request]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as EncryptResponse?)!; + } + } +} diff --git a/packages/native_crypto_platform_interface/lib/src/pigeon/test_api.dart b/packages/native_crypto_platform_interface/lib/src/pigeon/test_api.dart new file mode 100644 index 0000000..6687736 --- /dev/null +++ b/packages/native_crypto_platform_interface/lib/src/pigeon/test_api.dart @@ -0,0 +1,316 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. +// -- +// Autogenerated from Pigeon (v9.0.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import +// ignore_for_file: avoid_relative_lib_imports +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'messages.pigeon.dart'; + +class _TestNativeCryptoAPICodec extends StandardMessageCodec { + const _TestNativeCryptoAPICodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is DecryptFileRequest) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else if (value is DecryptFileResponse) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is DecryptRequest) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is DecryptResponse) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is EncryptFileRequest) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else if (value is EncryptFileResponse) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is EncryptRequest) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is EncryptResponse) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is EncryptWithIVRequest) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is GenerateSecureRandomRequest) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is GenerateSecureRandomResponse) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is HashRequest) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is HashResponse) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is HmacRequest) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is HmacResponse) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is Pbkdf2Request) { + buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is Pbkdf2Response) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return DecryptFileRequest.decode(readValue(buffer)!); + case 129: + return DecryptFileResponse.decode(readValue(buffer)!); + case 130: + return DecryptRequest.decode(readValue(buffer)!); + case 131: + return DecryptResponse.decode(readValue(buffer)!); + case 132: + return EncryptFileRequest.decode(readValue(buffer)!); + case 133: + return EncryptFileResponse.decode(readValue(buffer)!); + case 134: + return EncryptRequest.decode(readValue(buffer)!); + case 135: + return EncryptResponse.decode(readValue(buffer)!); + case 136: + return EncryptWithIVRequest.decode(readValue(buffer)!); + case 137: + return GenerateSecureRandomRequest.decode(readValue(buffer)!); + case 138: + return GenerateSecureRandomResponse.decode(readValue(buffer)!); + case 139: + return HashRequest.decode(readValue(buffer)!); + case 140: + return HashResponse.decode(readValue(buffer)!); + case 141: + return HmacRequest.decode(readValue(buffer)!); + case 142: + return HmacResponse.decode(readValue(buffer)!); + case 143: + return Pbkdf2Request.decode(readValue(buffer)!); + case 144: + return Pbkdf2Response.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class TestNativeCryptoAPI { + static const MessageCodec codec = _TestNativeCryptoAPICodec(); + + HashResponse hash(HashRequest request); + + HmacResponse hmac(HmacRequest request); + + GenerateSecureRandomResponse generateSecureRandom(GenerateSecureRandomRequest request); + + Pbkdf2Response pbkdf2(Pbkdf2Request request); + + EncryptResponse encrypt(EncryptRequest request); + + DecryptResponse decrypt(DecryptRequest request); + + EncryptFileResponse encryptFile(EncryptFileRequest request); + + DecryptFileResponse decryptFile(DecryptFileRequest request); + + EncryptResponse encryptWithIV(EncryptWithIVRequest request); + + static void setup(TestNativeCryptoAPI? api, {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.hash', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.hash was null.'); + final List args = (message as List?)!; + final HashRequest? arg_request = (args[0] as HashRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.hash was null, expected non-null HashRequest.'); + final HashResponse output = api.hash(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.hmac', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.hmac was null.'); + final List args = (message as List?)!; + final HmacRequest? arg_request = (args[0] as HmacRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.hmac was null, expected non-null HmacRequest.'); + final HmacResponse output = api.hmac(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.generateSecureRandom', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.generateSecureRandom was null.'); + final List args = (message as List?)!; + final GenerateSecureRandomRequest? arg_request = (args[0] as GenerateSecureRandomRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.generateSecureRandom was null, expected non-null GenerateSecureRandomRequest.'); + final GenerateSecureRandomResponse output = api.generateSecureRandom(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.pbkdf2', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.pbkdf2 was null.'); + final List args = (message as List?)!; + final Pbkdf2Request? arg_request = (args[0] as Pbkdf2Request?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.pbkdf2 was null, expected non-null Pbkdf2Request.'); + final Pbkdf2Response output = api.pbkdf2(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.encrypt', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.encrypt was null.'); + final List args = (message as List?)!; + final EncryptRequest? arg_request = (args[0] as EncryptRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.encrypt was null, expected non-null EncryptRequest.'); + final EncryptResponse output = api.encrypt(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.decrypt', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.decrypt was null.'); + final List args = (message as List?)!; + final DecryptRequest? arg_request = (args[0] as DecryptRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.decrypt was null, expected non-null DecryptRequest.'); + final DecryptResponse output = api.decrypt(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.encryptFile', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.encryptFile was null.'); + final List args = (message as List?)!; + final EncryptFileRequest? arg_request = (args[0] as EncryptFileRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.encryptFile was null, expected non-null EncryptFileRequest.'); + final EncryptFileResponse output = api.encryptFile(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.decryptFile', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.decryptFile was null.'); + final List args = (message as List?)!; + final DecryptFileRequest? arg_request = (args[0] as DecryptFileRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.decryptFile was null, expected non-null DecryptFileRequest.'); + final DecryptFileResponse output = api.decryptFile(arg_request!); + return [output]; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.NativeCryptoAPI.encryptWithIV', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.encryptWithIV was null.'); + final List args = (message as List?)!; + final EncryptWithIVRequest? arg_request = (args[0] as EncryptWithIVRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.NativeCryptoAPI.encryptWithIV was null, expected non-null EncryptWithIVRequest.'); + final EncryptResponse output = api.encryptWithIV(arg_request!); + return [output]; + }); + } + } + } +} diff --git a/packages/native_crypto_platform_interface/lib/src/platform_interface/native_crypto_platform.dart b/packages/native_crypto_platform_interface/lib/src/platform_interface/native_crypto_platform.dart deleted file mode 100644 index b09c0d3..0000000 --- a/packages/native_crypto_platform_interface/lib/src/platform_interface/native_crypto_platform.dart +++ /dev/null @@ -1,92 +0,0 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: native_crypto_platform_interface.dart -// Created Date: 25/12/2021 16:43:49 -// Last Modified: 25/05/2022 22:11:02 -// ----- -// Copyright (c) 2021 - -import 'dart:typed_data'; - -import 'package:native_crypto_platform_interface/src/method_channel/method_channel_native_crypto.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -/// The interface that implementations of path_provider must implement. -/// -/// Platform implementations should extend this class rather than implement -/// it as `NativeCrypto` does not consider newly added methods to be -/// breaking changes. Extending this class (using `extends`) ensures -/// that the subclass will get the default implementation, while platform -/// implementations that `implements` this interface will be -/// broken by newly added [NativeCryptoPlatform] methods. -abstract class NativeCryptoPlatform extends PlatformInterface { - /// Constructs a NativeCryptoPlatform. - NativeCryptoPlatform() : super(token: _token); - - static final Object _token = Object(); - - static NativeCryptoPlatform _instance = MethodChannelNativeCrypto(); - - /// The default instance of [NativeCryptoPlatform] to use. - /// - /// Defaults to [MethodChannelNativeCrypto]. - static NativeCryptoPlatform get instance => _instance; - - /// Platform-specific plugins should set this with their own platform-specific - /// class that extends [NativeCryptoPlatform] when they register themselves. - static set instance(NativeCryptoPlatform instance) { - PlatformInterface.verify(instance, _token); - _instance = instance; - } - - Future digest(Uint8List data, String algorithm) { - throw UnimplementedError('digest is not implemented'); - } - - Future generateSecretKey(int bitsCount) { - throw UnimplementedError('generateSecretKey is not implemented'); - } - - Future pbkdf2( - String password, - String salt, - int keyBytesCount, - int iterations, - String algorithm, - ) { - throw UnimplementedError('pbkdf2 is not implemented'); - } - - Future?> encryptAsList( - Uint8List data, - Uint8List key, - String algorithm, - ) { - throw UnimplementedError('encryptAsList is not implemented'); - } - - Future decryptAsList( - List data, - Uint8List key, - String algorithm, - ) { - throw UnimplementedError('decryptAsList is not implemented'); - } - - Future encrypt( - Uint8List data, - Uint8List key, - String algorithm, - ) { - throw UnimplementedError('encrypt is not implemented'); - } - - Future decrypt( - Uint8List data, - Uint8List key, - String algorithm, - ) { - throw UnimplementedError('decrypt is not implemented'); - } -} diff --git a/packages/native_crypto_platform_interface/lib/src/utils/exception.dart b/packages/native_crypto_platform_interface/lib/src/utils/exception.dart deleted file mode 100644 index b46bb4a..0000000 --- a/packages/native_crypto_platform_interface/lib/src/utils/exception.dart +++ /dev/null @@ -1,126 +0,0 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: exception.dart -// Created Date: 24/05/2022 18:54:48 -// Last Modified: 26/05/2022 20:36:04 -// ----- -// Copyright (c) 2022 - -// ignore_for_file: constant_identifier_names - -import 'dart:developer'; - -import 'package:flutter/services.dart'; - -enum NativeCryptoExceptionCode { - unknown, - not_implemented, - invalid_argument, - invalid_key, - invalid_key_length, - invalid_algorithm, - invalid_padding, - invalid_mode, - invalid_cipher, - invalid_data, - platform_not_supported, - platform_throws, - platform_returned_invalid_data, - platform_returned_empty_data, - platform_returned_null; - - String get code => toString().split('.').last.toLowerCase(); -} - -class NativeCryptoException implements Exception { - NativeCryptoException({ - this.message, - String? code, - this.stackTrace, - }) : code = code ?? NativeCryptoExceptionCode.unknown.code; - - /// The long form message of the exception. - final String? message; - - /// The optional code to accommodate the message. - final String code; - - /// The stack trace which provides information to the user about the call - /// sequence that triggered an exception - final StackTrace? stackTrace; - - @override - String toString() { - String output = '[NativeCryptoException/$code] $message'; - - if (stackTrace != null) { - output += '\n\n${stackTrace.toString()}'; - } - - return output; - } - - /// Catches a [PlatformException] and returns an [Exception]. - /// - /// If the [Exception] is a [PlatformException], - /// a [NativeCryptoException] is returned. - static Never convertPlatformException( - Object exception, - StackTrace stackTrace, - ) { - log(exception.toString()); - if (exception is! Exception || exception is! PlatformException) { - Error.throwWithStackTrace(exception, stackTrace); - } - - Error.throwWithStackTrace( - NativeCryptoException.fromPlatformException(exception, stackTrace), - stackTrace, - ); - } - - /// Converts a [PlatformException] into a [NativeCryptoException]. - /// - /// A [PlatformException] can only be converted to a [NativeCryptoException] - /// if the `details` of the exception exist. - factory NativeCryptoException.fromPlatformException( - PlatformException platformException, - StackTrace stackTrace, - ) { - final Map? details = platformException.details != null - ? Map.from( - platformException.details as Map, - ) - : null; - - String code = NativeCryptoExceptionCode.unknown.code; - String message = platformException.message ?? ''; - - if (details != null) { - code = details['code'] ?? code; - message = details['message'] ?? message; - } - - return NativeCryptoException( - message: message, - code: code, - stackTrace: stackTrace, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is NativeCryptoException && - other.message == message && - other.code == code && - other.stackTrace == stackTrace; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => message.hashCode ^ code.hashCode ^ stackTrace.hashCode; -} diff --git a/packages/native_crypto_platform_interface/pigeons/copyright_header.txt b/packages/native_crypto_platform_interface/pigeons/copyright_header.txt new file mode 100644 index 0000000..2701758 --- /dev/null +++ b/packages/native_crypto_platform_interface/pigeons/copyright_header.txt @@ -0,0 +1,6 @@ +Copyright 2019-2023 Hugo Pointcheval + +Use of this source code is governed by an MIT-style +license that can be found in the LICENSE file or at +https://opensource.org/licenses/MIT. +-- \ No newline at end of file diff --git a/packages/native_crypto_platform_interface/pigeons/messages.dart b/packages/native_crypto_platform_interface/pigeons/messages.dart new file mode 100644 index 0000000..e2802cd --- /dev/null +++ b/packages/native_crypto_platform_interface/pigeons/messages.dart @@ -0,0 +1,222 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + copyrightHeader: 'pigeons/copyright_header.txt', + dartOut: 'lib/src/pigeon/messages.pigeon.dart', + // We export in the lib folder to expose the class to other packages. + dartTestOut: 'lib/src/pigeon/test_api.dart', + javaOut: + '../native_crypto_android/android/src/main/java/fr/pointcheval/native_crypto_android/GeneratedAndroidNativeCrypto.java', + javaOptions: JavaOptions( + package: 'fr.pointcheval.native_crypto_android', + className: 'GeneratedAndroidNativeCrypto', + ), + objcHeaderOut: '../native_crypto_ios/ios/Classes/Public/messages.g.h', + objcSourceOut: '../native_crypto_ios/ios/Classes/messages.g.m', + ), +) +class HashRequest { + const HashRequest({ + this.data, + this.algorithm, + }); + + final Uint8List? data; + final String? algorithm; +} + +class HashResponse { + const HashResponse({ + this.hash, + }); + + final Uint8List? hash; +} + +class HmacRequest { + const HmacRequest({ + this.data, + this.key, + this.algorithm, + }); + + final Uint8List? data; + final Uint8List? key; + final String? algorithm; +} + +class HmacResponse { + const HmacResponse({ + this.hmac, + }); + + final Uint8List? hmac; +} + +class GenerateSecureRandomRequest { + const GenerateSecureRandomRequest({ + this.length, + }); + + final int? length; +} + +class GenerateSecureRandomResponse { + const GenerateSecureRandomResponse({ + this.random, + }); + + final Uint8List? random; +} + +class Pbkdf2Request { + const Pbkdf2Request({ + this.password, + this.salt, + this.length, + this.iterations, + this.hashAlgorithm, + }); + + final Uint8List? password; + final Uint8List? salt; + final int? length; + final int? iterations; + final String? hashAlgorithm; +} + +class Pbkdf2Response { + const Pbkdf2Response({ + this.key, + }); + + final Uint8List? key; +} + +class EncryptRequest { + const EncryptRequest({ + this.plainText, + this.key, + this.algorithm, + }); + + final Uint8List? plainText; + final Uint8List? key; + final String? algorithm; +} + +class EncryptResponse { + const EncryptResponse({ + this.cipherText, + }); + + final Uint8List? cipherText; +} + +class DecryptRequest { + const DecryptRequest({ + this.cipherText, + this.key, + this.algorithm, + }); + + final Uint8List? cipherText; + final Uint8List? key; + final String? algorithm; +} + +class DecryptResponse { + const DecryptResponse({ + this.plainText, + }); + + final Uint8List? plainText; +} + +class EncryptFileRequest { + const EncryptFileRequest({ + this.plainTextPath, + this.cipherTextPath, + this.key, + this.algorithm, + }); + + final String? plainTextPath; + final String? cipherTextPath; + final Uint8List? key; + final String? algorithm; +} + +class EncryptFileResponse { + const EncryptFileResponse({ + this.success, + }); + + final bool? success; +} + +class DecryptFileRequest { + const DecryptFileRequest({ + this.cipherTextPath, + this.plainTextPath, + this.key, + this.algorithm, + }); + + final String? cipherTextPath; + final String? plainTextPath; + final Uint8List? key; + final String? algorithm; +} + +class DecryptFileResponse { + const DecryptFileResponse({ + this.success, + }); + + final bool? success; +} + +class EncryptWithIVRequest { + const EncryptWithIVRequest({ + this.plainText, + this.iv, + this.key, + this.algorithm, + }); + + final Uint8List? plainText; + final Uint8List? iv; + final Uint8List? key; + final String? algorithm; +} + +@HostApi(dartHostTestHandler: 'TestNativeCryptoAPI') +abstract class NativeCryptoAPI { + HashResponse hash(HashRequest request); + HmacResponse hmac(HmacRequest request); + + GenerateSecureRandomResponse generateSecureRandom( + GenerateSecureRandomRequest request, + ); + + Pbkdf2Response pbkdf2(Pbkdf2Request request); + + EncryptResponse encrypt(EncryptRequest request); + + DecryptResponse decrypt(DecryptRequest request); + + EncryptFileResponse encryptFile(EncryptFileRequest request); + + DecryptFileResponse decryptFile(DecryptFileRequest request); + + EncryptResponse encryptWithIV(EncryptWithIVRequest request); +} diff --git a/packages/native_crypto_platform_interface/pubspec.yaml b/packages/native_crypto_platform_interface/pubspec.yaml index 21ec587..c3f9532 100644 --- a/packages/native_crypto_platform_interface/pubspec.yaml +++ b/packages/native_crypto_platform_interface/pubspec.yaml @@ -7,19 +7,19 @@ environment: flutter: ">=2.5.0" dependencies: - flutter: - sdk: flutter + equatable: ^2.0.5 + flutter: { sdk: flutter } plugin_platform_interface: ^2.1.3 dev_dependencies: - flutter_test: - sdk: flutter + flutter_test: { sdk: flutter } mockito: ^5.3.2 + pigeon: ^9.0.0 wyatt_analysis: hosted: url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ name: wyatt_analysis - version: 2.3.0 \ No newline at end of file + version: 2.4.0 diff --git a/packages/native_crypto_platform_interface/test/method_channel/method_channel_native_crypto_test.dart b/packages/native_crypto_platform_interface/test/method_channel/method_channel_native_crypto_test.dart deleted file mode 100644 index 28c01a1..0000000 --- a/packages/native_crypto_platform_interface/test/method_channel/method_channel_native_crypto_test.dart +++ /dev/null @@ -1,175 +0,0 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: method_channel_native_crypto_test.dart -// Created Date: 25/05/2022 22:47:41 -// Last Modified: 25/05/2022 23:22:44 -// ----- -// Copyright (c) 2022 - -import 'dart:typed_data'; - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:native_crypto_platform_interface/src/method_channel/method_channel_native_crypto.dart'; - -void main() { - TestWidgetsFlutterBinding - .ensureInitialized(); // Required for setMockMethodCallHandler - - group('$MethodChannelNativeCrypto', () { - const MethodChannel channel = - MethodChannel('plugins.hugop.cl/native_crypto'); - final List log = []; - final MethodChannelNativeCrypto nativeCrypto = MethodChannelNativeCrypto(); - - TestDefaultBinaryMessengerBinding.instance?.defaultBinaryMessenger - .setMockMethodCallHandler(channel, (MethodCall call) async { - log.add(call); - return null; - }); - - // Run after each test. - tearDown(log.clear); - - test('digest', () async { - await nativeCrypto.digest(Uint8List(0), 'sha256'); - expect( - log, - [ - isMethodCall( - 'digest', - arguments: { - 'data': Uint8List(0), - 'algorithm': 'sha256', - }, - ), - ], - ); - }); - - test('generateSecretKey', () async { - await nativeCrypto.generateSecretKey(256); - expect( - log, - [ - isMethodCall( - 'generateSecretKey', - arguments: { - 'bitsCount': 256, - }, - ), - ], - ); - }); - - test('pbkdf2', () async { - await nativeCrypto.pbkdf2( - 'password', - 'salt', - 32, - 10000, - 'sha256', - ); - expect( - log, - [ - isMethodCall( - 'pbkdf2', - arguments: { - 'password': 'password', - 'salt': 'salt', - 'keyBytesCount': 32, - 'iterations': 10000, - 'algorithm': 'sha256', - }, - ), - ], - ); - }); - - test('encryptAsList', () async { - await nativeCrypto.encryptAsList( - Uint8List(0), - Uint8List(0), - 'aes', - ); - expect( - log, - [ - isMethodCall( - 'encryptAsList', - arguments: { - 'data': Uint8List(0), - 'key': Uint8List(0), - 'algorithm': 'aes', - }, - ), - ], - ); - }); - - test('decryptAsList', () async { - await nativeCrypto.decryptAsList( - [Uint8List(0)], - Uint8List(0), - 'aes', - ); - expect( - log, - [ - isMethodCall( - 'decryptAsList', - arguments: { - 'data': [Uint8List(0)], - 'key': Uint8List(0), - 'algorithm': 'aes', - }, - ), - ], - ); - }); - - test('encrypt', () async { - await nativeCrypto.encrypt( - Uint8List(0), - Uint8List(0), - 'aes', - ); - expect( - log, - [ - isMethodCall( - 'encrypt', - arguments: { - 'data': Uint8List(0), - 'key': Uint8List(0), - 'algorithm': 'aes', - }, - ), - ], - ); - }); - - test('decrypt', () async { - await nativeCrypto.decrypt( - Uint8List(0), - Uint8List(0), - 'aes', - ); - expect( - log, - [ - isMethodCall( - 'decrypt', - arguments: { - 'data': Uint8List(0), - 'key': Uint8List(0), - 'algorithm': 'aes', - }, - ), - ], - ); - }); - }); -} diff --git a/packages/native_crypto_platform_interface/test/native_crypto_exception_test.dart b/packages/native_crypto_platform_interface/test/native_crypto_exception_test.dart new file mode 100644 index 0000000..0e8cbb0 --- /dev/null +++ b/packages/native_crypto_platform_interface/test/native_crypto_exception_test.dart @@ -0,0 +1,72 @@ +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:native_crypto_platform_interface/src/core/enums/exception_code.dart'; +import 'package:native_crypto_platform_interface/src/core/exceptions/exception.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('$NativeCryptoException', () { + test('should return a formatted message with only code', () async { + const e = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + ); + + expect(e.toString(), '[NativeCrypto/unknown_error]'); + }); + + test('should return a formatted message', () async { + const e = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + message: 'foo', + ); + + expect(e.toString(), '[NativeCrypto/unknown_error] foo'); + }); + + test('should return a formatted message with a stack trace', () async { + const e = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + message: 'foo', + ); + + expect(e.toString(), '[NativeCrypto/unknown_error] foo'); + }); + + test('should return a formatted message with a stack trace', () async { + final e = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + message: 'foo', + stackTrace: StackTrace.current, + ); + + // Anything with a stack trace adds 2 blanks lines following the message. + expect(e.toString(), startsWith('[NativeCrypto/unknown_error] foo\n\n')); + }); + + test('should override the == operator', () async { + const e1 = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + message: 'foo', + ); + + const e2 = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + message: 'foo', + ); + + const e3 = NativeCryptoException( + code: NativeCryptoExceptionCode.unknownError, + message: 'foo', + ); + + expect(e1 == e2, true); + expect(e1 != e3, false); + }); + }); +} diff --git a/packages/native_crypto_platform_interface/test/platform_interface/native_crypto_platform_test.dart b/packages/native_crypto_platform_interface/test/platform_interface/native_crypto_platform_test.dart index acd0f9d..8c1c890 100644 --- a/packages/native_crypto_platform_interface/test/platform_interface/native_crypto_platform_test.dart +++ b/packages/native_crypto_platform_interface/test/platform_interface/native_crypto_platform_test.dart @@ -1,43 +1,42 @@ -// Author: Hugo Pointcheval -// Email: git@pcl.ovh -// ----- -// File: native_crypto_platform_test.dart -// Created Date: 25/05/2022 21:43:25 -// Last Modified: 25/05/2022 23:26:18 -// ----- -// Copyright (c) 2022 +// Copyright 2019-2023 Hugo Pointcheval +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. -import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:native_crypto_platform_interface/src/platform_interface/native_crypto_platform.dart'; +import 'package:native_crypto_platform_interface/src/implementations/basic_message_channel_native_crypto.dart'; +import 'package:native_crypto_platform_interface/src/implementations/method_channel_native_crypto.dart'; +import 'package:native_crypto_platform_interface/src/interface/native_crypto_platform.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +class ImplementsNativeCryptoPlatform + // ignore: prefer_mixin + with Mock + implements NativeCryptoPlatform {} + +class ExtendsNativeCryptoPlatform extends NativeCryptoPlatform {} + +class NativeCryptoMockPlatform extends Mock + with + // ignore: prefer_mixin, plugin_platform_interface needs to migrate to use `mixin` + MockPlatformInterfaceMixin + implements + NativeCryptoPlatform {} + void main() { - late ExtendsNativeCryptoPlatform nativeCryptoPlatform; + TestWidgetsFlutterBinding.ensureInitialized(); group('$NativeCryptoPlatform', () { - setUpAll(() { - nativeCryptoPlatform = ExtendsNativeCryptoPlatform(); - }); - test('Constructor', () { - expect(nativeCryptoPlatform, isA()); - expect(nativeCryptoPlatform, isA()); + // should allow read of default app from native + test('$MethodChannelNativeCrypto is the default instance', () { + expect(NativeCryptoPlatform.instance, isA()); }); - test('get.instance', () { - expect( - NativeCryptoPlatform.instance, - isA(), - ); - }); - test('set.instance', () { + test('Can be extended', () { NativeCryptoPlatform.instance = ExtendsNativeCryptoPlatform(); - expect( - NativeCryptoPlatform.instance, - isA(), - ); }); test('Cannot be implemented with `implements`', () { @@ -45,122 +44,19 @@ void main() { () { NativeCryptoPlatform.instance = ImplementsNativeCryptoPlatform(); }, - throwsA(isInstanceOf()), + throwsA(anything), ); }); test('Can be mocked with `implements`', () { - final MockNativeCryptoPlatform mock = MockNativeCryptoPlatform(); + final NativeCryptoMockPlatform mock = NativeCryptoMockPlatform(); NativeCryptoPlatform.instance = mock; }); - test('Can be extended', () { - NativeCryptoPlatform.instance = ExtendsNativeCryptoPlatform(); - }); - - test('throws if .digest() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform.digest(Uint8List(0), 'sha256'), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'digest is not implemented', - ), - ), - ); - }); - - test('throws if .generateSecretKey() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform.generateSecretKey(256), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'generateSecretKey is not implemented', - ), - ), - ); - }); - - test('throws if .pbkdf2() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform.pbkdf2('password', 'salt', 0, 0, 'sha256'), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'pbkdf2 is not implemented', - ), - ), - ); - }); - - test('throws if .encryptAsList() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform.encryptAsList( - Uint8List(0), - Uint8List(0), - 'aes', - ), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'encryptAsList is not implemented', - ), - ), - ); - }); - - test('throws if .decryptAsList() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform - .decryptAsList([Uint8List(0)], Uint8List(0), 'aes'), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'decryptAsList is not implemented', - ), - ), - ); - }); - - test('throws if .encrypt() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform.encrypt(Uint8List(0), Uint8List(0), 'aes'), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'encrypt is not implemented', - ), - ), - ); - }); - - test('throws if .decrypt() not implemented', () async { - await expectLater( - () => nativeCryptoPlatform.decrypt(Uint8List(0), Uint8List(0), 'aes'), - throwsA( - isA().having( - (e) => e.message, - 'message', - 'decrypt is not implemented', - ), - ), - ); + test('Can set with $BasicMessageChannelNativeCrypto', () { + final BasicMessageChannelNativeCrypto pigeon = + BasicMessageChannelNativeCrypto(); + NativeCryptoPlatform.instance = pigeon; }); }); } - -class ExtendsNativeCryptoPlatform extends NativeCryptoPlatform {} - -class ImplementsNativeCryptoPlatform extends Mock - implements NativeCryptoPlatform {} - -class MockNativeCryptoPlatform extends Mock - with MockPlatformInterfaceMixin - implements NativeCryptoPlatform {}