mirror of
https://gitlab.com/TheOneWithTheBraid/dart_pkpass.git
synced 2025-07-05 12:58:47 +00:00
114 lines
3.3 KiB
Dart
114 lines
3.3 KiB
Dart
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:archive/archive.dart';
|
|
import 'package:crypto/crypto.dart';
|
|
import 'package:intl/locale.dart';
|
|
|
|
import 'package:pkpass/pkpass.dart';
|
|
import 'package:pkpass/src/file_matcher.dart';
|
|
|
|
final _utf8codec = Utf8Codec();
|
|
final _jsonCodec = JsonCodec();
|
|
|
|
class PassFile {
|
|
PassFile(this.metadata, this._folder);
|
|
|
|
static Future<PassFile> parse(Uint8List pass) async {
|
|
final codec = ZipDecoder();
|
|
Archive archive;
|
|
try {
|
|
archive = codec.decodeBytes(pass);
|
|
} catch (e) {
|
|
throw InvalidEncodingError();
|
|
}
|
|
|
|
Map<String, String> manifest;
|
|
|
|
try {
|
|
final file = archive.files
|
|
.singleWhere((element) => element.name == 'manifest.json');
|
|
manifest = (_jsonCodec.decode(
|
|
_utf8codec.decode(
|
|
file.rawContent?.toUint8List() ?? (file.content as Uint8List),
|
|
),
|
|
) as Map)
|
|
.cast<String, String>();
|
|
} catch (e) {
|
|
throw ManifestNotFoundError();
|
|
}
|
|
|
|
final folder = <ArchiveFile>[];
|
|
|
|
await Future.wait(
|
|
manifest.entries.map(
|
|
(manifestEntry) async {
|
|
final file = archive.files
|
|
.singleWhere((element) => element.name == manifestEntry.key);
|
|
|
|
final content =
|
|
file.rawContent?.toUint8List() ?? file.content as Uint8List;
|
|
|
|
String hash = sha1.convert(content).toString();
|
|
|
|
final checksum = manifestEntry.value;
|
|
|
|
if (hash != checksum) {
|
|
throw ManifestChecksumError(expected: checksum, actual: hash);
|
|
}
|
|
|
|
folder.add(file);
|
|
},
|
|
),
|
|
);
|
|
|
|
final passFile =
|
|
archive.singleWhere((element) => element.name == 'pass.json');
|
|
|
|
final PassMetadata metadata = PassMetadata.fromJson(
|
|
_jsonCodec.decode(passFile.stringContent) as Map<String, Object?>,
|
|
);
|
|
|
|
return PassFile(metadata, folder);
|
|
}
|
|
|
|
final PassMetadata metadata;
|
|
|
|
final List<ArchiveFile> _folder;
|
|
|
|
Uint8List? _matchUtf8List({
|
|
required String name,
|
|
required Locale? locale,
|
|
required int scale,
|
|
}) {
|
|
final files = _folder.map((e) => e.name).toList();
|
|
final path = FileMatcher.matchFile(
|
|
files: files,
|
|
name: name,
|
|
scale: scale,
|
|
locale: locale,
|
|
);
|
|
if (path == null) return null;
|
|
final file = _folder.singleWhere((element) => element.name == path);
|
|
final content = file.rawContent?.toUint8List() ?? file.content as Uint8List;
|
|
return content;
|
|
}
|
|
|
|
Uint8List? getBackground({Locale? locale, int scale = 1}) =>
|
|
_matchUtf8List(name: 'background', locale: locale, scale: scale);
|
|
Uint8List? getFooter({Locale? locale, int scale = 1}) =>
|
|
_matchUtf8List(name: 'footer', locale: locale, scale: scale);
|
|
Uint8List? getIcon({Locale? locale, int scale = 1}) =>
|
|
_matchUtf8List(name: 'icon', locale: locale, scale: scale);
|
|
Uint8List? getLogo({Locale? locale, int scale = 1}) =>
|
|
_matchUtf8List(name: 'logo', locale: locale, scale: scale);
|
|
Uint8List? getStrip({Locale? locale, int scale = 1}) =>
|
|
_matchUtf8List(name: 'strip', locale: locale, scale: scale);
|
|
Uint8List? getThumbnail({Locale? locale, int scale = 1}) =>
|
|
_matchUtf8List(name: 'thumbnail', locale: locale, scale: scale);
|
|
}
|
|
|
|
extension on ArchiveFile {
|
|
String get stringContent =>
|
|
_utf8codec.decode(rawContent?.toUint8List() ?? (content as Uint8List));
|
|
}
|