Release 0.7.0

This commit is contained in:
Yarmo Mackenbach 2020-12-05 23:17:54 +01:00
parent f5e1c07be2
commit 514ba3c4b4
7 changed files with 169 additions and 128 deletions

View file

@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.7.0] - 2020-12-05
### Changed
- Properly reject promises
## [0.6.0] - 2020-11-20 ## [0.6.0] - 2020-11-20
### Changed ### Changed
- Handle multiple users in key - Handle multiple users in key

224
dist/doip.js vendored
View file

@ -1193,7 +1193,7 @@ process.umask = function() { return 0; };
},{}],9:[function(require,module,exports){ },{}],9:[function(require,module,exports){
module.exports={ module.exports={
"name": "doipjs", "name": "doipjs",
"version": "0.5.1", "version": "0.6.0",
"description": "Decentralized OpenPGP Identity Proofs library in Node.js", "description": "Decentralized OpenPGP Identity Proofs library in Node.js",
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
@ -1259,7 +1259,11 @@ limitations under the License.
const path = require('path') const path = require('path')
const mergeOptions = require('merge-options') const mergeOptions = require('merge-options')
const validUrl = require('valid-url') const validUrl = require('valid-url')
const openpgp = require(path.join(require.resolve('openpgp'), '..', 'openpgp.min.js')) const openpgp = require(path.join(
require.resolve('openpgp'),
'..',
'openpgp.min.js'
))
const serviceproviders = require('./serviceproviders') const serviceproviders = require('./serviceproviders')
const keys = require('./keys') const keys = require('./keys')
const utils = require('./utils') const utils = require('./utils')
@ -1288,15 +1292,12 @@ const runVerificationJson = (
switch (checkRelation) { switch (checkRelation) {
default: default:
case 'contains': case 'contains':
re = new RegExp( re = new RegExp(checkClaim, 'gi')
checkClaim.replace('[', '\\[').replace(']', '\\]'), res.isVerified = re.test(proofData.replace(/\r?\n|\r|\\/g, ''))
'gi'
)
res.isVerified = re.test(proofData.replace(/\r?\n|\r/, ''))
break break
case 'equals': case 'equals':
res.isVerified = res.isVerified =
proofData.replace(/\r?\n|\r/, '').toLowerCase() == proofData.replace(/\r?\n|\r|\\/g, '').toLowerCase() ==
checkClaim.toLowerCase() checkClaim.toLowerCase()
break break
case 'oneOf': case 'oneOf':
@ -1354,9 +1355,24 @@ const runVerification = (proofData, spData) => {
const verify = async (input, fingerprint, opts) => { const verify = async (input, fingerprint, opts) => {
if (input instanceof openpgp.key.Key) { if (input instanceof openpgp.key.Key) {
const fingerprintLocal = await keys.getFingerprint(input) const fingerprintFromKey = await keys.getFingerprint(input)
const claims = await keys.getClaims(input) const userData = await keys.getUserData(input)
return await verify(claims, fingerprintLocal, opts)
const promises = userData.map(async (user, i) => {
return new Promise(async (resolve, reject) => {
try {
const res = await verify(user.notations, fingerprintFromKey, opts)
resolve(res)
} catch (e) {
console.error(`Claim verification failed: ${user.userData.id}`, e)
reject(e)
}
})
})
return Promise.all(promises).then((values) => {
return values
})
} }
if (input instanceof Array) { if (input instanceof Array) {
const promises = input.map(async (uri, i) => { const promises = input.map(async (uri, i) => {
@ -1390,7 +1406,7 @@ const verify = async (input, fingerprint, opts) => {
opts = mergeOptions(defaultOpts, opts ? opts : {}) opts = mergeOptions(defaultOpts, opts ? opts : {})
if (!validUrl.isUri(uri)) { if (!validUrl.isUri(uri)) {
throw new Error('Not a valid URI') throw new Error('Invalid URI')
} }
const spMatches = serviceproviders.match(uri, opts) const spMatches = serviceproviders.match(uri, opts)
@ -1493,11 +1509,15 @@ const path = require('path')
const bent = require('bent') const bent = require('bent')
const req = bent('GET') const req = bent('GET')
const validUrl = require('valid-url') const validUrl = require('valid-url')
const openpgp = require(path.join(require.resolve('openpgp'), '..', 'openpgp.min.js')) const openpgp = require(path.join(
require.resolve('openpgp'),
'..',
'openpgp.min.js'
))
const mergeOptions = require('merge-options') const mergeOptions = require('merge-options')
const fetchHKP = async (identifier, keyserverBaseUrl) => { const fetchHKP = (identifier, keyserverBaseUrl) => {
try { return new Promise(async (resolve, reject) => {
keyserverBaseUrl = keyserverBaseUrl keyserverBaseUrl = keyserverBaseUrl
? keyserverBaseUrl ? keyserverBaseUrl
: 'https://keys.openpgp.org/' : 'https://keys.openpgp.org/'
@ -1509,64 +1529,64 @@ const fetchHKP = async (identifier, keyserverBaseUrl) => {
let publicKey = await hkp.lookup(lookupOpts) let publicKey = await hkp.lookup(lookupOpts)
publicKey = (await openpgp.key.readArmored(publicKey)).keys[0] publicKey = (await openpgp.key.readArmored(publicKey)).keys[0]
return publicKey if (publicKey == undefined) {
} catch (e) { reject('Key does not exist or could not be fetched')
console.error(e)
return undefined
}
} }
const fetchWKD = async (identifier) => { resolve(publicKey)
try { })
}
const fetchWKD = (identifier) => {
return new Promise(async (resolve, reject) => {
const wkd = new openpgp.WKD() const wkd = new openpgp.WKD()
const lookupOpts = { const lookupOpts = {
email: identifier, email: identifier,
} }
const publicKey = (await wkd.lookup(lookupOpts)).keys[0] const publicKey = (await wkd.lookup(lookupOpts)).keys[0]
return publicKey if (publicKey == undefined) {
} catch (e) { reject('Key does not exist or could not be fetched')
console.error(e)
return undefined
}
} }
const fetchKeybase = async (username, fingerprint) => { resolve(publicKey)
try { })
}
const fetchKeybase = (username, fingerprint) => {
return new Promise(async (resolve, reject) => {
const keyLink = `https://keybase.io/${username}/pgp_keys.asc?fingerprint=${fingerprint}` const keyLink = `https://keybase.io/${username}/pgp_keys.asc?fingerprint=${fingerprint}`
try { try {
const rawKeyContent = await req(opts.keyLink) const rawKeyContent = await req(opts.keyLink)
.then(function (response) { .then((response) => {
if (response.status === 200) { if (response.status === 200) {
return response return response
} }
}) })
.then((response) => response.text()) .then((response) => response.text())
} catch (e) { } catch (e) {
return undefined reject(`Error fetching Keybase key: ${e.message}`)
} }
const publicKey = (await openpgp.key.readArmored(rawKeyContent)).keys[0] const publicKey = (await openpgp.key.readArmored(rawKeyContent)).keys[0]
return publicKey if (publicKey == undefined) {
} catch (e) { reject('Key does not exist or could not be fetched')
console.error(e)
return undefined
}
} }
const fetchPlaintext = async (rawKeyContent) => { resolve(publicKey)
try { })
}
const fetchPlaintext = (rawKeyContent) => {
return new Promise(async (resolve, reject) => {
const publicKey = (await openpgp.key.readArmored(rawKeyContent)).keys[0] const publicKey = (await openpgp.key.readArmored(rawKeyContent)).keys[0]
return publicKey resolve(publicKey)
} catch (e) { })
console.error(e)
return undefined
}
} }
const fetchSignature = async (rawSignatureContent, keyserverBaseUrl) => { const fetchSignature = (rawSignatureContent, keyserverBaseUrl) => {
try { return new Promise(async (resolve, reject) => {
let sig = await openpgp.signature.readArmored(rawSignatureContent) let sig = await openpgp.signature.readArmored(rawSignatureContent)
if ('compressed' in sig.packets[0]) { if ('compressed' in sig.packets[0]) {
sig = sig.packets[0] sig = sig.packets[0]
@ -1577,88 +1597,94 @@ const fetchSignature = async (rawSignatureContent, keyserverBaseUrl) => {
const sigUserId = sig.packets[0].signersUserId const sigUserId = sig.packets[0].signersUserId
const sigKeyId = await sig.packets[0].issuerKeyId.toHex() const sigKeyId = await sig.packets[0].issuerKeyId.toHex()
return fetchHKP(sigUserId ? sigUserId : sigKeyId, keyserverBaseUrl) resolve(fetchHKP(sigUserId ? sigUserId : sigKeyId, keyserverBaseUrl))
} catch (e) { })
console.error(e)
return undefined
}
} }
const fetchURI = async (uri) => { const fetchURI = (uri) => {
try { return new Promise(async (resolve, reject) => {
if (!validUrl.isUri(uri)) { if (!validUrl.isUri(uri)) {
throw new Error('Invalid URI') reject('Invalid URI')
} }
const re = /([a-zA-Z0-9]*):([a-zA-Z0-9@._=+\-]*)(\:[a-zA-Z0-9@._=+\-]*)?/ const re = /([a-zA-Z0-9]*):([a-zA-Z0-9@._=+\-]*)(\:[a-zA-Z0-9@._=+\-]*)?/
const match = uri.match(re) const match = uri.match(re)
if (!match[1]) { if (!match[1]) {
throw new Error('Invalid URI') reject('Invalid URI')
} }
switch (match[1]) { switch (match[1]) {
case 'hkp': case 'hkp':
return fetchHKP(match[2], match.length >= 4 ? match[3] : null) resolve(fetchHKP(match[2], match.length >= 4 ? match[3] : null))
break break
case 'wkd': case 'wkd':
return fetchWKD(match[2]) resolve(fetchWKD(match[2]))
break break
case 'kb': case 'kb':
return fetchKeybase(match[2], match.length >= 4 ? match[3] : null) resolve(fetchKeybase(match[2], match.length >= 4 ? match[3] : null))
break break
default: default:
throw new Error('Invalid URI protocol') reject('Invalid URI protocol')
break break
} }
} catch (e) { })
console.error(e)
return undefined
}
} }
const process = async (publicKey) => { const process = (publicKey) => {
try { return new Promise(async (resolve, reject) => {
if (!publicKey) {
reject('Invalid public key')
}
const fingerprint = await publicKey.primaryKey.getFingerprint() const fingerprint = await publicKey.primaryKey.getFingerprint()
const user = await publicKey.getPrimaryUser() const primaryUser = await publicKey.getPrimaryUser()
const users = publicKey.users
let primaryUserIndex,
usersOutput = []
return { users.forEach((user, i) => {
fingerprint: fingerprint, usersOutput[i] = {
user: user, userData: {
} id: user.userId.userid,
} catch (e) { name: user.userId.name,
console.error(e) email: user.userId.email,
return undefined comment: user.userId.comment,
} isPrimary: primaryUser.index === i,
},
} }
const getClaims = async (publicKey) => { const notations = user.selfCertifications[0].rawNotations
try { usersOutput[i].notations = notations.map(
const keyData = await process(publicKey) ({ name, value, humanReadable }) => {
let notations = keyData.user.selfCertification.rawNotations
notations = notations.map(({ name, value, humanReadable }) => {
if (humanReadable && name === 'proof@metacode.biz') { if (humanReadable && name === 'proof@metacode.biz') {
return openpgp.util.decode_utf8(value) return openpgp.util.decode_utf8(value)
} }
}
)
}) })
return notations resolve({
} catch (e) { fingerprint: fingerprint,
console.error(e) users: usersOutput,
return undefined primaryUserIndex: primaryUser.index,
} })
})
} }
const getFingerprint = async (publicKey) => { const getUserData = (publicKey) => {
try { return new Promise(async (resolve, reject) => {
const keyData = await process(publicKey) const keyData = await process(publicKey)
return keyData.fingerprint resolve(keyData.users)
} catch (e) { })
console.error(e)
return undefined
} }
const getFingerprint = (publicKey) => {
return new Promise(async (resolve, reject) => {
const keyData = await process(publicKey)
resolve(keyData.fingerprint)
})
} }
exports.fetch = { exports.fetch = {
@ -1670,7 +1696,7 @@ exports.fetch = {
signature: fetchSignature, signature: fetchSignature,
} }
exports.process = process exports.process = process
exports.getClaims = getClaims exports.getUserData = getUserData
exports.getFingerprint = getFingerprint exports.getFingerprint = getFingerprint
},{"bent":1,"merge-options":5,"path":6,"valid-url":8}],13:[function(require,module,exports){ },{"bent":1,"merge-options":5,"path":6,"valid-url":8}],13:[function(require,module,exports){
@ -1741,7 +1767,8 @@ const match = (uri, opts) => {
return matches return matches
} }
const directRequestHandler = async (spData, opts) => { const directRequestHandler = (spData, opts) => {
return new Promise(async (resolve, reject) => {
const url = spData.proof.fetch ? spData.proof.fetch : spData.proof.uri const url = spData.proof.fetch ? spData.proof.fetch : spData.proof.uri
let res let res
@ -1751,19 +1778,21 @@ const directRequestHandler = async (spData, opts) => {
Accept: 'application/json', Accept: 'application/json',
'User-Agent': `doipjs/${require('../package.json').version}`, 'User-Agent': `doipjs/${require('../package.json').version}`,
}) })
return await res.json() resolve(await res.json())
break break
case 'text': case 'text':
res = await req(url) res = await req(url)
return await res.text() resolve(await res.text())
break break
default: default:
throw new Error('No specified proof data format') reject('No specified proof data format')
break break
} }
})
} }
const proxyRequestHandler = async (spData, opts) => { const proxyRequestHandler = (spData, opts) => {
return new Promise(async (resolve, reject) => {
const url = spData.proof.fetch ? spData.proof.fetch : spData.proof.uri const url = spData.proof.fetch ? spData.proof.fetch : spData.proof.uri
const res = await req( const res = await req(
utils.generateProxyURL(spData.proof.format, url, opts), utils.generateProxyURL(spData.proof.format, url, opts),
@ -1771,7 +1800,8 @@ const proxyRequestHandler = async (spData, opts) => {
{ Accept: 'application/json' } { Accept: 'application/json' }
) )
const json = await res.json() const json = await res.json()
return json.content resolve(json.content)
})
} }
exports.list = list exports.list = list

2
dist/doip.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
# doip.js <small>0.6.0</small> # doip.js <small>0.7.0</small>
<img src="doip.png" width="120"> <img src="doip.png" width="120">

View file

@ -1,5 +1,12 @@
# Changelog # Changelog
## [0.7.0]
[2020-12-05](https://codeberg.org/keyoxide/doipjs/releases/tag/0.7.0)
### Changed
- Properly reject promises
## [0.6.0] ## [0.6.0]
[2020-11-20](https://codeberg.org/keyoxide/doipjs/releases/tag/0.6.0) [2020-11-20](https://codeberg.org/keyoxide/doipjs/releases/tag/0.6.0)

View file

@ -15,7 +15,7 @@ npm install --save doipjs
Install on website by including the following HTML snippet: Install on website by including the following HTML snippet:
```html ```html
<script src="https://cdn.jsdelivr.net/npm/doipjs@0.6.0/dist/doip.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/doipjs@0.7.0/dist/doip.min.js"></script>
``` ```
Next step: [quick start (Node.js)](quickstart-nodejs.md) and [quick start (browser)](quickstart-browser.md) Next step: [quick start (Node.js)](quickstart-nodejs.md) and [quick start (browser)](quickstart-browser.md)

View file

@ -1,6 +1,6 @@
{ {
"name": "doipjs", "name": "doipjs",
"version": "0.6.0", "version": "0.7.0",
"description": "Decentralized OpenPGP Identity Proofs library in Node.js", "description": "Decentralized OpenPGP Identity Proofs library in Node.js",
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {