Add jsdoc documentation

This commit is contained in:
Yarmo Mackenbach 2021-04-22 15:14:21 +02:00
parent 7ae9d2f9b1
commit 1a463594dc
No known key found for this signature in database
GPG key ID: 37367F4AF4087AD1
20 changed files with 412 additions and 126 deletions

25
jsdoc-lib.json Normal file
View file

@ -0,0 +1,25 @@
{
"plugins": ["plugins/markdown"],
"source": {
"include": [
"./src",
"./README.md"
]
},
"recurseDepth": 2,
"templates": {
"default": {
"staticFiles": {
"include": [
"./static"
]
}
}
},
"opts": {
"template": "node_modules/docdash"
},
"docdash": {
"search": true
}
}

View file

@ -42,7 +42,7 @@
"license:check": "./node_modules/.bin/license-check-and-add check", "license:check": "./node_modules/.bin/license-check-and-add check",
"license:add": "./node_modules/.bin/license-check-and-add add", "license:add": "./node_modules/.bin/license-check-and-add add",
"license:remove": "./node_modules/.bin/license-check-and-add remove", "license:remove": "./node_modules/.bin/license-check-and-add remove",
"docs:lib": "./node_modules/.bin/jsdoc -c jsdoc-lib.json -d ./docs", "docs:lib": "./node_modules/.bin/jsdoc -c jsdoc-lib.json -r -d ./docs",
"test": "./node_modules/.bin/mocha", "test": "./node_modules/.bin/mocha",
"proxy": "NODE_ENV=production node ./src/proxy/", "proxy": "NODE_ENV=production node ./src/proxy/",
"proxy:dev": "NODE_ENV=development ./node_modules/.bin/nodemon ./src/proxy/" "proxy:dev": "NODE_ENV=development ./node_modules/.bin/nodemon ./src/proxy/"

View file

@ -23,20 +23,24 @@ const defaults = require('./defaults')
const E = require('./enums') const E = require('./enums')
/** /**
* OpenPGP-based identity claim
* @class * @class
* @property {String} uri - The claim's URI * @classdesc OpenPGP-based identity claim
* @property {String} uri - The claim's URI * @property {string} uri - The claim's URI
* @property {String} uri - The claim's URI * @property {string} fingerprint - The fingerprint to verify the claim against
* @property {String} uri - The claim's URI * @property {string} status - The current status of the claim
* @property {String} uri - The claim's URI * @property {Array<object>} matches - The claim definitions matched against the URI
* @property {object} result - The result of the verification process
*/ */
class Claim { class Claim {
/** /**
* Initialize a Claim object * Initialize a Claim object
* @constructor * @constructor
* @param {string} [uri] - The URI of the identity claim * @param {string} [uri] - The URI of the identity claim
* @param {string} [fingerprint] - The fingerprint of the OpenPGP key * @param {string} [fingerprint] - The fingerprint of the OpenPGP key
* @example
* const claim = doip.Claim();
* const claim = doip.Claim('dns:domain.tld?type=TXT');
* const claim = doip.Claim('dns:domain.tld?type=TXT', '123abc123abc');
*/ */
constructor(uri, fingerprint) { constructor(uri, fingerprint) {
// Import JSON // Import JSON
@ -45,7 +49,7 @@ class Claim {
case 1: case 1:
this._uri = data.uri this._uri = data.uri
this._fingerprint = data.fingerprint this._fingerprint = data.fingerprint
this._state = data.state this._status = data.status
this._dataMatches = data.dataMatches this._dataMatches = data.dataMatches
this._verification = data.verification this._verification = data.verification
break break
@ -61,6 +65,7 @@ class Claim {
if (uri && !validUrl.isUri(uri)) { if (uri && !validUrl.isUri(uri)) {
throw new Error('Invalid URI') throw new Error('Invalid URI')
} }
// Verify validity of fingerprint // Verify validity of fingerprint
if (fingerprint) { if (fingerprint) {
try { try {
@ -72,67 +77,39 @@ class Claim {
this._uri = uri ? uri : null this._uri = uri ? uri : null
this._fingerprint = fingerprint ? fingerprint : null this._fingerprint = fingerprint ? fingerprint : null
this._state = E.ClaimState.INIT this._status = E.ClaimStatus.INIT
this._dataMatches = null this._dataMatches = null
this._verification = null this._verification = null
} }
/**
* Get the claim's URI
*/
get uri() { get uri() {
return this._uri return this._uri
} }
/**
* Get the fingerprint the claim is supposed to acknowledge
* @function
* @returns {string}
*/
get fingerprint() { get fingerprint() {
return this._fingerprint return this._fingerprint
} }
/** get status() {
* Get the current state of the claim's verification process return this._status
* @function
* @returns {string}
*/
get state() {
return this._state
} }
/**
* Get the candidate claim definitions the URI matched against
* @function
* @returns {object}
*/
get matches() { get matches() {
if (this._state === E.ClaimState.INIT) { if (this._status === E.ClaimStatus.INIT) {
throw new Error('This claim has not yet been matched') throw new Error('This claim has not yet been matched')
} }
return this._dataMatches return this._dataMatches
} }
/**
* Get the result of the verification process
* @function
* @returns {object}
*/
get result() { get result() {
if (this._state !== E.ClaimState.VERIFIED) { if (this._status !== E.ClaimStatus.VERIFIED) {
throw new Error('This claim has not yet been verified') throw new Error('This claim has not yet been verified')
} }
return this._verification return this._verification
} }
/**
* Set the claim's URI
* @function
* @param {string} uri - The new claim URI
*/
set uri(uri) { set uri(uri) {
if (this._state !== E.ClaimState.INIT) { if (this._status !== E.ClaimStatus.INIT) {
throw new Error( throw new Error(
'Cannot change the URI, this claim has already been matched' 'Cannot change the URI, this claim has already been matched'
) )
@ -147,13 +124,8 @@ class Claim {
this._uri = uri this._uri = uri
} }
/**
* Set the claim's fingerprint to verify against
* @function
* @param {string} fingerprint - The new fingerprint
*/
set fingerprint(fingerprint) { set fingerprint(fingerprint) {
if (this._state === E.ClaimState.VERIFIED) { if (this._status === E.ClaimStatus.VERIFIED) {
throw new Error( throw new Error(
'Cannot change the fingerprint, this claim has already been verified' 'Cannot change the fingerprint, this claim has already been verified'
) )
@ -161,29 +133,14 @@ class Claim {
this._fingerprint = fingerprint this._fingerprint = fingerprint
} }
/** set status(anything) {
* Throw error when attempting to alter the state throw new Error("Cannot change a claim's status")
* @function
* @param {any} anything - Anything will throw an error
*/
set state(anything) {
throw new Error("Cannot change a claim's state")
} }
/**
* Throw error when attempting to alter the dataMatches
* @function
* @param {any} anything - Anything will throw an error
*/
set dataMatches(anything) { set dataMatches(anything) {
throw new Error("Cannot change a claim's dataMatches") throw new Error("Cannot change a claim's dataMatches")
} }
/**
* Throw error when attempting to alter the verification data
* @function
* @param {any} anything - Anything will throw an error
*/
set verification(anything) { set verification(anything) {
throw new Error("Cannot change a claim's verification data") throw new Error("Cannot change a claim's verification data")
} }
@ -193,7 +150,7 @@ class Claim {
* @function * @function
*/ */
match() { match() {
if (this._state !== E.ClaimState.INIT) { if (this._status !== E.ClaimStatus.INIT) {
throw new Error('This claim was already matched') throw new Error('This claim was already matched')
} }
if (this._uri === null) { if (this._uri === null) {
@ -224,7 +181,7 @@ class Claim {
return true return true
}) })
this._state = E.ClaimState.MATCHED this._status = E.ClaimStatus.MATCHED
} }
/** /**
@ -237,10 +194,10 @@ class Claim {
* @param {object} [opts] - Options for proxy, fetchers * @param {object} [opts] - Options for proxy, fetchers
*/ */
async verify(opts) { async verify(opts) {
if (this._state === E.ClaimState.INIT) { if (this._status === E.ClaimStatus.INIT) {
throw new Error('This claim has not yet been matched') throw new Error('This claim has not yet been matched')
} }
if (this._state === E.ClaimState.VERIFIED) { if (this._status === E.ClaimStatus.VERIFIED) {
throw new Error('This claim has already been verified') throw new Error('This claim has already been verified')
} }
if (this._fingerprint === null) { if (this._fingerprint === null) {
@ -298,18 +255,18 @@ class Claim {
} }
} }
this._state = E.ClaimState.VERIFIED this._status = E.ClaimStatus.VERIFIED
} }
/** /**
* Get the ambiguity of the claim. A claim is only unambiguous if any * Determine the ambiguity of the claim. A claim is only unambiguous if any
* of the candidates is unambiguous. An ambiguous claim should never be * of the candidates is unambiguous. An ambiguous claim should never be
* displayed in an user interface when its result is negative. * displayed in an user interface when its result is negative.
* @function * @function
* @returns {boolean} * @returns {boolean}
*/ */
isAmbiguous() { isAmbiguous() {
if (this._state === E.ClaimState.INIT) { if (this._status === E.ClaimStatus.INIT) {
throw new Error('The claim has not been matched yet') throw new Error('The claim has not been matched yet')
} }
if (this._dataMatches.length === 0) { if (this._dataMatches.length === 0) {
@ -331,7 +288,7 @@ class Claim {
claimVersion: 1, claimVersion: 1,
uri: this._uri, uri: this._uri,
fingerprint: this._fingerprint, fingerprint: this._fingerprint,
state: this._state, status: this._status,
dataMatches: this._dataMatches, dataMatches: this._dataMatches,
verification: this._verification, verification: this._verification,
} }

View file

@ -15,6 +15,30 @@ limitations under the License.
*/ */
const E = require('./enums') const E = require('./enums')
/**
* Contains default values
* @module defaults
*/
/**
* The default options used throughout the library
* @constant {object}
* @property {object} proxy - Options related to the proxy
* @property {string|null} proxy.hostname - The hostname of the proxy
* @property {string} proxy.policy - The policy that defines when to use a proxy ({@link module:enums~ProxyPolicy|here})
* @property {object} claims - Options related to claim verification
* @property {object} claims.irc - Options related to the verification of IRC claims
* @property {string|null} claims.irc.nick - The nick that the library uses to connect to the IRC server
* @property {object} claims.matrix - Options related to the verification of Matrix claims
* @property {string|null} claims.matrix.instance - The server hostname on which the library can log in
* @property {string|null} claims.matrix.accessToken - The access token required to identify the library ({@link https://www.matrix.org/docs/guides/client-server-api|Matrix docs})
* @property {object} claims.xmpp - Options related to the verification of XMPP claims
* @property {string|null} claims.xmpp.service - The server hostname on which the library can log in
* @property {string|null} claims.xmpp.username - The username used to log in
* @property {string|null} claims.xmpp.password - The password used to log in
* @property {object} claims.twitter - Options related to the verification of Twitter claims
* @property {string|null} claims.twitter.bearerToken - The Twitter API's bearer token ({@link https://developer.twitter.com/en/docs/authentication/oauth-2-0/bearer-tokens|Twitter docs})
*/
const opts = { const opts = {
proxy: { proxy: {
hostname: null, hostname: null,

View file

@ -13,66 +13,123 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
/**
* Contains enums
* @module enums
*/
/**
* The proxy policy that decides how to fetch a proof
* @readonly
* @enum {string}
*/
const ProxyPolicy = { const ProxyPolicy = {
/** Proxy usage decision depends on environment and service provider */
ADAPTIVE: 'adaptive', ADAPTIVE: 'adaptive',
/** Always use a proxy */
ALWAYS: 'always', ALWAYS: 'always',
/** Never use a proxy, skip a verification if a proxy is inevitable */
NEVER: 'never', NEVER: 'never',
} }
Object.freeze(ProxyPolicy) Object.freeze(ProxyPolicy)
/**
* Methods for fetching proofs
* @readonly
* @enum {string}
*/
const Fetcher = { const Fetcher = {
/** Basic HTTP requests */
HTTP: 'http', HTTP: 'http',
/** DNS module from Node.js */
DNS: 'dns', DNS: 'dns',
/** IRC module from Node.js */
IRC: 'irc', IRC: 'irc',
/** XMPP module from Node.js */
XMPP: 'xmpp', XMPP: 'xmpp',
/** HTTP request to Matrix API */
MATRIX: 'matrix', MATRIX: 'matrix',
/** HTTP request to Gitlab API */
GITLAB: 'gitlab', GITLAB: 'gitlab',
/** HTTP request to Twitter API */
TWITTER: 'twitter', TWITTER: 'twitter',
} }
Object.freeze(Fetcher) Object.freeze(Fetcher)
/**
* Levels of access restriction for proof fetching
* @readonly
* @enum {number}
*/
const ProofAccess = { const ProofAccess = {
/** Any HTTP request will work */
GENERIC: 0, GENERIC: 0,
/** CORS requests are denied */
NOCORS: 1, NOCORS: 1,
/** HTTP requests must contain API or access tokens */
GRANTED: 2, GRANTED: 2,
/** Not accessible by HTTP request, needs server software */
SERVER: 3, SERVER: 3,
} }
Object.freeze(ProofAccess) Object.freeze(ProofAccess)
/**
* Format of proof
* @readonly
* @enum {string}
*/
const ProofFormat = { const ProofFormat = {
/** JSON format */
JSON: 'json', JSON: 'json',
/** Plaintext format */
TEXT: 'text', TEXT: 'text',
} }
Object.freeze(ProofFormat) Object.freeze(ProofFormat)
/**
* Format of claim
* @readonly
* @enum {number}
*/
const ClaimFormat = { const ClaimFormat = {
/** `openpgp4fpr:123123123` */
URI: 0, URI: 0,
/** `123123123` */
FINGERPRINT: 1, FINGERPRINT: 1,
/** `[Verifying my OpenPGP key: openpgp4fpr:123123123]` */
MESSAGE: 2, MESSAGE: 2,
} }
Object.freeze(ClaimFormat) Object.freeze(ClaimFormat)
/**
* How to find the claim inside the proof's JSON data
* @readonly
* @enum {number}
*/
const ClaimRelation = { const ClaimRelation = {
/** Claim is somewhere in the JSON field's textual content */
CONTAINS: 0, CONTAINS: 0,
/** Claim is equal to the JSON field's textual content */
EQUALS: 1, EQUALS: 1,
/** Claim is equal to an element of the JSON field's array of strings */
ONEOF: 2, ONEOF: 2,
} }
Object.freeze(ClaimRelation) Object.freeze(ClaimRelation)
const VerificationStatus = { /**
INIT: 0, * Status of the Claim instance
INPROGRESS: 1, * @readonly
FAILED: 2, * @enum {string}
COMPLETED: 3, */
} const ClaimStatus = {
Object.freeze(VerificationStatus) /** Claim has been initialized */
const ClaimState = {
INIT: 'init', INIT: 'init',
/** Claim has matched its URI to candidate claim definitions */
MATCHED: 'matched', MATCHED: 'matched',
/** Claim has verified one or multiple candidate claim definitions */
VERIFIED: 'verified', VERIFIED: 'verified',
} }
Object.freeze(ClaimState) Object.freeze(ClaimStatus)
exports.ProxyPolicy = ProxyPolicy exports.ProxyPolicy = ProxyPolicy
exports.Fetcher = Fetcher exports.Fetcher = Fetcher
@ -80,5 +137,4 @@ exports.ProofAccess = ProofAccess
exports.ProofFormat = ProofFormat exports.ProofFormat = ProofFormat
exports.ClaimFormat = ClaimFormat exports.ClaimFormat = ClaimFormat
exports.ClaimRelation = ClaimRelation exports.ClaimRelation = ClaimRelation
exports.VerificationStatus = VerificationStatus exports.ClaimStatus = ClaimStatus
exports.ClaimState = ClaimState

View file

@ -15,8 +15,24 @@ limitations under the License.
*/ */
const dns = require('dns') const dns = require('dns')
/**
* @module fetcher/dns
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000 module.exports.timeout = 5000
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.domain - The targeted domain
* @returns {object}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {

View file

@ -16,8 +16,25 @@ limitations under the License.
const bent = require('bent') const bent = require('bent')
const req = bent('GET') const req = bent('GET')
/**
* @module fetcher/gitlab
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000 module.exports.timeout = 5000
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.username - The username of the targeted account
* @param {string} data.domain - The domain on which the targeted account is registered
* @returns {object}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
@ -45,7 +62,7 @@ module.exports.fn = async (data, opts) => {
const project = jsonProject.find((proj) => proj.path === 'gitlab_proof') const project = jsonProject.find((proj) => proj.path === 'gitlab_proof')
if (!project) { if (!project) {
reject(`No project at ${spData.proof.uri}`) reject(`No project found`)
} }
resolve(project) resolve(project)

View file

@ -17,8 +17,25 @@ const bent = require('bent')
const req = bent('GET') const req = bent('GET')
const E = require('../enums') const E = require('../enums')
/**
* @module fetcher/http
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000 module.exports.timeout = 5000
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.url - The URL pointing at targeted content
* @param {string} data.format - The format of the targeted content
* @returns {object|string}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {

View file

@ -13,10 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
exports.dns = require('./dns') exports.dns = require('./dns')
exports.gitlab = require('./gitlab') exports.gitlab = require('./gitlab')
exports.http = require('./http') exports.http = require('./http')
exports.irc = require('./irc') exports.irc = require('./irc')
exports.matrix = require('./matrix') exports.matrix = require('./matrix')
exports.twitter = require('./twitter') exports.twitter = require('./twitter')
exports.xmpp = require('./xmpp') exports.xmpp = require('./xmpp')

View file

@ -16,8 +16,27 @@ limitations under the License.
const irc = require('irc-upd') const irc = require('irc-upd')
const validator = require('validator') const validator = require('validator')
/**
* @module fetcher/irc
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 20000 module.exports.timeout = 20000
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.nick - The nick of the targeted account
* @param {string} data.domain - The domain on which the targeted account is registered
* @param {object} opts - Options used to enable the request
* @param {string} opts.claims.irc.nick - The nick to be used by the library to log in
* @returns {object}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {

View file

@ -17,8 +17,28 @@ const bent = require('bent')
const bentReq = bent('GET') const bentReq = bent('GET')
const validator = require('validator') const validator = require('validator')
/**
* @module fetcher/matrix
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000 module.exports.timeout = 5000
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.eventId - The identifier of the targeted post
* @param {string} data.roomId - The identifier of the room containing the targeted post
* @param {object} opts - Options used to enable the request
* @param {string} opts.claims.matrix.instance - The server hostname on which the library can log in
* @param {string} opts.claims.matrix.accessToken - The access token required to identify the library ({@link https://www.matrix.org/docs/guides/client-server-api|Matrix docs})
* @returns {object}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {

View file

@ -17,8 +17,26 @@ const bent = require('bent')
const bentReq = bent('GET') const bentReq = bent('GET')
const validator = require('validator') const validator = require('validator')
/**
* @module fetcher/twitter
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000 module.exports.timeout = 5000
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {number|string} data.tweetId - Identifier of the tweet
* @param {object} opts - Options used to enable the request
* @param {string} opts.claims.twitter.bearerToken - The Twitter API's bearer token
* @returns {object}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {

View file

@ -18,6 +18,14 @@ const { client, xml } = require('@xmpp/client')
const debug = require('@xmpp/debug') const debug = require('@xmpp/debug')
const validator = require('validator') const validator = require('validator')
/**
* @module fetcher/xmpp
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000 module.exports.timeout = 5000
let xmpp = null, let xmpp = null,
@ -44,6 +52,19 @@ const xmppStart = async (service, username, password) => {
}) })
} }
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.id - The identifier of the targeted account
* @param {string} data.field - The vCard field to return (should be "note")
* @param {object} opts - Options used to enable the request
* @param {string} opts.claims.xmpp.service - The server hostname on which the library can log in
* @param {string} opts.claims.xmpp.username - The username used to log in
* @param {string} opts.claims.xmpp.password - The password used to log in
* @returns {object}
*/
module.exports.fn = async (data, opts) => { module.exports.fn = async (data, opts) => {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {

View file

@ -16,7 +16,6 @@ limitations under the License.
const Claim = require('./claim') const Claim = require('./claim')
const claimDefinitions = require('./claimDefinitions') const claimDefinitions = require('./claimDefinitions')
const proofs = require('./proofs') const proofs = require('./proofs')
const verifications = require('./verifications')
const keys = require('./keys') const keys = require('./keys')
const signatures = require('./signatures') const signatures = require('./signatures')
const enums = require('./enums') const enums = require('./enums')
@ -26,7 +25,6 @@ const utils = require('./utils')
exports.Claim = Claim exports.Claim = Claim
exports.claimDefinitions = claimDefinitions exports.claimDefinitions = claimDefinitions
exports.proofs = proofs exports.proofs = proofs
exports.verifications = verifications
exports.keys = keys exports.keys = keys
exports.signatures = signatures exports.signatures = signatures
exports.enums = enums exports.enums = enums

View file

@ -19,10 +19,25 @@ const validUrl = require('valid-url')
const openpgp = require('openpgp') const openpgp = require('openpgp')
const Claim = require('./claim') const Claim = require('./claim')
const fetchHKP = (identifier, keyserverBaseUrl) => { /**
* Functions related to the fetching and handling of keys
* @module keys
*/
/**
* Fetch a public key using keyservers
* @function
* @param {string} identifier - Fingerprint or email address
* @param {string} [keyserverDomain=keys.openpgp.org] - Domain of the keyserver
* @returns {openpgp.key.Key}
* @example
* const key1 = doip.keys.fetchHKP('alice@domain.tld');
* const key2 = doip.keys.fetchHKP('123abc123abc');
*/
exports.fetchHKP = (identifier, keyserverDomain) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
keyserverBaseUrl = keyserverBaseUrl const keyserverBaseUrl = keyserverDomain
? `https://${keyserverBaseUrl}` ? `https://${keyserverDomain}`
: 'https://keys.openpgp.org' : 'https://keys.openpgp.org'
const hkp = new openpgp.HKP(keyserverBaseUrl) const hkp = new openpgp.HKP(keyserverBaseUrl)
@ -51,7 +66,15 @@ const fetchHKP = (identifier, keyserverBaseUrl) => {
}) })
} }
const fetchWKD = (identifier) => { /**
* Fetch a public key using Web Key Directory
* @function
* @param {string} identifier - Identifier of format 'username@domain.tld`
* @returns {openpgp.key.Key}
* @example
* const key = doip.keys.fetchWKD('alice@domain.tld');
*/
exports.fetchWKD = (identifier) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const wkd = new openpgp.WKD() const wkd = new openpgp.WKD()
const lookupOpts = { const lookupOpts = {
@ -75,7 +98,16 @@ const fetchWKD = (identifier) => {
}) })
} }
const fetchKeybase = (username, fingerprint) => { /**
* Fetch a public key from Keybase
* @function
* @param {string} username - Keybase username
* @param {string} fingerprint - Fingerprint of key
* @returns {openpgp.key.Key}
* @example
* const key = doip.keys.fetchKeybase('alice', '123abc123abc');
*/
exports.fetchKeybase = (username, fingerprint) => {
return new Promise(async (resolve, reject) => { 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 {
@ -107,7 +139,21 @@ const fetchKeybase = (username, fingerprint) => {
}) })
} }
const fetchPlaintext = (rawKeyContent) => { /**
* Get a public key from plaintext data
* @function
* @param {string} rawKeyContent - Plaintext ASCII-formatted public key data
* @returns {openpgp.key.Key}
* @example
* const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
*
* mQINBF0mIsIBEADacleiyiV+z6FIunvLWrO6ZETxGNVpqM+WbBQKdW1BVrJBBolg
* [...]
* =6lib
* -----END PGP PUBLIC KEY BLOCK-----`
* const key = doip.keys.fetchPlaintext(plainkey);
*/
exports.fetchPlaintext = (rawKeyContent) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const publicKey = (await openpgp.key.readArmored(rawKeyContent)).keys[0] const publicKey = (await openpgp.key.readArmored(rawKeyContent)).keys[0]
@ -115,23 +161,17 @@ const fetchPlaintext = (rawKeyContent) => {
}) })
} }
const fetchSignature = (rawSignatureContent, keyserverBaseUrl) => { /**
return new Promise(async (resolve, reject) => { * Fetch a public key using an URI
let sig = await openpgp.signature.readArmored(rawSignatureContent) * @function
if ('compressed' in sig.packets[0]) { * @param {string} uri - URI that defines the location of the key
sig = sig.packets[0] * @returns {openpgp.key.Key}
let sigContent = await openpgp.stream.readToEnd( * @example
await sig.packets[1].getText() * const key1 = doip.keys.fetchURI('hkp:alice@domain.tld');
) * const key2 = doip.keys.fetchURI('hkp:123abc123abc');
} * const key3 = doip.keys.fetchURI('wkd:alice@domain.tld');
const sigUserId = sig.packets[0].signersUserId */
const sigKeyId = await sig.packets[0].issuerKeyId.toHex() exports.fetchURI = (uri) => {
resolve(fetchHKP(sigUserId ? sigUserId : sigKeyId, keyserverBaseUrl))
})
}
const fetchURI = (uri) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (!validUrl.isUri(uri)) { if (!validUrl.isUri(uri)) {
reject('Invalid URI') reject('Invalid URI')
@ -163,7 +203,19 @@ const fetchURI = (uri) => {
}) })
} }
const process = (publicKey) => { /**
* Process a public key to get user data and claims
* @function
* @param {openpgp.key.Key} publicKey - The public key to process
* @returns {object}
* @example
* const key = doip.keys.fetchURI('hkp:alice@domain.tld');
* const data = doip.keys.process(key);
* data.users[0].claims.forEach(claim => {
* console.log(claim.uri);
* });
*/
exports.process = (publicKey) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
if (!publicKey || !(publicKey instanceof openpgp.key.Key)) { if (!publicKey || !(publicKey instanceof openpgp.key.Key)) {
reject('Invalid public key') reject('Invalid public key')
@ -210,14 +262,4 @@ const process = (publicKey) => {
}, },
}) })
}) })
} }
exports.fetch = {
uri: fetchURI,
hkp: fetchHKP,
wkd: fetchWKD,
keybase: fetchKeybase,
plaintext: fetchPlaintext,
signature: fetchSignature,
}
exports.process = process

View file

@ -18,6 +18,21 @@ const fetcher = require('./fetcher')
const utils = require('./utils') const utils = require('./utils')
const E = require('./enums') const E = require('./enums')
/**
* @module proofs
*/
/**
* Delegate the proof request 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<object|string>}
*/
const fetch = (data, opts) => { const fetch = (data, opts) => {
switch (data.proof.request.fetcher) { switch (data.proof.request.fetcher) {
case E.Fetcher.HTTP: case E.Fetcher.HTTP:

View file

@ -17,6 +17,16 @@ const openpgp = require('openpgp')
const Claim = require('./claim') const Claim = require('./claim')
const keys = require('./keys') const keys = require('./keys')
/**
* @module signatures
*/
/**
* Extract data from a signature and fetch the associated key
* @async
* @param {string} signature - The plaintext signature to process
* @returns {Promise<object>}
*/
const process = (signature) => { const process = (signature) => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let sigData, let sigData,

View file

@ -16,6 +16,18 @@ limitations under the License.
const validator = require('validator') const validator = require('validator')
const E = require('./enums') const E = require('./enums')
/**
* @module utils
*/
/**
* Generate an URL to request data from a proxy server
* @param {string} type - The name of the fetcher the proxy must use
* @param {object} data - The data the proxy must provide to the fetcher
* @param {object} opts - Options to enable the request
* @param {object} opts.proxy.hostname - The hostname of the proxy server
* @returns {string}
*/
const generateProxyURL = (type, data, opts) => { const generateProxyURL = (type, data, opts) => {
try { try {
validator.isFQDN(opts.proxy.hostname) validator.isFQDN(opts.proxy.hostname)
@ -34,6 +46,12 @@ const generateProxyURL = (type, data, opts) => {
)}` )}`
} }
/**
* Generate the string that must be found in the proof to verify a claim
* @param {string} fingerprint - The fingerprint of the claim
* @param {number} format - The claim's format (see {@link module:enums~ClaimFormat|enums.ClaimFormat})
* @returns {string}
*/
const generateClaim = (fingerprint, format) => { const generateClaim = (fingerprint, format) => {
switch (format) { switch (format) {
case E.ClaimFormat.URI: case E.ClaimFormat.URI:

View file

@ -16,6 +16,11 @@ limitations under the License.
const utils = require('./utils') const utils = require('./utils')
const E = require('./enums') const E = require('./enums')
/**
* @module verifications
* @ignore
*/
const runJSON = (proofData, checkPath, checkClaim, checkRelation) => { const runJSON = (proofData, checkPath, checkClaim, checkRelation) => {
let re let re
@ -70,6 +75,13 @@ const runJSON = (proofData, checkPath, checkClaim, checkRelation) => {
) )
} }
/**
* Run the verification by finding the formatted fingerprint in the proof
* @param {object} proofData - The proof data
* @param {object} claimData - The claim data
* @param {string} fingerprint - The fingerprint
* @returns {object}
*/
const run = (proofData, claimData, fingerprint) => { const run = (proofData, claimData, fingerprint) => {
let res = { let res = {
result: false, result: false,

BIN
static/doip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB