├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── LICENSE
├── README.md
├── assets
├── favicon.ico
├── favicon.psd
├── logo.psd
├── logo192.png
└── logo512.png
├── craco.config.js
├── docs
└── Certificates.md
├── package.json
├── public
├── assets
│ └── certificates.json
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── scripts
├── build-certificate-list.js
├── deploy.sh
└── update-certificates.js
├── src
├── App.tsx
├── app.scss
├── components
│ ├── CPVQrDataTable
│ │ ├── CPVQrDataTable.tsx
│ │ ├── _cpv-qr-data-table.scss
│ │ └── index.ts
│ ├── CPVQrReader
│ │ ├── CPVQrReader.tsx
│ │ └── index.ts
│ └── CPVScanner
│ │ ├── CPVScanner.tsx
│ │ ├── _cpv-scanner.scss
│ │ └── index.ts
├── content
│ └── CPVLandingPage
│ │ ├── CPVLandingPage.tsx
│ │ ├── _cpv-landing-page.scss
│ │ └── index.ts
├── data
│ ├── certificates.json
│ ├── country-2-codes.json
│ ├── disease-agent-targeted.json
│ ├── test-manf.json
│ ├── test-result.json
│ ├── test-type.json
│ ├── vaccine-mah-manf.json
│ ├── vaccine-medicinal-product.json
│ └── vaccine-prophylaxis.json
├── index.scss
├── index.tsx
├── lib
│ ├── certificates.ts
│ ├── hcert-parser.ts
│ ├── hcert-verification.ts
│ ├── hcert.ts
│ ├── time.ts
│ ├── typed-array.ts
│ ├── valuesets
│ │ ├── common.ts
│ │ ├── country-2-codes.ts
│ │ ├── disease-agent-targeted.ts
│ │ ├── test-manufacturer.ts
│ │ ├── test-result.ts
│ │ ├── test-type.ts
│ │ ├── vaccine-manufacturer.ts
│ │ ├── vaccine-medicinal-product.ts
│ │ └── vaccine-prophylaxis.ts
│ └── zlib.ts
├── react-app-env.d.ts
├── reportWebVitals.ts
├── setupTests.ts
└── types
│ ├── base45-js.d.ts
│ ├── cbor-web.d.ts
│ └── cose-js.d.ts
├── tsconfig.json
├── tsconfig.paths.json
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | parserOptions: {
5 | ecmaVersion: 2020,
6 | sourceType: 'module',
7 | ecmaFeatures: {
8 | jsx: true
9 | }
10 | },
11 | plugins: [
12 | '@typescript-eslint',
13 | 'react-hooks'
14 | ],
15 | extends: [
16 | 'plugin:react/recommended',
17 | 'plugin:@typescript-eslint/recommended',
18 | 'plugin:prettier/recommended'
19 | ],
20 | settings: {
21 | react: {
22 | pragma: 'React',
23 | version: 'detect'
24 | }
25 | },
26 | rules: {
27 | 'react/react-in-jsx-scope': 'off' // No longer required as of React 17.
28 | }
29 | };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
106 |
107 | # dependencies
108 | /node_modules
109 | /.pnp
110 | .pnp.js
111 |
112 | # testing
113 | /coverage
114 |
115 | # production
116 | /build
117 |
118 | # misc
119 | .DS_Store
120 | .env.local
121 | .env.development.local
122 | .env.test.local
123 | .env.production.local
124 |
125 | npm-debug.log*
126 | yarn-debug.log*
127 | yarn-error.log*
128 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | trailingComma: 'all',
4 | singleQuote: true,
5 | printWidth: 120,
6 | tabWidth: 2
7 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🦠 COVID Pass Verifier [](https://opensource.org/licenses/Apache-2.0) [](https://github.com/bcsongor/covid-pass-verifier/issues)
2 |
3 | > Scan, parse and verify HCERT compliant government-issued COVID-19 passes.
4 |
5 | Compatible with EU Digital COVID Certificates 🇪🇺 and NHS COVID Passes 🇬🇧.
6 |
7 | All processing (including scanning, parsing and verification) happens on the local device and no data is sent to external servers.
8 |
9 | ## Features
10 |
11 | - Scans and verifies COVID passes issued by a [wide range of countries](docs/Certificates.md)
12 | - Runs locally on any device with a modern browser and a camera, no active internet connection required
13 | - Focuses on privacy: no data is sent to external servers
14 | - Supports vaccination and test result certificates, support for recovery certificates coming soon
15 | - Shows vaccination status badge: *fully vaccinated*, *partially vaccinated* or *not vaccinated*
16 | - Shows test result badge: *positive* or *negative*
17 |
18 | ## Usage
19 |
20 | Use a device that either has a built-in camera (e.g. smartphone) or has an external camera attached (e.g. desktop with webcam).
21 |
22 | ### Steps
23 |
24 | 1. Navigate to https://covid-pass-verifier.com/
25 | 2. Click on _Scan QR Code_
26 | 3. Scan the COVID pass QR code
27 | 4. If the COVID pass is
28 | - *valid*: a badge and a table will be displayed with the status and details
29 | - *invalid*: an error badge will be displayed
30 |
31 | ### Supported platforms
32 |
33 | | Platform | |
34 | |--------------------------------------|----|
35 | | Desktop (Chrome, Safari, Edge, etc.) | ✔ |
36 | | iOS Safari | ✔ |
37 | | iPadOS Safari | ✔ |
38 | | Android | ✔ |
39 |
40 | ### Supported certificates
41 |
42 | See [docs/Certificates.md](docs/Certificates.md) for the list government-issued certificates currently supported by COVID Pass Verifier.
43 |
44 | ## Development
45 |
46 | ### Available scripts
47 |
48 | In the project directory, you can run:
49 |
50 | #### `yarn start`
51 |
52 | Runs the app in the development mode.\
53 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
54 |
55 | The page will reload if you make edits.\
56 | You will also see any lint errors in the console.
57 |
58 | #### `yarn lint`
59 |
60 | Runs the linger against the code-base found under the `src` folder.
61 |
62 | #### `yarn build`
63 |
64 | Builds the app for production to the `build` folder.\
65 | It correctly bundles React in production mode and optimizes the build for the best performance.
66 |
67 | The build is minified and the filenames include the hashes.\
68 | Your app is ready to be deployed!
69 |
70 | #### `yarn deploy`
71 |
72 | Deploys the linted and built application to Microsoft Azure.\
73 | This requires certain access tokens and keys which can be set in the `.env` file.
74 |
75 | #### `yarn update-certificates`
76 |
77 | Updates the certificates used in the web application to verify the signature of the CBOR Web Tokens.
78 |
79 | This currently fetches the EU certificates from the Austrian government and enriches the data with a 3rd party source containing the UK certificates.
80 |
81 | Certificates currently used by the web app: https://covid-pass-verifier.com/assets/certificates.json
82 |
83 | #### `yarn build-certificate-list`
84 |
85 | Builds a Markdown document that lists the currently supported certificates.\
86 | See output at [docs/Certificates.md](docs/Certificates.md).
87 |
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/assets/favicon.ico
--------------------------------------------------------------------------------
/assets/favicon.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/assets/favicon.psd
--------------------------------------------------------------------------------
/assets/logo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/assets/logo.psd
--------------------------------------------------------------------------------
/assets/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/assets/logo192.png
--------------------------------------------------------------------------------
/assets/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/assets/logo512.png
--------------------------------------------------------------------------------
/craco.config.js:
--------------------------------------------------------------------------------
1 | const CracoAlias = require('craco-alias');
2 |
3 | module.exports = {
4 | plugins: [
5 | {
6 | plugin: CracoAlias,
7 | options: {
8 | source: 'tsconfig',
9 | // baseUrl SHOULD be specified, plugin does not take it from tsconfig
10 | baseUrl: './src',
11 | // tsConfigPath should point to the file where "baseUrl" and "paths" are specified
12 | tsConfigPath: './tsconfig.paths.json'
13 | }
14 | }
15 | ]
16 | };
17 |
--------------------------------------------------------------------------------
/docs/Certificates.md:
--------------------------------------------------------------------------------
1 | # Supported certificates
2 |
3 | **Last updated:** 2021-07-18
4 |
5 | **Number of supported certificates:** 150
6 |
7 | |KID|Country|Issuer|Subject|
8 | |-|-|-|-|
9 | |`Is2JtrOJhik=`|AT|BMSGPK|BMSGPK|
10 | |`ODqaG8mnbro=`|BE|eHealth - Belgium|eHealth - Belgium|
11 | |`Jjql9rBrjHI=`|BG|Ministry of Health|Ministry of Health|
12 | |`Ll3NP03zOxY=`|CH|Bundesamt fuer Informatik und Telekommunikation (BIT)|Bundesamt fC3BCr Gesundheit (BAG)|
13 | |`7rZbUrXNlLk=`|CY|Ministry of Health|Ministry of Health|
14 | |`e4lH6I4iMIM=`|CZ|MZCR|MZCR|
15 | |`fNf883wPIEg=`|CZ|MZCR|MZCR|
16 | |`0L7AaIwu+EY=`|DE|D-Trust GmbH|Robert Koch-Institut|
17 | |`1+da8dKEjlE=`|DE|D-Trust GmbH|Robert Koch-Institut|
18 | |`2BGoyFIyYPs=`|DE|D-Trust GmbH|Robert Koch-Institut|
19 | |`2JelGO/ymxQ=`|DE|D-Trust GmbH|Robert Koch-Institut|
20 | |`3LCRmucB9kU=`|DE|D-Trust GmbH|Robert Koch-Institut|
21 | |`3jqajzfHpKE=`|DE|D-Trust GmbH|Robert Koch-Institut|
22 | |`3lrBUHc4iQE=`|DE|D-Trust GmbH|Robert Koch-Institut|
23 | |`3oYtiEZ9wp4=`|DE|D-Trust GmbH|Robert Koch-Institut|
24 | |`5xtSr6KkAGA=`|DE|D-Trust GmbH|Robert Koch-Institut|
25 | |`6FNkACSMLEc=`|DE|D-Trust GmbH|Robert Koch-Institut|
26 | |`6VdOPLF8/Fg=`|DE|D-Trust GmbH|Robert Koch-Institut|
27 | |`7XLhQx1KXdQ=`|DE|D-Trust GmbH|Robert Koch-Institut|
28 | |`8AnF/hcilSo=`|DE|D-Trust GmbH|Robert Koch-Institut|
29 | |`9IZVOkJRZPQ=`|DE|D-Trust GmbH|Robert Koch-Institut|
30 | |`9v3FozjKAUo=`|DE|D-Trust GmbH|Robert Koch-Institut|
31 | |`AQCGDydsS1Q=`|DE|D-Trust GmbH|Robert Koch-Institut|
32 | |`CvktK3hdjeY=`|DE|D-Trust GmbH|Robert Koch-Institut|
33 | |`DusseXrzqO8=`|DE|D-Trust GmbH|Robert Koch-Institut|
34 | |`IZftFLRmKGY=`|DE|D-Trust GmbH|Robert Koch-Institut|
35 | |`L7XIA2gi2ps=`|DE|D-Trust GmbH|Robert Koch-Institut|
36 | |`M8bcnysCMj4=`|DE|D-Trust GmbH|Robert Koch-Institut|
37 | |`MxhfdcoHinc=`|DE|D-Trust GmbH|Robert Koch-Institut|
38 | |`NCdyt3s+cak=`|DE|D-Trust GmbH|Robert Koch-Institut|
39 | |`OKpEjMo/2MY=`|DE|D-Trust GmbH|Robert Koch-Institut|
40 | |`R7q7yd90ZPU=`|DE|D-Trust GmbH|Robert Koch-Institut|
41 | |`TGjTR+Re+yk=`|DE|D-Trust GmbH|Robert Koch-Institut|
42 | |`TpQIkAHAym4=`|DE|D-Trust GmbH|Robert Koch-Institut|
43 | |`Uj77p+qIQNs=`|DE|D-Trust GmbH|Robert Koch-Institut|
44 | |`XkVWZqUeeFc=`|DE|D-Trust GmbH|Robert Koch-Institut|
45 | |`XuCERkHu8kY=`|DE|D-Trust GmbH|Robert Koch-Institut|
46 | |`Yr8a8Rd+zqI=`|DE|D-Trust GmbH|Robert Koch-Institut|
47 | |`ZDoFfkn+yhY=`|DE|D-Trust GmbH|Robert Koch-Institut|
48 | |`bKmas9wa5tc=`|DE|D-Trust GmbH|Robert Koch-Institut|
49 | |`c1XrnEBoj/c=`|DE|D-Trust GmbH|Robert Koch-Institut|
50 | |`dhSzPDr4G2M=`|DE|D-Trust GmbH|Robert Koch-Institut|
51 | |`i5SVuCsR5TA=`|DE|D-Trust GmbH|Robert Koch-Institut|
52 | |`izUDZjGtHWY=`|DE|D-Trust GmbH|Robert Koch-Institut|
53 | |`juskqrNQf6k=`|DE|D-Trust GmbH|Robert Koch-Institut|
54 | |`kjEx2H7huNE=`|DE|D-Trust GmbH|Robert Koch-Institut|
55 | |`nHmZ5K96UY4=`|DE|D-Trust GmbH|Robert Koch-Institut|
56 | |`nPKEYm3gXzU=`|DE|D-Trust GmbH|Robert Koch-Institut|
57 | |`nTrG8glLUls=`|DE|D-Trust GmbH|Robert Koch-Institut|
58 | |`npo0ZWgdQSY=`|DE|D-Trust GmbH|Robert Koch-Institut|
59 | |`r9YkEJZgi9k=`|DE|D-Trust GmbH|Robert Koch-Institut|
60 | |`rKMDA66RiLE=`|DE|D-Trust GmbH|Robert Koch-Institut|
61 | |`rXP9L7xddL8=`|DE|D-Trust GmbH|Robert Koch-Institut|
62 | |`sYXcYixrOGA=`|DE|D-Trust GmbH|Robert Koch-Institut|
63 | |`vjm0I2ATJ+Y=`|DE|D-Trust GmbH|Robert Koch-Institut|
64 | |`vq08l/LTxhk=`|DE|D-Trust GmbH|Robert Koch-Institut|
65 | |`wb/2450PPrc=`|DE|D-Trust GmbH|Robert Koch-Institut|
66 | |`wtYpyAmNmdk=`|DE|D-Trust GmbH|Robert Koch-Institut|
67 | |`yWCRdph8XJs=`|DE|D-Trust GmbH|Robert Koch-Institut|
68 | |`NAyCKly+hCg=`|DK|The Danish Health Data Authority|The Danish Health Data Authority|
69 | |`EzYR1uk/E0I=`|EE|Estonia|Estonia|
70 | |`/IcqIBnnZzc=`|ES|European Agency of Digital Trust|SERVICIO DE SALUD DE LAS ISLAS BALEARES|
71 | |`3IsdmTYkAAM=`|ES|European Agency of Digital Trust|Servicio ExtremeC3B1o de Salud|
72 | |`4Qmniw7B0gc=`|ES|European Agency of Digital Trust|GERENCIA REGIONAL DE SALUD DE CASTILLA Y LEON|
73 | |`6ag2wJkSHtk=`|ES|European Agency of Digital Trust|DIRECCION GENERAL DE SALUD PUBLICA|
74 | |`ARrNkCRtprY=`|ES|European Agency of Digital Trust|Servicio Canario de la Salud|
75 | |`BEnvMVnNFK8=`|ES|European Agency of Digital Trust|CIUDAD AUTC393NOMA DE MELILLA|
76 | |`GMFMBu1RlCg=`|ES|European Agency of Digital Trust|SERVICIO ANDALUZ DE SALUD|
77 | |`GuQPQRxbMsU=`|ES|IZENPE S.A.|EUSKO JAURLARITZA - GOBIERNO VASCO|
78 | |`IaGR283U1jA=`|ES|European Agency of Digital Trust|Servicio CC3A1ntabro de Salud|
79 | |`JHd4CkNzadI=`|ES|European Agency of Digital Trust|Servicio de Salud de Castilla-La Mancha|
80 | |`MtI93IMknMk=`|ES|European Agency of Digital Trust|Ministerio de Defensa|
81 | |`NCc6YSsVioM=`|ES|European Agency of Digital Trust|Principado de Asturias|
82 | |`YRYidQ+wetg=`|ES|European Agency of Digital Trust|Servicio Navarro de Salud-Osasunbidea|
83 | |`YU9+X9nepqU=`|ES|European Agency of Digital Trust|CIUDAD AUTONOMA DE CEUTA|
84 | |`ZcfkloEvfGQ=`|ES|European Agency of Digital Trust|GENERALITAT VALENCIANA|
85 | |`e9SH8dtWwdY=`|ES|European Agency of Digital Trust|Departament de Salut de la Generalitat de Catalunya|
86 | |`hgpHHrTb4ws=`|ES|European Agency of Digital Trust|COMUNIDAD AUTONOMA DE LA REGION DE MURCIA|
87 | |`qFNF2dC+mjQ=`|ES|European Agency of Digital Trust|MINISTERIO DE SANIDAD|
88 | |`tCM87WnaaQE=`|ES|European Agency of Digital Trust|GOBIERNO DE ARAGON|
89 | |`ub6Qmv9xtAo=`|ES|European Agency of Digital Trust|SERVICIO MADRILEC391O DE SALUD|
90 | |`x3ch4ml934I=`|ES|European Agency of Digital Trust|ConsellerC3ADa de Sanidad|
91 | |`BKBFhNFXWAU=`|FI|Vaestorekisterikeskus CA|Kansanelakelaitos|
92 | |`2Yv0kajsIlA=`|FR|Gouv|DGS|
93 | |`53FOjX/4aJs=`|FR|Gouv|CNAM|
94 | |`AX/m4PDDCXE=`|FR|Gouv|DGS|
95 | |`CvmI4xOoMj4=`|FR|Gouv|DGS|
96 | |`G3jDFQ1oK0Q=`|FR|Gouv|CNAM|
97 | |`IMgNr10pfPQ=`|FR|Gouv|CNAM|
98 | |`Qe8D6lfZ5/Y=`|FR|Gouv|CNAM|
99 | |`Xo78qgBEx8k=`|FR|Gouv|DGS|
100 | |`YDAy+yvD5lU=`|FR|Gouv|DGS|
101 | |`YVpBYnLh1Hs=`|FR|Gouv|DGS|
102 | |`e+bFdywyJQE=`|FR|Gouv|APHP|
103 | |`eQOY6BDp+vM=`|FR|Gouv|APHP|
104 | |`eUVY16rD2Kc=`|FR|Gouv|CNAM|
105 | |`fGLuvg6n5wk=`|FR|Gouv|CNAM|
106 | |`lrxgMs2Duac=`|FR|Gouv|DGS|
107 | |`mo/w8S8rZ0Q=`|FR|Gouv|CNAM|
108 | |`pe6raiG2dWE=`|FR|Gouv|APHP|
109 | |`rLMiGt6uB3U=`|FR|Gouv|APHP|
110 | |`S2V5MVJF`|GB|||
111 | |`S2V5MlJF`|GB|||
112 | |`S2V5M1JF`|GB|||
113 | |`S2V5NFJF`|GB|||
114 | |`S2V5NVJF`|GB|||
115 | |`S2V5MVBSTw==`|GB|||
116 | |`S2V5MlBSTw==`|GB|||
117 | |`S2V5M1BSTw==`|GB|||
118 | |`S2V5NFBSTw==`|GB|||
119 | |`S2V5NVBSTw==`|GB|||
120 | |`vvYa1vaWkGg=`|GR|||
121 | |`25QCxBrBJvA=`|HR|AKD d.o.o.|AKD d.o.o.|
122 | |`4GkJs9YsYS4=`|HU|EESZT|OKFO|
123 | |`PBpDVqnJ7Us=`|IE|Department of Health|Department of Health|
124 | |`eNNsg2jd4wA=`|IE|Department of Health|Department of Health|
125 | |`HeWuzGwEM5c=`|IS|Directorate of Health|Directorate of Health|
126 | |`Pbydc1LscXo=`|IS|Directorate of Health|Directorate of Health|
127 | |`NJpCsMLQco4=`|IT|Ministero della Salute|Ministero della Salute|
128 | |`JkFekJel6/o=`|LI|Liechtensteinische Landesverwaltung|Liechtensteinische Landesverwaltung|
129 | |`e/YRqyv++qY=`|LI|Liechtensteinische Landesverwaltung|Liechtensteinische Landesverwaltung|
130 | |`jYpr5GHCDiQ=`|LI|Liechtensteinische Landesverwaltung|Liechtensteinische Landesverwaltung|
131 | |`7AfAwcpWOv0=`|LT|State Enterprise Centre of Registers|Ministry of Health of The Republic of Lithuania|
132 | |`lshLbYfCWRg=`|LT|State Enterprise Centre of Registers|Ministry of Health of The Republic of Lithuania|
133 | |`02vdAOY/+gI=`|LU|INCERT public agency|Ministry of Health|
134 | |`0kAwFy+vLpg=`|LU|INCERT public agency|Ministry of Health|
135 | |`bBnmkeVMV6A=`|LU|INCERT public agency|Ministry of Health|
136 | |`ln8K+9SqfuA=`|LU|INCERT public agency|Ministry of Health|
137 | |`MrT00mhDxLQ=`|LV|VAS Latvijas Valsts radio un televC4ABzijas centrs|NacionC481lais veselC4ABbas dienests|
138 | |`hFpY/ySOrwI=`|LV|VAS Latvijas Valsts radio un televC4ABzijas centrs|NacionC481lais veselC4ABbas dienests|
139 | |`GvVR3e6VJIM=`|MT|Government of Malta|Government of Malta|
140 | |`QacbC7DdD4U=`|MT|Government of Malta|Government of Malta|
141 | |`UZ1cSMaPcaQ=`|MT|Government of Malta|Government of Malta|
142 | |`bfoj2trt6bE=`|MT|Government of Malta|Government of Malta|
143 | |`ccgQ13tmkU8=`|MT|Government of Malta|Government of Malta|
144 | |`f6J92LRKpj0=`|MT|Government of Malta|Government of Malta|
145 | |`3lTmAZX19GQ=`|NL|Kingdom of the Netherlands|Kingdom of the Netherlands|
146 | |`f+4yAPIGTWg=`|NL|Kingdom of the Netherlands|Kingdom of the Netherlands|
147 | |`pSEfhlMubh4=`|NL|Kingdom of the Netherlands|Kingdom of the Netherlands|
148 | |`7z8+6oww2a8=`|NO|Norsk helsenett SF|Norwegian Institute of Public Health|
149 | |`Er5OTMwLd78=`|NO|Norsk helsenett SF|Norwegian Institute of Public Health|
150 | |`cdm9Ymfwn2I=`|NO|Norsk helsenett SF|Norwegian Institute of Public Health|
151 | |`AN1EeLIMAmo=`|PL|Ministry of Health|Ministry of Health|
152 | |`FDNJjaSCWi0=`|PL|Ministry of Health|Ministry of Health|
153 | |`HhkeqvrtQ0U=`|PL|Ministry of Health|Ministry of Health|
154 | |`KG9lzdohSY0=`|PT|Republica Portuguesa - Portuguese Republic|Republica Portuguesa - Portuguese Republic|
155 | |`hA1+pwEOxCI=`|RO|Ministerul Sanatatii|Ministerul Sanatatii|
156 | |`Z7k1XpIWZOE=`|SE|Swedish eHealth Agency|Swedish eHealth Agency|
157 | |`90CNG8dcdn0=`|SI|NIJZ|NIJZ|
158 | |`6CDB1hL+uKU=`|SK|NCZI|NCZI|
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "covid-pass-verifier",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@carbon/grid": "^10.30.0",
7 | "@carbon/icons-react": "10.22.0",
8 | "base45-js": "^1.0.2",
9 | "carbon-components": "^10.38.0",
10 | "carbon-components-react": "^7.38.0",
11 | "carbon-icons": "^7.0.7",
12 | "cbor-web": "^7.0.5",
13 | "cose-js": "^0.6.0",
14 | "pako": "^2.0.3",
15 | "react": "^17.0.2",
16 | "react-dom": "^17.0.2",
17 | "react-qr-reader": "^2.2.1",
18 | "react-router-dom": "^5.2.0",
19 | "web-vitals": "^1.0.1"
20 | },
21 | "devDependencies": {
22 | "@craco/craco": "^6.2.0",
23 | "@testing-library/jest-dom": "^5.11.4",
24 | "@testing-library/react": "^11.1.0",
25 | "@testing-library/user-event": "^12.1.10",
26 | "@types/carbon-components-react": "^7.36.0",
27 | "@types/carbon__icons-react": "^10.31.0",
28 | "@types/elliptic": "^6.4.12",
29 | "@types/jest": "^26.0.15",
30 | "@types/node": "^12.0.0",
31 | "@types/node-forge": "^0.10.0",
32 | "@types/pako": "^1.0.1",
33 | "@types/react": "^17.0.0",
34 | "@types/react-dom": "^17.0.0",
35 | "@types/react-qr-reader": "^2.1.3",
36 | "@types/react-router-dom": "^5.1.7",
37 | "@typescript-eslint/eslint-plugin": "^4.28.3",
38 | "@typescript-eslint/parser": "^4.28.3",
39 | "cbor-cli": "^7.0.5",
40 | "craco-alias": "^3.0.1",
41 | "eslint": "^7.30.0",
42 | "eslint-config-prettier": "^8.3.0",
43 | "eslint-plugin-jsx-a11y": "^6.4.1",
44 | "eslint-plugin-prettier": "^3.4.0",
45 | "eslint-plugin-react": "^7.24.0",
46 | "eslint-plugin-react-hooks": "^4.2.0",
47 | "node-fetch": "^2.6.1",
48 | "node-sass": "^5.0.0",
49 | "prettier": "^2.3.2",
50 | "react-scripts": "4.0.3",
51 | "typescript": "^4.3.5"
52 | },
53 | "scripts": {
54 | "start": "NODE_OPTIONS='--max-old-space-size=8192' REACT_APP_GIT_DATE=`git log -1 --format=%at | xargs -I{} date -d @{} +%Y%m%d` REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco start",
55 | "build": "NODE_OPTIONS='--max-old-space-size=8192' REACT_APP_GIT_DATE=`git log -1 --format=%at | xargs -I{} date -d @{} +%Y%m%d` REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build",
56 | "lint": "eslint ./src/ --ext .js,.jsx,.ts,.tsx",
57 | "test": "craco test",
58 | "deploy": "scripts/deploy.sh",
59 | "update-certificates": "scripts/update-certificates.js",
60 | "build-certificate-list": "scripts/build-certificate-list.js",
61 | "eject": "react-scripts eject"
62 | },
63 | "eslintConfig": {
64 | "extends": [
65 | "react-app",
66 | "react-app/jest"
67 | ]
68 | },
69 | "browserslist": {
70 | "production": [
71 | ">0.2%",
72 | "not dead",
73 | "not op_mini all"
74 | ],
75 | "development": [
76 | "last 1 chrome version",
77 | "last 1 firefox version",
78 | "last 1 safari version"
79 | ]
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
24 | COVID Pass Verifier
25 |
26 |
27 |
33 |
34 |
35 | You need to enable JavaScript to run this app.
36 |
37 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bcsongor/covid-pass-verifier/35336fd3c0ff969b5b4784d7763c64ead6305615/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "COVID Pass Verifier",
3 | "name": "COVID Pass Verifier",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/scripts/build-certificate-list.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require('fs');
4 | const certs = require('../src/data/certificates.json');
5 |
6 | const header = ['KID', 'Country', 'Issuer', 'Subject'];
7 | const body = certs.sort((a, b) => a.iss.C.localeCompare(b.iss.C)).map(crt => {
8 | const kid = Buffer.from(crt.kid).toString('base64');
9 | return ['`' + kid + '`', crt.sub.C, crt.iss.O, crt.sub.O];
10 | });
11 |
12 | function toMarkdown(arr) {
13 | return '|' + arr.join('|') + '|';
14 | }
15 |
16 | const md = [
17 | '# Supported certificates',
18 | '',
19 | '**Last updated:** ' + new Date().toISOString().slice(0, 10),
20 | '',
21 | '**Number of supported certificates:** ' + certs.length,
22 | '',
23 | toMarkdown(header),
24 | toMarkdown(header.map(_ => '-')),
25 | ...(body.map(el => toMarkdown(el)))
26 | ].join('\n');
27 |
28 | fs.writeFileSync('./docs/Certificates.md', md, 'utf-8');
29 |
--------------------------------------------------------------------------------
/scripts/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit script when any command fails.
4 | set -e
5 |
6 | yarn lint
7 | yarn build
8 |
9 | source .env
10 | export AZCOPY_SPA_CLIENT_SECRET=$AZ_AD_SP_CLIENT_SECRET
11 | azcopy login --service-principal --application-id $AZ_AD_SP_APP_ID --tenant-id $AZ_AD_SP_TENANT_ID
12 | azcopy copy "./build/*" "$AZ_BLOB_ENDPOINT/\$web" --recursive
--------------------------------------------------------------------------------
/scripts/update-certificates.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require('fs');
4 | const fetch = require('node-fetch');
5 | const cbor = require('cbor-web');
6 | const child_process = require('child_process');
7 |
8 | const parseDerPublicKey = (buff) => {
9 | const b64 = buff.toString('base64');
10 | const cmd = `echo "${b64}" | base64 --decode | openssl x509 -pubkey -noout -inform der -in /dev/stdin | openssl ec -pubin -in /dev/stdin -outform der | xxd -p`;
11 | return child_process.spawnSync('bash', ['-c', `'${cmd}'`], { shell: '/bin/bash', encoding : 'utf8' }).stdout.replace(/\n/g, '');
12 | };
13 |
14 | const getEcPoints = (asn1pubhex) => {
15 | if (!asn1pubhex) return null;
16 |
17 | // asn1 lead-in sequence of p256-ecdsa public key.
18 | const asn1Header = '3059301306072a8648ce3d020106082a8648ce3d030107034200';
19 | if (!asn1pubhex.startsWith(asn1Header)) {
20 | throw new Error(`invalid public key: failed to find asn1 lead-in sequence in ${asn1pubhex}`);
21 | }
22 |
23 | const pubhex = asn1pubhex.substring(asn1Header.length);
24 | const pub = Buffer.from(pubhex, 'hex').toJSON().data;
25 |
26 | if (pub[0] !== 4) {
27 | throw new Error(`compressed elliptic points are not supported: ${pub}`)
28 | }
29 |
30 | return {
31 | x: pub.slice(1, 33),
32 | y: pub.slice(33, 65)
33 | };
34 | };
35 |
36 | const getX509Tag = (buff, tag) => {
37 | const b64 = buff.toString('base64');
38 | const cmd = `echo "${b64}" | base64 --decode | openssl x509 -text -noout -inform der -in /dev/stdin | grep ${tag}: | xargs | cut -c ${tag.length + 3}-`;
39 | const raw = child_process.spawnSync('bash', ['-c', `'${cmd}'`], { shell: '/bin/bash', encoding : 'utf8' }).stdout;
40 | return raw.split(',').reduce((acc, curr) => {
41 | const kv = curr.split('=').map(e => e.trim());
42 | if (kv[1]) {
43 | acc[kv[0].trim()] = kv[1].trim();
44 | }
45 | return acc;
46 | }, {});
47 | };
48 |
49 | async function fetchEUCertificates(isProduction) {
50 | if (isProduction) {
51 | // Production trust list from AT government.
52 | // See discussion: https://github.com/eu-digital-green-certificates/dgc-participating-countries/issues/10
53 | const res = await fetch('https://greencheck.gv.at/api/masterdata');
54 | const json = await res.json();
55 | const trustListCbor = Buffer.from(json.trustList.trustListContent, 'base64');
56 | const trustList = cbor.decode(trustListCbor);
57 |
58 | return trustList.c.map(c => {
59 | return {
60 | kid: c.i.toJSON().data,
61 | crt: c.c.toJSON().data,
62 | iss: getX509Tag(c.c, 'Issuer'),
63 | sub: getX509Tag(c.c, 'Subject'),
64 | pub: getEcPoints(parseDerPublicKey(c.c))
65 | };
66 | });
67 | } else {
68 | // Test certificates from AT government.
69 | const res = await fetch('https://dgc.a-sit.at/ehn/cert/listv2');
70 | const listv2cbor = await res.buffer();
71 | const listv2 = cbor.decode(listv2cbor);
72 |
73 | listv2.c.map(c => {
74 | return {
75 | kid: c.i.toJSON().data,
76 | crt: c.c.toJSON().data,
77 | iss: getX509Tag(c.c, 'Issuer'),
78 | sub: getX509Tag(c.c, 'Subject'),
79 | pub: getEcPoints(parseDerPublicKey(c.c))
80 | };
81 | });
82 | }
83 | }
84 |
85 | async function fetchUKCertificates() {
86 | const res = await fetch('https://covid-status.service.nhsx.nhs.uk/pubkeys/keys.json');
87 | const json = await res.json();
88 |
89 | return json.map(p => {
90 | const pubhex = Buffer.from(p.publicKey, 'base64').toString('hex');
91 | try {
92 | return {
93 | kid: Buffer.from(p.kid, 'base64').toJSON().data,
94 | crt: [],
95 | iss: { C: 'GB' },
96 | sub: { C: 'GB' },
97 | pub: getEcPoints(pubhex),
98 | };
99 | } catch (e) {
100 | console.error(`failed to get EC points for pub key ${pubhex}: ${e}`);
101 | return null;
102 | }
103 | }).filter(p => p !== null);
104 | }
105 |
106 | (async function main(params) {
107 | const outName = 'certificates.json';
108 | const outPath = `./src/data/${outName}`;
109 |
110 | const certs = [...(await fetchEUCertificates(true)), ...(await fetchUKCertificates())];
111 | fs.writeFileSync(outPath, JSON.stringify(certs), 'utf8');
112 | fs.copyFileSync(outPath, `./public/assets/${outName}`);
113 | })();
114 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { Route, Switch } from 'react-router-dom';
2 |
3 | import '@cpv/app.scss';
4 | import CPVLandingPage from '@cpv/content/CPVLandingPage';
5 |
6 | function App(): JSX.Element {
7 | return (
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/src/app.scss:
--------------------------------------------------------------------------------
1 | @import 'carbon-components/scss/globals/scss/typography.scss';
2 | @import 'carbon-components/scss/globals/scss/vars.scss';
3 |
4 | @import '@cpv/components/CPVScanner/cpv-scanner';
5 | @import '@cpv/components/CPVQrDataTable/cpv-qr-data-table';
6 | @import '@cpv/content/CPVLandingPage/cpv-landing-page';
7 |
8 | .app__content {
9 | padding: 0;
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/CPVQrDataTable/CPVQrDataTable.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 | import {
3 | Accordion,
4 | AccordionItem,
5 | CodeSnippet,
6 | Table,
7 | TableHead,
8 | TableBody,
9 | TableRow,
10 | TableHeader,
11 | TableCell,
12 | } from 'carbon-components-react';
13 |
14 | import { HCERT, TestEntry, VaccinationEntry } from '@cpv/lib/hcert';
15 | import { parseHCERT } from '@cpv/lib/hcert-parser';
16 | import { validateHCERT, HCERTStatus } from '@cpv/lib/hcert-verification';
17 | import { formatISO8601Timestamp, formatTimestamp } from '@cpv/lib/time';
18 | // import { getCountry } from '@cpv/lib/valuesets/country-2-codes';
19 | import { getTargetDisease } from '@cpv/lib/valuesets/disease-agent-targeted';
20 | import { getVaccineProphylaxis } from '@cpv/lib/valuesets/vaccine-prophylaxis';
21 | import { getVaccineMedicinalProduct } from '@cpv/lib/valuesets/vaccine-medicinal-product';
22 | import { getVaccineManufacturer } from '@cpv/lib/valuesets/vaccine-manufacturer';
23 | import { getTestResult } from '@cpv/lib/valuesets/test-result';
24 | import { getTestManufacturer } from '@cpv/lib/valuesets/test-manufacturer';
25 | import { getTestType } from '@cpv/lib/valuesets/test-type';
26 |
27 | type Props = {
28 | qrData: string;
29 | onHCERTStatus: (status: HCERTStatus) => void;
30 | };
31 |
32 | type HCERTMappings = {
33 | [title: string]: {
34 | [label: string]: (obj: T) => string | undefined;
35 | };
36 | };
37 |
38 | const hcertMetadataMappings: HCERTMappings = {
39 | General: {
40 | 'Issuer Country': (h) => h.iss,
41 | 'Issued At': (h) => formatTimestamp(h.iat),
42 | 'Expires At': (h) => formatTimestamp(h.exp),
43 | },
44 | Personal: {
45 | 'Full Name': ({ hcert: { nam } }) => `${nam.fn} ${nam.gn}`,
46 | 'Date of Birth': ({ hcert }) => hcert.dob,
47 | },
48 | };
49 |
50 | const hcertVaccineMappings: HCERTMappings = {
51 | Vaccine: {
52 | 'Target Disease': (v) => getTargetDisease(v.tg),
53 | Vaccine: (v) => getVaccineProphylaxis(v.vp),
54 | 'Vaccine Product': (v) => getVaccineMedicinalProduct(v.mp),
55 | 'Vaccine Manufacturer': (v) => getVaccineManufacturer(v.ma),
56 | Dose: (v) => `${v.dn} / ${v.sd}`,
57 | 'Date of Vaccination': (v) => v.dt,
58 | 'Country of Vaccination': (v) => v.co,
59 | 'Certificate Issuer': (v) => v.is,
60 | },
61 | };
62 |
63 | const hcertTestMappings: HCERTMappings = {
64 | Test: {
65 | 'Target Disease': (t) => getTargetDisease(t.tg),
66 | 'Test Type': (t) => getTestType(t.tt),
67 | 'Test Manufacturer': (t) => t.nm || (t.ma && getTestManufacturer(t.ma)) || undefined,
68 | 'Test Time': (t) => formatISO8601Timestamp(t.sc),
69 | 'Test Result': (t) => getTestResult(t.tr),
70 | 'Testing Centre': (t) => t.tc,
71 | 'Country of Test': (t) => t.co,
72 | 'Certificate Issuer': (t) => t.is,
73 | },
74 | };
75 |
76 | export const CPVQrDataTable = ({ qrData, onHCERTStatus }: Props): JSX.Element => {
77 | const [hcert, setHCERT] = useState(null);
78 |
79 | useEffect(() => {
80 | async function getHCERT() {
81 | let status = HCERTStatus.Error;
82 |
83 | try {
84 | const hcert = await parseHCERT(qrData);
85 | setHCERT(hcert);
86 | status = validateHCERT(hcert);
87 | } catch (e) {
88 | console.error(e);
89 | }
90 |
91 | onHCERTStatus(status);
92 | }
93 |
94 | getHCERT();
95 | }, [qrData]);
96 |
97 | if (hcert === null) {
98 | return <>>;
99 | }
100 |
101 | return (
102 |
103 |
104 | {Object.entries(hcertMetadataMappings).map(([title, mappings]) => (
105 |
106 |
107 |
108 | {title}
109 |
110 |
111 |
112 | {Object.entries(mappings).map(([label, mapper]) => (
113 |
114 | {label}
115 | {mapper(hcert)}
116 |
117 | ))}
118 |
119 |
120 | ))}
121 |
122 | {hcert.hcert.v?.map((v, idx) =>
123 | Object.entries(hcertVaccineMappings).map(([title, mappings]) => (
124 |
125 |
126 |
127 | {title}
128 |
129 |
130 |
131 | {Object.entries(mappings).map(([label, mapper]) => (
132 |
133 | {label}
134 | {mapper(v)}
135 |
136 | ))}
137 |
138 |
139 | )),
140 | )}
141 |
142 | {hcert.hcert.t?.map((t, idx) =>
143 | Object.entries(hcertTestMappings).map(([title, mappings]) => (
144 |
145 |
146 |
147 | {title}
148 |
149 |
150 |
151 | {Object.entries(mappings)
152 | .filter(([, mapper]) => mapper(t) !== undefined)
153 | .map(([label, mapper]) => (
154 |
155 | {label}
156 | {mapper(t)}
157 |
158 | ))}
159 |
160 |
161 | )),
162 | )}
163 |
164 |
165 |
166 | {qrData}
167 |
168 |
169 |
170 | );
171 | };
172 |
--------------------------------------------------------------------------------
/src/components/CPVQrDataTable/_cpv-qr-data-table.scss:
--------------------------------------------------------------------------------
1 | .cpv-qr-data-parser__accordion {
2 | margin-top: $spacing-06;
3 |
4 | .bx--accordion__content {
5 | padding-left: 0;
6 | padding-right: 0;
7 | }
8 |
9 | .bx--data-table-content {
10 | margin-bottom: $spacing-06;
11 |
12 | &:last-child {
13 | margin-bottom: 0;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/components/CPVQrDataTable/index.ts:
--------------------------------------------------------------------------------
1 | import { CPVQrDataTable } from './CPVQrDataTable';
2 |
3 | export default CPVQrDataTable;
4 |
--------------------------------------------------------------------------------
/src/components/CPVQrReader/CPVQrReader.tsx:
--------------------------------------------------------------------------------
1 | import QrReader from 'react-qr-reader';
2 |
3 | type Props = {
4 | onQrData: (data: string) => void;
5 | };
6 |
7 | export const CPVQrReader = ({ onQrData }: Props): JSX.Element => {
8 | const handleScan = (data: string | null): void => {
9 | if (data != null) {
10 | onQrData(data);
11 | }
12 | };
13 |
14 | const handleError = (err: unknown): void => {
15 | alert(err);
16 | };
17 |
18 | return ;
19 | };
20 |
--------------------------------------------------------------------------------
/src/components/CPVQrReader/index.ts:
--------------------------------------------------------------------------------
1 | import { CPVQrReader } from './CPVQrReader';
2 |
3 | export default CPVQrReader;
4 |
--------------------------------------------------------------------------------
/src/components/CPVScanner/CPVScanner.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { Button, Grid, Row, Column } from 'carbon-components-react';
3 | import { Misuse32, CheckmarkFilled32, CheckmarkFilledWarning32, AddAlt32 } from '@carbon/icons-react';
4 | import CPVQrReader from '@cpv/components/CPVQrReader';
5 | import CPVQrDataParser from '@cpv/components/CPVQrDataTable';
6 | import { HCERTStatus } from '@cpv/lib/hcert-verification';
7 |
8 | const hcertStatusMapping = {
9 | [HCERTStatus.PartiallyVaccinated]: {
10 | icon: ,
11 | label: 'Partially Vaccinated',
12 | className: 'amber',
13 | },
14 | [HCERTStatus.FullyVaccinated]: {
15 | icon: ,
16 | label: 'Fully Vaccinated',
17 | className: 'green',
18 | },
19 | [HCERTStatus.NotVaccinated]: {
20 | icon: ,
21 | label: 'Not Vaccinated',
22 | className: 'red',
23 | },
24 | [HCERTStatus.Negative]: {
25 | icon: ,
26 | label: 'Negative',
27 | className: 'green',
28 | },
29 | [HCERTStatus.Positive]: {
30 | icon: ,
31 | label: 'Positive',
32 | className: 'red',
33 | },
34 | [HCERTStatus.Expired]: {
35 | icon: ,
36 | label: 'Expired',
37 | className: 'red',
38 | },
39 | [HCERTStatus.UnverifiedSignature]: {
40 | icon: ,
41 | label: 'Unverified Signature',
42 | className: 'red',
43 | },
44 | [HCERTStatus.Error]: {
45 | icon: ,
46 | label: 'Error',
47 | className: 'red',
48 | },
49 | };
50 |
51 | const CPVCertificateStatus = ({ status }: { status: HCERTStatus }): JSX.Element => {
52 | const mapped = hcertStatusMapping[status];
53 |
54 | return (
55 |
56 | {mapped.icon}
57 |
58 | {mapped.label}
59 |
60 | );
61 | };
62 |
63 | export const CPVScanner = (): JSX.Element => {
64 | const [isScanning, setIsScanning] = useState(false);
65 | const [qrData, setQrData] = useState(null);
66 | const [status, setStatus] = useState(null);
67 |
68 | const startScanning = () => {
69 | setQrData(null);
70 | setIsScanning(true);
71 | };
72 |
73 | const stopScanning = () => setIsScanning(false);
74 |
75 | const onQrData = (data: string) => {
76 | setQrData(data);
77 | setIsScanning(false);
78 | };
79 |
80 | const onHCERTStatus = (status: HCERTStatus) => {
81 | setStatus(status);
82 | };
83 |
84 | return (
85 | <>
86 | {!isScanning && (
87 |
88 |
89 |
90 | Scan QR Code
91 |
92 | {status !== null && }
93 |
94 |
95 | )}
96 | {isScanning && (
97 |
98 |
99 | Stop scanning
100 |
101 |
102 |
103 | )}
104 | {qrData && }
105 | >
106 | );
107 | };
108 |
--------------------------------------------------------------------------------
/src/components/CPVScanner/_cpv-scanner.scss:
--------------------------------------------------------------------------------
1 | .cpv-scanner__grid {
2 | padding: 0 $spacing-05;
3 | }
4 |
5 | .cpv-scanner__status {
6 | text-align: center;
7 |
8 | &.red { color: $support-01; }
9 | &.amber { color: $support-03; }
10 | &.green { color: $support-02; }
11 | }
--------------------------------------------------------------------------------
/src/components/CPVScanner/index.ts:
--------------------------------------------------------------------------------
1 | import { CPVScanner } from './CPVScanner';
2 |
3 | export default CPVScanner;
4 |
--------------------------------------------------------------------------------
/src/content/CPVLandingPage/CPVLandingPage.tsx:
--------------------------------------------------------------------------------
1 | import { LogoGithub16 } from '@carbon/icons-react';
2 | import CPVScanner from '@cpv/components/CPVScanner';
3 |
4 | export const CPVLandingPage = (): JSX.Element => (
5 |
6 |
7 |
8 |
COVID Pass Verifier
9 |
10 | Scan and verify HCERT compliant government-issued COVID-19 passes.
11 |
12 |
13 |
14 |
15 |
16 |
Compatible with EU Digital COVID Certificates 🇪🇺 and NHS COVID Passes 🇬🇧.
17 |
18 |
19 |
24 |
25 |
26 |
27 | All processing (including scanning, parsing and verification) happens on the local device and no data is sent
28 | to external servers.
29 |
30 |
31 | Please{' '}
32 |
33 | email me
34 | {' '}
35 | at hello@covid-pass-verifier.com with any questions or concerns. The source
36 | code for the entire web application is available{' '}
37 |
38 | on
39 | GitHub
40 |
41 | .
42 |
43 |
44 |
45 |
46 |
47 | v{process.env.REACT_APP_GIT_DATE}-{process.env.REACT_APP_GIT_SHA}
48 |
49 |
50 |
51 | );
52 |
--------------------------------------------------------------------------------
/src/content/CPVLandingPage/_cpv-landing-page.scss:
--------------------------------------------------------------------------------
1 | .cpv-landing-page__grid {
2 | max-width: 514px;
3 | padding: 0 $spacing-06;
4 | }
5 |
6 | .cpv-landing-page__banner {
7 | padding: $spacing-08 0;
8 | }
9 |
10 | .cpv-landing-page__heading {
11 | padding-bottom: $spacing-03;
12 | @include carbon--type-style('productive-heading-06');
13 | }
14 |
15 | .cpv-landing-page__subheading {
16 | @include carbon--type-style('productive-heading-03');
17 | }
18 |
19 | .cpv-landing-page__scanner {
20 | padding: $spacing-08 0;
21 | }
22 |
23 | .cpv-landing-page__disclaimer {
24 | color: $text-05;
25 |
26 | p {
27 | margin-bottom: $spacing-03;
28 | }
29 |
30 | a, a:hover, a:active {
31 | text-decoration: none;
32 | color: $link-01;
33 | }
34 |
35 | .email {
36 | @include carbon--type-style('code-02');
37 | }
38 | }
39 |
40 | .cpv-landing-page__footer {
41 | margin-top: $spacing-06;
42 | padding: $spacing-03;
43 | background-color: $ui-01;
44 | color: $disabled-02;
45 | text-align: center;
46 | }
--------------------------------------------------------------------------------
/src/content/CPVLandingPage/index.ts:
--------------------------------------------------------------------------------
1 | import { CPVLandingPage } from './CPVLandingPage';
2 |
3 | export default CPVLandingPage;
4 |
--------------------------------------------------------------------------------
/src/data/country-2-codes.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "country-2-codes",
3 | "valueSetDate": "2019-11-01",
4 | "valueSetValues": {
5 | "AD": {
6 | "display": "Andorra",
7 | "lang": "en",
8 | "active": true,
9 | "system": "urn:iso:std:iso:3166",
10 | "version": ""
11 | },
12 | "AE": {
13 | "display": "United Arab Emirates",
14 | "lang": "en",
15 | "active": true,
16 | "system": "urn:iso:std:iso:3166",
17 | "version": ""
18 | },
19 | "AF": {
20 | "display": "Afghanistan",
21 | "lang": "en",
22 | "active": true,
23 | "system": "urn:iso:std:iso:3166",
24 | "version": ""
25 | },
26 | "AG": {
27 | "display": "Antigua and Barbuda",
28 | "lang": "en",
29 | "active": true,
30 | "system": "urn:iso:std:iso:3166",
31 | "version": ""
32 | },
33 | "AI": {
34 | "display": "Anguilla",
35 | "lang": "en",
36 | "active": true,
37 | "system": "urn:iso:std:iso:3166",
38 | "version": ""
39 | },
40 | "AL": {
41 | "display": "Albania",
42 | "lang": "en",
43 | "active": true,
44 | "system": "urn:iso:std:iso:3166",
45 | "version": ""
46 | },
47 | "AM": {
48 | "display": "Armenia",
49 | "lang": "en",
50 | "active": true,
51 | "system": "urn:iso:std:iso:3166",
52 | "version": ""
53 | },
54 | "AO": {
55 | "display": "Angola",
56 | "lang": "en",
57 | "active": true,
58 | "system": "urn:iso:std:iso:3166",
59 | "version": ""
60 | },
61 | "AQ": {
62 | "display": "Antarctica",
63 | "lang": "en",
64 | "active": true,
65 | "system": "urn:iso:std:iso:3166",
66 | "version": ""
67 | },
68 | "AR": {
69 | "display": "Argentina",
70 | "lang": "en",
71 | "active": true,
72 | "system": "urn:iso:std:iso:3166",
73 | "version": ""
74 | },
75 | "AS": {
76 | "display": "American Samoa",
77 | "lang": "en",
78 | "active": true,
79 | "system": "urn:iso:std:iso:3166",
80 | "version": ""
81 | },
82 | "AT": {
83 | "display": "Austria",
84 | "lang": "en",
85 | "active": true,
86 | "system": "urn:iso:std:iso:3166",
87 | "version": ""
88 | },
89 | "AU": {
90 | "display": "Australia",
91 | "lang": "en",
92 | "active": true,
93 | "system": "urn:iso:std:iso:3166",
94 | "version": ""
95 | },
96 | "AW": {
97 | "display": "Aruba",
98 | "lang": "en",
99 | "active": true,
100 | "system": "urn:iso:std:iso:3166",
101 | "version": ""
102 | },
103 | "AX": {
104 | "display": "Åland Islands",
105 | "lang": "en",
106 | "active": true,
107 | "system": "urn:iso:std:iso:3166",
108 | "version": ""
109 | },
110 | "AZ": {
111 | "display": "Azerbaijan",
112 | "lang": "en",
113 | "active": true,
114 | "system": "urn:iso:std:iso:3166",
115 | "version": ""
116 | },
117 | "BA": {
118 | "display": "Bosnia and Herzegovina",
119 | "lang": "en",
120 | "active": true,
121 | "system": "urn:iso:std:iso:3166",
122 | "version": ""
123 | },
124 | "BB": {
125 | "display": "Barbados",
126 | "lang": "en",
127 | "active": true,
128 | "system": "urn:iso:std:iso:3166",
129 | "version": ""
130 | },
131 | "BD": {
132 | "display": "Bangladesh",
133 | "lang": "en",
134 | "active": true,
135 | "system": "urn:iso:std:iso:3166",
136 | "version": ""
137 | },
138 | "BE": {
139 | "display": "Belgium",
140 | "lang": "en",
141 | "active": true,
142 | "system": "urn:iso:std:iso:3166",
143 | "version": ""
144 | },
145 | "BF": {
146 | "display": "Burkina Faso",
147 | "lang": "en",
148 | "active": true,
149 | "system": "urn:iso:std:iso:3166",
150 | "version": ""
151 | },
152 | "BG": {
153 | "display": "Bulgaria",
154 | "lang": "en",
155 | "active": true,
156 | "system": "urn:iso:std:iso:3166",
157 | "version": ""
158 | },
159 | "BH": {
160 | "display": "Bahrain",
161 | "lang": "en",
162 | "active": true,
163 | "system": "urn:iso:std:iso:3166",
164 | "version": ""
165 | },
166 | "BI": {
167 | "display": "Burundi",
168 | "lang": "en",
169 | "active": true,
170 | "system": "urn:iso:std:iso:3166",
171 | "version": ""
172 | },
173 | "BJ": {
174 | "display": "Benin",
175 | "lang": "en",
176 | "active": true,
177 | "system": "urn:iso:std:iso:3166",
178 | "version": ""
179 | },
180 | "BL": {
181 | "display": "Saint Barthélemy",
182 | "lang": "en",
183 | "active": true,
184 | "system": "urn:iso:std:iso:3166",
185 | "version": ""
186 | },
187 | "BM": {
188 | "display": "Bermuda",
189 | "lang": "en",
190 | "active": true,
191 | "system": "urn:iso:std:iso:3166",
192 | "version": ""
193 | },
194 | "BN": {
195 | "display": "Brunei Darussalam",
196 | "lang": "en",
197 | "active": true,
198 | "system": "urn:iso:std:iso:3166",
199 | "version": ""
200 | },
201 | "BO": {
202 | "display": "Bolivia, Plurinational State of",
203 | "lang": "en",
204 | "active": true,
205 | "system": "urn:iso:std:iso:3166",
206 | "version": ""
207 | },
208 | "BQ": {
209 | "display": "Bonaire, Sint Eustatius and Saba",
210 | "lang": "en",
211 | "active": true,
212 | "system": "urn:iso:std:iso:3166",
213 | "version": ""
214 | },
215 | "BR": {
216 | "display": "Brazil",
217 | "lang": "en",
218 | "active": true,
219 | "system": "urn:iso:std:iso:3166",
220 | "version": ""
221 | },
222 | "BS": {
223 | "display": "Bahamas",
224 | "lang": "en",
225 | "active": true,
226 | "system": "urn:iso:std:iso:3166",
227 | "version": ""
228 | },
229 | "BT": {
230 | "display": "Bhutan",
231 | "lang": "en",
232 | "active": true,
233 | "system": "urn:iso:std:iso:3166",
234 | "version": ""
235 | },
236 | "BV": {
237 | "display": "Bouvet Island",
238 | "lang": "en",
239 | "active": true,
240 | "system": "urn:iso:std:iso:3166",
241 | "version": ""
242 | },
243 | "BW": {
244 | "display": "Botswana",
245 | "lang": "en",
246 | "active": true,
247 | "system": "urn:iso:std:iso:3166",
248 | "version": ""
249 | },
250 | "BY": {
251 | "display": "Belarus",
252 | "lang": "en",
253 | "active": true,
254 | "system": "urn:iso:std:iso:3166",
255 | "version": ""
256 | },
257 | "BZ": {
258 | "display": "Belize",
259 | "lang": "en",
260 | "active": true,
261 | "system": "urn:iso:std:iso:3166",
262 | "version": ""
263 | },
264 | "CA": {
265 | "display": "Canada",
266 | "lang": "en",
267 | "active": true,
268 | "system": "urn:iso:std:iso:3166",
269 | "version": ""
270 | },
271 | "CC": {
272 | "display": "Cocos (Keeling) Islands",
273 | "lang": "en",
274 | "active": true,
275 | "system": "urn:iso:std:iso:3166",
276 | "version": ""
277 | },
278 | "CD": {
279 | "display": "Congo, the Democratic Republic of the",
280 | "lang": "en",
281 | "active": true,
282 | "system": "urn:iso:std:iso:3166",
283 | "version": ""
284 | },
285 | "CF": {
286 | "display": "Central African Republic",
287 | "lang": "en",
288 | "active": true,
289 | "system": "urn:iso:std:iso:3166",
290 | "version": ""
291 | },
292 | "CG": {
293 | "display": "Congo",
294 | "lang": "en",
295 | "active": true,
296 | "system": "urn:iso:std:iso:3166",
297 | "version": ""
298 | },
299 | "CH": {
300 | "display": "Switzerland",
301 | "lang": "en",
302 | "active": true,
303 | "system": "urn:iso:std:iso:3166",
304 | "version": ""
305 | },
306 | "CI": {
307 | "display": "Côte d''Ivoire",
308 | "lang": "en",
309 | "active": true,
310 | "system": "urn:iso:std:iso:3166",
311 | "version": ""
312 | },
313 | "CK": {
314 | "display": "Cook Islands",
315 | "lang": "en",
316 | "active": true,
317 | "system": "urn:iso:std:iso:3166",
318 | "version": ""
319 | },
320 | "CL": {
321 | "display": "Chile",
322 | "lang": "en",
323 | "active": true,
324 | "system": "urn:iso:std:iso:3166",
325 | "version": ""
326 | },
327 | "CM": {
328 | "display": "Cameroon",
329 | "lang": "en",
330 | "active": true,
331 | "system": "urn:iso:std:iso:3166",
332 | "version": ""
333 | },
334 | "CN": {
335 | "display": "China",
336 | "lang": "en",
337 | "active": true,
338 | "system": "urn:iso:std:iso:3166",
339 | "version": ""
340 | },
341 | "CO": {
342 | "display": "Colombia",
343 | "lang": "en",
344 | "active": true,
345 | "system": "urn:iso:std:iso:3166",
346 | "version": ""
347 | },
348 | "CR": {
349 | "display": "Costa Rica",
350 | "lang": "en",
351 | "active": true,
352 | "system": "urn:iso:std:iso:3166",
353 | "version": ""
354 | },
355 | "CU": {
356 | "display": "Cuba",
357 | "lang": "en",
358 | "active": true,
359 | "system": "urn:iso:std:iso:3166",
360 | "version": ""
361 | },
362 | "CV": {
363 | "display": "Cabo Verde",
364 | "lang": "en",
365 | "active": true,
366 | "system": "urn:iso:std:iso:3166",
367 | "version": ""
368 | },
369 | "CW": {
370 | "display": "Curaçao",
371 | "lang": "en",
372 | "active": true,
373 | "system": "urn:iso:std:iso:3166",
374 | "version": ""
375 | },
376 | "CX": {
377 | "display": "Christmas Island",
378 | "lang": "en",
379 | "active": true,
380 | "system": "urn:iso:std:iso:3166",
381 | "version": ""
382 | },
383 | "CY": {
384 | "display": "Cyprus",
385 | "lang": "en",
386 | "active": true,
387 | "system": "urn:iso:std:iso:3166",
388 | "version": ""
389 | },
390 | "CZ": {
391 | "display": "Czechia",
392 | "lang": "en",
393 | "active": true,
394 | "system": "urn:iso:std:iso:3166",
395 | "version": ""
396 | },
397 | "DE": {
398 | "display": "Germany",
399 | "lang": "en",
400 | "active": true,
401 | "system": "urn:iso:std:iso:3166",
402 | "version": ""
403 | },
404 | "DJ": {
405 | "display": "Djibouti",
406 | "lang": "en",
407 | "active": true,
408 | "system": "urn:iso:std:iso:3166",
409 | "version": ""
410 | },
411 | "DK": {
412 | "display": "Denmark",
413 | "lang": "en",
414 | "active": true,
415 | "system": "urn:iso:std:iso:3166",
416 | "version": ""
417 | },
418 | "DM": {
419 | "display": "Dominica",
420 | "lang": "en",
421 | "active": true,
422 | "system": "urn:iso:std:iso:3166",
423 | "version": ""
424 | },
425 | "DO": {
426 | "display": "Dominican Republic",
427 | "lang": "en",
428 | "active": true,
429 | "system": "urn:iso:std:iso:3166",
430 | "version": ""
431 | },
432 | "DZ": {
433 | "display": "Algeria",
434 | "lang": "en",
435 | "active": true,
436 | "system": "urn:iso:std:iso:3166",
437 | "version": ""
438 | },
439 | "EC": {
440 | "display": "Ecuador",
441 | "lang": "en",
442 | "active": true,
443 | "system": "urn:iso:std:iso:3166",
444 | "version": ""
445 | },
446 | "EE": {
447 | "display": "Estonia",
448 | "lang": "en",
449 | "active": true,
450 | "system": "urn:iso:std:iso:3166",
451 | "version": ""
452 | },
453 | "EG": {
454 | "display": "Egypt",
455 | "lang": "en",
456 | "active": true,
457 | "system": "urn:iso:std:iso:3166",
458 | "version": ""
459 | },
460 | "EH": {
461 | "display": "Western Sahara",
462 | "lang": "en",
463 | "active": true,
464 | "system": "urn:iso:std:iso:3166",
465 | "version": ""
466 | },
467 | "ER": {
468 | "display": "Eritrea",
469 | "lang": "en",
470 | "active": true,
471 | "system": "urn:iso:std:iso:3166",
472 | "version": ""
473 | },
474 | "ES": {
475 | "display": "Spain",
476 | "lang": "en",
477 | "active": true,
478 | "system": "urn:iso:std:iso:3166",
479 | "version": ""
480 | },
481 | "ET": {
482 | "display": "Ethiopia",
483 | "lang": "en",
484 | "active": true,
485 | "system": "urn:iso:std:iso:3166",
486 | "version": ""
487 | },
488 | "FI": {
489 | "display": "Finland",
490 | "lang": "en",
491 | "active": true,
492 | "system": "urn:iso:std:iso:3166",
493 | "version": ""
494 | },
495 | "FJ": {
496 | "display": "Fiji",
497 | "lang": "en",
498 | "active": true,
499 | "system": "urn:iso:std:iso:3166",
500 | "version": ""
501 | },
502 | "FK": {
503 | "display": "Falkland Islands (Malvinas)",
504 | "lang": "en",
505 | "active": true,
506 | "system": "urn:iso:std:iso:3166",
507 | "version": ""
508 | },
509 | "FM": {
510 | "display": "Micronesia, Federated States of",
511 | "lang": "en",
512 | "active": true,
513 | "system": "urn:iso:std:iso:3166",
514 | "version": ""
515 | },
516 | "FO": {
517 | "display": "Faroe Islands",
518 | "lang": "en",
519 | "active": true,
520 | "system": "urn:iso:std:iso:3166",
521 | "version": ""
522 | },
523 | "FR": {
524 | "display": "France",
525 | "lang": "en",
526 | "active": true,
527 | "system": "urn:iso:std:iso:3166",
528 | "version": ""
529 | },
530 | "GA": {
531 | "display": "Gabon",
532 | "lang": "en",
533 | "active": true,
534 | "system": "urn:iso:std:iso:3166",
535 | "version": ""
536 | },
537 | "GB": {
538 | "display": "United Kingdom of Great Britain and Northern Ireland",
539 | "lang": "en",
540 | "active": true,
541 | "system": "urn:iso:std:iso:3166",
542 | "version": ""
543 | },
544 | "GD": {
545 | "display": "Grenada",
546 | "lang": "en",
547 | "active": true,
548 | "system": "urn:iso:std:iso:3166",
549 | "version": ""
550 | },
551 | "GE": {
552 | "display": "Georgia",
553 | "lang": "en",
554 | "active": true,
555 | "system": "urn:iso:std:iso:3166",
556 | "version": ""
557 | },
558 | "GF": {
559 | "display": "French Guiana",
560 | "lang": "en",
561 | "active": true,
562 | "system": "urn:iso:std:iso:3166",
563 | "version": ""
564 | },
565 | "GG": {
566 | "display": "Guernsey",
567 | "lang": "en",
568 | "active": true,
569 | "system": "urn:iso:std:iso:3166",
570 | "version": ""
571 | },
572 | "GH": {
573 | "display": "Ghana",
574 | "lang": "en",
575 | "active": true,
576 | "system": "urn:iso:std:iso:3166",
577 | "version": ""
578 | },
579 | "GI": {
580 | "display": "Gibraltar",
581 | "lang": "en",
582 | "active": true,
583 | "system": "urn:iso:std:iso:3166",
584 | "version": ""
585 | },
586 | "GL": {
587 | "display": "Greenland",
588 | "lang": "en",
589 | "active": true,
590 | "system": "urn:iso:std:iso:3166",
591 | "version": ""
592 | },
593 | "GM": {
594 | "display": "Gambia",
595 | "lang": "en",
596 | "active": true,
597 | "system": "urn:iso:std:iso:3166",
598 | "version": ""
599 | },
600 | "GN": {
601 | "display": "Guinea",
602 | "lang": "en",
603 | "active": true,
604 | "system": "urn:iso:std:iso:3166",
605 | "version": ""
606 | },
607 | "GP": {
608 | "display": "Guadeloupe",
609 | "lang": "en",
610 | "active": true,
611 | "system": "urn:iso:std:iso:3166",
612 | "version": ""
613 | },
614 | "GQ": {
615 | "display": "Equatorial Guinea",
616 | "lang": "en",
617 | "active": true,
618 | "system": "urn:iso:std:iso:3166",
619 | "version": ""
620 | },
621 | "GR": {
622 | "display": "Greece",
623 | "lang": "en",
624 | "active": true,
625 | "system": "urn:iso:std:iso:3166",
626 | "version": ""
627 | },
628 | "GS": {
629 | "display": "South Georgia and the South Sandwich Islands",
630 | "lang": "en",
631 | "active": true,
632 | "system": "urn:iso:std:iso:3166",
633 | "version": ""
634 | },
635 | "GT": {
636 | "display": "Guatemala",
637 | "lang": "en",
638 | "active": true,
639 | "system": "urn:iso:std:iso:3166",
640 | "version": ""
641 | },
642 | "GU": {
643 | "display": "Guam",
644 | "lang": "en",
645 | "active": true,
646 | "system": "urn:iso:std:iso:3166",
647 | "version": ""
648 | },
649 | "GW": {
650 | "display": "Guinea-Bissau",
651 | "lang": "en",
652 | "active": true,
653 | "system": "urn:iso:std:iso:3166",
654 | "version": ""
655 | },
656 | "GY": {
657 | "display": "Guyana",
658 | "lang": "en",
659 | "active": true,
660 | "system": "urn:iso:std:iso:3166",
661 | "version": ""
662 | },
663 | "HK": {
664 | "display": "Hong Kong",
665 | "lang": "en",
666 | "active": true,
667 | "system": "urn:iso:std:iso:3166",
668 | "version": ""
669 | },
670 | "HM": {
671 | "display": "Heard Island and McDonald Islands",
672 | "lang": "en",
673 | "active": true,
674 | "system": "urn:iso:std:iso:3166",
675 | "version": ""
676 | },
677 | "HN": {
678 | "display": "Honduras",
679 | "lang": "en",
680 | "active": true,
681 | "system": "urn:iso:std:iso:3166",
682 | "version": ""
683 | },
684 | "HR": {
685 | "display": "Croatia",
686 | "lang": "en",
687 | "active": true,
688 | "system": "urn:iso:std:iso:3166",
689 | "version": ""
690 | },
691 | "HT": {
692 | "display": "Haiti",
693 | "lang": "en",
694 | "active": true,
695 | "system": "urn:iso:std:iso:3166",
696 | "version": ""
697 | },
698 | "HU": {
699 | "display": "Hungary",
700 | "lang": "en",
701 | "active": true,
702 | "system": "urn:iso:std:iso:3166",
703 | "version": ""
704 | },
705 | "ID": {
706 | "display": "Indonesia",
707 | "lang": "en",
708 | "active": true,
709 | "system": "urn:iso:std:iso:3166",
710 | "version": ""
711 | },
712 | "IE": {
713 | "display": "Ireland",
714 | "lang": "en",
715 | "active": true,
716 | "system": "urn:iso:std:iso:3166",
717 | "version": ""
718 | },
719 | "IL": {
720 | "display": "Israel",
721 | "lang": "en",
722 | "active": true,
723 | "system": "urn:iso:std:iso:3166",
724 | "version": ""
725 | },
726 | "IM": {
727 | "display": "Isle of Man",
728 | "lang": "en",
729 | "active": true,
730 | "system": "urn:iso:std:iso:3166",
731 | "version": ""
732 | },
733 | "IN": {
734 | "display": "India",
735 | "lang": "en",
736 | "active": true,
737 | "system": "urn:iso:std:iso:3166",
738 | "version": ""
739 | },
740 | "IO": {
741 | "display": "British Indian Ocean Territory",
742 | "lang": "en",
743 | "active": true,
744 | "system": "urn:iso:std:iso:3166",
745 | "version": ""
746 | },
747 | "IQ": {
748 | "display": "Iraq",
749 | "lang": "en",
750 | "active": true,
751 | "system": "urn:iso:std:iso:3166",
752 | "version": ""
753 | },
754 | "IR": {
755 | "display": "Iran, Islamic Republic of",
756 | "lang": "en",
757 | "active": true,
758 | "system": "urn:iso:std:iso:3166",
759 | "version": ""
760 | },
761 | "IS": {
762 | "display": "Iceland",
763 | "lang": "en",
764 | "active": true,
765 | "system": "urn:iso:std:iso:3166",
766 | "version": ""
767 | },
768 | "IT": {
769 | "display": "Italy",
770 | "lang": "en",
771 | "active": true,
772 | "system": "urn:iso:std:iso:3166",
773 | "version": ""
774 | },
775 | "JE": {
776 | "display": "Jersey",
777 | "lang": "en",
778 | "active": true,
779 | "system": "urn:iso:std:iso:3166",
780 | "version": ""
781 | },
782 | "JM": {
783 | "display": "Jamaica",
784 | "lang": "en",
785 | "active": true,
786 | "system": "urn:iso:std:iso:3166",
787 | "version": ""
788 | },
789 | "JO": {
790 | "display": "Jordan",
791 | "lang": "en",
792 | "active": true,
793 | "system": "urn:iso:std:iso:3166",
794 | "version": ""
795 | },
796 | "JP": {
797 | "display": "Japan",
798 | "lang": "en",
799 | "active": true,
800 | "system": "urn:iso:std:iso:3166",
801 | "version": ""
802 | },
803 | "KE": {
804 | "display": "Kenya",
805 | "lang": "en",
806 | "active": true,
807 | "system": "urn:iso:std:iso:3166",
808 | "version": ""
809 | },
810 | "KG": {
811 | "display": "Kyrgyzstan",
812 | "lang": "en",
813 | "active": true,
814 | "system": "urn:iso:std:iso:3166",
815 | "version": ""
816 | },
817 | "KH": {
818 | "display": "Cambodia",
819 | "lang": "en",
820 | "active": true,
821 | "system": "urn:iso:std:iso:3166",
822 | "version": ""
823 | },
824 | "KI": {
825 | "display": "Kiribati",
826 | "lang": "en",
827 | "active": true,
828 | "system": "urn:iso:std:iso:3166",
829 | "version": ""
830 | },
831 | "KM": {
832 | "display": "Comoros",
833 | "lang": "en",
834 | "active": true,
835 | "system": "urn:iso:std:iso:3166",
836 | "version": ""
837 | },
838 | "KN": {
839 | "display": "Saint Kitts and Nevis",
840 | "lang": "en",
841 | "active": true,
842 | "system": "urn:iso:std:iso:3166",
843 | "version": ""
844 | },
845 | "KP": {
846 | "display": "Korea, Democratic People''s Republic of",
847 | "lang": "en",
848 | "active": true,
849 | "system": "urn:iso:std:iso:3166",
850 | "version": ""
851 | },
852 | "KR": {
853 | "display": "Korea, Republic of",
854 | "lang": "en",
855 | "active": true,
856 | "system": "urn:iso:std:iso:3166",
857 | "version": ""
858 | },
859 | "KW": {
860 | "display": "Kuwait",
861 | "lang": "en",
862 | "active": true,
863 | "system": "urn:iso:std:iso:3166",
864 | "version": ""
865 | },
866 | "KY": {
867 | "display": "Cayman Islands",
868 | "lang": "en",
869 | "active": true,
870 | "system": "urn:iso:std:iso:3166",
871 | "version": ""
872 | },
873 | "KZ": {
874 | "display": "Kazakhstan",
875 | "lang": "en",
876 | "active": true,
877 | "system": "urn:iso:std:iso:3166",
878 | "version": ""
879 | },
880 | "LA": {
881 | "display": "Lao People''s Democratic Republic",
882 | "lang": "en",
883 | "active": true,
884 | "system": "urn:iso:std:iso:3166",
885 | "version": ""
886 | },
887 | "LB": {
888 | "display": "Lebanon",
889 | "lang": "en",
890 | "active": true,
891 | "system": "urn:iso:std:iso:3166",
892 | "version": ""
893 | },
894 | "LC": {
895 | "display": "Saint Lucia",
896 | "lang": "en",
897 | "active": true,
898 | "system": "urn:iso:std:iso:3166",
899 | "version": ""
900 | },
901 | "LI": {
902 | "display": "Liechtenstein",
903 | "lang": "en",
904 | "active": true,
905 | "system": "urn:iso:std:iso:3166",
906 | "version": ""
907 | },
908 | "LK": {
909 | "display": "Sri Lanka",
910 | "lang": "en",
911 | "active": true,
912 | "system": "urn:iso:std:iso:3166",
913 | "version": ""
914 | },
915 | "LR": {
916 | "display": "Liberia",
917 | "lang": "en",
918 | "active": true,
919 | "system": "urn:iso:std:iso:3166",
920 | "version": ""
921 | },
922 | "LS": {
923 | "display": "Lesotho",
924 | "lang": "en",
925 | "active": true,
926 | "system": "urn:iso:std:iso:3166",
927 | "version": ""
928 | },
929 | "LT": {
930 | "display": "Lithuania",
931 | "lang": "en",
932 | "active": true,
933 | "system": "urn:iso:std:iso:3166",
934 | "version": ""
935 | },
936 | "LU": {
937 | "display": "Luxembourg",
938 | "lang": "en",
939 | "active": true,
940 | "system": "urn:iso:std:iso:3166",
941 | "version": ""
942 | },
943 | "LV": {
944 | "display": "Latvia",
945 | "lang": "en",
946 | "active": true,
947 | "system": "urn:iso:std:iso:3166",
948 | "version": ""
949 | },
950 | "LY": {
951 | "display": "Libya",
952 | "lang": "en",
953 | "active": true,
954 | "system": "urn:iso:std:iso:3166",
955 | "version": ""
956 | },
957 | "MA": {
958 | "display": "Morocco",
959 | "lang": "en",
960 | "active": true,
961 | "system": "urn:iso:std:iso:3166",
962 | "version": ""
963 | },
964 | "MC": {
965 | "display": "Monaco",
966 | "lang": "en",
967 | "active": true,
968 | "system": "urn:iso:std:iso:3166",
969 | "version": ""
970 | },
971 | "MD": {
972 | "display": "Moldova, Republic of",
973 | "lang": "en",
974 | "active": true,
975 | "system": "urn:iso:std:iso:3166",
976 | "version": ""
977 | },
978 | "ME": {
979 | "display": "Montenegro",
980 | "lang": "en",
981 | "active": true,
982 | "system": "urn:iso:std:iso:3166",
983 | "version": ""
984 | },
985 | "MF": {
986 | "display": "Saint Martin (French part)",
987 | "lang": "en",
988 | "active": true,
989 | "system": "urn:iso:std:iso:3166",
990 | "version": ""
991 | },
992 | "MG": {
993 | "display": "Madagascar",
994 | "lang": "en",
995 | "active": true,
996 | "system": "urn:iso:std:iso:3166",
997 | "version": ""
998 | },
999 | "MH": {
1000 | "display": "Marshall Islands",
1001 | "lang": "en",
1002 | "active": true,
1003 | "system": "urn:iso:std:iso:3166",
1004 | "version": ""
1005 | },
1006 | "MK": {
1007 | "display": "Macedonia, the former Yugoslav Republic of",
1008 | "lang": "en",
1009 | "active": true,
1010 | "system": "urn:iso:std:iso:3166",
1011 | "version": ""
1012 | },
1013 | "ML": {
1014 | "display": "Mali",
1015 | "lang": "en",
1016 | "active": true,
1017 | "system": "urn:iso:std:iso:3166",
1018 | "version": ""
1019 | },
1020 | "MM": {
1021 | "display": "Myanmar",
1022 | "lang": "en",
1023 | "active": true,
1024 | "system": "urn:iso:std:iso:3166",
1025 | "version": ""
1026 | },
1027 | "MN": {
1028 | "display": "Mongolia",
1029 | "lang": "en",
1030 | "active": true,
1031 | "system": "urn:iso:std:iso:3166",
1032 | "version": ""
1033 | },
1034 | "MO": {
1035 | "display": "Macao",
1036 | "lang": "en",
1037 | "active": true,
1038 | "system": "urn:iso:std:iso:3166",
1039 | "version": ""
1040 | },
1041 | "MP": {
1042 | "display": "Northern Mariana Islands",
1043 | "lang": "en",
1044 | "active": true,
1045 | "system": "urn:iso:std:iso:3166",
1046 | "version": ""
1047 | },
1048 | "MQ": {
1049 | "display": "Martinique",
1050 | "lang": "en",
1051 | "active": true,
1052 | "system": "urn:iso:std:iso:3166",
1053 | "version": ""
1054 | },
1055 | "MR": {
1056 | "display": "Mauritania",
1057 | "lang": "en",
1058 | "active": true,
1059 | "system": "urn:iso:std:iso:3166",
1060 | "version": ""
1061 | },
1062 | "MS": {
1063 | "display": "Montserrat",
1064 | "lang": "en",
1065 | "active": true,
1066 | "system": "urn:iso:std:iso:3166",
1067 | "version": ""
1068 | },
1069 | "MT": {
1070 | "display": "Malta",
1071 | "lang": "en",
1072 | "active": true,
1073 | "system": "urn:iso:std:iso:3166",
1074 | "version": ""
1075 | },
1076 | "MU": {
1077 | "display": "Mauritius",
1078 | "lang": "en",
1079 | "active": true,
1080 | "system": "urn:iso:std:iso:3166",
1081 | "version": ""
1082 | },
1083 | "MV": {
1084 | "display": "Maldives",
1085 | "lang": "en",
1086 | "active": true,
1087 | "system": "urn:iso:std:iso:3166",
1088 | "version": ""
1089 | },
1090 | "MW": {
1091 | "display": "Malawi",
1092 | "lang": "en",
1093 | "active": true,
1094 | "system": "urn:iso:std:iso:3166",
1095 | "version": ""
1096 | },
1097 | "MX": {
1098 | "display": "Mexico",
1099 | "lang": "en",
1100 | "active": true,
1101 | "system": "urn:iso:std:iso:3166",
1102 | "version": ""
1103 | },
1104 | "MY": {
1105 | "display": "Malaysia",
1106 | "lang": "en",
1107 | "active": true,
1108 | "system": "urn:iso:std:iso:3166",
1109 | "version": ""
1110 | },
1111 | "MZ": {
1112 | "display": "Mozambique",
1113 | "lang": "en",
1114 | "active": true,
1115 | "system": "urn:iso:std:iso:3166",
1116 | "version": ""
1117 | },
1118 | "NA": {
1119 | "display": "Namibia",
1120 | "lang": "en",
1121 | "active": true,
1122 | "system": "urn:iso:std:iso:3166",
1123 | "version": ""
1124 | },
1125 | "NC": {
1126 | "display": "New Caledonia",
1127 | "lang": "en",
1128 | "active": true,
1129 | "system": "urn:iso:std:iso:3166",
1130 | "version": ""
1131 | },
1132 | "NE": {
1133 | "display": "Niger",
1134 | "lang": "en",
1135 | "active": true,
1136 | "system": "urn:iso:std:iso:3166",
1137 | "version": ""
1138 | },
1139 | "NF": {
1140 | "display": "Norfolk Island",
1141 | "lang": "en",
1142 | "active": true,
1143 | "system": "urn:iso:std:iso:3166",
1144 | "version": ""
1145 | },
1146 | "NG": {
1147 | "display": "Nigeria",
1148 | "lang": "en",
1149 | "active": true,
1150 | "system": "urn:iso:std:iso:3166",
1151 | "version": ""
1152 | },
1153 | "NI": {
1154 | "display": "Nicaragua",
1155 | "lang": "en",
1156 | "active": true,
1157 | "system": "urn:iso:std:iso:3166",
1158 | "version": ""
1159 | },
1160 | "NL": {
1161 | "display": "Netherlands",
1162 | "lang": "en",
1163 | "active": true,
1164 | "system": "urn:iso:std:iso:3166",
1165 | "version": ""
1166 | },
1167 | "NO": {
1168 | "display": "Norway",
1169 | "lang": "en",
1170 | "active": true,
1171 | "system": "urn:iso:std:iso:3166",
1172 | "version": ""
1173 | },
1174 | "NP": {
1175 | "display": "Nepal",
1176 | "lang": "en",
1177 | "active": true,
1178 | "system": "urn:iso:std:iso:3166",
1179 | "version": ""
1180 | },
1181 | "NR": {
1182 | "display": "Nauru",
1183 | "lang": "en",
1184 | "active": true,
1185 | "system": "urn:iso:std:iso:3166",
1186 | "version": ""
1187 | },
1188 | "NU": {
1189 | "display": "Niue",
1190 | "lang": "en",
1191 | "active": true,
1192 | "system": "urn:iso:std:iso:3166",
1193 | "version": ""
1194 | },
1195 | "NZ": {
1196 | "display": "New Zealand",
1197 | "lang": "en",
1198 | "active": true,
1199 | "system": "urn:iso:std:iso:3166",
1200 | "version": ""
1201 | },
1202 | "OM": {
1203 | "display": "Oman",
1204 | "lang": "en",
1205 | "active": true,
1206 | "system": "urn:iso:std:iso:3166",
1207 | "version": ""
1208 | },
1209 | "PA": {
1210 | "display": "Panama",
1211 | "lang": "en",
1212 | "active": true,
1213 | "system": "urn:iso:std:iso:3166",
1214 | "version": ""
1215 | },
1216 | "PE": {
1217 | "display": "Peru",
1218 | "lang": "en",
1219 | "active": true,
1220 | "system": "urn:iso:std:iso:3166",
1221 | "version": ""
1222 | },
1223 | "PF": {
1224 | "display": "French Polynesia",
1225 | "lang": "en",
1226 | "active": true,
1227 | "system": "urn:iso:std:iso:3166",
1228 | "version": ""
1229 | },
1230 | "PG": {
1231 | "display": "Papua New Guinea",
1232 | "lang": "en",
1233 | "active": true,
1234 | "system": "urn:iso:std:iso:3166",
1235 | "version": ""
1236 | },
1237 | "PH": {
1238 | "display": "Philippines",
1239 | "lang": "en",
1240 | "active": true,
1241 | "system": "urn:iso:std:iso:3166",
1242 | "version": ""
1243 | },
1244 | "PK": {
1245 | "display": "Pakistan",
1246 | "lang": "en",
1247 | "active": true,
1248 | "system": "urn:iso:std:iso:3166",
1249 | "version": ""
1250 | },
1251 | "PL": {
1252 | "display": "Poland",
1253 | "lang": "en",
1254 | "active": true,
1255 | "system": "urn:iso:std:iso:3166",
1256 | "version": ""
1257 | },
1258 | "PM": {
1259 | "display": "Saint Pierre and Miquelon",
1260 | "lang": "en",
1261 | "active": true,
1262 | "system": "urn:iso:std:iso:3166",
1263 | "version": ""
1264 | },
1265 | "PN": {
1266 | "display": "Pitcairn",
1267 | "lang": "en",
1268 | "active": true,
1269 | "system": "urn:iso:std:iso:3166",
1270 | "version": ""
1271 | },
1272 | "PR": {
1273 | "display": "Puerto Rico",
1274 | "lang": "en",
1275 | "active": true,
1276 | "system": "urn:iso:std:iso:3166",
1277 | "version": ""
1278 | },
1279 | "PS": {
1280 | "display": "Palestine, State of",
1281 | "lang": "en",
1282 | "active": true,
1283 | "system": "urn:iso:std:iso:3166",
1284 | "version": ""
1285 | },
1286 | "PT": {
1287 | "display": "Portugal",
1288 | "lang": "en",
1289 | "active": true,
1290 | "system": "urn:iso:std:iso:3166",
1291 | "version": ""
1292 | },
1293 | "PW": {
1294 | "display": "Palau",
1295 | "lang": "en",
1296 | "active": true,
1297 | "system": "urn:iso:std:iso:3166",
1298 | "version": ""
1299 | },
1300 | "PY": {
1301 | "display": "Paraguay",
1302 | "lang": "en",
1303 | "active": true,
1304 | "system": "urn:iso:std:iso:3166",
1305 | "version": ""
1306 | },
1307 | "QA": {
1308 | "display": "Qatar",
1309 | "lang": "en",
1310 | "active": true,
1311 | "system": "urn:iso:std:iso:3166",
1312 | "version": ""
1313 | },
1314 | "RE": {
1315 | "display": "Réunion",
1316 | "lang": "en",
1317 | "active": true,
1318 | "system": "urn:iso:std:iso:3166",
1319 | "version": ""
1320 | },
1321 | "RO": {
1322 | "display": "Romania",
1323 | "lang": "en",
1324 | "active": true,
1325 | "system": "urn:iso:std:iso:3166",
1326 | "version": ""
1327 | },
1328 | "RS": {
1329 | "display": "Serbia",
1330 | "lang": "en",
1331 | "active": true,
1332 | "system": "urn:iso:std:iso:3166",
1333 | "version": ""
1334 | },
1335 | "RU": {
1336 | "display": "Russian Federation",
1337 | "lang": "en",
1338 | "active": true,
1339 | "system": "urn:iso:std:iso:3166",
1340 | "version": ""
1341 | },
1342 | "RW": {
1343 | "display": "Rwanda",
1344 | "lang": "en",
1345 | "active": true,
1346 | "system": "urn:iso:std:iso:3166",
1347 | "version": ""
1348 | },
1349 | "SA": {
1350 | "display": "Saudi Arabia",
1351 | "lang": "en",
1352 | "active": true,
1353 | "system": "urn:iso:std:iso:3166",
1354 | "version": ""
1355 | },
1356 | "SB": {
1357 | "display": "Solomon Islands",
1358 | "lang": "en",
1359 | "active": true,
1360 | "system": "urn:iso:std:iso:3166",
1361 | "version": ""
1362 | },
1363 | "SC": {
1364 | "display": "Seychelles",
1365 | "lang": "en",
1366 | "active": true,
1367 | "system": "urn:iso:std:iso:3166",
1368 | "version": ""
1369 | },
1370 | "SD": {
1371 | "display": "Sudan",
1372 | "lang": "en",
1373 | "active": true,
1374 | "system": "urn:iso:std:iso:3166",
1375 | "version": ""
1376 | },
1377 | "SE": {
1378 | "display": "Sweden",
1379 | "lang": "en",
1380 | "active": true,
1381 | "system": "urn:iso:std:iso:3166",
1382 | "version": ""
1383 | },
1384 | "SG": {
1385 | "display": "Singapore",
1386 | "lang": "en",
1387 | "active": true,
1388 | "system": "urn:iso:std:iso:3166",
1389 | "version": ""
1390 | },
1391 | "SH": {
1392 | "display": "Saint Helena, Ascension and Tristan da Cunha",
1393 | "lang": "en",
1394 | "active": true,
1395 | "system": "urn:iso:std:iso:3166",
1396 | "version": ""
1397 | },
1398 | "SI": {
1399 | "display": "Slovenia",
1400 | "lang": "en",
1401 | "active": true,
1402 | "system": "urn:iso:std:iso:3166",
1403 | "version": ""
1404 | },
1405 | "SJ": {
1406 | "display": "Svalbard and Jan Mayen",
1407 | "lang": "en",
1408 | "active": true,
1409 | "system": "urn:iso:std:iso:3166",
1410 | "version": ""
1411 | },
1412 | "SK": {
1413 | "display": "Slovakia",
1414 | "lang": "en",
1415 | "active": true,
1416 | "system": "urn:iso:std:iso:3166",
1417 | "version": ""
1418 | },
1419 | "SL": {
1420 | "display": "Sierra Leone",
1421 | "lang": "en",
1422 | "active": true,
1423 | "system": "urn:iso:std:iso:3166",
1424 | "version": ""
1425 | },
1426 | "SM": {
1427 | "display": "San Marino",
1428 | "lang": "en",
1429 | "active": true,
1430 | "system": "urn:iso:std:iso:3166",
1431 | "version": ""
1432 | },
1433 | "SN": {
1434 | "display": "Senegal",
1435 | "lang": "en",
1436 | "active": true,
1437 | "system": "urn:iso:std:iso:3166",
1438 | "version": ""
1439 | },
1440 | "SO": {
1441 | "display": "Somalia",
1442 | "lang": "en",
1443 | "active": true,
1444 | "system": "urn:iso:std:iso:3166",
1445 | "version": ""
1446 | },
1447 | "SR": {
1448 | "display": "Suriname",
1449 | "lang": "en",
1450 | "active": true,
1451 | "system": "urn:iso:std:iso:3166",
1452 | "version": ""
1453 | },
1454 | "SS": {
1455 | "display": "South Sudan",
1456 | "lang": "en",
1457 | "active": true,
1458 | "system": "urn:iso:std:iso:3166",
1459 | "version": ""
1460 | },
1461 | "ST": {
1462 | "display": "Sao Tome and Principe",
1463 | "lang": "en",
1464 | "active": true,
1465 | "system": "urn:iso:std:iso:3166",
1466 | "version": ""
1467 | },
1468 | "SV": {
1469 | "display": "El Salvador",
1470 | "lang": "en",
1471 | "active": true,
1472 | "system": "urn:iso:std:iso:3166",
1473 | "version": ""
1474 | },
1475 | "SX": {
1476 | "display": "Sint Maarten (Dutch part)",
1477 | "lang": "en",
1478 | "active": true,
1479 | "system": "urn:iso:std:iso:3166",
1480 | "version": ""
1481 | },
1482 | "SY": {
1483 | "display": "Syrian Arab Republic",
1484 | "lang": "en",
1485 | "active": true,
1486 | "system": "urn:iso:std:iso:3166",
1487 | "version": ""
1488 | },
1489 | "SZ": {
1490 | "display": "Swaziland",
1491 | "lang": "en",
1492 | "active": true,
1493 | "system": "urn:iso:std:iso:3166",
1494 | "version": ""
1495 | },
1496 | "TC": {
1497 | "display": "Turks and Caicos Islands",
1498 | "lang": "en",
1499 | "active": true,
1500 | "system": "urn:iso:std:iso:3166",
1501 | "version": ""
1502 | },
1503 | "TD": {
1504 | "display": "Chad",
1505 | "lang": "en",
1506 | "active": true,
1507 | "system": "urn:iso:std:iso:3166",
1508 | "version": ""
1509 | },
1510 | "TF": {
1511 | "display": "French Southern Territories",
1512 | "lang": "en",
1513 | "active": true,
1514 | "system": "urn:iso:std:iso:3166",
1515 | "version": ""
1516 | },
1517 | "TG": {
1518 | "display": "Togo",
1519 | "lang": "en",
1520 | "active": true,
1521 | "system": "urn:iso:std:iso:3166",
1522 | "version": ""
1523 | },
1524 | "TH": {
1525 | "display": "Thailand",
1526 | "lang": "en",
1527 | "active": true,
1528 | "system": "urn:iso:std:iso:3166",
1529 | "version": ""
1530 | },
1531 | "TJ": {
1532 | "display": "Tajikistan",
1533 | "lang": "en",
1534 | "active": true,
1535 | "system": "urn:iso:std:iso:3166",
1536 | "version": ""
1537 | },
1538 | "TK": {
1539 | "display": "Tokelau",
1540 | "lang": "en",
1541 | "active": true,
1542 | "system": "urn:iso:std:iso:3166",
1543 | "version": ""
1544 | },
1545 | "TL": {
1546 | "display": "Timor-Leste",
1547 | "lang": "en",
1548 | "active": true,
1549 | "system": "urn:iso:std:iso:3166",
1550 | "version": ""
1551 | },
1552 | "TM": {
1553 | "display": "Turkmenistan",
1554 | "lang": "en",
1555 | "active": true,
1556 | "system": "urn:iso:std:iso:3166",
1557 | "version": ""
1558 | },
1559 | "TN": {
1560 | "display": "Tunisia",
1561 | "lang": "en",
1562 | "active": true,
1563 | "system": "urn:iso:std:iso:3166",
1564 | "version": ""
1565 | },
1566 | "TO": {
1567 | "display": "Tonga",
1568 | "lang": "en",
1569 | "active": true,
1570 | "system": "urn:iso:std:iso:3166",
1571 | "version": ""
1572 | },
1573 | "TR": {
1574 | "display": "Turkey",
1575 | "lang": "en",
1576 | "active": true,
1577 | "system": "urn:iso:std:iso:3166",
1578 | "version": ""
1579 | },
1580 | "TT": {
1581 | "display": "Trinidad and Tobago",
1582 | "lang": "en",
1583 | "active": true,
1584 | "system": "urn:iso:std:iso:3166",
1585 | "version": ""
1586 | },
1587 | "TV": {
1588 | "display": "Tuvalu",
1589 | "lang": "en",
1590 | "active": true,
1591 | "system": "urn:iso:std:iso:3166",
1592 | "version": ""
1593 | },
1594 | "TW": {
1595 | "display": "Taiwan, Province of China",
1596 | "lang": "en",
1597 | "active": true,
1598 | "system": "urn:iso:std:iso:3166",
1599 | "version": ""
1600 | },
1601 | "TZ": {
1602 | "display": "Tanzania, United Republic of",
1603 | "lang": "en",
1604 | "active": true,
1605 | "system": "urn:iso:std:iso:3166",
1606 | "version": ""
1607 | },
1608 | "UA": {
1609 | "display": "Ukraine",
1610 | "lang": "en",
1611 | "active": true,
1612 | "system": "urn:iso:std:iso:3166",
1613 | "version": ""
1614 | },
1615 | "UG": {
1616 | "display": "Uganda",
1617 | "lang": "en",
1618 | "active": true,
1619 | "system": "urn:iso:std:iso:3166",
1620 | "version": ""
1621 | },
1622 | "UM": {
1623 | "display": "United States Minor Outlying Islands",
1624 | "lang": "en",
1625 | "active": true,
1626 | "system": "urn:iso:std:iso:3166",
1627 | "version": ""
1628 | },
1629 | "US": {
1630 | "display": "United States of America",
1631 | "lang": "en",
1632 | "active": true,
1633 | "system": "urn:iso:std:iso:3166",
1634 | "version": ""
1635 | },
1636 | "UY": {
1637 | "display": "Uruguay",
1638 | "lang": "en",
1639 | "active": true,
1640 | "system": "urn:iso:std:iso:3166",
1641 | "version": ""
1642 | },
1643 | "UZ": {
1644 | "display": "Uzbekistan",
1645 | "lang": "en",
1646 | "active": true,
1647 | "system": "urn:iso:std:iso:3166",
1648 | "version": ""
1649 | },
1650 | "VA": {
1651 | "display": "Holy See",
1652 | "lang": "en",
1653 | "active": true,
1654 | "system": "urn:iso:std:iso:3166",
1655 | "version": ""
1656 | },
1657 | "VC": {
1658 | "display": "Saint Vincent and the Grenadines",
1659 | "lang": "en",
1660 | "active": true,
1661 | "system": "urn:iso:std:iso:3166",
1662 | "version": ""
1663 | },
1664 | "VE": {
1665 | "display": "Venezuela, Bolivarian Republic of",
1666 | "lang": "en",
1667 | "active": true,
1668 | "system": "urn:iso:std:iso:3166",
1669 | "version": ""
1670 | },
1671 | "VG": {
1672 | "display": "Virgin Islands, British",
1673 | "lang": "en",
1674 | "active": true,
1675 | "system": "urn:iso:std:iso:3166",
1676 | "version": ""
1677 | },
1678 | "VI": {
1679 | "display": "Virgin Islands,",
1680 | "lang": "en",
1681 | "active": true,
1682 | "system": "urn:iso:std:iso:3166",
1683 | "version": ""
1684 | },
1685 | "VN": {
1686 | "display": "Viet Nam",
1687 | "lang": "en",
1688 | "active": true,
1689 | "system": "urn:iso:std:iso:3166",
1690 | "version": ""
1691 | },
1692 | "VU": {
1693 | "display": "Vanuatu",
1694 | "lang": "en",
1695 | "active": true,
1696 | "system": "urn:iso:std:iso:3166",
1697 | "version": ""
1698 | },
1699 | "WF": {
1700 | "display": "Wallis and Futuna",
1701 | "lang": "en",
1702 | "active": true,
1703 | "system": "urn:iso:std:iso:3166",
1704 | "version": ""
1705 | },
1706 | "WS": {
1707 | "display": "Samoa",
1708 | "lang": "en",
1709 | "active": true,
1710 | "system": "urn:iso:std:iso:3166",
1711 | "version": ""
1712 | },
1713 | "YE": {
1714 | "display": "Yemen",
1715 | "lang": "en",
1716 | "active": true,
1717 | "system": "urn:iso:std:iso:3166",
1718 | "version": ""
1719 | },
1720 | "YT": {
1721 | "display": "Mayotte",
1722 | "lang": "en",
1723 | "active": true,
1724 | "system": "urn:iso:std:iso:3166",
1725 | "version": ""
1726 | },
1727 | "ZA": {
1728 | "display": "South Africa",
1729 | "lang": "en",
1730 | "active": true,
1731 | "system": "urn:iso:std:iso:3166",
1732 | "version": ""
1733 | },
1734 | "ZM": {
1735 | "display": "Zambia",
1736 | "lang": "en",
1737 | "active": true,
1738 | "system": "urn:iso:std:iso:3166",
1739 | "version": ""
1740 | },
1741 | "ZW": {
1742 | "display": "Zimbabwe",
1743 | "lang": "en",
1744 | "active": true,
1745 | "system": "urn:iso:std:iso:3166",
1746 | "version": ""
1747 | }
1748 | }
1749 | }
--------------------------------------------------------------------------------
/src/data/disease-agent-targeted.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "disease-agent-targeted",
3 | "valueSetDate": "2021-04-27",
4 | "valueSetValues": {
5 | "840539006": {
6 | "display": "COVID-19",
7 | "lang": "en",
8 | "active": true,
9 | "version": "http://snomed.info/sct/900000000000207008/version/20210131",
10 | "system": "http://snomed.info/sct"
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/data/test-manf.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "covid-19-lab-test-manufacturer-and-name",
3 | "valueSetDate": "2021-05-27",
4 | "valueSetValues": {
5 | "1833": {
6 | "display": "AAZ-LMB, COVID-VIRO",
7 | "lang": "en",
8 | "active": true,
9 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
10 | "version": "2021-05-17 11:02:12 CET"
11 | },
12 | "1232": {
13 | "display": "Abbott Rapid Diagnostics, Panbio COVID-19 Ag Rapid Test",
14 | "lang": "en",
15 | "active": true,
16 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
17 | "version": "2021-05-17 11:01:42 CET"
18 | },
19 | "1468": {
20 | "display": "ACON Laboratories, Inc, Flowflex SARS-CoV-2 Antigen rapid test",
21 | "lang": "en",
22 | "active": true,
23 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
24 | "version": "2021-05-10 20:07:30 CET"
25 | },
26 | "1304": {
27 | "display": "AMEDA Labordiagnostik GmbH, AMP Rapid Test SARS-CoV-2 Ag",
28 | "lang": "en",
29 | "active": true,
30 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
31 | "version": "2021-05-10 13:04:00 CET"
32 | },
33 | "1822": {
34 | "display": "Anbio (Xiamen) Biotechnology Co., Ltd, Rapid COVID-19 Antigen Test(Colloidal Gold)",
35 | "lang": "en",
36 | "active": true,
37 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
38 | "version": "2021-05-10 19:40:14 CET"
39 | },
40 | "1815": {
41 | "display": "Anhui Deep Blue Medical Technology Co., Ltd, COVID-19 (SARS-CoV-2) Antigen Test Kit (Colloidal Gold) - Nasal Swab",
42 | "lang": "en",
43 | "active": true,
44 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
45 | "version": "2021-05-12 12:27:46 CET"
46 | },
47 | "1736": {
48 | "display": "Anhui Deep Blue Medical Technology Co., Ltd, COVID-19 (SARS-CoV-2) Antigen Test Kit(Colloidal Gold)",
49 | "lang": "en",
50 | "active": true,
51 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
52 | "version": "2021-05-10 19:40:14 CET"
53 | },
54 | "768": {
55 | "display": "ArcDia International Ltd, mariPOC SARS-CoV-2",
56 | "lang": "en",
57 | "active": true,
58 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
59 | "version": "2021-05-19 17:12:12 CET"
60 | },
61 | "1654": {
62 | "display": "Asan Pharmaceutical CO., LTD, Asan Easy Test COVID-19 Ag",
63 | "lang": "en",
64 | "active": true,
65 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
66 | "version": "2021-05-10 19:40:14 CET"
67 | },
68 | "2010": {
69 | "display": "Atlas Link Technology Co., Ltd., NOVA Test® SARS-CoV-2 Antigen Rapid Test Kit (Colloidal Gold Immunochromatography)",
70 | "lang": "en",
71 | "active": true,
72 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
73 | "version": "2021-05-11 09:29:55 CET"
74 | },
75 | "1906": {
76 | "display": "Azure Biotech Inc, COVID-19 Antigen Rapid Test Device",
77 | "lang": "en",
78 | "active": true,
79 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
80 | "version": "2021-05-19 17:14:21 CET"
81 | },
82 | "1870": {
83 | "display": "Beijing Hotgen Biotech Co., Ltd, Novel Coronavirus 2019-nCoV Antigen Test (Colloidal Gold)",
84 | "lang": "en",
85 | "active": true,
86 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
87 | "version": "2021-05-10 20:07:30 CET"
88 | },
89 | "1331": {
90 | "display": "Beijing Lepu Medical Technology Co., Ltd, SARS-CoV-2 Antigen Rapid Test Kit",
91 | "lang": "en",
92 | "active": true,
93 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
94 | "version": "2021-05-10 13:04:00 CET"
95 | },
96 | "1484": {
97 | "display": "Beijing Wantai Biological Pharmacy Enterprise Co., Ltd, Wantai SARS-CoV-2 Ag Rapid Test (FIA)",
98 | "lang": "en",
99 | "active": true,
100 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
101 | "version": "2021-05-10 13:04:00 CET"
102 | },
103 | "1223": {
104 | "display": "BIOSYNEX S.A., BIOSYNEX COVID-19 Ag BSS",
105 | "lang": "en",
106 | "active": true,
107 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
108 | "version": "2021-05-10 13:18:20 CET"
109 | },
110 | "1236": {
111 | "display": "BTNX Inc, Rapid Response COVID-19 Antigen Rapid Test",
112 | "lang": "en",
113 | "active": true,
114 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
115 | "version": "2021-05-10 19:40:13 CET"
116 | },
117 | "1173": {
118 | "display": "CerTest Biotec, CerTest SARS-CoV-2 Card test",
119 | "lang": "en",
120 | "active": true,
121 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
122 | "version": "2021-05-10 13:18:20 CET"
123 | },
124 | "1919": {
125 | "display": "Core Technology Co., Ltd, Coretests COVID-19 Ag Test",
126 | "lang": "en",
127 | "active": true,
128 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
129 | "version": "2021-05-10 20:12:51 CET"
130 | },
131 | "1225": {
132 | "display": "DDS DIAGNOSTIC, Test Rapid Covid-19 Antigen (tampon nazofaringian)",
133 | "lang": "en",
134 | "active": true,
135 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
136 | "version": "2021-05-10 19:40:13 CET"
137 | },
138 | "1375": {
139 | "display": "DIALAB GmbH, DIAQUICK COVID-19 Ag Cassette",
140 | "lang": "en",
141 | "active": true,
142 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
143 | "version": "2021-05-10 20:07:30 CET"
144 | },
145 | "1244": {
146 | "display": "GenBody, Inc, Genbody COVID-19 Ag Test",
147 | "lang": "en",
148 | "active": true,
149 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
150 | "version": "2021-05-10 13:04:00 CET"
151 | },
152 | "1253": {
153 | "display": "GenSure Biotech Inc, GenSure COVID-19 Antigen Rapid Kit (REF: P2004)",
154 | "lang": "en",
155 | "active": true,
156 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
157 | "version": "2021-05-10 19:40:14 CET"
158 | },
159 | "1144": {
160 | "display": "Green Cross Medical Science Corp., GENEDIA W COVID-19 Ag",
161 | "lang": "en",
162 | "active": true,
163 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
164 | "version": "2021-05-11 09:31:09 CET"
165 | },
166 | "1747": {
167 | "display": "Guangdong Hecin Scientific, Inc., 2019-nCoV Antigen Test Kit (colloidal gold method)",
168 | "lang": "en",
169 | "active": true,
170 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
171 | "version": "2021-05-10 19:40:14 CET"
172 | },
173 | "1360": {
174 | "display": "Guangdong Wesail Biotech Co., Ltd, COVID-19 Ag Test Kit",
175 | "lang": "en",
176 | "active": true,
177 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
178 | "version": "2021-05-10 13:04:00 CET"
179 | },
180 | "1437": {
181 | "display": "Guangzhou Wondfo Biotech Co., Ltd, Wondfo 2019-nCoV Antigen Test (Lateral Flow Method)",
182 | "lang": "en",
183 | "active": true,
184 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
185 | "version": "2021-05-10 20:07:30 CET"
186 | },
187 | "1256": {
188 | "display": "Hangzhou AllTest Biotech Co., Ltd, COVID-19 and Influenza A+B Antigen Combo Rapid Test",
189 | "lang": "en",
190 | "active": true,
191 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
192 | "version": "2021-05-10 19:40:14 CET"
193 | },
194 | "1363": {
195 | "display": "Hangzhou Clongene Biotech Co., Ltd, Covid-19 Antigen Rapid Test Kit",
196 | "lang": "en",
197 | "active": true,
198 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
199 | "version": "2021-05-10 13:04:00 CET"
200 | },
201 | "1365": {
202 | "display": "Hangzhou Clongene Biotech Co., Ltd, COVID-19/Influenza A+B Antigen Combo Rapid Test",
203 | "lang": "en",
204 | "active": true,
205 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
206 | "version": "2021-05-10 19:40:14 CET"
207 | },
208 | "1844": {
209 | "display": "Hangzhou Immuno Biotech Co.,Ltd, Immunobio SARS-CoV-2 Antigen ANTERIOR NASAL Rapid Test Kit (minimal invasive)",
210 | "lang": "en",
211 | "active": true,
212 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
213 | "version": "2021-05-10 19:40:14 CET"
214 | },
215 | "1215": {
216 | "display": "Hangzhou Laihe Biotech Co., Ltd, LYHER Novel Coronavirus (COVID-19) Antigen Test Kit(Colloidal Gold)",
217 | "lang": "en",
218 | "active": true,
219 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
220 | "version": "2021-05-10 19:40:13 CET"
221 | },
222 | "1392": {
223 | "display": "Hangzhou Testsea Biotechnology Co., Ltd, COVID-19 Antigen Test Cassette",
224 | "lang": "en",
225 | "active": true,
226 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
227 | "version": "2021-05-10 19:40:14 CET"
228 | },
229 | "1767": {
230 | "display": "Healgen Scientific, Coronavirus Ag Rapid Test Cassette",
231 | "lang": "en",
232 | "active": true,
233 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
234 | "version": "2021-05-10 13:18:20 CET"
235 | },
236 | "1263": {
237 | "display": "Humasis, Humasis COVID-19 Ag Test",
238 | "lang": "en",
239 | "active": true,
240 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
241 | "version": "2021-05-10 20:07:30 CET"
242 | },
243 | "1333": {
244 | "display": "Joinstar Biomedical Technology Co., Ltd, COVID-19 Rapid Antigen Test (Colloidal Gold)",
245 | "lang": "en",
246 | "active": true,
247 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
248 | "version": "2021-05-10 20:07:30 CET"
249 | },
250 | "1764": {
251 | "display": "JOYSBIO (Tianjin) Biotechnology Co., Ltd, SARS-CoV-2 Antigen Rapid Test Kit (Colloidal Gold)",
252 | "lang": "en",
253 | "active": true,
254 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
255 | "version": "2021-05-11 09:28:10 CET"
256 | },
257 | "1266": {
258 | "display": "Labnovation Technologies Inc, SARS-CoV-2 Antigen Rapid Test Kit",
259 | "lang": "en",
260 | "active": true,
261 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
262 | "version": "2021-05-10 19:40:14 CET"
263 | },
264 | "1267": {
265 | "display": "LumiQuick Diagnostics Inc, QuickProfile COVID-19 Antigen Test",
266 | "lang": "en",
267 | "active": true,
268 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
269 | "version": "2021-05-10 20:07:30 CET"
270 | },
271 | "1268": {
272 | "display": "LumiraDX, LumiraDx SARS-CoV-2 Ag Test",
273 | "lang": "en",
274 | "active": true,
275 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
276 | "version": "2021-05-10 13:18:20 CET"
277 | },
278 | "1180": {
279 | "display": "MEDsan GmbH, MEDsan SARS-CoV-2 Antigen Rapid Test",
280 | "lang": "en",
281 | "active": true,
282 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
283 | "version": "2021-05-10 20:07:30 CET"
284 | },
285 | "1190": {
286 | "display": "möLab, COVID-19 Rapid Antigen Test",
287 | "lang": "en",
288 | "active": true,
289 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
290 | "version": "2021-05-10 19:40:13 CET"
291 | },
292 | "1481": {
293 | "display": "MP Biomedicals, Rapid SARS-CoV-2 Antigen Test Card",
294 | "lang": "en",
295 | "active": true,
296 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
297 | "version": "2021-05-10 20:07:30 CET"
298 | },
299 | "1162": {
300 | "display": "Nal von minden GmbH, NADAL COVID-19 Ag Test",
301 | "lang": "en",
302 | "active": true,
303 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
304 | "version": "2021-05-10 13:04:00 CET"
305 | },
306 | "1420": {
307 | "display": "NanoEntek, FREND COVID-19 Ag",
308 | "lang": "en",
309 | "active": true,
310 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
311 | "version": "2021-05-10 19:40:14 CET"
312 | },
313 | "1199": {
314 | "display": "Oncosem Onkolojik Sistemler San. ve Tic. A.S., CAT",
315 | "lang": "en",
316 | "active": true,
317 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
318 | "version": "2021-05-10 19:40:13 CET"
319 | },
320 | "308": {
321 | "display": "PCL Inc, PCL COVID19 Ag Rapid FIA",
322 | "lang": "en",
323 | "active": true,
324 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
325 | "version": "2021-05-10 20:07:30 CET"
326 | },
327 | "1271": {
328 | "display": "Precision Biosensor, Inc, Exdia COVID-19 Ag",
329 | "lang": "en",
330 | "active": true,
331 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
332 | "version": "2021-05-10 13:04:00 CET"
333 | },
334 | "1341": {
335 | "display": "Qingdao Hightop Biotech Co., Ltd, SARS-CoV-2 Antigen Rapid Test (Immunochromatography)",
336 | "lang": "en",
337 | "active": true,
338 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
339 | "version": "2021-05-10 13:04:00 CET"
340 | },
341 | "1097": {
342 | "display": "Quidel Corporation, Sofia SARS Antigen FIA",
343 | "lang": "en",
344 | "active": true,
345 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
346 | "version": "2021-05-10 13:04:00 CET"
347 | },
348 | "1606": {
349 | "display": "RapiGEN Inc, BIOCREDIT COVID-19 Ag - SARS-CoV 2 Antigen test",
350 | "lang": "en",
351 | "active": true,
352 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
353 | "version": "2021-05-10 20:07:30 CET"
354 | },
355 | "1604": {
356 | "display": "Roche (SD BIOSENSOR), SARS-CoV-2 Antigen Rapid Test",
357 | "lang": "en",
358 | "active": true,
359 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
360 | "version": "2021-05-10 20:07:30 CET"
361 | },
362 | "1489": {
363 | "display": "Safecare Biotech (Hangzhou) Co. Ltd, COVID-19 Antigen Rapid Test Kit (Swab)",
364 | "lang": "en",
365 | "active": true,
366 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
367 | "version": "2021-05-12 12:58:25 CET"
368 | },
369 | "1490": {
370 | "display": "Safecare Biotech (Hangzhou) Co. Ltd, Multi-Respiratory Virus Antigen Test Kit(Swab) (Influenza A+B/ COVID-19)",
371 | "lang": "en",
372 | "active": true,
373 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
374 | "version": "2021-05-10 19:40:14 CET"
375 | },
376 | "344": {
377 | "display": "SD BIOSENSOR Inc, STANDARD F COVID-19 Ag FIA",
378 | "lang": "en",
379 | "active": true,
380 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
381 | "version": "2021-05-10 13:04:00 CET"
382 | },
383 | "345": {
384 | "display": "SD BIOSENSOR Inc, STANDARD Q COVID-19 Ag Test",
385 | "lang": "en",
386 | "active": true,
387 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
388 | "version": "2021-05-10 13:04:00 CET"
389 | },
390 | "1319": {
391 | "display": "SGA Medikal, V-Chek SARS-CoV-2 Ag Rapid Test Kit (Colloidal Gold)",
392 | "lang": "en",
393 | "active": true,
394 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
395 | "version": "2021-05-10 19:40:14 CET"
396 | },
397 | "2017": {
398 | "display": "Shenzhen Ultra-Diagnostics Biotec.Co.,Ltd, SARS-CoV-2 Antigen Test Kit",
399 | "lang": "en",
400 | "active": true,
401 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
402 | "version": "2021-05-19 17:15:38 CET"
403 | },
404 | "1769": {
405 | "display": "Shenzhen Watmind Medical Co., Ltd, SARS-CoV-2 Ag Diagnostic Test Kit (Colloidal Gold)",
406 | "lang": "en",
407 | "active": true,
408 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
409 | "version": "2021-05-10 20:07:30 CET"
410 | },
411 | "1574": {
412 | "display": "Shenzhen Zhenrui Biotechnology Co., Ltd, Zhenrui ®COVID-19 Antigen Test Cassette",
413 | "lang": "en",
414 | "active": true,
415 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
416 | "version": "2021-05-10 19:40:14 CET"
417 | },
418 | "1218": {
419 | "display": "Siemens Healthineers, CLINITEST Rapid Covid-19 Antigen Test",
420 | "lang": "en",
421 | "active": true,
422 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
423 | "version": "2021-05-10 13:04:00 CET"
424 | },
425 | "1114": {
426 | "display": "Sugentech, Inc, SGTi-flex COVID-19 Ag",
427 | "lang": "en",
428 | "active": true,
429 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
430 | "version": "2021-05-10 19:40:13 CET"
431 | },
432 | "1466": {
433 | "display": "TODA PHARMA, TODA CORONADIAG Ag",
434 | "lang": "en",
435 | "active": true,
436 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
437 | "version": "2021-05-10 20:07:30 CET"
438 | },
439 | "1934": {
440 | "display": "Tody Laboratories Int., Coronavirus (SARS-CoV 2) Antigen - Oral Fluid",
441 | "lang": "en",
442 | "active": true,
443 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
444 | "version": "2021-05-19 17:16:42 CET"
445 | },
446 | "1443": {
447 | "display": "Vitrosens Biotechnology Co., Ltd, RapidFor SARS-CoV-2 Rapid Ag Test",
448 | "lang": "en",
449 | "active": true,
450 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
451 | "version": "2021-05-10 19:40:14 CET"
452 | },
453 | "1246": {
454 | "display": "VivaChek Biotech (Hangzhou) Co., Ltd, Vivadiag SARS CoV 2 Ag Rapid Test",
455 | "lang": "en",
456 | "active": true,
457 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
458 | "version": "2021-05-10 19:40:14 CET"
459 | },
460 | "1763": {
461 | "display": "Xiamen AmonMed Biotechnology Co., Ltd, COVID-19 Antigen Rapid Test Kit (Colloidal Gold)",
462 | "lang": "en",
463 | "active": true,
464 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
465 | "version": "2021-05-10 19:40:14 CET"
466 | },
467 | "1278": {
468 | "display": "Xiamen Boson Biotech Co. Ltd, Rapid SARS-CoV-2 Antigen Test Card",
469 | "lang": "en",
470 | "active": true,
471 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
472 | "version": "2021-05-10 13:04:00 CET"
473 | },
474 | "1456": {
475 | "display": "Xiamen Wiz Biotech Co., Ltd, SARS-CoV-2 Antigen Rapid Test",
476 | "lang": "en",
477 | "active": true,
478 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
479 | "version": "2021-05-19 17:10:21 CET"
480 | },
481 | "1884": {
482 | "display": "Xiamen Wiz Biotech Co., Ltd, SARS-CoV-2 Antigen Rapid Test (Colloidal Gold)",
483 | "lang": "en",
484 | "active": true,
485 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
486 | "version": "2021-05-20 15:15:25 CET"
487 | },
488 | "1296": {
489 | "display": "Zhejiang Anji Saianfu Biotech Co., Ltd, AndLucky COVID-19 Antigen Rapid Test",
490 | "lang": "en",
491 | "active": true,
492 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
493 | "version": "2021-05-10 19:40:14 CET"
494 | },
495 | "1295": {
496 | "display": "Zhejiang Anji Saianfu Biotech Co., Ltd, reOpenTest COVID-19 Antigen Rapid Test",
497 | "lang": "en",
498 | "active": true,
499 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
500 | "version": "2021-05-10 19:40:14 CET"
501 | },
502 | "1343": {
503 | "display": "Zhezhiang Orient Gene Biotech Co., Ltd, Coronavirus Ag Rapid Test Cassette (Swab)",
504 | "lang": "en",
505 | "active": true,
506 | "system": "https://covid-19-diagnostics.jrc.ec.europa.eu/devices",
507 | "version": "2021-05-10 13:18:20 CET"
508 | }
509 | }
510 | }
--------------------------------------------------------------------------------
/src/data/test-result.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "covid-19-lab-result",
3 | "valueSetDate": "2021-04-27",
4 | "valueSetValues": {
5 | "260415000": {
6 | "display": "Not detected",
7 | "lang": "en",
8 | "active": true,
9 | "version": "http://snomed.info/sct/900000000000207008/version/20210131",
10 | "system": "http://snomed.info/sct"
11 | },
12 | "260373001": {
13 | "display": "Detected",
14 | "lang": "en",
15 | "active": true,
16 | "version": "http://snomed.info/sct/900000000000207008/version/20210131",
17 | "system": "http://snomed.info/sct"
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/data/test-type.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "covid-19-lab-test-type",
3 | "valueSetDate": "2021-04-27",
4 | "valueSetValues": {
5 | "LP6464-4": {
6 | "display": "Nucleic acid amplification with probe detection",
7 | "lang": "en",
8 | "active": true,
9 | "version": "2.69",
10 | "system": "http://loinc.org"
11 | },
12 | "LP217198-3": {
13 | "display": "Rapid immunoassay",
14 | "lang": "en",
15 | "active": true,
16 | "version": "2.69",
17 | "system": "http://loinc.org"
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/data/vaccine-mah-manf.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "vaccines-covid-19-auth-holders",
3 | "valueSetDate": "2021-04-27",
4 | "valueSetValues": {
5 | "ORG-100001699": {
6 | "display": "AstraZeneca AB",
7 | "lang": "en",
8 | "active": true,
9 | "system": "https://spor.ema.europa.eu/v1/organisations",
10 | "version": ""
11 | },
12 | "ORG-100030215": {
13 | "display": "Biontech Manufacturing GmbH",
14 | "lang": "en",
15 | "active": true,
16 | "system": "https://spor.ema.europa.eu/v1/organisations",
17 | "version": ""
18 | },
19 | "ORG-100001417": {
20 | "display": "Janssen-Cilag International",
21 | "lang": "en",
22 | "active": true,
23 | "system": "https://spor.ema.europa.eu/v1/organisations",
24 | "version": ""
25 | },
26 | "ORG-100031184": {
27 | "display": "Moderna Biotech Spain S.L.",
28 | "lang": "en",
29 | "active": true,
30 | "system": "https://spor.ema.europa.eu/v1/organisations",
31 | "version": ""
32 | },
33 | "ORG-100006270": {
34 | "display": "Curevac AG",
35 | "lang": "en",
36 | "active": true,
37 | "system": "https://spor.ema.europa.eu/v1/organisations",
38 | "version": ""
39 | },
40 | "ORG-100013793": {
41 | "display": "CanSino Biologics",
42 | "lang": "en",
43 | "active": true,
44 | "system": "https://spor.ema.europa.eu/v1/organisations",
45 | "version": ""
46 | },
47 | "ORG-100020693": {
48 | "display": "China Sinopharm International Corp. - Beijing location",
49 | "lang": "en",
50 | "active": true,
51 | "system": "https://spor.ema.europa.eu/v1/organisations",
52 | "version": ""
53 | },
54 | "ORG-100010771": {
55 | "display": "Sinopharm Weiqida Europe Pharmaceutical s.r.o. - Prague location",
56 | "lang": "en",
57 | "active": true,
58 | "system": "https://spor.ema.europa.eu/v1/organisations",
59 | "version": ""
60 | },
61 | "ORG-100024420": {
62 | "display": "Sinopharm Zhijun (Shenzhen) Pharmaceutical Co. Ltd. - Shenzhen location",
63 | "lang": "en",
64 | "active": true,
65 | "system": "https://spor.ema.europa.eu/v1/organisations",
66 | "version": ""
67 | },
68 | "ORG-100032020": {
69 | "display": "Novavax CZ AS",
70 | "lang": "en",
71 | "active": true,
72 | "system": "https://spor.ema.europa.eu/v1/organisations",
73 | "version": ""
74 | },
75 | "Gamaleya-Research-Institute": {
76 | "display": "Gamaleya Research Institute",
77 | "lang": "en",
78 | "active": true,
79 | "system": "http://ec.europa.eu/temp/vaccinemanufacturer",
80 | "version": "1.0"
81 | },
82 | "Vector-Institute": {
83 | "display": "Vector Institute",
84 | "lang": "en",
85 | "active": true,
86 | "system": "http://ec.europa.eu/temp/vaccinemanufacturer",
87 | "version": "1.0"
88 | },
89 | "Sinovac-Biotech": {
90 | "display": "Sinovac Biotech",
91 | "lang": "en",
92 | "active": true,
93 | "system": "http://ec.europa.eu/temp/vaccinemanufacturer",
94 | "version": "1.0"
95 | },
96 | "Bharat-Biotech": {
97 | "display": "Bharat Biotech",
98 | "lang": "en",
99 | "active": true,
100 | "system": "http://ec.europa.eu/temp/vaccinemanufacturer",
101 | "version": "1.0"
102 | }
103 | }
104 | }
--------------------------------------------------------------------------------
/src/data/vaccine-medicinal-product.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "vaccines-covid-19-names",
3 | "valueSetDate": "2021-04-27",
4 | "valueSetValues": {
5 | "EU/1/20/1528": {
6 | "display": "Comirnaty",
7 | "lang": "en",
8 | "active": true,
9 | "system": "https://ec.europa.eu/health/documents/community-register/html/",
10 | "version": ""
11 | },
12 | "EU/1/20/1507": {
13 | "display": "COVID-19 Vaccine Moderna",
14 | "lang": "en",
15 | "active": true,
16 | "system": "https://ec.europa.eu/health/documents/community-register/html/",
17 | "version": ""
18 | },
19 | "EU/1/21/1529": {
20 | "display": "Vaxzevria",
21 | "lang": "en",
22 | "active": true,
23 | "system": "https://ec.europa.eu/health/documents/community-register/html/",
24 | "version": ""
25 | },
26 | "EU/1/20/1525": {
27 | "display": "COVID-19 Vaccine Janssen",
28 | "lang": "en",
29 | "active": true,
30 | "system": "https://ec.europa.eu/health/documents/community-register/html/",
31 | "version": ""
32 | },
33 | "CVnCoV": {
34 | "display": "CVnCoV",
35 | "lang": "en",
36 | "active": true,
37 | "system": "http://ec.europa.eu/temp/vaccineproductname",
38 | "version": "1.0"
39 | },
40 | "Sputnik-V": {
41 | "display": "Sputnik-V",
42 | "lang": "en",
43 | "active": true,
44 | "system": "http://ec.europa.eu/temp/vaccineproductname",
45 | "version": "1.0"
46 | },
47 | "Convidecia": {
48 | "display": "Convidecia",
49 | "lang": "en",
50 | "active": true,
51 | "system": "http://ec.europa.eu/temp/vaccineproductname",
52 | "version": "1.0"
53 | },
54 | "EpiVacCorona": {
55 | "display": "EpiVacCorona",
56 | "lang": "en",
57 | "active": true,
58 | "system": "http://ec.europa.eu/temp/vaccineproductname",
59 | "version": "1.0"
60 | },
61 | "BBIBP-CorV": {
62 | "display": "BBIBP-CorV",
63 | "lang": "en",
64 | "active": true,
65 | "system": "http://ec.europa.eu/temp/vaccineproductname",
66 | "version": "1.0"
67 | },
68 | "Inactivated-SARS-CoV-2-Vero-Cell": {
69 | "display": "Inactivated SARS-CoV-2 (Vero Cell)",
70 | "lang": "en",
71 | "active": true,
72 | "system": "http://ec.europa.eu/temp/vaccineproductname",
73 | "version": "1.0"
74 | },
75 | "CoronaVac": {
76 | "display": "CoronaVac",
77 | "lang": "en",
78 | "active": true,
79 | "system": "http://ec.europa.eu/temp/vaccineproductname",
80 | "version": "1.0"
81 | },
82 | "Covaxin": {
83 | "display": "Covaxin (also known as BBV152 A, B, C)",
84 | "lang": "en",
85 | "active": true,
86 | "system": "http://ec.europa.eu/temp/vaccineproductname",
87 | "version": "1.0"
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/src/data/vaccine-prophylaxis.json:
--------------------------------------------------------------------------------
1 | {
2 | "valueSetId": "sct-vaccines-covid-19",
3 | "valueSetDate": "2021-04-27",
4 | "valueSetValues": {
5 | "1119349007": {
6 | "display": "SARS-CoV-2 mRNA vaccine",
7 | "lang": "en",
8 | "active": true,
9 | "version": "http://snomed.info/sct/900000000000207008/version/20210131",
10 | "system": "http://snomed.info/sct"
11 | },
12 | "1119305005": {
13 | "display": "SARS-CoV-2 antigen vaccine",
14 | "lang": "en",
15 | "active": true,
16 | "version": "http://snomed.info/sct/900000000000207008/version/20210131",
17 | "system": "http://snomed.info/sct"
18 | },
19 | "J07BX03": {
20 | "display": "covid-19 vaccines",
21 | "lang": "en",
22 | "active": true,
23 | "version": "2021-01",
24 | "system": "http://www.whocc.no/atc"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/index.scss:
--------------------------------------------------------------------------------
1 | $feature-flags: (
2 | grid-columns-16: true,
3 | );
4 |
5 | @import 'carbon-components/scss/globals/scss/styles.scss';
6 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter as Router } from 'react-router-dom';
4 |
5 | import '@cpv/index.scss';
6 | import App from '@cpv/App';
7 | import reportWebVitals from '@cpv/reportWebVitals';
8 |
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | document.getElementById('root'),
14 | );
15 |
16 | // If you want to start measuring performance in your app, pass a function
17 | // to log results (for example: reportWebVitals(console.log))
18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
19 | reportWebVitals();
20 |
--------------------------------------------------------------------------------
/src/lib/certificates.ts:
--------------------------------------------------------------------------------
1 | import { equal8 } from '@cpv/lib/typed-array';
2 | import rawCertificates from '@cpv/data/certificates.json';
3 |
4 | export interface Certificate {
5 | kid: Uint8Array;
6 | crt: Uint8Array;
7 | iss: { [tag: string]: string | undefined };
8 | sub: { [tag: string]: string | undefined };
9 | pub: { x: number[]; y: number[] } | null;
10 | }
11 |
12 | export const certificates: Certificate[] = rawCertificates.map((cert) => ({
13 | ...cert,
14 | kid: Uint8Array.from(cert.kid),
15 | crt: Uint8Array.from(cert.crt),
16 | }));
17 |
18 | export const findCertificate = (kid: Uint8Array): Certificate | undefined =>
19 | certificates.find((cert) => equal8(cert.kid, kid));
20 |
21 | export const supportedIssuers = (): string[] => {
22 | return Array.from(new Set(certificates.map((c) => `${c.iss.O}, ${c.iss.C}`))) as string[];
23 | };
24 |
--------------------------------------------------------------------------------
/src/lib/hcert-parser.ts:
--------------------------------------------------------------------------------
1 | import base45 from 'base45-js/lib/base45-js';
2 | import * as cbor from 'cbor-web';
3 | import * as cose from 'cose-js';
4 |
5 | import { equal8 } from '@cpv/lib/typed-array';
6 | import { inflate } from '@cpv/lib/zlib';
7 | import { HCERT } from '@cpv/lib/hcert';
8 | import { findCertificate } from '@cpv/lib/certificates';
9 |
10 | /** CBOR tags used for COSE message identification. */
11 | enum CBORTags {
12 | COSESign = 98,
13 | COSESign1 = 18,
14 | }
15 |
16 | /** Common COSE header parameters. */
17 | enum COSEHeaderParameters {
18 | Algorithm = 1, // alg
19 | CriticalHeaders = 2, // crit
20 | ContentType = 3, // content type
21 | KeyIdentifier = 4, // kid
22 | InitialisationVector = 5, // IV
23 | PartialInitialisationVector = 6, // Partial IV
24 | CounterSignature = 7, // counter signature
25 | }
26 |
27 | /** COSE signature algorithms used to verify the signature. */
28 | enum COSESignatureAlgoritms {
29 | ES256_SHA256 = -7,
30 | }
31 |
32 | /** Claims in the CBOR Web Token. */
33 | enum CWTClaims {
34 | Issuer = 1, // iss
35 | IssuedAt = 6, // iat
36 | ExpirationTime = 4, // exp
37 | HealthCertificate = -260, // hcert
38 | }
39 |
40 | /**
41 | * Claims in a Health Certificate.
42 | * Note: Currently all government-issued certificates share the same claim key.
43 | */
44 | enum HCERTClaims {
45 | DigitalHealthCertificate = 1, // eu_dgc_v1, this claim is the same for NHS COVID Passes too.
46 | }
47 |
48 | /** List of KIDs to exclude from the COSE signature verification. */
49 | const EXCLUDED_KIDS: Uint8Array[] = [
50 | Uint8Array.from([217, 25, 55, 95, 193, 231, 182, 178]), // https://dgc.a-sit.at/ehn test certificate
51 | ];
52 |
53 | /**
54 | * Parses the given 2D barcode payload.
55 | * @return Compressed CBOR Web Token payload contained within the 2D barcode.
56 | */
57 | const parseBarcode = (payload: string): Uint8Array => {
58 | const supportedVersions = ['1'];
59 |
60 | if (!/^HC[1-9A-Z]:/.test(payload)) {
61 | throw new Error('missing HCERT context indetifier in barcode payload');
62 | }
63 |
64 | const version = payload[2];
65 | if (!supportedVersions.includes(version)) {
66 | throw new Error(`unsupportted HCERT version: ${version}`);
67 | }
68 |
69 | // Strip off HCERT context identifier.
70 | const stripped = payload.substring(4);
71 | return new Uint8Array(base45.decode(stripped));
72 | };
73 |
74 | /**
75 | * Parses a HCERT payload as specified in
76 | * https://github.com/ehn-dcc-development/hcert-spec/releases/download/1.0.5/dgc_spec-1.0.5-final.pdf
77 | */
78 | export const parseHCERT = async (barcodePayload: string): Promise => {
79 | // The HCERT barcode payload is a compressed CBOR Web Token.
80 | const cwt = inflate(parseBarcode(barcodePayload));
81 |
82 | // CBOR Web Token is technically a signed COSE message (https://datatracker.ietf.org/doc/html/rfc8392#page-8).
83 | const coseSignedMsg = cbor.decode(cwt);
84 |
85 | // Validate the structure of the decoded CBOR structure.
86 | if (
87 | (coseSignedMsg.tag !== CBORTags.COSESign && coseSignedMsg.tag !== CBORTags.COSESign1) ||
88 | coseSignedMsg.value.length !== 4
89 | ) {
90 | throw new Error('invalid COSE sign structure');
91 | }
92 |
93 | // Deconstruct the COSE sign structure (https://datatracker.ietf.org/doc/html/rfc8152#page-17)
94 | const [prot, , payload] = coseSignedMsg.value; // Array content: [protected, unprotected, payload, signers]. We only use the protected header for now.
95 |
96 | // Verify COSE signature.
97 | const p = cbor.decode(prot);
98 | const alg = p.get(COSEHeaderParameters.Algorithm);
99 | if (alg !== COSESignatureAlgoritms.ES256_SHA256) {
100 | throw new Error(`unsupported signature algorithm: ${alg}`);
101 | }
102 |
103 | const kid = p.get(COSEHeaderParameters.KeyIdentifier);
104 |
105 | // Temporary exclusion of certificates we still need to acquire.
106 | const isExcluded = EXCLUDED_KIDS.some((ekid) => equal8(kid, ekid));
107 |
108 | let sig = isExcluded;
109 |
110 | if (!isExcluded) {
111 | const crt = findCertificate(kid);
112 | if (crt === undefined) {
113 | throw new Error(`could not find certificate for kid: ${kid.toString('hex')}`);
114 | }
115 |
116 | if (crt.pub === null) {
117 | throw new Error(`could not find public key in certificate for kid: ${kid.toString('hex')}`);
118 | }
119 |
120 | try {
121 | await cose.sign.verify(cwt, { key: crt.pub });
122 | sig = true;
123 | } finally {
124 | // Do nothing here, sig is either false or true depending whether cose.sign.verify threw or not.
125 | }
126 | }
127 |
128 | // Decode the claims in the payload.
129 | const claims = cbor.decode(payload);
130 |
131 | const iss = claims.get(CWTClaims.Issuer);
132 | const iat = claims.get(CWTClaims.IssuedAt);
133 | const exp = claims.get(CWTClaims.ExpirationTime);
134 | const hcert = claims.get(CWTClaims.HealthCertificate).get(HCERTClaims.DigitalHealthCertificate);
135 |
136 | return { iss, iat, exp, hcert, sig };
137 | };
138 |
--------------------------------------------------------------------------------
/src/lib/hcert-verification.ts:
--------------------------------------------------------------------------------
1 | import { HCERT, TestEntry, VaccinationEntry } from '@cpv/lib/hcert';
2 | import { TargetDisease } from './valuesets/disease-agent-targeted';
3 | import { TestResult } from './valuesets/test-result';
4 |
5 | export enum HCERTStatus {
6 | FullyVaccinated = 0,
7 | PartiallyVaccinated,
8 | NotVaccinated,
9 | Negative,
10 | Positive,
11 | Expired,
12 | UnverifiedSignature,
13 | Error,
14 | }
15 |
16 | const validateVaccinationGroup = (vg: VaccinationEntry[]): HCERTStatus => {
17 | // Filter out non-COVID-19 vaccines.
18 | const v = vg.filter((vv) => vv.tg === TargetDisease.COVID19);
19 |
20 | if (v.length === 0) return HCERTStatus.NotVaccinated;
21 |
22 | if (v.length > 0) {
23 | // Group doses by vaccine.
24 | const grouped = v.reduce((acc, curr) => {
25 | acc[curr.vp] = [...(acc[curr.vp] || []), curr];
26 | return acc;
27 | }, {} as { [key: string]: VaccinationEntry[] });
28 |
29 | // For each vaccine get the doses required and current doses.
30 | const doses = Object.values(grouped).map((group) =>
31 | group.reduce(
32 | (acc, curr) => {
33 | const sd = parseInt(curr.sd, 10);
34 | const dn = parseInt(curr.dn, 10);
35 |
36 | if (acc.required < sd) acc.required = sd;
37 | if (acc.got < dn) acc.got = dn;
38 |
39 | return acc;
40 | },
41 | { required: 0, got: 0 },
42 | ),
43 | );
44 |
45 | // Check if there's at least one vaccine for which all doses have been administered.
46 | const hasAllDoses = doses.some((d) => d.required === d.got);
47 |
48 | if (!hasAllDoses) return HCERTStatus.PartiallyVaccinated;
49 | }
50 |
51 | return HCERTStatus.FullyVaccinated;
52 | };
53 |
54 | const validateTestGroup = (t: TestEntry[]): HCERTStatus => {
55 | // ISO-8601 dates can be lexicographically ordered.
56 | const latestTest = t.sort((a, b) => b.tt.localeCompare(a.tt))[0];
57 |
58 | if (latestTest.tr === TestResult.Positive) return HCERTStatus.Positive;
59 | return HCERTStatus.Negative;
60 | };
61 |
62 | export const validateHCERT = ({ iat, exp, hcert, sig }: HCERT): HCERTStatus => {
63 | if (!sig) return HCERTStatus.UnverifiedSignature;
64 |
65 | const now = Math.floor(Date.now() / 1000);
66 |
67 | if (iat > now) return HCERTStatus.Expired;
68 | if (exp < now) return HCERTStatus.Expired;
69 |
70 | if (hcert.v) return validateVaccinationGroup(hcert.v);
71 | else if (hcert.t) return validateTestGroup(hcert.t);
72 | else return HCERTStatus.Error;
73 | };
74 |
--------------------------------------------------------------------------------
/src/lib/hcert.ts:
--------------------------------------------------------------------------------
1 | export interface VaccinationEntry {
2 | tg: string; // target disease, e.g. "840539006" for COVID-19
3 | vp: string; // vaccine, e.g. "1119349007" for a SARS-CoV-2 mRNA vaccine
4 | mp: string; // vaccine product
5 | ma: string; // manufacturer of the vaccine product
6 | dn: string; // number of dose in a series of doses
7 | sd: string; // total number of doses in a series
8 | dt: string; // date of vaccination
9 | co: string; // country that administered the vaccine
10 | is: string; // certificate issuer
11 | ci: string; // unique certificate identifier
12 | }
13 |
14 | export interface TestEntry {
15 | tg: string; // target disease
16 | tt: string; // type of test
17 | nm?: string; // name of the nucleic acid amplification test (NAAT)
18 | ma?: string; // name and manufacturer of the rapid antigen test (RAT)
19 | sc: string; // test collection timestamp
20 | tr: string; // test result
21 | tc?: string; // testing centre
22 | co: string; // country of test
23 | is: string; // certificate issuer
24 | ci: string; // unique certificate identifier
25 | }
26 |
27 | export interface DigitalHealthCertificate {
28 | ver: string; // version
29 | dob: string; // date of birth
30 | nam: {
31 | fn: string; // forename
32 | fnt: string; // standardised forename (ICAO 9303)
33 | gn: string; // surname
34 | gnt: string; // standardised surname (ICAO 9303)
35 | };
36 | v?: VaccinationEntry[];
37 | t?: TestEntry[];
38 | }
39 |
40 | /**
41 | * Specified in https://ec.europa.eu/health/sites/default/files/ehealth/docs/covid-certificate_json_specification_en.pdf.
42 | * JSON schema: https://raw.githubusercontent.com/ehn-dcc-development/ehn-dcc-schema/release/1.3.0/DCC.combined-schema.json.
43 | */
44 | export interface HCERT {
45 | iss: string; // issuer country (alpha-2)
46 | iat: number; // issued at timestamp
47 | exp: number; // expires at timestamp
48 | hcert: DigitalHealthCertificate;
49 | sig: boolean; // signature validity
50 | }
51 |
--------------------------------------------------------------------------------
/src/lib/time.ts:
--------------------------------------------------------------------------------
1 | const format = new Intl.DateTimeFormat('en-GB', {
2 | dateStyle: 'medium',
3 | timeStyle: 'medium',
4 | timeZone: 'UTC',
5 | });
6 |
7 | export const formatTimestamp = (timestamp: number): string => {
8 | return format.format(new Date(timestamp * 1e3));
9 | };
10 |
11 | export const formatISO8601Timestamp = (timestamp: string): string => {
12 | return format.format(new Date(timestamp));
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib/typed-array.ts:
--------------------------------------------------------------------------------
1 | export const equal8 = (a: Uint8Array, b: Uint8Array): boolean => compare(a, b);
2 |
3 | const compare = (a: Uint8Array, b: Uint8Array): boolean => {
4 | for (let i = a.length; -1 < i; i -= 1) {
5 | if (a[i] !== b[i]) return false;
6 | }
7 | return true;
8 | };
9 |
--------------------------------------------------------------------------------
/src/lib/valuesets/common.ts:
--------------------------------------------------------------------------------
1 | function isKeyOf(obj: { [key in T]: unknown }, key: unknown): key is T {
2 | if (key === null || typeof key !== 'string') return false;
3 | return Object.keys(obj).includes(key);
4 | }
5 |
6 | export function getFromValueSetValues(obj: { [key in T]: { display: string } }, key: string): string {
7 | if (isKeyOf(obj, key)) {
8 | return obj[key].display;
9 | }
10 |
11 | return `Unknown (${key})`;
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/valuesets/country-2-codes.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/country-2-codes.json';
3 |
4 | export const getCountry = (c: string): string => getFromValueSetValues(valueSetValues, c);
5 |
--------------------------------------------------------------------------------
/src/lib/valuesets/disease-agent-targeted.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/disease-agent-targeted.json';
3 |
4 | export enum TargetDisease {
5 | COVID19 = '840539006',
6 | }
7 |
8 | export const getTargetDisease = (tg: string): string => getFromValueSetValues(valueSetValues, tg);
9 |
--------------------------------------------------------------------------------
/src/lib/valuesets/test-manufacturer.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/test-manf.json';
3 |
4 | export const getTestManufacturer = (ma: string): string => getFromValueSetValues(valueSetValues, ma);
5 |
--------------------------------------------------------------------------------
/src/lib/valuesets/test-result.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/test-result.json';
3 |
4 | export enum TestResult {
5 | Negative = '260415000',
6 | Positive = '260373001',
7 | }
8 |
9 | export const getTestResult = (tr: string): string => getFromValueSetValues(valueSetValues, tr);
10 |
--------------------------------------------------------------------------------
/src/lib/valuesets/test-type.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/test-type.json';
3 |
4 | export const getTestType = (tt: string): string => getFromValueSetValues(valueSetValues, tt);
5 |
--------------------------------------------------------------------------------
/src/lib/valuesets/vaccine-manufacturer.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/vaccine-mah-manf.json';
3 |
4 | export const getVaccineManufacturer = (ma: string): string => getFromValueSetValues(valueSetValues, ma);
5 |
--------------------------------------------------------------------------------
/src/lib/valuesets/vaccine-medicinal-product.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/vaccine-medicinal-product.json';
3 |
4 | export const getVaccineMedicinalProduct = (mp: string): string => getFromValueSetValues(valueSetValues, mp);
5 |
--------------------------------------------------------------------------------
/src/lib/valuesets/vaccine-prophylaxis.ts:
--------------------------------------------------------------------------------
1 | import { getFromValueSetValues } from '@cpv/lib/valuesets/common';
2 | import { valueSetValues } from '@cpv/data/vaccine-prophylaxis.json';
3 |
4 | export const getVaccineProphylaxis = (vp: string): string => getFromValueSetValues(valueSetValues, vp);
5 |
--------------------------------------------------------------------------------
/src/lib/zlib.ts:
--------------------------------------------------------------------------------
1 | import pako from 'pako';
2 |
3 | /**
4 | * Decompresses an arbitrary payload using the Deflate compression mechanism.
5 | */
6 | export const inflate = (data: Uint8Array): Uint8Array => {
7 | // Zlib magic headers:
8 | // 78 01 - No Compression/low
9 | // 78 9C - Default Compression
10 | // 78 DA - Best Compression
11 | if (data[0] === 0x78) {
12 | return pako.inflate(data);
13 | }
14 | return data;
15 | };
16 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler): void => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/types/base45-js.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'base45-js/lib/base45-js' {
2 | export function encode(buffer: ArrayBuffer): string;
3 | export function decode(str: string): ArrayBuffer;
4 | }
5 |
--------------------------------------------------------------------------------
/src/types/cbor-web.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */
2 |
3 | declare module 'cbor-web' {
4 | export function decode(
5 | input: string | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | DataView | stream.Readable,
6 | options?: DecoderOptions | string,
7 | ): any;
8 |
9 | type DecoderOptions = {
10 | /**
11 | * - the maximum depth to parse.
12 | * Use -1 for "until you run out of memory". Set this to a finite
13 | * positive number for un-trusted inputs. Most standard inputs won't nest
14 | * more than 100 or so levels; I've tested into the millions before
15 | * running out of memory.
16 | */
17 | max_depth?: number;
18 | /**
19 | * - mapping from tag number to function(v),
20 | * where v is the decoded value that comes after the tag, and where the
21 | * function returns the correctly-created value for that tag.
22 | */
23 | tags?: object;
24 | /**
25 | * generate JavaScript BigInt's
26 | * instead of BigNumbers, when possible.
27 | */
28 | bigint?: boolean;
29 | /**
30 | * if true, prefer Uint8Arrays to
31 | * be generated instead of node Buffers. This might turn on some more
32 | * changes in the future, so forward-compatibility is not guaranteed yet.
33 | */
34 | preferWeb?: boolean;
35 | /**
36 | * - The encoding of the input.
37 | * Ignored if input is a Buffer.
38 | */
39 | encoding?: string;
40 | /**
41 | * - Should an error be thrown when no
42 | * data is in the input?
43 | */
44 | required?: boolean;
45 | /**
46 | * - if true, emit extended
47 | * results, which will be an object with shape {@link ExtendedResults}.
48 | * The value will already have been null-checked.
49 | */
50 | extendedResults?: boolean;
51 | };
52 | }
53 |
--------------------------------------------------------------------------------
/src/types/cose-js.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'cose-js' {
2 | type BufferLike = number[] | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray;
3 |
4 | export namespace sign {
5 | type Verifier = {
6 | key: {
7 | x: BufferLike;
8 | y: BufferLike;
9 | };
10 | };
11 |
12 | export function verify(message: BufferLike, verifier: Verifier): Promise;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.paths.json",
3 | "compilerOptions": {
4 | "target": "es5",
5 | "lib": [
6 | "dom",
7 | "dom.iterable",
8 | "esnext"
9 | ],
10 | "typeRoots": [
11 | "./src/types",
12 | "./node_modules/@types"
13 | ],
14 | "allowJs": true,
15 | "skipLibCheck": true,
16 | "esModuleInterop": true,
17 | "allowSyntheticDefaultImports": true,
18 | "strict": true,
19 | "forceConsistentCasingInFileNames": true,
20 | "noFallthroughCasesInSwitch": true,
21 | "module": "esnext",
22 | "moduleResolution": "node",
23 | "resolveJsonModule": true,
24 | "isolatedModules": true,
25 | "noEmit": true,
26 | "jsx": "react-jsx"
27 | },
28 | "include": [
29 | "src"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/tsconfig.paths.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./src",
4 | "paths": {
5 | "@cpv/*" : ["./*"]
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------