forked from Mirrors/doipjs
feat: Add marker fetching logic
This commit is contained in:
parent
46cffbf056
commit
870a544550
5 changed files with 131 additions and 37 deletions
38
src/claim.js
38
src/claim.js
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
const validator = require('validator')
|
||||
const validUrl = require('valid-url')
|
||||
const mergeOptions = require('merge-options')
|
||||
const proofs = require('./proofs')
|
||||
const request = require('./request')
|
||||
const verifications = require('./verifications')
|
||||
const claimDefinitions = require('./claimDefinitions')
|
||||
const defaults = require('./defaults')
|
||||
|
@ -229,10 +229,44 @@ class Claim {
|
|||
|
||||
let verificationResult = null
|
||||
let proofData = null
|
||||
let markersData = null
|
||||
let proofFetchError
|
||||
|
||||
// Handle markers
|
||||
try {
|
||||
proofData = await proofs.fetch(claimData, opts)
|
||||
markersData = await request.fetchMarkers(claimData, opts)
|
||||
} catch (err) {
|
||||
proofFetchError = err
|
||||
}
|
||||
if (markersData) {
|
||||
let shouldSkipMatch = false
|
||||
markersData.forEach(marker => {
|
||||
// Skip marker if another was already proven false
|
||||
if (shouldSkipMatch) return
|
||||
|
||||
// Ignore markers that were rejected
|
||||
if (marker.status !== 'fulfilled') return
|
||||
|
||||
let endpointExists
|
||||
switch (marker.value.data.test.type) {
|
||||
case E.MarkerTestType.HTTP_ENDPOINT_MUST_EXIST:
|
||||
endpointExists = marker.value.result && !marker.value.error
|
||||
if ((endpointExists && marker.value.data.test.inverse) || (!(endpointExists || marker.value.data.test.inverse))) {
|
||||
shouldSkipMatch = true
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
if (shouldSkipMatch) continue
|
||||
}
|
||||
|
||||
// Handle proof
|
||||
try {
|
||||
proofData = await request.fetchProof(claimData, opts)
|
||||
} catch (err) {
|
||||
proofFetchError = err
|
||||
}
|
||||
|
|
15
src/enums.js
15
src/enums.js
|
@ -146,6 +146,20 @@ const ClaimStatus = {
|
|||
}
|
||||
Object.freeze(ClaimStatus)
|
||||
|
||||
/**
|
||||
* How to test a marker
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
const MarkerTestType = {
|
||||
/** HTTP endpoint must exist */
|
||||
HTTP_ENDPOINT_MUST_EXIST: 'httpEndpointMustExist'
|
||||
// TODO Implement JSON_CONTAINS
|
||||
// /** JSON data must contain a certain string */
|
||||
// JSON_CONTAINS: 'jsonContains'
|
||||
}
|
||||
Object.freeze(MarkerTestType)
|
||||
|
||||
exports.ProxyPolicy = ProxyPolicy
|
||||
exports.Fetcher = Fetcher
|
||||
exports.EntityEncodingFormat = EntityEncodingFormat
|
||||
|
@ -154,3 +168,4 @@ exports.ProofFormat = ProofFormat
|
|||
exports.ClaimFormat = ClaimFormat
|
||||
exports.ClaimRelation = ClaimRelation
|
||||
exports.ClaimStatus = ClaimStatus
|
||||
exports.MarkerTestType = MarkerTestType
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
const Claim = require('./claim')
|
||||
const claimDefinitions = require('./claimDefinitions')
|
||||
const proofs = require('./proofs')
|
||||
const request = require('./request')
|
||||
const keys = require('./keys')
|
||||
const signatures = require('./signatures')
|
||||
const enums = require('./enums')
|
||||
|
@ -26,7 +26,7 @@ const fetcher = require('./fetcher')
|
|||
|
||||
exports.Claim = Claim
|
||||
exports.claimDefinitions = claimDefinitions
|
||||
exports.proofs = proofs
|
||||
exports.request = request
|
||||
exports.keys = keys
|
||||
exports.signatures = signatures
|
||||
exports.enums = enums
|
||||
|
|
|
@ -19,7 +19,7 @@ const utils = require('./utils')
|
|||
const E = require('./enums')
|
||||
|
||||
/**
|
||||
* @module proofs
|
||||
* @module request
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ const E = require('./enums')
|
|||
* @param {object} opts - Options to enable the request
|
||||
* @returns {Promise<object|string>}
|
||||
*/
|
||||
const fetch = (data, opts) => {
|
||||
const fetchProof = (data, opts) => {
|
||||
switch (data.proof.request.fetcher) {
|
||||
case E.Fetcher.HTTP:
|
||||
data.proof.request.data.format = data.proof.request.format
|
||||
|
@ -44,22 +44,49 @@ const fetch = (data, opts) => {
|
|||
}
|
||||
|
||||
if (jsEnv.isNode) {
|
||||
return handleNodeRequests(data, opts)
|
||||
return handleNodeRequests(data.proof, opts, false)
|
||||
}
|
||||
|
||||
return handleBrowserRequests(data, opts)
|
||||
return handleBrowserRequests(data.proof, opts, false)
|
||||
}
|
||||
|
||||
const handleBrowserRequests = (data, opts) => {
|
||||
/**
|
||||
* Delegate the marker requests to the correct fetcher.
|
||||
* This method uses the current environment (browser/node), certain values from
|
||||
* the `data` parameter and the proxy policy set in the `opts` parameter to
|
||||
* choose the right approach to fetch the proof. An error will be thrown if no
|
||||
* approach is possible.
|
||||
* @async
|
||||
* @param {object} data - Data from a claim definition
|
||||
* @param {object} opts - Options to enable the request
|
||||
* @returns {Promise<Array<object>>}
|
||||
*/
|
||||
const fetchMarkers = async (data, opts) => {
|
||||
const promises = []
|
||||
|
||||
if (!(data.markers && data.markers.length > 0)) throw new Error('No markers found')
|
||||
|
||||
data.markers.forEach(marker => {
|
||||
if (jsEnv.isNode) {
|
||||
promises.push(handleNodeRequests(marker, opts, true))
|
||||
} else {
|
||||
promises.push(handleBrowserRequests(marker, opts, true))
|
||||
}
|
||||
})
|
||||
|
||||
return Promise.allSettled(promises)
|
||||
}
|
||||
|
||||
const handleBrowserRequests = (data, opts, alwaysResolve) => {
|
||||
switch (opts.proxy.policy) {
|
||||
case E.ProxyPolicy.ALWAYS:
|
||||
return createProxyRequestPromise(data, opts)
|
||||
return createProxyRequestPromise(data, opts, alwaysResolve)
|
||||
|
||||
case E.ProxyPolicy.NEVER:
|
||||
switch (data.proof.request.access) {
|
||||
switch (data.request.access) {
|
||||
case E.ProofAccess.GENERIC:
|
||||
case E.ProofAccess.GRANTED:
|
||||
return createDefaultRequestPromise(data, opts)
|
||||
return createDefaultRequestPromise(data, opts, alwaysResolve)
|
||||
case E.ProofAccess.NOCORS:
|
||||
case E.ProofAccess.SERVER:
|
||||
throw new Error(
|
||||
|
@ -70,15 +97,13 @@ const handleBrowserRequests = (data, opts) => {
|
|||
}
|
||||
|
||||
case E.ProxyPolicy.ADAPTIVE:
|
||||
switch (data.proof.request.access) {
|
||||
switch (data.request.access) {
|
||||
case E.ProofAccess.GENERIC:
|
||||
return createFallbackRequestPromise(data, opts)
|
||||
case E.ProofAccess.NOCORS:
|
||||
return createProxyRequestPromise(data, opts)
|
||||
case E.ProofAccess.GRANTED:
|
||||
return createFallbackRequestPromise(data, opts)
|
||||
return createFallbackRequestPromise(data, opts, alwaysResolve)
|
||||
case E.ProofAccess.NOCORS:
|
||||
case E.ProofAccess.SERVER:
|
||||
return createProxyRequestPromise(data, opts)
|
||||
return createProxyRequestPromise(data, opts, alwaysResolve)
|
||||
default:
|
||||
throw new Error('Invalid proof access value')
|
||||
}
|
||||
|
@ -88,47 +113,56 @@ const handleBrowserRequests = (data, opts) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleNodeRequests = (data, opts) => {
|
||||
const handleNodeRequests = (data, opts, alwaysResolve) => {
|
||||
switch (opts.proxy.policy) {
|
||||
case E.ProxyPolicy.ALWAYS:
|
||||
return createProxyRequestPromise(data, opts)
|
||||
return createProxyRequestPromise(data, opts, alwaysResolve)
|
||||
|
||||
case E.ProxyPolicy.NEVER:
|
||||
return createDefaultRequestPromise(data, opts)
|
||||
return createDefaultRequestPromise(data, opts, alwaysResolve)
|
||||
|
||||
case E.ProxyPolicy.ADAPTIVE:
|
||||
return createFallbackRequestPromise(data, opts)
|
||||
return createFallbackRequestPromise(data, opts, alwaysResolve)
|
||||
|
||||
default:
|
||||
throw new Error('Invalid proxy policy')
|
||||
}
|
||||
}
|
||||
|
||||
const createDefaultRequestPromise = (data, opts) => {
|
||||
const createDefaultRequestPromise = (data, opts, alwaysResolve) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetcher[data.proof.request.fetcher]
|
||||
.fn(data.proof.request.data, opts)
|
||||
fetcher[data.request.fetcher]
|
||||
.fn(data.request.data, opts)
|
||||
.then((res) => {
|
||||
return resolve({
|
||||
fetcher: data.proof.request.fetcher,
|
||||
fetcher: data.request.fetcher,
|
||||
data: data,
|
||||
viaProxy: false,
|
||||
result: res
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
if (alwaysResolve) {
|
||||
return resolve({
|
||||
fetcher: 'http',
|
||||
data: data,
|
||||
viaProxy: true,
|
||||
error: err
|
||||
})
|
||||
} else {
|
||||
return reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const createProxyRequestPromise = (data, opts) => {
|
||||
const createProxyRequestPromise = (data, opts, alwaysResolve) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let proxyUrl
|
||||
try {
|
||||
proxyUrl = utils.generateProxyURL(
|
||||
data.proof.request.fetcher,
|
||||
data.proof.request.data,
|
||||
data.request.fetcher,
|
||||
data.request.data,
|
||||
opts
|
||||
)
|
||||
} catch (err) {
|
||||
|
@ -137,8 +171,8 @@ const createProxyRequestPromise = (data, opts) => {
|
|||
|
||||
const requestData = {
|
||||
url: proxyUrl,
|
||||
format: data.proof.request.format,
|
||||
fetcherTimeout: fetcher[data.proof.request.fetcher].timeout
|
||||
format: data.request.format,
|
||||
fetcherTimeout: fetcher[data.request.fetcher].timeout
|
||||
}
|
||||
fetcher.http
|
||||
.fn(requestData, opts)
|
||||
|
@ -151,19 +185,28 @@ const createProxyRequestPromise = (data, opts) => {
|
|||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
if (alwaysResolve) {
|
||||
return resolve({
|
||||
fetcher: 'http',
|
||||
data: data,
|
||||
viaProxy: true,
|
||||
error: err
|
||||
})
|
||||
} else {
|
||||
return reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const createFallbackRequestPromise = (data, opts) => {
|
||||
const createFallbackRequestPromise = (data, opts, alwaysResolve) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
createDefaultRequestPromise(data, opts)
|
||||
createDefaultRequestPromise(data, opts, alwaysResolve)
|
||||
.then((res) => {
|
||||
return resolve(res)
|
||||
})
|
||||
.catch((err1) => {
|
||||
createProxyRequestPromise(data, opts)
|
||||
createProxyRequestPromise(data, opts, alwaysResolve)
|
||||
.then((res) => {
|
||||
return resolve(res)
|
||||
})
|
||||
|
@ -174,4 +217,5 @@ const createFallbackRequestPromise = (data, opts) => {
|
|||
})
|
||||
}
|
||||
|
||||
exports.fetch = fetch
|
||||
exports.fetchProof = fetchProof
|
||||
exports.fetchMarkers = fetchMarkers
|
|
@ -38,6 +38,7 @@ const pattern = {
|
|||
return _.isString(x) || _.isNull(x)
|
||||
},
|
||||
},
|
||||
markers: _.isArray,
|
||||
proof: {
|
||||
uri: (x) => {
|
||||
return _.isString(x) || _.isNull(x)
|
||||
|
|
Loading…
Reference in a new issue