Skip to content

Commit

Permalink
Merge pull request #1 from iamEtornam/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
iamEtornam committed Mar 24, 2024
2 parents fd682e0 + 175febc commit 247625f
Show file tree
Hide file tree
Showing 15 changed files with 608 additions and 83 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Expand Up @@ -31,4 +31,4 @@ jobs:
- run: flutter pub get

- name: Flutter test
run: flutter test --no-sound-null-safety
run: flutter test
4 changes: 2 additions & 2 deletions example/android/app/build.gradle
Expand Up @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 32
compileSdkVersion 33

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand All @@ -40,7 +40,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.mrtdeg"
minSdkVersion 21
targetSdkVersion 32
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
5 changes: 3 additions & 2 deletions example/android/build.gradle
@@ -1,5 +1,6 @@
buildscript {
ext.kotlin_version = '1.6.10'
//ext.kotlin_version = '1.6.21'
ext.kotlin_version = '1.8.0'
repositories {
google()
jcenter()
Expand All @@ -26,6 +27,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
2 changes: 1 addition & 1 deletion example/lib/main.dart
Expand Up @@ -560,7 +560,7 @@ class _MrtdHomePageState extends State<MrtdHomePage> {
SizedBox(height: 40),
_buildForm(context),
SizedBox(height: 20),
PlatformButton( // btn Read MRTD
PlatformElevatedButton( // btn Read MRTD
onPressed: _disabledInput() || !_mrzData.currentState!.validate() ? null : _readMRTD,
child: PlatformText(_isReading ? 'Reading ...' : 'Read Passport'),
),
Expand Down
6 changes: 3 additions & 3 deletions example/pubspec.yaml
Expand Up @@ -15,7 +15,7 @@ description: A new Flutter project.
version: 1.2.1

environment:
sdk: '>=2.17.1 <3.0.0'
sdk: '>=2.17.6 <3.0.0'

publish_to: none

Expand All @@ -26,8 +26,8 @@ dependencies:
sdk: flutter
flutter_localizations:
sdk: flutter
flutter_platform_widgets: ^1.7.1
intl: ^0.17.0
flutter_platform_widgets: ^3.3.5
intl: ^0.18.0

# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
Expand Down
Empty file added lib/src/constants/asn1_ber.dart
Empty file.
15 changes: 11 additions & 4 deletions lib/src/extension/string_apis.dart
Expand Up @@ -16,7 +16,7 @@ extension StringDecodeApis on String {

extension StringYYMMDDateApi on String {
DateTime parseDateYYMMDD() {
if(length < 6) {
if (length < 6) {
throw FormatException("invalid length of compact date string");
}

Expand All @@ -27,10 +27,17 @@ extension StringYYMMDDateApi on String {
// Sub 100 years from parsed year if greater than 10 years and 5 months from now.
final now = DateTime.now();
final tenYearsFromNow = now.year + 10;
if (y > tenYearsFromNow ||
(y == tenYearsFromNow && now.month + 5 < m)) {
if (y > tenYearsFromNow || (y == tenYearsFromNow && now.month + 5 < m)) {
y -= 100;
}
return DateTime(y, m, d);
}
}

DateTime parseDate() {
if (length == 6) {
return this.parseDateYYMMDD();
} else {
return DateTime.parse(this);
}
}
}
103 changes: 103 additions & 0 deletions lib/src/lds/asn1ObjectIdentifiers.dart
@@ -0,0 +1,103 @@
// Created by Nejc Skerjanc, copyright © 2023 ZeroPass. All rights reserved.

import 'dart:typed_data';
import 'package:dmrtd/extensions.dart';
import 'package:logging/logging.dart';
import 'package:pointycastle/asn1.dart';
import 'package:pointycastle/asn1/object_identifiers_database.dart';

import '../../types/exception.dart';


// here you can add additional object identifiers that are not defined in pointycastle library
List<Map<String, Object>> customOIDS = [
{
'identifierString': '1.2.3.4.5', 'readableName': 'someName', 'identifier': [0, 1, 2, 3, 4, 5]
}
];


// add additional object identifiers

class ASN1ObjectIdentifierException implements DMRTDException {
final String message;
@override
String exceptionName = 'ASN1ObjectIdentifierException';

ASN1ObjectIdentifierException(this.message);
//@override
//String toString() {
// String result = 'ASN1ObjectIdentifierException';
// if (message is String) return '$result: $message';
// return result;
//}


}


class ASN1ObjectIdentifiers {
// object identifiers that are defined in pointycastle library
List<Map<String, Object>> _OIDS = oi;
final _log = Logger("ASN1ObjectIdentifiers");


ASN1ObjectIdentifiers(){
// add custom object identifiers to existing ones
for (var customOID in customOIDS) {
if (!checkOID(item:customOID)){
throw ASN1ObjectIdentifierException('Object identifier is not valid.');
}
_OIDS.add(customOID);
}
}

// check if object identifier is valid
bool checkOID({required Map<String, Object> item}){
//check if list contains all required keys
if (!item.containsKey('identifier') || !item.containsKey('identifierString') || !item.containsKey('readableName')) {
_log.error('Object identifier must contain identifier, identifierString and readableName.');
return false;
}

if (item['identifier'] is! List<int>) {
_log.error('Object identifier identifier must be List<int>.');
return false;
}
if (item['identifierString'] is! String) {
_log.error('Object identifier identifierString must be String.');
return false;
}
if (item['readableName'] is! String) {
_log.error('Object identifier readableName must be String.');
return false;
}
return true;
}


// has object identifier with identifier string
bool hasOIDWithIdentifierString(String identifierString) {
return _OIDS.any((element) => element['identifierString'] == identifierString);
}


// get object identifier by identifier string
Map<String, Object> getOIDByIdentifierString(String identifierString) {
return _OIDS.firstWhere((element) => element['identifierString'] == identifierString, orElse: () =>
throw ASN1ObjectIdentifierException('Object identifier with identifier string $identifierString does not exist.'));
}

// has object identifier wih identifier
bool hasOIDWithIdentifier(List<int> identifier) {
return _OIDS.any((element) => element['identifier'] == identifier);
}

// get object identifier by identifier
Map<String, Object> getOIDByIdentifier(List<int> identifier) {
return _OIDS.firstWhere((element) => element['identifier'] == identifier, orElse: () =>
throw ASN1ObjectIdentifierException('Object identifier with identifier $identifier does not exist.'));
}

}

126 changes: 125 additions & 1 deletion lib/src/lds/df1/efdg11.dart
@@ -1,14 +1,73 @@
// Created by Crt Vavros, copyright © 2022 ZeroPass. All rights reserved.
// ignore_for_file: constant_identifier_names

import 'dart:convert';
import 'dart:core';
import 'dart:typed_data';
import 'package:dmrtd/dmrtd.dart';
import 'package:dmrtd/extensions.dart';

import 'dg.dart';

class EfDG11 extends DataGroup {
static const FID = 0x010B;
static const SFI = 0x0B;
static const TAG = DgTag(0x6B);

static const FULL_NAME_TAG = 0x5F0E;
static const OTHER_NAME_TAG = 0x5F0F;
static const PERSONAL_NUMBER_TAG = 0x5F10;

// In 'CCYYMMDD' format.
static const FULL_DATE_OF_BIRTH_TAG = 0x5F2B;

// Fields separated by '<'
static const PLACE_OF_BIRTH_TAG = 0x5F11;

// Fields separated by '<'
static const PERMANENT_ADDRESS_TAG = 0x5F42;
static const TELEPHONE_TAG = 0x5F12;
static const PROFESSION_TAG = 0x5F13;
static const TITLE_TAG = 0x5F14;
static const PERSONAL_SUMMARY_TAG = 0x5F15;

// Compressed image per ISO/IEC 10918
static const PROOF_OF_CITIZENSHIP_TAG = 0x5F16;

// Separated by '<'
static const OTHER_VALID_TD_NUMBERS_TAG = 0x5F17;
static const CUSTODY_INFORMATION_TAG = 0x5F18;

static const TAG_LIST_TAG = 0x5c;

String? _nameOfHolder;
final _otherNames = <String>[];
String? _personalNumber;
DateTime? _fullDateOfBirth;
final _placeOfBirth = <String>[];
final _permanentAddress = <String>[];
String? _telephone;
String? _profession;
String? _title;
String? _personalSummary;
Uint8List? _proofOfCitizenship;
var _otherValidTDNumbers = <String>[];
String? _custodyInformation;

String? get nameOfHolder => _nameOfHolder;
List<String> get otherNames => _otherNames;
String? get personalNumber => _personalNumber;
DateTime? get fullDateOfBirth => _fullDateOfBirth;
List<String> get placeOfBirth => _placeOfBirth;
List<String> get permanentAddress => _permanentAddress;
String? get telephone => _telephone;
String? get profession => _profession;
String? get title => _title;
String? get ersonalSummary => _personalSummary;
Uint8List? get proofOfCitizenship => _proofOfCitizenship;
List<String> get otherValidTDNumbers => _otherValidTDNumbers;
String? get custodyInformation => _custodyInformation;

EfDG11.fromBytes(Uint8List data) : super.fromBytes(data);

@override
Expand All @@ -19,4 +78,69 @@ class EfDG11 extends DataGroup {

@override
int get tag => TAG.value;
}

@override
void parse(Uint8List content) {
final tlv = TLV.fromBytes(content);
if (tlv.tag != tag) {
throw EfParseError(
"Invalid DG11 tag=${tlv.tag.hex()}, expected tag=${TAG.value.hex()}");
}

final data = tlv.value;
final tagListTag = TLV.decode(data);
if (tagListTag.tag.value != TAG_LIST_TAG) {
throw EfParseError(
"Invalid version object tag=${tagListTag.tag.value.hex()}, expected version object with tag=5c");
}
var tagListLength = tlv.value.length;
int tagListBytesRead = tagListTag.encodedLen;

while (tagListBytesRead < tagListLength) {
final uvtv = TLV.decode(data.sublist(tagListBytesRead));
tagListBytesRead += uvtv.encodedLen;

switch (uvtv.tag.value) {
case FULL_NAME_TAG:
_nameOfHolder = utf8.decode(uvtv.value);
break;
case PERSONAL_NUMBER_TAG:
_personalNumber = utf8.decode(uvtv.value);
break;
case OTHER_NAME_TAG:
_otherNames.add(utf8.decode(uvtv.value));
break;
case FULL_DATE_OF_BIRTH_TAG:
_fullDateOfBirth = String.fromCharCodes(uvtv.value).parseDate();
break;
case PLACE_OF_BIRTH_TAG:
_placeOfBirth.add(utf8.decode(uvtv.value));
break;
case PERMANENT_ADDRESS_TAG:
_permanentAddress.add(utf8.decode(uvtv.value));
break;
case TELEPHONE_TAG:
_telephone = utf8.decode(uvtv.value);
break;
case PROFESSION_TAG:
_profession = utf8.decode(uvtv.value);
break;
case TITLE_TAG:
_title = utf8.decode(uvtv.value);
break;
case PERSONAL_SUMMARY_TAG:
_personalSummary = utf8.decode(uvtv.value);
break;
case PROOF_OF_CITIZENSHIP_TAG:
_proofOfCitizenship = uvtv.value;
break;
case OTHER_VALID_TD_NUMBERS_TAG:
_otherValidTDNumbers.add(utf8.decode(uvtv.value));
break;
case CUSTODY_INFORMATION_TAG:
_custodyInformation = utf8.decode(uvtv.value);
break;
}
}
}
}

0 comments on commit 247625f

Please sign in to comment.