From 3ebb2f39f5d6c398a338b8515b87ac23609fbb76 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Mon, 21 Aug 2023 15:24:03 -0600 Subject: [PATCH 1/7] add rest api support --- test/vc-data-model-1.0/util.js | 65 +++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/test/vc-data-model-1.0/util.js b/test/vc-data-model-1.0/util.js index 1fff430..3e2bac0 100644 --- a/test/vc-data-model-1.0/util.js +++ b/test/vc-data-model-1.0/util.js @@ -4,10 +4,39 @@ 'use strict'; const path = require('path'); const util = require('util'); +const fs = require('fs'); +const axios = require('axios'); const exec = util.promisify(require('child_process').exec); async function generate(file, options) { + if (options.restapi) { + return await generate_from_restapi(file, options.restapi); + } else { + return await generate_from_binary(file, options); + } +} + +async function generate_from_restapi(file, options) { + const url = `${options.base_url}${options.generator}`; + const file_content = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); + const data_to_issue = create_issuance_data(file_content, options.generatorOptions); + const axios_options = { + timeout: 2000, + headers: { + 'Content-Type': 'application/json', + 'Authorization': `${options.oauth_token_type} ${options.oauth_token}` + } + } + try { + const response = await axios.post(url, data_to_issue, axios_options); + return response.data?.verifiableCredential ? response.data.verifiableCredential : {}; + } catch (error) { + throw error; + } +} + +async function generate_from_binary(file, options) { options = options || {}; const {stdout, stderr} = await exec(options.generator + ' ' + options.generatorOptions + ' ' + path.join(__dirname, 'input', file)); @@ -32,8 +61,33 @@ async function generateJwt(file, options) { return stdout; } - async function generatePresentation(file, options) { + if (options.restapi) { + return await generatePresentation_from_restapi(file, options.restapi); + } else { + return await generatePresentation_from_binary(file, options); + } +} + +async function generatePresentation_from_restapi(file, options) { + const file_content = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); + const url = `${options.base_url}${options.presentationGenerator}`; + const axios_options = { + timeout: 2000, + headers: { + 'Content-Type': 'application/json', + 'Authorization': `${options.oauth_token_type} ${options.oauth_token}` + } + } + try { + const response = await axios.post(url, file_content, axios_options); + return response.data?.verifiableCredential ? response.data.verifiableCredential : {}; + } catch (error) { + throw error; + } +} + +async function generatePresentation_from_binary(file, options) { options = options || {}; const {stdout, stderr} = await exec(options.presentationGenerator + ' ' + options.generatorOptions + ' ' + path.join(__dirname, 'input', file)); @@ -78,6 +132,15 @@ const RFC3339regex = new RegExp('^(\\d{4})-(0[1-9]|1[0-2])-' + '(\\.[0-9]+)?(Z|(\\+|-)([01][0-9]|2[0-3]):' + '([0-5][0-9]))$', 'i'); +/** + * + * @param {String} unsigned_jsonld A string of an unsigend jsonld + * @returns {String} A jsonld to be used against REST APIs + */ +function create_issuance_data(unsigned_jsonld, options) { + return JSON.stringify({ credential: JSON.parse(unsigned_jsonld), options: options }); +} + module.exports = { generate, generatePresentation, From bfbb8ec24ba500a3b550005d366b37bbd8018a18 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Mon, 21 Aug 2023 15:27:08 -0600 Subject: [PATCH 2/7] update config example --- config.json.example | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/config.json.example b/config.json.example index 78a93f9..ed36b47 100644 --- a/config.json.example +++ b/config.json.example @@ -24,6 +24,23 @@ // The arguments that should be passed to the VC generator. "generatorOptions":"", + // This section overrides the above binary settings in favor of a + // REST API for credential issuance and presentation + "restapi": { + // URL of REST API + "base_url": "https://example.com", + // Issuance endpoint + "generator": "/credentials/issue", + // Presentation endpoint + "presentationGenerator": "/presentations/prove", + // Options to be based in request body + "generatorOptions": {}, + // Authorization token type + "oauth_token_type": "Bearer", + // Authorization token + "oauth_token": "" + }, + // Add section features you are explicitly not supporting // For example, to exclude all features, you would: // "sectionsNotSupported": ["basic", ""schema", "refresh", "evidence", "status", "tou", "ldp", "jwt", "zkp"] From e029279bbc34a4b03a0d17bb62119358ebcd83f0 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Mon, 21 Aug 2023 15:32:55 -0600 Subject: [PATCH 3/7] fix casing --- config.json.example | 6 ++--- test/vc-data-model-1.0/util.js | 40 +++++++++++++++++----------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/config.json.example b/config.json.example index ed36b47..a54816a 100644 --- a/config.json.example +++ b/config.json.example @@ -28,7 +28,7 @@ // REST API for credential issuance and presentation "restapi": { // URL of REST API - "base_url": "https://example.com", + "baseUrl": "https://example.com", // Issuance endpoint "generator": "/credentials/issue", // Presentation endpoint @@ -36,9 +36,9 @@ // Options to be based in request body "generatorOptions": {}, // Authorization token type - "oauth_token_type": "Bearer", + "oauthTokenType": "Bearer", // Authorization token - "oauth_token": "" + "oauthToken": "" }, // Add section features you are explicitly not supporting diff --git a/test/vc-data-model-1.0/util.js b/test/vc-data-model-1.0/util.js index 3e2bac0..56b97bb 100644 --- a/test/vc-data-model-1.0/util.js +++ b/test/vc-data-model-1.0/util.js @@ -11,32 +11,32 @@ const exec = util.promisify(require('child_process').exec); async function generate(file, options) { if (options.restapi) { - return await generate_from_restapi(file, options.restapi); + return await generateFromRestapi(file, options.restapi); } else { - return await generate_from_binary(file, options); + return await generateFromBinary(file, options); } } -async function generate_from_restapi(file, options) { - const url = `${options.base_url}${options.generator}`; - const file_content = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); - const data_to_issue = create_issuance_data(file_content, options.generatorOptions); - const axios_options = { +async function generateFromRestapi(file, options) { + const url = `${options.baseUrl}${options.generator}`; + const fileContent = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); + const dataToIssue = createIssuanceData(fileContent, options.generatorOptions); + const axiosOptions = { timeout: 2000, headers: { 'Content-Type': 'application/json', - 'Authorization': `${options.oauth_token_type} ${options.oauth_token}` + 'Authorization': `${options.oauthTokenType} ${options.oauthToken}` } } try { - const response = await axios.post(url, data_to_issue, axios_options); + const response = await axios.post(url, dataToIssue, axiosOptions); return response.data?.verifiableCredential ? response.data.verifiableCredential : {}; } catch (error) { throw error; } } -async function generate_from_binary(file, options) { +async function generateFromBinary(file, options) { options = options || {}; const {stdout, stderr} = await exec(options.generator + ' ' + options.generatorOptions + ' ' + path.join(__dirname, 'input', file)); @@ -63,31 +63,31 @@ async function generateJwt(file, options) { async function generatePresentation(file, options) { if (options.restapi) { - return await generatePresentation_from_restapi(file, options.restapi); + return await generatePresentationFromRestapi(file, options.restapi); } else { - return await generatePresentation_from_binary(file, options); + return await generatePresentationFromBinary(file, options); } } -async function generatePresentation_from_restapi(file, options) { - const file_content = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); - const url = `${options.base_url}${options.presentationGenerator}`; - const axios_options = { +async function generatePresentationFromRestapi(file, options) { + const fileContent = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); + const url = `${options.baseUrl}${options.presentationGenerator}`; + const axiosOptions = { timeout: 2000, headers: { 'Content-Type': 'application/json', - 'Authorization': `${options.oauth_token_type} ${options.oauth_token}` + 'Authorization': `${options.oauthTokenType} ${options.oauthToken}` } } try { - const response = await axios.post(url, file_content, axios_options); + const response = await axios.post(url, fileContent, axiosOptions); return response.data?.verifiableCredential ? response.data.verifiableCredential : {}; } catch (error) { throw error; } } -async function generatePresentation_from_binary(file, options) { +async function generatePresentationFromBinary(file, options) { options = options || {}; const {stdout, stderr} = await exec(options.presentationGenerator + ' ' + options.generatorOptions + ' ' + path.join(__dirname, 'input', file)); @@ -137,7 +137,7 @@ const RFC3339regex = new RegExp('^(\\d{4})-(0[1-9]|1[0-2])-' + * @param {String} unsigned_jsonld A string of an unsigend jsonld * @returns {String} A jsonld to be used against REST APIs */ -function create_issuance_data(unsigned_jsonld, options) { +function createIssuanceData(unsigned_jsonld, options) { return JSON.stringify({ credential: JSON.parse(unsigned_jsonld), options: options }); } From 2739e1b2ac8fd55ce0966345d2f46d28cc535853 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Mon, 18 Sep 2023 13:43:25 -0600 Subject: [PATCH 4/7] include missing axios --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index b885f25..77c1245 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "@decentralized-identity/did-auth-jose": "^0.1.13" }, "devDependencies": { + "axios": "^1.5.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "mocha": "^6.1.4" From ed1b62921026426ddf2a2ac11f041f647de57a49 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Tue, 10 Oct 2023 14:34:56 -0600 Subject: [PATCH 5/7] modify to work with rest api presentations --- test/vc-data-model-1.0/util.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/test/vc-data-model-1.0/util.js b/test/vc-data-model-1.0/util.js index 56b97bb..6037782 100644 --- a/test/vc-data-model-1.0/util.js +++ b/test/vc-data-model-1.0/util.js @@ -71,6 +71,7 @@ async function generatePresentation(file, options) { async function generatePresentationFromRestapi(file, options) { const fileContent = fs.readFileSync(path.join(__dirname, 'input', file), 'utf8'); + const dataToIssue = createPresentationData(fileContent, options.generatorOptions); const url = `${options.baseUrl}${options.presentationGenerator}`; const axiosOptions = { timeout: 2000, @@ -80,8 +81,8 @@ async function generatePresentationFromRestapi(file, options) { } } try { - const response = await axios.post(url, fileContent, axiosOptions); - return response.data?.verifiableCredential ? response.data.verifiableCredential : {}; + const response = await axios.post(url, dataToIssue, axiosOptions); + return response.data?.verifiablePresentation ? response.data.verifiablePresentation : {}; } catch (error) { throw error; } @@ -133,12 +134,23 @@ const RFC3339regex = new RegExp('^(\\d{4})-(0[1-9]|1[0-2])-' + '([0-5][0-9]))$', 'i'); /** - * - * @param {String} unsigned_jsonld A string of an unsigend jsonld + * Transform a test input jsonld file to a payload for a REST credentials/issue + * @param {String} unsigned_jsonld A string of an unsigned credential jsonld + * @param {Object} options The arguments that should be passed to the VC generator * @returns {String} A jsonld to be used against REST APIs */ function createIssuanceData(unsigned_jsonld, options) { - return JSON.stringify({ credential: JSON.parse(unsigned_jsonld), options: options }); + return JSON.stringify({ credential: JSON.parse(unsigned_jsonld), options }); +} + +/** + * Transform a test input jsonld file to a payload for a REST presentation/prove + * @param {String} unsigned_jsonld A string of an unsigned presentation jsonld + * @param {String} options The arguments that should be passed to the VP generator + * @returns {String} A jsonld to be used against REST APIs + */ +function createPresentationData(unsigned_jsonld, options) { + return JSON.stringify({ presentation: JSON.parse(unsigned_jsonld), options }); } module.exports = { From 5584ee74066ccee4b010a2eab29f04601bc8ac26 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Wed, 11 Oct 2023 12:53:11 -0600 Subject: [PATCH 6/7] fix error for implementation report --- test/vc-data-model-1.0/util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/vc-data-model-1.0/util.js b/test/vc-data-model-1.0/util.js index 6037782..da6a261 100644 --- a/test/vc-data-model-1.0/util.js +++ b/test/vc-data-model-1.0/util.js @@ -32,7 +32,7 @@ async function generateFromRestapi(file, options) { const response = await axios.post(url, dataToIssue, axiosOptions); return response.data?.verifiableCredential ? response.data.verifiableCredential : {}; } catch (error) { - throw error; + throw new Error('Failed to get valid response'); } } @@ -84,7 +84,7 @@ async function generatePresentationFromRestapi(file, options) { const response = await axios.post(url, dataToIssue, axiosOptions); return response.data?.verifiablePresentation ? response.data.verifiablePresentation : {}; } catch (error) { - throw error; + throw new Error('Failed to get valid response'); } } From 1e464cc47ff98218954d3f27c6b06124d6b8c032 Mon Sep 17 00:00:00 2001 From: Adam Ahmed Date: Mon, 23 Oct 2023 15:22:39 -0600 Subject: [PATCH 7/7] Update test/vc-data-model-1.0/util.js Co-authored-by: Ted Thibodeau Jr --- test/vc-data-model-1.0/util.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/vc-data-model-1.0/util.js b/test/vc-data-model-1.0/util.js index da6a261..9cc9fd9 100644 --- a/test/vc-data-model-1.0/util.js +++ b/test/vc-data-model-1.0/util.js @@ -134,20 +134,20 @@ const RFC3339regex = new RegExp('^(\\d{4})-(0[1-9]|1[0-2])-' + '([0-5][0-9]))$', 'i'); /** - * Transform a test input jsonld file to a payload for a REST credentials/issue - * @param {String} unsigned_jsonld A string of an unsigned credential jsonld + * Transform a test input JSON-LD file to a payload for a REST credentials/issue + * @param {String} unsigned_jsonld A string of an unsigned credential JSON-LD * @param {Object} options The arguments that should be passed to the VC generator - * @returns {String} A jsonld to be used against REST APIs + * @returns {String} A JSON-LD string to be used against REST APIs */ function createIssuanceData(unsigned_jsonld, options) { return JSON.stringify({ credential: JSON.parse(unsigned_jsonld), options }); } /** - * Transform a test input jsonld file to a payload for a REST presentation/prove - * @param {String} unsigned_jsonld A string of an unsigned presentation jsonld + * Transform a test input JSON-LD file to a payload for a REST presentation/prove + * @param {String} unsigned_jsonld A string of an unsigned presentation JSON-LD * @param {String} options The arguments that should be passed to the VP generator - * @returns {String} A jsonld to be used against REST APIs + * @returns {String} A JSON-LD string to be used against REST APIs */ function createPresentationData(unsigned_jsonld, options) { return JSON.stringify({ presentation: JSON.parse(unsigned_jsonld), options });