feat: convert CJS to ESM

This commit is contained in:
Yarmo Mackenbach 2023-07-08 08:17:13 +02:00
parent 7f1d972fa7
commit 0f7c444d3c
No known key found for this signature in database
GPG key ID: 3C57D093219103A3
59 changed files with 851 additions and 913 deletions

View file

@ -1,4 +1,4 @@
const doip = require('../src')
import * as doip from '../src/index.js'
const main = async () => {
// Fetch the key using HKP

View file

@ -1,4 +1,4 @@
const doip = require('../src')
import * as doip from '../src/index.js'
const main = async () => {
// Obtain the plaintext public key

View file

@ -1,4 +1,4 @@
const doip = require('../src')
import * as doip from '../src/index.js'
const main = async () => {
// Fetch the key using WKD

View file

@ -1,4 +1,4 @@
const doip = require('../src')
import * as doip from '../src/index.js'
const main = async () => {
// Fetch the profile using ASPE

View file

@ -1,4 +1,4 @@
const doip = require('../src')
import * as doip from '../src/index.js'
const signature = `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

View file

@ -1,4 +1,4 @@
const doip = require('../src')
import * as doip from '../src/index.js'
const main = async () => {
// Generate the claim

View file

@ -2,6 +2,7 @@
"name": "doipjs",
"version": "0.19.0",
"description": "Decentralized Online Identity Proofs library in Node.js",
"type": "module",
"main": "./src/index.js",
"packageManager": "yarn@1.22.19",
"dependencies": {

View file

@ -13,12 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
const jose = require('jose')
const { base32, base64url } = require('rfc4648')
const Claim = require('./claim')
const Persona = require('./persona')
const Profile = require('./profile')
import axios from 'axios'
import { decodeProtectedHeader, importJWK, compactVerify, calculateJwkThumbprint } from 'jose'
import { base32, base64url } from 'rfc4648'
import { Claim } from './claim.js'
import { Persona } from './persona.js'
import { Profile } from './profile.js'
const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512']
@ -35,7 +35,7 @@ const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512']
* @example
* const key = doip.aspe.fetchASPE('aspe:domain.tld:1234567890');
*/
const fetchASPE = async uri => {
export async function fetchASPE (uri) {
const re = /aspe:(.*):(.*)/
if (!re.test(uri)) {
@ -78,12 +78,12 @@ const fetchASPE = async uri => {
* @example
* const key = doip.aspe.parseProfileJws('...');
*/
const parseProfileJws = async (profileJws, uri) => {
export async function parseProfileJws (profileJws, uri) {
const matches = uri.match(/aspe:(.*):(.*)/)
const localPart = matches[2].toUpperCase()
// Decode the headers
const protectedHeader = jose.decodeProtectedHeader(profileJws)
const protectedHeader = decodeProtectedHeader(profileJws)
// Extract the JWK
if (!SupportedCryptoAlg.includes(protectedHeader.alg)) {
@ -95,7 +95,7 @@ const parseProfileJws = async (profileJws, uri) => {
if (!protectedHeader.jwk) {
throw new Error('Invalid profile JWS: missing key')
}
const publicKey = await jose.importJWK(protectedHeader.jwk, protectedHeader.alg)
const publicKey = await importJWK(protectedHeader.jwk, protectedHeader.alg)
// Compute and verify the fingerprint
const fp = await computeJwkFingerprint(protectedHeader.jwk)
@ -108,7 +108,7 @@ const parseProfileJws = async (profileJws, uri) => {
}
// Decode the payload
const { payload } = await jose.compactVerify(profileJws, publicKey)
const { payload } = await compactVerify(profileJws, publicKey)
const payloadJson = JSON.parse(new TextDecoder().decode(payload))
// Verify the payload
@ -139,16 +139,13 @@ const parseProfileJws = async (profileJws, uri) => {
/**
* Compute the fingerprint for JWK keys
* @function
* @param {jose.JWK} key
* @param {import('jose').JWK} key
* @returns {Promise<string>}
*/
const computeJwkFingerprint = async key => {
const thumbprint = await jose.calculateJwkThumbprint(key, 'sha512')
export async function computeJwkFingerprint (key) {
const thumbprint = await calculateJwkThumbprint(key, 'sha512')
const fingerprintBytes = base64url.parse(thumbprint, { loose: true }).slice(0, 16)
const fingerprint = base32.stringify(fingerprintBytes, { pad: false })
return fingerprint
}
exports.fetchASPE = fetchASPE
exports.parseProfileJws = parseProfileJws

View file

@ -13,14 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const validator = require('validator').default
const validUrl = require('valid-url')
const mergeOptions = require('merge-options')
const proofs = require('./proofs')
const verifications = require('./verifications')
const claimDefinitions = require('./claimDefinitions')
const defaults = require('./defaults')
const E = require('./enums')
import isAlphanumeric from 'validator/lib/isAlphanumeric.js'
import { isUri } from 'valid-url'
import mergeOptions from 'merge-options'
import { fetch } from './proofs.js'
import { run } from './verifications.js'
import { list, data as _data } from './claimDefinitions/index.js'
import { opts as _opts } from './defaults.js'
import { ClaimStatus } from './enums.js'
/**
* @class
@ -31,7 +31,7 @@ const E = require('./enums')
* @property {Array<object>} matches - The claim definitions matched against the URI
* @property {object} verification - The result of the verification process
*/
class Claim {
export class Claim {
/**
* Initialize a Claim object
* @constructor
@ -63,14 +63,15 @@ class Claim {
}
// Verify validity of URI
if (uri && !validUrl.isUri(uri)) {
if (uri && !isUri(uri)) {
throw new Error('Invalid URI')
}
// Verify validity of fingerprint
if (fingerprint) {
try {
validator.isAlphanumeric(fingerprint)
// @ts-ignore
isAlphanumeric.default(fingerprint)
} catch (err) {
throw new Error('Invalid fingerprint')
}
@ -78,7 +79,7 @@ class Claim {
this._uri = uri || ''
this._fingerprint = fingerprint || ''
this._status = E.ClaimStatus.INIT
this._status = ClaimStatus.INIT
this._matches = []
this._verification = {}
}
@ -96,27 +97,27 @@ class Claim {
}
get matches () {
if (this._status === E.ClaimStatus.INIT) {
if (this._status === ClaimStatus.INIT) {
throw new Error('This claim has not yet been matched')
}
return this._matches
}
get verification () {
if (this._status !== E.ClaimStatus.VERIFIED) {
if (this._status !== ClaimStatus.VERIFIED) {
throw new Error('This claim has not yet been verified')
}
return this._verification
}
set uri (uri) {
if (this._status !== E.ClaimStatus.INIT) {
if (this._status !== ClaimStatus.INIT) {
throw new Error(
'Cannot change the URI, this claim has already been matched'
)
}
// Verify validity of URI
if (uri.length > 0 && !validUrl.isUri(uri)) {
if (uri.length > 0 && !isUri(uri)) {
throw new Error('The URI was invalid')
}
// Remove leading and trailing spaces
@ -126,7 +127,7 @@ class Claim {
}
set fingerprint (fingerprint) {
if (this._status === E.ClaimStatus.VERIFIED) {
if (this._status === ClaimStatus.VERIFIED) {
throw new Error(
'Cannot change the fingerprint, this claim has already been verified'
)
@ -151,17 +152,17 @@ class Claim {
* @function
*/
match () {
if (this._status !== E.ClaimStatus.INIT) {
if (this._status !== ClaimStatus.INIT) {
throw new Error('This claim was already matched')
}
if (this._uri.length === 0 || !validUrl.isUri(this._uri)) {
if (this._uri.length === 0 || !isUri(this._uri)) {
throw new Error('This claim has no URI')
}
this._matches = []
claimDefinitions.list.every((name, i) => {
const def = claimDefinitions.data[name]
list.every((name, i) => {
const def = _data[name]
// If the candidate is invalid, continue matching
if (!def.reURI.test(this._uri)) {
@ -187,7 +188,7 @@ class Claim {
return true
})
this._status = E.ClaimStatus.MATCHED
this._status = ClaimStatus.MATCHED
}
/**
@ -200,10 +201,10 @@ class Claim {
* @param {object} [opts] - Options for proxy, fetchers
*/
async verify (opts) {
if (this._status === E.ClaimStatus.INIT) {
if (this._status === ClaimStatus.INIT) {
throw new Error('This claim has not yet been matched')
}
if (this._status === E.ClaimStatus.VERIFIED) {
if (this._status === ClaimStatus.VERIFIED) {
throw new Error('This claim has already been verified')
}
if (this._fingerprint.length === 0) {
@ -211,7 +212,7 @@ class Claim {
}
// Handle options
opts = mergeOptions(defaults.opts, opts || {})
opts = mergeOptions(_opts, opts || {})
// If there are no matches
if (this._matches.length === 0) {
@ -232,14 +233,14 @@ class Claim {
let proofFetchError
try {
proofData = await proofs.fetch(claimData, opts)
proofData = await fetch(claimData, opts)
} catch (err) {
proofFetchError = err
}
if (proofData) {
// Run the verification process
verificationResult = await verifications.run(
verificationResult = await run(
proofData.result,
claimData,
this._fingerprint
@ -250,7 +251,7 @@ class Claim {
}
// Post process the data
const def = claimDefinitions.data[claimData.serviceprovider.name]
const def = _data[claimData.serviceprovider.name]
if (def.functions?.postprocess) {
try {
({ claimData, proofData } = def.functions.postprocess(claimData, proofData))
@ -289,7 +290,7 @@ class Claim {
errors: []
}
this._status = E.ClaimStatus.VERIFIED
this._status = ClaimStatus.VERIFIED
}
/**
@ -300,7 +301,7 @@ class Claim {
* @returns {boolean}
*/
isAmbiguous () {
if (this._status === E.ClaimStatus.INIT) {
if (this._status === ClaimStatus.INIT) {
throw new Error('The claim has not been matched yet')
}
if (this._matches.length === 0) {
@ -326,5 +327,3 @@ class Claim {
}
}
}
module.exports = Claim

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)\/?/
export const reURI = /^https:\/\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
return {
serviceprovider: {
type: 'web',
@ -66,14 +70,14 @@ const processURI = (uri) => {
}
}
const functions = {
export const functions = {
postprocess: (claimData, proofData) => {
claimData.profile.display = `@${proofData.result.preferredUsername}@${new URL(proofData.result.url).hostname}`
return { claimData, proofData }
}
}
const tests = [
export const tests = [
{
uri: 'https://domain.org',
shouldMatch: true
@ -107,8 +111,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.functions = functions
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)\/u\/(.*)\/?/
export const reURI = /^https:\/\/(.*)\/u\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://domain.org/u/alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^dns:([a-zA-Z0-9.\-_]*)(?:\?(.*))?/
export const reURI = /^dns:([a-zA-Z0-9.\-_]*)(?:\?(.*))?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -54,7 +58,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'dns:domain.org',
shouldMatch: true
@ -68,7 +72,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
export const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://domain.org/alice/post',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
export const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://domain.org/alice/forgejo_proof',
shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
export const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://domain.org/alice/gitea_proof',
shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/gist\.github\.com\/(.*)\/(.*)\/?/
export const reURI = /^https:\/\/gist\.github\.com\/(.*)\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://gist.github.com/Alice/123456789',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)\/(.*)\/gitlab_proof\/?/
export const reURI = /^https:\/\/(.*)\/(.*)\/gitlab_proof\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://gitlab.domain.org/alice/gitlab_proof',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/news\.ycombinator\.com\/user\?id=(.*)\/?/
export const reURI = /^https:\/\/news\.ycombinator\.com\/user\?id=(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://news.ycombinator.com/user?id=Alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,31 +13,53 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as dns from './dns.js'
import * as irc from './irc.js'
import * as xmpp from './xmpp.js'
import * as matrix from './matrix.js'
import * as telegram from './telegram.js'
import * as twitter from './twitter.js'
import * as reddit from './reddit.js'
import * as liberapay from './liberapay.js'
import * as lichess from './lichess.js'
import * as hackernews from './hackernews.js'
import * as lobsters from './lobsters.js'
import * as forem from './forem.js'
// import * as forgejo from './forgejo.js'
import * as gitea from './gitea.js'
import * as gitlab from './gitlab.js'
import * as github from './github.js'
import * as activitypub from './activitypub.js'
import * as discourse from './discourse.js'
import * as owncast from './owncast.js'
import * as stackexchange from './stackexchange.js'
import * as keybase from './keybase.js'
import * as opencollective from './opencollective.js'
const data = {
dns: require('./dns'),
irc: require('./irc'),
xmpp: require('./xmpp'),
matrix: require('./matrix'),
telegram: require('./telegram'),
twitter: require('./twitter'),
reddit: require('./reddit'),
liberapay: require('./liberapay'),
lichess: require('./lichess'),
hackernews: require('./hackernews'),
lobsters: require('./lobsters'),
forem: require('./forem'),
// forgejo: require('./forgejo'),
gitea: require('./gitea'),
gitlab: require('./gitlab'),
github: require('./github'),
activitypub: require('./activitypub'),
discourse: require('./discourse'),
owncast: require('./owncast'),
stackexchange: require('./stackexchange'),
keybase: require('./keybase'),
opencollective: require('./opencollective')
const _data = {
dns,
irc,
xmpp,
matrix,
telegram,
twitter,
reddit,
liberapay,
lichess,
hackernews,
lobsters,
forem,
// forgejo,
gitea,
gitlab,
github,
activitypub,
discourse,
owncast,
stackexchange,
keybase,
opencollective
}
exports.list = Object.keys(data)
exports.data = data
export const list = Object.keys(_data)
export { _data as data }

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^irc:\/\/(.*)\/([a-zA-Z0-9\-[\]\\`_^{|}]*)/
export const reURI = /^irc:\/\/(.*)\/([a-zA-Z0-9\-[\]\\`_^{|}]*)/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'irc://chat.ircserver.org/Alice1',
shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/keybase.io\/(.*)\/?/
export const reURI = /^https:\/\/keybase.io\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://keybase.io/Alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/liberapay\.com\/(.*)\/?/
export const reURI = /^https:\/\/liberapay\.com\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://liberapay.com/alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/lichess\.org\/@\/(.*)\/?/
export const reURI = /^https:\/\/lichess\.org\/@\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://lichess.org/@/Alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/lobste\.rs\/u\/(.*)\/?/
export const reURI = /^https:\/\/lobste\.rs\/u\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://lobste.rs/u/Alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^matrix:u\/(?:@)?([^@:]*:[^?]*)(\?.*)?/
export const reURI = /^matrix:u\/(?:@)?([^@:]*:[^?]*)(\?.*)?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
if (!match[2]) {
@ -71,7 +75,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri:
'matrix:u/alice:matrix.domain.org?org.keyoxide.r=123:domain.org&org.keyoxide.e=123',
@ -95,7 +99,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/opencollective\.com\/(.*)\/?/
export const reURI = /^https:\/\/opencollective\.com\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://opencollective.com/Alice',
shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*)/
export const reURI = /^https:\/\/(.*)/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://live.domain.org',
shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: true
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(?:www\.)?reddit\.com\/user\/(.*)\/comments\/(.*)\/(.*)\/?/
export const reURI = /^https:\/\/(?:www\.)?reddit\.com\/user\/(.*)\/comments\/(.*)\/(.*)\/?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://www.reddit.com/user/Alice/comments/123456/post',
shouldMatch: true
@ -77,7 +81,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,12 +13,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/(.*(?:askubuntu|mathoverflow|serverfault|stackapps|stackoverflow|superuser)|.+\.stackexchange)\.com\/users\/(\d+)/
export const reURI = /^https:\/\/(.*(?:askubuntu|mathoverflow|serverfault|stackapps|stackoverflow|superuser)|.+\.stackexchange)\.com\/users\/(\d+)/
const reStackExchange = /\.stackexchange$/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const [, domain, id] = uri.match(reURI)
const site = domain.replace(reStackExchange, '')
@ -57,7 +61,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://stackoverflow.com/users/1234',
shouldMatch: true
@ -112,7 +116,3 @@ const tests = [
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /https:\/\/t.me\/([A-Za-z0-9_]{5,32})\?proof=([A-Za-z0-9_]{5,32})/
export const reURI = /https:\/\/t.me\/([A-Za-z0-9_]{5,32})\?proof=([A-Za-z0-9_]{5,32})/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://t.me/alice?proof=foobar',
shouldMatch: true
@ -77,7 +81,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,13 +13,21 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^https:\/\/twitter\.com\/(.*)\/status\/([0-9]*)(?:\?.*)?/
export const reURI = /^https:\/\/twitter\.com\/(.*)\/status\/([0-9]*)(?:\?.*)?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
const urlsp = new URLSearchParams()
urlsp.set('url', match[0])
urlsp.set('omit_script', '1')
return {
serviceprovider: {
type: 'web',
@ -42,7 +50,7 @@ const processURI = (uri) => {
format: E.ProofFormat.JSON,
data: {
// Returns an oembed json object with the tweet content in html form
url: `https://publish.twitter.com/oembed?${new URLSearchParams({ url: match[0], omit_script: 1 })}`,
url: `https://publish.twitter.com/oembed?${urlsp}`,
format: E.ProofFormat.JSON
}
}
@ -56,7 +64,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'https://twitter.com/alice/status/1234567890123456789',
shouldMatch: true
@ -70,7 +78,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

View file

@ -13,11 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('../enums')
import * as E from '../enums.js'
const reURI = /^xmpp:([a-zA-Z0-9.\-_]*)@([a-zA-Z0-9.\-_]*)(?:\?(.*))?/
export const reURI = /^xmpp:([a-zA-Z0-9.\-_]*)@([a-zA-Z0-9.\-_]*)(?:\?(.*))?/
const processURI = (uri) => {
/**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const match = uri.match(reURI)
return {
@ -54,7 +58,7 @@ const processURI = (uri) => {
}
}
const tests = [
export const tests = [
{
uri: 'xmpp:alice@domain.org',
shouldMatch: true
@ -68,7 +72,3 @@ const tests = [
shouldMatch: false
}
]
exports.reURI = reURI
exports.processURI = processURI
exports.tests = tests

25
src/constants.js Normal file
View file

@ -0,0 +1,25 @@
/*
Copyright 2023 Yarmo Mackenbach
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* Contains constant values
* @module constants
*/
/**
* doip.js library version
* @constant {string}
*/
export const version = '0.20.0'

View file

@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const E = require('./enums')
import { ProxyPolicy } from './enums.js'
/**
* Contains default values
@ -42,10 +42,10 @@ const E = require('./enums')
* @property {string|null} claims.xmpp.username - The username used to log in
* @property {string|null} claims.xmpp.password - The password used to log in
*/
const opts = {
export const opts = {
proxy: {
hostname: null,
policy: E.ProxyPolicy.NEVER
policy: ProxyPolicy.NEVER
},
claims: {
activitypub: {
@ -69,5 +69,3 @@ const opts = {
}
}
}
exports.opts = opts

View file

@ -23,7 +23,7 @@ limitations under the License.
* @readonly
* @enum {string}
*/
const ProxyPolicy = {
export const ProxyPolicy = {
/** Proxy usage decision depends on environment and service provider */
ADAPTIVE: 'adaptive',
/** Always use a proxy */
@ -31,14 +31,13 @@ const ProxyPolicy = {
/** Never use a proxy, skip a verification if a proxy is inevitable */
NEVER: 'never'
}
Object.freeze(ProxyPolicy)
/**
* Methods for fetching proofs
* @readonly
* @enum {string}
*/
const Fetcher = {
export const Fetcher = {
/** HTTP requests to ActivityPub */
ACTIVITYPUB: 'activitypub',
/** DNS module from Node.js */
@ -56,14 +55,13 @@ const Fetcher = {
/** XMPP module from Node.js */
XMPP: 'xmpp'
}
Object.freeze(Fetcher)
/**
* Entity encoding format
* @readonly
* @enum {string}
*/
const EntityEncodingFormat = {
export const EntityEncodingFormat = {
/** No special formatting */
PLAIN: 'plain',
/** HTML encoded entities */
@ -71,14 +69,13 @@ const EntityEncodingFormat = {
/** XML encoded entities */
XML: 'xml'
}
Object.freeze(EntityEncodingFormat)
/**
* Levels of access restriction for proof fetching
* @readonly
* @enum {string}
*/
const ProofAccess = {
export const ProofAccess = {
/** Any HTTP request will work */
GENERIC: 'generic',
/** CORS requests are denied */
@ -88,40 +85,37 @@ const ProofAccess = {
/** Not accessible by HTTP request, needs server software */
SERVER: 'server'
}
Object.freeze(ProofAccess)
/**
* Format of proof
* @readonly
* @enum {string}
*/
const ProofFormat = {
export const ProofFormat = {
/** JSON format */
JSON: 'json',
/** Plaintext format */
TEXT: 'text'
}
Object.freeze(ProofFormat)
/**
* Format of claim
* @readonly
* @enum {string}
*/
const ClaimFormat = {
export const ClaimFormat = {
/** `openpgp4fpr:123123123` */
URI: 'uri',
/** `123123123` */
FINGERPRINT: 'fingerprint'
}
Object.freeze(ClaimFormat)
/**
* How to find the claim inside the proof's JSON data
* @readonly
* @enum {string}
*/
const ClaimRelation = {
export const ClaimRelation = {
/** Claim is somewhere in the JSON field's textual content */
CONTAINS: 'contains',
/** Claim is equal to the JSON field's textual content */
@ -129,14 +123,13 @@ const ClaimRelation = {
/** Claim is equal to an element of the JSON field's array of strings */
ONEOF: 'oneof'
}
Object.freeze(ClaimRelation)
/**
* Status of the Claim instance
* @readonly
* @enum {string}
*/
const ClaimStatus = {
export const ClaimStatus = {
/** Claim has been initialized */
INIT: 'init',
/** Claim has matched its URI to candidate claim definitions */
@ -144,13 +137,3 @@ const ClaimStatus = {
/** Claim has verified one or multiple candidate claim definitions */
VERIFIED: 'verified'
}
Object.freeze(ClaimStatus)
exports.ProxyPolicy = ProxyPolicy
exports.Fetcher = Fetcher
exports.EntityEncodingFormat = EntityEncodingFormat
exports.ProofAccess = ProofAccess
exports.ProofFormat = ProofFormat
exports.ClaimFormat = ClaimFormat
exports.ClaimRelation = ClaimRelation
exports.ClaimStatus = ClaimStatus

View file

@ -13,19 +13,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
const validator = require('validator').default
const jsEnv = require('browser-or-node')
import axios from 'axios'
import isURL from 'validator/lib/isURL.js'
import { isNode } from 'browser-or-node'
import crypto from 'crypto'
import { version } from '../constants.js'
/**
* @module fetcher/activitypub
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
export const timeout = 5000
/**
* Execute a fetch request
@ -41,17 +35,12 @@ module.exports.timeout = 5000
* @param {string} opts.claims.activitypub.privateKey - The private key to sign the request
* @returns {Promise<object>}
*/
module.exports.fn = async (data, opts) => {
let crypto
if (jsEnv.isNode) {
crypto = require('crypto')
}
export async function fn (data, opts) {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
@ -59,7 +48,7 @@ module.exports.fn = async (data, opts) => {
(async () => {
let isConfigured = false
try {
validator.isURL(opts.claims.activitypub.url)
isURL(opts.claims.activitypub.url)
isConfigured = true
} catch (_) {}
@ -71,10 +60,10 @@ module.exports.fn = async (data, opts) => {
date: now.toUTCString(),
accept: 'application/activity+json',
// @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}`
'User-Agent': `doipjs/${version}`
}
if (isConfigured && jsEnv.isNode) {
if (isConfigured && isNode) {
// Generate the signature
const signedString = `(request-target): get ${pathname}${search}\nhost: ${host}\ndate: ${now.toUTCString()}`
const sign = crypto.createSign('SHA256')

View file

@ -13,60 +13,51 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const jsEnv = require('browser-or-node')
import { isBrowser } from 'browser-or-node'
import dns from 'dns'
export const timeout = 5000
/**
* @module fetcher/dns
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.domain - The targeted domain
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>}
*/
export async function fn (data, opts) {
if (isBrowser) {
return null
}
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
if (jsEnv.isNode) {
const dns = require('dns')
const fetchPromise = new Promise((resolve, reject) => {
dns.resolveTxt(data.domain, (err, records) => {
if (err) {
reject(err)
return
}
/**
* Execute a fetch request
* @function
* @async
* @param {object} data - Data used in the request
* @param {string} data.domain - The targeted domain
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>}
*/
module.exports.fn = async (data, opts) => {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
)
})
const fetchPromise = new Promise((resolve, reject) => {
dns.resolveTxt(data.domain, (err, records) => {
if (err) {
reject(err)
return
resolve({
domain: data.domain,
records: {
txt: records
}
resolve({
domain: data.domain,
records: {
txt: records
}
})
})
})
})
return Promise.race([fetchPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle)
return result
})
}
} else {
module.exports.fn = null
return Promise.race([fetchPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle)
return result
})
}

View file

@ -13,17 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
import axios from 'axios'
import { version } from '../constants.js'
/**
* @module fetcher/graphql
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
export const timeout = 5000
/**
* Execute a GraphQL query via HTTP request
@ -35,12 +28,12 @@ module.exports.timeout = 5000
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object|string>}
*/
module.exports.fn = async (data, opts) => {
export async function fn (data, opts) {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
@ -61,7 +54,7 @@ module.exports.fn = async (data, opts) => {
headers: {
'Content-Type': 'application/json',
// @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}`
'User-Agent': `doipjs/${version}`
},
validateStatus: function (status) {
return status >= 200 && status < 400

View file

@ -13,18 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
const E = require('../enums')
import axios from 'axios'
import { ProofFormat } from '../enums.js'
import { version } from '../constants.js'
/**
* @module fetcher/http
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
export const timeout = 5000
/**
* Execute a fetch request
@ -36,12 +29,12 @@ module.exports.timeout = 5000
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object|string>}
*/
module.exports.fn = async (data, opts) => {
export async function fn (data, opts) {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
@ -52,12 +45,12 @@ module.exports.fn = async (data, opts) => {
}
switch (data.format) {
case E.ProofFormat.JSON:
case ProofFormat.JSON:
axios.get(data.url, {
headers: {
Accept: 'application/json',
// @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}`
'User-Agent': `doipjs/${version}`
},
validateStatus: function (status) {
return status >= 200 && status < 400
@ -70,7 +63,7 @@ module.exports.fn = async (data, opts) => {
reject(e)
})
break
case E.ProofFormat.TEXT:
case ProofFormat.TEXT:
axios.get(data.url, {
validateStatus: function (status) {
return status >= 200 && status < 400

View file

@ -13,12 +13,14 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import dotenv from 'dotenv'
dotenv.config()
exports.activitypub = require('./activitypub')
exports.dns = require('./dns')
exports.graphql = require('./graphql')
exports.http = require('./http')
exports.irc = require('./irc')
exports.matrix = require('./matrix')
exports.telegram = require('./telegram')
exports.xmpp = require('./xmpp')
export * as activitypub from './activitypub.js'
export * as dns from './dns.js'
export * as graphql from './graphql.js'
export * as http from './http.js'
export * as irc from './irc.js'
export * as matrix from './matrix.js'
export * as telegram from './telegram.js'
export * as xmpp from './xmpp.js'

View file

@ -0,0 +1,20 @@
/*
Copyright 2021 Yarmo Mackenbach
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export * as activitypub from './activitypub.js'
export * as graphql from './graphql.js'
export * as http from './http.js'
export * as matrix from './matrix.js'
export * as telegram from './telegram.js'

View file

@ -13,89 +13,75 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const jsEnv = require('browser-or-node')
import irc from 'irc-upd'
import isAscii from 'validator/lib/isAscii.js'
export const timeout = 20000
/**
* @module fetcher/irc
* 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 {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.irc
* @param {string} opts.claims.irc.nick - The nick to be used by the library to log in
* @returns {Promise<object>}
*/
export async function fn (data, opts) {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 20000
const fetchPromise = new Promise((resolve, reject) => {
try {
isAscii(opts.claims.irc.nick)
} catch (err) {
throw new Error(`IRC fetcher was not set up properly (${err.message})`)
}
if (jsEnv.isNode) {
const irc = require('irc-upd')
const validator = require('validator').default
try {
const client = new irc.Client(data.domain, opts.claims.irc.nick, {
port: 6697,
secure: true,
channels: [],
showErrors: false,
debug: false
})
const reKey = /[a-zA-Z0-9\-_]+\s+:\s(openpgp4fpr:.*)/
const reEnd = /End\sof\s.*\staxonomy./
const keys = []
/**
* 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 {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.irc
* @param {string} opts.claims.irc.nick - The nick to be used by the library to log in
* @returns {Promise<object>}
*/
module.exports.fn = async (data, opts) => {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
)
})
// @ts-ignore
client.addListener('registered', (message) => {
client.send(`PRIVMSG NickServ TAXONOMY ${data.nick}`)
})
// @ts-ignore
client.addListener('notice', (nick, to, text, message) => {
if (reKey.test(text)) {
const match = text.match(reKey)
keys.push(match[1])
}
if (reEnd.test(text)) {
client.disconnect()
resolve(keys)
}
})
} catch (error) {
reject(error)
}
})
const fetchPromise = new Promise((resolve, reject) => {
try {
validator.isAscii(opts.claims.irc.nick)
} catch (err) {
throw new Error(`IRC fetcher was not set up properly (${err.message})`)
}
try {
const client = new irc.Client(data.domain, opts.claims.irc.nick, {
port: 6697,
secure: true,
channels: [],
showErrors: false,
debug: false
})
const reKey = /[a-zA-Z0-9\-_]+\s+:\s(openpgp4fpr:.*)/
const reEnd = /End\sof\s.*\staxonomy./
const keys = []
// @ts-ignore
client.addListener('registered', (message) => {
client.send(`PRIVMSG NickServ TAXONOMY ${data.nick}`)
})
// @ts-ignore
client.addListener('notice', (nick, to, text, message) => {
if (reKey.test(text)) {
const match = text.match(reKey)
keys.push(match[1])
}
if (reEnd.test(text)) {
client.disconnect()
resolve(keys)
}
})
} catch (error) {
reject(error)
}
})
return Promise.race([fetchPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle)
return result
})
}
} else {
module.exports.fn = null
return Promise.race([fetchPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle)
return result
})
}

View file

@ -13,18 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
const validator = require('validator').default
import axios from 'axios'
import isFQDN from 'validator/lib/isFQDN.js'
import isAscii from 'validator/lib/isAscii.js'
import { version } from '../constants.js'
/**
* @module fetcher/matrix
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
export const timeout = 5000
/**
* Execute a fetch request
@ -41,19 +35,19 @@ module.exports.timeout = 5000
* @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 {Promise<object>}
*/
module.exports.fn = async (data, opts) => {
export async function fn (data, opts) {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
const fetchPromise = new Promise((resolve, reject) => {
try {
validator.isFQDN(opts.claims.matrix.instance)
validator.isAscii(opts.claims.matrix.accessToken)
isFQDN(opts.claims.matrix.instance)
isAscii(opts.claims.matrix.accessToken)
} catch (err) {
throw new Error(`Matrix fetcher was not set up properly (${err.message})`)
}
@ -64,7 +58,7 @@ module.exports.fn = async (data, opts) => {
headers: {
Accept: 'application/json',
// @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}`
'User-Agent': `doipjs/${version}`
}
})
.then(res => {

View file

@ -13,19 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
const validator = require('validator').default
import axios from 'axios'
import isAscii from 'validator/lib/isAscii.js'
import { version } from '../constants.js'
/**
* @module fetcher/telegram
*/
/**
* The single request's timeout value in milliseconds
* This fetcher makes two requests in total
* @constant {number} timeout
*/
module.exports.timeout = 5000
export const timeout = 5000
/**
* Execute a fetch request
@ -41,18 +33,18 @@ module.exports.timeout = 5000
* @param {string} opts.claims.telegram.token - The Telegram Bot API token
* @returns {Promise<object|string>}
*/
module.exports.fn = async (data, opts) => {
export async function fn (data, opts) {
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
const apiPromise = (/** @type {string} */ method) => new Promise((resolve, reject) => {
try {
validator.isAscii(opts.claims.telegram.token)
isAscii(opts.claims.telegram.token)
} catch (err) {
throw new Error(`Telegram fetcher was not set up properly (${err.message})`)
}
@ -67,7 +59,7 @@ module.exports.fn = async (data, opts) => {
headers: {
Accept: 'application/json',
// @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}`
'User-Agent': `doipjs/${version}`
},
validateStatus: (status) => status === 200
})

View file

@ -13,184 +13,171 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const jsEnv = require('browser-or-node')
import { client, xml } from '@xmpp/client'
import debug from '@xmpp/debug'
import isFQDN from 'validator/lib/isFQDN.js'
import isAscii from 'validator/lib/isAscii.js'
/**
* @module fetcher/xmpp
*/
export const timeout = 5000
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
let xmpp = null
let iqCaller = null
if (jsEnv.isNode) {
const { client, xml } = require('@xmpp/client')
const debug = require('@xmpp/debug')
const validator = require('validator').default
let xmpp = null
let iqCaller = null
const xmppStart = async (service, username, password) => {
return new Promise((resolve, reject) => {
const xmpp = client({
service,
username,
password
})
if (process.env.NODE_ENV !== 'production') {
debug(xmpp, true)
}
const { iqCaller } = xmpp
xmpp.start()
xmpp.on('online', _ => {
resolve({ xmpp, iqCaller })
})
xmpp.on('error', error => {
reject(error)
})
const xmppStart = async (service, username, password) => {
return new Promise((resolve, reject) => {
const xmpp = client({
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 {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.xmpp
* @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 {Promise<object>}
*/
module.exports.fn = async (data, opts) => {
try {
validator.isFQDN(opts.claims.xmpp.service)
validator.isAscii(opts.claims.xmpp.username)
validator.isAscii(opts.claims.xmpp.password)
} catch (err) {
throw new Error(`XMPP fetcher was not set up properly (${err.message})`)
if (process.env.NODE_ENV !== 'production') {
debug(xmpp, true)
}
if (!xmpp || xmpp.status !== 'online') {
const xmppStartRes = await xmppStart(
opts.claims.xmpp.service,
opts.claims.xmpp.username,
opts.claims.xmpp.password
)
xmpp = xmppStartRes.xmpp
iqCaller = xmppStartRes.iqCaller
}
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout
)
const { iqCaller } = xmpp
xmpp.start()
xmpp.on('online', _ => {
resolve({ xmpp, iqCaller })
})
const fetchPromise = new Promise((resolve, reject) => {
(async () => {
let completed = false
const proofs = []
// Try the ariadne-id pubsub request
if (!completed) {
try {
const response = await iqCaller.request(
xml('iq', { type: 'get', to: data.id }, xml('pubsub', 'http://jabber.org/protocol/pubsub', xml('items', { node: 'http://ariadne.id/protocol/proof' }))),
30 * 1000
)
// Traverse the XML response
response.getChild('pubsub').getChildren('items').forEach(items => {
if (items.attrs.node === 'http://ariadne.id/protocol/proof') {
items.getChildren('item').forEach(item => {
proofs.push(item.getChildText('value'))
})
}
})
resolve(proofs)
completed = true
} catch (_) {}
}
// Try the vcard4 pubsub request [backward compatibility]
if (!completed) {
try {
const response = await iqCaller.request(
xml('iq', { type: 'get', to: data.id }, xml('pubsub', 'http://jabber.org/protocol/pubsub', xml('items', { node: 'urn:xmpp:vcard4', max_items: '1' }))),
30 * 1000
)
// Traverse the XML response
response.getChild('pubsub').getChildren('items').forEach(items => {
if (items.attrs.node === 'urn:xmpp:vcard4') {
items.getChildren('item').forEach(item => {
if (item.attrs.id === 'current') {
const itemVcard = item.getChild('vcard', 'urn:ietf:params:xml:ns:vcard-4.0')
// Find the vCard URLs
itemVcard.getChildren('url').forEach(url => {
proofs.push(url.getChildText('uri'))
})
// Find the vCard notes
itemVcard.getChildren('note').forEach(note => {
proofs.push(note.getChildText('text'))
})
}
})
}
})
resolve(proofs)
completed = true
} catch (_) {}
}
// Try the vcard-temp IQ request [backward compatibility]
if (!completed) {
try {
const response = await iqCaller.request(
xml('iq', { type: 'get', to: data.id }, xml('vCard', 'vcard-temp')),
30 * 1000
)
// Find the vCard URLs
response.getChild('vCard', 'vcard-temp').getChildren('URL').forEach(url => {
proofs.push(url.children[0])
})
// Find the vCard notes
response.getChild('vCard', 'vcard-temp').getChildren('NOTE').forEach(note => {
proofs.push(note.children[0])
})
response.getChild('vCard', 'vcard-temp').getChildren('DESC').forEach(note => {
proofs.push(note.children[0])
})
resolve(proofs)
completed = true
} catch (error) {
reject(error)
}
}
xmpp.stop()
})()
xmpp.on('error', error => {
reject(error)
})
return Promise.race([fetchPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle)
return result
})
}
} else {
module.exports.fn = null
})
}
/**
* 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 {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.xmpp
* @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 {Promise<object>}
*/
export async function fn (data, opts) {
try {
isFQDN(opts.claims.xmpp.service)
isAscii(opts.claims.xmpp.username)
isAscii(opts.claims.xmpp.password)
} catch (err) {
throw new Error(`XMPP fetcher was not set up properly (${err.message})`)
}
if (!xmpp || xmpp.status !== 'online') {
const xmppStartRes = await xmppStart(
opts.claims.xmpp.service,
opts.claims.xmpp.username,
opts.claims.xmpp.password
)
xmpp = xmppStartRes.xmpp
iqCaller = xmppStartRes.iqCaller
}
let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : timeout
)
})
const fetchPromise = new Promise((resolve, reject) => {
(async () => {
let completed = false
const proofs = []
// Try the ariadne-id pubsub request
if (!completed) {
try {
const response = await iqCaller.request(
xml('iq', { type: 'get', to: data.id }, xml('pubsub', 'http://jabber.org/protocol/pubsub', xml('items', { node: 'http://ariadne.id/protocol/proof' }))),
30 * 1000
)
// Traverse the XML response
response.getChild('pubsub').getChildren('items').forEach(items => {
if (items.attrs.node === 'http://ariadne.id/protocol/proof') {
items.getChildren('item').forEach(item => {
proofs.push(item.getChildText('value'))
})
}
})
resolve(proofs)
completed = true
} catch (_) {}
}
// Try the vcard4 pubsub request [backward compatibility]
if (!completed) {
try {
const response = await iqCaller.request(
xml('iq', { type: 'get', to: data.id }, xml('pubsub', 'http://jabber.org/protocol/pubsub', xml('items', { node: 'urn:xmpp:vcard4', max_items: '1' }))),
30 * 1000
)
// Traverse the XML response
response.getChild('pubsub').getChildren('items').forEach(items => {
if (items.attrs.node === 'urn:xmpp:vcard4') {
items.getChildren('item').forEach(item => {
if (item.attrs.id === 'current') {
const itemVcard = item.getChild('vcard', 'urn:ietf:params:xml:ns:vcard-4.0')
// Find the vCard URLs
itemVcard.getChildren('url').forEach(url => {
proofs.push(url.getChildText('uri'))
})
// Find the vCard notes
itemVcard.getChildren('note').forEach(note => {
proofs.push(note.getChildText('text'))
})
}
})
}
})
resolve(proofs)
completed = true
} catch (_) {}
}
// Try the vcard-temp IQ request [backward compatibility]
if (!completed) {
try {
const response = await iqCaller.request(
xml('iq', { type: 'get', to: data.id }, xml('vCard', 'vcard-temp')),
30 * 1000
)
// Find the vCard URLs
response.getChild('vCard', 'vcard-temp').getChildren('URL').forEach(url => {
proofs.push(url.children[0])
})
// Find the vCard notes
response.getChild('vCard', 'vcard-temp').getChildren('NOTE').forEach(note => {
proofs.push(note.children[0])
})
response.getChild('vCard', 'vcard-temp').getChildren('DESC').forEach(note => {
proofs.push(note.children[0])
})
resolve(proofs)
completed = true
} catch (error) {
reject(error)
}
}
xmpp.stop()
})()
})
return Promise.race([fetchPromise, timeoutPromise]).then((result) => {
clearTimeout(timeoutHandle)
return result
})
}

View file

@ -13,30 +13,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const Profile = require('./profile')
const Persona = require('./persona')
const Claim = require('./claim')
const claimDefinitions = require('./claimDefinitions')
const proofs = require('./proofs')
const keys = require('./keys')
const asp = require('./asp')
const signatures = require('./signatures')
const enums = require('./enums')
const defaults = require('./defaults')
const utils = require('./utils')
const verifications = require('./verifications')
const fetcher = require('./fetcher')
exports.Profile = Profile
exports.Persona = Persona
exports.Claim = Claim
exports.claimDefinitions = claimDefinitions
exports.proofs = proofs
exports.keys = keys
exports.asp = asp
exports.signatures = signatures
exports.enums = enums
exports.defaults = defaults
exports.utils = utils
exports.verifications = verifications
exports.fetcher = fetcher
export { Profile } from './profile.js'
export { Persona } from './persona.js'
export { Claim } from './claim.js'
export * as claimDefinitions from './claimDefinitions/index.js'
export * as proofs from './proofs.js'
export * as keys from './keys.js'
export * as asp from './asp.js'
export * as signatures from './signatures.js'
export * as enums from './enums.js'
export * as defaults from './defaults.js'
export * as utils from './utils.js'
export * as verifications from './verifications.js'
export * as fetcher from './fetcher/index.js'

View file

@ -13,12 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const axios = require('axios').default
const validUrl = require('valid-url')
const openpgp = require('openpgp')
const HKP = require('@openpgp/hkp-client')
const WKD = require('@openpgp/wkd-client')
const Claim = require('./claim')
import axios from 'axios'
import { isUri } from 'valid-url'
import { readKey, PublicKey } from 'openpgp'
import HKP from '@openpgp/hkp-client'
import WKD from '@openpgp/wkd-client'
import { Claim } from './claim.js'
/**
* Functions related to the fetching and handling of keys
@ -30,12 +30,12 @@ const Claim = require('./claim')
* @function
* @param {string} identifier - Fingerprint or email address
* @param {string} [keyserverDomain=keys.openpgp.org] - Domain of the keyserver
* @returns {Promise<openpgp.PublicKey>}
* @returns {Promise<PublicKey>}
* @example
* const key1 = doip.keys.fetchHKP('alice@domain.tld');
* const key2 = doip.keys.fetchHKP('123abc123abc');
*/
const fetchHKP = async (identifier, keyserverDomain) => {
export async function fetchHKP (identifier, keyserverDomain) {
const keyserverBaseUrl = keyserverDomain
? `https://${keyserverDomain}`
: 'https://keys.openpgp.org'
@ -56,7 +56,7 @@ const fetchHKP = async (identifier, keyserverDomain) => {
throw new Error('Key does not exist or could not be fetched')
}
return await openpgp.readKey({
return await readKey({
armoredKey: publicKey
})
.catch((error) => {
@ -68,11 +68,11 @@ const fetchHKP = async (identifier, keyserverDomain) => {
* Fetch a public key using Web Key Directory
* @function
* @param {string} identifier - Identifier of format 'username@domain.tld`
* @returns {Promise<openpgp.PublicKey>}
* @returns {Promise<PublicKey>}
* @example
* const key = doip.keys.fetchWKD('alice@domain.tld');
*/
const fetchWKD = async (identifier) => {
export async function fetchWKD (identifier) {
// @ts-ignore
const wkd = new WKD()
const lookupOpts = {
@ -89,7 +89,7 @@ const fetchWKD = async (identifier) => {
throw new Error('Key does not exist or could not be fetched')
}
return await openpgp.readKey({
return await readKey({
binaryKey: publicKey
})
.catch((error) => {
@ -102,11 +102,11 @@ const fetchWKD = async (identifier) => {
* @function
* @param {string} username - Keybase username
* @param {string} fingerprint - Fingerprint of key
* @returns {Promise<openpgp.PublicKey>}
* @returns {Promise<PublicKey>}
* @example
* const key = doip.keys.fetchKeybase('alice', '123abc123abc');
*/
const fetchKeybase = async (username, fingerprint) => {
export async function fetchKeybase (username, fingerprint) {
const keyLink = `https://keybase.io/${username}/pgp_keys.asc?fingerprint=${fingerprint}`
let rawKeyContent
try {
@ -126,7 +126,7 @@ const fetchKeybase = async (username, fingerprint) => {
throw new Error(`Error fetching Keybase key: ${e.message}`)
}
return await openpgp.readKey({
return await readKey({
armoredKey: rawKeyContent
})
.catch((error) => {
@ -138,7 +138,7 @@ const fetchKeybase = async (username, fingerprint) => {
* Get a public key from plaintext data
* @function
* @param {string} rawKeyContent - Plaintext ASCII-formatted public key data
* @returns {Promise<openpgp.PublicKey>}
* @returns {Promise<PublicKey>}
* @example
* const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
*
@ -148,8 +148,8 @@ const fetchKeybase = async (username, fingerprint) => {
* -----END PGP PUBLIC KEY BLOCK-----`
* const key = doip.keys.fetchPlaintext(plainkey);
*/
const fetchPlaintext = async (rawKeyContent) => {
const publicKey = await openpgp.readKey({
export async function fetchPlaintext (rawKeyContent) {
const publicKey = await readKey({
armoredKey: rawKeyContent
})
.catch((error) => {
@ -163,14 +163,14 @@ const fetchPlaintext = async (rawKeyContent) => {
* Fetch a public key using an URI
* @function
* @param {string} uri - URI that defines the location of the key
* @returns {Promise<openpgp.PublicKey>}
* @returns {Promise<PublicKey>}
* @example
* 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 fetchURI = async (uri) => {
if (!validUrl.isUri(uri)) {
export async function fetchURI (uri) {
if (!isUri(uri)) {
throw new Error('Invalid URI')
}
@ -209,12 +209,12 @@ const fetchURI = async (uri) => {
* This function will also try and parse the input as a plaintext key
* @function
* @param {string} identifier - URI that defines the location of the key
* @returns {Promise<openpgp.PublicKey>}
* @returns {Promise<PublicKey>}
* @example
* const key1 = doip.keys.fetch('alice@domain.tld');
* const key2 = doip.keys.fetch('123abc123abc');
*/
const fetch = async (identifier) => {
export async function fetch (identifier) {
const re = /([a-zA-Z0-9@._=+-]*)(?::([a-zA-Z0-9@._=+-]*))?/
const match = identifier.match(re)
@ -252,7 +252,7 @@ const fetch = async (identifier) => {
/**
* Process a public key to get user data and claims
* @function
* @param {openpgp.PublicKey} publicKey - The public key to process
* @param {PublicKey} publicKey - The public key to process
* @returns {Promise<object>}
* @example
* const key = doip.keys.fetchURI('hkp:alice@domain.tld');
@ -261,8 +261,8 @@ const fetch = async (identifier) => {
* console.log(claim.uri);
* });
*/
const process = async (publicKey) => {
if (!(publicKey && (publicKey instanceof openpgp.PublicKey))) {
export async function process (publicKey) {
if (!(publicKey && (publicKey instanceof PublicKey))) {
throw new Error('Invalid public key')
}
@ -313,11 +313,3 @@ const process = async (publicKey) => {
}
}
}
exports.fetchHKP = fetchHKP
exports.fetchWKD = fetchWKD
exports.fetchKeybase = fetchKeybase
exports.fetchPlaintext = fetchPlaintext
exports.fetchURI = fetchURI
exports.fetch = fetch
exports.process = process

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// eslint-disable-next-line
const Claim = require('./claim')
import { Claim } from './claim.js'
/**
* A persona with identity claims
@ -25,7 +25,7 @@ const Claim = require('./claim')
* const claim = Claim('https://alice.tld', '123');
* const pers = Persona('Alice', 'About Alice', [claim]);
*/
class Persona {
export class Persona {
/**
* @param {string} name
* @param {string} [description]
@ -52,5 +52,3 @@ class Persona {
this.claims = claims
}
}
module.exports = Persona

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// eslint-disable-next-line
const Persona = require('./persona')
import { Persona } from './persona.js'
/**
* A profile of personas with identity claims
@ -26,7 +26,7 @@ const Persona = require('./persona')
* const pers = Persona('Alice', 'About Alice', [claim]);
* const profile = Profile([pers]);
*/
class Profile {
export class Profile {
/**
* Create a new profile
* @function
@ -48,5 +48,3 @@ class Profile {
this.primaryPersona = -1
}
}
module.exports = Profile

View file

@ -13,10 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const jsEnv = require('browser-or-node')
const fetcher = require('./fetcher')
const utils = require('./utils')
const E = require('./enums')
import { isNode } from 'browser-or-node'
import * as fetcher from './fetcher/index.js'
import { generateProxyURL } from './utils.js'
import { Fetcher, ProxyPolicy, ProofAccess } from './enums.js'
/**
* @module proofs
@ -33,9 +33,9 @@ const E = require('./enums')
* @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/
const fetch = (data, opts) => {
export async function fetch (data, opts) {
switch (data.proof.request.fetcher) {
case E.Fetcher.HTTP:
case Fetcher.HTTP:
data.proof.request.data.format = data.proof.request.format
break
@ -43,7 +43,7 @@ const fetch = (data, opts) => {
break
}
if (jsEnv.isNode) {
if (isNode) {
return handleNodeRequests(data, opts)
}
@ -52,16 +52,16 @@ const fetch = (data, opts) => {
const handleBrowserRequests = (data, opts) => {
switch (opts.proxy.policy) {
case E.ProxyPolicy.ALWAYS:
case ProxyPolicy.ALWAYS:
return createProxyRequestPromise(data, opts)
case E.ProxyPolicy.NEVER:
case ProxyPolicy.NEVER:
switch (data.proof.request.access) {
case E.ProofAccess.GENERIC:
case E.ProofAccess.GRANTED:
case ProofAccess.GENERIC:
case ProofAccess.GRANTED:
return createDefaultRequestPromise(data, opts)
case E.ProofAccess.NOCORS:
case E.ProofAccess.SERVER:
case ProofAccess.NOCORS:
case ProofAccess.SERVER:
throw new Error(
'Impossible to fetch proof (bad combination of service access and proxy policy)'
)
@ -69,15 +69,15 @@ const handleBrowserRequests = (data, opts) => {
throw new Error('Invalid proof access value')
}
case E.ProxyPolicy.ADAPTIVE:
case ProxyPolicy.ADAPTIVE:
switch (data.proof.request.access) {
case E.ProofAccess.GENERIC:
case ProofAccess.GENERIC:
return createFallbackRequestPromise(data, opts)
case E.ProofAccess.NOCORS:
case ProofAccess.NOCORS:
return createProxyRequestPromise(data, opts)
case E.ProofAccess.GRANTED:
case ProofAccess.GRANTED:
return createFallbackRequestPromise(data, opts)
case E.ProofAccess.SERVER:
case ProofAccess.SERVER:
return createProxyRequestPromise(data, opts)
default:
throw new Error('Invalid proof access value')
@ -90,13 +90,13 @@ const handleBrowserRequests = (data, opts) => {
const handleNodeRequests = (data, opts) => {
switch (opts.proxy.policy) {
case E.ProxyPolicy.ALWAYS:
case ProxyPolicy.ALWAYS:
return createProxyRequestPromise(data, opts)
case E.ProxyPolicy.NEVER:
case ProxyPolicy.NEVER:
return createDefaultRequestPromise(data, opts)
case E.ProxyPolicy.ADAPTIVE:
case ProxyPolicy.ADAPTIVE:
return createFallbackRequestPromise(data, opts)
default:
@ -126,7 +126,7 @@ const createProxyRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => {
let proxyUrl
try {
proxyUrl = utils.generateProxyURL(
proxyUrl = generateProxyURL(
data.proof.request.fetcher,
data.proof.request.data,
opts
@ -173,5 +173,3 @@ const createFallbackRequestPromise = (data, opts) => {
})
})
}
exports.fetch = fetch

View file

@ -13,9 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const openpgp = require('openpgp')
const Claim = require('./claim')
const keys = require('./keys')
import { readCleartextMessage, verify } from 'openpgp'
import { Claim } from './claim.js'
import { fetchURI } from './keys.js'
/**
* @module signatures
@ -27,8 +27,8 @@ const keys = require('./keys')
* @param {string} signature - The plaintext signature to process
* @returns {Promise<object>}
*/
const process = async (signature) => {
/** @type {openpgp.CleartextMessage} */
export async function process (signature) {
/** @type {import('openpgp').CleartextMessage} */
let sigData
const result = {
fingerprint: null,
@ -48,7 +48,7 @@ const process = async (signature) => {
// Read the signature
try {
sigData = await openpgp.readCleartextMessage({
sigData = await readCleartextMessage({
cleartextMessage: signature
})
} catch (e) {
@ -89,7 +89,7 @@ const process = async (signature) => {
if (sigKeys.length > 0) {
try {
result.key.uri = sigKeys[0]
result.key.data = await keys.fetchURI(result.key.uri)
result.key.data = await fetchURI(result.key.uri)
result.key.fetchMethod = result.key.uri.split(':')[0]
} catch (e) {}
}
@ -97,7 +97,7 @@ const process = async (signature) => {
if (!result.key.data && signersUserID) {
try {
result.key.uri = `wkd:${signersUserID}`
result.key.data = await keys.fetchURI(result.key.uri)
result.key.data = await fetchURI(result.key.uri)
result.key.fetchMethod = 'wkd'
} catch (e) {}
}
@ -106,7 +106,7 @@ const process = async (signature) => {
try {
const match = preferredKeyServer.match(/^(.*:\/\/)?([^/]*)(?:\/)?$/i)
result.key.uri = `hkp:${match[2]}:${issuerKeyID || signersUserID}`
result.key.data = await keys.fetchURI(result.key.uri)
result.key.data = await fetchURI(result.key.uri)
result.key.fetchMethod = 'hkp'
} catch (e) {
throw new Error('Public key not found')
@ -114,7 +114,7 @@ const process = async (signature) => {
}
// Verify the signature
const verificationResult = await openpgp.verify({
const verificationResult = await verify({
// @ts-ignore
message: sigData,
verificationKeys: result.key.data
@ -158,5 +158,3 @@ const process = async (signature) => {
return result
}
exports.process = process

View file

@ -13,8 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const validator = require('validator').default
const E = require('./enums')
import isFQDN from 'validator/lib/isFQDN.js'
import { ClaimFormat } from './enums.js'
/**
* @module utils
@ -26,12 +26,13 @@ const E = require('./enums')
* @param {object} data - The data the proxy must provide to the fetcher
* @param {object} opts - Options to enable the request
* @param {object} opts.proxy - Proxy related options
* @param {object} opts.proxy.scheme - The scheme used by the proxy server
* @param {object} opts.proxy.hostname - The hostname of the proxy server
* @returns {string}
*/
const generateProxyURL = (type, data, opts) => {
export function generateProxyURL (type, data, opts) {
try {
validator.isFQDN(opts.proxy.hostname)
isFQDN(opts.proxy.hostname)
} catch (err) {
throw new Error('Invalid proxy hostname')
}
@ -55,14 +56,14 @@ const generateProxyURL = (type, data, opts) => {
* @param {string} format - The claim's format (see {@link module:enums~ClaimFormat|enums.ClaimFormat})
* @returns {string}
*/
const generateClaim = (fingerprint, format) => {
export function generateClaim (fingerprint, format) {
switch (format) {
case E.ClaimFormat.URI:
case ClaimFormat.URI:
if (fingerprint.match(/^(openpgp4fpr|aspe):/)) {
return fingerprint
}
return `openpgp4fpr:${fingerprint}`
case E.ClaimFormat.FINGERPRINT:
case ClaimFormat.FINGERPRINT:
return fingerprint
default:
throw new Error('No valid claim format')
@ -74,7 +75,7 @@ const generateClaim = (fingerprint, format) => {
* @param {string} text - The text that may contain URIs
* @returns {Array<string>}
*/
const getUriFromString = (text) => {
export function getUriFromString (text) {
const re = /((([A-Za-z0-9]+:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w\-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/gi
const res = text.match(re)
@ -102,7 +103,3 @@ const getUriFromString = (text) => {
return urls
}
exports.generateProxyURL = generateProxyURL
exports.generateClaim = generateClaim
exports.getUriFromString = getUriFromString

View file

@ -13,10 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const utils = require('./utils')
const E = require('./enums')
const { bcryptVerify, argon2Verify } = require('hash-wasm')
const entities = require('entities')
import { generateClaim, getUriFromString } from './utils.js'
import { ClaimFormat, EntityEncodingFormat, ClaimRelation, ProofFormat } from './enums.js'
import { bcryptVerify, argon2Verify } from 'hash-wasm'
import { decodeHTML, decodeXML } from 'entities'
/**
* @module verifications
@ -34,25 +34,25 @@ const entities = require('entities')
* @returns {Promise<boolean>}
*/
const containsProof = async (data, params) => {
const fingerprintFormatted = utils.generateClaim(params.target, params.claimFormat)
const fingerprintURI = utils.generateClaim(params.target, E.ClaimFormat.URI)
const fingerprintFormatted = generateClaim(params.target, params.claimFormat)
const fingerprintURI = generateClaim(params.target, ClaimFormat.URI)
let result = false
// Decode eventual special entities
switch (params.proofEncodingFormat) {
case E.EntityEncodingFormat.HTML:
data = entities.decodeHTML(data)
case EntityEncodingFormat.HTML:
data = decodeHTML(data)
break
case E.EntityEncodingFormat.XML:
data = entities.decodeXML(data)
case EntityEncodingFormat.XML:
data = decodeXML(data)
break
case E.EntityEncodingFormat.PLAIN:
case EntityEncodingFormat.PLAIN:
default:
break
}
data = entities.decodeHTML(data)
data = decodeHTML(data)
// Check for plaintext proof
result = data
@ -132,7 +132,7 @@ const containsProof = async (data, params) => {
// Check for HTTP proof
if (!result) {
const uris = utils.getUriFromString(data)
const uris = getUriFromString(data)
for (let index = 0; index < uris.length; index++) {
if (result) continue
@ -207,11 +207,11 @@ const runJSON = async (proofData, checkPath, params) => {
if (checkPath.length === 0) {
switch (params.claimRelation) {
case E.ClaimRelation.ONEOF:
case ClaimRelation.ONEOF:
return await containsProof(proofData.join('|'), params)
case E.ClaimRelation.CONTAINS:
case E.ClaimRelation.EQUALS:
case ClaimRelation.CONTAINS:
case ClaimRelation.EQUALS:
default:
return await containsProof(proofData, params)
}
@ -236,7 +236,7 @@ const runJSON = async (proofData, checkPath, params) => {
* @param {string} fingerprint - The fingerprint
* @returns {Promise<object>}
*/
const run = async (proofData, claimData, fingerprint) => {
export async function run (proofData, claimData, fingerprint) {
const res = {
result: false,
completed: false,
@ -244,7 +244,7 @@ const run = async (proofData, claimData, fingerprint) => {
}
switch (claimData.proof.request.format) {
case E.ProofFormat.JSON:
case ProofFormat.JSON:
for (let index = 0; index < claimData.claim.length; index++) {
const claimMethod = claimData.claim[index]
try {
@ -264,7 +264,7 @@ const run = async (proofData, claimData, fingerprint) => {
}
res.completed = true
break
case E.ProofFormat.TEXT:
case ProofFormat.TEXT:
for (let index = 0; index < claimData.claim.length; index++) {
const claimMethod = claimData.claim[index]
try {
@ -292,5 +292,3 @@ const run = async (proofData, claimData, fingerprint) => {
return res
}
exports.run = run

View file

@ -13,12 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-as-promised'))
import { expect, use } from 'chai'
import chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
const doipjs = require('../src')
const { log } = require('console')
import { asp, Profile } from '../src/index.js'
const asp25519Uri = "aspe:domain.tld:QPRGVPJNWDXH4ESK2RYDTZJLTE"
const asp25519ProfileName = "test"
@ -33,20 +32,21 @@ const asp25519ProfileJwk = {
describe('asp.fetchASPE', () => {
it('should be a function (1 argument)', () => {
expect(doipjs.asp.fetchASPE).to.be.a('function')
expect(doipjs.asp.fetchASPE).to.have.length(1)
expect(asp.fetchASPE).to.be.a('function')
expect(asp.fetchASPE).to.have.length(1)
})
})
describe('asp.parseProfileJws', () => {
it('should be a function (2 arguments)', () => {
expect(doipjs.asp.parseProfileJws).to.be.a('function')
expect(doipjs.asp.parseProfileJws).to.have.length(2)
expect(asp.parseProfileJws).to.be.a('function')
expect(asp.parseProfileJws).to.have.length(2)
})
it('should return a valid Profile object when provided a valid JWS', async () => {
let profile = await doipjs.asp.parseProfileJws(asp25519ProfileJws, asp25519Uri)
let profile = await asp.parseProfileJws(asp25519ProfileJws, asp25519Uri)
console.log(profile);
expect(profile).to.be.instanceOf(doipjs.Profile)
expect(profile).to.be.instanceOf(Profile)
expect(profile.personas).to.be.length(1)
expect(profile.personas[0].name).to.be.equal(asp25519ProfileName)
expect(profile.personas[0].claims).to.be.length(2)

View file

@ -13,14 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
const chaiMatchPattern = require('chai-match-pattern')
chai.use(chaiMatchPattern)
chai.use(require('chai-as-promised'))
import { expect, use } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import chaiMatchPattern from 'chai-match-pattern'
use(chaiAsPromised)
use(chaiMatchPattern)
const _ = chaiMatchPattern.getLodashModule()
const doipjs = require('../src')
import { claimDefinitions } from '../src/index.js'
const pattern = {
serviceprovider: {
@ -52,12 +53,12 @@ const pattern = {
claim: _.isArray
}
doipjs.claimDefinitions.list.forEach((claimDefName, i) => {
const claimDef = doipjs.claimDefinitions.data[claimDefName]
claimDefinitions.list.forEach((claimDefName, i) => {
const claimDef = claimDefinitions.data[claimDefName]
describe(`claimDefinitions.${claimDefName}`, () => {
it('should be an object', () => {
expect(claimDef).to.be.a('object')
expect(typeof claimDef).to.equal('object')
})
it('should have a RegExp instance named "reURI"', () => {
expect(claimDef.reURI).to.be.instanceof(RegExp)

View file

@ -13,13 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-as-promised'))
import { expect, use } from 'chai'
import chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
const path = require('path')
const openpgp = require('openpgp')
const doipjs = require('../src')
import { PublicKey } from 'openpgp'
import { keys } from '../src/index.js'
const pubKeyFingerprint = "3637202523e7c1309ab79e99ef2dc5827b445f4b"
const pubKeyEmail = "test@doip.rocks"
@ -93,68 +92,68 @@ Q+AZdYCbM0hdBjP4xdKZcpqak8ksb+aQFXjGacDL/XN4VrP+tBGxkqIqreoDcgIb
describe('keys.fetch', () => {
it('should be a function (1 argument)', () => {
expect(doipjs.keys.fetch).to.be.a('function')
expect(doipjs.keys.fetch).to.have.length(1)
expect(keys.fetch).to.be.a('function')
expect(keys.fetch).to.have.length(1)
})
it('should return a Key object when provided a valid fingerprint', async () => {
expect(
await doipjs.keys.fetch(pubKeyFingerprint)
).to.be.instanceOf(openpgp.PublicKey)
await keys.fetch(pubKeyFingerprint)
).to.be.instanceOf(PublicKey)
}).timeout('12s')
it('should return a Key object when provided a valid email address', async () => {
expect(
await doipjs.keys.fetch(pubKeyEmail)
).to.be.instanceOf(openpgp.PublicKey)
await keys.fetch(pubKeyEmail)
).to.be.instanceOf(PublicKey)
}).timeout('12s')
it('should reject when provided an invalid email address', () => {
return expect(
doipjs.keys.fetch('invalid@doip.rocks')
keys.fetch('invalid@doip.rocks')
).to.eventually.be.rejectedWith('Key does not exist or could not be fetched')
}).timeout('12s')
})
describe('keys.fetchURI', () => {
it('should be a function (1 argument)', () => {
expect(doipjs.keys.fetchURI).to.be.a('function')
expect(doipjs.keys.fetchURI).to.have.length(1)
expect(keys.fetchURI).to.be.a('function')
expect(keys.fetchURI).to.have.length(1)
})
it('should return a Key object when provided a hkp: uri', async () => {
expect(
await doipjs.keys.fetchURI(`hkp:${pubKeyFingerprint}`)
).to.be.instanceOf(openpgp.PublicKey)
await keys.fetchURI(`hkp:${pubKeyFingerprint}`)
).to.be.instanceOf(PublicKey)
}).timeout('12s')
it('should reject when provided an invalid uri', () => {
return expect(
doipjs.keys.fetchURI(`inv:${pubKeyFingerprint}`)
keys.fetchURI(`inv:${pubKeyFingerprint}`)
).to.eventually.be.rejectedWith('Invalid URI protocol')
}).timeout('12s')
})
describe('keys.fetchHKP', () => {
it('should be a function (2 arguments)', () => {
expect(doipjs.keys.fetchHKP).to.be.a('function')
expect(doipjs.keys.fetchHKP).to.have.length(2)
expect(keys.fetchHKP).to.be.a('function')
expect(keys.fetchHKP).to.have.length(2)
})
it('should return a Key object when provided a valid fingerprint', async () => {
expect(await doipjs.keys.fetchHKP(pubKeyFingerprint)).to.be.instanceOf(
openpgp.PublicKey
expect(await keys.fetchHKP(pubKeyFingerprint)).to.be.instanceOf(
PublicKey
)
}).timeout('12s')
it('should return a Key object when provided a valid email address', async () => {
expect(await doipjs.keys.fetchHKP(pubKeyEmail)).to.be.instanceOf(
openpgp.PublicKey
expect(await keys.fetchHKP(pubKeyEmail)).to.be.instanceOf(
PublicKey
)
}).timeout('12s')
it('should reject when provided an invalid fingerprint', async () => {
return expect(
doipjs.keys.fetchHKP('4637202523e7c1309ab79e99ef2dc5827b445f4b')
keys.fetchHKP('4637202523e7c1309ab79e99ef2dc5827b445f4b')
).to.eventually.be.rejectedWith(
'Key does not exist or could not be fetched'
)
}).timeout('12s')
it('should reject when provided an invalid email address', async () => {
return expect(
doipjs.keys.fetchHKP('invalid@doip.rocks')
keys.fetchHKP('invalid@doip.rocks')
).to.eventually.be.rejectedWith(
'Key does not exist or could not be fetched'
)
@ -163,24 +162,24 @@ describe('keys.fetchHKP', () => {
describe('keys.fetchPlaintext', () => {
it('should be a function (1 argument)', () => {
expect(doipjs.keys.fetchPlaintext).to.be.a('function')
expect(doipjs.keys.fetchPlaintext).to.have.length(1)
expect(keys.fetchPlaintext).to.be.a('function')
expect(keys.fetchPlaintext).to.have.length(1)
})
it('should return a Key object', async () => {
expect(await doipjs.keys.fetchPlaintext(pubKeyPlaintext)).to.be.instanceOf(
openpgp.PublicKey
expect(await keys.fetchPlaintext(pubKeyPlaintext)).to.be.instanceOf(
PublicKey
)
}).timeout('12s')
})
describe('keys.process', () => {
it('should be a function (1 argument)', () => {
expect(doipjs.keys.process).to.be.a('function')
expect(doipjs.keys.process).to.have.length(1)
expect(keys.process).to.be.a('function')
expect(keys.process).to.have.length(1)
})
it('should return an object with specific keys', async () => {
const pubKey = await doipjs.keys.fetchPlaintext(pubKeyPlaintext)
const obj = await doipjs.keys.process(pubKey)
const pubKey = await keys.fetchPlaintext(pubKeyPlaintext)
const obj = await keys.process(pubKey)
expect(obj).to.have.keys([
'users',
'fingerprint',
@ -189,15 +188,15 @@ describe('keys.process', () => {
])
})
it('should ignore non-proof notations', async () => {
const pubKey = await doipjs.keys.fetchPlaintext(pubKeyWithOtherNotations)
const obj = await doipjs.keys.process(pubKey)
const pubKey = await keys.fetchPlaintext(pubKeyWithOtherNotations)
const obj = await keys.process(pubKey)
expect(obj.users).to.be.lengthOf(1)
expect(obj.users[0].claims).to.be.lengthOf(1)
expect(obj.users[0].claims[0].uri).to.be.equal('dns:yarmo.eu?type=TXT')
})
it('should properly handle revoked UIDs', async () => {
const pubKey = await doipjs.keys.fetchPlaintext(pubKeyWithRevokedUID)
const obj = await doipjs.keys.process(pubKey)
const pubKey = await keys.fetchPlaintext(pubKeyWithRevokedUID)
const obj = await keys.process(pubKey)
expect(obj.users).to.be.lengthOf(2)
expect(obj.users[0].userData.isRevoked).to.be.true
expect(obj.users[1].userData.isRevoked).to.be.false

View file

@ -13,10 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
import { expect } from 'chai'
const doipjs = require('../src')
import { signatures } from '../src/index.js'
const sigProfile = `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
@ -83,11 +82,11 @@ YCKJPotiqe50nBijHHbuABtBianiMZOm2BbaPnsmdHIX5ynWhOI8LHR1CVmTI/0o
describe('signatures.process', () => {
it('should be a function (2 arguments)', () => {
expect(doipjs.signatures.process).to.be.a('function')
expect(doipjs.signatures.process).to.have.length(1)
expect(signatures.process).to.be.a('function')
expect(signatures.process).to.have.length(1)
})
it('should verify a valid signature', async () => {
const verification = await doipjs.signatures.process(sigProfile)
const verification = await signatures.process(sigProfile)
expect(verification.fingerprint).to.be.equal(
'3637202523e7c1309ab79e99ef2dc5827b445f4b'
)
@ -95,14 +94,14 @@ describe('signatures.process', () => {
})
it('should reject an invalid signature', async () => {
return expect(
doipjs.signatures.process(invalidSigProfileMessage)
signatures.process(invalidSigProfileMessage)
).to.eventually.be.rejectedWith(
'Signature could not be verified (Signed digest did not match)'
)
})
it('should reject an invalid signature', async () => {
return expect(
doipjs.signatures.process(invalidSigProfileHash)
signatures.process(invalidSigProfileHash)
).to.eventually.be.rejectedWith(
'Signature could not be read (Ascii armor integrity check failed)'
)

View file

@ -13,10 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
import { expect } from 'chai'
const doipjs = require('../src')
import { utils, enums } from '../src/index.js'
const textWithUrls = `This is text with URLs like https://domain.tld. Ow, a trailing dot.
What about (https://between.parentheses)? What about [https://between.brackets]?
@ -28,19 +27,19 @@ const urlsFromText = ["https://domain.tld", "https://between.parentheses",
describe('utils.generateClaim', () => {
it('should be a function (2 arguments)', () => {
expect(doipjs.utils.generateClaim).to.be.a('function')
expect(doipjs.utils.generateClaim).to.have.length(2)
expect(utils.generateClaim).to.be.a('function')
expect(utils.generateClaim).to.have.length(2)
})
it('should generate a correct "uri" claim', () => {
expect(
doipjs.utils.generateClaim('123456789', doipjs.enums.ClaimFormat.URI)
utils.generateClaim('123456789', enums.ClaimFormat.URI)
).to.equal('openpgp4fpr:123456789')
})
it('should generate a correct "fingerprint" claim', () => {
expect(
doipjs.utils.generateClaim(
utils.generateClaim(
'123456789',
doipjs.enums.ClaimFormat.FINGERPRINT
enums.ClaimFormat.FINGERPRINT
)
).to.equal('123456789')
})
@ -48,8 +47,8 @@ describe('utils.generateClaim', () => {
describe('utils.generateProxyURL', () => {
it('should be a function (3 arguments)', () => {
expect(doipjs.utils.generateProxyURL).to.be.a('function')
expect(doipjs.utils.generateProxyURL).to.have.length(3)
expect(utils.generateProxyURL).to.be.a('function')
expect(utils.generateProxyURL).to.have.length(3)
})
it('should generate correct proxy URLs for explicit https scheme', () => {
const opts = {
@ -59,10 +58,10 @@ describe('utils.generateProxyURL', () => {
},
}
expect(
doipjs.utils.generateProxyURL('http', { domain: 'domain.org' }, opts)
utils.generateProxyURL('http', { domain: 'domain.org' }, opts)
).to.equal('https://localhost/api/2/get/http?domain=domain.org')
expect(
doipjs.utils.generateProxyURL('dns', { domain: 'domain.org' }, opts)
utils.generateProxyURL('dns', { domain: 'domain.org' }, opts)
).to.equal('https://localhost/api/2/get/dns?domain=domain.org')
})
it('should generate correct proxy URLs for explicit http scheme', () => {
@ -73,10 +72,10 @@ describe('utils.generateProxyURL', () => {
},
}
expect(
doipjs.utils.generateProxyURL('http', { domain: 'domain.org' }, opts)
utils.generateProxyURL('http', { domain: 'domain.org' }, opts)
).to.equal('http://localhost/api/2/get/http?domain=domain.org')
expect(
doipjs.utils.generateProxyURL('dns', { domain: 'domain.org' }, opts)
utils.generateProxyURL('dns', { domain: 'domain.org' }, opts)
).to.equal('http://localhost/api/2/get/dns?domain=domain.org')
})
it('should generate correct proxy URLs for default scheme', () => {
@ -86,10 +85,10 @@ describe('utils.generateProxyURL', () => {
},
}
expect(
doipjs.utils.generateProxyURL('http', { domain: 'domain.org' }, opts)
utils.generateProxyURL('http', { domain: 'domain.org' }, opts)
).to.equal('https://localhost/api/2/get/http?domain=domain.org')
expect(
doipjs.utils.generateProxyURL('dns', { domain: 'domain.org' }, opts)
utils.generateProxyURL('dns', { domain: 'domain.org' }, opts)
).to.equal('https://localhost/api/2/get/dns?domain=domain.org')
})
@ -98,12 +97,12 @@ describe('utils.generateProxyURL', () => {
describe('utils.getUriFromString', () => {
it('should be a function (1 arguments)', () => {
expect(doipjs.utils.getUriFromString).to.be.a('function')
expect(doipjs.utils.getUriFromString).to.have.length(1)
expect(utils.getUriFromString).to.be.a('function')
expect(utils.getUriFromString).to.have.length(1)
})
it('should extract URLs from text', () => {
expect(
doipjs.utils.getUriFromString(textWithUrls)
utils.getUriFromString(textWithUrls)
).to.have.length(urlsFromText.length)
})
// TODO Properly check each URL

View file

@ -13,11 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-as-promised'))
import { expect, use } from 'chai'
import chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
const doipjs = require('../src')
import { claimDefinitions, verifications } from '../src/index.js'
const fingerprint = '3637202523e7c1309ab79e99ef2dc5827b445f4b'
const plaintextCorrectProofData = [
@ -44,40 +44,40 @@ const bcryptIncorrectProofData = [
const bcryptCostlyProofData = [
'$2y$16$4Knuu11ZyPXa1qxEbEsKQemKY6ZHM8Bk7WElYfL8q5kmzNjY1Ty8W'
]
const claimData = doipjs.claimDefinitions.data.irc.processURI('irc://domain.tld/test')
const claimData = claimDefinitions.data.irc.processURI('irc://domain.tld/test')
describe('verifications.run', () => {
it('should verify a plaintext proof', async () => {
const result = await doipjs.verifications.run(plaintextCorrectProofData, claimData, fingerprint)
const result = await verifications.run(plaintextCorrectProofData, claimData, fingerprint)
expect(result.result).to.be.true
})
// issue #22
it('should handle a plaintext proof with whitespace', async () => {
const result = await doipjs.verifications.run(plaintextCorrectProofDataWithWhitespace, claimData, fingerprint)
const result = await verifications.run(plaintextCorrectProofDataWithWhitespace, claimData, fingerprint)
expect(result.result).to.be.true
})
it('should reject a wrong plaintext proof', async () => {
const result = await doipjs.verifications.run(plaintextIncorrectProofData, claimData, fingerprint)
const result = await verifications.run(plaintextIncorrectProofData, claimData, fingerprint)
expect(result.result).to.be.false
})
it('should verify a argon2-hashed proof', async () => {
const result = await doipjs.verifications.run(argon2CorrectProofData, claimData, fingerprint)
const result = await verifications.run(argon2CorrectProofData, claimData, fingerprint)
expect(result.result).to.be.true
})
it('should reject a wrong argon2-hashed proof', async () => {
const result = await doipjs.verifications.run(argon2IncorrectProofData, claimData, fingerprint)
const result = await verifications.run(argon2IncorrectProofData, claimData, fingerprint)
expect(result.result).to.be.false
})
it('should verify a bcrypt-hashed proof', async () => {
const result = await doipjs.verifications.run(bcryptCorrectProofData, claimData, fingerprint)
const result = await verifications.run(bcryptCorrectProofData, claimData, fingerprint)
expect(result.result).to.be.true
})
it('should reject a wrong bcrypt-hashed proof', async () => {
const result = await doipjs.verifications.run(bcryptIncorrectProofData, claimData, fingerprint)
const result = await verifications.run(bcryptIncorrectProofData, claimData, fingerprint)
expect(result.result).to.be.false
})
it('should reject a too costly hashed proof', async () => {
const result = await doipjs.verifications.run(bcryptCostlyProofData, claimData, fingerprint)
const result = await verifications.run(bcryptCostlyProofData, claimData, fingerprint)
expect(result.result).to.be.false
})
})