Skip to content

Commit

Permalink
Merge branch 'master' into backend
Browse files Browse the repository at this point in the history
  • Loading branch information
ueman committed Sep 25, 2024
2 parents 4592ee2 + 03bb0e9 commit 9abddff
Show file tree
Hide file tree
Showing 23 changed files with 384 additions and 176 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

This repo contains various packages to deal with PkPass files.

| Package | Description | Pub.dev | Version |
|----------------------------------|------------------------------------------------------------------------|----------------------------------------|----------------------------------------------------------------------------------------------------------|
| [`app`](app) | App which makes use of the various libraries. Android only. | | |
| [`apple_passkit`](apple_passkit) | Package to interface with the native functionality on iOS | https://pub.dev/packages/apple_passkit | [![pub package](https://img.shields.io/pub/v/apple_passkit.svg)](https://pub.dev/packages/apple_passkit) |
| [`passkit`](passkit) | Pure Dart package to read PkPass files. Can be used on server side too | https://pub.dev/packages/passkit | [![pub package](https://img.shields.io/pub/v/passkit.svg)](https://pub.dev/packages/passkit) |
| [`passkit_ui`](passkit_ui) | Pure Flutter package to show PkPass files. Makes use of `passkit` | https://pub.dev/packages/passkit_ui | [![pub package](https://img.shields.io/pub/v/passkit_ui.svg)](https://pub.dev/packages/passkit_ui) |
| Package | Description | Version | Likes | Popularity | Points |
|----------------------------------|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| [`app`](app) | App which makes use of the various libraries. Android only. | | | | |
| [`apple_passkit`](apple_passkit) | Package to interface with the native functionality on iOS | [![pub package](https://img.shields.io/pub/v/apple_passkit.svg)](https://pub.dev/packages/apple_passkit) | [![likes](https://img.shields.io/pub/likes/apple_passkit)](https://pub.dev/packages/apple_passkit/score) | [![popularity](https://img.shields.io/pub/popularity/apple_passkit)](https://pub.dev/packages/apple_passkit/score) | [![pub points](https://img.shields.io/pub/points/apple_passkit)](https://pub.dev/packages/apple_passkit/score) |
| [`passkit`](passkit) | Pure Dart package to read PkPass files. Can be used on server side too | [![pub package](https://img.shields.io/pub/v/passkit.svg)](https://pub.dev/packages/passkit) | [![likes](https://img.shields.io/pub/likes/passkit)](https://pub.dev/packages/passkit/score) | [![popularity](https://img.shields.io/pub/popularity/passkit)](https://pub.dev/packages/passkit/score) | [![pub points](https://img.shields.io/pub/points/passkit)](https://pub.dev/packages/passkit/score) |
| [`passkit_ui`](passkit_ui) | Pure Flutter package to show PkPass files. Makes use of `passkit` | [![pub package](https://img.shields.io/pub/v/passkit_ui.svg)](https://pub.dev/packages/passkit_ui) | [![likes](https://img.shields.io/pub/likes/passkit_ui)](https://pub.dev/packages/passkit_ui/score) | [![popularity](https://img.shields.io/pub/popularity/passkit_ui)](https://pub.dev/packages/passkit_ui/score) | [![pub points](https://img.shields.io/pub/points/passkit_ui)](https://pub.dev/packages/passkit_ui/score) |
2 changes: 1 addition & 1 deletion app/lib/import_pass/import_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class _ImportPassPageState extends State<ImportPassPage> {
await db.passEntryDao.insertPassEntry(
PassEntry(
id: pass!.pass.serialNumber,
pass: Uint8List.fromList(pass!.sourceData),
pass: pass!.sourceData!,
description: pass!.pass.description,
),
);
Expand Down
8 changes: 3 additions & 5 deletions app/lib/pass_backside/pass_backside_page.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';

import 'package:app/db/db.dart';
import 'package:app/db/pass_entry.dart';
Expand All @@ -17,10 +16,10 @@ import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:geocoding/geocoding.dart' as geocoding;
import 'package:passkit/passkit.dart';
import 'package:passkit_ui/passkit_ui.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:path/path.dart' as p;

class PassBackSidePageArgs {
PassBackSidePageArgs(this.pass, this.showDelete);
Expand Down Expand Up @@ -49,7 +48,6 @@ class PassBacksidePage extends StatefulWidget {
PassType.eventTicket => pass.pass.eventTicket?.backFields,
PassType.generic => pass.pass.generic?.backFields,
PassType.storeCard => pass.pass.storeCard?.backFields,
PassType.unknown => null,
};
}
}
Expand Down Expand Up @@ -229,15 +227,15 @@ class _PassBacksidePageState extends State<PassBacksidePage> {
PassEntry(
id: updatedPass.pass.serialNumber,
description: updatedPass.pass.description,
pass: Uint8List.fromList(updatedPass.sourceData),
pass: updatedPass.sourceData!,
),
);

unawaited(passListNotifier.loadPasses());
}

void _sharePass() {
final data = Uint8List.fromList(widget.pass.sourceData);
final data = widget.pass.sourceData!;
Share.shareXFiles([XFile.fromData(data)]);
}

Expand Down
4 changes: 4 additions & 0 deletions passkit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased

- Make it possible to override the bundled Apple WWDR G4 certificate

## 0.0.7

- The library is now able to create properly signed `pkpass` files that work with Apple Wallet.
Expand Down
34 changes: 17 additions & 17 deletions passkit/lib/passkit.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
library;

export 'src/apple_wwdr_certificate.dart';
export 'src/order/order_address.dart';
export 'src/order/order_application.dart';
export 'src/order/order_barcode.dart';
export 'src/order/order_customer.dart';
export 'src/order/order_data.dart';
export 'src/order/order_line_item.dart';
export 'src/order/order_location.dart';
export 'src/order/order_merchant.dart';
export 'src/order/order_payment.dart';
export 'src/order/order_pickup_fulfillment.dart';
export 'src/order/order_provider.dart';
export 'src/order/order_return.dart';
export 'src/order/order_return_info.dart';
export 'src/order/order_shipping_fulfillment.dart';
export 'src/order/pk_order.dart';
export 'src/pk_image.dart';
export 'src/pkpass/barcode.dart';
export 'src/pkpass/beacon.dart';
export 'src/pkpass/field_dict.dart';
Expand All @@ -10,27 +27,10 @@ export 'src/pkpass/pass_data.dart';
export 'src/pkpass/pass_structure.dart';
export 'src/pkpass/pass_type.dart';
export 'src/pkpass/personalization.dart';
export 'src/pkpass/pk_pass_image.dart';
export 'src/pkpass/pkpass.dart';
export 'src/pkpass/semantic_tag_type.dart';
export 'src/pkpass/semantics.dart';
export 'src/pkpass_webservice/passkit_web_client.dart';
export 'src/pkpass_webservice/passkit_web_client_exceptions.dart';
export 'src/pkpass_webservice/personalization_dictionary.dart';
export 'src/pkpass_webservice/serial_numbers.dart';

export 'src/order/order_address.dart';
export 'src/order/order_application.dart';
export 'src/order/order_barcode.dart';
export 'src/order/order_customer.dart';
export 'src/order/order_data.dart';
export 'src/order/order_line_item.dart';
export 'src/order/order_location.dart';
export 'src/order/order_merchant.dart';
export 'src/order/order_payment.dart';
export 'src/order/order_pickup_fulfillment.dart';
export 'src/order/order_provider.dart';
export 'src/order/order_return.dart';
export 'src/order/order_return_info.dart';
export 'src/order/order_shipping_fulfillment.dart';
export 'src/order/pk_order.dart';
12 changes: 11 additions & 1 deletion passkit/lib/src/apple_wwdr_certificate.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import 'dart:typed_data';

import 'package:meta/meta.dart';
import 'package:pkcs7/pkcs7.dart';

X509 get wwdrG4 =>
/// This is the content of https://www.apple.com/certificateauthority/AppleWWDRCAG4.cer
///
/// You can override this property to use a different certificate. Make sure to
/// override it before reading or creating any PkPass or Order files.
///
/// You can find other certificates at:
/// - https://developer.apple.com/help/account/reference/wwdr-intermediate-certificates/
/// - https://www.apple.com/certificateauthority/
X509 wwdrG4 =
X509.fromDer(Uint8List.fromList(worldwide_Developer_Relations_G4));

/// This is the content of https://www.apple.com/certificateauthority/AppleWWDRCAG4.cer .
Expand All @@ -12,6 +21,7 @@ X509 get wwdrG4 =>
/// More info at:
/// https://developer.apple.com/help/account/reference/wwdr-intermediate-certificates/
/// https://www.apple.com/certificateauthority/
@internal
// ignore: constant_identifier_names, non_constant_identifier_names
final worldwide_Developer_Relations_G4 = Uint8List.fromList([
48,
Expand Down
29 changes: 19 additions & 10 deletions passkit/lib/src/archive_extensions.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import 'dart:convert';
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/pk_image.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';

/// Dart uses a special fast decoder when using a fused [Utf8Decoder] and [JsonDecoder].
/// This speeds up decoding.
/// See
/// - https://api.dart.dev/stable/3.4.4/dart-convert/Utf8Decoder-class.html
/// - https://github.com/dart-lang/sdk/blob/5b2ea0c7a227d91c691d2ff8cbbeb5f7f86afdb9/sdk/lib/_internal/vm/lib/convert_patch.dart#L40
final _utf8JsonDecoder = const Utf8Decoder().fuse(const JsonDecoder());
import 'package:passkit/src/utils.dart';

extension ArchiveX on Archive {
Uint8List? findBytesForFile(String fileName) =>
Expand All @@ -24,7 +17,7 @@ extension ArchiveX on Archive {
if (bytes == null) {
return null;
}
return _utf8JsonDecoder.convert(bytes) as Map<String, dynamic>?;
return utf8JsonDecode(bytes);
}

PkImage? loadImage(String name) {
Expand Down Expand Up @@ -89,4 +82,20 @@ extension ArchiveX on Archive {
}
}
}

Uint8List createManifest() {
final manifest = <String, String>{};
for (final file in files) {
manifest[file.name] = sha1.convert(file.binaryContent).toString();
}

final manifestContent = utf8JsonEncode(manifest);
final manifestFile = ArchiveFile(
'manifest.json',
manifestContent.length,
manifestContent,
);
addFile(manifestFile);
return Uint8List.fromList(manifestContent);
}
}
14 changes: 14 additions & 0 deletions passkit/lib/src/certificate_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:collection/collection.dart';
import 'package:pkcs7/pkcs7.dart';

extension CertX on X509 {
/// Matches the pass type identifer for PkPass and the merchant identifier for
/// orders
String? get identifier =>
subject.firstWhereOrNull((it) => it.key.name == 'UID')?.value as String?;

/// Matches the team identifier
String? get teamIdentifier => subject
.firstWhereOrNull((it) => it.key.name == 'organizationalUnitName')
?.value as String?;
}
4 changes: 2 additions & 2 deletions passkit/lib/src/order/pk_order.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class PkOrder {
});

/// Parses bytes to a [PkOrder] instance.
/// Setting [skipVerification] to true disables any checksum or signature
/// verification and validation.
/// Setting [skipChecksumVerification] and [skipSignatureVerification] to true
/// disables checksum or signature verification and validation.
// TODO(ueman): Provide an async method for this.
static PkOrder fromBytes(
final Uint8List bytes, {
Expand Down
File renamed without changes.
5 changes: 3 additions & 2 deletions passkit/lib/src/pkpass/field_dict.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ class FieldDict {
@JsonKey(name: 'timeStyle')
final DateStyle? timeStyle;

/// The style of the number to display in the field. Formatter styles have the same meaning as the formats with corresponding names in NumberFormatter.Style.
/// Possible Values: PKNumberStyleDecimal, PKNumberStylePercent, PKNumberStyleScientific, PKNumberStyleSpellOut
/// The style of the number to display in the field. Formatter styles have the
/// same meaning as the formats with corresponding names in
/// NumberFormatter.Style.
@JsonKey(name: 'numberStyle')
final NumberStyle? numberStyle;

Expand Down
57 changes: 55 additions & 2 deletions passkit/lib/src/pkpass/pass_data.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:csslib/parser.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:passkit/src/certificate_extension.dart';
import 'package:passkit/src/pkpass/barcode.dart';
import 'package:passkit/src/pkpass/beacon.dart';
import 'package:passkit/src/pkpass/location.dart';
import 'package:passkit/src/pkpass/nfc.dart';
import 'package:passkit/src/pkpass/parse_utils.dart';
import 'package:passkit/src/pkpass/pass_structure.dart';
import 'package:passkit/src/pkpass/semantics.dart';
import 'package:pkcs7/pkcs7.dart';

part 'pass_data.g.dart';

@JsonSerializable(includeIfNull: false)
class PassData {
PassData({
required this.description,
required this.formatVersion,
required this.organizationName,
required this.passTypeIdentifier,
required this.serialNumber,
required this.teamIdentifier,
this.formatVersion = 1,
this.appLaunchURL,
this.associatedStoreIdentifiers,
this.userInfo,
Expand Down Expand Up @@ -49,6 +51,47 @@ class PassData {
this.semantics,
});

/// Sets the [teamIdentifier] and [passTypeIdentifier] from a certificate pem
/// file. Otherwise, it's identical to the default constructor.
PassData.fromCertificate({
required this.description,
required this.organizationName,
required this.serialNumber,
required String certificatePem,
this.formatVersion = 1,
this.appLaunchURL,
this.associatedStoreIdentifiers,
this.userInfo,
this.expirationDate,
this.voided,
this.beacons,
this.locations,
this.maxDistance,
this.relevantDate,
this.boardingPass,
this.coupon,
this.eventTicket,
this.generic,
this.storeCard,
this.barcode,
this.barcodes,
this.backgroundColor,
this.foregroundColor,
this.groupingIdentifier,
this.labelColor,
this.logoText,
this.suppressStripShine,
this.sharingProhibited,
this.authenticationToken,
this.webServiceURL,
this.nfc,
this.semantics,
}) :
// It's kinda stupid to parse it twice, but it works.
// TODO(any): Make this more performant
teamIdentifier = X509.fromPem(certificatePem).teamIdentifier!,
passTypeIdentifier = X509.fromPem(certificatePem).identifier!;

factory PassData.fromJson(Map<String, dynamic> json) =>
_$PassDataFromJson(json);

Expand Down Expand Up @@ -181,7 +224,7 @@ class PassData {

/// Optional. Information specific to the pass’s barcode. For this
/// dictionary’s keys, see Barcode Dictionary Keys.
/// Note:Deprecated in iOS 9.0 and later; use barcodes instead.
/// Note: Deprecated in iOS 9.0 and later; use barcodes instead.
@JsonKey(name: 'barcode')
final Barcode? barcode;

Expand Down Expand Up @@ -340,4 +383,14 @@ class PassData {
semantics: semantics ?? this.semantics,
);
}

/// Overrides the current [passTypeIdentifier] and [teamIdentifier] with
/// the IDs from the certificate PEM file.
PassData copyWithFieldsFromCertificate(String certificatePem) {
final issuer = X509.fromPem(certificatePem);
return copyWith(
passTypeIdentifier: issuer.identifier,
teamIdentifier: issuer.teamIdentifier,
);
}
}
1 change: 0 additions & 1 deletion passkit/lib/src/pkpass/pass_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ enum PassType {
eventTicket,
storeCard,
generic,
unknown,
}
Loading

0 comments on commit 9abddff

Please sign in to comment.