SimulatedBelgianCard constructor

SimulatedBelgianCard({
  1. String cardNumber = '591000000106',
  2. DateTime? validFrom,
  3. DateTime? validUntil,
  4. String issuingMunicipality = 'Bruxelles',
  5. String nationalNumber = '90051512391',
  6. String lastName = 'Specimen',
  7. String firstNames = 'Alice Marie',
  8. String? thirdGivenNameInitial = 'J',
  9. String nationality = 'Belge',
  10. String birthPlace = 'Namur',
  11. String birthDate = '15 MAI 1990',
  12. String sex = 'F',
  13. BelgianDocumentType documentType = BelgianDocumentType.eid,
  14. String streetAndNumber = 'Rue de la Loi 16',
  15. String postalCode = '1000',
  16. String municipality = 'Bruxelles',
  17. Uint8List? photo,
  18. Map<int, Object> extraIdentityFields = const {},
  19. String pin = '1234',
  20. int appletVersion = 0x18,
  21. Duration latency = Duration.zero,
  22. String? tamperedLastName,
  23. bool cloned = false,
  24. bool holderCertificates = true,
})

A card holding the given data, by default that of a fictional citizen.

birthDate is written as on the card, such as 15 MAI 1990, and sex as M or F. extraIdentityFields adds or replaces identity fields by tag. An appletVersion below 0x18 gives an older card. latency delays every answer.

tamperedLastName is written after signing, so the signature fails. A cloned card fails BelgianEidReader.proveGenuine. holderCertificates false leaves out the holder's certificates, as on a Kids ID.

Implementation

SimulatedBelgianCard({
  String cardNumber = '591000000106',
  DateTime? validFrom,
  DateTime? validUntil,
  String issuingMunicipality = 'Bruxelles',
  String nationalNumber = '90051512391',
  String lastName = 'Specimen',
  String firstNames = 'Alice Marie',
  String? thirdGivenNameInitial = 'J',
  String nationality = 'Belge',
  String birthPlace = 'Namur',
  String birthDate = '15 MAI 1990',
  String sex = 'F',
  BelgianDocumentType documentType = BelgianDocumentType.eid,
  String streetAndNumber = 'Rue de la Loi 16',
  String postalCode = '1000',
  String municipality = 'Bruxelles',
  Uint8List? photo,
  Map<int, Object> extraIdentityFields = const {},
  String pin = '1234',
  this.appletVersion = 0x18,
  this.latency = Duration.zero,
  String? tamperedLastName,
  bool cloned = false,
  bool holderCertificates = true,
})  : _pinBlock = pinBlock(pin),
      _basicKey = cloned
          ? SimulatedPki.instance.cloneKey
          : SimulatedPki.instance.basicKey {
  final cardPhoto = photo ?? specimenPhoto;
  final basicPublicKey = SimulatedPki.instance.basicPublicKeyFile;
  final pki = SimulatedPki.instance;
  Uint8List identityWith(String lastName) => _tlv({
        0x00: const [0x00, 0x02],
        0x01: cardNumber,
        0x02: serialNumber,
        0x03: _dotted(validFrom ?? DateTime.utc(2024, 3, 14)),
        0x04: _dotted(validUntil ?? DateTime.utc(2034, 3, 13)),
        0x05: issuingMunicipality,
        0x06: nationalNumber,
        0x07: lastName,
        0x08: firstNames,
        0x09: thirdGivenNameInitial ?? '',
        0x0A: nationality,
        0x0B: birthPlace,
        0x0C: birthDate,
        0x0D: sex,
        0x0E: '',
        0x0F: '${documentType.code}',
        0x10: '0',
        0x11: _photoHash(cardPhoto),
        if (appletVersion >= 0x18) 0x1A: sha384.convert(basicPublicKey).bytes,
        ...extraIdentityFields,
      });
  final address = _tlv({
    0x00: const [0x00, 0x02],
    0x01: streetAndNumber,
    0x02: postalCode,
    0x03: municipality,
  });
  // Signing is asynchronous on the web: the first command waits for it.
  _files = _sign(
    identity: identityWith(tamperedLastName ?? lastName),
    signedIdentity: identityWith(lastName),
    address: address,
    photo: cardPhoto,
    basicPublicKey: basicPublicKey,
    holderCertificates: holderCertificates
        ? pki.holderCertificates(
            lastName: lastName,
            firstNames: firstNames,
            nationalNumber: nationalNumber,
          )
        : null,
  );
  // A failure surfaces on the first command, not as an unhandled error.
  _files.ignore();
}