feat: tweaks to src, use new classes and enums

This commit is contained in:
Yarmo Mackenbach 2023-07-09 12:03:25 +02:00
parent 149ac6f71e
commit 00d646e2b2
No known key found for this signature in database
GPG key ID: 3C57D093219103A3
6 changed files with 130 additions and 47 deletions

View file

@ -19,6 +19,7 @@ import { base32, base64url } from 'rfc4648'
import { Claim } from './claim.js' import { Claim } from './claim.js'
import { Persona } from './persona.js' import { Persona } from './persona.js'
import { Profile } from './profile.js' import { Profile } from './profile.js'
import { ProfileType } from './enums.js'
const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512'] const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512']
@ -129,9 +130,12 @@ export async function parseProfileJws (profileJws, uri) {
const profileClaimsParsed = profileClaims.map(x => new Claim(x, uri)) const profileClaimsParsed = profileClaims.map(x => new Claim(x, uri))
const pe = new Persona(profileName, profileDescription || '', profileClaimsParsed) const pe = new Persona(profileName, profileClaimsParsed)
const pr = new Profile([pe]) if (profileDescription) {
pr.primaryPersona = 0 pe.setDescription(profileDescription)
}
const pr = new Profile(ProfileType.ASP, uri, [pe])
return pr return pr
} }

View file

@ -75,9 +75,9 @@ export const EntityEncodingFormat = {
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
export const ProofAccess = { export const ProofAccessRestriction = {
/** Any HTTP request will work */ /** Any HTTP request will work */
GENERIC: 'generic', NONE: 'none',
/** CORS requests are denied */ /** CORS requests are denied */
NOCORS: 'nocors', NOCORS: 'nocors',
/** HTTP requests must contain API or access tokens */ /** HTTP requests must contain API or access tokens */
@ -127,13 +127,72 @@ export const ClaimRelation = {
/** /**
* Status of the Claim instance * Status of the Claim instance
* @readonly * @readonly
* @enum {string} * @enum {number}
*/ */
export const ClaimStatus = { export const ClaimStatus = {
/** Claim has been initialized */ /** Claim has been initialized */
INIT: 'init', INIT: 100,
/** Claim has matched its URI to candidate claim definitions */ /** Claim has matched its URI to candidate claim definitions */
MATCHED: 'matched', MATCHED: 101,
/** Claim has verified one or multiple candidate claim definitions */ /** Claim was successfully verified */
VERIFIED: 'verified' VERIFIED: 200,
/** Claim was successfully verified using proxied data */
VERIFIED_VIA_PROXY: 201,
/** Unknown matching error */
MATCHING_ERROR: 300,
/** No matched service providers */
NO_MATCHES: 301,
/** Unknown matching error */
VERIFICATION_ERROR: 400,
/** No proof found in data returned by service providers */
NO_PROOF_FOUND: 401
}
/**
* Profile type
* @readonly
* @enum {string}
*/
export const ProfileType = {
/** ASP profile */
ASP: 'asp',
/** OpenPGP profile */
OPENPGP: 'openpgp'
}
/**
* Public key type
* @readonly
* @enum {string}
*/
export const PublicKeyType = {
EDDSA: 'eddsa',
ES256: 'es256',
OPENPGP: 'openpgp',
NONE: 'none'
}
/**
* Public key format
* @readonly
* @enum {string}
*/
export const PublicKeyEncoding = {
PEM: 'pem',
JWK: 'jwk',
ARMORED_PGP: 'armored_pgp',
NONE: 'none'
}
/**
* Method to fetch the public key
* @readonly
* @enum {string}
*/
export const PublicKeyFetchMethod = {
ASPE: 'aspe',
HKP: 'hkp',
WKD: 'wkd',
HTTP: 'http',
NONE: 'none'
} }

View file

@ -17,6 +17,7 @@ export { Profile } from './profile.js'
export { Persona } from './persona.js' export { Persona } from './persona.js'
export { Claim } from './claim.js' export { Claim } from './claim.js'
export { ServiceProvider } from './serviceProvider.js' export { ServiceProvider } from './serviceProvider.js'
export * as ServiceProviderDefinitions from './serviceProviders/index.js'
export * as proofs from './proofs.js' export * as proofs from './proofs.js'
export * as openpgp from './openpgp.js' export * as openpgp from './openpgp.js'
export * as asp from './asp.js' export * as asp from './asp.js'

View file

@ -16,7 +16,7 @@ limitations under the License.
import { isNode } from 'browser-or-node' import { isNode } from 'browser-or-node'
import * as fetcher from './fetcher/index.js' import * as fetcher from './fetcher/index.js'
import { generateProxyURL } from './utils.js' import { generateProxyURL } from './utils.js'
import { Fetcher, ProxyPolicy, ProofAccess } from './enums.js' import { ProxyPolicy, ProofAccessRestriction } from './enums.js'
/** /**
* @module proofs * @module proofs
@ -29,20 +29,11 @@ import { Fetcher, ProxyPolicy, ProofAccess } from './enums.js'
* choose the right approach to fetch the proof. An error will be thrown if no * choose the right approach to fetch the proof. An error will be thrown if no
* approach is possible. * approach is possible.
* @async * @async
* @param {object} data - Data from a claim definition * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} * @returns {Promise<object|string>}
*/ */
export async function fetch (data, opts) { export async function fetch (data, opts) {
switch (data.proof.request.fetcher) {
case Fetcher.HTTP:
data.proof.request.data.format = data.proof.request.format
break
default:
break
}
if (isNode) { if (isNode) {
return handleNodeRequests(data, opts) return handleNodeRequests(data, opts)
} }
@ -50,6 +41,11 @@ export async function fetch (data, opts) {
return handleBrowserRequests(data, opts) return handleBrowserRequests(data, opts)
} }
/**
* @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/
const handleBrowserRequests = (data, opts) => { const handleBrowserRequests = (data, opts) => {
switch (opts.proxy.policy) { switch (opts.proxy.policy) {
case ProxyPolicy.ALWAYS: case ProxyPolicy.ALWAYS:
@ -57,11 +53,11 @@ const handleBrowserRequests = (data, opts) => {
case ProxyPolicy.NEVER: case ProxyPolicy.NEVER:
switch (data.proof.request.access) { switch (data.proof.request.access) {
case ProofAccess.GENERIC: case ProofAccessRestriction.NONE:
case ProofAccess.GRANTED: case ProofAccessRestriction.GRANTED:
return createDefaultRequestPromise(data, opts) return createDefaultRequestPromise(data, opts)
case ProofAccess.NOCORS: case ProofAccessRestriction.NOCORS:
case ProofAccess.SERVER: case ProofAccessRestriction.SERVER:
throw new Error( throw new Error(
'Impossible to fetch proof (bad combination of service access and proxy policy)' 'Impossible to fetch proof (bad combination of service access and proxy policy)'
) )
@ -71,13 +67,13 @@ const handleBrowserRequests = (data, opts) => {
case ProxyPolicy.ADAPTIVE: case ProxyPolicy.ADAPTIVE:
switch (data.proof.request.access) { switch (data.proof.request.access) {
case ProofAccess.GENERIC: case ProofAccessRestriction.NONE:
return createFallbackRequestPromise(data, opts) return createFallbackRequestPromise(data, opts)
case ProofAccess.NOCORS: case ProofAccessRestriction.NOCORS:
return createProxyRequestPromise(data, opts) return createProxyRequestPromise(data, opts)
case ProofAccess.GRANTED: case ProofAccessRestriction.GRANTED:
return createFallbackRequestPromise(data, opts) return createFallbackRequestPromise(data, opts)
case ProofAccess.SERVER: case ProofAccessRestriction.SERVER:
return createProxyRequestPromise(data, opts) return createProxyRequestPromise(data, opts)
default: default:
throw new Error('Invalid proof access value') throw new Error('Invalid proof access value')
@ -88,6 +84,11 @@ const handleBrowserRequests = (data, opts) => {
} }
} }
/**
* @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/
const handleNodeRequests = (data, opts) => { const handleNodeRequests = (data, opts) => {
switch (opts.proxy.policy) { switch (opts.proxy.policy) {
case ProxyPolicy.ALWAYS: case ProxyPolicy.ALWAYS:
@ -104,13 +105,21 @@ const handleNodeRequests = (data, opts) => {
} }
} }
/**
* @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/
const createDefaultRequestPromise = (data, opts) => { const createDefaultRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fetcher[data.proof.request.fetcher] if (!(data.proof.request.protocol in fetcher)) {
reject(new Error(`fetcher for ${data.proof.request.protocol} not found`))
}
fetcher[data.proof.request.protocol]
.fn(data.proof.request.data, opts) .fn(data.proof.request.data, opts)
.then((res) => { .then((res) => {
return resolve({ return resolve({
fetcher: data.proof.request.fetcher, protocol: data.proof.request.protocol,
data, data,
viaProxy: false, viaProxy: false,
result: res result: res
@ -122,12 +131,17 @@ const createDefaultRequestPromise = (data, opts) => {
}) })
} }
/**
* @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/
const createProxyRequestPromise = (data, opts) => { const createProxyRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let proxyUrl let proxyUrl
try { try {
proxyUrl = generateProxyURL( proxyUrl = generateProxyURL(
data.proof.request.fetcher, data.proof.request.protocol,
data.proof.request.data, data.proof.request.data,
opts opts
) )
@ -138,13 +152,13 @@ const createProxyRequestPromise = (data, opts) => {
const requestData = { const requestData = {
url: proxyUrl, url: proxyUrl,
format: data.proof.request.format, format: data.proof.request.format,
fetcherTimeout: fetcher[data.proof.request.fetcher].timeout fetcherTimeout: fetcher[data.proof.request.protocol].timeout
} }
fetcher.http fetcher.http
.fn(requestData, opts) .fn(requestData, opts)
.then((res) => { .then((res) => {
return resolve({ return resolve({
fetcher: 'http', protocol: 'http',
data, data,
viaProxy: true, viaProxy: true,
result: res result: res
@ -156,6 +170,11 @@ const createProxyRequestPromise = (data, opts) => {
}) })
} }
/**
* @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/
const createFallbackRequestPromise = (data, opts) => { const createFallbackRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
createDefaultRequestPromise(data, opts) createDefaultRequestPromise(data, opts)

View file

@ -15,7 +15,7 @@ limitations under the License.
*/ */
import { readCleartextMessage, verify } from 'openpgp' import { readCleartextMessage, verify } from 'openpgp'
import { Claim } from './claim.js' import { Claim } from './claim.js'
import { fetchURI } from './keys.js' import { fetchURI } from './openpgp.js'
/** /**
* @module signatures * @module signatures
@ -89,7 +89,7 @@ export async function process (signature) {
if (sigKeys.length > 0) { if (sigKeys.length > 0) {
try { try {
result.key.uri = sigKeys[0] result.key.uri = sigKeys[0]
result.key.data = await fetchURI(result.key.uri) result.key.data = (await fetchURI(result.key.uri)).publicKey.key
result.key.fetchMethod = result.key.uri.split(':')[0] result.key.fetchMethod = result.key.uri.split(':')[0]
} catch (e) {} } catch (e) {}
} }
@ -97,7 +97,7 @@ export async function process (signature) {
if (!result.key.data && signersUserID) { if (!result.key.data && signersUserID) {
try { try {
result.key.uri = `wkd:${signersUserID}` result.key.uri = `wkd:${signersUserID}`
result.key.data = await fetchURI(result.key.uri) result.key.data = (await fetchURI(result.key.uri)).publicKey.key
result.key.fetchMethod = 'wkd' result.key.fetchMethod = 'wkd'
} catch (e) {} } catch (e) {}
} }
@ -106,7 +106,7 @@ export async function process (signature) {
try { try {
const match = preferredKeyServer.match(/^(.*:\/\/)?([^/]*)(?:\/)?$/i) const match = preferredKeyServer.match(/^(.*:\/\/)?([^/]*)(?:\/)?$/i)
result.key.uri = `hkp:${match[2]}:${issuerKeyID || signersUserID}` result.key.uri = `hkp:${match[2]}:${issuerKeyID || signersUserID}`
result.key.data = await fetchURI(result.key.uri) result.key.data = (await fetchURI(result.key.uri)).publicKey.key
result.key.fetchMethod = 'hkp' result.key.fetchMethod = 'hkp'
} catch (e) { } catch (e) {
throw new Error('Public key not found') throw new Error('Public key not found')

View file

@ -176,7 +176,7 @@ const containsProof = async (data, params) => {
/** /**
* @function * @function
* @param {any} proofData * @param {any} proofData
* @param {string} checkPath * @param {string[]} checkPath
* @param {object} params * @param {object} params
* @param {string} params.target * @param {string} params.target
* @param {string} params.claimFormat * @param {string} params.claimFormat
@ -231,9 +231,9 @@ const runJSON = async (proofData, checkPath, params) => {
/** /**
* Run the verification by finding the formatted fingerprint in the proof * Run the verification by finding the formatted fingerprint in the proof
* @async * @async
* @param {object} proofData - The proof data * @param {object} proofData - The proof data
* @param {object} claimData - The claim data * @param {import('./serviceProvider.js').ServiceProvider} claimData - The claim data
* @param {string} fingerprint - The fingerprint * @param {string} fingerprint - The fingerprint
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
export async function run (proofData, claimData, fingerprint) { export async function run (proofData, claimData, fingerprint) {
@ -243,10 +243,10 @@ export async function run (proofData, claimData, fingerprint) {
errors: [] errors: []
} }
switch (claimData.proof.request.format) { switch (claimData.proof.response.format) {
case ProofFormat.JSON: case ProofFormat.JSON:
for (let index = 0; index < claimData.claim.length; index++) { for (let index = 0; index < claimData.proof.target.length; index++) {
const claimMethod = claimData.claim[index] const claimMethod = claimData.proof.target[index]
try { try {
res.result = res.result || await runJSON( res.result = res.result || await runJSON(
proofData, proofData,
@ -265,8 +265,8 @@ export async function run (proofData, claimData, fingerprint) {
res.completed = true res.completed = true
break break
case ProofFormat.TEXT: case ProofFormat.TEXT:
for (let index = 0; index < claimData.claim.length; index++) { for (let index = 0; index < claimData.proof.target.length; index++) {
const claimMethod = claimData.claim[index] const claimMethod = claimData.proof.target[index]
try { try {
res.result = res.result || await containsProof( res.result = res.result || await containsProof(
proofData, proofData,