Support Health Cards 0.0.11 (#40)
* Upgrade to fhir r4 (#35) * Add C19 immunization example * Add summary examples for immunization status * Clarify role of issuer in examples * Update FHIR R2 -> R4 * Update sidetree v1.0 (#37) * Update to sidetree 1.0 * Update date -> occurrenceDateTime for Immunizations * Update canonical domain to smarthealth.cards (#39)
This commit is contained in:
Родитель
62bed14615
Коммит
5ed3496122
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -20,7 +20,7 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@decentralized-identity/sidetree": "^0.9.1",
|
||||
"@decentralized-identity/sidetree": "^1.0.0",
|
||||
"@types/node-jose": "^1.1.5",
|
||||
"@types/react": "^16.9.55",
|
||||
"@types/react-dom": "^16.9.9",
|
||||
|
@ -29,6 +29,7 @@
|
|||
"base-64": "^0.1.0",
|
||||
"base64url": "^3.0.1",
|
||||
"bootstrap": "^4.5.3",
|
||||
"canonicalize": "^1.0.5",
|
||||
"cbor": "^5.1.0",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"cors": "^2.8.5",
|
||||
|
|
|
@ -53,10 +53,10 @@ const CovidCard: React.FC<{
|
|||
if (smartState?.access_token && issuerInteraction?.siopResponse && holderState.vcStore.length === 0) {
|
||||
|
||||
/*
|
||||
const credentials = axios.get(uiState.fhirClient.server + `/DiagnosticReport?patient=${smartState.patient}&_tag=https://healthwallet.cards|covid19`)
|
||||
const credentials = axios.get(uiState.fhirClient.server + `/DiagnosticReport?patient=${smartState.patient}&_tag=https://smarthealth.cards|covid19`)
|
||||
credentials.then(response => {
|
||||
const vcs = response.data.entry[0].resource.extension
|
||||
.filter(e => e.url === 'https://healthwallet.cards#vc-attachment')
|
||||
.filter(e => e.url === 'https://smarthealth.cards#vc-attachment')
|
||||
.map(e => base64.decode(e.valueAttachment.data))
|
||||
|
||||
dispatchToHolder(retrieveVcs(vcs, holderState))
|
||||
|
@ -67,10 +67,10 @@ const CovidCard: React.FC<{
|
|||
"resourceType": "Parameters",
|
||||
"parameter": [{
|
||||
"name": "credentialType",
|
||||
"valueUri": "https://healthwallet.cards#health-card"
|
||||
"valueUri": "https://smarthealth.cards#health-card"
|
||||
},{
|
||||
"name": "presentationContext",
|
||||
"valueUri": "https://healthwallet.cards#presentation-context-online"
|
||||
"valueUri": "https://smarthealth.cards#presentation-context-online"
|
||||
}, {
|
||||
"name": "encryptForKeyId",
|
||||
"valueString": "#encryption-key-1"
|
||||
|
@ -84,7 +84,7 @@ const CovidCard: React.FC<{
|
|||
}, [smartState, holderState.interactions])
|
||||
|
||||
|
||||
const covidVcs = holderState.vcStore.filter(vc => vc.type.includes("https://healthwallet.cards#covid19"));
|
||||
const covidVcs = holderState.vcStore.filter(vc => vc.type.includes("https://smarthealth.cards#covid19"));
|
||||
const conclusions = covidVcs.flatMap(vc =>
|
||||
vc.vcPayload.vc.credentialSubject.fhirBundle.entry
|
||||
.filter(e => e.resource.resourceType === 'DiagnosticReport')
|
||||
|
|
|
@ -102,10 +102,10 @@ export const SiopApprovalModal: React.FC<SiopApprovalProps | null> = (props) =>
|
|||
<ModalBody>The following details will be shared:
|
||||
<ul>
|
||||
<li><b>Your ID Card:</b> allows secure communications</li>
|
||||
{props.share.includes('https://healthwallet.cards#covid19') && <li>
|
||||
{props.share.includes('https://smarthealth.cards#covid19') && <li>
|
||||
<b>Your COVID Card:</b> labs and vaccines for COVID-19
|
||||
</li>}
|
||||
{props.share.includes('https://healthwallet.cards#immunization') && <li>
|
||||
{props.share.includes('https://smarthealth.cards#immunization') && <li>
|
||||
<b>Your Immunizations Card:</b> full vaccine history
|
||||
</li>}
|
||||
</ul>
|
||||
|
|
|
@ -82,19 +82,19 @@ export interface CredentialGenerationDetals {
|
|||
}
|
||||
|
||||
export const defaultIdentityClaims = {
|
||||
"https://healthwallet.cards#presentation-context-online": [
|
||||
"https://smarthealth.cards#presentation-context-online": [
|
||||
"Patient.telecom",
|
||||
"Patient.name",
|
||||
],
|
||||
"https://healthwallet.cards#presentation-context-in-person": [
|
||||
"https://smarthealth.cards#presentation-context-in-person": [
|
||||
"Patient.name",
|
||||
"Patient.photo"
|
||||
]
|
||||
}
|
||||
|
||||
export const issueVcsToHolder = async (state: VerifierState, details: CredentialGenerationDetals = {
|
||||
type: 'https://healthwallet.cards#covid19',
|
||||
presentationContext: 'https://healthwallet.cards#presentation-context-online',
|
||||
type: 'https://smarthealth.cards#covid19',
|
||||
presentationContext: 'https://smarthealth.cards#presentation-context-online',
|
||||
identityClaims: null,
|
||||
encryptVc: true,
|
||||
}): Promise<{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { EncryptionKey, SigningKey, KeyGenerators } from './KeyTypes';
|
||||
export type ClaimType = 'https://healthwallet.cards#covid19' | 'https://healthwallet.cards#immunization' | 'https://healthwallet.cards#tdap';
|
||||
export type ClaimType = 'https://smarthealth.cards#covid19' | 'https://smarthealth.cards#immunization' | 'https://smarthealth.cards#tdap';
|
||||
export type SiopResponseMode = 'form_post' | 'fragment';
|
||||
|
||||
export interface VerifierState {
|
||||
|
|
76
src/dids.ts
76
src/dids.ts
|
@ -21,11 +21,9 @@ export async function verifyJws(jws: string, {
|
|||
const ENCRYPTION_KEY_TYPES = ['JsonWebKey2020', 'JwsVerificationKey2020'];
|
||||
|
||||
export async function encryptFor(jws: string, did: string, { generateEncryptionKey }: KeyGenerators, keyIdIn?: string) {
|
||||
const didDoc = (await axios.get(resolveUrl + encodeURIComponent(did))).data;
|
||||
const encryptionKeys = didDoc.publicKey.filter(k => k.publicKeyJwk.alg === 'ECDH-ES');
|
||||
|
||||
const keyId = keyIdIn ? keyIdIn : encryptionKeys[0].id;
|
||||
const encryptionKey = encryptionKeys.filter(k => k.id === keyId)[0]
|
||||
const didDoc = (await axios.get(resolveUrl +did)).data;
|
||||
const keyId = keyIdIn ? keyIdIn : '#' + didDoc.keyAgreement[0].split("#")[1];
|
||||
const encryptionKey = didDoc.verificationMethod.filter(k => k.id == keyId)[0];
|
||||
|
||||
const ek = await generateEncryptionKey({
|
||||
...encryptionKey.publicKeyJwk,
|
||||
|
@ -35,63 +33,70 @@ export async function encryptFor(jws: string, did: string, { generateEncryptionK
|
|||
}
|
||||
const resolveKeyId = async (kid: string): Promise<JsonWebKey> => {
|
||||
const fragment = '#' + kid.split('#')[1];
|
||||
const didDoc = (await axios.get(resolveUrl + encodeURIComponent(kid))).data;
|
||||
return didDoc.publicKey.filter(k => k.id === fragment)[0].publicKeyJwk;
|
||||
const didDoc = (await axios.get(resolveUrl +kid)).data;
|
||||
return didDoc.verificationMethod.filter(k => k.id === fragment)[0].publicKeyJwk;
|
||||
};
|
||||
export async function generateDid({ signingPublicJwk, encryptionPublicJwk, recoveryPublicJwk, updatePublicJwk, domains = [] as string[]}) {
|
||||
const hashAlgorithmName = multihashes.codes[18];
|
||||
|
||||
const hash = (b: string|Buffer) => multihashes.encode(crypto.createHash('sha256').update(b).digest(), hashAlgorithmName);
|
||||
|
||||
const revealCommitPair = (publicKey: SigningKey) => {
|
||||
const revealValueEncodedString = canonicalize(publicKey)
|
||||
const commitmentHash = hash(revealValueEncodedString);
|
||||
const commitmentHashEncodedString = base64url.encode(commitmentHash);
|
||||
return [revealValueEncodedString, commitmentHashEncodedString];
|
||||
const revealValueEncodedString = canonicalize(publicKey);
|
||||
const commitmentHashHash = hash(hash(revealValueEncodedString));
|
||||
const commitmentHashHashEncodedString = base64url.encode(commitmentHashHash);
|
||||
return [revealValueEncodedString, commitmentHashHashEncodedString];
|
||||
};
|
||||
|
||||
const [recoveryValue, recoveryCommitment] = revealCommitPair(recoveryPublicJwk);
|
||||
const [updateValue, updateCommitment] = revealCommitPair(updatePublicJwk);
|
||||
let patches: {action: string, public_keys?: any, service_endpoints?: any}[] = [{
|
||||
let patches: {action: string, publicKeys?: any, services?: any}[] = [{
|
||||
action: 'add-public-keys',
|
||||
public_keys: [{
|
||||
publicKeys: [{
|
||||
id: 'signing-key-1',
|
||||
purpose: ['general', 'auth'],
|
||||
purposes: ['authentication', 'assertionMethod'],
|
||||
type: 'JsonWebKey2020',
|
||||
jwk: signingPublicJwk
|
||||
publicKeyJwk: JSON.parse(JSON.stringify({...signingPublicJwk, kid: undefined}))
|
||||
}, {
|
||||
id: 'encryption-key-1',
|
||||
purpose: ['general', 'auth'],
|
||||
purposes: ['keyAgreement', 'assertionMethod'],
|
||||
type: 'JsonWebKey2020',
|
||||
jwk: encryptionPublicJwk
|
||||
publicKeyJwk: JSON.parse(JSON.stringify({...encryptionPublicJwk, kid: undefined}))
|
||||
}]
|
||||
}]
|
||||
if (domains.length > 0) {
|
||||
patches.push({
|
||||
"action": "add-service-endpoints",
|
||||
"service_endpoints": [{
|
||||
"action": "add-services",
|
||||
"services": [{
|
||||
"id": "linked-domain",
|
||||
"type": "LinkedDomains",
|
||||
"endpoint": domains[0]
|
||||
"serviceEndpoint": domains[0]
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Patches", JSON.stringify(patches, null, 2));
|
||||
const delta: Record<string, any> = {
|
||||
'update_commitment': updateCommitment,
|
||||
updateCommitment,
|
||||
patches
|
||||
};
|
||||
const deltaCanonical = JSON.stringify(delta);
|
||||
const deltaEncoded = base64url.encode(deltaCanonical);
|
||||
const suffixData = {
|
||||
delta_hash: base64url.encode(hash(Buffer.from(deltaCanonical))),
|
||||
recovery_commitment: recoveryCommitment
|
||||
};
|
||||
const suffixDataCanonical = JSON.stringify(suffixData);
|
||||
const suffix = base64url.encode(hash(Buffer.from(suffixDataCanonical)));
|
||||
|
||||
const deltaCanonical = canonicalize(delta);
|
||||
const suffixData = {
|
||||
deltaHash: base64url.encode(hash(Buffer.from(deltaCanonical))),
|
||||
recoveryCommitment: recoveryCommitment
|
||||
};
|
||||
|
||||
const suffixDataCanonical = canonicalize(suffixData);
|
||||
const suffix = base64url.encode(hash(Buffer.from(suffixDataCanonical)));
|
||||
const didShort = `did:ion:${suffix}`;
|
||||
const suffixDataEncoded = base64url.encode(suffixDataCanonical);
|
||||
const didLong = `did:ion:${suffix}?-ion-initial-state=${suffixDataEncoded}.${deltaEncoded}`;
|
||||
return {
|
||||
|
||||
const longFormPayload = { suffixData, delta };
|
||||
const longFormPayloadCanonical = canonicalize(longFormPayload);
|
||||
const longFormFinalSegment = base64url.encode(longFormPayloadCanonical);
|
||||
const didLong = `${didShort}:${longFormFinalSegment}`;
|
||||
|
||||
let ret = {
|
||||
did: didLong,
|
||||
recoveryValue,
|
||||
recoveryCommitment,
|
||||
|
@ -99,12 +104,13 @@ export async function generateDid({ signingPublicJwk, encryptionPublicJwk, recov
|
|||
updateCommitment,
|
||||
delta,
|
||||
deltaCanonical,
|
||||
deltaEncoded,
|
||||
suffixData,
|
||||
suffixDataCanonical,
|
||||
suffixDataEncoded,
|
||||
didShort,
|
||||
didLong
|
||||
}
|
||||
};
|
||||
|
||||
console.log("Key deets", ret);
|
||||
return ret;
|
||||
}
|
||||
const jwtHeader = (jwt) => JSON.parse(base64url.decode(jwt.split('.')[0]));
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -10,12 +10,12 @@
|
|||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"https://healthwallet.cards#health-card",
|
||||
"https://healthwallet.cards#covid19",
|
||||
"https://healthwallet.cards#presentation-context-online"
|
||||
"https://smarthealth.cards#health-card",
|
||||
"https://smarthealth.cards#covid19",
|
||||
"https://smarthealth.cards#presentation-context-online"
|
||||
],
|
||||
"credentialSubject": {
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle": {
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
@ -32,9 +32,7 @@
|
|||
],
|
||||
"name": [
|
||||
{
|
||||
"family": [
|
||||
"Everywoman"
|
||||
],
|
||||
"family": "Everywoman",
|
||||
"given": [
|
||||
"Eve"
|
||||
]
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"https://healthwallet.cards#health-card",
|
||||
"https://healthwallet.cards#immunization",
|
||||
"https://healthwallet.cards#covid19"
|
||||
"https://smarthealth.cards#health-card",
|
||||
"https://smarthealth.cards#immunization",
|
||||
"https://smarthealth.cards#covid19"
|
||||
],
|
||||
"credentialSubject": {
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle": {
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
@ -32,9 +32,7 @@
|
|||
],
|
||||
"name": [
|
||||
{
|
||||
"family": [
|
||||
"Everywoman"
|
||||
],
|
||||
"family": "Everywoman",
|
||||
"given": [
|
||||
"Evelyn"
|
||||
]
|
||||
|
@ -53,7 +51,7 @@
|
|||
"resource": {
|
||||
"resourceType": "Immunization",
|
||||
"status": "completed",
|
||||
"date": "2020-12-18",
|
||||
"occurrenceDateTime": "2020-12-18",
|
||||
"vaccineCode": {
|
||||
"coding": [
|
||||
{
|
||||
|
@ -78,7 +76,7 @@
|
|||
"resource": {
|
||||
"resourceType": "Immunization",
|
||||
"status": "completed",
|
||||
"date": "2021-01-14",
|
||||
"occurrenceDateTime": "2021-01-14",
|
||||
"vaccineCode": {
|
||||
"coding": [
|
||||
{
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
"@context": [
|
||||
"https://www.w3.org/2018/credentials/v1"
|
||||
],
|
||||
"type": [ "VerifiableCredential", "https://healthwallet.cards#health-card"],
|
||||
"type": [ "VerifiableCredential", "https://smarthealth.cards#health-card"],
|
||||
"issuer": "<<did:ion identifier for issuer>>",
|
||||
"issuanceDate": "2020-06-01T11:59:00-07:00",
|
||||
"credentialSubject": {
|
||||
"id": "<<did:identifier for subject if known>>",
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle":{
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"https://healthwallet.cards#health-card",
|
||||
"https://healthwallet.cards#covid19",
|
||||
"https://healthwallet.cards#presentation-context-online"
|
||||
"https://smarthealth.cards#health-card",
|
||||
"https://smarthealth.cards#covid19",
|
||||
"https://smarthealth.cards#presentation-context-online"
|
||||
],
|
||||
"credentialSubject": {
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle": {
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
@ -32,9 +32,7 @@
|
|||
],
|
||||
"name": [
|
||||
{
|
||||
"family": [
|
||||
"Everywoman"
|
||||
],
|
||||
"family": "Everywoman",
|
||||
"given": [
|
||||
"Eve"
|
||||
]
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"https://healthwallet.cards#health-card",
|
||||
"https://healthwallet.cards#immunization",
|
||||
"https://healthwallet.cards#tdap",
|
||||
"https://healthwallet.cards#presentation-context-online"
|
||||
"https://smarthealth.cards#health-card",
|
||||
"https://smarthealth.cards#immunization",
|
||||
"https://smarthealth.cards#tdap",
|
||||
"https://smarthealth.cards#presentation-context-online"
|
||||
],
|
||||
"credentialSubject": {
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle": {
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
@ -33,9 +33,7 @@
|
|||
],
|
||||
"name": [
|
||||
{
|
||||
"family": [
|
||||
"Everywoman"
|
||||
],
|
||||
"family": "Everywoman",
|
||||
"given": [
|
||||
"Evelyn"
|
||||
]
|
||||
|
@ -55,7 +53,7 @@
|
|||
"resource": {
|
||||
"resourceType": "Immunization",
|
||||
"status": "completed",
|
||||
"date": "2020-04-28",
|
||||
"occurrenceDateTime": "2020-04-28",
|
||||
"vaccineCode": {
|
||||
"coding": [
|
||||
{
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"https://healthwallet.cards#covid19",
|
||||
"https://healthwallet.cards#presentation-context-online"],
|
||||
"https://smarthealth.cards#covid19",
|
||||
"https://smarthealth.cards#presentation-context-online"],
|
||||
"issuer": "<<did:ion identifier for issuer>>",
|
||||
"issuanceDate": "2020-06-01T11:59:00-07:00",
|
||||
"credentialSubject": {
|
||||
"id": "<<did:identifier for subject if known>>",
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle":{
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
@ -23,7 +23,7 @@
|
|||
"valueCode": "P2"
|
||||
}],
|
||||
"name": [{
|
||||
"family": ["Everywoman"],
|
||||
"family": "Everywoman",
|
||||
"given": ["Eve"]
|
||||
}],
|
||||
"telecom": [{
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
],
|
||||
"type": [
|
||||
"VerifiableCredential",
|
||||
"https://healthwallet.cards#covid19",
|
||||
"https://healthwallet.cards#presentation-context-online"],
|
||||
"https://smarthealth.cards#covid19",
|
||||
"https://smarthealth.cards#presentation-context-online"],
|
||||
"issuer": "<<did:ion identifier for issuer>>",
|
||||
"issuanceDate": "2020-05-01T11:59:00-07:00",
|
||||
"display": "COVID-19 Card for Eve Everywoman",
|
||||
"credentialSubject": {
|
||||
"id": "<<did:identifier for subject if known>>",
|
||||
"fhirVersion": "1.0.2",
|
||||
"fhirVersion": "4.0.1",
|
||||
"fhirBundle":{
|
||||
"resourceType": "Bundle",
|
||||
"type": "collection",
|
||||
|
@ -24,7 +24,7 @@
|
|||
"valueCode": "P2"
|
||||
}],
|
||||
"name": [{
|
||||
"family": ["Everywoman"],
|
||||
"family": "Everywoman",
|
||||
"given": ["Eve"]
|
||||
}],
|
||||
"telecom": [{
|
||||
|
|
|
@ -191,7 +191,7 @@ const App: React.FC<AppProps> = (props) => {
|
|||
ID Card
|
||||
</CardTitle>
|
||||
<CardSubtitle className="text-muted">This identifier is all yours, with keys stored safely on your device.</CardSubtitle>
|
||||
<CardText style={{ fontFamily: "monospace" }}> {holderState.did.split('?')[0]}</CardText>
|
||||
<CardText style={{ fontFamily: "monospace" }}> {holderState.did.split(':').slice(0,3).join(':')+':...'}</CardText>
|
||||
</Card>
|
||||
<CovidCard
|
||||
holderState={holderState}
|
||||
|
@ -270,4 +270,4 @@ export default async function main() {
|
|||
);
|
||||
}
|
||||
|
||||
main().then(r => console.log('Finished Holder Page,', r));
|
||||
main().then(r => console.log('Finished Holder Page,', r));
|
||||
|
|
|
@ -11,7 +11,7 @@ export const keyGenerators: KeyGenerators = {
|
|||
generateSigningKey
|
||||
};
|
||||
|
||||
const encryptionKeyPros = {
|
||||
const encryptionKeyProps = {
|
||||
"kty": "EC",
|
||||
"crv": "P-256",
|
||||
"alg": 'ECDH-ES',
|
||||
|
@ -33,7 +33,7 @@ export async function generateEncryptionKey(inputPublic?: JsonWebKey, inputPriva
|
|||
privateKey = await jose.JWK.asKey(inputPrivate)
|
||||
}
|
||||
} else {
|
||||
publicKey = privateKey = await keystore.generate("EC", "P-256", encryptionKeyPros);
|
||||
publicKey = privateKey = await keystore.generate("EC", "P-256", encryptionKeyProps);
|
||||
}
|
||||
|
||||
const publicJwk = publicKey.toJSON(false);
|
||||
|
|
|
@ -20,8 +20,6 @@ import { generateDid, verifyJws, encryptFor } from './dids';
|
|||
import { issuerReducer, prepareSiopRequest, issueVcsToHolder, parseSiopResponse, CredentialGenerationDetals } from './VerifierLogic';
|
||||
|
||||
import * as s1 from '@decentralized-identity/sidetree/dist/lib/core/versions/latest/protocol-parameters.json';
|
||||
import * as s2 from '@decentralized-identity/sidetree/dist/lib/bitcoin/protocol-parameters.json';
|
||||
|
||||
|
||||
const app = express();
|
||||
app.use(express.raw({ type: 'application/x-www-form-urlencoded', limit: '5000kb' }));
|
||||
|
@ -34,7 +32,9 @@ const port = 8080; // default port to listen
|
|||
const fhirBase = 'https://hapi.fhir.org/baseR4';
|
||||
|
||||
async function resolveDid(did: string) {
|
||||
console.log("preparsed", did);
|
||||
const parsedDid = await Did.create(did, 'ion');
|
||||
console.log("Parsed", parsedDid);
|
||||
const operationWithMockedAnchorTime: AnchoredOperationModel = {
|
||||
didUniqueSuffix: parsedDid.uniqueSuffix,
|
||||
type: OperationType.Create,
|
||||
|
@ -47,7 +47,7 @@ async function resolveDid(did: string) {
|
|||
const processor = new OperationProcessor();
|
||||
|
||||
const newDidState = await processor.apply(operationWithMockedAnchorTime, undefined);
|
||||
const document = DocumentComposer.transformToExternalDocument(newDidState, did);
|
||||
const document = DocumentComposer.transformToExternalDocument(newDidState, parsedDid, false);
|
||||
return document;
|
||||
}
|
||||
|
||||
|
@ -196,8 +196,8 @@ app.get('/api/fhir/Patient/:patientID/[\$]HealthWallet.connect', async (req, res
|
|||
});
|
||||
|
||||
async function getVcsForPatient(patientId, details: CredentialGenerationDetals = {
|
||||
type: 'https://healthwallet.cards#covid19',
|
||||
presentationContext: 'https://healthwallet.cards#presentation-context-online',
|
||||
type: 'https://smarthealth.cards#covid19',
|
||||
presentationContext: 'https://smarthealth.cards#presentation-context-online',
|
||||
identityClaims: null,
|
||||
encryptVc: false
|
||||
}) {
|
||||
|
@ -235,12 +235,12 @@ app.get('/api/fhir/DiagnosticReport', async (req, res, err) => {
|
|||
resource: {
|
||||
meta: {
|
||||
tag: [{
|
||||
system: "https://healthwallet.cards",
|
||||
system: "https://smarthealth.cards",
|
||||
code: "covid19"
|
||||
}]
|
||||
},
|
||||
extension: vc ? [{
|
||||
"url": "https://healthwallet.cards#vc-attachment",
|
||||
"url": "https://smarthealth.cards#vc-attachment",
|
||||
"valueAttachment": {
|
||||
"title": "COVID-19 Card for online presentation",
|
||||
"data": base64.encode(vc)
|
||||
|
@ -564,7 +564,7 @@ app.use(function(err, req, res, next) {
|
|||
"diagnostics": err + "\n" + err.message + "\n" + err.stack,
|
||||
"details": {
|
||||
coding: err.code ? [{
|
||||
"system": "https://healthwallet.cards",
|
||||
"system": "https://smarthealth.cards",
|
||||
"code": err.code,
|
||||
"display": err.display
|
||||
}] : undefined
|
||||
|
|
|
@ -11,7 +11,7 @@ LOINC PCR Tests in DB [
|
|||
FHIR Bundle size 1225
|
||||
|
||||
Summary JSON {
|
||||
alg: 'https://healthwallet.cards#c19-status',
|
||||
alg: 'https://smarthealth.cards#c19-status',
|
||||
ver: '0.0.1',
|
||||
ptName: 'Eve Everywoman',
|
||||
ptPhone: '000-000-0000',
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://healthwallet.cards/c19-status.schema.json",
|
||||
"$id": "https://smarthealth.cards/c19-status.schema.json",
|
||||
"type": "object",
|
||||
"title": "Summarize Covid Status",
|
||||
"description": "Represents a summary of FHIR data to determine COVID-19 infection status as at specific points in time.",
|
||||
"examples": [{
|
||||
"alg": "https://healthwallet.cards#c19-status",
|
||||
"alg": "https://smarthealth.cards#c19-status",
|
||||
"ver": "0.0.1",
|
||||
"ial": 2,
|
||||
"ptName": "Eve Everywoman",
|
||||
|
@ -28,7 +28,7 @@
|
|||
"type": "string",
|
||||
"title": "Algorithm",
|
||||
"description": "Algorithm used to produce this summary",
|
||||
"const": "https://healthwallet.cards#c19-status"
|
||||
"const": "https://smarthealth.cards#c19-status"
|
||||
},
|
||||
"ver": {
|
||||
"$id": "#/properties/ver",
|
||||
|
|
|
@ -48,12 +48,12 @@ const hasCodeFrom = (codes) => (cc) => (cc.coding || [] as { code: string }[])
|
|||
const patient = fhirBundle.entry.map(e => e.resource).filter(r => r.resourceType === 'Patient')[0]
|
||||
|
||||
const output = {
|
||||
alg: "https://healthwallet.cards#c19-status",
|
||||
alg: "https://smarthealth.cards#c19-status",
|
||||
ver: "0.0.1",
|
||||
ptName: patient.name.map(n =>
|
||||
[n.prefix || ""]
|
||||
.concat(n.given)
|
||||
.concat(n.family)
|
||||
.concat([n.family])
|
||||
.concat([n.suffix || ""])
|
||||
.filter(n => n).join(" "))
|
||||
[0],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://healthwallet.cards/algorithms/2-c19-immunization-status.schema.json",
|
||||
"$id": "https://smarthealth.cards/algorithms/2-c19-immunization-status.schema.json",
|
||||
"type": "object",
|
||||
"title": "Summarize Covid-19 Immunization Status",
|
||||
"description": "Represents a summary of FHIR data to determine COVID-19 immunization status at a specifie point in time.",
|
||||
|
|
|
@ -21,7 +21,7 @@ const modernaImmunizations: [any] = fhirBundle.entry
|
|||
.map(e => e.resource)
|
||||
.filter(r => r.resourceType === 'Immunization')
|
||||
.filter(r => r.vaccineCode.coding.filter(c => c.system === CVX && c.code === MODERNA).length > 0)
|
||||
.sort((i1, i2) => new Date(i2.date).getTime() - new Date(i1.date).getTime());
|
||||
.sort((i1, i2) => new Date(i2.occurrenceDateTime).getTime() - new Date(i1.occurrenceDateTime).getTime());
|
||||
|
||||
enum ImmunizationStatus {
|
||||
Never = 0,
|
||||
|
@ -42,7 +42,7 @@ const output = {
|
|||
ptName: patient.name.map(n =>
|
||||
[n.prefix || ""]
|
||||
.concat(n.given)
|
||||
.concat(n.family)
|
||||
.concat([n.family])
|
||||
.concat([n.suffix || ""])
|
||||
.filter(n => n).join(" "))
|
||||
[0],
|
||||
|
@ -62,7 +62,7 @@ const output = {
|
|||
})
|
||||
[0],
|
||||
result: [{
|
||||
effective: modernaImmunizations[0].date,
|
||||
effective: modernaImmunizations[0].occurrenceDateTime,
|
||||
status: modernaImmunizations.length
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as crypto from 'crypto';
|
||||
import { issuerWorld } from './issuer';
|
||||
import { holderWorld } from './holder';
|
||||
import { verifierWorld } from './verifier';
|
||||
|
|
|
@ -72,7 +72,7 @@ const App: React.FC<{
|
|||
if (displayResponse) {
|
||||
did = displayResponse.idTokenPayload.did.replace(/\?.*/, "");
|
||||
const fhirName = displayResponse?.idTokenVcs[0].vc.credentialSubject.fhirBundle.entry[0].resource.name[0]
|
||||
name = fhirName?.given[0] + " " + fhirName?.family[0]
|
||||
name = fhirName?.given[0] + " " + fhirName?.family
|
||||
conclusion = displayResponse?.idTokenVcs.map(jwtPayload => jwtPayload.vc.credentialSubject.fhirBundle.entry[1].resource.conclusion)
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ const App: React.FC<{
|
|||
export default async function main() {
|
||||
const state = await initializeVerifier({
|
||||
role: 'venue',
|
||||
claimsRequired: ['https://healthwallet.cards#covid19'],
|
||||
claimsRequired: ['https://smarthealth.cards#covid19'],
|
||||
responseMode: 'form_post',
|
||||
postRequest: async (url, r) => (await axios.post(url, r)).data,
|
||||
serverBase,
|
||||
|
|
|
@ -12,7 +12,7 @@ import { verifierReducer, prepareSiopRequest, parseSiopResponse } from './Verifi
|
|||
export async function verifierWorld (role = 'verifier', responseMode: SiopResponseMode = 'form_post', reset = false) {
|
||||
let state = await initializeVerifier({
|
||||
role,
|
||||
claimsRequired: ['https://healthwallet.cards#covid19'],
|
||||
claimsRequired: ['https://smarthealth.cards#covid19'],
|
||||
responseMode: responseMode,
|
||||
reset,
|
||||
displayQr: false,
|
||||
|
|
|
@ -18,7 +18,7 @@ const clinicalResource = {
|
|||
describe('CredentialManager', () => {
|
||||
|
||||
test('Does not alter inputs', () => {
|
||||
const asVc = CredentialManager.createVc(issuer, subject, idResource, [clinicalResource])
|
||||
const asVc = CredentialManager.createVc("", [], issuer, subject, idResource, [clinicalResource])
|
||||
|
||||
expect(asVc.issuer).toEqual(issuer)
|
||||
expect(asVc.credentialSubject.id).toEqual(subject)
|
||||
|
@ -32,7 +32,8 @@ describe('CredentialManager', () => {
|
|||
})
|
||||
|
||||
test('creates a VC from FHIR payloads', () => {
|
||||
const asVc = CredentialManager.createVc(issuer, subject, idResource, [clinicalResource])
|
||||
const asVc = CredentialManager.createVc("", [], issuer, subject, idResource, [clinicalResource])
|
||||
|
||||
|
||||
expect(asVc.issuer).toEqual(issuer)
|
||||
expect(asVc.credentialSubject.id).toEqual(subject)
|
||||
|
@ -44,7 +45,7 @@ describe('CredentialManager', () => {
|
|||
})
|
||||
|
||||
test('creates a JWT payload from a VC', () => {
|
||||
const asVc = CredentialManager.createVc(issuer, subject, idResource, [clinicalResource])
|
||||
const asVc = CredentialManager.createVc("sample-context-type", ["sample-type-1", "sample-type-2"], issuer, subject, idResource, [clinicalResource])
|
||||
const asJwtPayload = CredentialManager.vcToJwtPayload(asVc) as any;
|
||||
|
||||
expect(asJwtPayload.id).toBeUndefined()
|
||||
|
@ -69,7 +70,7 @@ describe('CredentialManager', () => {
|
|||
})
|
||||
|
||||
test('recovers a VC from JWT payload', () => {
|
||||
const asVc = CredentialManager.createVc(issuer, subject, idResource, [clinicalResource])
|
||||
const asVc = CredentialManager.createVc("", [], issuer, subject, idResource, [clinicalResource])
|
||||
const asVcCloned = deepcopy(asVc)
|
||||
|
||||
const asJwtPayload = CredentialManager.vcToJwtPayload(asVc) as any;
|
||||
|
|
Загрузка…
Ссылка в новой задаче