Skip to content

Commit

Permalink
feat: added unwrap option to batch command (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminlim00 authored Jan 29, 2020
1 parent 9efa1ee commit 9acc4c8
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 17 deletions.
76 changes: 66 additions & 10 deletions src/__tests__/batchIssue.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const inputDirectoryName = `${fixtureFolderName}/_tmp_in`;
const outputDirectoryName = `${fixtureFolderName}/_tmp_out`;
const validFileName = `${fixtureFolderName}/valid-open-attestation-document.json`;
const invalidFileName = `${fixtureFolderName}/invalid-open-attestation-document.json`;
const wrappedFileName = `${fixtureFolderName}/wrapped-open-attestation-document.json`;
const inputDirectory = path.resolve(__dirname, inputDirectoryName);
const outputDirectory = path.resolve(__dirname, outputDirectoryName);

Expand All @@ -29,7 +30,10 @@ describe("batchIssue", () => {
path.resolve(__dirname, validFileName),
path.resolve(__dirname, `${inputDirectoryName}/valid-open-attestation-document.json`)
);
const merkleRoot = await batchIssue(inputDirectory, outputDirectory, { version: "open-attestation/3.0" });
const merkleRoot = await batchIssue(inputDirectory, outputDirectory, {
version: "open-attestation/3.0",
unwrap: false
});

const file = JSON.parse(
fs.readFileSync(`${outputDirectory}/valid-open-attestation-document.json`, { encoding: "utf8" })
Expand All @@ -51,7 +55,10 @@ describe("batchIssue", () => {
path.resolve(__dirname, validFileName),
path.resolve(__dirname, `${inputDirectoryName}/valid-open-attestation-document-3.json`)
);
const merkleRoot = await batchIssue(inputDirectory, outputDirectory, { version: "open-attestation/3.0" });
const merkleRoot = await batchIssue(inputDirectory, outputDirectory, {
version: "open-attestation/3.0",
unwrap: false
});
const file1 = JSON.parse(
fs.readFileSync(`${outputDirectory}/valid-open-attestation-document-1.json`, { encoding: "utf8" })
);
Expand All @@ -78,7 +85,9 @@ describe("batchIssue", () => {
path.resolve(__dirname, `${inputDirectoryName}/invalid-open-attestation-document.json`)
);

await expect(batchIssue(inputDirectory, outputDirectory, { version: "open-attestation/3.0" })).rejects.toThrow(
await expect(
batchIssue(inputDirectory, outputDirectory, { version: "open-attestation/3.0", unwrap: false })
).rejects.toThrow(
expect.objectContaining({
message: expect.stringContaining(
"src/__tests__/fixture/_tmp_in/invalid-open-attestation-document.json is not valid against open-attestation schema"
Expand All @@ -101,7 +110,9 @@ describe("batchIssue", () => {
path.resolve(__dirname, `${inputDirectoryName}/invalid-open-attestation-document-3.json`)
);

await expect(batchIssue(inputDirectory, outputDirectory, { version: "open-attestation/3.0" })).rejects.toThrow(
await expect(
batchIssue(inputDirectory, outputDirectory, { version: "open-attestation/3.0", unwrap: false })
).rejects.toThrow(
expect.objectContaining({
message: expect.stringContaining(
"src/__tests__/fixture/_tmp_in/invalid-open-attestation-document-1.json is not valid against open-attestation schema"
Expand All @@ -110,16 +121,57 @@ describe("batchIssue", () => {
);
expect(fs.readdirSync(outputDirectory)).toHaveLength(0);
});
it("should not issue document when given wrapped document without --unwrap", async () => {
fs.copyFileSync(
path.resolve(__dirname, wrappedFileName),
path.resolve(__dirname, `${inputDirectoryName}/wrapped-open-attestation-document.json`)
);

await expect(
batchIssue(inputDirectory, outputDirectory, {
version: "open-attestation/3.0",
unwrap: false
})
).rejects.toThrow(
expect.objectContaining({
message: expect.stringContaining(
"src/__tests__/fixture/_tmp_in/wrapped-open-attestation-document.json is not valid against open-attestation schema"
)
})
);
expect(fs.readdirSync(outputDirectory)).toHaveLength(0);
});

it("should issue document when the given document is wrapped and --unwrap is specified", async () => {
fs.copyFileSync(
path.resolve(__dirname, wrappedFileName),
path.resolve(__dirname, `${inputDirectoryName}/wrapped-open-attestation-document.json`)
);

const merkleRoot = await batchIssue(inputDirectory, outputDirectory, {
version: "open-attestation/3.0",
unwrap: true
});

const file = JSON.parse(
fs.readFileSync(`${outputDirectory}/wrapped-open-attestation-document.json`, { encoding: "utf8" })
);

expect(merkleRoot).toHaveLength(64);
expect(merkleRoot).toStrictEqual(file.signature.merkleRoot);
expect(merkleRoot).toStrictEqual(file.signature.targetHash);
});
});
describe("with schema", () => {
it("should issue documents when folder contain one valid open attestation that is also valid against the local schema provided", async () => {
it("should not issue document when the given document is wrapped and --unwrap is not specified", async () => {
fs.copyFileSync(
path.resolve(__dirname, `${fixtureFolderName}/valid-custom-schema-document.json`),
path.resolve(__dirname, `${inputDirectoryName}/valid-custom-schema-document.json`)
);
const merkleRoot = await batchIssue(inputDirectory, outputDirectory, {
schemaPath: path.resolve(__dirname, fixtureFolderName, "schema.json"),
version: "open-attestation/3.0"
version: "open-attestation/3.0",
unwrap: false
});

const file = JSON.parse(
Expand All @@ -137,7 +189,8 @@ describe("batchIssue", () => {
await expect(
batchIssue(inputDirectory, outputDirectory, {
schemaPath: path.resolve(__dirname, fixtureFolderName, "schema.json"),
version: "open-attestation/3.0"
version: "open-attestation/3.0",
unwrap: false
})
).rejects.toThrow(
expect.objectContaining({
Expand All @@ -156,7 +209,8 @@ describe("batchIssue", () => {
const merkleRoot = await batchIssue(inputDirectory, outputDirectory, {
schemaPath:
"https://gist.githubusercontent.com/Nebulis/dd8198ab76443489e14121dad225d351/raw/693b50a1694942fb3cc6a8dcf5187cc7c75adb58/schema.json",
version: "open-attestation/3.0"
version: "open-attestation/3.0",
unwrap: false
});

const file = JSON.parse(
Expand All @@ -175,7 +229,8 @@ describe("batchIssue", () => {
batchIssue(inputDirectory, outputDirectory, {
schemaPath:
"https://gist.githubusercontent.com/Nebulis/dd8198ab76443489e14121dad225d351/raw/693b50a1694942fb3cc6a8dcf5187cc7c75adb58/schema.json",
version: "open-attestation/3.0"
version: "open-attestation/3.0",
unwrap: false
})
).rejects.toThrow(
expect.objectContaining({
Expand All @@ -190,7 +245,8 @@ describe("batchIssue", () => {
await expect(
batchIssue(inputDirectory, outputDirectory, {
schemaPath: path.resolve(__dirname, fixtureFolderName, "invalid-schema.json"),
version: "open-attestation/3.0"
version: "open-attestation/3.0",
unwrap: false
})
).rejects.toThrow("Invalid schema, you must provide an $id property to your schema");
expect(fs.readdirSync(outputDirectory)).toHaveLength(0);
Expand Down
35 changes: 35 additions & 0 deletions src/__tests__/fixture/wrapped-open-attestation-document.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"version": "open-attestation/3.0",
"data": {
"reference": "bb580cf5-87f2-42c8-b0cf-e9d445db336d:string:ABCXXXXX00",
"name": "84f3857b-40f7-41e7-8f71-cb8008fab163:string:Certificate of whatever",
"template": {
"name": "25d8bf44-0470-41cf-8ada-39d72c7364df:string:CUSTOM_TEMPLATE",
"type": "b82ae6ef-1f01-4714-b653-72debeea1839:string:EMBEDDED_RENDERER",
"url": "bfea6de8-db78-46f7-884b-ebbd1339e550:string:http://localhost:3000/rederer"
},
"validFrom": "b99a84c7-3871-4d33-996a-ff03a221371b:string:2018-08-30T00:00:00+08:00",
"proof": {
"type": "710ee6cf-5cea-41b9-a71b-106ad73460a9:string:OpenAttestationSignature2018",
"method": "07d987ad-97b8-4f9e-b06e-a3691a31ae03:string:TOKEN_REGISTRY",
"value": "509cc6a9-3c7d-4214-be79-d2b5fe4a5731:string:0xb53499ee758352fAdDfCed863d9ac35C809E2F20"
},
"issuer": {
"id": "84cf6e77-ed24-416d-bf1a-bd2a88058211:string:https://example.com",
"name": "90ded788-2f16-4b11-bfd4-21c58445730e:string:Issuer name",
"identityProof": {
"type": "283b3e84-b0e5-4dcb-a925-0036fa1f78ea:string:DNS-TXT",
"location": "75a891d6-9ba9-4d5e-9877-efe966dcd901:string:some.io"
}
}
},
"privacy": {
"obfuscatedData": []
},
"signature": {
"type": "SHA3MerkleProof",
"targetHash": "25d71e606ca2b56c1a5345101264626c9c7b89f124f21182b27e46ec208690ae",
"proof": [],
"merkleRoot": "25d71e606ca2b56c1a5345101264626c9c7b89f124f21182b27e46ec208690ae"
}
}
24 changes: 19 additions & 5 deletions src/batchIssue.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { documentsInDirectory, readCert, writeCertToDisk } from "./diskUtils";
import { dirSync } from "tmp";
import mkdirp from "mkdirp";
import { isSchemaValidationError, wrapDocument, utils } from "@govtechsg/open-attestation";
import { isSchemaValidationError, wrapDocument, utils, getData } from "@govtechsg/open-attestation";
import path from "path";
import fetch from "node-fetch";
import Ajv from "ajv";
Expand All @@ -21,6 +21,7 @@ export const digestDocument = async (
undigestedCertDir: string,
digestedCertDir: string,
version: "open-attestation/2.0" | "open-attestation/3.0",
unwrap: boolean,
schema?: Schema
): Promise<Buffer[]> => {
const hashArray: Buffer[] = [];
Expand All @@ -29,9 +30,16 @@ export const digestDocument = async (
if (schema) {
compile = new Ajv().compile(schema);
}

certFileNames.forEach(file => {
// Read individual document
const document = readCert(undigestedCertDir, file);
let document;
if (unwrap) {
document = getData(readCert(undigestedCertDir, file));
} else {
// Read individual document
document = readCert(undigestedCertDir, file);
}

// Digest individual document
if (compile) {
const valid = compile(document);
Expand Down Expand Up @@ -157,7 +165,7 @@ const loadSchema = (schemaPath?: string): Promise<Schema | undefined> => {
export const batchIssue = async (
inputDir: string,
outputDir: string,
options: { schemaPath?: string; version: "open-attestation/2.0" | "open-attestation/3.0" }
options: { schemaPath?: string; version: "open-attestation/2.0" | "open-attestation/3.0"; unwrap: boolean }
): Promise<string> => {
// Create output dir
mkdirp.sync(outputDir);
Expand All @@ -169,7 +177,13 @@ export const batchIssue = async (

// Phase 1: For each document, read content, digest and write to file
const schema = await loadSchema(options.schemaPath);
const individualDocumentHashes = await digestDocument(inputDir, intermediateDir, options.version, schema);
const individualDocumentHashes = await digestDocument(
inputDir,
intermediateDir,
options.version,
options.unwrap,
schema
);

if (!individualDocumentHashes || individualDocumentHashes.length === 0)
throw new Error(`No documents found in ${inputDir}`);
Expand Down
10 changes: 8 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface BatchCommand {
batchedDir: string;
schema: any;
openAttestationV3: boolean;
unwrap: boolean;
}

const isBatchCommand = (args: any): args is BatchCommand => {
Expand Down Expand Up @@ -75,13 +76,17 @@ const parseArguments = (argv: string[]) =>
alias: "oav3",
conflicts: "open-attestation-v2"
})
.option("unwrap", {
alias: "u",
description: "Use if raw directory contains wrapped files"
})
)
.parse(argv);

const batch = async (
raw: string,
batched: string,
options: { schemaPath?: string; version: "open-attestation/2.0" | "open-attestation/3.0" }
options: { schemaPath?: string; version: "open-attestation/2.0" | "open-attestation/3.0"; unwrap: boolean }
): Promise<string | void> => {
mkdirp.sync(batched);
return batchIssue(raw, batched, options).then(merkleRoot => {
Expand Down Expand Up @@ -115,7 +120,8 @@ const main = async (argv: string[]): Promise<any> => {
if (isBatchCommand(args)) {
return batch(args.rawDir, args.batchedDir, {
schemaPath: args.schema,
version: args.openAttestationV3 ? "open-attestation/3.0" : "open-attestation/2.0"
version: args.openAttestationV3 ? "open-attestation/3.0" : "open-attestation/2.0",
unwrap: args.unwrap
});
} else if (isFilterCommand(args)) {
return obfuscate(args.source, args.destination, args.fields);
Expand Down

0 comments on commit 9acc4c8

Please sign in to comment.