From 1a7a61d257685a6f541c121973bf810d034de4a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Uek=C3=B6tter?= Date: Sun, 15 Sep 2024 13:39:48 +0200 Subject: [PATCH] Use Uint8Lists --- app/lib/import_pass/import_page.dart | 2 +- passkit/lib/src/apple_wwdr_certificate.dart | 6 +-- passkit/lib/src/archive_extensions.dart | 21 ++++----- passkit/lib/src/archive_file_extension.dart | 7 +++ passkit/lib/src/order/pk_order.dart | 11 +++-- passkit/lib/src/pkpass/pkpass.dart | 45 ++++++++----------- passkit/lib/src/signature_verification.dart | 5 ++- .../naive_strings_file_parser.dart | 3 +- 8 files changed, 48 insertions(+), 52 deletions(-) create mode 100644 passkit/lib/src/archive_file_extension.dart diff --git a/app/lib/import_pass/import_page.dart b/app/lib/import_pass/import_page.dart index 4e385d1..099233a 100644 --- a/app/lib/import_pass/import_page.dart +++ b/app/lib/import_pass/import_page.dart @@ -22,7 +22,7 @@ class PkPassImportSource { final String? contentResolverPath; final String? filePath; - final List? bytes; + final Uint8List? bytes; Future getPass() async { if (contentResolverPath != null) { diff --git a/passkit/lib/src/apple_wwdr_certificate.dart b/passkit/lib/src/apple_wwdr_certificate.dart index 129d8e4..10f8eb8 100644 --- a/passkit/lib/src/apple_wwdr_certificate.dart +++ b/passkit/lib/src/apple_wwdr_certificate.dart @@ -12,8 +12,8 @@ X509 get wwdrG4 => /// More info at: /// https://developer.apple.com/help/account/reference/wwdr-intermediate-certificates/ /// https://www.apple.com/certificateauthority/ -// ignore: constant_identifier_names -const worldwide_Developer_Relations_G4 = [ +// ignore: constant_identifier_names, non_constant_identifier_names +final worldwide_Developer_Relations_G4 = Uint8List.fromList([ 48, 130, 4, @@ -1127,4 +1127,4 @@ const worldwide_Developer_Relations_G4 = [ 207, 242, 159, -]; +]); diff --git a/passkit/lib/src/archive_extensions.dart b/passkit/lib/src/archive_extensions.dart index 2ff0e6a..a69f7cd 100644 --- a/passkit/lib/src/archive_extensions.dart +++ b/passkit/lib/src/archive_extensions.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:archive/archive.dart'; import 'package:crypto/crypto.dart'; +import 'package:passkit/src/archive_file_extension.dart'; import 'package:passkit/src/pkpass/exceptions.dart'; import 'package:passkit/src/pkpass/pk_pass_image.dart'; import 'package:passkit/src/strings_parser/naive_strings_file_parser.dart'; @@ -15,13 +16,8 @@ import 'package:passkit/src/strings_parser/naive_strings_file_parser.dart'; final _utf8JsonDecoder = const Utf8Decoder().fuse(const JsonDecoder()); extension ArchiveX on Archive { - List? findBytesForFile(String fileName) => - findFile(fileName)?.content as List?; - - Uint8List? findUint8ListForFile(String fileName) { - final data = findBytesForFile(fileName); - return data == null ? null : Uint8List.fromList(data); - } + Uint8List? findBytesForFile(String fileName) => + findFile(fileName)?.binaryContent; Map? findFileAndReadAsJson(String fileName) { final bytes = findBytesForFile(fileName); @@ -33,9 +29,9 @@ extension ArchiveX on Archive { PkImage? loadImage(String name) { return PkImage.fromImages( - image1: findUint8ListForFile('$name.png'), - image2: findUint8ListForFile('$name@2.png'), - image3: findUint8ListForFile('$name@3.png'), + image1: findBytesForFile('$name.png'), + image2: findBytesForFile('$name@2.png'), + image3: findBytesForFile('$name@3.png'), ); } @@ -52,8 +48,7 @@ extension ArchiveX on Archive { for (final languageFile in translationFiles) { final language = languageFile.name.split('.').first; - languageData[language] = - parseStringsFile(languageFile.content as List); + languageData[language] = parseStringsFile(languageFile.binaryContent); } return languageData; } @@ -88,7 +83,7 @@ extension ArchiveX on Archive { for (final file in filesWithoutSignatureAndManifest) { final checksumInManifest = manifest[file.name] as String?; - final digest = sha1.convert(file.content as List); + final digest = sha1.convert(file.binaryContent); if (checksumInManifest != digest.toString()) { throw ChecksumMismatchException(file.name); } diff --git a/passkit/lib/src/archive_file_extension.dart b/passkit/lib/src/archive_file_extension.dart new file mode 100644 index 0000000..38d0a8d --- /dev/null +++ b/passkit/lib/src/archive_file_extension.dart @@ -0,0 +1,7 @@ +import 'dart:typed_data'; + +import 'package:archive/archive.dart'; + +extension ArchiveFileX on ArchiveFile { + Uint8List get binaryContent => Uint8List.fromList(content as List); +} diff --git a/passkit/lib/src/order/pk_order.dart b/passkit/lib/src/order/pk_order.dart index f43a648..79cd64f 100644 --- a/passkit/lib/src/order/pk_order.dart +++ b/passkit/lib/src/order/pk_order.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:archive/archive.dart'; import 'package:passkit/src/archive_extensions.dart'; +import 'package:passkit/src/archive_file_extension.dart'; import 'package:passkit/src/pkpass/exceptions.dart'; import 'package:passkit/src/signature_verification.dart'; @@ -20,7 +21,7 @@ class PkOrder { /// verification and validation. // TODO(ueman): Provide an async method for this. static PkOrder fromBytes( - final List bytes, { + final Uint8List bytes, { bool skipChecksumVerification = false, bool skipSignatureVerification = false, }) { @@ -38,10 +39,8 @@ class PkOrder { if (skipSignatureVerification) { final manifestContent = - archive.findFile('manifest.json')!.content as List; - final signatureContent = Uint8List.fromList( - archive.findFile('signature')!.content as List, - ); + archive.findFile('manifest.json')!.binaryContent; + final signatureContent = archive.findFile('signature')!.binaryContent; verifySignature( signatureBytes: signatureContent, @@ -77,7 +76,7 @@ class PkOrder { final Map>? languageData; /// The bytes of this PkPass - final List sourceData; + final Uint8List sourceData; /// Indicates whether a webservices is available. bool get isWebServiceAvailable => order.webServiceURL != null; diff --git a/passkit/lib/src/pkpass/pkpass.dart b/passkit/lib/src/pkpass/pkpass.dart index 1860c41..873cb0b 100644 --- a/passkit/lib/src/pkpass/pkpass.dart +++ b/passkit/lib/src/pkpass/pkpass.dart @@ -5,6 +5,7 @@ import 'package:archive/archive.dart'; import 'package:crypto/crypto.dart'; import 'package:meta/meta.dart'; import 'package:passkit/src/apple_wwdr_certificate.dart'; +import 'package:passkit/src/archive_file_extension.dart'; import 'package:passkit/src/pkpass/exceptions.dart'; import 'package:passkit/src/pkpass/pass_data.dart'; import 'package:passkit/src/pkpass/pass_type.dart'; @@ -27,7 +28,7 @@ import 'package:passkit/src/strings_parser/naive_strings_file_parser.dart'; /// a PR: https://github.com/ueman/passkit/issues/74 typedef SignatureBuilder = Uint8List Function( String manifest, - List wwdrCertificate, + Uint8List wwdrCertificate, ); /// Dart uses a special fast decoder when using a fused [Utf8Decoder] and [JsonDecoder]. @@ -82,7 +83,7 @@ class PkPass { /// certificate. // TODO(any): Provide an async method for this. static PkPass fromBytes( - final List bytes, { + final Uint8List bytes, { bool skipChecksumVerification = false, bool skipSignatureVerification = false, }) { @@ -99,10 +100,8 @@ class PkPass { archive.checkSha1Checksums(manifest); if (!skipSignatureVerification) { final manifestContent = - archive.findFile('manifest.json')!.content as List; - final signatureContent = Uint8List.fromList( - archive.findFile('signature')!.content as List, - ); + archive.findFile('manifest.json')!.binaryContent; + final signatureContent = archive.findFile('signature')!.binaryContent; verifySignature( signatureBytes: signatureContent, @@ -148,7 +147,7 @@ class PkPass { // gracefully fall back to just parsing the PkPass file. // TODO(ueman): Provide an async method for this. static List passesFromBytes( - final List bytes, { + final Uint8List bytes, { bool skipChecksumVerification = false, bool skipSignatureVerification = false, }) { @@ -162,7 +161,7 @@ class PkPass { return pkPasses .map( (file) => fromBytes( - file.content as List, + file.binaryContent, skipChecksumVerification: skipChecksumVerification, skipSignatureVerification: skipSignatureVerification, ), @@ -243,7 +242,7 @@ class PkPass { final Map>? languageData; /// The bytes of this PkPass - final List sourceData; + final Uint8List sourceData; /// Indicates whether a webservices is available. bool get isWebServiceAvailable => pass.webServiceURL != null; @@ -301,7 +300,7 @@ class PkPass { final manifest = {}; for (final file in archive.files) { - manifest[file.name] = sha1.convert(file.content as List).toString(); + manifest[file.name] = sha1.convert(file.binaryContent).toString(); } final manifestContent = encoder.convert(manifest); @@ -332,13 +331,8 @@ class PkPass { // This is intentionally not exposed to keep this an implementation detail. // Tests should be written against the PkPass class directly. extension on Archive { - List? findBytesForFile(String fileName) => - findFile(fileName)?.content as List?; - - Uint8List? findUint8ListForFile(String fileName) { - final data = findBytesForFile(fileName); - return data == null ? null : Uint8List.fromList(data); - } + Uint8List? findBytesForFile(String fileName) => + findFile(fileName)?.binaryContent; /// Returns a map of locale to a map of resolution to image bytes. /// Returns null, if no image is localized @@ -367,11 +361,11 @@ extension on Archive { } if (fileName.endsWith('@2x.png')) { - map[language]![2] = Uint8List.fromList(file.content as List); + map[language]![2] = file.binaryContent; } else if (fileName.endsWith('@3x.png')) { - map[language]![3] = Uint8List.fromList(file.content as List); + map[language]![3] = file.binaryContent; } else { - map[language]![1] = Uint8List.fromList(file.content as List); + map[language]![1] = file.binaryContent; } } @@ -395,9 +389,9 @@ extension on Archive { PkImage? loadImage(String name) { return PkImage.fromImages( - image1: findUint8ListForFile('$name.png'), - image2: findUint8ListForFile('$name@2x.png'), - image3: findUint8ListForFile('$name@3x.png'), + image1: findBytesForFile('$name.png'), + image2: findBytesForFile('$name@2x.png'), + image3: findBytesForFile('$name@3x.png'), localizedImages: loadLocalizedImage(name), ); } @@ -415,8 +409,7 @@ extension on Archive { for (final languageFile in translationFiles) { final language = languageFile.name.split('.').first; - languageData[language] = - parseStringsFile(languageFile.content as List); + languageData[language] = parseStringsFile(languageFile.binaryContent); } return languageData; } @@ -468,7 +461,7 @@ extension on Archive { for (final file in filesWithoutSignatureAndManifest) { final checksumInManifest = manifest[file.name] as String?; - final digest = sha1.convert(file.content as List); + final digest = sha1.convert(file.binaryContent); if (checksumInManifest != digest.toString()) { throw ChecksumMismatchException(file.name); } diff --git a/passkit/lib/src/signature_verification.dart b/passkit/lib/src/signature_verification.dart index bad8288..7e3f41a 100644 --- a/passkit/lib/src/signature_verification.dart +++ b/passkit/lib/src/signature_verification.dart @@ -1,9 +1,10 @@ import 'dart:typed_data'; + +import 'package:collection/collection.dart'; import 'package:crypto/crypto.dart'; import 'package:passkit/src/apple_wwdr_certificate.dart'; import 'package:passkit/src/pkpass/exceptions.dart'; import 'package:pkcs7/pkcs7.dart'; -import 'package:collection/collection.dart'; /// [identifier] corresponds to the `passTypeIdentifier` in PkPasses or the /// `orderTypeIdentifier` for PkOrders. @@ -17,7 +18,7 @@ import 'package:collection/collection.dart'; // as long as the contents match? bool verifySignature({ required Uint8List signatureBytes, - required List manifestBytes, + required Uint8List manifestBytes, required String identifier, required String teamIdentifier, DateTime? now, diff --git a/passkit/lib/src/strings_parser/naive_strings_file_parser.dart b/passkit/lib/src/strings_parser/naive_strings_file_parser.dart index e2f27bc..5dfa999 100644 --- a/passkit/lib/src/strings_parser/naive_strings_file_parser.dart +++ b/passkit/lib/src/strings_parser/naive_strings_file_parser.dart @@ -1,8 +1,9 @@ import 'dart:convert'; +import 'dart:typed_data'; /// Parses [content] to a [Map] which contains the /// key-value-pairs for translations. -Map parseStringsFile(List content) { +Map parseStringsFile(Uint8List content) { final string = _stringsFileDecoder.convert(content); return naiveStringsFileParser(string); }