├── .github └── ISSUE_TEMPLATE │ ├── 01_bug.md │ ├── 02_feature_request.md │ ├── 03_enhancement.md │ └── 04_question.md ├── .gitignore ├── .idea └── .gitignore ├── .ort.yml ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── THIRD-PARTY-NOTICES ├── build.gradle ├── codestyle └── checkstyle.xml ├── decoder ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── dgca │ │ └── verifier │ │ └── app │ │ └── decoder │ │ ├── CertificateDecoder.kt │ │ ├── DefaultCertificateDecoder.kt │ │ ├── Extensions.kt │ │ ├── JsonSchema.kt │ │ ├── SignatureExt.kt │ │ ├── Util.kt │ │ ├── base45 │ │ ├── Base45Decoder.kt │ │ ├── Base45Service.kt │ │ └── DefaultBase45Service.kt │ │ ├── cbor │ │ ├── CborService.kt │ │ ├── DefaultCborService.kt │ │ ├── DefaultGreenCertificateMapper.kt │ │ └── GreenCertificateMapper.kt │ │ ├── compression │ │ ├── CompressorService.kt │ │ └── DefaultCompressorService.kt │ │ ├── cose │ │ ├── CoseService.kt │ │ ├── CryptoService.kt │ │ ├── DefaultCoseService.kt │ │ └── VerificationCryptoService.kt │ │ ├── cwt │ │ └── CwtHeaderKeys.kt │ │ ├── model │ │ ├── CertificateType.kt │ │ ├── CoseData.kt │ │ ├── GreenCertificate.kt │ │ ├── KeyPairData.kt │ │ ├── Person.kt │ │ ├── RecoveryStatement.kt │ │ ├── Test.kt │ │ ├── Vaccination.kt │ │ └── VerificationResult.kt │ │ ├── prefixvalidation │ │ ├── DefaultPrefixValidationService.kt │ │ └── PrefixValidationService.kt │ │ ├── schema │ │ ├── DefaultSchemaValidator.kt │ │ └── SchemaValidator.kt │ │ └── services │ │ └── X509.kt │ └── test │ └── java │ └── dgca │ └── verifier │ └── app │ └── decoder │ ├── CertificateCheckTest.kt │ ├── CertificateTestRunner.kt │ ├── QrCodeTests.kt │ ├── TestCase.kt │ ├── X509Tests.kt │ └── cbor │ └── DefaultGreenCertificateMapperTest.kt ├── dokka └── html │ ├── decoder │ ├── dgca.verifier.app.decoder.base45 │ │ ├── -base45-decode-exception │ │ │ ├── -base45-decode-exception.html │ │ │ ├── get-cause.html │ │ │ ├── get-message.html │ │ │ └── index.html │ │ ├── -base45-decoder │ │ │ ├── -base45-decoder.html │ │ │ ├── decode.html │ │ │ └── index.html │ │ ├── -base45-service │ │ │ ├── decode.html │ │ │ └── index.html │ │ ├── -default-base45-service │ │ │ ├── -default-base45-service.html │ │ │ ├── decode.html │ │ │ └── index.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.cbor │ │ ├── -cbor-service │ │ │ ├── decode-data.html │ │ │ ├── decode.html │ │ │ ├── get-payload.html │ │ │ └── index.html │ │ ├── -default-cbor-service │ │ │ ├── -default-cbor-service.html │ │ │ ├── decode-data.html │ │ │ ├── decode.html │ │ │ ├── get-payload.html │ │ │ └── index.html │ │ ├── -default-green-certificate-mapper │ │ │ ├── -default-green-certificate-mapper.html │ │ │ ├── index.html │ │ │ └── read-value.html │ │ ├── -green-certificate-data │ │ │ ├── -green-certificate-data.html │ │ │ ├── get-expiration-time.html │ │ │ ├── get-green-certificate.html │ │ │ ├── get-hcert-json.html │ │ │ ├── get-issued-at.html │ │ │ ├── get-issuing-country.html │ │ │ ├── get-normalized-issuing-country.html │ │ │ └── index.html │ │ ├── -green-certificate-mapper │ │ │ ├── index.html │ │ │ └── read-value.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.compression │ │ ├── -compressor-service │ │ │ ├── decode.html │ │ │ └── index.html │ │ ├── -default-compressor-service │ │ │ ├── -default-compressor-service.html │ │ │ ├── decode.html │ │ │ └── index.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.cose │ │ ├── -cose-service │ │ │ ├── anonymize-cose.html │ │ │ ├── decode.html │ │ │ └── index.html │ │ ├── -crypto-service │ │ │ ├── index.html │ │ │ └── validate.html │ │ ├── -default-cose-service-kt │ │ │ └── index.html │ │ ├── -default-cose-service │ │ │ ├── -default-cose-service.html │ │ │ ├── anonymize-cose.html │ │ │ ├── decode.html │ │ │ └── index.html │ │ ├── -verification-crypto-service │ │ │ ├── -algo │ │ │ │ ├── -a-l-g-o_-e-c-d-s-a256 │ │ │ │ │ └── index.html │ │ │ │ ├── -a-l-g-o_-r-s-a256_-p-s-s │ │ │ │ │ └── index.html │ │ │ │ ├── get-name.html │ │ │ │ ├── get-ordinal.html │ │ │ │ ├── get-value.html │ │ │ │ └── index.html │ │ │ ├── -verification-crypto-service.html │ │ │ ├── index.html │ │ │ └── validate.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.cwt │ │ ├── -cwt-header-keys │ │ │ ├── -e-x-p-i-r-a-t-i-o-n │ │ │ │ └── index.html │ │ │ ├── -h-c-e-r-t │ │ │ │ └── index.html │ │ │ ├── -i-s-s-u-e-d_-a-t │ │ │ │ └── index.html │ │ │ ├── -i-s-s-u-i-n-g_-c-o-u-n-t-r-y │ │ │ │ └── index.html │ │ │ ├── as-c-b-o-r.html │ │ │ └── index.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.model │ │ ├── -certificate-type │ │ │ ├── -r-e-c-o-v-e-r-y │ │ │ │ └── index.html │ │ │ ├── -t-e-s-t │ │ │ │ └── index.html │ │ │ ├── -u-n-k-n-o-w-n │ │ │ │ └── index.html │ │ │ ├── -v-a-c-c-i-n-a-t-i-o-n │ │ │ │ └── index.html │ │ │ ├── get-name.html │ │ │ ├── get-ordinal.html │ │ │ └── index.html │ │ ├── -cose-data │ │ │ ├── -cose-data.html │ │ │ ├── equals.html │ │ │ ├── get-cbor.html │ │ │ ├── get-kid.html │ │ │ ├── hash-code.html │ │ │ └── index.html │ │ ├── -green-certificate │ │ │ ├── -green-certificate.html │ │ │ ├── get-date-of-birth.html │ │ │ ├── get-dgci.html │ │ │ ├── get-issuing-country.html │ │ │ ├── get-person.html │ │ │ ├── get-recovery-statements.html │ │ │ ├── get-schema-version.html │ │ │ ├── get-tests.html │ │ │ ├── get-type.html │ │ │ ├── get-vaccinations.html │ │ │ └── index.html │ │ ├── -key-pair-data │ │ │ ├── -key-pair-data.html │ │ │ ├── get-algo.html │ │ │ ├── get-key-pair.html │ │ │ └── index.html │ │ ├── -person │ │ │ ├── -person.html │ │ │ ├── get-family-name.html │ │ │ ├── get-given-name.html │ │ │ ├── get-standardised-family-name.html │ │ │ ├── get-standardised-given-name.html │ │ │ └── index.html │ │ ├── -recovery-statement │ │ │ ├── -companion │ │ │ │ └── index.html │ │ │ ├── -recovery-statement.html │ │ │ ├── get-certificate-identifier.html │ │ │ ├── get-certificate-issuer.html │ │ │ ├── get-certificate-valid-from.html │ │ │ ├── get-certificate-valid-until.html │ │ │ ├── get-country-of-vaccination.html │ │ │ ├── get-date-of-first-positive-test.html │ │ │ ├── get-disease.html │ │ │ ├── index.html │ │ │ ├── is-certificate-not-valid-anymore.html │ │ │ └── is-certificate-not-valid-so-far.html │ │ ├── -recovery-verification-result │ │ │ ├── -recovery-verification-result.html │ │ │ ├── index.html │ │ │ ├── is-not-valid-anymore.html │ │ │ ├── is-not-valid-so-far.html │ │ │ └── is-recovery-valid.html │ │ ├── -test-verification-result │ │ │ ├── -test-verification-result.html │ │ │ ├── index.html │ │ │ ├── is-test-date-in-the-past.html │ │ │ ├── is-test-result-negative.html │ │ │ └── is-test-valid.html │ │ ├── -test │ │ │ ├── -test-result │ │ │ │ ├── -d-e-t-e-c-t-e-d │ │ │ │ │ └── index.html │ │ │ │ ├── -n-o-t_-d-e-t-e-c-t-e-d │ │ │ │ │ └── index.html │ │ │ │ ├── get-name.html │ │ │ │ ├── get-ordinal.html │ │ │ │ ├── get-value.html │ │ │ │ └── index.html │ │ │ ├── -test.html │ │ │ ├── get-certificate-identifier.html │ │ │ ├── get-certificate-issuer.html │ │ │ ├── get-country-of-vaccination.html │ │ │ ├── get-date-time-of-collection.html │ │ │ ├── get-date-time-of-test-result.html │ │ │ ├── get-disease.html │ │ │ ├── get-test-name-and-manufacturer.html │ │ │ ├── get-test-name.html │ │ │ ├── get-test-result-type.html │ │ │ ├── get-test-result.html │ │ │ ├── get-testing-centre.html │ │ │ ├── get-type-of-test.html │ │ │ ├── index.html │ │ │ ├── is-date-in-the-past.html │ │ │ └── is-result-negative.html │ │ ├── -vaccination-verification-result │ │ │ ├── -vaccination-verification-result.html │ │ │ ├── index.html │ │ │ ├── is-vaccination-date-in-the-past.html │ │ │ └── is-vaccination-valid.html │ │ ├── -vaccination │ │ │ ├── -vaccination.html │ │ │ ├── get-certificate-identifier.html │ │ │ ├── get-certificate-issuer.html │ │ │ ├── get-country-of-vaccination.html │ │ │ ├── get-date-of-vaccination.html │ │ │ ├── get-disease.html │ │ │ ├── get-dose-number.html │ │ │ ├── get-manufacturer.html │ │ │ ├── get-medicinal-product.html │ │ │ ├── get-total-series-of-doses.html │ │ │ ├── get-vaccine.html │ │ │ ├── index.html │ │ │ └── is-date-in-the-past.html │ │ ├── -verification-result │ │ │ ├── -verification-result.html │ │ │ ├── get-base45-decoded.html │ │ │ ├── get-cbor-decoded.html │ │ │ ├── get-context-prefix.html │ │ │ ├── get-cose-verified.html │ │ │ ├── get-recovery-verification.html │ │ │ ├── get-rules-validation-failed.html │ │ │ ├── get-test-verification.html │ │ │ ├── get-vaccination-verification.html │ │ │ ├── get-zlib-decoded.html │ │ │ ├── index.html │ │ │ ├── is-issued-time-correct.html │ │ │ ├── is-not-expired.html │ │ │ ├── is-recovery-not-valid-anymore.html │ │ │ ├── is-recovery-not-valid-so-far.html │ │ │ ├── is-schema-valid.html │ │ │ ├── is-test-date-in-the-future.html │ │ │ ├── is-test-with-positive-result.html │ │ │ ├── is-vaccination-date-in-the-future.html │ │ │ ├── is-valid.html │ │ │ ├── set-base45-decoded.html │ │ │ ├── set-cbor-decoded.html │ │ │ ├── set-context-prefix.html │ │ │ ├── set-cose-verified.html │ │ │ ├── set-issued-time-correct.html │ │ │ ├── set-not-expired.html │ │ │ ├── set-recovery-verification.html │ │ │ ├── set-rules-validation-failed.html │ │ │ ├── set-schema-valid.html │ │ │ ├── set-test-verification.html │ │ │ ├── set-vaccination-verification.html │ │ │ ├── set-zlib-decoded.html │ │ │ └── to-string.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.prefixvalidation │ │ ├── -default-prefix-validation-service │ │ │ ├── -default-prefix-validation-service.html │ │ │ ├── decode.html │ │ │ ├── encode.html │ │ │ └── index.html │ │ ├── -prefix-validation-service │ │ │ ├── decode.html │ │ │ ├── encode.html │ │ │ └── index.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.schema │ │ ├── -default-schema-validator │ │ │ ├── -default-schema-validator.html │ │ │ ├── index.html │ │ │ └── validate.html │ │ ├── -schema-validator │ │ │ ├── index.html │ │ │ └── validate.html │ │ └── index.html │ ├── dgca.verifier.app.decoder.services │ │ ├── -x509 │ │ │ ├── -x509.html │ │ │ ├── check-is-suitable.html │ │ │ ├── index.html │ │ │ └── is-suitable.html │ │ └── index.html │ ├── dgca.verifier.app.decoder │ │ ├── -certificate-decoder │ │ │ ├── decode-certificate.html │ │ │ └── index.html │ │ ├── -certificate-decoding-error │ │ │ ├── -base45-decoding-error │ │ │ │ ├── -certificate-decoding-error.-base45-decoding-error.html │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── -base45-decompression-error │ │ │ │ ├── -certificate-decoding-error.-base45-decompression-error.html │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── -certificate-conversion-error │ │ │ │ ├── -certificate-decoding-error.-certificate-conversion-error.html │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── -cose-data-decoding-error │ │ │ │ ├── -certificate-decoding-error.-cose-data-decoding-error.html │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── -empty-green-certificate │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── -green-certificate-decoding-error │ │ │ │ ├── -certificate-decoding-error.-green-certificate-decoding-error.html │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── get-error.html │ │ │ └── index.html │ │ ├── -certificate-decoding-result │ │ │ ├── -error │ │ │ │ ├── -certificate-decoding-result.-error.html │ │ │ │ ├── get-error.html │ │ │ │ └── index.html │ │ │ ├── -success │ │ │ │ ├── -certificate-decoding-result.-success.html │ │ │ │ ├── get-green-certificate.html │ │ │ │ └── index.html │ │ │ └── index.html │ │ ├── -default-certificate-decoder │ │ │ ├── -companion │ │ │ │ ├── get-p-r-e-f-i-x.html │ │ │ │ └── index.html │ │ │ ├── -default-certificate-decoder.html │ │ │ ├── decode-certificate.html │ │ │ └── index.html │ │ ├── -extensions-kt │ │ │ ├── base64-to-x509-certificate.html │ │ │ ├── delete-key-pair-for.html │ │ │ ├── from-base64.html │ │ │ ├── generate-key-pair-for.html │ │ │ ├── get-key-pair-for.html │ │ │ ├── hex-to-byte-array.html │ │ │ ├── index.html │ │ │ ├── to-base64.html │ │ │ ├── to-hash.html │ │ │ └── to-hex-string.html │ │ ├── -json-schema-kt │ │ │ └── index.html │ │ ├── -signature-ext-kt │ │ │ ├── convert-to-der.html │ │ │ ├── get-validation-data-from-c-o-s-e.html │ │ │ ├── index.html │ │ │ └── verify.html │ │ ├── -util-kt │ │ │ ├── generate-claim-signature.html │ │ │ └── index.html │ │ └── index.html │ └── package-list │ ├── images │ ├── anchor-copy-button.svg │ ├── arrow_down.svg │ ├── copy-icon.svg │ ├── copy-successful-icon.svg │ ├── footer-go-to-link.svg │ ├── go-to-top-icon.svg │ ├── logo-icon.svg │ └── theme-toggle.svg │ ├── index.html │ ├── navigation.html │ ├── scripts │ ├── clipboard.js │ ├── main.js │ ├── navigation-loader.js │ ├── pages.json │ ├── platform-content-handler.js │ ├── prism.js │ └── sourceset_dependencies.js │ └── styles │ ├── jetbrains-mono.css │ ├── logo-styles.css │ ├── main.css │ ├── prism.css │ └── style.css ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── templates └── file-header.txt /.github/ISSUE_TEMPLATE/01_bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F6A8 Bug" 3 | about: Did you come across a bug or unexpected behaviour differing from the docs? 4 | labels: bug 5 | --- 6 | 7 | 13 | 14 | ## Describe the bug 15 | 16 | 17 | 18 | ## Expected behaviour 19 | 20 | 21 | 22 | ## Steps to reproduce the issue 23 | 24 | 25 | 26 | 32 | 33 | ## Technical details 34 | 35 | - Host Machine OS (Windows/Linux/Mac): 36 | 37 | ## Possible Fix 38 | 39 | 40 | 41 | ## Additional context 42 | 43 | 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02_feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F381 Feature Request" 3 | about: Do you have an idea for a new feature? 4 | labels: feature request 5 | --- 6 | 7 | 13 | 14 | ## Feature description 15 | 16 | 21 | 22 | ## Problem and motivation 23 | 24 | 28 | 29 | ## Is this something you're interested in working on 30 | 31 | 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/03_enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\u23F1\uFE0F Enhancement" 3 | about: Do you have an idea for an enhancement? 4 | labels: enhancement 5 | --- 6 | 7 | 13 | 14 | ## Current Implementation 15 | 16 | 17 | 18 | ## Suggested Enhancement 19 | 20 | 24 | 25 | ## Expected Benefits 26 | 27 | 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/04_question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U00002753 Question" 3 | about: If you have questions about pieces of the code or documentation for this component, please post them here. 4 | labels: question 5 | --- 6 | 7 | 13 | 14 | ## Your Question 15 | 16 | 17 | 18 | * Source File: 19 | * Line(s): 20 | * Question: 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | .cxx 9 | local.properties 10 | 11 | .idea/workspace.xml 12 | .idea/tasks.xml 13 | .idea/gradle.xml 14 | .idea/assetWizardSettings.xml 15 | .idea/dictionaries 16 | .idea/libraries 17 | .idea/sonarlint/ 18 | .idea/sonarIssues.xml 19 | .idea/codeStyles/ 20 | 21 | # User-specific configurations 22 | .idea/caches/ 23 | .idea/shelf/ 24 | .idea/.name 25 | .idea/compiler.xml 26 | .idea/encodings.xml 27 | .idea/misc.xml 28 | .idea/vcs.xml 29 | .idea/jarRepositories.xml 30 | .idea/modules.xml 31 | .idea/kotlinScripting.xml -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.ort.yml: -------------------------------------------------------------------------------- 1 | excludes: 2 | scopes: 3 | - pattern: "test.*" 4 | reason: "TEST_DEPENDENCY_OF" 5 | comment: "Packages for testing only." 6 | - pattern: ".*Test.*" 7 | reason: "TEST_DEPENDENCY_OF" 8 | comment: "Packages for testing only." -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file provides an overview of code owners in this repository. 2 | 3 | # Each line is a file pattern followed by one or more owners. 4 | # The last matching pattern has the most precedence. 5 | # For more details, read the following article on GitHub: https://help.github.com/articles/about-codeowners/. 6 | 7 | # These are the default owners for the whole content of this repository. The default owners are automatically added as reviewers when you open a pull request, unless different owners are specified in the file. 8 | * @eu-digital-green-certificates/dgc-android-apps-codeowners 9 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 T-Systems International GmbH and all other contributors. 2 | 3 | This project is licensed under Apache License, Version 2.0; 4 | you may not use them except in compliance with the License. 5 | 6 | Contributors: 7 | ------------- 8 | 9 | Daniel Eder [daniel-eder], T-Mobile International Austria GmbH 10 | Andreas Scheibal [ascheibal], T-Systems International GmbH -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | 4 | repositories { 5 | google() 6 | jcenter() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | classpath "com.android.tools.build:gradle:4.1.3" 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21" 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | jcenter() 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } -------------------------------------------------------------------------------- /decoder/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /decoder/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | id("org.jetbrains.dokka") version "1.6.21" 5 | } 6 | 7 | android { 8 | compileSdkVersion 30 9 | 10 | defaultConfig { 11 | minSdkVersion 23 12 | targetSdkVersion 30 13 | versionCode 2 14 | versionName "1.3.0" 15 | 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | consumerProguardFiles "consumer-rules.pro" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | 27 | compileOptions { 28 | coreLibraryDesugaringEnabled = true 29 | sourceCompatibility JavaVersion.VERSION_1_8 30 | targetCompatibility JavaVersion.VERSION_1_8 31 | } 32 | 33 | kotlinOptions { 34 | jvmTarget = '1.8' 35 | } 36 | 37 | libraryVariants.all { variant -> 38 | variant.outputs.each { output -> 39 | def lintTask = tasks["lint${variant.name.capitalize()}"] 40 | output.assemble.dependsOn lintTask 41 | } 42 | } 43 | } 44 | 45 | dependencies { 46 | coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.0" 47 | 48 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.21" 49 | implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.21" 50 | implementation "com.upokecenter:cbor:4.5.1" 51 | implementation("com.github.java-json-tools:json-schema-validator:2.2.14") { 52 | exclude group: "org.mozilla", module: "rhino" 53 | } 54 | 55 | implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.14.0" 56 | implementation "org.bouncycastle:bcpkix-jdk15to18:1.68" 57 | 58 | testImplementation "junit:junit:4.13.1" 59 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.7.1" 60 | testImplementation "org.junit.jupiter:junit-jupiter-params:5.7.1" 61 | testImplementation "org.hamcrest:hamcrest:2.2" 62 | testImplementation "org.mockito:mockito-core:3.9.0" 63 | testImplementation "org.mockito.kotlin:mockito-kotlin:3.2.0" 64 | testImplementation "org.mockito:mockito-inline:2.7.21" 65 | 66 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.7.1" 67 | dokkaHtmlPlugin("org.jetbrains.dokka:kotlin-as-java-plugin:1.6.21") 68 | } -------------------------------------------------------------------------------- /decoder/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eu-digital-green-certificates/dgca-app-core-android/4039792a01a19388bafa1374a4318849a03e05b2/decoder/consumer-rules.pro -------------------------------------------------------------------------------- /decoder/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep public class dgca.verifier.app.decoder.model.* 23 | -keep public class com.github.fge.jsonschema.** { *; } -------------------------------------------------------------------------------- /decoder/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/CertificateDecoder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by osarapulov on 5/10/21 11:28 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder 24 | 25 | import dgca.verifier.app.decoder.model.GreenCertificate 26 | 27 | /** 28 | * Represents error that might occur during decoding green certificate QR. 29 | */ 30 | sealed class CertificateDecodingError(val error: Throwable? = null) { 31 | class Base45DecodingError(error: Throwable) : CertificateDecodingError(error) 32 | class Base45DecompressionError(error: Throwable) : CertificateDecodingError(error) 33 | class CoseDataDecodingError(error: Throwable) : CertificateDecodingError(error) 34 | class GreenCertificateDecodingError(error: Throwable) : CertificateDecodingError(error) 35 | object EmptyGreenCertificate : CertificateDecodingError() 36 | class CertificateConversionError(error: Throwable) : CertificateDecodingError(error) 37 | } 38 | 39 | /** 40 | * Represents green certificate decoding result. If it's successful - it should return {@link Success}, 41 | * specific descriptive error {@link Error}. 42 | */ 43 | sealed class CertificateDecodingResult { 44 | class Success(val greenCertificate: GreenCertificate) : CertificateDecodingResult() 45 | data class Error(val error: CertificateDecodingError) : CertificateDecodingResult() 46 | } 47 | 48 | /** 49 | * Provides ability to decode QR code representing green certificate to local model {@link CertificateModel} 50 | */ 51 | interface CertificateDecoder { 52 | 53 | /** 54 | * Returns success result with {@link CertificateModel} or descriptive error model. 55 | */ 56 | fun decodeCertificate(qrCodeText: String): CertificateDecodingResult 57 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/SignatureExt.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 5/5/21 6:59 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder 24 | 25 | import com.upokecenter.cbor.CBORObject 26 | import java.security.PublicKey 27 | import java.security.Signature 28 | import java.util.* 29 | import kotlin.experimental.and 30 | 31 | fun Signature.verify(verificationKey: PublicKey, dataToBeVerified: ByteArray, coseSignature: ByteArray): Boolean { 32 | initVerify(verificationKey) 33 | update(dataToBeVerified) 34 | 35 | return verify(coseSignature) 36 | } 37 | 38 | fun ByteArray.convertToDer(): ByteArray { 39 | val len = size / 2 40 | val r = copyOfRange(0, len) 41 | val s = copyOfRange(len, size) 42 | return encodeSignature(r, s) 43 | } 44 | 45 | private fun encodeSignature(r: ByteArray, s: ByteArray): ByteArray { 46 | val x = ArrayList() 47 | x.add(r.unsignedInteger()) 48 | x.add(s.unsignedInteger()) 49 | return sequence(x) 50 | } 51 | 52 | private fun sequence(members: ArrayList): ByteArray { 53 | val y = toBytes(members) 54 | val x = ArrayList() 55 | x.add(byteArrayOf(0x30)) 56 | x.add(computeLength(y.size)) 57 | x.add(y) 58 | return toBytes(x) 59 | } 60 | 61 | private fun toBytes(x: ArrayList): ByteArray { 62 | var l = 0 63 | l = x.stream().map { r: ByteArray -> r.size }.reduce(l) { i: Int, i1: Int -> Integer.sum(i, i1) } 64 | val b = ByteArray(l) 65 | l = 0 66 | for (r in x) { 67 | System.arraycopy(r, 0, b, l, r.size) 68 | l += r.size 69 | } 70 | return b 71 | } 72 | 73 | private fun computeLength(x: Int): ByteArray { 74 | return when { 75 | x <= 127 -> byteArrayOf(x.toByte()) 76 | x < 256 -> byteArrayOf(0x81.toByte(), x.toByte()) 77 | else -> throw Exception() 78 | } 79 | } 80 | 81 | private fun ByteArray.unsignedInteger(): ByteArray { 82 | var pad = 0 83 | var offset = 0 84 | while (offset < size && this[offset] == 0.toByte()) { 85 | offset++ 86 | } 87 | if (offset == size) { 88 | return byteArrayOf(0x02, 0x01, 0x00) 89 | } 90 | if ((this[offset] and 0x80.toByte()) != 0.toByte()) { 91 | pad++ 92 | } 93 | 94 | val length = size - offset 95 | val der = ByteArray(2 + length + pad) 96 | der[0] = 0x02 97 | der[1] = (length + pad).toByte() 98 | System.arraycopy(this, offset, der, 2 + pad, length) 99 | 100 | return der 101 | } 102 | 103 | fun ByteArray.getValidationDataFromCOSE(): ByteArray { 104 | val messageObject = CBORObject.DecodeFromBytes(this) 105 | val protectedHeader = messageObject[0].GetByteString() 106 | val content = messageObject[2].GetByteString() 107 | 108 | return CBORObject.NewArray().apply { 109 | Add("Signature1") 110 | Add(protectedHeader) 111 | Add(ByteArray(0)) 112 | Add(content) 113 | }.EncodeToBytes() 114 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/Util.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 5/11/21 11:12 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder 24 | 25 | import android.util.Base64 26 | import java.nio.charset.StandardCharsets 27 | import java.security.PrivateKey 28 | import java.security.Signature 29 | 30 | fun generateClaimSignature( 31 | tanHash: String, 32 | certHash: String, 33 | publicKey: String, 34 | privateKey: PrivateKey, sigAlg: String 35 | ): String { 36 | val sigValue = StringBuilder() 37 | sigValue.append(tanHash) 38 | .append(certHash) 39 | .append(publicKey) 40 | val signature = Signature.getInstance(sigAlg) 41 | signature.initSign(privateKey) 42 | signature.update(sigValue.toString().toByteArray(StandardCharsets.UTF_8)) 43 | val sigData = signature.sign() 44 | 45 | return Base64.encodeToString(sigData, Base64.NO_WRAP) 46 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/base45/Base45Decoder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:50 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.base45 24 | 25 | // Lookup tables for faster processing 26 | internal val ENCODING_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".encodeToByteArray() 27 | private val DECODING_CHARSET = ByteArray(256) { -1 }.also { charset -> 28 | ENCODING_CHARSET.forEachIndexed { index, byte -> 29 | charset[byte.toInt()] = index.toByte() 30 | } 31 | } 32 | 33 | /** 34 | * The Base45 Data Decoding 35 | * 36 | * https://datatracker.ietf.org/doc/draft-faltstrom-base45/?include_text=1 37 | */ 38 | @ExperimentalUnsignedTypes 39 | class Base45Decoder { 40 | 41 | @Throws(Base45DecodeException::class) 42 | fun decode(input: String): ByteArray = 43 | input.toByteArray().asSequence().map { 44 | DECODING_CHARSET[it.toInt()].also { index -> 45 | if (index < 0) throw Base45DecodeException("Invalid characters in input.") 46 | } 47 | }.chunked(3) { chunk -> 48 | if (chunk.size < 2) throw Base45DecodeException("Invalid input length.") 49 | chunk.reversed().toInt(45).toBase(base = 256, count = chunk.size - 1).reversed() 50 | }.flatten().toList().toByteArray() 51 | 52 | /** Converts integer to a list of [count] integers in the given [base]. */ 53 | @Throws(Base45DecodeException::class) 54 | private fun Int.toBase(base: Int, count: Int): List = 55 | mutableListOf().apply { 56 | var tmp = this@toBase 57 | repeat(count) { 58 | add((tmp % base).toByte()) 59 | tmp /= base 60 | } 61 | if (tmp != 0) throw Base45DecodeException("Invalid character sequence.") 62 | } 63 | 64 | /** Converts list of bytes in given [base] to an integer. */ 65 | private fun List.toInt(base: Int): Int = 66 | fold(0) { acc, i -> acc * base + i.toUByte().toInt() } 67 | } 68 | 69 | /** Thrown when [Base45.decode] can't decode the input data. */ 70 | class Base45DecodeException(message: String) : IllegalArgumentException(message) -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/base45/Base45Service.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:50 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.base45 24 | 25 | import dgca.verifier.app.decoder.model.VerificationResult 26 | 27 | /** 28 | * Decodes input from Base45 29 | */ 30 | interface Base45Service { 31 | 32 | fun decode(input: String, verificationResult: VerificationResult): ByteArray 33 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/base45/DefaultBase45Service.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:50 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.base45 24 | 25 | import dgca.verifier.app.decoder.model.VerificationResult 26 | 27 | /** 28 | * Decodes input from Base45 29 | */ 30 | @ExperimentalUnsignedTypes 31 | class DefaultBase45Service : Base45Service { 32 | 33 | private val decoder = Base45Decoder() 34 | 35 | override fun decode(input: String, verificationResult: VerificationResult): ByteArray { 36 | verificationResult.base45Decoded = false 37 | return try { 38 | decoder.decode(input).also { 39 | verificationResult.base45Decoded = true 40 | } 41 | } catch (e: Throwable) { 42 | input.toByteArray() 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cbor/CborService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:50 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cbor 24 | 25 | import dgca.verifier.app.decoder.model.GreenCertificate 26 | import dgca.verifier.app.decoder.model.VerificationResult 27 | import java.time.ZonedDateTime 28 | import java.util.* 29 | 30 | data class GreenCertificateData( 31 | val issuingCountry: String?, 32 | val hcertJson: String, 33 | val greenCertificate: GreenCertificate, 34 | val issuedAt: ZonedDateTime, 35 | val expirationTime: ZonedDateTime 36 | ) { 37 | 38 | fun getNormalizedIssuingCountry(): String = 39 | (if (this.issuingCountry?.isNotBlank() == true) { 40 | this.issuingCountry 41 | } else { 42 | this.greenCertificate.getIssuingCountry() 43 | }).toLowerCase(Locale.ROOT) 44 | } 45 | 46 | /** 47 | * Decodes input as a CBOR structure 48 | */ 49 | interface CborService { 50 | 51 | fun decode(input: ByteArray, verificationResult: VerificationResult): GreenCertificate? 52 | 53 | fun decodeData(input: ByteArray, verificationResult: VerificationResult): GreenCertificateData? 54 | 55 | fun getPayload(input: ByteArray): ByteArray? 56 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cbor/DefaultCborService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:50 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cbor 24 | 25 | import com.upokecenter.cbor.CBORObject 26 | import dgca.verifier.app.decoder.cwt.CwtHeaderKeys 27 | import dgca.verifier.app.decoder.model.GreenCertificate 28 | import dgca.verifier.app.decoder.model.VerificationResult 29 | import java.time.Instant 30 | import java.time.ZoneOffset 31 | 32 | /** 33 | * Decodes input as a CBOR structure 34 | */ 35 | class DefaultCborService(private val greenCertificateMapper: GreenCertificateMapper = DefaultGreenCertificateMapper()) : 36 | CborService { 37 | 38 | override fun decode(input: ByteArray, verificationResult: VerificationResult): GreenCertificate? = 39 | decodeData(input, verificationResult)?.greenCertificate 40 | 41 | override fun decodeData( 42 | input: ByteArray, 43 | verificationResult: VerificationResult 44 | ): GreenCertificateData? { 45 | verificationResult.cborDecoded = false 46 | return try { 47 | val map = CBORObject.DecodeFromBytes(input) 48 | 49 | val issuingCountry: String? = map[CwtHeaderKeys.ISSUING_COUNTRY.asCBOR()]?.AsString() 50 | 51 | val issuedAt = Instant.ofEpochSecond(map[CwtHeaderKeys.ISSUED_AT.asCBOR()].AsInt64()) 52 | verificationResult.isIssuedTimeCorrect = issuedAt.isBefore(Instant.now()) 53 | 54 | val expirationTime = Instant.ofEpochSecond(map[CwtHeaderKeys.EXPIRATION.asCBOR()].AsInt64()) 55 | verificationResult.isNotExpired = expirationTime.isAfter(Instant.now()) 56 | 57 | val hcert = map[CwtHeaderKeys.HCERT.asCBOR()] 58 | 59 | val cborObject = hcert[CBORObject.FromObject(1)] 60 | 61 | val greenCertificate: GreenCertificate = greenCertificateMapper.readValue(cborObject) 62 | .also { verificationResult.cborDecoded = true } 63 | GreenCertificateData( 64 | issuingCountry, 65 | cborObject.ToJSONString(), 66 | greenCertificate, 67 | issuedAt.atZone(ZoneOffset.UTC), 68 | expirationTime.atZone(ZoneOffset.UTC) 69 | ) 70 | } catch (e: Throwable) { 71 | null 72 | } 73 | } 74 | 75 | override fun getPayload(input: ByteArray): ByteArray? { 76 | return try { 77 | val map = CBORObject.DecodeFromBytes(input) 78 | val hcert = map[CwtHeaderKeys.HCERT.asCBOR()] 79 | hcert[CBORObject.FromObject(1)].EncodeToBytes() 80 | } catch (ex: Exception) { 81 | null 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cbor/DefaultGreenCertificateMapper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by osarapulov on 7/28/21 1:23 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cbor 24 | 25 | import com.fasterxml.jackson.core.JsonParser 26 | import com.fasterxml.jackson.databind.DeserializationContext 27 | import com.fasterxml.jackson.databind.JsonDeserializer 28 | import com.fasterxml.jackson.databind.module.SimpleModule 29 | import com.fasterxml.jackson.dataformat.cbor.databind.CBORMapper 30 | import com.upokecenter.cbor.CBORObject 31 | import dgca.verifier.app.decoder.model.GreenCertificate 32 | 33 | class DefaultGreenCertificateMapper : GreenCertificateMapper, CBORMapper() { 34 | 35 | init { 36 | SimpleModule().apply { 37 | addDeserializer(String::class.java, object : JsonDeserializer() { 38 | override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): String? = p?.valueAsString?.trim() 39 | }) 40 | registerModule(this) 41 | } 42 | 43 | } 44 | 45 | override fun readValue(cborObject: CBORObject): GreenCertificate { 46 | val bytes = cborObject.EncodeToBytes() 47 | return readValue(bytes, GreenCertificate::class.java) 48 | } 49 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cbor/GreenCertificateMapper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by osarapulov on 7/28/21 1:19 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cbor 24 | 25 | import com.upokecenter.cbor.CBORObject 26 | import dgca.verifier.app.decoder.model.GreenCertificate 27 | 28 | interface GreenCertificateMapper { 29 | 30 | fun readValue(cborObject: CBORObject): GreenCertificate 31 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/compression/CompressorService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:50 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.compression 24 | 25 | import dgca.verifier.app.decoder.model.VerificationResult 26 | 27 | /** 28 | * Decompresses input 29 | */ 30 | interface CompressorService { 31 | 32 | fun decode(input: ByteArray, verificationResult: VerificationResult): ByteArray? 33 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cose/CoseService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cose 24 | 25 | import dgca.verifier.app.decoder.model.CoseData 26 | import dgca.verifier.app.decoder.model.VerificationResult 27 | 28 | /** 29 | * Decodes input according to COSE specification (RFC8152) 30 | */ 31 | interface CoseService { 32 | 33 | fun decode(input: ByteArray, verificationResult: VerificationResult): CoseData? 34 | 35 | fun anonymizeCose(input: ByteArray): ByteArray? 36 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cose/CryptoService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 4/24/21 3:09 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cose 24 | 25 | import dgca.verifier.app.decoder.model.CertificateType 26 | import dgca.verifier.app.decoder.model.VerificationResult 27 | import java.security.cert.Certificate 28 | 29 | /** 30 | * Verifies COSE signature 31 | */ 32 | interface CryptoService { 33 | 34 | fun validate(cose: ByteArray, certificate: Certificate, verificationResult: VerificationResult) 35 | 36 | fun validate( 37 | cose: ByteArray, 38 | certificate: Certificate, 39 | verificationResult: VerificationResult, 40 | certificateType: CertificateType 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cose/DefaultCoseService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cose 24 | 25 | import com.google.common.primitives.Bytes 26 | import com.upokecenter.cbor.CBORObject 27 | import dgca.verifier.app.decoder.model.CoseData 28 | import dgca.verifier.app.decoder.model.VerificationResult 29 | 30 | const val HEADER_KID = 4 31 | 32 | /** 33 | * Decodes input according to COSE specification (RFC8152) 34 | */ 35 | class DefaultCoseService : CoseService { 36 | 37 | override fun decode(input: ByteArray, verificationResult: VerificationResult): CoseData? { 38 | return try { 39 | val messageObject = CBORObject.DecodeFromBytes(input) 40 | val content = messageObject[2].GetByteString() 41 | val protectedHeader = messageObject[0].GetByteString() 42 | val unprotectedHeader = messageObject[1] 43 | val kid = getKid(protectedHeader, unprotectedHeader) 44 | val kidByteString = kid?.GetByteString() 45 | CoseData(content, kidByteString) 46 | 47 | } catch (e: Throwable) { 48 | null 49 | } 50 | } 51 | 52 | private fun getKid(protectedHeader: ByteArray, unprotectedHeader: CBORObject): CBORObject? { 53 | val key = CBORObject.FromObject(HEADER_KID) 54 | return if (protectedHeader.isNotEmpty()) { 55 | try { 56 | val kid = CBORObject.DecodeFromBytes(protectedHeader).get(key) 57 | kid ?: unprotectedHeader.get(key) 58 | } catch (ex: Exception) { 59 | unprotectedHeader.get(key) 60 | } 61 | } else { 62 | unprotectedHeader.get(key) 63 | } 64 | } 65 | 66 | override fun anonymizeCose(input: ByteArray): ByteArray? { 67 | return try { 68 | val messageObject = CBORObject.DecodeFromBytes(input) 69 | 70 | val content = messageObject[2].EncodeToBytes() 71 | val index = Bytes.indexOf(input, content) 72 | 73 | val newArray = ByteArray(input.size) 74 | 75 | val anonymize = ByteArray(content.size) 76 | anonymize.forEachIndexed { i, _ -> 77 | anonymize[i] = 0x58 78 | } 79 | 80 | System.arraycopy(input, 0, newArray, 0, index) 81 | System.arraycopy(anonymize, 0, newArray, index, anonymize.size) 82 | System.arraycopy( 83 | input, 84 | index + anonymize.size, 85 | newArray, 86 | index + anonymize.size, 87 | input.size - (anonymize.size + index) 88 | ) 89 | 90 | newArray 91 | 92 | } catch (e: Throwable) { 93 | null 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/cwt/CwtHeaderKeys.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cwt 24 | 25 | import com.upokecenter.cbor.CBORObject 26 | 27 | /** 28 | * Adapted from [COSE.HeaderKeys] to use CWT specific ones (https://tools.ietf.org/html/rfc8392) 29 | */ 30 | @Suppress("ClassName") 31 | sealed class CwtHeaderKeys(value: Int) { 32 | 33 | private val value: CBORObject = CBORObject.FromObject(value) 34 | 35 | fun asCBOR(): CBORObject { 36 | return value 37 | } 38 | 39 | object ISSUING_COUNTRY : CwtHeaderKeys(1) 40 | object EXPIRATION : CwtHeaderKeys(4) 41 | object ISSUED_AT : CwtHeaderKeys(6) 42 | object HCERT : CwtHeaderKeys(-260) 43 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/CertificateType.kt: -------------------------------------------------------------------------------- 1 | package dgca.verifier.app.decoder.model 2 | 3 | enum class CertificateType { 4 | UNKNOWN, VACCINATION, RECOVERY, TEST 5 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/CoseData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 4/24/21 3:42 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | data class CoseData( 26 | val cbor: ByteArray, 27 | val kid: ByteArray? = null 28 | ) { 29 | 30 | override fun equals(other: Any?): Boolean { 31 | if (this === other) return true 32 | if (javaClass != other?.javaClass) return false 33 | 34 | other as CoseData 35 | 36 | if (!cbor.contentEquals(other.cbor)) return false 37 | if (kid != null) { 38 | if (other.kid == null) return false 39 | if (!kid.contentEquals(other.kid)) return false 40 | } else if (other.kid != null) return false 41 | 42 | return true 43 | } 44 | 45 | override fun hashCode(): Int { 46 | var result = cbor.contentHashCode() 47 | result = 31 * result + (kid?.contentHashCode() ?: 0) 48 | return result 49 | } 50 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/GreenCertificate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 26 | import com.fasterxml.jackson.annotation.JsonProperty 27 | import java.io.Serializable 28 | import java.util.* 29 | 30 | /** 31 | * CBOR structure of the certificate 32 | */ 33 | @JsonIgnoreProperties(ignoreUnknown = true) 34 | data class GreenCertificate( 35 | 36 | @JsonProperty("ver") 37 | val schemaVersion: String, 38 | 39 | @JsonProperty("nam") 40 | val person: Person, 41 | 42 | @JsonProperty("dob") 43 | val dateOfBirth: String, 44 | 45 | @JsonProperty("v") 46 | val vaccinations: List?, 47 | 48 | @JsonProperty("t") 49 | val tests: List?, 50 | 51 | @JsonProperty("r") 52 | val recoveryStatements: List? 53 | 54 | ) : Serializable { 55 | 56 | fun getDgci(): String { 57 | return try { 58 | return when { 59 | vaccinations?.isNotEmpty() == true -> vaccinations.last().certificateIdentifier 60 | tests?.isNotEmpty() == true -> tests.last().certificateIdentifier 61 | recoveryStatements?.isNotEmpty() == true -> recoveryStatements.last().certificateIdentifier 62 | else -> "" 63 | } 64 | } catch (ex: Exception) { 65 | "" 66 | } 67 | } 68 | 69 | fun getIssuingCountry(): String = try { 70 | when { 71 | vaccinations?.isNotEmpty() == true -> vaccinations.last().countryOfVaccination 72 | tests?.isNotEmpty() == true -> tests.last().countryOfVaccination 73 | recoveryStatements?.isNotEmpty() == true -> recoveryStatements.last().countryOfVaccination 74 | else -> "" 75 | } 76 | } catch (ex: Exception) { 77 | "" 78 | }.toLowerCase(Locale.ROOT) 79 | 80 | fun getType(): CertificateType { 81 | if (vaccinations?.isNotEmpty() == true) 82 | return CertificateType.VACCINATION 83 | if (tests?.isNotEmpty() == true) return CertificateType.TEST 84 | if (recoveryStatements?.isNotEmpty() == true) return CertificateType.RECOVERY 85 | return CertificateType.UNKNOWN 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/KeyPairData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 5/12/21 12:42 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | import java.security.KeyPair 26 | 27 | data class KeyPairData( 28 | val algo: String, 29 | val keyPair: KeyPair 30 | ) -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/Person.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 4/30/21 1:25 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | import com.fasterxml.jackson.annotation.JsonProperty 26 | import java.io.Serializable 27 | 28 | data class Person( 29 | 30 | @JsonProperty("fnt") 31 | val standardisedFamilyName: String, 32 | 33 | @JsonProperty("fn") 34 | val familyName: String?, 35 | 36 | @JsonProperty("gnt") 37 | val standardisedGivenName: String?, 38 | 39 | @JsonProperty("gn") 40 | val givenName: String? 41 | 42 | ) : Serializable -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/RecoveryStatement.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 4/30/21 1:59 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 26 | import com.fasterxml.jackson.annotation.JsonProperty 27 | import java.io.Serializable 28 | import java.time.* 29 | 30 | @JsonIgnoreProperties(ignoreUnknown = true) 31 | data class RecoveryStatement( 32 | 33 | @JsonProperty("tg") 34 | val disease: String, 35 | 36 | @JsonProperty("fr") 37 | val dateOfFirstPositiveTest: String, 38 | 39 | @JsonProperty("co") 40 | val countryOfVaccination: String, 41 | 42 | @JsonProperty("is") 43 | val certificateIssuer: String, 44 | 45 | @JsonProperty("df") 46 | val certificateValidFrom: String, 47 | 48 | @JsonProperty("du") 49 | val certificateValidUntil: String, 50 | 51 | @JsonProperty("ci") 52 | val certificateIdentifier: String 53 | 54 | ) : Serializable { 55 | 56 | fun isCertificateNotValidAnymore(): Boolean? = 57 | certificateValidUntil.toZonedDateTimeOrUtcLocal()?.isBefore(ZonedDateTime.now()) 58 | 59 | fun isCertificateNotValidSoFar(): Boolean? = 60 | certificateValidFrom.toZonedDateTimeOrUtcLocal()?.isAfter(ZonedDateTime.now()) 61 | 62 | private fun String.toZonedDateTime(): ZonedDateTime? = try { 63 | ZonedDateTime.parse(this) 64 | } catch (error: Throwable) { 65 | null 66 | } 67 | 68 | private fun String.toLocalDateTime(): LocalDateTime? = try { 69 | LocalDateTime.parse(this) 70 | } catch (error: Throwable) { 71 | null 72 | } 73 | 74 | private fun String.toLocalDate(): LocalDate? = try { 75 | LocalDate.parse(this) 76 | } catch (error: Throwable) { 77 | null 78 | } 79 | 80 | private fun String.toZonedDateTimeOrUtcLocal(): ZonedDateTime? = 81 | this.toZonedDateTime()?.withZoneSameInstant(UTC_ZONE_ID) ?: this.toLocalDateTime() 82 | ?.atZone(UTC_ZONE_ID) ?: this.toLocalDate()?.atStartOfDay(UTC_ZONE_ID) 83 | 84 | companion object { 85 | private val UTC_ZONE_ID: ZoneId = ZoneId.ofOffset("", ZoneOffset.UTC).normalized() 86 | } 87 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 4/30/21 1:44 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 26 | import com.fasterxml.jackson.annotation.JsonProperty 27 | import java.io.Serializable 28 | import java.time.OffsetDateTime 29 | import java.time.ZoneOffset 30 | import java.time.format.DateTimeFormatter 31 | 32 | @JsonIgnoreProperties(ignoreUnknown = true) 33 | data class Test( 34 | 35 | @JsonProperty("tg") 36 | val disease: String, 37 | 38 | @JsonProperty("tt") 39 | val typeOfTest: String, 40 | 41 | @JsonProperty("nm") 42 | val testName: String?, 43 | 44 | @JsonProperty("ma") 45 | val testNameAndManufacturer: String?, 46 | 47 | @JsonProperty("sc") 48 | val dateTimeOfCollection: String, 49 | 50 | @JsonProperty("dr") 51 | val dateTimeOfTestResult: String?, 52 | 53 | @JsonProperty("tr") 54 | val testResult: String, 55 | 56 | @JsonProperty("tc") 57 | val testingCentre: String, 58 | 59 | @JsonProperty("co") 60 | val countryOfVaccination: String, 61 | 62 | @JsonProperty("is") 63 | val certificateIssuer: String, 64 | 65 | @JsonProperty("ci") 66 | val certificateIdentifier: String 67 | 68 | ) : Serializable { 69 | 70 | fun isResultNegative(): Boolean = testResult == TestResult.NOT_DETECTED.value 71 | 72 | fun isDateInThePast(): Boolean = parseToUtcTimestamp(dateTimeOfCollection).isBefore(OffsetDateTime.now()) 73 | 74 | fun getTestResultType(): TestResult { 75 | return when (testResult) { 76 | TestResult.DETECTED.value -> TestResult.DETECTED 77 | TestResult.NOT_DETECTED.value -> TestResult.NOT_DETECTED 78 | else -> TestResult.NOT_DETECTED 79 | } 80 | } 81 | 82 | private fun parseToUtcTimestamp(value: String?): OffsetDateTime { 83 | if (value.isNullOrEmpty()) { 84 | return OffsetDateTime.MAX 85 | } 86 | 87 | return try { 88 | DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(value, OffsetDateTime::from).withOffsetSameInstant(ZoneOffset.UTC) 89 | } catch (ex: Exception) { 90 | OffsetDateTime.MAX 91 | } 92 | } 93 | 94 | enum class TestResult(val value: String) { 95 | DETECTED("260373001"), 96 | NOT_DETECTED("260415000") 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/model/Vaccination.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by mykhailo.nester on 4/30/21 1:29 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.model 24 | 25 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 26 | import com.fasterxml.jackson.annotation.JsonProperty 27 | import org.joda.time.DateTime 28 | import java.io.Serializable 29 | import java.time.OffsetDateTime 30 | 31 | @JsonIgnoreProperties(ignoreUnknown = true) 32 | data class Vaccination( 33 | 34 | @JsonProperty("tg") 35 | val disease: String, 36 | 37 | @JsonProperty("vp") 38 | val vaccine: String, 39 | 40 | @JsonProperty("mp") 41 | val medicinalProduct: String, 42 | 43 | @JsonProperty("ma") 44 | val manufacturer: String, 45 | 46 | @JsonProperty("dn") 47 | val doseNumber: Int, 48 | 49 | @JsonProperty("sd") 50 | val totalSeriesOfDoses: Int, 51 | 52 | @JsonProperty("dt") 53 | val dateOfVaccination: String, 54 | 55 | @JsonProperty("co") 56 | val countryOfVaccination: String, 57 | 58 | @JsonProperty("is") 59 | val certificateIssuer: String, 60 | 61 | @JsonProperty("ci") 62 | val certificateIdentifier: String, 63 | 64 | ) : Serializable { 65 | 66 | fun isDateInThePast(): Boolean = 67 | try { 68 | DateTime.parse(dateOfVaccination).millis < OffsetDateTime.now().toEpochSecond() * 1000 69 | } catch (ex: Exception) { 70 | false 71 | } 72 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/prefixvalidation/DefaultPrefixValidationService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.prefixvalidation 24 | 25 | import dgca.verifier.app.decoder.model.VerificationResult 26 | 27 | /** 28 | * Drops a country-specific prefix from contents, e.g. "HC1:" 29 | */ 30 | class DefaultPrefixValidationService(private val prefix: String = "HC1:") : PrefixValidationService { 31 | 32 | override fun decode(input: String, verificationResult: VerificationResult): String = when { 33 | input.startsWith(prefix) -> input.drop(prefix.length).also { verificationResult.contextPrefix = prefix } 34 | else -> input.also { verificationResult.contextPrefix = null } 35 | } 36 | 37 | override fun encode(input: String): String = when { 38 | input.startsWith(prefix) -> input 39 | else -> "$prefix$input" 40 | } 41 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/prefixvalidation/PrefixValidationService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.prefixvalidation 24 | 25 | import dgca.verifier.app.decoder.model.VerificationResult 26 | 27 | /** 28 | * Drops prefix from input 29 | */ 30 | interface PrefixValidationService { 31 | 32 | fun decode(input: String, verificationResult: VerificationResult): String 33 | 34 | fun encode(input: String): String 35 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/schema/DefaultSchemaValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:51 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.schema 24 | 25 | import com.fasterxml.jackson.databind.JsonNode 26 | import com.fasterxml.jackson.databind.ObjectMapper 27 | import com.github.fge.jsonschema.core.report.ProcessingReport 28 | import com.github.fge.jsonschema.main.JsonSchema 29 | import com.github.fge.jsonschema.main.JsonSchemaFactory 30 | import com.upokecenter.cbor.CBORObject 31 | import dgca.verifier.app.decoder.JSON_SCHEMA_V1 32 | import dgca.verifier.app.decoder.cwt.CwtHeaderKeys 33 | import dgca.verifier.app.decoder.model.VerificationResult 34 | 35 | /** 36 | * Verifies CBOR with predefined schema 37 | * 38 | * @see JSON_SCHEMA_V1 39 | */ 40 | class DefaultSchemaValidator : SchemaValidator { 41 | 42 | override fun validate(cbor: ByteArray, verificationResult: VerificationResult): Boolean { 43 | var isValid = false 44 | try { 45 | val map = CBORObject.DecodeFromBytes(cbor) 46 | val hcert = map[CwtHeaderKeys.HCERT.asCBOR()] 47 | val json = hcert[CBORObject.FromObject(1)].ToJSONString() 48 | 49 | val mapper = ObjectMapper() 50 | val schemaNode: JsonNode = mapper.readTree(JSON_SCHEMA_V1) 51 | val jsonNode: JsonNode = mapper.readTree(json) 52 | 53 | val factory = JsonSchemaFactory.byDefault() 54 | val schema: JsonSchema = factory.getJsonSchema(schemaNode) 55 | 56 | val report: ProcessingReport = schema.validate(jsonNode) 57 | 58 | isValid = report.isSuccess 59 | verificationResult.isSchemaValid = isValid 60 | 61 | } catch (ex: Exception) { 62 | } 63 | 64 | return isValid 65 | } 66 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/schema/SchemaValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by Mykhailo Nester on 4/23/21 9:52 AM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.schema 24 | 25 | import dgca.verifier.app.decoder.model.VerificationResult 26 | 27 | /** 28 | * Verifies CBOR schema 29 | */ 30 | interface SchemaValidator { 31 | 32 | fun validate(cbor: ByteArray, verificationResult: VerificationResult): Boolean 33 | } -------------------------------------------------------------------------------- /decoder/src/main/java/dgca/verifier/app/decoder/services/X509.kt: -------------------------------------------------------------------------------- 1 | package dgca.verifier.app.decoder.services 2 | 3 | import dgca.verifier.app.decoder.model.CertificateType 4 | import java.io.ByteArrayInputStream 5 | import java.security.cert.* 6 | 7 | 8 | class X509 { 9 | 10 | private val OID_TEST = "1.3.6.1.4.1.1847.2021.1.1" 11 | private val OID_ALT_TEST = "1.3.6.1.4.1.0.1847.2021.1.1" 12 | private val OID_VACCINATION = "1.3.6.1.4.1.1847.2021.1.2" 13 | private val OID_ALT_VACCINATION = "1.3.6.1.4.1.0.1847.2021.1.2" 14 | private val OID_RECOVERY = "1.3.6.1.4.1.1847.2021.1.3" 15 | private val OID_ALT_RECOVERY = "1.3.6.1.4.1.0.1847.2021.1.3" 16 | 17 | fun checkIsSuitable(cert: String?, certType: CertificateType?): Boolean { 18 | val b64: ByteArray = org.bouncycastle.util.encoders.Base64.decode(cert) 19 | return isSuitable(b64, certType) 20 | } 21 | 22 | fun isSuitable(data: ByteArray?, certificateType: CertificateType?): Boolean { 23 | try { 24 | val cf: CertificateFactory = CertificateFactory.getInstance("X.509") 25 | val cert: Certificate = cf.generateCertificate(ByteArrayInputStream(data)) 26 | if (isType(cert as X509Certificate)) { 27 | val extendedKeys = cert.extendedKeyUsage 28 | return when (certificateType) { 29 | CertificateType.TEST -> extendedKeys.contains(OID_TEST) || extendedKeys.contains( 30 | OID_ALT_TEST 31 | ) 32 | CertificateType.VACCINATION -> extendedKeys.contains(OID_VACCINATION) || extendedKeys.contains( 33 | OID_ALT_VACCINATION 34 | ) 35 | CertificateType.RECOVERY -> extendedKeys.contains(OID_RECOVERY) || extendedKeys.contains( 36 | OID_ALT_RECOVERY 37 | ) 38 | CertificateType.UNKNOWN -> false 39 | else -> false 40 | } 41 | } 42 | } catch (e: CertificateException) { 43 | return false 44 | } 45 | return true 46 | } 47 | 48 | private fun isType(certificate: X509Certificate): Boolean { 49 | return try { 50 | val extendedKeyUsage: List = certificate.extendedKeyUsage ?: return false 51 | 52 | extendedKeyUsage.contains(OID_TEST) 53 | || extendedKeyUsage.contains(OID_ALT_TEST) 54 | || extendedKeyUsage.contains(OID_RECOVERY) 55 | || extendedKeyUsage.contains(OID_ALT_RECOVERY) 56 | || extendedKeyUsage.contains(OID_VACCINATION) 57 | || extendedKeyUsage.contains(OID_ALT_VACCINATION) 58 | } catch (e: CertificateParsingException) { 59 | false 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /decoder/src/test/java/dgca/verifier/app/decoder/CertificateCheckTest.kt: -------------------------------------------------------------------------------- 1 | package dgca.verifier.app.decoder 2 | 3 | import dgca.verifier.app.decoder.model.RecoveryStatement 4 | import org.junit.Assert 5 | import org.junit.Test 6 | 7 | class CertificateCheckTest { 8 | @Test 9 | fun TestTestValidity() { 10 | val test = dgca.verifier.app.decoder.model.Test( 11 | "12", 12 | "", 13 | "", 14 | "", 15 | "2021-02-20T12:34:56Z", 16 | "", 17 | "260415000", 18 | "", 19 | "", 20 | "", 21 | "" 22 | ) 23 | Assert.assertTrue(test.isDateInThePast()) 24 | Assert.assertTrue(test.isResultNegative()) 25 | } 26 | 27 | @Test 28 | fun testIsCertificateNotValidAnymore() { 29 | var recovery = RecoveryStatement("", "", "", "", "", "2021-03-04", "") 30 | Assert.assertTrue(recovery.isCertificateNotValidAnymore()!!) 31 | recovery = RecoveryStatement("", "", "", "", "", "2030-02-04", "") 32 | Assert.assertTrue(!recovery.isCertificateNotValidAnymore()!!) 33 | recovery = RecoveryStatement("", "", "", "", "", "2021-02-20T12:34:56Z", "") 34 | Assert.assertTrue(recovery.isCertificateNotValidAnymore()!!) 35 | recovery = RecoveryStatement("", "", "", "", "", "2007-12-03T10:15:30+01:00", "") 36 | Assert.assertTrue(recovery.isCertificateNotValidAnymore()!!) 37 | } 38 | 39 | @Test 40 | fun testIsCertificateNotValidSoFar() { 41 | var recovery = RecoveryStatement("", "", "", "", "2100-03-04", "", "") 42 | Assert.assertTrue(recovery.isCertificateNotValidSoFar()!!) 43 | recovery = RecoveryStatement("", "", "", "", "2000-02-04", "", "") 44 | Assert.assertTrue(!recovery.isCertificateNotValidSoFar()!!) 45 | recovery = RecoveryStatement("", "", "", "", "2100-02-20T12:34:56Z", "", "") 46 | Assert.assertTrue(recovery.isCertificateNotValidSoFar()!!) 47 | recovery = RecoveryStatement("", "", "", "", "2100-12-03T10:15:30+01:00", "", "") 48 | Assert.assertTrue(recovery.isCertificateNotValidSoFar()!!) 49 | } 50 | 51 | @Test 52 | fun testCertificateValidity() { 53 | val recovery = RecoveryStatement("", "", "", "", "", "", "") 54 | Assert.assertNull(recovery.isCertificateNotValidSoFar()) 55 | Assert.assertNull(recovery.isCertificateNotValidAnymore()) 56 | } 57 | } -------------------------------------------------------------------------------- /decoder/src/test/java/dgca/verifier/app/decoder/TestCase.kt: -------------------------------------------------------------------------------- 1 | package dgca.verifier.app.decoder 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import dgca.verifier.app.decoder.model.GreenCertificate 5 | 6 | data class TestCase( 7 | 8 | @JsonProperty("JSON") 9 | val eudgc: GreenCertificate? = null, 10 | 11 | @JsonProperty("CBOR") 12 | val cborHex: String? = null, 13 | 14 | @JsonProperty("COSE") 15 | val coseHex: String? = null, 16 | 17 | @JsonProperty("COMPRESSED") 18 | val compressedHex: String? = null, 19 | 20 | @JsonProperty("BASE45") 21 | val base45: String? = null, 22 | 23 | @JsonProperty("PREFIX") 24 | val base45WithPrefix: String? = null, 25 | 26 | @JsonProperty("2DCODE") 27 | val qrCodePng: String? = null, 28 | 29 | @JsonProperty("TESTCTX") 30 | val context: TestContext, 31 | 32 | @JsonProperty("EXPECTEDRESULTS") 33 | val expectedResult: TestExpectedResults 34 | ) 35 | 36 | data class TestContext( 37 | 38 | @JsonProperty("VERSION") 39 | val version: Int, 40 | 41 | @JsonProperty("SCHEMA") 42 | val schema: String, 43 | 44 | @JsonProperty("CERTIFICATE") 45 | val certificate: String?, 46 | 47 | @JsonProperty("VALIDATIONCLOCK") 48 | val validationClock: String?, 49 | 50 | @JsonProperty("DESCRIPTION") 51 | val description: String 52 | ) 53 | 54 | data class TestExpectedResults( 55 | 56 | @JsonProperty("EXPECTEDVALIDOBJECT") 57 | val schemaGeneration: Boolean? = null, 58 | 59 | @JsonProperty("EXPECTEDSCHEMAVALIDATION") 60 | val schemaValidation: Boolean? = null, 61 | 62 | @JsonProperty("EXPECTEDENCODE") 63 | val encodeGeneration: Boolean? = null, 64 | 65 | @JsonProperty("EXPECTEDDECODE") 66 | val cborDecode: Boolean? = null, 67 | 68 | @JsonProperty("EXPECTEDVERIFY") 69 | val coseSignature: Boolean? = null, 70 | 71 | @JsonProperty("EXPECTEDUNPREFIX") 72 | val prefix: Boolean? = null, 73 | 74 | @JsonProperty("EXPECTEDVALIDJSON") 75 | val json: Boolean? = null, 76 | 77 | @JsonProperty("EXPECTEDCOMPRESSION") 78 | val compression: Boolean? = null, 79 | 80 | @JsonProperty("EXPECTEDB45DECODE") 81 | val base45Decode: Boolean? = null, 82 | 83 | @JsonProperty("EXPECTEDPICTUREDECODE") 84 | val qrDecode: Boolean? = null, 85 | 86 | @JsonProperty("EXPECTEDEXPIRATIONCHECK") 87 | val expirationCheck: Boolean? = null, 88 | 89 | @JsonProperty("EXPECTEDKEYUSAGE") 90 | val keyUsage: Boolean? = null 91 | ) -------------------------------------------------------------------------------- /decoder/src/test/java/dgca/verifier/app/decoder/cbor/DefaultGreenCertificateMapperTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-verifier-app-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | * 20 | * Created by osarapulov on 7/28/21 1:32 PM 21 | */ 22 | 23 | package dgca.verifier.app.decoder.cbor 24 | 25 | import com.upokecenter.cbor.CBORObject 26 | import dgca.verifier.app.decoder.model.GreenCertificate 27 | import org.junit.Assert.assertEquals 28 | import org.junit.Test 29 | 30 | internal class DefaultGreenCertificateMapperTest { 31 | val JSON = "{\n" + 32 | " \"t\": [\n" + 33 | " {\n" + 34 | " \"sc\": \" 2021-07-26T21:00:00Z \",\n" + 35 | " \"ma\": \" 1223 \",\n" + 36 | " \"tt\": \" LP217198-3 \",\n" + 37 | " \"tc\": \" Custom Testing Centre \",\n" + 38 | " \"co\": \" FR \",\n" + 39 | " \"ci\": \" URN:UVCI:V1:DE:O39BNVCVNHTRMKY0E9DYT4A43T \",\n" + 40 | " \"is\": \" Custom Issuer Certifcate \",\n" + 41 | " \"tg\": \" 840539006 \",\n" + 42 | " \"tr\": \" 260415000 \"\n" + 43 | " }\n" + 44 | " ],\n" + 45 | " \"nam\": {\n" + 46 | " \"fnt\": \" STANDARDISEDFAMILY \"\n" + 47 | " },\n" + 48 | " \"ver\": \" 1.3.0 \",\n" + 49 | " \"dob\": \" \"\n" + 50 | "}" 51 | 52 | 53 | @Test 54 | fun test() { 55 | val greenCertificateMapper = DefaultGreenCertificateMapper() 56 | val cborObject = CBORObject.FromJSONString(JSON) 57 | val greenCertificate: GreenCertificate = 58 | greenCertificateMapper.readValue(cborObject) 59 | val testingCenter: String = greenCertificate.tests!!.first().testingCentre 60 | assertEquals(testingCenter.trim(), testingCenter) 61 | } 62 | } -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.base45/-base45-decode-exception/get-cause.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getCause 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.base45/Base45DecodeException/getCause 47 | 48 | getCause 49 | 50 | Throwable getCause()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.base45/-base45-decode-exception/get-message.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getMessage 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.base45/Base45DecodeException/getMessage 47 | 48 | getMessage 49 | 50 | String getMessage()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.base45/-base45-decoder/-base45-decoder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Base45Decoder 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.base45/Base45Decoder/Base45Decoder 47 | 48 | Base45Decoder 49 | 50 | Base45Decoder Base45Decoder()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.base45/-default-base45-service/-default-base45-service.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultBase45Service 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.base45/DefaultBase45Service/DefaultBase45Service 47 | 48 | DefaultBase45Service 49 | 50 | DefaultBase45Service DefaultBase45Service()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.cose/-default-cose-service/-default-cose-service.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCoseService 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.cose/DefaultCoseService/DefaultCoseService 47 | 48 | DefaultCoseService 49 | 50 | DefaultCoseService DefaultCoseService()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.cwt/-cwt-header-keys/as-c-b-o-r.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | asCBOR 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.cwt/CwtHeaderKeys/asCBOR 47 | 48 | asCBOR 49 | 50 | final CBORObject asCBOR()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-certificate-type/get-name.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getName 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/CertificateType/getName 47 | 48 | getName 49 | 50 | final String getName()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-certificate-type/get-ordinal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getOrdinal 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/CertificateType/getOrdinal 47 | 48 | getOrdinal 49 | 50 | final Integer getOrdinal()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-cose-data/get-cbor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getCbor 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/CoseData/getCbor 47 | 48 | getCbor 49 | 50 | final ByteArray getCbor()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-cose-data/get-kid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getKid 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/CoseData/getKid 47 | 48 | getKid 49 | 50 | final ByteArray getKid()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-cose-data/hash-code.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | hashCode 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/CoseData/hashCode 47 | 48 | hashCode 49 | 50 | Integer hashCode()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-green-certificate/get-dgci.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getDgci 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/GreenCertificate/getDgci 47 | 48 | getDgci 49 | 50 | final String getDgci()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-green-certificate/get-person.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getPerson 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/GreenCertificate/getPerson 47 | 48 | getPerson 49 | 50 | final Person getPerson()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-green-certificate/get-type.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getType 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/GreenCertificate/getType 47 | 48 | getType 49 | 50 | final CertificateType getType()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-key-pair-data/get-algo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getAlgo 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/KeyPairData/getAlgo 47 | 48 | getAlgo 49 | 50 | final String getAlgo()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-key-pair-data/get-key-pair.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getKeyPair 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/KeyPairData/getKeyPair 47 | 48 | getKeyPair 49 | 50 | final KeyPair getKeyPair()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-person/get-family-name.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getFamilyName 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Person/getFamilyName 47 | 48 | getFamilyName 49 | 50 | final String getFamilyName()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-person/get-given-name.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getGivenName 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Person/getGivenName 47 | 48 | getGivenName 49 | 50 | final String getGivenName()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-recovery-statement/get-disease.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getDisease 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/RecoveryStatement/getDisease 47 | 48 | getDisease 49 | 50 | final String getDisease()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-test/get-disease.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getDisease 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Test/getDisease 47 | 48 | getDisease 49 | 50 | final String getDisease()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-test/get-test-name.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getTestName 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Test/getTestName 47 | 48 | getTestName 49 | 50 | final String getTestName()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-test/get-test-result-type.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getTestResultType 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Test/getTestResultType 47 | 48 | getTestResultType 49 | 50 | final Test.TestResult getTestResultType()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-test/get-test-result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getTestResult 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Test/getTestResult 47 | 48 | getTestResult 49 | 50 | final String getTestResult()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-test/get-testing-centre.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getTestingCentre 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Test/getTestingCentre 47 | 48 | getTestingCentre 49 | 50 | final String getTestingCentre()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-test/get-type-of-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getTypeOfTest 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Test/getTypeOfTest 47 | 48 | getTypeOfTest 49 | 50 | final String getTypeOfTest()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-vaccination/get-disease.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getDisease 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Vaccination/getDisease 47 | 48 | getDisease 49 | 50 | final String getDisease()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-vaccination/get-dose-number.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getDoseNumber 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Vaccination/getDoseNumber 47 | 48 | getDoseNumber 49 | 50 | final Integer getDoseNumber()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-vaccination/get-manufacturer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getManufacturer 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Vaccination/getManufacturer 47 | 48 | getManufacturer 49 | 50 | final String getManufacturer()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-vaccination/get-vaccine.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getVaccine 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/Vaccination/getVaccine 47 | 48 | getVaccine 49 | 50 | final String getVaccine()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-verification-result/is-valid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | isValid 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/VerificationResult/isValid 47 | 48 | isValid 49 | 50 | final Boolean isValid()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.model/-verification-result/to-string.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | toString 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.model/VerificationResult/toString 47 | 48 | toString 49 | 50 | String toString()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder.services/-x509/-x509.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | X509 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder.services/X509/X509 47 | 48 | X509 49 | 50 | X509 X509()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/decoder/dgca.verifier.app.decoder/-certificate-decoding-error/get-error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | getError 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | decoder 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | decoder/dgca.verifier.app.decoder/CertificateDecodingError/getError 47 | 48 | getError 49 | 50 | final Throwable getError()Content copied to clipboard 51 | 52 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dokka/html/images/anchor-copy-button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dokka/html/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dokka/html/images/copy-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dokka/html/images/copy-successful-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dokka/html/images/footer-go-to-link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dokka/html/images/go-to-top-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /dokka/html/images/logo-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /dokka/html/images/theme-toggle.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /dokka/html/scripts/clipboard.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', () => { 2 | document.querySelectorAll('span.copy-icon').forEach(element => { 3 | element.addEventListener('click', (el) => copyElementsContentToClipboard(element)); 4 | }) 5 | 6 | document.querySelectorAll('span.anchor-icon').forEach(element => { 7 | element.addEventListener('click', (el) => { 8 | if(element.hasAttribute('pointing-to')){ 9 | const location = hrefWithoutCurrentlyUsedAnchor() + '#' + element.getAttribute('pointing-to') 10 | copyTextToClipboard(element, location) 11 | } 12 | }); 13 | }) 14 | }) 15 | 16 | const copyElementsContentToClipboard = (element) => { 17 | const selection = window.getSelection(); 18 | const range = document.createRange(); 19 | range.selectNodeContents(element.parentNode.parentNode); 20 | selection.removeAllRanges(); 21 | selection.addRange(range); 22 | 23 | copyAndShowPopup(element, () => selection.removeAllRanges()) 24 | } 25 | 26 | const copyTextToClipboard = (element, text) => { 27 | var textarea = document.createElement("textarea"); 28 | textarea.textContent = text; 29 | textarea.style.position = "fixed"; 30 | document.body.appendChild(textarea); 31 | textarea.select(); 32 | 33 | copyAndShowPopup(element, () => document.body.removeChild(textarea)) 34 | } 35 | 36 | const copyAndShowPopup = (element, after) => { 37 | try { 38 | document.execCommand('copy'); 39 | element.nextElementSibling.classList.add('active-popup'); 40 | setTimeout(() => { 41 | element.nextElementSibling.classList.remove('active-popup'); 42 | }, 1200); 43 | } catch (e) { 44 | console.error('Failed to write to clipboard:', e) 45 | } 46 | finally { 47 | if(after) after() 48 | } 49 | } 50 | 51 | const hrefWithoutCurrentlyUsedAnchor = () => window.location.href.split('#')[0] 52 | 53 | -------------------------------------------------------------------------------- /dokka/html/scripts/navigation-loader.js: -------------------------------------------------------------------------------- 1 | navigationPageText = fetch(pathToRoot + "navigation.html").then(response => response.text()) 2 | 3 | displayNavigationFromPage = () => { 4 | navigationPageText.then(data => { 5 | document.getElementById("sideMenu").innerHTML = data; 6 | }).then(() => { 7 | document.querySelectorAll(".overview > a").forEach(link => { 8 | link.setAttribute("href", pathToRoot + link.getAttribute("href")); 9 | }) 10 | }).then(() => { 11 | document.querySelectorAll(".sideMenuPart").forEach(nav => { 12 | if (!nav.classList.contains("hidden")) 13 | nav.classList.add("hidden") 14 | }) 15 | }).then(() => { 16 | revealNavigationForCurrentPage() 17 | }) 18 | document.querySelectorAll('.footer a[href^="#"]').forEach(anchor => { 19 | anchor.addEventListener('click', function (e) { 20 | e.preventDefault(); 21 | document.querySelector(this.getAttribute('href')).scrollIntoView({ 22 | behavior: 'smooth' 23 | }); 24 | }); 25 | }); 26 | } 27 | 28 | revealNavigationForCurrentPage = () => { 29 | let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); 30 | let parts = document.querySelectorAll(".sideMenuPart"); 31 | let found = 0; 32 | do { 33 | parts.forEach(part => { 34 | if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { 35 | found = 1; 36 | if (part.classList.contains("hidden")) { 37 | part.classList.remove("hidden"); 38 | part.setAttribute('data-active', ""); 39 | } 40 | revealParents(part) 41 | } 42 | }); 43 | pageId = pageId.substring(0, pageId.lastIndexOf("/")) 44 | } while (pageId.indexOf("/") !== -1 && found === 0) 45 | }; 46 | revealParents = (part) => { 47 | if (part.classList.contains("sideMenuPart")) { 48 | if (part.classList.contains("hidden")) 49 | part.classList.remove("hidden"); 50 | revealParents(part.parentNode) 51 | } 52 | }; 53 | 54 | /* 55 | This is a work-around for safari being IE of our times. 56 | It doesn't fire a DOMContentLoaded, presumabely because eventListener is added after it wants to do it 57 | */ 58 | if (document.readyState == 'loading') { 59 | window.addEventListener('DOMContentLoaded', () => { 60 | displayNavigationFromPage() 61 | }) 62 | } else { 63 | displayNavigationFromPage() 64 | } -------------------------------------------------------------------------------- /dokka/html/scripts/sourceset_dependencies.js: -------------------------------------------------------------------------------- 1 | sourceset_dependencies='{":decoder:dokkaHtml/androidTestRelease":[],":decoder:dokkaHtml/debug":[],":decoder:dokkaHtml/main":[],":decoder:dokkaHtml/release":[]}' 2 | -------------------------------------------------------------------------------- /dokka/html/styles/jetbrains-mono.css: -------------------------------------------------------------------------------- 1 | @font-face{ 2 | font-family: 'JetBrains Mono'; 3 | src: url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/web/JetBrainsMono-Regular.eot') format('embedded-opentype'), 4 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/webfonts/JetBrainsMono-Regular.woff2') format('woff2'), 5 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/ttf/JetBrainsMono-Regular.ttf') format('truetype'); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | @font-face{ 11 | font-family: 'JetBrains Mono'; 12 | src: url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/web/JetBrainsMono-Bold.eot') format('embedded-opentype'), 13 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/webfonts/JetBrainsMono-Bold.woff2') format('woff2'), 14 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/ttf/JetBrainsMono-Bold.ttf') format('truetype'); 15 | font-weight: bold; 16 | font-style: bold; 17 | } -------------------------------------------------------------------------------- /dokka/html/styles/logo-styles.css: -------------------------------------------------------------------------------- 1 | .library-name a { 2 | position: relative; 3 | margin-left: 55px; 4 | } 5 | 6 | .library-name a::before { 7 | content: ''; 8 | background: url("../images/logo-icon.svg") center no-repeat; 9 | background-size: contain; 10 | position: absolute; 11 | width: 50px; 12 | height: 50px; 13 | top: -18px; 14 | left: -55px; 15 | } -------------------------------------------------------------------------------- /dokka/html/styles/prism.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --keyword-color: #07a; 3 | --property-color: #905; 4 | --function-color: #DD4A68; 5 | } 6 | 7 | :root.theme-dark { 8 | --keyword-color: #cc7832; 9 | --property-color: #9876aa; 10 | --function-color: #ffc66d; 11 | } 12 | 13 | code .token { 14 | white-space: pre; 15 | } 16 | 17 | /* PrismJS 1.24.1 18 | https://prismjs.com/download.html#themes=prism&languages=clike+java+javadoclike+kotlin&plugins=keep-markup */ 19 | /** 20 | * prism.js default theme for JavaScript, CSS and HTML 21 | * Based on dabblet (http://dabblet.com) 22 | * @author Lea Verou 23 | */ 24 | 25 | .token.comment, 26 | .token.prolog, 27 | .token.doctype, 28 | .token.cdata { 29 | color: slategray; 30 | } 31 | 32 | .token.punctuation { 33 | color: #999; 34 | } 35 | 36 | .token.namespace { 37 | opacity: .7; 38 | } 39 | 40 | .token.property, 41 | .token.tag, 42 | .token.boolean, 43 | .token.number, 44 | .token.constant, 45 | .token.symbol, 46 | .token.deleted { 47 | color: var(--property-color); 48 | } 49 | 50 | .token.selector, 51 | .token.attr-name, 52 | .token.string, 53 | .token.char, 54 | .token.builtin, 55 | .token.annotation, 56 | .token.inserted { 57 | color: #690; 58 | } 59 | 60 | .token.operator, 61 | .token.entity, 62 | .token.url, 63 | .language-css .token.string, 64 | .style .token.string { 65 | color: #9a6e3a; 66 | /* This background color was intended by the author of this theme. */ 67 | /*background: hsla(0, 0%, 100%, .5);*/ 68 | } 69 | 70 | .token.atrule, 71 | .token.attr-value, 72 | .token.keyword { 73 | color: var(--keyword-color); 74 | font-size: inherit; /* to override .keyword */ 75 | } 76 | 77 | .token.function, 78 | .token.class-name { 79 | color: var(--function-color); 80 | } 81 | 82 | .token.regex, 83 | .token.important, 84 | .token.variable { 85 | color: #e90; 86 | } 87 | 88 | .token.important, 89 | .token.bold { 90 | font-weight: bold; 91 | } 92 | .token.italic { 93 | font-style: italic; 94 | } 95 | 96 | .token.entity { 97 | cursor: help; 98 | } 99 | 100 | .annotation,.control,.field,.filename,.keyword,.menupath,.property,.string,.value { 101 | color: #27282c; 102 | font-weight: 700; 103 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eu-digital-green-certificates/dgca-app-core-android/4039792a01a19388bafa1374a4318849a03e05b2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 14 20:54:09 EEST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':decoder' 2 | rootProject.name = "dgca-app-core-android" -------------------------------------------------------------------------------- /templates/file-header.txt: -------------------------------------------------------------------------------- 1 | /*- 2 | * ---license-start 3 | * eu-digital-green-certificates / dgca-app-core-android 4 | * --- 5 | * Copyright (C) 2021 T-Systems International GmbH and all other contributors 6 | * --- 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ---license-end 19 | */ 20 | --------------------------------------------------------------------------------