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 () => { const main = async () => {
// Fetch the key using HKP // 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 () => { const main = async () => {
// Obtain the plaintext public key // 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 () => { const main = async () => {
// Fetch the key using WKD // 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 () => { const main = async () => {
// Fetch the profile using ASPE // 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----- const signature = `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512 Hash: SHA512

View file

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

View file

@ -2,6 +2,7 @@
"name": "doipjs", "name": "doipjs",
"version": "0.19.0", "version": "0.19.0",
"description": "Decentralized Online Identity Proofs library in Node.js", "description": "Decentralized Online Identity Proofs library in Node.js",
"type": "module",
"main": "./src/index.js", "main": "./src/index.js",
"packageManager": "yarn@1.22.19", "packageManager": "yarn@1.22.19",
"dependencies": { "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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
const jose = require('jose') import { decodeProtectedHeader, importJWK, compactVerify, calculateJwkThumbprint } from 'jose'
const { base32, base64url } = require('rfc4648') import { base32, base64url } from 'rfc4648'
const Claim = require('./claim') import { Claim } from './claim.js'
const Persona = require('./persona') import { Persona } from './persona.js'
const Profile = require('./profile') import { Profile } from './profile.js'
const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512'] const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512']
@ -35,7 +35,7 @@ const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512']
* @example * @example
* const key = doip.aspe.fetchASPE('aspe:domain.tld:1234567890'); * const key = doip.aspe.fetchASPE('aspe:domain.tld:1234567890');
*/ */
const fetchASPE = async uri => { export async function fetchASPE (uri) {
const re = /aspe:(.*):(.*)/ const re = /aspe:(.*):(.*)/
if (!re.test(uri)) { if (!re.test(uri)) {
@ -78,12 +78,12 @@ const fetchASPE = async uri => {
* @example * @example
* const key = doip.aspe.parseProfileJws('...'); * const key = doip.aspe.parseProfileJws('...');
*/ */
const parseProfileJws = async (profileJws, uri) => { export async function parseProfileJws (profileJws, uri) {
const matches = uri.match(/aspe:(.*):(.*)/) const matches = uri.match(/aspe:(.*):(.*)/)
const localPart = matches[2].toUpperCase() const localPart = matches[2].toUpperCase()
// Decode the headers // Decode the headers
const protectedHeader = jose.decodeProtectedHeader(profileJws) const protectedHeader = decodeProtectedHeader(profileJws)
// Extract the JWK // Extract the JWK
if (!SupportedCryptoAlg.includes(protectedHeader.alg)) { if (!SupportedCryptoAlg.includes(protectedHeader.alg)) {
@ -95,7 +95,7 @@ const parseProfileJws = async (profileJws, uri) => {
if (!protectedHeader.jwk) { if (!protectedHeader.jwk) {
throw new Error('Invalid profile JWS: missing key') 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 // Compute and verify the fingerprint
const fp = await computeJwkFingerprint(protectedHeader.jwk) const fp = await computeJwkFingerprint(protectedHeader.jwk)
@ -108,7 +108,7 @@ const parseProfileJws = async (profileJws, uri) => {
} }
// Decode the payload // Decode the payload
const { payload } = await jose.compactVerify(profileJws, publicKey) const { payload } = await compactVerify(profileJws, publicKey)
const payloadJson = JSON.parse(new TextDecoder().decode(payload)) const payloadJson = JSON.parse(new TextDecoder().decode(payload))
// Verify the payload // Verify the payload
@ -139,16 +139,13 @@ const parseProfileJws = async (profileJws, uri) => {
/** /**
* Compute the fingerprint for JWK keys * Compute the fingerprint for JWK keys
* @function * @function
* @param {jose.JWK} key * @param {import('jose').JWK} key
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
const computeJwkFingerprint = async key => { export async function computeJwkFingerprint (key) {
const thumbprint = await jose.calculateJwkThumbprint(key, 'sha512') const thumbprint = await calculateJwkThumbprint(key, 'sha512')
const fingerprintBytes = base64url.parse(thumbprint, { loose: true }).slice(0, 16) const fingerprintBytes = base64url.parse(thumbprint, { loose: true }).slice(0, 16)
const fingerprint = base32.stringify(fingerprintBytes, { pad: false }) const fingerprint = base32.stringify(fingerprintBytes, { pad: false })
return fingerprint 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const validator = require('validator').default import isAlphanumeric from 'validator/lib/isAlphanumeric.js'
const validUrl = require('valid-url') import { isUri } from 'valid-url'
const mergeOptions = require('merge-options') import mergeOptions from 'merge-options'
const proofs = require('./proofs') import { fetch } from './proofs.js'
const verifications = require('./verifications') import { run } from './verifications.js'
const claimDefinitions = require('./claimDefinitions') import { list, data as _data } from './claimDefinitions/index.js'
const defaults = require('./defaults') import { opts as _opts } from './defaults.js'
const E = require('./enums') import { ClaimStatus } from './enums.js'
/** /**
* @class * @class
@ -31,7 +31,7 @@ const E = require('./enums')
* @property {Array<object>} matches - The claim definitions matched against the URI * @property {Array<object>} matches - The claim definitions matched against the URI
* @property {object} verification - The result of the verification process * @property {object} verification - The result of the verification process
*/ */
class Claim { export class Claim {
/** /**
* Initialize a Claim object * Initialize a Claim object
* @constructor * @constructor
@ -63,14 +63,15 @@ class Claim {
} }
// Verify validity of URI // Verify validity of URI
if (uri && !validUrl.isUri(uri)) { if (uri && !isUri(uri)) {
throw new Error('Invalid URI') throw new Error('Invalid URI')
} }
// Verify validity of fingerprint // Verify validity of fingerprint
if (fingerprint) { if (fingerprint) {
try { try {
validator.isAlphanumeric(fingerprint) // @ts-ignore
isAlphanumeric.default(fingerprint)
} catch (err) { } catch (err) {
throw new Error('Invalid fingerprint') throw new Error('Invalid fingerprint')
} }
@ -78,7 +79,7 @@ class Claim {
this._uri = uri || '' this._uri = uri || ''
this._fingerprint = fingerprint || '' this._fingerprint = fingerprint || ''
this._status = E.ClaimStatus.INIT this._status = ClaimStatus.INIT
this._matches = [] this._matches = []
this._verification = {} this._verification = {}
} }
@ -96,27 +97,27 @@ class Claim {
} }
get matches () { get matches () {
if (this._status === E.ClaimStatus.INIT) { if (this._status === ClaimStatus.INIT) {
throw new Error('This claim has not yet been matched') throw new Error('This claim has not yet been matched')
} }
return this._matches return this._matches
} }
get verification () { get verification () {
if (this._status !== E.ClaimStatus.VERIFIED) { if (this._status !== ClaimStatus.VERIFIED) {
throw new Error('This claim has not yet been verified') throw new Error('This claim has not yet been verified')
} }
return this._verification return this._verification
} }
set uri (uri) { set uri (uri) {
if (this._status !== E.ClaimStatus.INIT) { if (this._status !== ClaimStatus.INIT) {
throw new Error( throw new Error(
'Cannot change the URI, this claim has already been matched' 'Cannot change the URI, this claim has already been matched'
) )
} }
// Verify validity of URI // Verify validity of URI
if (uri.length > 0 && !validUrl.isUri(uri)) { if (uri.length > 0 && !isUri(uri)) {
throw new Error('The URI was invalid') throw new Error('The URI was invalid')
} }
// Remove leading and trailing spaces // Remove leading and trailing spaces
@ -126,7 +127,7 @@ class Claim {
} }
set fingerprint (fingerprint) { set fingerprint (fingerprint) {
if (this._status === E.ClaimStatus.VERIFIED) { if (this._status === ClaimStatus.VERIFIED) {
throw new Error( throw new Error(
'Cannot change the fingerprint, this claim has already been verified' 'Cannot change the fingerprint, this claim has already been verified'
) )
@ -151,17 +152,17 @@ class Claim {
* @function * @function
*/ */
match () { match () {
if (this._status !== E.ClaimStatus.INIT) { if (this._status !== ClaimStatus.INIT) {
throw new Error('This claim was already matched') 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') throw new Error('This claim has no URI')
} }
this._matches = [] this._matches = []
claimDefinitions.list.every((name, i) => { list.every((name, i) => {
const def = claimDefinitions.data[name] const def = _data[name]
// If the candidate is invalid, continue matching // If the candidate is invalid, continue matching
if (!def.reURI.test(this._uri)) { if (!def.reURI.test(this._uri)) {
@ -187,7 +188,7 @@ class Claim {
return true return true
}) })
this._status = E.ClaimStatus.MATCHED this._status = ClaimStatus.MATCHED
} }
/** /**
@ -200,10 +201,10 @@ class Claim {
* @param {object} [opts] - Options for proxy, fetchers * @param {object} [opts] - Options for proxy, fetchers
*/ */
async verify (opts) { async verify (opts) {
if (this._status === E.ClaimStatus.INIT) { if (this._status === ClaimStatus.INIT) {
throw new Error('This claim has not yet been matched') 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') throw new Error('This claim has already been verified')
} }
if (this._fingerprint.length === 0) { if (this._fingerprint.length === 0) {
@ -211,7 +212,7 @@ class Claim {
} }
// Handle options // Handle options
opts = mergeOptions(defaults.opts, opts || {}) opts = mergeOptions(_opts, opts || {})
// If there are no matches // If there are no matches
if (this._matches.length === 0) { if (this._matches.length === 0) {
@ -232,14 +233,14 @@ class Claim {
let proofFetchError let proofFetchError
try { try {
proofData = await proofs.fetch(claimData, opts) proofData = await fetch(claimData, opts)
} catch (err) { } catch (err) {
proofFetchError = err proofFetchError = err
} }
if (proofData) { if (proofData) {
// Run the verification process // Run the verification process
verificationResult = await verifications.run( verificationResult = await run(
proofData.result, proofData.result,
claimData, claimData,
this._fingerprint this._fingerprint
@ -250,7 +251,7 @@ class Claim {
} }
// Post process the data // Post process the data
const def = claimDefinitions.data[claimData.serviceprovider.name] const def = _data[claimData.serviceprovider.name]
if (def.functions?.postprocess) { if (def.functions?.postprocess) {
try { try {
({ claimData, proofData } = def.functions.postprocess(claimData, proofData)) ({ claimData, proofData } = def.functions.postprocess(claimData, proofData))
@ -289,7 +290,7 @@ class Claim {
errors: [] errors: []
} }
this._status = E.ClaimStatus.VERIFIED this._status = ClaimStatus.VERIFIED
} }
/** /**
@ -300,7 +301,7 @@ class Claim {
* @returns {boolean} * @returns {boolean}
*/ */
isAmbiguous () { isAmbiguous () {
if (this._status === E.ClaimStatus.INIT) { if (this._status === ClaimStatus.INIT) {
throw new Error('The claim has not been matched yet') throw new Error('The claim has not been matched yet')
} }
if (this._matches.length === 0) { 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 See the License for the specific language governing permissions and
limitations under the License. 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 { return {
serviceprovider: { serviceprovider: {
type: 'web', type: 'web',
@ -66,14 +70,14 @@ const processURI = (uri) => {
} }
} }
const functions = { export const functions = {
postprocess: (claimData, proofData) => { postprocess: (claimData, proofData) => {
claimData.profile.display = `@${proofData.result.preferredUsername}@${new URL(proofData.result.url).hostname}` claimData.profile.display = `@${proofData.result.preferredUsername}@${new URL(proofData.result.url).hostname}`
return { claimData, proofData } return { claimData, proofData }
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://domain.org', uri: 'https://domain.org',
shouldMatch: true shouldMatch: true
@ -107,8 +111,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://domain.org/u/alice', uri: 'https://domain.org/u/alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -54,7 +58,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'dns:domain.org', uri: 'dns:domain.org',
shouldMatch: true shouldMatch: true
@ -68,7 +72,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://domain.org/alice/post', uri: 'https://domain.org/alice/post',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://domain.org/alice/forgejo_proof', uri: 'https://domain.org/alice/forgejo_proof',
shouldMatch: true shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://domain.org/alice/gitea_proof', uri: 'https://domain.org/alice/gitea_proof',
shouldMatch: true shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://gist.github.com/Alice/123456789', uri: 'https://gist.github.com/Alice/123456789',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://gitlab.domain.org/alice/gitlab_proof', uri: 'https://gitlab.domain.org/alice/gitlab_proof',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://news.ycombinator.com/user?id=Alice', uri: 'https://news.ycombinator.com/user?id=Alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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 = { const _data = {
dns: require('./dns'), dns,
irc: require('./irc'), irc,
xmpp: require('./xmpp'), xmpp,
matrix: require('./matrix'), matrix,
telegram: require('./telegram'), telegram,
twitter: require('./twitter'), twitter,
reddit: require('./reddit'), reddit,
liberapay: require('./liberapay'), liberapay,
lichess: require('./lichess'), lichess,
hackernews: require('./hackernews'), hackernews,
lobsters: require('./lobsters'), lobsters,
forem: require('./forem'), forem,
// forgejo: require('./forgejo'), // forgejo,
gitea: require('./gitea'), gitea,
gitlab: require('./gitlab'), gitlab,
github: require('./github'), github,
activitypub: require('./activitypub'), activitypub,
discourse: require('./discourse'), discourse,
owncast: require('./owncast'), owncast,
stackexchange: require('./stackexchange'), stackexchange,
keybase: require('./keybase'), keybase,
opencollective: require('./opencollective') opencollective
} }
exports.list = Object.keys(data) export const list = Object.keys(_data)
exports.data = 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'irc://chat.ircserver.org/Alice1', uri: 'irc://chat.ircserver.org/Alice1',
shouldMatch: true shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://keybase.io/Alice', uri: 'https://keybase.io/Alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://liberapay.com/alice', uri: 'https://liberapay.com/alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://lichess.org/@/Alice', uri: 'https://lichess.org/@/Alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://lobste.rs/u/Alice', uri: 'https://lobste.rs/u/Alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
if (!match[2]) { if (!match[2]) {
@ -71,7 +75,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: uri:
'matrix:u/alice:matrix.domain.org?org.keyoxide.r=123:domain.org&org.keyoxide.e=123', 'matrix:u/alice:matrix.domain.org?org.keyoxide.r=123:domain.org&org.keyoxide.e=123',
@ -95,7 +99,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://opencollective.com/Alice', uri: 'https://opencollective.com/Alice',
shouldMatch: true shouldMatch: true
@ -69,7 +73,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://live.domain.org', uri: 'https://live.domain.org',
shouldMatch: true shouldMatch: true
@ -73,7 +77,3 @@ const tests = [
shouldMatch: true 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://www.reddit.com/user/Alice/comments/123456/post', uri: 'https://www.reddit.com/user/Alice/comments/123456/post',
shouldMatch: true shouldMatch: true
@ -77,7 +81,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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 reStackExchange = /\.stackexchange$/
const processURI = (uri) => { /**
* @function
* @param {string} uri
*/
export function processURI (uri) {
const [, domain, id] = uri.match(reURI) const [, domain, id] = uri.match(reURI)
const site = domain.replace(reStackExchange, '') const site = domain.replace(reStackExchange, '')
@ -57,7 +61,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://stackoverflow.com/users/1234', uri: 'https://stackoverflow.com/users/1234',
shouldMatch: true 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -55,7 +59,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://t.me/alice?proof=foobar', uri: 'https://t.me/alice?proof=foobar',
shouldMatch: true shouldMatch: true
@ -77,7 +81,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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 match = uri.match(reURI)
const urlsp = new URLSearchParams()
urlsp.set('url', match[0])
urlsp.set('omit_script', '1')
return { return {
serviceprovider: { serviceprovider: {
type: 'web', type: 'web',
@ -42,7 +50,7 @@ const processURI = (uri) => {
format: E.ProofFormat.JSON, format: E.ProofFormat.JSON,
data: { data: {
// Returns an oembed json object with the tweet content in html form // 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 format: E.ProofFormat.JSON
} }
} }
@ -56,7 +64,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'https://twitter.com/alice/status/1234567890123456789', uri: 'https://twitter.com/alice/status/1234567890123456789',
shouldMatch: true shouldMatch: true
@ -70,7 +78,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. 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) const match = uri.match(reURI)
return { return {
@ -54,7 +58,7 @@ const processURI = (uri) => {
} }
} }
const tests = [ export const tests = [
{ {
uri: 'xmpp:alice@domain.org', uri: 'xmpp:alice@domain.org',
shouldMatch: true shouldMatch: true
@ -68,7 +72,3 @@ const tests = [
shouldMatch: false 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const E = require('./enums') import { ProxyPolicy } from './enums.js'
/** /**
* Contains default values * 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.username - The username used to log in
* @property {string|null} claims.xmpp.password - The password used to log in * @property {string|null} claims.xmpp.password - The password used to log in
*/ */
const opts = { export const opts = {
proxy: { proxy: {
hostname: null, hostname: null,
policy: E.ProxyPolicy.NEVER policy: ProxyPolicy.NEVER
}, },
claims: { claims: {
activitypub: { activitypub: {
@ -69,5 +69,3 @@ const opts = {
} }
} }
} }
exports.opts = opts

View file

@ -23,7 +23,7 @@ limitations under the License.
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const ProxyPolicy = { export const ProxyPolicy = {
/** Proxy usage decision depends on environment and service provider */ /** Proxy usage decision depends on environment and service provider */
ADAPTIVE: 'adaptive', ADAPTIVE: 'adaptive',
/** Always use a proxy */ /** Always use a proxy */
@ -31,14 +31,13 @@ const ProxyPolicy = {
/** Never use a proxy, skip a verification if a proxy is inevitable */ /** Never use a proxy, skip a verification if a proxy is inevitable */
NEVER: 'never' NEVER: 'never'
} }
Object.freeze(ProxyPolicy)
/** /**
* Methods for fetching proofs * Methods for fetching proofs
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const Fetcher = { export const Fetcher = {
/** HTTP requests to ActivityPub */ /** HTTP requests to ActivityPub */
ACTIVITYPUB: 'activitypub', ACTIVITYPUB: 'activitypub',
/** DNS module from Node.js */ /** DNS module from Node.js */
@ -56,14 +55,13 @@ const Fetcher = {
/** XMPP module from Node.js */ /** XMPP module from Node.js */
XMPP: 'xmpp' XMPP: 'xmpp'
} }
Object.freeze(Fetcher)
/** /**
* Entity encoding format * Entity encoding format
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const EntityEncodingFormat = { export const EntityEncodingFormat = {
/** No special formatting */ /** No special formatting */
PLAIN: 'plain', PLAIN: 'plain',
/** HTML encoded entities */ /** HTML encoded entities */
@ -71,14 +69,13 @@ const EntityEncodingFormat = {
/** XML encoded entities */ /** XML encoded entities */
XML: 'xml' XML: 'xml'
} }
Object.freeze(EntityEncodingFormat)
/** /**
* Levels of access restriction for proof fetching * Levels of access restriction for proof fetching
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const ProofAccess = { export const ProofAccess = {
/** Any HTTP request will work */ /** Any HTTP request will work */
GENERIC: 'generic', GENERIC: 'generic',
/** CORS requests are denied */ /** CORS requests are denied */
@ -88,40 +85,37 @@ const ProofAccess = {
/** Not accessible by HTTP request, needs server software */ /** Not accessible by HTTP request, needs server software */
SERVER: 'server' SERVER: 'server'
} }
Object.freeze(ProofAccess)
/** /**
* Format of proof * Format of proof
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const ProofFormat = { export const ProofFormat = {
/** JSON format */ /** JSON format */
JSON: 'json', JSON: 'json',
/** Plaintext format */ /** Plaintext format */
TEXT: 'text' TEXT: 'text'
} }
Object.freeze(ProofFormat)
/** /**
* Format of claim * Format of claim
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const ClaimFormat = { export const ClaimFormat = {
/** `openpgp4fpr:123123123` */ /** `openpgp4fpr:123123123` */
URI: 'uri', URI: 'uri',
/** `123123123` */ /** `123123123` */
FINGERPRINT: 'fingerprint' FINGERPRINT: 'fingerprint'
} }
Object.freeze(ClaimFormat)
/** /**
* How to find the claim inside the proof's JSON data * How to find the claim inside the proof's JSON data
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const ClaimRelation = { export const ClaimRelation = {
/** Claim is somewhere in the JSON field's textual content */ /** Claim is somewhere in the JSON field's textual content */
CONTAINS: 'contains', CONTAINS: 'contains',
/** Claim is equal to the JSON field's textual content */ /** 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 */ /** Claim is equal to an element of the JSON field's array of strings */
ONEOF: 'oneof' ONEOF: 'oneof'
} }
Object.freeze(ClaimRelation)
/** /**
* Status of the Claim instance * Status of the Claim instance
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */
const ClaimStatus = { export const ClaimStatus = {
/** Claim has been initialized */ /** Claim has been initialized */
INIT: 'init', INIT: 'init',
/** Claim has matched its URI to candidate claim definitions */ /** Claim has matched its URI to candidate claim definitions */
@ -144,13 +137,3 @@ const ClaimStatus = {
/** Claim has verified one or multiple candidate claim definitions */ /** Claim has verified one or multiple candidate claim definitions */
VERIFIED: 'verified' 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
const validator = require('validator').default import isURL from 'validator/lib/isURL.js'
const jsEnv = require('browser-or-node') import { isNode } from 'browser-or-node'
import crypto from 'crypto'
import { version } from '../constants.js'
/** export const timeout = 5000
* @module fetcher/activitypub
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
/** /**
* Execute a fetch request * 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 * @param {string} opts.claims.activitypub.privateKey - The private key to sign the request
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
let crypto
if (jsEnv.isNode) {
crypto = require('crypto')
}
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => 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 () => { (async () => {
let isConfigured = false let isConfigured = false
try { try {
validator.isURL(opts.claims.activitypub.url) isURL(opts.claims.activitypub.url)
isConfigured = true isConfigured = true
} catch (_) {} } catch (_) {}
@ -71,10 +60,10 @@ module.exports.fn = async (data, opts) => {
date: now.toUTCString(), date: now.toUTCString(),
accept: 'application/activity+json', accept: 'application/activity+json',
// @ts-ignore // @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}` 'User-Agent': `doipjs/${version}`
} }
if (isConfigured && jsEnv.isNode) { if (isConfigured && isNode) {
// Generate the signature // Generate the signature
const signedString = `(request-target): get ${pathname}${search}\nhost: ${host}\ndate: ${now.toUTCString()}` const signedString = `(request-target): get ${pathname}${search}\nhost: ${host}\ndate: ${now.toUTCString()}`
const sign = crypto.createSign('SHA256') const sign = crypto.createSign('SHA256')

View file

@ -13,20 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const jsEnv = require('browser-or-node') import { isBrowser } from 'browser-or-node'
import dns from 'dns'
/** export const timeout = 5000
* @module fetcher/dns
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
if (jsEnv.isNode) {
const dns = require('dns')
/** /**
* Execute a fetch request * Execute a fetch request
@ -37,12 +27,16 @@ if (jsEnv.isNode) {
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
if (isBrowser) {
return null
}
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout data.fetcherTimeout ? data.fetcherTimeout : timeout
) )
}) })
@ -67,6 +61,3 @@ if (jsEnv.isNode) {
return result return result
}) })
} }
} else {
module.exports.fn = null
}

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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
import { version } from '../constants.js'
/** export const timeout = 5000
* @module fetcher/graphql
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
/** /**
* Execute a GraphQL query via HTTP request * Execute a GraphQL query via HTTP request
@ -35,12 +28,12 @@ module.exports.timeout = 5000
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object|string>} * @returns {Promise<object|string>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => 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: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// @ts-ignore // @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}` 'User-Agent': `doipjs/${version}`
}, },
validateStatus: function (status) { validateStatus: function (status) {
return status >= 200 && status < 400 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
const E = require('../enums') import { ProofFormat } from '../enums.js'
import { version } from '../constants.js'
/** export const timeout = 5000
* @module fetcher/http
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
@ -36,12 +29,12 @@ module.exports.timeout = 5000
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object|string>} * @returns {Promise<object|string>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => 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) { switch (data.format) {
case E.ProofFormat.JSON: case ProofFormat.JSON:
axios.get(data.url, { axios.get(data.url, {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
// @ts-ignore // @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}` 'User-Agent': `doipjs/${version}`
}, },
validateStatus: function (status) { validateStatus: function (status) {
return status >= 200 && status < 400 return status >= 200 && status < 400
@ -70,7 +63,7 @@ module.exports.fn = async (data, opts) => {
reject(e) reject(e)
}) })
break break
case E.ProofFormat.TEXT: case ProofFormat.TEXT:
axios.get(data.url, { axios.get(data.url, {
validateStatus: function (status) { validateStatus: function (status) {
return status >= 200 && status < 400 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import dotenv from 'dotenv'
dotenv.config()
exports.activitypub = require('./activitypub') export * as activitypub from './activitypub.js'
exports.dns = require('./dns') export * as dns from './dns.js'
exports.graphql = require('./graphql') export * as graphql from './graphql.js'
exports.http = require('./http') export * as http from './http.js'
exports.irc = require('./irc') export * as irc from './irc.js'
exports.matrix = require('./matrix') export * as matrix from './matrix.js'
exports.telegram = require('./telegram') export * as telegram from './telegram.js'
exports.xmpp = require('./xmpp') 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,21 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
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
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 20000
if (jsEnv.isNode) {
const irc = require('irc-upd')
const validator = require('validator').default
/** /**
* Execute a fetch request * Execute a fetch request
@ -43,18 +32,18 @@ if (jsEnv.isNode) {
* @param {string} opts.claims.irc.nick - The nick to be used by the library to log in * @param {string} opts.claims.irc.nick - The nick to be used by the library to log in
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => 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) => { const fetchPromise = new Promise((resolve, reject) => {
try { try {
validator.isAscii(opts.claims.irc.nick) isAscii(opts.claims.irc.nick)
} catch (err) { } catch (err) {
throw new Error(`IRC fetcher was not set up properly (${err.message})`) throw new Error(`IRC fetcher was not set up properly (${err.message})`)
} }
@ -96,6 +85,3 @@ if (jsEnv.isNode) {
return result return result
}) })
} }
} else {
module.exports.fn = null
}

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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
const validator = require('validator').default import isFQDN from 'validator/lib/isFQDN.js'
import isAscii from 'validator/lib/isAscii.js'
import { version } from '../constants.js'
/** export const timeout = 5000
* @module fetcher/matrix
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
/** /**
* Execute a fetch request * 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}) * @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>} * @returns {Promise<object>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => 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) => { const fetchPromise = new Promise((resolve, reject) => {
try { try {
validator.isFQDN(opts.claims.matrix.instance) isFQDN(opts.claims.matrix.instance)
validator.isAscii(opts.claims.matrix.accessToken) isAscii(opts.claims.matrix.accessToken)
} catch (err) { } catch (err) {
throw new Error(`Matrix fetcher was not set up properly (${err.message})`) throw new Error(`Matrix fetcher was not set up properly (${err.message})`)
} }
@ -64,7 +58,7 @@ module.exports.fn = async (data, opts) => {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
// @ts-ignore // @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}` 'User-Agent': `doipjs/${version}`
} }
}) })
.then(res => { .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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
const validator = require('validator').default import isAscii from 'validator/lib/isAscii.js'
import { version } from '../constants.js'
/** export const timeout = 5000
* @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
/** /**
* Execute a fetch request * Execute a fetch request
@ -41,18 +33,18 @@ module.exports.timeout = 5000
* @param {string} opts.claims.telegram.token - The Telegram Bot API token * @param {string} opts.claims.telegram.token - The Telegram Bot API token
* @returns {Promise<object|string>} * @returns {Promise<object|string>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => 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) => { const apiPromise = (/** @type {string} */ method) => new Promise((resolve, reject) => {
try { try {
validator.isAscii(opts.claims.telegram.token) isAscii(opts.claims.telegram.token)
} catch (err) { } catch (err) {
throw new Error(`Telegram fetcher was not set up properly (${err.message})`) throw new Error(`Telegram fetcher was not set up properly (${err.message})`)
} }
@ -67,7 +59,7 @@ module.exports.fn = async (data, opts) => {
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
// @ts-ignore // @ts-ignore
'User-Agent': `doipjs/${require('../../package.json').version}` 'User-Agent': `doipjs/${version}`
}, },
validateStatus: (status) => status === 200 validateStatus: (status) => status === 200
}) })

View file

@ -13,22 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
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'
/** export const timeout = 5000
* @module fetcher/xmpp
*/
/**
* The request's timeout value in milliseconds
* @constant {number} timeout
*/
module.exports.timeout = 5000
if (jsEnv.isNode) {
const { client, xml } = require('@xmpp/client')
const debug = require('@xmpp/debug')
const validator = require('validator').default
let xmpp = null let xmpp = null
let iqCaller = null let iqCaller = null
@ -69,11 +59,11 @@ if (jsEnv.isNode) {
* @param {string} opts.claims.xmpp.password - The password used to log in * @param {string} opts.claims.xmpp.password - The password used to log in
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
module.exports.fn = async (data, opts) => { export async function fn (data, opts) {
try { try {
validator.isFQDN(opts.claims.xmpp.service) isFQDN(opts.claims.xmpp.service)
validator.isAscii(opts.claims.xmpp.username) isAscii(opts.claims.xmpp.username)
validator.isAscii(opts.claims.xmpp.password) isAscii(opts.claims.xmpp.password)
} catch (err) { } catch (err) {
throw new Error(`XMPP fetcher was not set up properly (${err.message})`) throw new Error(`XMPP fetcher was not set up properly (${err.message})`)
} }
@ -92,7 +82,7 @@ if (jsEnv.isNode) {
const timeoutPromise = new Promise((resolve, reject) => { const timeoutPromise = new Promise((resolve, reject) => {
timeoutHandle = setTimeout( timeoutHandle = setTimeout(
() => reject(new Error('Request was timed out')), () => reject(new Error('Request was timed out')),
data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout data.fetcherTimeout ? data.fetcherTimeout : timeout
) )
}) })
@ -191,6 +181,3 @@ if (jsEnv.isNode) {
return result return result
}) })
} }
} else {
module.exports.fn = null
}

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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const Profile = require('./profile') export { Profile } from './profile.js'
const Persona = require('./persona') export { Persona } from './persona.js'
const Claim = require('./claim') export { Claim } from './claim.js'
const claimDefinitions = require('./claimDefinitions') export * as claimDefinitions from './claimDefinitions/index.js'
const proofs = require('./proofs') export * as proofs from './proofs.js'
const keys = require('./keys') export * as keys from './keys.js'
const asp = require('./asp') export * as asp from './asp.js'
const signatures = require('./signatures') export * as signatures from './signatures.js'
const enums = require('./enums') export * as enums from './enums.js'
const defaults = require('./defaults') export * as defaults from './defaults.js'
const utils = require('./utils') export * as utils from './utils.js'
const verifications = require('./verifications') export * as verifications from './verifications.js'
const fetcher = require('./fetcher') export * as fetcher from './fetcher/index.js'
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

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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const axios = require('axios').default import axios from 'axios'
const validUrl = require('valid-url') import { isUri } from 'valid-url'
const openpgp = require('openpgp') import { readKey, PublicKey } from 'openpgp'
const HKP = require('@openpgp/hkp-client') import HKP from '@openpgp/hkp-client'
const WKD = require('@openpgp/wkd-client') import WKD from '@openpgp/wkd-client'
const Claim = require('./claim') import { Claim } from './claim.js'
/** /**
* Functions related to the fetching and handling of keys * Functions related to the fetching and handling of keys
@ -30,12 +30,12 @@ const Claim = require('./claim')
* @function * @function
* @param {string} identifier - Fingerprint or email address * @param {string} identifier - Fingerprint or email address
* @param {string} [keyserverDomain=keys.openpgp.org] - Domain of the keyserver * @param {string} [keyserverDomain=keys.openpgp.org] - Domain of the keyserver
* @returns {Promise<openpgp.PublicKey>} * @returns {Promise<PublicKey>}
* @example * @example
* const key1 = doip.keys.fetchHKP('alice@domain.tld'); * const key1 = doip.keys.fetchHKP('alice@domain.tld');
* const key2 = doip.keys.fetchHKP('123abc123abc'); * const key2 = doip.keys.fetchHKP('123abc123abc');
*/ */
const fetchHKP = async (identifier, keyserverDomain) => { export async function fetchHKP (identifier, keyserverDomain) {
const keyserverBaseUrl = keyserverDomain const keyserverBaseUrl = keyserverDomain
? `https://${keyserverDomain}` ? `https://${keyserverDomain}`
: 'https://keys.openpgp.org' : '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') throw new Error('Key does not exist or could not be fetched')
} }
return await openpgp.readKey({ return await readKey({
armoredKey: publicKey armoredKey: publicKey
}) })
.catch((error) => { .catch((error) => {
@ -68,11 +68,11 @@ const fetchHKP = async (identifier, keyserverDomain) => {
* Fetch a public key using Web Key Directory * Fetch a public key using Web Key Directory
* @function * @function
* @param {string} identifier - Identifier of format 'username@domain.tld` * @param {string} identifier - Identifier of format 'username@domain.tld`
* @returns {Promise<openpgp.PublicKey>} * @returns {Promise<PublicKey>}
* @example * @example
* const key = doip.keys.fetchWKD('alice@domain.tld'); * const key = doip.keys.fetchWKD('alice@domain.tld');
*/ */
const fetchWKD = async (identifier) => { export async function fetchWKD (identifier) {
// @ts-ignore // @ts-ignore
const wkd = new WKD() const wkd = new WKD()
const lookupOpts = { const lookupOpts = {
@ -89,7 +89,7 @@ const fetchWKD = async (identifier) => {
throw new Error('Key does not exist or could not be fetched') throw new Error('Key does not exist or could not be fetched')
} }
return await openpgp.readKey({ return await readKey({
binaryKey: publicKey binaryKey: publicKey
}) })
.catch((error) => { .catch((error) => {
@ -102,11 +102,11 @@ const fetchWKD = async (identifier) => {
* @function * @function
* @param {string} username - Keybase username * @param {string} username - Keybase username
* @param {string} fingerprint - Fingerprint of key * @param {string} fingerprint - Fingerprint of key
* @returns {Promise<openpgp.PublicKey>} * @returns {Promise<PublicKey>}
* @example * @example
* const key = doip.keys.fetchKeybase('alice', '123abc123abc'); * 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}` const keyLink = `https://keybase.io/${username}/pgp_keys.asc?fingerprint=${fingerprint}`
let rawKeyContent let rawKeyContent
try { try {
@ -126,7 +126,7 @@ const fetchKeybase = async (username, fingerprint) => {
throw new Error(`Error fetching Keybase key: ${e.message}`) throw new Error(`Error fetching Keybase key: ${e.message}`)
} }
return await openpgp.readKey({ return await readKey({
armoredKey: rawKeyContent armoredKey: rawKeyContent
}) })
.catch((error) => { .catch((error) => {
@ -138,7 +138,7 @@ const fetchKeybase = async (username, fingerprint) => {
* Get a public key from plaintext data * Get a public key from plaintext data
* @function * @function
* @param {string} rawKeyContent - Plaintext ASCII-formatted public key data * @param {string} rawKeyContent - Plaintext ASCII-formatted public key data
* @returns {Promise<openpgp.PublicKey>} * @returns {Promise<PublicKey>}
* @example * @example
* const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK----- * const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
* *
@ -148,8 +148,8 @@ const fetchKeybase = async (username, fingerprint) => {
* -----END PGP PUBLIC KEY BLOCK-----` * -----END PGP PUBLIC KEY BLOCK-----`
* const key = doip.keys.fetchPlaintext(plainkey); * const key = doip.keys.fetchPlaintext(plainkey);
*/ */
const fetchPlaintext = async (rawKeyContent) => { export async function fetchPlaintext (rawKeyContent) {
const publicKey = await openpgp.readKey({ const publicKey = await readKey({
armoredKey: rawKeyContent armoredKey: rawKeyContent
}) })
.catch((error) => { .catch((error) => {
@ -163,14 +163,14 @@ const fetchPlaintext = async (rawKeyContent) => {
* Fetch a public key using an URI * Fetch a public key using an URI
* @function * @function
* @param {string} uri - URI that defines the location of the key * @param {string} uri - URI that defines the location of the key
* @returns {Promise<openpgp.PublicKey>} * @returns {Promise<PublicKey>}
* @example * @example
* const key1 = doip.keys.fetchURI('hkp:alice@domain.tld'); * const key1 = doip.keys.fetchURI('hkp:alice@domain.tld');
* const key2 = doip.keys.fetchURI('hkp:123abc123abc'); * const key2 = doip.keys.fetchURI('hkp:123abc123abc');
* const key3 = doip.keys.fetchURI('wkd:alice@domain.tld'); * const key3 = doip.keys.fetchURI('wkd:alice@domain.tld');
*/ */
const fetchURI = async (uri) => { export async function fetchURI (uri) {
if (!validUrl.isUri(uri)) { if (!isUri(uri)) {
throw new Error('Invalid 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 * This function will also try and parse the input as a plaintext key
* @function * @function
* @param {string} identifier - URI that defines the location of the key * @param {string} identifier - URI that defines the location of the key
* @returns {Promise<openpgp.PublicKey>} * @returns {Promise<PublicKey>}
* @example * @example
* const key1 = doip.keys.fetch('alice@domain.tld'); * const key1 = doip.keys.fetch('alice@domain.tld');
* const key2 = doip.keys.fetch('123abc123abc'); * 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 re = /([a-zA-Z0-9@._=+-]*)(?::([a-zA-Z0-9@._=+-]*))?/
const match = identifier.match(re) const match = identifier.match(re)
@ -252,7 +252,7 @@ const fetch = async (identifier) => {
/** /**
* Process a public key to get user data and claims * Process a public key to get user data and claims
* @function * @function
* @param {openpgp.PublicKey} publicKey - The public key to process * @param {PublicKey} publicKey - The public key to process
* @returns {Promise<object>} * @returns {Promise<object>}
* @example * @example
* const key = doip.keys.fetchURI('hkp:alice@domain.tld'); * const key = doip.keys.fetchURI('hkp:alice@domain.tld');
@ -261,8 +261,8 @@ const fetch = async (identifier) => {
* console.log(claim.uri); * console.log(claim.uri);
* }); * });
*/ */
const process = async (publicKey) => { export async function process (publicKey) {
if (!(publicKey && (publicKey instanceof openpgp.PublicKey))) { if (!(publicKey && (publicKey instanceof PublicKey))) {
throw new Error('Invalid public key') 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. limitations under the License.
*/ */
// eslint-disable-next-line // eslint-disable-next-line
const Claim = require('./claim') import { Claim } from './claim.js'
/** /**
* A persona with identity claims * A persona with identity claims
@ -25,7 +25,7 @@ const Claim = require('./claim')
* const claim = Claim('https://alice.tld', '123'); * const claim = Claim('https://alice.tld', '123');
* const pers = Persona('Alice', 'About Alice', [claim]); * const pers = Persona('Alice', 'About Alice', [claim]);
*/ */
class Persona { export class Persona {
/** /**
* @param {string} name * @param {string} name
* @param {string} [description] * @param {string} [description]
@ -52,5 +52,3 @@ class Persona {
this.claims = claims 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. limitations under the License.
*/ */
// eslint-disable-next-line // eslint-disable-next-line
const Persona = require('./persona') import { Persona } from './persona.js'
/** /**
* A profile of personas with identity claims * A profile of personas with identity claims
@ -26,7 +26,7 @@ const Persona = require('./persona')
* const pers = Persona('Alice', 'About Alice', [claim]); * const pers = Persona('Alice', 'About Alice', [claim]);
* const profile = Profile([pers]); * const profile = Profile([pers]);
*/ */
class Profile { export class Profile {
/** /**
* Create a new profile * Create a new profile
* @function * @function
@ -48,5 +48,3 @@ class Profile {
this.primaryPersona = -1 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const jsEnv = require('browser-or-node') import { isNode } from 'browser-or-node'
const fetcher = require('./fetcher') import * as fetcher from './fetcher/index.js'
const utils = require('./utils') import { generateProxyURL } from './utils.js'
const E = require('./enums') import { Fetcher, ProxyPolicy, ProofAccess } from './enums.js'
/** /**
* @module proofs * @module proofs
@ -33,9 +33,9 @@ const E = require('./enums')
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} * @returns {Promise<object|string>}
*/ */
const fetch = (data, opts) => { export async function fetch (data, opts) {
switch (data.proof.request.fetcher) { switch (data.proof.request.fetcher) {
case E.Fetcher.HTTP: case Fetcher.HTTP:
data.proof.request.data.format = data.proof.request.format data.proof.request.data.format = data.proof.request.format
break break
@ -43,7 +43,7 @@ const fetch = (data, opts) => {
break break
} }
if (jsEnv.isNode) { if (isNode) {
return handleNodeRequests(data, opts) return handleNodeRequests(data, opts)
} }
@ -52,16 +52,16 @@ const fetch = (data, opts) => {
const handleBrowserRequests = (data, opts) => { const handleBrowserRequests = (data, opts) => {
switch (opts.proxy.policy) { switch (opts.proxy.policy) {
case E.ProxyPolicy.ALWAYS: case ProxyPolicy.ALWAYS:
return createProxyRequestPromise(data, opts) return createProxyRequestPromise(data, opts)
case E.ProxyPolicy.NEVER: case ProxyPolicy.NEVER:
switch (data.proof.request.access) { switch (data.proof.request.access) {
case E.ProofAccess.GENERIC: case ProofAccess.GENERIC:
case E.ProofAccess.GRANTED: case ProofAccess.GRANTED:
return createDefaultRequestPromise(data, opts) return createDefaultRequestPromise(data, opts)
case E.ProofAccess.NOCORS: case ProofAccess.NOCORS:
case E.ProofAccess.SERVER: case ProofAccess.SERVER:
throw new Error( throw new Error(
'Impossible to fetch proof (bad combination of service access and proxy policy)' 'Impossible to fetch proof (bad combination of service access and proxy policy)'
) )
@ -69,15 +69,15 @@ const handleBrowserRequests = (data, opts) => {
throw new Error('Invalid proof access value') throw new Error('Invalid proof access value')
} }
case E.ProxyPolicy.ADAPTIVE: case ProxyPolicy.ADAPTIVE:
switch (data.proof.request.access) { switch (data.proof.request.access) {
case E.ProofAccess.GENERIC: case ProofAccess.GENERIC:
return createFallbackRequestPromise(data, opts) return createFallbackRequestPromise(data, opts)
case E.ProofAccess.NOCORS: case ProofAccess.NOCORS:
return createProxyRequestPromise(data, opts) return createProxyRequestPromise(data, opts)
case E.ProofAccess.GRANTED: case ProofAccess.GRANTED:
return createFallbackRequestPromise(data, opts) return createFallbackRequestPromise(data, opts)
case E.ProofAccess.SERVER: case ProofAccess.SERVER:
return createProxyRequestPromise(data, opts) return createProxyRequestPromise(data, opts)
default: default:
throw new Error('Invalid proof access value') throw new Error('Invalid proof access value')
@ -90,13 +90,13 @@ const handleBrowserRequests = (data, opts) => {
const handleNodeRequests = (data, opts) => { const handleNodeRequests = (data, opts) => {
switch (opts.proxy.policy) { switch (opts.proxy.policy) {
case E.ProxyPolicy.ALWAYS: case ProxyPolicy.ALWAYS:
return createProxyRequestPromise(data, opts) return createProxyRequestPromise(data, opts)
case E.ProxyPolicy.NEVER: case ProxyPolicy.NEVER:
return createDefaultRequestPromise(data, opts) return createDefaultRequestPromise(data, opts)
case E.ProxyPolicy.ADAPTIVE: case ProxyPolicy.ADAPTIVE:
return createFallbackRequestPromise(data, opts) return createFallbackRequestPromise(data, opts)
default: default:
@ -126,7 +126,7 @@ const createProxyRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let proxyUrl let proxyUrl
try { try {
proxyUrl = utils.generateProxyURL( proxyUrl = generateProxyURL(
data.proof.request.fetcher, data.proof.request.fetcher,
data.proof.request.data, data.proof.request.data,
opts 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const openpgp = require('openpgp') import { readCleartextMessage, verify } from 'openpgp'
const Claim = require('./claim') import { Claim } from './claim.js'
const keys = require('./keys') import { fetchURI } from './keys.js'
/** /**
* @module signatures * @module signatures
@ -27,8 +27,8 @@ const keys = require('./keys')
* @param {string} signature - The plaintext signature to process * @param {string} signature - The plaintext signature to process
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
const process = async (signature) => { export async function process (signature) {
/** @type {openpgp.CleartextMessage} */ /** @type {import('openpgp').CleartextMessage} */
let sigData let sigData
const result = { const result = {
fingerprint: null, fingerprint: null,
@ -48,7 +48,7 @@ const process = async (signature) => {
// Read the signature // Read the signature
try { try {
sigData = await openpgp.readCleartextMessage({ sigData = await readCleartextMessage({
cleartextMessage: signature cleartextMessage: signature
}) })
} catch (e) { } catch (e) {
@ -89,7 +89,7 @@ const process = async (signature) => {
if (sigKeys.length > 0) { if (sigKeys.length > 0) {
try { try {
result.key.uri = sigKeys[0] result.key.uri = sigKeys[0]
result.key.data = await keys.fetchURI(result.key.uri) result.key.data = await fetchURI(result.key.uri)
result.key.fetchMethod = result.key.uri.split(':')[0] result.key.fetchMethod = result.key.uri.split(':')[0]
} catch (e) {} } catch (e) {}
} }
@ -97,7 +97,7 @@ const process = async (signature) => {
if (!result.key.data && signersUserID) { if (!result.key.data && signersUserID) {
try { try {
result.key.uri = `wkd:${signersUserID}` result.key.uri = `wkd:${signersUserID}`
result.key.data = await keys.fetchURI(result.key.uri) result.key.data = await fetchURI(result.key.uri)
result.key.fetchMethod = 'wkd' result.key.fetchMethod = 'wkd'
} catch (e) {} } catch (e) {}
} }
@ -106,7 +106,7 @@ const process = async (signature) => {
try { try {
const match = preferredKeyServer.match(/^(.*:\/\/)?([^/]*)(?:\/)?$/i) const match = preferredKeyServer.match(/^(.*:\/\/)?([^/]*)(?:\/)?$/i)
result.key.uri = `hkp:${match[2]}:${issuerKeyID || signersUserID}` result.key.uri = `hkp:${match[2]}:${issuerKeyID || signersUserID}`
result.key.data = await keys.fetchURI(result.key.uri) result.key.data = await fetchURI(result.key.uri)
result.key.fetchMethod = 'hkp' result.key.fetchMethod = 'hkp'
} catch (e) { } catch (e) {
throw new Error('Public key not found') throw new Error('Public key not found')
@ -114,7 +114,7 @@ const process = async (signature) => {
} }
// Verify the signature // Verify the signature
const verificationResult = await openpgp.verify({ const verificationResult = await verify({
// @ts-ignore // @ts-ignore
message: sigData, message: sigData,
verificationKeys: result.key.data verificationKeys: result.key.data
@ -158,5 +158,3 @@ const process = async (signature) => {
return result 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const validator = require('validator').default import isFQDN from 'validator/lib/isFQDN.js'
const E = require('./enums') import { ClaimFormat } from './enums.js'
/** /**
* @module utils * @module utils
@ -26,12 +26,13 @@ const E = require('./enums')
* @param {object} data - The data the proxy must provide to the fetcher * @param {object} data - The data the proxy must provide to the fetcher
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @param {object} opts.proxy - Proxy related options * @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 * @param {object} opts.proxy.hostname - The hostname of the proxy server
* @returns {string} * @returns {string}
*/ */
const generateProxyURL = (type, data, opts) => { export function generateProxyURL (type, data, opts) {
try { try {
validator.isFQDN(opts.proxy.hostname) isFQDN(opts.proxy.hostname)
} catch (err) { } catch (err) {
throw new Error('Invalid proxy hostname') 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}) * @param {string} format - The claim's format (see {@link module:enums~ClaimFormat|enums.ClaimFormat})
* @returns {string} * @returns {string}
*/ */
const generateClaim = (fingerprint, format) => { export function generateClaim (fingerprint, format) {
switch (format) { switch (format) {
case E.ClaimFormat.URI: case ClaimFormat.URI:
if (fingerprint.match(/^(openpgp4fpr|aspe):/)) { if (fingerprint.match(/^(openpgp4fpr|aspe):/)) {
return fingerprint return fingerprint
} }
return `openpgp4fpr:${fingerprint}` return `openpgp4fpr:${fingerprint}`
case E.ClaimFormat.FINGERPRINT: case ClaimFormat.FINGERPRINT:
return fingerprint return fingerprint
default: default:
throw new Error('No valid claim format') throw new Error('No valid claim format')
@ -74,7 +75,7 @@ const generateClaim = (fingerprint, format) => {
* @param {string} text - The text that may contain URIs * @param {string} text - The text that may contain URIs
* @returns {Array<string>} * @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 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) const res = text.match(re)
@ -102,7 +103,3 @@ const getUriFromString = (text) => {
return urls 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const utils = require('./utils') import { generateClaim, getUriFromString } from './utils.js'
const E = require('./enums') import { ClaimFormat, EntityEncodingFormat, ClaimRelation, ProofFormat } from './enums.js'
const { bcryptVerify, argon2Verify } = require('hash-wasm') import { bcryptVerify, argon2Verify } from 'hash-wasm'
const entities = require('entities') import { decodeHTML, decodeXML } from 'entities'
/** /**
* @module verifications * @module verifications
@ -34,25 +34,25 @@ const entities = require('entities')
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
const containsProof = async (data, params) => { const containsProof = async (data, params) => {
const fingerprintFormatted = utils.generateClaim(params.target, params.claimFormat) const fingerprintFormatted = generateClaim(params.target, params.claimFormat)
const fingerprintURI = utils.generateClaim(params.target, E.ClaimFormat.URI) const fingerprintURI = generateClaim(params.target, ClaimFormat.URI)
let result = false let result = false
// Decode eventual special entities // Decode eventual special entities
switch (params.proofEncodingFormat) { switch (params.proofEncodingFormat) {
case E.EntityEncodingFormat.HTML: case EntityEncodingFormat.HTML:
data = entities.decodeHTML(data) data = decodeHTML(data)
break break
case E.EntityEncodingFormat.XML: case EntityEncodingFormat.XML:
data = entities.decodeXML(data) data = decodeXML(data)
break break
case E.EntityEncodingFormat.PLAIN: case EntityEncodingFormat.PLAIN:
default: default:
break break
} }
data = entities.decodeHTML(data) data = decodeHTML(data)
// Check for plaintext proof // Check for plaintext proof
result = data result = data
@ -132,7 +132,7 @@ const containsProof = async (data, params) => {
// Check for HTTP proof // Check for HTTP proof
if (!result) { if (!result) {
const uris = utils.getUriFromString(data) const uris = getUriFromString(data)
for (let index = 0; index < uris.length; index++) { for (let index = 0; index < uris.length; index++) {
if (result) continue if (result) continue
@ -207,11 +207,11 @@ const runJSON = async (proofData, checkPath, params) => {
if (checkPath.length === 0) { if (checkPath.length === 0) {
switch (params.claimRelation) { switch (params.claimRelation) {
case E.ClaimRelation.ONEOF: case ClaimRelation.ONEOF:
return await containsProof(proofData.join('|'), params) return await containsProof(proofData.join('|'), params)
case E.ClaimRelation.CONTAINS: case ClaimRelation.CONTAINS:
case E.ClaimRelation.EQUALS: case ClaimRelation.EQUALS:
default: default:
return await containsProof(proofData, params) return await containsProof(proofData, params)
} }
@ -236,7 +236,7 @@ const runJSON = async (proofData, checkPath, params) => {
* @param {string} fingerprint - The fingerprint * @param {string} fingerprint - The fingerprint
* @returns {Promise<object>} * @returns {Promise<object>}
*/ */
const run = async (proofData, claimData, fingerprint) => { export async function run (proofData, claimData, fingerprint) {
const res = { const res = {
result: false, result: false,
completed: false, completed: false,
@ -244,7 +244,7 @@ const run = async (proofData, claimData, fingerprint) => {
} }
switch (claimData.proof.request.format) { switch (claimData.proof.request.format) {
case E.ProofFormat.JSON: case ProofFormat.JSON:
for (let index = 0; index < claimData.claim.length; index++) { for (let index = 0; index < claimData.claim.length; index++) {
const claimMethod = claimData.claim[index] const claimMethod = claimData.claim[index]
try { try {
@ -264,7 +264,7 @@ const run = async (proofData, claimData, fingerprint) => {
} }
res.completed = true res.completed = true
break break
case E.ProofFormat.TEXT: case ProofFormat.TEXT:
for (let index = 0; index < claimData.claim.length; index++) { for (let index = 0; index < claimData.claim.length; index++) {
const claimMethod = claimData.claim[index] const claimMethod = claimData.claim[index]
try { try {
@ -292,5 +292,3 @@ const run = async (proofData, claimData, fingerprint) => {
return res 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const chai = require('chai') import { expect, use } from 'chai'
const expect = chai.expect import chaiAsPromised from 'chai-as-promised'
chai.use(require('chai-as-promised')) use(chaiAsPromised)
const doipjs = require('../src') import { asp, Profile } from '../src/index.js'
const { log } = require('console')
const asp25519Uri = "aspe:domain.tld:QPRGVPJNWDXH4ESK2RYDTZJLTE" const asp25519Uri = "aspe:domain.tld:QPRGVPJNWDXH4ESK2RYDTZJLTE"
const asp25519ProfileName = "test" const asp25519ProfileName = "test"
@ -33,20 +32,21 @@ const asp25519ProfileJwk = {
describe('asp.fetchASPE', () => { describe('asp.fetchASPE', () => {
it('should be a function (1 argument)', () => { it('should be a function (1 argument)', () => {
expect(doipjs.asp.fetchASPE).to.be.a('function') expect(asp.fetchASPE).to.be.a('function')
expect(doipjs.asp.fetchASPE).to.have.length(1) expect(asp.fetchASPE).to.have.length(1)
}) })
}) })
describe('asp.parseProfileJws', () => { describe('asp.parseProfileJws', () => {
it('should be a function (2 arguments)', () => { it('should be a function (2 arguments)', () => {
expect(doipjs.asp.parseProfileJws).to.be.a('function') expect(asp.parseProfileJws).to.be.a('function')
expect(doipjs.asp.parseProfileJws).to.have.length(2) expect(asp.parseProfileJws).to.have.length(2)
}) })
it('should return a valid Profile object when provided a valid JWS', async () => { 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).to.be.length(1)
expect(profile.personas[0].name).to.be.equal(asp25519ProfileName) expect(profile.personas[0].name).to.be.equal(asp25519ProfileName)
expect(profile.personas[0].claims).to.be.length(2) 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const chai = require('chai') import { expect, use } from 'chai'
const expect = chai.expect import chaiAsPromised from 'chai-as-promised'
const chaiMatchPattern = require('chai-match-pattern') import chaiMatchPattern from 'chai-match-pattern'
chai.use(chaiMatchPattern) use(chaiAsPromised)
chai.use(require('chai-as-promised')) use(chaiMatchPattern)
const _ = chaiMatchPattern.getLodashModule() const _ = chaiMatchPattern.getLodashModule()
const doipjs = require('../src')
import { claimDefinitions } from '../src/index.js'
const pattern = { const pattern = {
serviceprovider: { serviceprovider: {
@ -52,12 +53,12 @@ const pattern = {
claim: _.isArray claim: _.isArray
} }
doipjs.claimDefinitions.list.forEach((claimDefName, i) => { claimDefinitions.list.forEach((claimDefName, i) => {
const claimDef = doipjs.claimDefinitions.data[claimDefName] const claimDef = claimDefinitions.data[claimDefName]
describe(`claimDefinitions.${claimDefName}`, () => { describe(`claimDefinitions.${claimDefName}`, () => {
it('should be an object', () => { 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"', () => { it('should have a RegExp instance named "reURI"', () => {
expect(claimDef.reURI).to.be.instanceof(RegExp) 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const chai = require('chai') import { expect, use } from 'chai'
const expect = chai.expect import chaiAsPromised from 'chai-as-promised'
chai.use(require('chai-as-promised')) use(chaiAsPromised)
const path = require('path') import { PublicKey } from 'openpgp'
const openpgp = require('openpgp') import { keys } from '../src/index.js'
const doipjs = require('../src')
const pubKeyFingerprint = "3637202523e7c1309ab79e99ef2dc5827b445f4b" const pubKeyFingerprint = "3637202523e7c1309ab79e99ef2dc5827b445f4b"
const pubKeyEmail = "test@doip.rocks" const pubKeyEmail = "test@doip.rocks"
@ -93,68 +92,68 @@ Q+AZdYCbM0hdBjP4xdKZcpqak8ksb+aQFXjGacDL/XN4VrP+tBGxkqIqreoDcgIb
describe('keys.fetch', () => { describe('keys.fetch', () => {
it('should be a function (1 argument)', () => { it('should be a function (1 argument)', () => {
expect(doipjs.keys.fetch).to.be.a('function') expect(keys.fetch).to.be.a('function')
expect(doipjs.keys.fetch).to.have.length(1) expect(keys.fetch).to.have.length(1)
}) })
it('should return a Key object when provided a valid fingerprint', async () => { it('should return a Key object when provided a valid fingerprint', async () => {
expect( expect(
await doipjs.keys.fetch(pubKeyFingerprint) await keys.fetch(pubKeyFingerprint)
).to.be.instanceOf(openpgp.PublicKey) ).to.be.instanceOf(PublicKey)
}).timeout('12s') }).timeout('12s')
it('should return a Key object when provided a valid email address', async () => { it('should return a Key object when provided a valid email address', async () => {
expect( expect(
await doipjs.keys.fetch(pubKeyEmail) await keys.fetch(pubKeyEmail)
).to.be.instanceOf(openpgp.PublicKey) ).to.be.instanceOf(PublicKey)
}).timeout('12s') }).timeout('12s')
it('should reject when provided an invalid email address', () => { it('should reject when provided an invalid email address', () => {
return expect( 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') ).to.eventually.be.rejectedWith('Key does not exist or could not be fetched')
}).timeout('12s') }).timeout('12s')
}) })
describe('keys.fetchURI', () => { describe('keys.fetchURI', () => {
it('should be a function (1 argument)', () => { it('should be a function (1 argument)', () => {
expect(doipjs.keys.fetchURI).to.be.a('function') expect(keys.fetchURI).to.be.a('function')
expect(doipjs.keys.fetchURI).to.have.length(1) expect(keys.fetchURI).to.have.length(1)
}) })
it('should return a Key object when provided a hkp: uri', async () => { it('should return a Key object when provided a hkp: uri', async () => {
expect( expect(
await doipjs.keys.fetchURI(`hkp:${pubKeyFingerprint}`) await keys.fetchURI(`hkp:${pubKeyFingerprint}`)
).to.be.instanceOf(openpgp.PublicKey) ).to.be.instanceOf(PublicKey)
}).timeout('12s') }).timeout('12s')
it('should reject when provided an invalid uri', () => { it('should reject when provided an invalid uri', () => {
return expect( return expect(
doipjs.keys.fetchURI(`inv:${pubKeyFingerprint}`) keys.fetchURI(`inv:${pubKeyFingerprint}`)
).to.eventually.be.rejectedWith('Invalid URI protocol') ).to.eventually.be.rejectedWith('Invalid URI protocol')
}).timeout('12s') }).timeout('12s')
}) })
describe('keys.fetchHKP', () => { describe('keys.fetchHKP', () => {
it('should be a function (2 arguments)', () => { it('should be a function (2 arguments)', () => {
expect(doipjs.keys.fetchHKP).to.be.a('function') expect(keys.fetchHKP).to.be.a('function')
expect(doipjs.keys.fetchHKP).to.have.length(2) expect(keys.fetchHKP).to.have.length(2)
}) })
it('should return a Key object when provided a valid fingerprint', async () => { it('should return a Key object when provided a valid fingerprint', async () => {
expect(await doipjs.keys.fetchHKP(pubKeyFingerprint)).to.be.instanceOf( expect(await keys.fetchHKP(pubKeyFingerprint)).to.be.instanceOf(
openpgp.PublicKey PublicKey
) )
}).timeout('12s') }).timeout('12s')
it('should return a Key object when provided a valid email address', async () => { it('should return a Key object when provided a valid email address', async () => {
expect(await doipjs.keys.fetchHKP(pubKeyEmail)).to.be.instanceOf( expect(await keys.fetchHKP(pubKeyEmail)).to.be.instanceOf(
openpgp.PublicKey PublicKey
) )
}).timeout('12s') }).timeout('12s')
it('should reject when provided an invalid fingerprint', async () => { it('should reject when provided an invalid fingerprint', async () => {
return expect( return expect(
doipjs.keys.fetchHKP('4637202523e7c1309ab79e99ef2dc5827b445f4b') keys.fetchHKP('4637202523e7c1309ab79e99ef2dc5827b445f4b')
).to.eventually.be.rejectedWith( ).to.eventually.be.rejectedWith(
'Key does not exist or could not be fetched' 'Key does not exist or could not be fetched'
) )
}).timeout('12s') }).timeout('12s')
it('should reject when provided an invalid email address', async () => { it('should reject when provided an invalid email address', async () => {
return expect( return expect(
doipjs.keys.fetchHKP('invalid@doip.rocks') keys.fetchHKP('invalid@doip.rocks')
).to.eventually.be.rejectedWith( ).to.eventually.be.rejectedWith(
'Key does not exist or could not be fetched' 'Key does not exist or could not be fetched'
) )
@ -163,24 +162,24 @@ describe('keys.fetchHKP', () => {
describe('keys.fetchPlaintext', () => { describe('keys.fetchPlaintext', () => {
it('should be a function (1 argument)', () => { it('should be a function (1 argument)', () => {
expect(doipjs.keys.fetchPlaintext).to.be.a('function') expect(keys.fetchPlaintext).to.be.a('function')
expect(doipjs.keys.fetchPlaintext).to.have.length(1) expect(keys.fetchPlaintext).to.have.length(1)
}) })
it('should return a Key object', async () => { it('should return a Key object', async () => {
expect(await doipjs.keys.fetchPlaintext(pubKeyPlaintext)).to.be.instanceOf( expect(await keys.fetchPlaintext(pubKeyPlaintext)).to.be.instanceOf(
openpgp.PublicKey PublicKey
) )
}).timeout('12s') }).timeout('12s')
}) })
describe('keys.process', () => { describe('keys.process', () => {
it('should be a function (1 argument)', () => { it('should be a function (1 argument)', () => {
expect(doipjs.keys.process).to.be.a('function') expect(keys.process).to.be.a('function')
expect(doipjs.keys.process).to.have.length(1) expect(keys.process).to.have.length(1)
}) })
it('should return an object with specific keys', async () => { it('should return an object with specific keys', async () => {
const pubKey = await doipjs.keys.fetchPlaintext(pubKeyPlaintext) const pubKey = await keys.fetchPlaintext(pubKeyPlaintext)
const obj = await doipjs.keys.process(pubKey) const obj = await keys.process(pubKey)
expect(obj).to.have.keys([ expect(obj).to.have.keys([
'users', 'users',
'fingerprint', 'fingerprint',
@ -189,15 +188,15 @@ describe('keys.process', () => {
]) ])
}) })
it('should ignore non-proof notations', async () => { it('should ignore non-proof notations', async () => {
const pubKey = await doipjs.keys.fetchPlaintext(pubKeyWithOtherNotations) const pubKey = await keys.fetchPlaintext(pubKeyWithOtherNotations)
const obj = await doipjs.keys.process(pubKey) const obj = await keys.process(pubKey)
expect(obj.users).to.be.lengthOf(1) expect(obj.users).to.be.lengthOf(1)
expect(obj.users[0].claims).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') expect(obj.users[0].claims[0].uri).to.be.equal('dns:yarmo.eu?type=TXT')
}) })
it('should properly handle revoked UIDs', async () => { it('should properly handle revoked UIDs', async () => {
const pubKey = await doipjs.keys.fetchPlaintext(pubKeyWithRevokedUID) const pubKey = await keys.fetchPlaintext(pubKeyWithRevokedUID)
const obj = await doipjs.keys.process(pubKey) const obj = await keys.process(pubKey)
expect(obj.users).to.be.lengthOf(2) expect(obj.users).to.be.lengthOf(2)
expect(obj.users[0].userData.isRevoked).to.be.true expect(obj.users[0].userData.isRevoked).to.be.true
expect(obj.users[1].userData.isRevoked).to.be.false 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const chai = require('chai') import { expect } from 'chai'
const expect = chai.expect
const doipjs = require('../src') import { signatures } from '../src/index.js'
const sigProfile = `-----BEGIN PGP SIGNED MESSAGE----- const sigProfile = `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512 Hash: SHA512
@ -83,11 +82,11 @@ YCKJPotiqe50nBijHHbuABtBianiMZOm2BbaPnsmdHIX5ynWhOI8LHR1CVmTI/0o
describe('signatures.process', () => { describe('signatures.process', () => {
it('should be a function (2 arguments)', () => { it('should be a function (2 arguments)', () => {
expect(doipjs.signatures.process).to.be.a('function') expect(signatures.process).to.be.a('function')
expect(doipjs.signatures.process).to.have.length(1) expect(signatures.process).to.have.length(1)
}) })
it('should verify a valid signature', async () => { 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( expect(verification.fingerprint).to.be.equal(
'3637202523e7c1309ab79e99ef2dc5827b445f4b' '3637202523e7c1309ab79e99ef2dc5827b445f4b'
) )
@ -95,14 +94,14 @@ describe('signatures.process', () => {
}) })
it('should reject an invalid signature', async () => { it('should reject an invalid signature', async () => {
return expect( return expect(
doipjs.signatures.process(invalidSigProfileMessage) signatures.process(invalidSigProfileMessage)
).to.eventually.be.rejectedWith( ).to.eventually.be.rejectedWith(
'Signature could not be verified (Signed digest did not match)' 'Signature could not be verified (Signed digest did not match)'
) )
}) })
it('should reject an invalid signature', async () => { it('should reject an invalid signature', async () => {
return expect( return expect(
doipjs.signatures.process(invalidSigProfileHash) signatures.process(invalidSigProfileHash)
).to.eventually.be.rejectedWith( ).to.eventually.be.rejectedWith(
'Signature could not be read (Ascii armor integrity check failed)' '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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const chai = require('chai') import { expect } from 'chai'
const expect = chai.expect
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. 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]? 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', () => { describe('utils.generateClaim', () => {
it('should be a function (2 arguments)', () => { it('should be a function (2 arguments)', () => {
expect(doipjs.utils.generateClaim).to.be.a('function') expect(utils.generateClaim).to.be.a('function')
expect(doipjs.utils.generateClaim).to.have.length(2) expect(utils.generateClaim).to.have.length(2)
}) })
it('should generate a correct "uri" claim', () => { it('should generate a correct "uri" claim', () => {
expect( expect(
doipjs.utils.generateClaim('123456789', doipjs.enums.ClaimFormat.URI) utils.generateClaim('123456789', enums.ClaimFormat.URI)
).to.equal('openpgp4fpr:123456789') ).to.equal('openpgp4fpr:123456789')
}) })
it('should generate a correct "fingerprint" claim', () => { it('should generate a correct "fingerprint" claim', () => {
expect( expect(
doipjs.utils.generateClaim( utils.generateClaim(
'123456789', '123456789',
doipjs.enums.ClaimFormat.FINGERPRINT enums.ClaimFormat.FINGERPRINT
) )
).to.equal('123456789') ).to.equal('123456789')
}) })
@ -48,8 +47,8 @@ describe('utils.generateClaim', () => {
describe('utils.generateProxyURL', () => { describe('utils.generateProxyURL', () => {
it('should be a function (3 arguments)', () => { it('should be a function (3 arguments)', () => {
expect(doipjs.utils.generateProxyURL).to.be.a('function') expect(utils.generateProxyURL).to.be.a('function')
expect(doipjs.utils.generateProxyURL).to.have.length(3) expect(utils.generateProxyURL).to.have.length(3)
}) })
it('should generate correct proxy URLs for explicit https scheme', () => { it('should generate correct proxy URLs for explicit https scheme', () => {
const opts = { const opts = {
@ -59,10 +58,10 @@ describe('utils.generateProxyURL', () => {
}, },
} }
expect( 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') ).to.equal('https://localhost/api/2/get/http?domain=domain.org')
expect( 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') ).to.equal('https://localhost/api/2/get/dns?domain=domain.org')
}) })
it('should generate correct proxy URLs for explicit http scheme', () => { it('should generate correct proxy URLs for explicit http scheme', () => {
@ -73,10 +72,10 @@ describe('utils.generateProxyURL', () => {
}, },
} }
expect( 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') ).to.equal('http://localhost/api/2/get/http?domain=domain.org')
expect( 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') ).to.equal('http://localhost/api/2/get/dns?domain=domain.org')
}) })
it('should generate correct proxy URLs for default scheme', () => { it('should generate correct proxy URLs for default scheme', () => {
@ -86,10 +85,10 @@ describe('utils.generateProxyURL', () => {
}, },
} }
expect( 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') ).to.equal('https://localhost/api/2/get/http?domain=domain.org')
expect( 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') ).to.equal('https://localhost/api/2/get/dns?domain=domain.org')
}) })
@ -98,12 +97,12 @@ describe('utils.generateProxyURL', () => {
describe('utils.getUriFromString', () => { describe('utils.getUriFromString', () => {
it('should be a function (1 arguments)', () => { it('should be a function (1 arguments)', () => {
expect(doipjs.utils.getUriFromString).to.be.a('function') expect(utils.getUriFromString).to.be.a('function')
expect(doipjs.utils.getUriFromString).to.have.length(1) expect(utils.getUriFromString).to.have.length(1)
}) })
it('should extract URLs from text', () => { it('should extract URLs from text', () => {
expect( expect(
doipjs.utils.getUriFromString(textWithUrls) utils.getUriFromString(textWithUrls)
).to.have.length(urlsFromText.length) ).to.have.length(urlsFromText.length)
}) })
// TODO Properly check each URL // 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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const chai = require('chai') import { expect, use } from 'chai'
const expect = chai.expect import chaiAsPromised from 'chai-as-promised'
chai.use(require('chai-as-promised')) use(chaiAsPromised)
const doipjs = require('../src') import { claimDefinitions, verifications } from '../src/index.js'
const fingerprint = '3637202523e7c1309ab79e99ef2dc5827b445f4b' const fingerprint = '3637202523e7c1309ab79e99ef2dc5827b445f4b'
const plaintextCorrectProofData = [ const plaintextCorrectProofData = [
@ -44,40 +44,40 @@ const bcryptIncorrectProofData = [
const bcryptCostlyProofData = [ const bcryptCostlyProofData = [
'$2y$16$4Knuu11ZyPXa1qxEbEsKQemKY6ZHM8Bk7WElYfL8q5kmzNjY1Ty8W' '$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', () => { describe('verifications.run', () => {
it('should verify a plaintext proof', async () => { 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 expect(result.result).to.be.true
}) })
// issue #22 // issue #22
it('should handle a plaintext proof with whitespace', async () => { 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 expect(result.result).to.be.true
}) })
it('should reject a wrong plaintext proof', async () => { 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 expect(result.result).to.be.false
}) })
it('should verify a argon2-hashed proof', async () => { 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 expect(result.result).to.be.true
}) })
it('should reject a wrong argon2-hashed proof', async () => { 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 expect(result.result).to.be.false
}) })
it('should verify a bcrypt-hashed proof', async () => { 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 expect(result.result).to.be.true
}) })
it('should reject a wrong bcrypt-hashed proof', async () => { 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 expect(result.result).to.be.false
}) })
it('should reject a too costly hashed proof', async () => { 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 expect(result.result).to.be.false
}) })
}) })