Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: finalise OA v4.0 context url #311

Merged
merged 11 commits into from
Jul 26, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ try {
const wrappedDocument = await wrapDocument({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json",
"https://schemata.openattestation.com/com/openattestation/4.0/context.json",
],
type: ["VerifiableCredential", "OpenAttestationCredential"],
name: "Republic of Singapore Driving Licence",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"test:vc": "scripts/runVcTest.sh",
"lint": "eslint . --ext .ts,.json --max-warnings 0",
"lint:fix": "npm run lint -- --fix",
"fetch-v4-contexts": "npx ts-node scripts/fetchV4Contexts.ts",
"generate-v4-fixtures": "npx ts-node scripts/generateV4JsonFixtures.ts",
"generate-v4-json-schemas": "npx ts-node scripts/generateV4JsonSchemas.ts",
"publish:schema": "./scripts/publishSchema.sh",
Expand Down
24 changes: 24 additions & 0 deletions scripts/fetchV4Contexts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import fs from "fs";
import path from "path";
import { ContextUrl } from "../src/4.0/context";

const OUTPUT_DIR = path.resolve("./src/4.0/contexts/__generated__");

// make sure the output directory exists
if (fs.existsSync(OUTPUT_DIR)) {
fs.rmSync(OUTPUT_DIR, { recursive: true });
}
fs.mkdirSync(OUTPUT_DIR, { recursive: true });

const CONTEXTS_TO_FETCH = Object.values(ContextUrl);

const sb: string[] = [`const contextsMap = new Map<string, string>();`];
Promise.all(
CONTEXTS_TO_FETCH.map(async (url) => {
const context = await (await fetch(url)).json();
sb.push(`contextsMap.set("${url}", \`${JSON.stringify(context)}\`);`);
})
).then(() => {
sb.push(`export { contextsMap };`);
fs.writeFileSync(path.join(OUTPUT_DIR, "index.ts"), sb.join("\n"));
});
66 changes: 33 additions & 33 deletions src/4.0/__tests__/digest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { obfuscateVerifiableCredential } from "../obfuscate";
const ROOT_CREDENTIAL_TARGET_HASH = ROOT_CREDENTIAL.proof.targetHash;

describe("V4 digestCredential", () => {
test("given all testobfuscated documents are generated from the ROOT_CREDENTIAL, ROOT_CREDENTIAL_TARGET_HASH should match snapshot", () => {
test("given that obfuscated documents are generated from the ROOT_CREDENTIAL, ROOT_CREDENTIAL_TARGET_HASH should match snapshot", () => {
expect(ROOT_CREDENTIAL_TARGET_HASH).toMatchInlineSnapshot(
`"dd55a7d96d47e58350f2cfb03ebdf3f859684c9f97ba75eed55b1bdcc761c5aa"`
`"0b1f90bc8e87cfce8ec49cea60d406291ad130ddedc26e866a8c4f2152747abc"`
);
});

Expand Down Expand Up @@ -66,7 +66,7 @@ describe("V4 digestCredential", () => {
`);
expect(OBFUSCATED_WRAPPED_DOCUMENT.proof.privacy.obfuscated).toMatchInlineSnapshot(`
[
"410849f7c317307141d4cecd4d72fe7efb9655abaa0ee37374b2ec53a3588ee7",
"31744f7aac0af84e23e752611279933657ff78a9065330f8c5029ec5205979a3",
]
`);

Expand Down Expand Up @@ -105,9 +105,9 @@ describe("V4 digestCredential", () => {
`);
expect(OBFUSCATED_WRAPPED_DOCUMENT.proof.privacy.obfuscated).toMatchInlineSnapshot(`
[
"410849f7c317307141d4cecd4d72fe7efb9655abaa0ee37374b2ec53a3588ee7",
"21f8a6f2f464ff14afbc52e4dcb965d7891a7c63fd37eb93f8f98477dcdfc7f9",
"228eb6b469ca3a475238455f11125b7edc826c6dc3ae727d023d1eb71d0e60d6",
"31744f7aac0af84e23e752611279933657ff78a9065330f8c5029ec5205979a3",
"f49443c7e5fcb9f20dad4463a5e0b2cb3e341c430d4792cb87cb11bce0efd9b0",
"7f2ecdae29b49b3a971d5acdfbbf9225a193e735ce41b89b0d84cca801794fc9",
]
`);

Expand All @@ -128,40 +128,40 @@ describe("V4 digestCredential", () => {
proof: {
type: "OpenAttestationMerkleProofSignature2018",
proofPurpose: "assertionMethod",
targetHash: "dd55a7d96d47e58350f2cfb03ebdf3f859684c9f97ba75eed55b1bdcc761c5aa",
targetHash: "0b1f90bc8e87cfce8ec49cea60d406291ad130ddedc26e866a8c4f2152747abc",
proofs: [],
merkleRoot: "dd55a7d96d47e58350f2cfb03ebdf3f859684c9f97ba75eed55b1bdcc761c5aa",
merkleRoot: "0b1f90bc8e87cfce8ec49cea60d406291ad130ddedc26e866a8c4f2152747abc",
salts: "W10=",
privacy: {
obfuscated: [
"0fd4ac5ade244ee2fe47437ea43cd142479540b878fffc86662600fce4d47ef5",
"0cc6e4c50bb090af720d224a9bd73be4c0d72831fc701907339693cdcb34ede3",
"d2afadbec39872577eae0d5e4ea3b590608cab744f214a2f703f65a5b41683cb",
"569b596d71fb145e9c87be1b301da3cbc89cfc104627f6dd95c8123f7974e9c6",
"5dee7aa2b48b9a5edae5042459c7c3eeaa8c5b13132b1477641c727a89471b36",
"2a1ff14be659821afa68edc245f67b9e25331b450715b41348ed2405334d5abd",
"0f1d172b5352464121dffc550e16f64b8019637e39768c506fd2e517a0da305d",
"ff4eeed1d7bb70aef646d46dc75b3408cf019e0daeaf2ef0313974690d8beef2",
"2a4e9fd43be0221af2f02a6b959edf704b630559268a0b2a657fe046e282fbb8",
"bbdf2b05cc0bd2a64fc3483211806e2f863bea05fba81f63092ec07c4ee8ebd9",
"bd9acf6bef05f94720f0fa9c5540bb9db7d6370c39e2bbbee31e408842985dae",
"410849f7c317307141d4cecd4d72fe7efb9655abaa0ee37374b2ec53a3588ee7",
"32a55f464387e37df8f74cf3de6a8e04626e19c2f4d5ec8931aee4b866329fb8",
"21f8a6f2f464ff14afbc52e4dcb965d7891a7c63fd37eb93f8f98477dcdfc7f9",
"6bc7b2350b59b02a44d2593ee7538590114544bc3a39fe9564ee49b387c883c4",
"228eb6b469ca3a475238455f11125b7edc826c6dc3ae727d023d1eb71d0e60d6",
"d6e7027dd62b265e83aaf306f095446efab2677e940a0fbb118cc91dd8226fdb",
"da26ce90128b1cfd747218cad4c7e86b83f6ab236598ce18aecc3b10426b1b71",
"5edea35aa869577c2fd14159534b08da061a7833665cf1cc28f400474c26be01",
"d55b72f926f7adaa5ea4f271ffc2f574e4859b05c16042f5b604e52f044a11d0",
"dd69de699de90b82cfb658fc304ae4f3131e841d56fd68eb20e17af73613a4d3",
"280bc622006d5ec28a42096b57f15f8238df27762c3f754d56dcd89f3aa02c25",
"3d8bc5cbcd2826489cdc80a64d586a4d220d975bc2848aa535bd1e4f17dc619f",
"fb3e116ab528a97d055822754f9ccd1ca5d2962a74d533cc34f066e65a93c76f",
"fe5c8db00ea1f1b4cfcbc29d00810cd6e18f715b98d3660090ee30cf88b4375c",
"27c33bf2f9e5ba4d94c017569174f1432f8887994bfaa70a50c0cf42e62e9f3e",
"5094d0467785684f843648d3edbd1e370df296327796a13b18112e0941bbf14e",
"a4723abfc6809faa72d62d44bb9a11d35e93a780c7a5cb69cdd3693c45960367",
"62858cb5907188767134ec958c6cdfd17e44e52f1511e56b06670fe1b0588160",
"f0250ff7053e849fda119078d5d5dd6689eb7751a74cab71aa11f92941d22aa9",
"d1741f3c9b8bde24eea271870f8200c6c627a94739051d7b7a480e0aaff60bc0",
"6da741164cefb41160b23388b3ee9b0944fab0bedd70b63e20cee0af3fabe565",
"780e835a67653d28f0582d8fb3a1980709b178841fe4d1f6019be0f49db41ac3",
"5c91f334f63f258e4ba299da14880019711538169512e5c6449fbfca7edd7110",
"31744f7aac0af84e23e752611279933657ff78a9065330f8c5029ec5205979a3",
"ab0957fe8747ac06749268e6398bd4cf67a8a22bf0e67eaacc030bcb5f11e3ed",
"f49443c7e5fcb9f20dad4463a5e0b2cb3e341c430d4792cb87cb11bce0efd9b0",
"0df8aa79b275612b491103b10804276364da6dc49f398faa7be2190de1d60cd2",
"7f2ecdae29b49b3a971d5acdfbbf9225a193e735ce41b89b0d84cca801794fc9",
"0eccbf844ac0b68bdd5de85894dce6ecb429f36f4e21630ff70d487a92b2e75f",
"135c5417e9baec64bbe977f9244496aae4a452bf58177b4fd9064c8afdfe483a",
"b8e8cc46e99c58420e5819ed9f80b90489b2db72f6eb94dc84d1f6a15a331030",
"b5554487209f1b99fc73190a8f32e3b2087a6e310f3d05f7c8f7c1f488565b0c",
"c38928d0bad7d71f6e2a7aa33b4983afbeaa9e3c990de6137385b30fc6d5a9ac",
"856d307b40543221d78ba858c6438f4f3e773ab2a81f3140bdff8bc21e30b0d5",
"2be8c866f23b27108c9f2d9acfc21bfef5f61124a2272eb3cee1e94cd79c68c0",
],
},
key: "did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller",
key: "did:ethr:0xB26B4941941C51a4885E5B7D3A1B861E54405f90#controller",
signature:
"0xa3ac9f73a7314c0aad47bad875921f5c88d2af9440d6c309fc2f93dbf43bd8235e84b744cb1ff1c09c214b559ce3bd6eb148c2f68c677cb8408d96e9b5411dfb1c",
"0x949b76d8df493a56c1cf21303a74d6a54904461c1c10f4619b43ad7d339c64467c61eb4c0873f279cd21d5bdd044d3af5318f14d63f57acbd4cde30f271f3eb71c",
},
} as unknown as V4SignedWrappedDocument;

Expand Down
2 changes: 1 addition & 1 deletion src/4.0/__tests__/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe("V4 E2E Test Scenarios", () => {
const wrappedDocument = await wrapDocument(RAW_DOCUMENT_DID);
expect(wrappedDocument["@context"]).toEqual([
"https://www.w3.org/ns/credentials/v2",
"https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json",
"https://schemata.openattestation.com/com/openattestation/4.0/context.json",
]);
expect(wrappedDocument.type).toEqual(["VerifiableCredential", "OpenAttestationCredential"]);
expect(wrappedDocument.proof.type).toBe("OpenAttestationMerkleProofSignature2018");
Expand Down
4 changes: 3 additions & 1 deletion src/4.0/__tests__/obfuscate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,9 @@ describe("privacy", () => {
test("should return array of hashes when there is obfuscated data in document", () => {
const obfuscatedData = getObfuscatedData(SIGNED_WRAPPED_DOCUMENT_DID_OBFUSCATED);
expect(obfuscatedData.length).toBe(1);
expect(obfuscatedData?.[0]).toBe("0394c26c5be1bde929bf5aec2e076fc6843ace379be541c30707dab467baa59f");
expect(obfuscatedData?.[0]).toMatchInlineSnapshot(
`"7f2ecdae29b49b3a971d5acdfbbf9225a193e735ce41b89b0d84cca801794fc9"`
);
});
});

Expand Down
8 changes: 4 additions & 4 deletions src/4.0/__tests__/sign.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ describe("V4 sign", () => {
const { proof } = parsedResults.data;
expect(Object.keys(proof).length).toBe(9);
expect(proof.key).toBe("did:ethr:0xE712878f6E8d5d4F9e87E10DA604F9cB564C9a89#controller");
expect(proof.signature).toBe(
"0xa3ac9f73a7314c0aad47bad875921f5c88d2af9440d6c309fc2f93dbf43bd8235e84b744cb1ff1c09c214b559ce3bd6eb148c2f68c677cb8408d96e9b5411dfb1c"
expect(proof.signature).toMatchInlineSnapshot(
`"0x625a9c8f7915c4f495fc872dd771d30fb289f405b11030862292a015f10602455451c7f4b5981109fb301915327fb502b4961beeb64b9acf3f9c9c8f8b42deeb1c"`
);
});
it("should sign a document with a wallet", async () => {
Expand All @@ -41,8 +41,8 @@ describe("V4 sign", () => {
const { proof } = parsedResults.data;
expect(Object.keys(proof).length).toBe(9);
expect(proof.key).toBe("did:ethr:0x906FB815De8976b1e38D9a4C1014a3acE16Ce53C#controller");
expect(proof.signature).toBe(
"0xb850c0f34d834a7de4185eead5295eeebf9a56ada4603d94f10a72e0fe144179140ce534ddb4123c6fffbf5594d112e1f679e537b29c5188ccd2b940c4798dd11b"
expect(proof.signature).toMatchInlineSnapshot(
`"0xde916f44e6d3a83ec082fd35eb0b85fc541deebe5e53082c2eaf07ec5ddd503f1929f650f3c39c6b4c224a56599e4e66d018dfd536019560f117b89adff6ead61b"`
);
});

Expand Down
6 changes: 3 additions & 3 deletions src/4.0/__tests__/wrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe("V4.0 wrap document", () => {
const wrapped = await wrapDocument({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json",
"https://schemata.openattestation.com/com/openattestation/4.0/context.json",
],
type: ["VerifiableCredential", "OpenAttestationCredential"],
credentialSubject: {
Expand Down Expand Up @@ -40,7 +40,7 @@ describe("V4.0 wrap document", () => {
wrapDocument({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json",
"https://schemata.openattestation.com/com/openattestation/4.0/context.json",
],

type: ["VerifiableCredential", "OpenAttestationCredential"],
Expand Down Expand Up @@ -76,7 +76,7 @@ describe("V4.0 wrap document", () => {
wrapDocument({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json",
"https://schemata.openattestation.com/com/openattestation/4.0/context.json",
],

type: ["VerifiableCredential", "OpenAttestationCredential"],
Expand Down
26 changes: 13 additions & 13 deletions src/4.0/context.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { expand, Options, JsonLdDocument } from "jsonld";
import { fetch } from "cross-fetch";
import { expand, Options, JsonLdDocument } from "jsonld";
import { contextsMap } from "./contexts/__generated__";

export const ContextUrl = {
v2_vc: "https://www.w3.org/ns/credentials/v2",
v4_alpha: "https://schemata.openattestation.com/com/openattestation/4.0/alpha-context.json",
w3c_vc_v2: "https://www.w3.org/ns/credentials/v2",
oa_vc_v4: "https://schemata.openattestation.com/com/openattestation/4.0/context.json",
} as const;

export const ContextType = {
BaseContext: "VerifiableCredential",
V4AlphaContext: "OpenAttestationCredential",
OAV4Context: "OpenAttestationCredential",
} as const;

const preloadedContextList = [ContextUrl.v2_vc, ContextUrl.v4_alpha];
const contexts: Map<string, any> = new Map();
const contextCache: Map<string, Record<any, any>> = new Map();

// Preload frequently used contexts
// https://github.com/digitalbazaar/jsonld.js?tab=readme-ov-file#custom-document-loader
let isFirstLoad = true;
// https://github.com/digitalbazaar/jsonld.js?tab=readme-ov-file#custom-document-loader
// FIXME: @types/json-ld seems to be outdated as callback is supposed to be options
const documentLoader: Options.DocLoader["documentLoader"] = async (url, _) => {
// On first load: Preload frequently used contexts so that no network request will be made on runtime
if (isFirstLoad) {
isFirstLoad = false;
for (const url of preloadedContextList) {
const document = await fetch(url).then((res) => res.json());
contexts.set(url, document);
for (const [url, value] of contextsMap) {
const parsed = JSON.parse(value);
contextCache.set(url, parsed);
}
}
if (contexts.get(url)) {
if (contextCache.get(url)) {
return {
contextUrl: undefined, // this is for a context via a link header
document: contexts.get(url), // this is the actual document that was loaded
document: contextCache.get(url), // this is the actual document that was loaded
documentUrl: url, // this is the actual context URL after redirects
};
} else {
Expand Down
Loading
Loading