Revert "sync with smart-on-fhir/health-cards-tests"
This commit is contained in:
Родитель
b494b992d3
Коммит
37a3918264
|
@ -129,7 +129,7 @@ js/*
|
|||
# qr-scanner js files to enable in-browser qr scanning
|
||||
# showdown js files to markdown to html
|
||||
# github-markdown css files format markdown in a github style
|
||||
public/jsQR.js
|
||||
public/jsQr.js
|
||||
public/github-markdown*
|
||||
|
||||
# localhost tls cert and key generated at install
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
FROM node:15
|
||||
|
||||
ENV HOST_PORT=8080
|
||||
ENV SERVER_BASE=http://localhost:8080/
|
||||
ENV SERVER_BASE=relative
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
|
@ -16,3 +15,4 @@ RUN npm run build
|
|||
|
||||
# Start
|
||||
CMD [ "npm", "run", "deploy" ]
|
||||
EXPOSE 8080
|
||||
|
|
|
@ -2,13 +2,6 @@
|
|||
|
||||
This project demonstrates the issuance and validation of cards specified in the [SMART Health Card Framework](https://smarthealth.cards/).
|
||||
|
||||
# Live Demo
|
||||
|
||||
* https://demo-portals.smarthealth.cards/VerifierPortal.html
|
||||
* https://demo-portals.smarthealth.cards/DevPortal.html
|
||||
|
||||
# Development
|
||||
|
||||
## Setup
|
||||
|
||||
1. Make sure [node.js](https://nodejs.org/) and [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) are installed on your system; the latest Long-Term Support (LTS) version is recommended for both.
|
||||
|
@ -37,3 +30,26 @@ This project demonstrates the issuance and validation of cards specified in the
|
|||
The demo stands up an endpoint illustrating the SMART Health Card operations listening on port 8080:
|
||||
- [developer](https://localhost:8080/DevPortal.html) portal for constructing SMART Health Cards from FHIR data.
|
||||
- [verifier](https://localhost:8080/VerifierPortal.html) for validating SMART Health Cards and extracting embedded FHIR data.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Trademarks
|
||||
|
||||
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
|
||||
trademarks or logos is subject to and must follow
|
||||
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
|
||||
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
||||
Any use of third-party trademarks or logos are subject to those third-party's policies.
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
- [X] Red in error boxes
|
||||
- [X] fade color gets stuck
|
||||
- [X] dev top side-by-side sections not even when shrinking window
|
||||
- [ ] dev fhir bad json no triggering error
|
||||
- [X] dev clearing key TA does not clear error (empty should result in clean validation)
|
||||
- [X] clear does not restore TA heights
|
||||
- [ ]
|
||||
- [ ]
|
||||
- [ ]
|
|
@ -48,7 +48,7 @@ This public key will be used to verify the JWS signature and must be available a
|
|||
|
||||
<div style="display: inline-block">
|
||||
<label></label>
|
||||
<input type="text" id='textIssuer' placeholder="https://<your-issuer-site>/issuer"
|
||||
<input type="text" id='textIssuer' placeholder="https://contoso.com/issuer"
|
||||
style="width: 300px;" />
|
||||
<label>/.well-known/jwks.json</label>
|
||||
</div>
|
||||
|
@ -74,9 +74,9 @@ The __Signing Key__ is expected in the following form:
|
|||
|
||||
|
||||
|
||||
Use a sample ES256 key from [https://raw.githubusercontent.com/smart-on-fhir/health-cards/main/generate-examples/src/config/issuer.jwks.private.json](https://raw.githubusercontent.com/smart-on-fhir/health-cards/main/generate-examples/src/config/issuer.jwks.private.json) for creating a JWS signature:
|
||||
Generate a new sample ES256 key for creating a JWS signature:
|
||||
|
||||
<input type="button" id='buttonGenerateKey' value="Use Sample Key" onclick="downloadIssuerKeySample()" />
|
||||
<input type="button" id='buttonGenerateKey' value="Generate Key" onclick="generateKeyPair()" />
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
|
|
@ -417,20 +417,6 @@
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Downloads a sample issuer key
|
||||
//
|
||||
async function downloadIssuerKeySample() {
|
||||
const sampleUrl = 'https://raw.githubusercontent.com/smart-on-fhir/health-cards/main/generate-examples/src/config/issuer.jwks.private.json'
|
||||
const result = await restCall(sampleUrl, "", 'GET', 'text');
|
||||
// select the first key from the sample JWK set
|
||||
const key = JSON.stringify(JSON.parse(result).keys[0], null, 2);
|
||||
secInitKey.setValue(key);
|
||||
secInitKey.fields[0].dispatchEvent(new Event('input'));
|
||||
document.getElementById('textIssuer').value = 'https://smarthealth.cards/examples/issuer';
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Generates a new ES256 key with 'kid' and writes it to the Signing-Key textarea element
|
||||
//
|
||||
|
|
|
@ -4,7 +4,7 @@ const developerDocs = {
|
|||
"r": ""
|
||||
},
|
||||
"initKey": {
|
||||
"l": "<h2 id=\"keys\">Keys</h2>\n<p>See: <a href=\"https://smarthealth.cards/#protocol-details\">Generating and resolving cryptographic keys</a> </p>\n<h3 id=\"issuerpublickey\">Issuer Public Key</h3>\n<p>See: <a href=\"https://smarthealth.cards/#determining-keys-associated-with-an-issuer\">Determining keys associated with an issuer</a><br />\nThis public key will be used to verify the JWS signature and must be available at: </p>\n<div style=\"display: inline-block\">\n<label></label>\n<input type=\"text\" id='textIssuer' placeholder=\"https://<your-issuer-site>/issuer\"\n style=\"width: 300px;\" />\n<label>/.well-known/jwks.json</label>\n</div>\n<p><br/><br/></p>\n<h3 id=\"issuersigningkey\">Issuer Signing Key</h3>\n<p>The credential payload will be signed with a private ES256 key. </p>\n<p>The <strong>Signing Key</strong> is expected in the following form: </p>\n<pre><code>{\n \"kty\": \"EC\",\n \"kid\": \"LR8EPRFYkdyreMNakALHRoq9ce3jaVbb9tyzji4jUzY\",\n \"use\": \"sig\",\n \"alg\": \"ES256\",\n \"crv\": \"P-256\",\n \"x\": \"Xm6UNA7d5BmR1LyrOdq9vuOw92AQiMl9ZfRh2u1fTDI\",\n \"y\": \"B_11Uf_Wzx-1Va8hx_E2-AX7KpJf9LXGQTHQmqchQOg\",\n \"d\": \"Kxhn2ve8W3KZPPLfNaXklghC9u5kDrzgt40dbSwWAKY\"\n}\n</code></pre>\n<p>Use a sample ES256 key from <a href=\"https://raw.githubusercontent.com/smart-on-fhir/health-cards/main/generate-examples/src/config/issuer.jwks.private.json\">https://raw.githubusercontent.com/smart-on-fhir/health-cards/main/generate-examples/src/config/issuer.jwks.private.json</a> for creating a JWS signature: </p>\n<p><input type=\"button\" id='buttonGenerateKey' value=\"Use Sample Key\" onclick=\"downloadIssuerKeySample()\" /></p>\n<p><br/><br/></p>\n<p><strong>Paste your ES256 private key below in JWK format:</strong> </p>",
|
||||
"l": "<h2 id=\"keys\">Keys</h2>\n<p>See: <a href=\"https://smarthealth.cards/#protocol-details\">Generating and resolving cryptographic keys</a> </p>\n<h3 id=\"issuerpublickey\">Issuer Public Key</h3>\n<p>See: <a href=\"https://smarthealth.cards/#determining-keys-associated-with-an-issuer\">Determining keys associated with an issuer</a><br />\nThis public key will be used to verify the JWS signature and must be available at: </p>\n<div style=\"display: inline-block\">\n<label></label>\n<input type=\"text\" id='textIssuer' placeholder=\"https://contoso.com/issuer\"\n style=\"width: 300px;\" />\n<label>/.well-known/jwks.json</label>\n</div>\n<p><br/><br/></p>\n<h3 id=\"issuersigningkey\">Issuer Signing Key</h3>\n<p>The credential payload will be signed with a private ES256 key. </p>\n<p>The <strong>Signing Key</strong> is expected in the following form: </p>\n<pre><code>{\n \"kty\": \"EC\",\n \"kid\": \"LR8EPRFYkdyreMNakALHRoq9ce3jaVbb9tyzji4jUzY\",\n \"use\": \"sig\",\n \"alg\": \"ES256\",\n \"crv\": \"P-256\",\n \"x\": \"Xm6UNA7d5BmR1LyrOdq9vuOw92AQiMl9ZfRh2u1fTDI\",\n \"y\": \"B_11Uf_Wzx-1Va8hx_E2-AX7KpJf9LXGQTHQmqchQOg\",\n \"d\": \"Kxhn2ve8W3KZPPLfNaXklghC9u5kDrzgt40dbSwWAKY\"\n}\n</code></pre>\n<p>Generate a new sample ES256 key for creating a JWS signature: </p>\n<p><input type=\"button\" id='buttonGenerateKey' value=\"Generate Key\" onclick=\"generateKeyPair()\" /></p>\n<p><br/><br/></p>\n<p><strong>Paste your ES256 private key below in JWK format:</strong> </p>",
|
||||
"r": ""
|
||||
},
|
||||
"createCredential": {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Portals</title>
|
||||
<base target="_blank">
|
||||
<link rel="stylesheet" href="portal.css">
|
||||
</head>
|
||||
|
||||
<body style="background-color: #3A4856;">
|
||||
<div>
|
||||
<div style='padding: 3%'>
|
||||
<div style="font-family: Arial, Helvetica, sans-serif;color: white;">
|
||||
<hr />
|
||||
<h2>Developer Portal</h2>
|
||||
<p>Generate a SMART Health Card, step by step, from an initial FHIR Bundle and Key</p>
|
||||
</div>
|
||||
<input id="buttonDevPortal" type="button" value="Go to Developer Portal"
|
||||
onClick="parent.location='DevPortal.html'" />
|
||||
<br><br><br><br><br><br>
|
||||
<div style="font-family: Arial, Helvetica, sans-serif;color: white;">
|
||||
|
||||
<hr />
|
||||
<h2>Verifier Portal</h2>
|
||||
<p>
|
||||
The Verifier Portal takes as input, a QR-Code image of a SMART Health Card.
|
||||
</p>
|
||||
<p>
|
||||
After the image is scanned, it is decoded, in stages, into a FHIR Bundle.
|
||||
</p>
|
||||
<p>
|
||||
Each step in the process does some amount of validation.
|
||||
</p>
|
||||
|
||||
<input id="buttonVerifierPortal" type="button" value="Go to Verifier Portal"
|
||||
onClick="parent.location='VerifierPortal.html'" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
export const Config = {
|
||||
|
||||
// REST API endpoints
|
||||
|
@ -18,6 +21,9 @@ export const Config = {
|
|||
DOWNLOAD_PUBLIC_KEY: '/download-public-key',
|
||||
UPLOAD_PUBLIC_KEY: '/upload-public-key',
|
||||
|
||||
SERVER_BASE : process.env.SERVER_BASE || 'http://localhost:' + (process.env.HOST_PORT || 8080) + '/',
|
||||
SERVICE_PORT: process.env.HOST_PORT || 8080
|
||||
ISSUER_URL: '', // instantiated at startup if empty
|
||||
SERVICE_PORT: 8080,
|
||||
|
||||
// Issuer name to be included in health cards
|
||||
ISSUER_NAME: 'Contoso Hospital'
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import {Config} from './config';
|
||||
|
||||
// TODO: validate vaccine code https://www.cdc.gov/vaccines/programs/iis/COVID-19-related-codes.html
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import jose, { JWK } from 'node-jose';
|
||||
import pako from 'pako';
|
||||
import QrCode, { QRCodeSegment } from 'qrcode';
|
||||
|
@ -48,7 +51,7 @@ export function healthCard(jws: string): VerifiableCredential {
|
|||
}
|
||||
|
||||
export async function generateHealthCard(fhirBundle: FhirBundle, signingKey: Key) {
|
||||
return healthCard(await sign(deflate(minify(credential(fhirBundle, Config.SERVER_BASE, []))), signingKey));
|
||||
return healthCard(await sign(deflate(minify(credential(fhirBundle, Config.ISSUER_URL, []))), signingKey));
|
||||
}
|
||||
|
||||
function partitionJws(jws: string): string[] {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import {jsPDF, ImageOptions} from 'jspdf';
|
||||
import {codeToVaccine} from './fhir';
|
||||
import fs from 'fs';
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Simple test server for SMART Health Card operations
|
||||
// This code is for illustration purposes only, it shouldn't be used in
|
||||
|
@ -80,7 +83,6 @@ app.post(Config.DEFLATE_PAYLOAD, async (req, res) => {
|
|||
res.send(Buffer.from(result as Uint8Array));
|
||||
});
|
||||
|
||||
|
||||
app.post(Config.INFLATE_PAYLOAD, async (req, res) => {
|
||||
console.log('Received POST for', Config.INFLATE_PAYLOAD, req.body);
|
||||
const payload = JSON.stringify(req.body.payload);
|
||||
|
@ -161,9 +163,15 @@ app.post(Config.UPLOAD_PUBLIC_KEY, async (req, res) => {
|
|||
});
|
||||
|
||||
|
||||
http.createServer(app).listen(Config.SERVICE_PORT, () => {
|
||||
const url = Config.SERVER_BASE;
|
||||
console.log("Service listening at " + url);
|
||||
console.log("\nVerifierPortal: " + url + 'VerifierPortal.html');
|
||||
console.log("DevPortal: " + url + 'DevPortal.html');
|
||||
const httpServer = http.createServer(app).listen(Config.SERVICE_PORT, () => {
|
||||
const address = httpServer.address() as unknown as { address: string, family: string, port: string };
|
||||
const host = address.address === '::' ? 'localhost' : address.address;
|
||||
const port = address.port === '80' ? '' : ':' + address.port;
|
||||
const url = `http://${host}${port}`;
|
||||
if (!Config.ISSUER_URL) {
|
||||
Config.ISSUER_URL = url;
|
||||
}
|
||||
console.log("Demo service listening at " + url);
|
||||
console.log("\nVerifierPortal: " + url + '/VerifierPortal.html');
|
||||
console.log("DevPortal: " + url + '/DevPortal.html');
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
declare var process: NodeJS.Process;
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
interface Immunization {
|
||||
// vaccine code
|
||||
|
|
Загрузка…
Ссылка в новой задаче