From d8227ab961401e2baceab500c43ed7d7b3e769a4 Mon Sep 17 00:00:00 2001 From: Adel HB Date: Sun, 8 Mar 2026 20:13:49 +0100 Subject: [PATCH] Small fixes to increase pub.dev score --- ios/m_security/Package.swift | 22 ++++++ .../Sources/m_security/PrivacyInfo.xcprivacy | 14 ++++ .../Sources/m_security/dummy_file.c | 1 + lib/m_security.dart | 2 +- lib/src/compression/compression_service.dart | 61 +++++++++------- lib/src/encryption/aes_gcm.dart | 9 ++- lib/src/encryption/chacha20.dart | 9 ++- lib/src/evfs/vault_service.dart | 12 ++-- lib/src/hashing/argon2.dart | 14 ++-- lib/src/kdf/hkdf.dart | 14 ++-- lib/src/streaming/streaming_service.dart | 70 ++++++++++--------- macos/m_security/Package.swift | 22 ++++++ .../Sources/m_security/PrivacyInfo.xcprivacy | 12 ++++ .../Sources/m_security/dummy_file.c | 1 + pubspec.yaml | 6 +- 15 files changed, 174 insertions(+), 95 deletions(-) create mode 100644 ios/m_security/Package.swift create mode 100644 ios/m_security/Sources/m_security/PrivacyInfo.xcprivacy create mode 100644 ios/m_security/Sources/m_security/dummy_file.c create mode 100644 macos/m_security/Package.swift create mode 100644 macos/m_security/Sources/m_security/PrivacyInfo.xcprivacy create mode 100644 macos/m_security/Sources/m_security/dummy_file.c diff --git a/ios/m_security/Package.swift b/ios/m_security/Package.swift new file mode 100644 index 0000000..a07a36e --- /dev/null +++ b/ios/m_security/Package.swift @@ -0,0 +1,22 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "m_security", + platforms: [ + .iOS("11.0") + ], + products: [ + .library(name: "m-security", targets: ["m_security"]) + ], + dependencies: [], + targets: [ + .target( + name: "m_security", + dependencies: [], + resources: [ + .process("PrivacyInfo.xcprivacy") + ] + ) + ] +) diff --git a/ios/m_security/Sources/m_security/PrivacyInfo.xcprivacy b/ios/m_security/Sources/m_security/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..a34b7e2 --- /dev/null +++ b/ios/m_security/Sources/m_security/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/ios/m_security/Sources/m_security/dummy_file.c b/ios/m_security/Sources/m_security/dummy_file.c new file mode 100644 index 0000000..4ffd1b2 --- /dev/null +++ b/ios/m_security/Sources/m_security/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to satisfy Swift Package Manager requirements. diff --git a/lib/m_security.dart b/lib/m_security.dart index 95e2de1..c30df3c 100644 --- a/lib/m_security.dart +++ b/lib/m_security.dart @@ -5,4 +5,4 @@ export 'src/kdf/hkdf.dart'; export 'src/rust/frb_generated.dart' show RustLib; export 'src/streaming/streaming_service.dart'; export 'src/compression/compression_service.dart'; -export 'src/evfs/vault_service.dart'; \ No newline at end of file +export 'src/evfs/vault_service.dart'; diff --git a/lib/src/compression/compression_service.dart b/lib/src/compression/compression_service.dart index aee6ed7..f1534d3 100644 --- a/lib/src/compression/compression_service.dart +++ b/lib/src/compression/compression_service.dart @@ -22,12 +22,14 @@ class CompressionService { algorithm: CompressionAlgorithm.zstd, ), }) { - return _guardedStream(() => rust_streaming.streamCompressEncryptFile( - cipher: cipher, - compression: config, - inputPath: inputPath, - outputPath: outputPath, - )); + return _guardedStream( + () => rust_streaming.streamCompressEncryptFile( + cipher: cipher, + compression: config, + inputPath: inputPath, + outputPath: outputPath, + ), + ); } /// Decrypt then decompress a file. @@ -37,31 +39,36 @@ class CompressionService { required String outputPath, required rust_encryption.CipherHandle cipher, }) { - return _guardedStream(() => rust_streaming.streamDecryptDecompressFile( - cipher: cipher, - inputPath: inputPath, - outputPath: outputPath, - )); + return _guardedStream( + () => rust_streaming.streamDecryptDecompressFile( + cipher: cipher, + inputPath: inputPath, + outputPath: outputPath, + ), + ); } static Stream _guardedStream(Stream Function() factory) { final controller = StreamController(); - runZonedGuarded(() { - factory().listen( - controller.add, - onError: controller.addError, - onDone: () { - Future(() { - if (!controller.isClosed) controller.close(); - }); - }, - ); - }, (error, stack) { - if (!controller.isClosed) { - controller.addError(error, stack); - controller.close(); - } - }); + runZonedGuarded( + () { + factory().listen( + controller.add, + onError: controller.addError, + onDone: () { + Future(() { + if (!controller.isClosed) controller.close(); + }); + }, + ); + }, + (error, stack) { + if (!controller.isClosed) { + controller.addError(error, stack); + controller.close(); + } + }, + ); return controller.stream; } } diff --git a/lib/src/encryption/aes_gcm.dart b/lib/src/encryption/aes_gcm.dart index 1c6f9e5..de1567b 100644 --- a/lib/src/encryption/aes_gcm.dart +++ b/lib/src/encryption/aes_gcm.dart @@ -3,7 +3,6 @@ import 'dart:typed_data'; import 'package:m_security/src/rust/api/encryption.dart' as rust_encryption; class AesGcmService { - rust_encryption.CipherHandle? _cipher; Future initWithRandomKey() async { @@ -14,7 +13,9 @@ class AesGcmService { Future encrypt(Uint8List data) async { final cipher = _cipher; if (cipher == null) { - throw StateError('Cipher not initialized. Call initWithRandomKey() first.'); + throw StateError( + 'Cipher not initialized. Call initWithRandomKey() first.', + ); } return rust_encryption.encrypt( @@ -27,7 +28,9 @@ class AesGcmService { Future decrypt(Uint8List encrypted) async { final cipher = _cipher; if (cipher == null) { - throw StateError('Cipher not initialized. Call initWithRandomKey() first.'); + throw StateError( + 'Cipher not initialized. Call initWithRandomKey() first.', + ); } return rust_encryption.decrypt( diff --git a/lib/src/encryption/chacha20.dart b/lib/src/encryption/chacha20.dart index 8b521ed..a683915 100644 --- a/lib/src/encryption/chacha20.dart +++ b/lib/src/encryption/chacha20.dart @@ -3,7 +3,6 @@ import 'dart:typed_data'; import 'package:m_security/src/rust/api/encryption.dart' as rust_encryption; class Chacha20Service { - rust_encryption.CipherHandle? _cipher; Future initWithRandomKey() async { @@ -14,7 +13,9 @@ class Chacha20Service { Future encrypt(Uint8List plaintext, {Uint8List? aad}) async { final cipher = _cipher; if (cipher == null) { - throw StateError('Cipher not initialized. Call initWithRandomKey() first.'); + throw StateError( + 'Cipher not initialized. Call initWithRandomKey() first.', + ); } return rust_encryption.encrypt( @@ -27,7 +28,9 @@ class Chacha20Service { Future decrypt(Uint8List ciphertext, {Uint8List? aad}) async { final cipher = _cipher; if (cipher == null) { - throw StateError('Cipher not initialized. Call initWithRandomKey() first.'); + throw StateError( + 'Cipher not initialized. Call initWithRandomKey() first.', + ); } return rust_encryption.decrypt( diff --git a/lib/src/evfs/vault_service.dart b/lib/src/evfs/vault_service.dart index 768ff16..01fef04 100644 --- a/lib/src/evfs/vault_service.dart +++ b/lib/src/evfs/vault_service.dart @@ -33,7 +33,7 @@ class VaultService { }) { return rust_evfs.vaultOpen(path: path, key: key); } - + /// Write (or overwrite) a named segment. /// /// [compression] is optional — defaults to no compression. @@ -70,9 +70,7 @@ class VaultService { } /// List all segment names. - static Future> list({ - required rust_evfs.VaultHandle handle, - }) { + static Future> list({required rust_evfs.VaultHandle handle}) { return rust_evfs.vaultList(handle: handle); } @@ -84,9 +82,7 @@ class VaultService { } /// Close the vault (release lock, zeroize keys). - static Future close({ - required rust_evfs.VaultHandle handle, - }) { + static Future close({required rust_evfs.VaultHandle handle}) { return rust_evfs.vaultClose(handle: handle); } -} \ No newline at end of file +} diff --git a/lib/src/hashing/argon2.dart b/lib/src/hashing/argon2.dart index 29e168b..5c29a46 100644 --- a/lib/src/hashing/argon2.dart +++ b/lib/src/hashing/argon2.dart @@ -8,8 +8,9 @@ export '../rust/api/hashing/argon2.dart' show Argon2Preset; // Compile-time flag: pass -DIS_DESKTOP=true for desktop/server builds const bool _isDesktop = bool.fromEnvironment('IS_DESKTOP'); -const ffi.Argon2Preset _defaultPreset = - _isDesktop ? ffi.Argon2Preset.desktop : ffi.Argon2Preset.mobile; +const ffi.Argon2Preset _defaultPreset = _isDesktop + ? ffi.Argon2Preset.desktop + : ffi.Argon2Preset.mobile; /// Hash a password using Argon2id. /// @@ -18,8 +19,7 @@ const ffi.Argon2Preset _defaultPreset = Future argon2IdHash({ required String password, ffi.Argon2Preset preset = _defaultPreset, -}) => - ffi.argon2IdHash(password: password, preset: preset); +}) => ffi.argon2IdHash(password: password, preset: preset); /// Hash a password using Argon2id with an explicit salt. /// @@ -28,12 +28,10 @@ Future argon2IdHashWithSalt({ required String password, required String salt, ffi.Argon2Preset preset = _defaultPreset, -}) => - ffi.argon2IdHashWithSalt(password: password, salt: salt, preset: preset); +}) => ffi.argon2IdHashWithSalt(password: password, salt: salt, preset: preset); /// Verify a password against an Argon2id PHC hash string. Future argon2IdVerify({ required String phcHash, required String password, -}) => - ffi.argon2IdVerify(phcHash: phcHash, password: password); +}) => ffi.argon2IdVerify(phcHash: phcHash, password: password); diff --git a/lib/src/kdf/hkdf.dart b/lib/src/kdf/hkdf.dart index 995341f..479af61 100644 --- a/lib/src/kdf/hkdf.dart +++ b/lib/src/kdf/hkdf.dart @@ -26,14 +26,8 @@ class MHKDF { /// Performs HKDF-Extract. /// Produces a pseudorandom key (PRK) from input key material. - static Uint8List extract({ - required Uint8List ikm, - Uint8List? salt, - }) { - return rust_hkdf.hkdfExtract( - ikm: ikm, - salt: salt ?? Uint8List(0), - ); + static Uint8List extract({required Uint8List ikm, Uint8List? salt}) { + return rust_hkdf.hkdfExtract(ikm: ikm, salt: salt ?? Uint8List(0)); } /// Performs HKDF-Expand. @@ -58,7 +52,9 @@ class MHKDF { // SHA-256 HKDF max: 255 * 32 = 8160 if (outputLen > 8160) { throw ArgumentError.value( - outputLen, 'outputLen', 'must be <= 8160 bytes (RFC 5869 limit for SHA-256)', + outputLen, + 'outputLen', + 'must be <= 8160 bytes (RFC 5869 limit for SHA-256)', ); } } diff --git a/lib/src/streaming/streaming_service.dart b/lib/src/streaming/streaming_service.dart index b92b2bc..211ae52 100644 --- a/lib/src/streaming/streaming_service.dart +++ b/lib/src/streaming/streaming_service.dart @@ -18,11 +18,13 @@ class StreamingService { required String outputPath, required rust_encryption.CipherHandle cipher, }) { - return _guardedStream(() => rust_streaming.streamEncryptFile( - cipher: cipher, - inputPath: inputPath, - outputPath: outputPath, - )); + return _guardedStream( + () => rust_streaming.streamEncryptFile( + cipher: cipher, + inputPath: inputPath, + outputPath: outputPath, + ), + ); } /// Decrypt a streaming-encrypted file. @@ -32,11 +34,13 @@ class StreamingService { required String outputPath, required rust_encryption.CipherHandle cipher, }) { - return _guardedStream(() => rust_streaming.streamDecryptFile( - cipher: cipher, - inputPath: inputPath, - outputPath: outputPath, - )); + return _guardedStream( + () => rust_streaming.streamDecryptFile( + cipher: cipher, + inputPath: inputPath, + outputPath: outputPath, + ), + ); } /// Hash a file without loading it into memory. @@ -45,10 +49,9 @@ class StreamingService { required String filePath, required rust_hashing.HasherHandle hasher, }) async { - await _guardedStream(() => rust_streaming.streamHashFile( - hasher: hasher, - filePath: filePath, - )).drain(); + await _guardedStream( + () => rust_streaming.streamHashFile(hasher: hasher, filePath: filePath), + ).drain(); return await rust_hashing.hasherFinalize(handle: hasher); } @@ -58,24 +61,27 @@ class StreamingService { // closing the controller to let the zone handler forward it first. static Stream _guardedStream(Stream Function() factory) { final controller = StreamController(); - runZonedGuarded(() { - factory().listen( - controller.add, - onError: controller.addError, - onDone: () { - // FRB delivers errors after the stream closes — schedule close - // in the event loop so pending microtasks (zone errors) run first. - Future(() { - if (!controller.isClosed) controller.close(); - }); - }, - ); - }, (error, stack) { - if (!controller.isClosed) { - controller.addError(error, stack); - controller.close(); - } - }); + runZonedGuarded( + () { + factory().listen( + controller.add, + onError: controller.addError, + onDone: () { + // FRB delivers errors after the stream closes — schedule close + // in the event loop so pending microtasks (zone errors) run first. + Future(() { + if (!controller.isClosed) controller.close(); + }); + }, + ); + }, + (error, stack) { + if (!controller.isClosed) { + controller.addError(error, stack); + controller.close(); + } + }, + ); return controller.stream; } } diff --git a/macos/m_security/Package.swift b/macos/m_security/Package.swift new file mode 100644 index 0000000..c37e6f2 --- /dev/null +++ b/macos/m_security/Package.swift @@ -0,0 +1,22 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "m_security", + platforms: [ + .macOS("10.11") + ], + products: [ + .library(name: "m-security", targets: ["m_security"]) + ], + dependencies: [], + targets: [ + .target( + name: "m_security", + dependencies: [], + resources: [ + .process("PrivacyInfo.xcprivacy") + ] + ) + ] +) diff --git a/macos/m_security/Sources/m_security/PrivacyInfo.xcprivacy b/macos/m_security/Sources/m_security/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..918d80b --- /dev/null +++ b/macos/m_security/Sources/m_security/PrivacyInfo.xcprivacy @@ -0,0 +1,12 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/macos/m_security/Sources/m_security/dummy_file.c b/macos/m_security/Sources/m_security/dummy_file.c new file mode 100644 index 0000000..4ffd1b2 --- /dev/null +++ b/macos/m_security/Sources/m_security/dummy_file.c @@ -0,0 +1 @@ +// This is an empty file to satisfy Swift Package Manager requirements. diff --git a/pubspec.yaml b/pubspec.yaml index 3aef3a7..73ea98a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,9 +1,7 @@ name: m_security description: >- - A high-performance cryptographic SDK for Flutter powered by native Rust via FFI. - Provides authenticated encryption (AES-256-GCM, ChaCha20-Poly1305), modern hashing - (BLAKE3, SHA-3, Argon2id), key derivation (HKDF), streaming encryption with compression - (Zstd, Brotli), and an encrypted virtual file system (EVFS). + A native Rust cryptographic SDK for Flutter via FFI. AES-256-GCM, ChaCha20-Poly1305, + BLAKE3, SHA-3, Argon2id, HKDF, streaming encryption, and encrypted virtual file system. version: 0.3.0 homepage: https://github.com/MicroClub-USTHB/M-Security repository: https://github.com/MicroClub-USTHB/M-Security