Compare commits

..

1 commit

Author SHA1 Message Date
Yarmo Mackenbach
440062796d
chore: switch from yarn to npm 2024-01-26 20:59:31 +01:00
72 changed files with 10404 additions and 10834 deletions

View file

@ -4,10 +4,7 @@
"es2021": true, "es2021": true,
"node": true "node": true
}, },
"extends": [ "extends": "standard",
"standard",
"plugin:jsdoc/recommended"
],
"overrides": [ "overrides": [
], ],
"parserOptions": { "parserOptions": {
@ -15,8 +12,5 @@
"sourceType": "module" "sourceType": "module"
}, },
"rules": { "rules": {
}, }
"plugins": [
"jsdoc"
]
} }

View file

@ -4,7 +4,7 @@ about: 'Report a bug'
title: '[BUG] ' title: '[BUG] '
ref: 'dev' ref: 'dev'
labels: labels:
- 'Status/Needs Triage' - Status/Backlog
- Type/Bug - Type/Bug
--- ---

View file

@ -4,7 +4,7 @@ about: 'Report a claim no longer verifying, or not verifying as it should'
title: '[CLAIM BUG] ' title: '[CLAIM BUG] '
ref: 'dev' ref: 'dev'
labels: labels:
- 'Status/Needs Triage' - Status/Backlog
- Type/Bug - Type/Bug
--- ---

View file

@ -4,7 +4,7 @@ about: 'Suggest a new service provider or website for identity verification'
title: '[NEW CLAIM] ' title: '[NEW CLAIM] '
ref: 'dev' ref: 'dev'
labels: labels:
- 'Status/Needs Triage' - Status/Backlog
- 'Type/New Claim' - 'Type/New Claim'
--- ---

Binary file not shown.

View file

@ -1,6 +0,0 @@
nodeLinker: node-modules
npmScopes:
myriation:
npmPublishRegistry: https://git.myriation.xyz/api/packages/myriation/npm/
npmAlwaysAuth: true
npmAuthToken: REPLACE-ME

View file

@ -6,16 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [1.2.9] - 2024-02-01
### Added
- ORCiD identity claims
### Changed
- Improved code documentation
- Optimized creation of Regexp instances
### Fixed
- Bad promise timeout logic
- Dependencies cleaned up
## [1.2.8] - 2024-01-23 ## [1.2.8] - 2024-01-23
### Added ### Added
- OpenPGP and ASP claims - OpenPGP and ASP claims

View file

@ -1,18 +1,22 @@
# doip.js # doip.js
[![status-badge](https://ci.codeberg.org/api/badges/5907/status.svg)](https://ci.codeberg.org/repos/5907)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue?style=flat)](https://codeberg.org/keyoxide/doipjs/src/branch/main/LICENSE)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/247838?domain=https%3A%2F%2Ffosstodon.org&style=flat)](https://fosstodon.org/@keyoxide)
[![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/keyoxide?style=flat)](https://opencollective.com/keyoxide)
![](static/doip.png) ![](static/doip.png)
![](doip.png) ![](doip.png)
[doip.js](https://codeberg.org/keyoxide/doipjs) allows websites and Node.js projects to verify decentralized online doip.js allows websites and Node.js projects to verify decentralized online
identities. identities based on OpenPGP.
Source code available at [codeberg.org](https://codeberg.org/keyoxide/doipjs).
Documentation available at [js.doip.rocks](https://js.doip.rocks). Documentation available at [js.doip.rocks](https://js.doip.rocks).
## Features
- Verify online identities using decentralized technology
- Based on [OpenPGP](https://www.openpgp.org), a widely-used cryptographic standard
- Regex-based service provider detection
- [Mocha](https://mochajs.org) tests
## Installation (node) ## Installation (node)
Install using **yarn** or **npm**: Install using **yarn** or **npm**:
@ -52,32 +56,32 @@ const verifyIdentity = async (url, fp) => {
verifyIdentity('dns:doip.rocks', '9f0048ac0b23301e1f77e994909f6bd6f80f485d') verifyIdentity('dns:doip.rocks', '9f0048ac0b23301e1f77e994909f6bd6f80f485d')
``` ```
This snippet verifies the [doip.rocks](https://doip.rocks) domain as This snippet works and will verify the [doip.rocks](https://doip.rocks) domain as
bidirectionally linked to Yarmo's cryptographic key. bidirectionally linked to Yarmo's cryptographic key.
## Contributing ## About Keyoxide
Anyone can contribute! [Keyoxide](https://keyoxide.org/), made by Yarmo Mackenbach, is a modern, secure
and privacy-friendly platform to establish decentralized online identities using
a novel concept know as [DOIP](doip.md). In an effort to make this technology
accessible for other projects and stimulate the emergence of both complementary
and competing projects, this project-agnostic library is
[published on codeberg.org](https://codeberg.org/keyoxide/doipjs) and open
sourced under the
[Apache-2.0](https://codeberg.org/keyoxide/doipjs/src/branch/main/LICENSE)
license.
Developers are invited to: ## Community
- fork the repository and play around There's a [Keyoxide Matrix room](https://matrix.to/#/#keyoxide:matrix.org) where
- submit PRs to [implement new features or fix bugs](https://codeberg.org/keyoxide/doipjs/issues) we discuss everything DOIP and Keyoxide.
If you are new to contributing to open source software, we'd love to help you! To get started, here's a [list of "good first issues"](https://codeberg.org/keyoxide/doipjs/issues?q=&type=all&state=open&labels=183598) that you could look into. ## Donate
Everyone is invited to: Please consider [donating](https://liberapay.com/Keyoxide/) if you think this
project is a step in the right direction for the internet.
- find and [report bugs](https://codeberg.org/keyoxide/doipjs/issues/new/choose) ## Funding
- suggesting [new features](https://codeberg.org/keyoxide/doipjs/issues/new/choose)
- [help with translations](https://translate.codeberg.org/projects/keyoxide/)
- [improve documentation](https://codeberg.org/keyoxide/keyoxide-docs)
- start using open source software and promote it
Please note that this project has a [Code of Conduct](https://codeberg.org/keyoxide/web/src/branch/main/CODE_OF_CONDUCT.md) that all contributors agree to abide when participating. This library was realized with funding from
[NLnet](https://nlnet.nl/project/Keyoxide/).
## About the Keyoxide project
The Keyoxide project strives for a healthier internet for all and has made its efforts fully [open source](https://codeberg.org/keyoxide). Our [community](https://docs.keyoxide.org/community/) is open and welcoming, feel free to say hi!
Funding for the project comes from the [NLnet foundation](https://nlnet.nl/), [NGI0](https://www.ngi.eu/) and the people supporting our [OpenCollective](https://opencollective.com/keyoxide). The project is grateful for all your support.

1553
dist/doip.core.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

1774
dist/doip.fetchers.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,8 +1,5 @@
{ {
"plugins": [ "plugins": ["plugins/markdown"],
"plugins/markdown",
"node_modules/jsdoc-tsimport-plugin"
],
"source": { "source": {
"include": ["./src", "./README.md"] "include": ["./src", "./README.md"]
}, },
@ -15,26 +12,21 @@
} }
}, },
"opts": { "opts": {
"template": "node_modules/docdash", "template": "node_modules/clean-jsdoc-theme",
"destination": "docs/" "theme_opts": {
}, "theme": "light",
"docdash": { "menu": [
"collapse": true, {
"meta": { "title": "Source code",
"title": "doipjs", "link": "https://codeberg.org/keyoxide/doipjs",
"description": "Documentation for the doip.js library" "target": "_blank"
}, },
"menu": { {
"Keyoxide": { "title": "Keyoxide",
"href":"https://keyoxide.org", "link": "https://keyoxide.org",
"target":"_blank", "target": "_blank"
"class":"menu-item" }
}, ]
"Keyoxide docs": {
"href":"https://docs.keyoxide.org",
"target":"_blank",
"class":"menu-item"
}
} }
} }
} }

8090
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{ {
"name": "@myriation/doipjs", "name": "doipjs",
"version": "1.2.9+myriaiton.1", "version": "1.2.8",
"description": "Decentralized Online Identity Proofs library in Node.js", "description": "Decentralized Online Identity Proofs library in Node.js",
"type": "module", "type": "module",
"main": "./src/index.js", "main": "./src/index.js",
@ -15,7 +15,6 @@
"default": "./src/fetcher/index.minimal.js" "default": "./src/fetcher/index.minimal.js"
} }
}, },
"packageManager": "yarn@4.3.0",
"dependencies": { "dependencies": {
"@openpgp/hkp-client": "^0.0.3", "@openpgp/hkp-client": "^0.0.3",
"@openpgp/wkd-client": "^0.0.4", "@openpgp/wkd-client": "^0.0.4",
@ -23,7 +22,10 @@
"@xmpp/debug": "^0.13.0", "@xmpp/debug": "^0.13.0",
"axios": "^1.6.5", "axios": "^1.6.5",
"browser-or-node": "^1.3.0", "browser-or-node": "^1.3.0",
"cors": "^2.8.5",
"entities": "^4.4.0", "entities": "^4.4.0",
"express": "^4.17.1",
"express-validator": "^6.10.0",
"hash-wasm": "^4.9.0", "hash-wasm": "^4.9.0",
"irc-upd": "^0.11.0", "irc-upd": "^0.11.0",
"jose": "^4.14.4", "jose": "^4.14.4",
@ -39,20 +41,19 @@
"@rollup/plugin-node-resolve": "^15.1.0", "@rollup/plugin-node-resolve": "^15.1.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"docdash": "^2.0.2", "clean-jsdoc-theme": "^4.2.17",
"eslint": "^8.39.0", "eslint": "^8.39.0",
"eslint-config-standard": "^17.0.0", "eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^48.0.4",
"eslint-plugin-n": "^15.7.0", "eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.1.1",
"husky": "^7.0.0", "husky": "^7.0.0",
"jsdoc": "^4.0.2", "jsdoc": "^4.0.2",
"jsdoc-tsimport-plugin": "^1.0.5",
"license-check-and-add": "^4.0.3", "license-check-and-add": "^4.0.3",
"lint-staged": "^11.0.0", "lint-staged": "^11.0.0",
"minify": "^9.1", "minify": "^9.1",
"mocha": "^9.2.0", "mocha": "^9.2.0",
"nodemon": "^3.0.3",
"rollup": "^3.26.2", "rollup": "^3.26.2",
"rollup-plugin-polyfill-node": "^0.12.0", "rollup-plugin-polyfill-node": "^0.12.0",
"rollup-plugin-visualizer": "^5.9.2" "rollup-plugin-visualizer": "^5.9.2"
@ -73,7 +74,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.myriation.org/myriation/doipjs" "url": "https://codeberg.org/keyoxide/doipjs"
}, },
"homepage": "https://js.doip.rocks", "homepage": "https://js.doip.rocks",
"keywords": [ "keywords": [

View file

@ -32,9 +32,9 @@ const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512']
* Fetch a public key using Web Key Directory * Fetch a public key using Web Key Directory
* @function * @function
* @param {string} uri - ASPE URI * @param {string} uri - ASPE URI
* @returns {Promise<Profile>} The fetched profile * @returns {Promise<Profile>}
* @example * @example
* const key = await doip.aspe.fetchASPE('aspe:domain.example:1234567890'); * const key = doip.aspe.fetchASPE('aspe:domain.tld:1234567890');
*/ */
export async function fetchASPE (uri) { export async function fetchASPE (uri) {
const re = /aspe:(.*):(.*)/ const re = /aspe:(.*):(.*)/
@ -76,13 +76,13 @@ export async function fetchASPE (uri) {
} }
/** /**
* Parse a JWS and extract the profile it contains * Fetch a public key using Web Key Directory
* @function * @function
* @param {string} profileJws - Compact-Serialized profile JWS * @param {string} profileJws - Compact-Serialized profile JWS
* @param {string} uri - The ASPE URI associated with the profile * @param {string} uri - The ASPE URI associated with the profile
* @returns {Promise<Profile>} The extracted profile * @returns {Promise<Profile>}
* @example * @example
* const key = await doip.aspe.parseProfileJws('...', 'aspe:domain.example:123'); * const key = doip.aspe.parseProfileJws('...');
*/ */
export async function parseProfileJws (profileJws, uri) { export async function parseProfileJws (profileJws, uri) {
const matches = uri.match(/aspe:(.*):(.*)/) const matches = uri.match(/aspe:(.*):(.*)/)
@ -132,7 +132,7 @@ export async function parseProfileJws (profileJws, uri) {
const profileDescription = payloadJson['http://ariadne.id/description'] const profileDescription = payloadJson['http://ariadne.id/description']
/** @type {string} */ /** @type {string} */
const profileThemeColor = payloadJson['http://ariadne.id/color'] const profileThemeColor = payloadJson['http://ariadne.id/color']
/** @type {Array<string>} */ /** @type {string[]} */
const profileClaims = payloadJson['http://ariadne.id/claims'] const profileClaims = payloadJson['http://ariadne.id/claims']
const profileClaimsParsed = profileClaims.map(x => new Claim(x, uri)) const profileClaimsParsed = profileClaims.map(x => new Claim(x, uri))
@ -169,10 +169,10 @@ export async function parseProfileJws (profileJws, uri) {
} }
/** /**
* Compute the fingerprint for {@link https://github.com/panva/jose/blob/main/docs/interfaces/types.JWK.md JWK} keys * Compute the fingerprint for JWK keys
* @function * @function
* @param {import('jose').JWK} key - The JWK public key for which to compute the fingerprint * @param {import('jose').JWK} key
* @returns {Promise<string>} The computed fingerprint * @returns {Promise<string>}
*/ */
export async function computeJwkFingerprint (key) { export async function computeJwkFingerprint (key) {
const thumbprint = await calculateJwkThumbprint(key, 'sha512') const thumbprint = await calculateJwkThumbprint(key, 'sha512')

View file

@ -30,16 +30,17 @@ import { ServiceProvider } from './serviceProvider.js'
* @property {string} fingerprint - The fingerprint to verify the claim against * @property {string} fingerprint - The fingerprint to verify the claim against
* @property {number} status - The current status code of the claim * @property {number} status - The current status code of the claim
* @property {Array<object>} matches - The claim definitions matched against the URI * @property {Array<object>} matches - The claim definitions matched against the URI
* @example
* const claim = doip.Claim();
* const claim = doip.Claim('dns:domain.tld?type=TXT');
* const claim = doip.Claim('dns:domain.tld?type=TXT', '123abc123abc');
*/ */
export class Claim { export class Claim {
/** /**
* Initialize a Claim object * Initialize a Claim object
* @constructor
* @param {string} [uri] - The URI of the identity claim * @param {string} [uri] - The URI of the identity claim
* @param {string} [fingerprint] - The fingerprint of the OpenPGP key * @param {string} [fingerprint] - The fingerprint of the OpenPGP key
* @example
* const claim = doip.Claim();
* const claim = doip.Claim('dns:domain.tld?type=TXT');
* const claim = doip.Claim('dns:domain.tld?type=TXT', '123abc123abc');
*/ */
constructor (uri, fingerprint) { constructor (uri, fingerprint) {
// Verify validity of URI // Verify validity of URI
@ -70,16 +71,15 @@ export class Claim {
*/ */
this._status = ClaimStatus.INIT this._status = ClaimStatus.INIT
/** /**
* @type {Array<ServiceProvider>} * @type {import('./serviceProvider.js').ServiceProvider[]}
*/ */
this._matches = [] this._matches = []
} }
/** /**
* @function * @function
* @param {*} claimObject - JSON representation of a claim * @param {object} claimObject
* @returns {Claim} Parsed claim * @returns {Claim | Error}
* @throws Will throw an error if the JSON object can't be coerced into a Claim
* @example * @example
* doip.Claim.fromJSON(JSON.stringify(claim)); * doip.Claim.fromJSON(JSON.stringify(claim));
*/ */
@ -215,8 +215,9 @@ export class Claim {
* checked for the fingerprint. The verification stops when either a positive * checked for the fingerprint. The verification stops when either a positive
* result was obtained, or an unambiguous claim definition was processed * result was obtained, or an unambiguous claim definition was processed
* regardless of the result. * regardless of the result.
* @async
* @function * @function
* @param {import('./types').VerificationConfig} [opts] - Options for proxy, fetchers * @param {object} [opts] - Options for proxy, fetchers
*/ */
async verify (opts) { async verify (opts) {
if (this._status === ClaimStatus.INIT) { if (this._status === ClaimStatus.INIT) {
@ -244,7 +245,6 @@ export class Claim {
let claimData = this._matches[index] let claimData = this._matches[index]
/** @type {import('./types').VerificationResult | null} */
let verificationResult = null let verificationResult = null
let proofData = null let proofData = null
let proofFetchError let proofFetchError
@ -286,7 +286,7 @@ export class Claim {
verificationResult = verificationResult || { verificationResult = verificationResult || {
result: false, result: false,
completed: true, completed: true,
proof: null, proof: {},
errors: [proofFetchError] errors: [proofFetchError]
} }
} }
@ -310,7 +310,7 @@ export class Claim {
* of the candidates is unambiguous. An ambiguous claim should never be * of the candidates is unambiguous. An ambiguous claim should never be
* displayed in an user interface when its result is negative. * displayed in an user interface when its result is negative.
* @function * @function
* @returns {boolean} Whether the claim is ambiguous * @returns {boolean}
*/ */
isAmbiguous () { isAmbiguous () {
if (this._status < ClaimStatus.MATCHED) { if (this._status < ClaimStatus.MATCHED) {
@ -327,7 +327,7 @@ export class Claim {
* Get a JSON representation of the Claim object. Useful when transferring * Get a JSON representation of the Claim object. Useful when transferring
* data between instances/machines. * data between instances/machines.
* @function * @function
* @returns {object} JSON reprentation of the claim * @returns {object}
*/ */
toJSON () { toJSON () {
let displayProfileName = this._uri let displayProfileName = this._uri
@ -362,9 +362,8 @@ export class Claim {
} }
/** /**
* @ignore * @param {object} claimObject
* @param {object} claimObject - JSON representation of a claim * @returns {Claim | Error}
* @returns {Claim | Error} Parsed claim
*/ */
function importJsonClaimVersion1 (claimObject) { function importJsonClaimVersion1 (claimObject) {
if (!('claimVersion' in claimObject && claimObject.claimVersion === 1)) { if (!('claimVersion' in claimObject && claimObject.claimVersion === 1)) {
@ -404,9 +403,8 @@ function importJsonClaimVersion1 (claimObject) {
} }
/** /**
* @ignore * @param {object} claimObject
* @param {object} claimObject - JSON representation of a claim * @returns {Claim | Error}
* @returns {Claim | Error} Parsed claim
*/ */
function importJsonClaimVersion2 (claimObject) { function importJsonClaimVersion2 (claimObject) {
if (!('claimVersion' in claimObject && claimObject.claimVersion === 2)) { if (!('claimVersion' in claimObject && claimObject.claimVersion === 2)) {

View file

@ -22,4 +22,4 @@ limitations under the License.
* doip.js library version * doip.js library version
* @constant {string} * @constant {string}
*/ */
export const version = '1.2.9+myriaiton.1' export const version = '1.2.8'

View file

@ -21,8 +21,26 @@ import { ProxyPolicy } from './enums.js'
*/ */
/** /**
* The default claim verification config used throughout the library * The default options used throughout the library
* @type {import('./types').VerificationConfig} * @constant {object}
* @property {object} proxy - Options related to the proxy
* @property {string|null} proxy.hostname - The hostname of the proxy
* @property {string} proxy.policy - The policy that defines when to use a proxy ({@link module:enums~ProxyPolicy|here})
* @property {object} claims - Options related to claim verification
* @property {object} claims.activitypub - Options related to the verification of activitypub claims
* @property {string|null} claims.activitypub.url - The URL of the verifier account
* @property {string|null} claims.activitypub.privateKey - The private key to sign the request
* @property {object} claims.irc - Options related to the verification of IRC claims
* @property {string|null} claims.irc.nick - The nick that the library uses to connect to the IRC server
* @property {object} claims.matrix - Options related to the verification of Matrix claims
* @property {string|null} claims.matrix.instance - The server hostname on which the library can log in
* @property {string|null} claims.matrix.accessToken - The access token required to identify the library ({@link https://www.matrix.org/docs/guides/client-server-api|Matrix docs})
* @property {object} claims.telegram - Options related to the verification of Telegram claims
* @property {string|null} claims.telegram.token - The Telegram API's token ({@link https://core.telegram.org/bots/api#authorizing-your-bot|Telegram docs})
* @property {object} claims.xmpp - Options related to the verification of XMPP claims
* @property {string|null} claims.xmpp.service - The server hostname on which the library can log in
* @property {string|null} claims.xmpp.username - The username used to log in
* @property {string|null} claims.xmpp.password - The password used to log in
*/ */
export const opts = { export const opts = {
proxy: { proxy: {
@ -35,8 +53,7 @@ export const opts = {
privateKey: null privateKey: null
}, },
irc: { irc: {
nick: null, nick: null
sasl: []
}, },
matrix: { matrix: {
instance: null, instance: null,

View file

@ -115,7 +115,7 @@ export const ClaimFormat = {
} }
/** /**
* How to find the proof inside the fetched data * How to find the claim inside the proof's JSON data
* @readonly * @readonly
* @enum {string} * @enum {string}
*/ */

View file

@ -13,36 +13,27 @@ 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.
*/ */
/**
* Fetch proofs using ActivityPub HTTP requests
* @module fetcher/activitypub
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.activitypub.fn({ url: 'https://domain.example/@alice' });
*/
import axios from 'axios' import axios from 'axios'
import isURL from 'validator/lib/isURL.js' import isURL from 'validator/lib/isURL.js'
import { isNode } from 'browser-or-node' import { isNode } from 'browser-or-node'
import crypto from 'crypto' import crypto from 'crypto'
import { version } from '../constants.js' import { version } from '../constants.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.url - The URL of the account to verify * @param {object} data - Data used in the request
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.url - The URL of the account to verify
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} The fetched ActivityPub object * @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.activitypub
* @param {string} opts.claims.activitypub.url - The URL of the verifier account
* @param {string} opts.claims.activitypub.privateKey - The private key to sign the request
* @returns {Promise<object>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,24 +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.
*/ */
/**
* Fetch proofs from Profile obtained through ASPE
* @module fetcher/aspe
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.aspe.fn({ aspeUri: 'aspe:domain.example:abc123def456' });
*/
import axios from 'axios' import axios from 'axios'
import isFQDN from 'validator/lib/isFQDN.js' import isFQDN from 'validator/lib/isFQDN.js'
import { version } from '../constants.js' import { version } from '../constants.js'
import { parseProfileJws } from '../asp.js' import { parseProfileJws } from '../asp.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
const reURI = /^aspe:([a-zA-Z0-9.\-_]*):([a-zA-Z0-9]*)/ const reURI = /^aspe:([a-zA-Z0-9.\-_]*):([a-zA-Z0-9]*)/
@ -38,11 +25,11 @@ const reURI = /^aspe:([a-zA-Z0-9.\-_]*):([a-zA-Z0-9]*)/
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.aspeUri - ASPE URI of the targeted profile * @param {object} data - Data used in the request
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.aspeUri - ASPE URI of the targeted profile
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} The fetched claims from an ASP profile * @returns {Promise<object|string>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,33 +13,19 @@ 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.
*/ */
/**
* Fetch proofs using DNS TXT records
* @module fetcher/dns
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.dns.fn({ domain: 'domain.example' });
*/
import { isBrowser } from 'browser-or-node' import { isBrowser } from 'browser-or-node'
import dns from 'dns' import dns from 'dns'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.domain - The targeted domain * @param {object} data - Data used in the request
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.domain - The targeted domain
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} The fetched DNS records * @returns {Promise<object>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
if (isBrowser) { if (isBrowser) {

View file

@ -13,34 +13,20 @@ 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.
*/ */
/**
* Fetch proofs using GraphQL queries
* @module fetcher/graphql
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.graphql.fn({ url: 'https://domain.example/graphql/v2', query: '{ "query": "..." }' });
*/
import axios from 'axios' import axios from 'axios'
import { version } from '../constants.js' import { version } from '../constants.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a GraphQL query via HTTP request * Execute a GraphQL query via HTTP request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.url - The URL pointing at the GraphQL HTTP endpoint * @param {object} data - Data used in the request
* @param {string} data.query - The GraphQL query to fetch the data containing the proof * @param {string} data.url - The URL pointing at the GraphQL HTTP endpoint
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.query - The GraphQL query to fetch the data containing the proof
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} The fetched GraphQL object * @returns {Promise<object|string>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,35 +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.
*/ */
/**
* Fetch proofs using HTTP requests
* @module fetcher/http
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.http.fn({ url: 'https://domain.example/data.json', format: 'json' });
*/
import axios from 'axios' import axios from 'axios'
import { ProofFormat } from '../enums.js' import { ProofFormat } from '../enums.js'
import { version } from '../constants.js' import { version } from '../constants.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.url - The URL pointing at targeted content * @param {object} data - Data used in the request
* @param {string} data.format - The format of the targeted content * @param {string} data.url - The URL pointing at targeted content
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.format - The format of the targeted content
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object|string>} The fetched JSON object or text * @returns {Promise<object|string>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,34 +13,24 @@ 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.
*/ */
/**
* Fetch proofs using IRC
* @module fetcher/irc
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.irc.fn({ nick: 'alice', domain: 'domain.example' });
*/
import irc from 'irc-upd' import irc from 'irc-upd'
import isAscii from 'validator/lib/isAscii.js' import isAscii from 'validator/lib/isAscii.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 20000
*/
export const timeout = 20000 export const timeout = 20000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.nick - The nick of the targeted account * @param {object} data - Data used in the request
* @param {string} data.domain - The domain on which the targeted account is registered * @param {string} data.nick - The nick of the targeted account
* @param {string} data.domain - The domain on which the targeted account is registered
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {object} opts - Options used to enable the request
* @returns {Promise<Array<string>>} The fetched proofs from an IRC account * @param {object} opts.claims
* @param {object} opts.claims.irc
* @param {string} opts.claims.irc.nick - The nick to be used by the library to log in
* @returns {Promise<object>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle
@ -59,25 +49,12 @@ export async function fn (data, opts) {
} }
try { try {
// Add sasl-related config if the server matches
const matchedSaslConfig = opts.claims.irc.sasl.find(saslConfig => data.domain.match(new RegExp(saslConfig.domainRegex)) !== null)
const saslOptions = matchedSaslConfig
? {
sasl: true,
userName: matchedSaslConfig.username,
password: matchedSaslConfig.password
}
: {
sasl: false
}
const client = new irc.Client(data.domain, opts.claims.irc.nick, { const client = new irc.Client(data.domain, opts.claims.irc.nick, {
port: 6697, port: 6697,
secure: true, secure: true,
channels: [], channels: [],
showErrors: false, showErrors: false,
debug: false, debug: false
...saslOptions
}) })
const reKey = /[a-zA-Z0-9\-_]+\s+:\s((?:openpgp4fpr|aspe):.*)/ const reKey = /[a-zA-Z0-9\-_]+\s+:\s((?:openpgp4fpr|aspe):.*)/
const reEnd = /End\sof\s.*\staxonomy./ const reEnd = /End\sof\s.*\staxonomy./

View file

@ -13,36 +13,27 @@ 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.
*/ */
/**
* Fetch proofs using Matrix messages
* @module fetcher/matrix
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.matrix.fn({ eventId: '$abc123def456', roomId: '!dBfQZxCoGVmSTujfiv:matrix.org' });
*/
import axios from 'axios' import axios from 'axios'
import isFQDN from 'validator/lib/isFQDN.js' import isFQDN from 'validator/lib/isFQDN.js'
import isAscii from 'validator/lib/isAscii.js' import isAscii from 'validator/lib/isAscii.js'
import { version } from '../constants.js' import { version } from '../constants.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.eventId - The identifier of the targeted post * @param {object} data - Data used in the request
* @param {string} data.roomId - The identifier of the room containing the targeted post * @param {string} data.eventId - The identifier of the targeted post
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.roomId - The identifier of the room containing the targeted post
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} The fetched Matrix object * @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.matrix
* @param {string} opts.claims.matrix.instance - The server hostname on which the library can log in
* @param {string} opts.claims.matrix.accessToken - The access token required to identify the library ({@link https://www.matrix.org/docs/guides/client-server-api|Matrix docs})
* @returns {Promise<object>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,44 +13,23 @@ 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.
*/ */
/**
* Fetch proofs from OpenPGP notations
* @module fetcher/openpgp
* @example
* import { fetcher, enums as E } from 'doipjs';
*
* const hkpProtocol = E.OpenPgpQueryProtocol.HKP;
* const hkpUrl = 'https://keys.openpgp.org/vks/v1/by-fingerprint/ABC123DEF456';
* const hkpData = await fetcher.openpgp.fn({ url: hkpUrl, protocol: hkpProtocol });
*
* const wkdProtocol = E.OpenPgpQueryProtocol.WKD;
* const wkdUrl = 'https://domain.example/.well-known/openpgpkey/hu/kei1q4tipxxu1yj79k9kfukdhfy631xe?l=alice';
* const wkdData = await fetcher.openpgp.fn({ url: wkdUrl, protocol: wkdProtocol });
*/
import axios from 'axios' import axios from 'axios'
import { readKey } from 'openpgp' import { readKey } from 'openpgp'
import { OpenPgpQueryProtocol } from '../enums.js' import { OpenPgpQueryProtocol } from '../enums.js'
import { version } from '../constants.js' import { version } from '../constants.js'
import { parsePublicKey } from '../openpgp.js' import { parsePublicKey } from '../openpgp.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.url - The URL pointing at targeted content * @param {object} data - Data used in the request
* @param {OpenPgpQueryProtocol} data.protocol - The protocol used to access the targeted content * @param {string} data.url - The URL pointing at targeted content
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {OpenPgpQueryProtocol} data.protocol - The protocol used to access the targeted content
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object>} The fetched notations from an OpenPGP key * @returns {Promise<object|string>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,35 +13,25 @@ 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.
*/ */
/**
* Fetch proofs using Telegram groups
* @module fetcher/telegram
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.telegram.fn({ user: 'alice', chat: 'alice_identity_proof' });
*/
import axios from 'axios' import axios from 'axios'
import isAscii from 'validator/lib/isAscii.js' import isAscii from 'validator/lib/isAscii.js'
import { version } from '../constants.js' import { version } from '../constants.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.chat - Telegram public group name (slug) * @param {object} data - Data used in the request
* @param {string} data.user - Telegram username * @param {string} data.chat - Telegram public chat username
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.user - Telegram user username
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<object|string>} The fetched Telegram object * @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.telegram
* @param {string} opts.claims.telegram.token - The Telegram Bot API token
* @returns {Promise<object|string>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
let timeoutHandle let timeoutHandle

View file

@ -13,40 +13,23 @@ 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.
*/ */
/**
* Fetch proofs from XMPP accounts
* @module fetcher/xmpp
* @example
* import { fetcher } from 'doipjs';
* const data = await fetcher.xmpp.fn({ id: 'alice@domain.example' });
*/
import { client, xml } from '@xmpp/client' import { client, xml } from '@xmpp/client'
import debug from '@xmpp/debug' import debug from '@xmpp/debug'
import isFQDN from 'validator/lib/isFQDN.js' import isFQDN from 'validator/lib/isFQDN.js'
import isAscii from 'validator/lib/isAscii.js' import isAscii from 'validator/lib/isAscii.js'
/**
* Default timeout after which the fetch is aborted
* @constant
* @type {number}
* @default 5000
*/
export const timeout = 5000 export const timeout = 5000
let xmpp = null let xmpp = null
let iqCaller = null let iqCaller = null
/** const xmppStart = async (service, username, password) => {
* Start the XMPP client
* @ignore
* @function
* @param {import('../types').XmppClaimVerificationConfig} params - XMPP claim verification config
* @returns {Promise<object>} The fetched proofs from an XMPP account
*/
const xmppStart = async (params) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const xmpp = client({ ...params }) const xmpp = client({
service,
username,
password
})
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
debug(xmpp, true) debug(xmpp, true)
} }
@ -64,11 +47,17 @@ const xmppStart = async (params) => {
/** /**
* Execute a fetch request * Execute a fetch request
* @function * @function
* @param {object} data - Data used in the request * @async
* @param {string} data.id - The identifier of the targeted account * @param {object} data - Data used in the request
* @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher * @param {string} data.id - The identifier of the targeted account
* @param {import('../types').VerificationConfig} [opts] - Options used to enable the request * @param {number} [data.fetcherTimeout] - Optional timeout for the fetcher
* @returns {Promise<Array<string>>} The fetched proofs from an XMPP account * @param {object} opts - Options used to enable the request
* @param {object} opts.claims
* @param {object} opts.claims.xmpp
* @param {string} opts.claims.xmpp.service - The server hostname on which the library can log in
* @param {string} opts.claims.xmpp.username - The username used to log in
* @param {string} opts.claims.xmpp.password - The password used to log in
* @returns {Promise<object>}
*/ */
export async function fn (data, opts) { export async function fn (data, opts) {
try { try {
@ -80,7 +69,11 @@ export async function fn (data, opts) {
} }
if (!xmpp || xmpp.status !== 'online') { if (!xmpp || xmpp.status !== 'online') {
const xmppStartRes = await xmppStart(opts.claims.xmpp) const xmppStartRes = await xmppStart(
opts.claims.xmpp.service,
opts.claims.xmpp.username,
opts.claims.xmpp.password
)
xmpp = xmppStartRes.xmpp xmpp = xmppStartRes.xmpp
iqCaller = xmppStartRes.iqCaller iqCaller = xmppStartRes.iqCaller
} }

View file

@ -13,11 +13,6 @@ 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.
*/ */
/**
* @module doipjs
* @license Apache-2.0
*/
export { Profile } from './profile.js' export { Profile } from './profile.js'
export { Persona } from './persona.js' export { Persona } from './persona.js'
export { Claim } from './claim.js' export { Claim } from './claim.js'

View file

@ -31,16 +31,17 @@ import { Persona } from './persona.js'
/** /**
* Fetch a public key using keyservers * Fetch a public key using keyservers
* @function * @function
* @param {string} identifier - Fingerprint or email address * @param {string} identifier - Fingerprint or email address
* @param {string} [keyserverDomain] - Domain of the keyserver * @param {string} [keyserverDomain=keys.openpgp.org] - Domain of the keyserver
* @returns {Promise<Profile>} The profile from the fetched OpenPGP key * @returns {Promise<Profile>}
* @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 key3 = doip.keys.fetchHKP('123abc123abc', 'pgpkeys.eu');
*/ */
export async function fetchHKP (identifier, keyserverDomain = 'keys.openpgp.org') { export async function fetchHKP (identifier, keyserverDomain) {
const keyserverBaseUrl = `https://${keyserverDomain ?? 'keys.openpgp.org'}` const keyserverBaseUrl = keyserverDomain
? `https://${keyserverDomain}`
: 'https://keys.openpgp.org'
const hkp = new HKP(keyserverBaseUrl) const hkp = new HKP(keyserverBaseUrl)
const lookupOpts = { const lookupOpts = {
@ -75,7 +76,7 @@ export async function fetchHKP (identifier, keyserverDomain = 'keys.openpgp.org'
* 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<Profile>} The profile from the fetched OpenPGP key * @returns {Promise<Profile>}
* @example * @example
* const key = doip.keys.fetchWKD('alice@domain.tld'); * const key = doip.keys.fetchWKD('alice@domain.tld');
*/ */
@ -112,9 +113,9 @@ export async function fetchWKD (identifier) {
/** /**
* Fetch a public key from Keybase * Fetch a public key from Keybase
* @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<Profile>} The profile from the fetched OpenPGP key * @returns {Promise<Profile>}
* @example * @example
* const key = doip.keys.fetchKeybase('alice', '123abc123abc'); * const key = doip.keys.fetchKeybase('alice', '123abc123abc');
*/ */
@ -154,10 +155,10 @@ export async function fetchKeybase (username, fingerprint) {
} }
/** /**
* Get a public key from armored public key text 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<Profile>} The profile from the armored public key * @returns {Promise<Profile>}
* @example * @example
* const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK----- * const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
* *
@ -184,7 +185,7 @@ export async function fetchPlaintext (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<Profile>} The profile from the fetched OpenPGP key * @returns {Promise<Profile>}
* @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');
@ -230,7 +231,7 @@ export async function fetchURI (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<Profile>} The profile from the fetched OpenPGP key * @returns {Promise<Profile>}
* @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');
@ -272,7 +273,7 @@ export async function fetch (identifier) {
* Process a public key to get a profile * Process a public key to get a profile
* @function * @function
* @param {PublicKey} publicKey - The public key to parse * @param {PublicKey} publicKey - The public key to parse
* @returns {Promise<Profile>} The profile from the processed OpenPGP key * @returns {Promise<Profile>}
* @example * @example
* const key = doip.keys.fetchURI('hkp:alice@domain.tld'); * const key = doip.keys.fetchURI('hkp:alice@domain.tld');
* const profile = doip.keys.parsePublicKey(key); * const profile = doip.keys.parsePublicKey(key);

View file

@ -16,16 +16,18 @@ limitations under the License.
import { Claim } from './claim.js' import { Claim } from './claim.js'
/** /**
* A persona with identity claims
* @class * @class
* @classdesc A persona with identity claims * @constructor
* @public
* @example * @example
* 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]);
*/ */
export class Persona { export class Persona {
/** /**
* @param {string} name - Name of the persona * @param {string} name
* @param {Array<Claim>} claims - Claims of the persona * @param {import('./claim.js').Claim[]} claims
*/ */
constructor (name, claims) { constructor (name, claims) {
/** /**
@ -66,7 +68,7 @@ export class Persona {
this.themeColor = null this.themeColor = null
/** /**
* List of identity claims * List of identity claims
* @type {Array<Claim>} * @type {import('./claim.js').Claim[]}
* @public * @public
*/ */
this.claims = claims this.claims = claims
@ -79,11 +81,10 @@ export class Persona {
} }
/** /**
* Parse a JSON object and convert it into a persona
* @function * @function
* @param {object} personaObject - JSON representation of a persona * @param {object} personaObject
* @param {number} profileVersion - Version of the Profile containing the persona * @param {number} profileVersion
* @returns {Persona | Error} Parsed persona * @returns {Persona | Error}
* @example * @example
* doip.Persona.fromJSON(JSON.stringify(persona), 2); * doip.Persona.fromJSON(JSON.stringify(persona), 2);
*/ */
@ -111,52 +112,46 @@ export class Persona {
} }
/** /**
* Set the persona's identifier
* @function * @function
* @param {string} identifier - Identifier of the persona * @param {string} identifier
*/ */
setIdentifier (identifier) { setIdentifier (identifier) {
this.identifier = identifier this.identifier = identifier
} }
/** /**
* Set the persona's description
* @function * @function
* @param {string} description - Description of the persona * @param {string} description
*/ */
setDescription (description) { setDescription (description) {
this.description = description this.description = description
} }
/** /**
* Set the persona's email address
* @function * @function
* @param {string} email - Email address of the persona * @param {string} email
*/ */
setEmailAddress (email) { setEmailAddress (email) {
this.email = email this.email = email
} }
/** /**
* Set the URL to the persona's avatar
* @function * @function
* @param {string} avatarUrl - URL to the persona's avatar * @param {string} avatarUrl
*/ */
setAvatarUrl (avatarUrl) { setAvatarUrl (avatarUrl) {
this.avatarUrl = avatarUrl this.avatarUrl = avatarUrl
} }
/** /**
* Add a claim
* @function * @function
* @param {Claim} claim - Claim to add * @param {import('./claim.js').Claim} claim
*/ */
addClaim (claim) { addClaim (claim) {
this.claims.push(claim) this.claims.push(claim)
} }
/** /**
* Revoke the persona
* @function * @function
*/ */
revoke () { revoke () {
@ -164,9 +159,9 @@ export class Persona {
} }
/** /**
* Get a JSON representation of the persona * Get a JSON representation of the Profile object
* @function * @function
* @returns {object} JSON representation of the persona * @returns {object}
*/ */
toJSON () { toJSON () {
return { return {
@ -183,9 +178,8 @@ export class Persona {
} }
/** /**
* @ignore * @param {object} personaObject
* @param {object} personaObject - JSON representation of a persona * @returns {Persona | Error}
* @returns {Persona | Error} Parsed persona
*/ */
function importJsonPersonaVersion2 (personaObject) { function importJsonPersonaVersion2 (personaObject) {
const claims = personaObject.claims.map(x => Claim.fromJSON(x)) const claims = personaObject.claims.map(x => Claim.fromJSON(x))

View file

@ -13,13 +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 { PublicKeyFetchMethod, PublicKeyEncoding, PublicKeyType, ProfileType } from './enums.js' import { PublicKeyFetchMethod, PublicKeyEncoding, PublicKeyType } from './enums.js'
import { Persona } from './persona.js' import { Persona } from './persona.js'
/** /**
* @class * A profile of personas with identity claims
* @classdesc A profile of personas with identity claims * @function
* @param {Array<Persona>} personas - Personas of the profile * @param {Array<import('./persona.js').Persona>} personas
* @public
* @example * @example
* 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]);
@ -29,16 +30,21 @@ export class Profile {
/** /**
* Create a new profile * Create a new profile
* @function * @function
* @param {ProfileType} profileType - Type of profile (ASP, OpenPGP, etc.) * @param {import('./enums.js').ProfileType} profileType
* @param {string} identifier - Profile identifier (fingerprint, URI, etc.) * @param {string} identifier
* @param {Array<Persona>} personas - Personas of the profile * @param {Array<import('./persona.js').Persona>} personas
* @public * @public
*/ */
constructor (profileType, identifier, personas) { constructor (profileType, identifier, personas) {
/**
* Profile version
* @type {number}
* @public
*/
this.profileVersion = 2 this.profileVersion = 2
/** /**
* Profile version * Profile version
* @type {ProfileType} * @type {import('./enums.js').ProfileType}
* @public * @public
*/ */
this.profileType = profileType this.profileType = profileType
@ -50,7 +56,7 @@ export class Profile {
this.identifier = identifier this.identifier = identifier
/** /**
* List of personas * List of personas
* @type {Array<Persona>} * @type {Array<import('./persona.js').Persona>}
* @public * @public
*/ */
this.personas = personas || [] this.personas = personas || []
@ -62,34 +68,78 @@ export class Profile {
this.primaryPersonaIndex = personas.length > 0 ? 0 : -1 this.primaryPersonaIndex = personas.length > 0 ? 0 : -1
/** /**
* The cryptographic key associated with the profile * The cryptographic key associated with the profile
* @type {import('./types').ProfilePublicKey} * @property {object}
* @public * @public
*/ */
this.publicKey = { this.publicKey = {
/**
* The type of cryptographic key
* @type {PublicKeyType}
* @public
*/
keyType: PublicKeyType.NONE, keyType: PublicKeyType.NONE,
/**
* The fingerprint of the cryptographic key
* @type {string | null}
* @public
*/
fingerprint: null, fingerprint: null,
/**
* The encoding of the cryptographic key
* @type {PublicKeyEncoding}
* @public
*/
encoding: PublicKeyEncoding.NONE, encoding: PublicKeyEncoding.NONE,
/**
* The encoded cryptographic key
* @type {string | null}
* @public
*/
encodedKey: null, encodedKey: null,
/**
* The raw cryptographic key as object (to be removed during toJSON())
* @type {import('openpgp').PublicKey | import('jose').JWK | null}
* @public
*/
key: null, key: null,
/**
* Details on how to fetch the public key
* @property {object}
* @public
*/
fetch: { fetch: {
/**
* The method to fetch the key
* @type {PublicKeyFetchMethod}
* @public
*/
method: PublicKeyFetchMethod.NONE, method: PublicKeyFetchMethod.NONE,
/**
* The query to fetch the key
* @type {string | null}
* @public
*/
query: null, query: null,
/**
* The URL the method eventually resolved to
* @type {string | null}
* @public
*/
resolvedUrl: null resolvedUrl: null
} }
} }
/** /**
* List of verifier URLs * List of verifier URLs
* @type {Array<import('./types').ProfileVerifier>} * @type {{name: string, url: string}[]}
* @public * @public
*/ */
this.verifiers = [] this.verifiers = []
} }
/** /**
* Parse a JSON object and convert it into a profile
* @function * @function
* @param {object} profileObject - JSON representation of a profile * @param {object} profileObject
* @returns {Profile | Error} Parsed profile * @returns {Profile | Error}
* @example * @example
* doip.Profile.fromJSON(JSON.stringify(profile)); * doip.Profile.fromJSON(JSON.stringify(profile));
*/ */
@ -117,19 +167,18 @@ export class Profile {
} }
/** /**
* Add profile verifier to the profile
* @function * @function
* @param {string} name - Name of the verifier * @param {string} name
* @param {string} url - URL of the verifier * @param {string} url
*/ */
addVerifier (name, url) { addVerifier (name, url) {
this.verifiers.push({ name, url }) this.verifiers.push({ name, url })
} }
/** /**
* Get a JSON representation of the profile * Get a JSON representation of the Profile object
* @function * @function
* @returns {object} JSON representation of the profile * @returns {object}
*/ */
toJSON () { toJSON () {
return { return {
@ -155,9 +204,8 @@ export class Profile {
} }
/** /**
* @ignore * @param {object} profileObject
* @param {object} profileObject - JSON representation of the profile * @returns {Profile | Error}
* @returns {Profile | Error} Parsed profile
*/ */
function importJsonProfileVersion2 (profileObject) { function importJsonProfileVersion2 (profileObject) {
if (!('profileVersion' in profileObject && profileObject.profileVersion === 2)) { if (!('profileVersion' in profileObject && profileObject.profileVersion === 2)) {

View file

@ -17,7 +17,6 @@ import { isNode } from 'browser-or-node'
import { fetcher } from './index.js' import { fetcher } from './index.js'
import { generateProxyURL } from './utils.js' import { generateProxyURL } from './utils.js'
import { ProxyPolicy, ProofAccessRestriction } from './enums.js' import { ProxyPolicy, ProofAccessRestriction } from './enums.js'
import { ServiceProvider } from './serviceProvider.js'
/** /**
* @module proofs * @module proofs
@ -29,9 +28,10 @@ import { ServiceProvider } from './serviceProvider.js'
* the `data` parameter and the proxy policy set in the `opts` parameter to * the `data` parameter and the proxy policy set in the `opts` parameter to
* choose the right approach to fetch the proof. An error will be thrown if no * choose the right approach to fetch the proof. An error will be thrown if no
* approach is possible. * approach is possible.
* @param {ServiceProvider} data - Data from a claim definition * @async
* @param {import('./types').VerificationConfig} opts - Options to enable the request * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @returns {Promise<object|string>} Fetched proof data * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>}
*/ */
export async function fetch (data, opts) { export async function fetch (data, opts) {
if (isNode) { if (isNode) {
@ -42,9 +42,9 @@ export async function fetch (data, opts) {
} }
/** /**
* @param {ServiceProvider} data - Data from a claim definition * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} Fetched proof data * @returns {Promise<object|string>}
*/ */
const handleBrowserRequests = (data, opts) => { const handleBrowserRequests = (data, opts) => {
switch (opts.proxy.policy) { switch (opts.proxy.policy) {
@ -85,9 +85,9 @@ const handleBrowserRequests = (data, opts) => {
} }
/** /**
* @param {ServiceProvider} data - Data from a claim definition * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} Fetched proof data * @returns {Promise<object|string>}
*/ */
const handleNodeRequests = (data, opts) => { const handleNodeRequests = (data, opts) => {
switch (opts.proxy.policy) { switch (opts.proxy.policy) {
@ -106,9 +106,9 @@ const handleNodeRequests = (data, opts) => {
} }
/** /**
* @param {ServiceProvider} data - Data from a claim definition * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} Fetched proof data * @returns {Promise<object|string>}
*/ */
const createDefaultRequestPromise = (data, opts) => { const createDefaultRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -132,9 +132,9 @@ const createDefaultRequestPromise = (data, opts) => {
} }
/** /**
* @param {ServiceProvider} data - Data from a claim definition * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} Fetched proof data * @returns {Promise<object|string>}
*/ */
const createProxyRequestPromise = (data, opts) => { const createProxyRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -171,9 +171,9 @@ const createProxyRequestPromise = (data, opts) => {
} }
/** /**
* @param {ServiceProvider} data - Data from a claim definition * @param {import('./serviceProvider.js').ServiceProvider} data - Data from a claim definition
* @param {object} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {Promise<object|string>} Fetched proof data * @returns {Promise<object|string>}
*/ */
const createFallbackRequestPromise = (data, opts) => { const createFallbackRequestPromise = (data, opts) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View file

@ -13,43 +13,129 @@ 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.
*/ */
/** /**
* A service provider matched to an identity claim * A service provider matched to an identity claim
* @class * @class
* @constructor
* @public * @public
*/ */
export class ServiceProvider { export class ServiceProvider {
/** /**
* @param {import('./types').ServiceProviderObject} serviceProviderObject - JSON representation of a {@link ServiceProvider} * @param {object} spObj
*/ */
constructor (serviceProviderObject) { constructor (spObj) {
/** /**
* Details about the service provider * Details about the service provider
* @type {import('./types').ServiceProviderAbout} * @property {object}
*/ */
this.about = serviceProviderObject.about this.about = {
/**
* Identifier of the service provider (no whitespace or symbols, lowercase)
* @type {string}
*/
id: spObj.about.id,
/**
* Full name of the service provider
* @type {string}
*/
name: spObj.about.name,
/**
* URL to the homepage of the service provider
* @type {string | null}
*/
homepage: spObj.about.homepage || null
}
/** /**
* What the profile would look like if a claim matches this service provider * What the profile would look like if the match is correct
* @type {import('./types').ServiceProviderProfile} * @property {object}
*/ */
this.profile = serviceProviderObject.profile this.profile = {
/**
* Profile name to be displayed
* @type {string}
*/
display: spObj.profile.display,
/**
* URI or URL for public access to the profile
* @type {string}
*/
uri: spObj.profile.uri,
/**
* URI or URL associated with the profile usually served as a QR code
* @type {string | null}
*/
qr: spObj.profile.qr || null
}
/** /**
* Information about the claim matching process * Details from the claim matching process
* @type {import('./types').ServiceProviderClaim} * @property {object}
*/ */
this.claim = serviceProviderObject.claim this.claim = {
/**
* Regular expression used to parse the URI
* @type {string}
*/
uriRegularExpression: spObj.claim.uriRegularExpression,
/**
* Whether this match automatically excludes other matches
* @type {boolean}
*/
uriIsAmbiguous: spObj.claim.uriIsAmbiguous
}
/** /**
* Information for the proof verification process * Information for the proof verification process
* @type {import('./types').ServiceProviderProof} * @property {object}
*/ */
this.proof = serviceProviderObject.proof this.proof = {
/**
* Details to request the potential proof
* @property {object}
*/
request: {
/**
* Location of the proof
* @type {string | null}
*/
uri: spObj.proof.request.uri,
/**
* Fetcher to be used to request the proof
* @type {string}
*/
fetcher: spObj.proof.request.fetcher,
/**
* Type of access restriction
* @type {import('./enums.js').ProofAccessRestriction}
*/
accessRestriction: spObj.proof.request.accessRestriction,
/**
* Data needed by the fetcher or proxy to request the proof
* @type {object}
*/
data: spObj.proof.request.data
},
/**
* Details about the expected response
* @property {object}
*/
response: {
/**
* Expected format of the proof
* @type {import('./enums.js').ProofFormat}
*/
format: spObj.proof.response.format
},
/**
* Details about the target located in the response
* @type {{format: import('./enums.js').ClaimFormat, encoding: import('./enums.js').EntityEncodingFormat, relation: import('./enums.js').ClaimRelation, path: string[]}[]}
*/
target: spObj.proof.target
}
} }
/** /**
* Get a JSON representation of the {@link ServiceProvider} * Get a JSON representation of the ServiceProvider object
* @function * @function
* @returns {import('./types').ServiceProviderObject} JSON representation of a {@link ServiceProvider} * @returns {object}
*/ */
toJSON () { toJSON () {
return { return {

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* ActivityPub service provider ({@link https://docs.keyoxide.org/service-providers/activitypub/|Keyoxide docs})
* @module serviceProviders/activitypub
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.activitypub.processURI('https://domain.example/@alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { fetcher } from '../index.js' import { fetcher } from '../index.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -29,8 +21,8 @@ export const reURI = /^https:\/\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI * @returns {ServiceProvider}
*/ */
export function processURI (uri) { export function processURI (uri) {
return new ServiceProvider({ return new ServiceProvider({

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* ASPE service provider ({@link https://docs.keyoxide.org/service-providers/aspe/|Keyoxide docs})
* @module serviceProviders/aspe
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.activitypub.processURI('aspe:domain.example:abc123def456');
*/
import isFQDN from 'validator/lib/isFQDN.js' import isFQDN from 'validator/lib/isFQDN.js'
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -29,8 +21,7 @@ export const reURI = /^aspe:([a-zA-Z0-9.\-_]*):([a-zA-Z0-9]*)/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -1,127 +0,0 @@
/*
Copyright 2024 Bram Hagens
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.
*/
/**
* Discord service provider
* @module serviceProviders/discord
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.discord.processURI('https://discord.com/invite/AbCdEf');
*/
import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js'
export const reURI = /^https:\/\/(?:discord\.gg|discord\.com\/invite)\/(.+)/
/**
* @function
* @param {string} uri - Claim URI to process
* @returns {ServiceProvider} The service provider information based on the claim URI
*/
export function processURI (uri) {
const match = uri.match(reURI)
return new ServiceProvider({
about: {
id: 'discord',
name: 'Discord',
homepage: 'https://discord.com'
},
profile: {
display: null,
uri: null,
qr: null
},
claim: {
uriRegularExpression: reURI.toString(),
uriIsAmbiguous: false
},
// Get proof from invites (https://discord.com/developers/docs/resources/invite#get-invite)
// See https://discord.com/developers/docs/reference#api-versioning for Discord's API versioning
proof: {
request: {
uri: `https://discord.com/api/v10/invites/${match[1]}`,
fetcher: E.Fetcher.HTTP,
accessRestriction: E.ProofAccessRestriction.NOCORS,
data: {
url: `https://discord.com/api/v10/invites/${match[1]}`,
format: E.ProofFormat.JSON
}
},
response: {
format: E.ProofFormat.JSON
},
target: [
{
format: E.ClaimFormat.URI,
encoding: E.EntityEncodingFormat.PLAIN,
relation: E.ClaimRelation.CONTAINS,
path: ['guild', 'description']
},
{
format: E.ClaimFormat.URI,
encoding: E.EntityEncodingFormat.PLAIN,
relation: E.ClaimRelation.CONTAINS,
path: ['guild', 'name']
}
]
}
})
}
export const functions = {
postprocess: async (claimData, proofData, opts) => {
// Extract inviter's username from https://discord.com/developers/docs/resources/invite#invite-object
claimData.profile.display = proofData.result.inviter.username
return { claimData, proofData }
}
}
export const tests = [
{
uri: 'https://discord.com/invite/AbCdEf',
shouldMatch: true
},
{
uri: 'https://discord.com/invite/AbCdEfGh',
shouldMatch: true
},
{
uri: 'https://discord.gg/AbCdEf',
shouldMatch: true
},
{
uri: 'https://discord.gg/AbCdEfGh',
shouldMatch: true
},
{
uri: 'https://domain.com/invite/AbCdEf',
shouldMatch: false
},
{
uri: 'https://domain.gg/AbCdEf',
shouldMatch: false
},
{
uri: 'https://discord.com/invite/',
shouldMatch: false
},
{
uri: 'https://discord.gg/',
shouldMatch: false
}
]

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Discourse service provider ({@link https://docs.keyoxide.org/service-providers/discourse/|Keyoxide docs})
* @module serviceProviders/discourse
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.activitypub.processURI('https://domain.example/u/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,8 @@ export const reURI = /^https:\/\/(.*)\/u\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI * @returns {ServiceProvider}
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* DNS service provider ({@link https://docs.keyoxide.org/service-providers/dns/|Keyoxide docs})
* @module serviceProviders/dns
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.dns.processURI('dns:domain.example?type=TXT');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^dns:([a-zA-Z0-9.\-_]*)(?:\?(.*))?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Forem service provider ({@link https://docs.keyoxide.org/service-providers/forem/|Keyoxide docs})
* @module serviceProviders/forem
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.forem.processURI('https://domain.example/alice/title');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Forgejo service provider ({@link https://docs.keyoxide.org/service-providers/forgejo/|Keyoxide docs})
* @module serviceProviders/forgejo
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.forgejo.processURI('https://domain.example/alice/repo');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { fetcher } from '../index.js' import { fetcher } from '../index.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -29,8 +21,7 @@ export const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Gitea service provider ({@link https://docs.keyoxide.org/service-providers/gitea/|Keyoxide docs})
* @module serviceProviders/gitea
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.gitea.processURI('https://domain.example/alice/repo');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/(.*)\/(.*)\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Github service provider ({@link https://docs.keyoxide.org/service-providers/github/|Keyoxide docs})
* @module serviceProviders/github
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.github.processURI('https://gist.github.com/alice/title');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/gist\.github\.com\/(.*)\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Gitlab service provider ({@link https://docs.keyoxide.org/service-providers/gitlab/|Keyoxide docs})
* @module serviceProviders/gitlab
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.gitlab.processURI('https://domain.example/alice/repo');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/(.*)\/(.*)\/gitlab_proof\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)
@ -50,6 +41,7 @@ export function processURI (uri) {
uriIsAmbiguous: true uriIsAmbiguous: true
}, },
proof: { proof: {
uri,
request: { request: {
fetcher: E.Fetcher.HTTP, fetcher: E.Fetcher.HTTP,
accessRestriction: E.ProofAccessRestriction.NONE, accessRestriction: E.ProofAccessRestriction.NONE,

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Hackernews service provider ({@link https://docs.keyoxide.org/service-providers/hackernews/|Keyoxide docs})
* @module serviceProviders/hackernews
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.hackernews.processURI('https://news.ycombinator.com/user?id=alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/news\.ycombinator\.com\/user\?id=(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -38,8 +38,6 @@ import * as stackexchange from './stackexchange.js'
import * as keybase from './keybase.js' import * as keybase from './keybase.js'
import * as opencollective from './opencollective.js' import * as opencollective from './opencollective.js'
import * as orcid from './orcid.js' import * as orcid from './orcid.js'
import * as pronounscc from './pronounscc.js'
import * as discord from './discord.js'
const _data = { const _data = {
aspe, aspe,
@ -66,9 +64,7 @@ const _data = {
stackexchange, stackexchange,
keybase, keybase,
opencollective, opencollective,
orcid, orcid
pronounscc,
discord
} }
export const list = Object.keys(_data) export const list = Object.keys(_data)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* IRC service provider ({@link https://docs.keyoxide.org/service-providers/irc/|Keyoxide docs})
* @module serviceProviders/irc
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.irc.processURI('irc://domain.example/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^irc:\/\/(.*)\/([a-zA-Z0-9\-[\]\\`_^{|}]*)/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Keybase service provider ({@link https://docs.keyoxide.org/service-providers/keybase/|Keyoxide docs})
* @module serviceProviders/keybase
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.keybase.processURI('https://keybase.io/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/keybase.io\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Liberapay service provider ({@link https://docs.keyoxide.org/service-providers/liberapay/|Keyoxide docs})
* @module serviceProviders/liberapay
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.liberapay.processURI('https://liberapay.com/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/liberapay\.com\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Lichess service provider ({@link https://docs.keyoxide.org/service-providers/lichess/|Keyoxide docs})
* @module serviceProviders/lichess
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.lichess.processURI('https://lichess.org/@/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/lichess\.org\/@\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Lobste.rs service provider ({@link https://docs.keyoxide.org/service-providers/lobsters/|Keyoxide docs})
* @module serviceProviders/lobsters
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.lobsters.processURI('https://lobste.rs/~alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/lobste\.rs\/(?:~|u\/)(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Matrix service provider ({@link https://docs.keyoxide.org/service-providers/matrix/|Keyoxide docs})
* @module serviceProviders/matrix
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.matrix.processURI('matrix:u/...');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^matrix:u\/(?:@)?([^@:]*:[^?]*)(\?.*)?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* OpenCollective service provider ({@link https://docs.keyoxide.org/service-providers/opencollective/|Keyoxide docs})
* @module serviceProviders/opencollective
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.opencollective.processURI('https://opencollective.com/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/opencollective\.com\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* OpenPGP service provider ({@link https://docs.keyoxide.org/service-providers/openpgp/|Keyoxide docs})
* @module serviceProviders/openpgp
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.openpgp.processURI('openpgp4fpr:ABC123DEF456');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -32,8 +24,7 @@ const reURIWkdAdvanced = /^https:\/\/(openpgpkey.*)\/.well-known\/openpgpkey\/(.
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
let reURI = null let reURI = null

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* ORCiD service provider ({@link https://docs.keyoxide.org/service-providers/orcid/|Keyoxide docs})
* @module serviceProviders/orcid
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.orcid.processURI('https://orcid.org/123-456-789-123');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/orcid\.org\/(.*)\/?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Owncast service provider ({@link https://docs.keyoxide.org/service-providers/owncast/|Keyoxide docs})
* @module serviceProviders/owncast
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.owncast.processURI('https://domain.example');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/(.*)/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -1,100 +0,0 @@
/*
Copyright 2024 Tyler Beckman
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.
*/
/**
* pronouns.cc service provider
* @module serviceProviders/pronounscc
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.pronounscc.processURI('https://pronouns.cc/@Alice');
*/
import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js'
export const reURI = /^https:\/\/pronouns\.cc\/@(.*)\/?/
/**
* @function
* @param {string} uri - Claim URI to process
* @returns {ServiceProvider} The service provider information based on the claim URI
*/
export function processURI (uri) {
const match = uri.match(reURI)
return new ServiceProvider({
about: {
id: 'pronounscc',
name: 'pronouns.cc',
homepage: 'https://pronouns.cc'
},
profile: {
display: `@${match[1]}`,
uri: `https://pronouns.cc/@${match[1]}`,
qr: null
},
claim: {
uriRegularExpression: reURI.toString(),
uriIsAmbiguous: false
},
proof: {
request: {
uri,
fetcher: E.Fetcher.HTTP,
accessRestriction: E.ProofAccessRestriction.NOCORS,
data: {
url: `https://pronouns.cc/api/v1/users/${match[1]}`,
format: E.ProofFormat.JSON
}
},
response: {
format: E.ProofFormat.JSON
},
target: [
{
format: E.ClaimFormat.URI,
encoding: E.EntityEncodingFormat.PLAIN,
relation: E.ClaimRelation.CONTAINS,
path: ['links']
},
{
format: E.ClaimFormat.URI,
encoding: E.EntityEncodingFormat.PLAIN,
relation: E.ClaimRelation.CONTAINS,
path: ['bio']
}
]
}
})
}
export const tests = [
{
uri: 'https://pronouns.cc/@Alice',
shouldMatch: true
},
{
uri: 'https://pronouns.cc/@Alice/',
shouldMatch: true
},
{
uri: 'https://pronouns.cc/Alice',
shouldMatch: false
},
{
uri: 'https://pronouns.cc/Alice/',
shouldMatch: false
}
]

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Reddit service provider ({@link https://docs.keyoxide.org/service-providers/reddit/|Keyoxide docs})
* @module serviceProviders/reddit
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.reddit.processURI('https://reddit.com/...');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/(?:www\.)?reddit\.com\/user\/(.*)\/comments\/(.
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* StackExchange service provider ({@link https://docs.keyoxide.org/service-providers/stackexchange/|Keyoxide docs})
* @module serviceProviders/stackexchange
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.stackexchange.processURI('https://stackoverflow.com/users/123/alice');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -29,8 +21,7 @@ const reStackExchange = /\.stackexchange$/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const [, domain, id] = uri.match(reURI) const [, domain, id] = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Telegram service provider ({@link https://docs.keyoxide.org/service-providers/telegram/|Keyoxide docs})
* @module serviceProviders/telegram
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.telegram.processURI('https://t.me/alice?proof=mygroup');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /https:\/\/t.me\/([A-Za-z0-9_]{5,32})\?proof=([A-Za-z0-9_]{
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* Twitter service provider ({@link https://docs.keyoxide.org/service-providers/twitter/|Keyoxide docs})
* @module serviceProviders/twitter
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.twitter.processURI('https://twitter.com/alice/status/123456789');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^https:\/\/twitter\.com\/(.*)\/status\/([0-9]*)(?:\?.*)?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

View file

@ -13,14 +13,6 @@ 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.
*/ */
/**
* XMPP service provider ({@link https://docs.keyoxide.org/service-providers/xmpp/|Keyoxide docs})
* @module serviceProviders/xmpp
* @example
* import { ServiceProviderDefinitions } from 'doipjs';
* const sp = ServiceProviderDefinitions.data.xmpp.processURI('xmpp:alice@domain.example');
*/
import * as E from '../enums.js' import * as E from '../enums.js'
import { ServiceProvider } from '../serviceProvider.js' import { ServiceProvider } from '../serviceProvider.js'
@ -28,8 +20,7 @@ export const reURI = /^xmpp:([a-zA-Z0-9.\-_]*)@([a-zA-Z0-9.\-_]*)(?:\?(.*))?/
/** /**
* @function * @function
* @param {string} uri - Claim URI to process * @param {string} uri
* @returns {ServiceProvider} The service provider information based on the claim URI
*/ */
export function processURI (uri) { export function processURI (uri) {
const match = uri.match(reURI) const match = uri.match(reURI)

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.
*/ */
import { CleartextMessage, PublicKey, readCleartextMessage, verify } from 'openpgp' import { readCleartextMessage, verify } from 'openpgp'
import { Claim } from './claim.js' import { Claim } from './claim.js'
import { fetchURI } from './openpgp.js' import { fetchURI } from './openpgp.js'
import { Profile } from './profile.js' import { Profile } from './profile.js'
@ -26,11 +26,12 @@ import { Persona } from './persona.js'
/** /**
* Extract the profile from a signature and fetch the associated key * Extract the profile from a signature and fetch the associated key
* @async
* @param {string} signature - The plaintext signature to parse * @param {string} signature - The plaintext signature to parse
* @returns {Promise<Profile>} The profile obtained from the signature * @returns {Promise<import('./profile.js').Profile>}
*/ */
export async function parse (signature) { export async function parse (signature) {
/** @type {CleartextMessage} */ /** @type {import('openpgp').CleartextMessage} */
let sigData let sigData
// Read the signature // Read the signature
@ -83,7 +84,7 @@ export async function parse (signature) {
if (sigKeys.length > 0) { if (sigKeys.length > 0) {
try { try {
obtainedKey.query = sigKeys[0] obtainedKey.query = sigKeys[0]
/** @type {PublicKey} */ /** @type {import('openpgp').PublicKey} */
obtainedKey.data = (await fetchURI(obtainedKey.query)).publicKey.key obtainedKey.data = (await fetchURI(obtainedKey.query)).publicKey.key
obtainedKey.method = obtainedKey.query.split(':')[0] obtainedKey.method = obtainedKey.query.split(':')[0]
} catch (e) {} } catch (e) {}

View file

@ -1,198 +0,0 @@
/*
Copyright 2024 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 various types
* @module types
*/
import { PublicKeyType, PublicKeyEncoding, PublicKeyFetchMethod, ProxyPolicy, ClaimFormat, EntityEncodingFormat, ClaimRelation, ProofAccessRestriction, ProofFormat } from './enums'
/**
* Service provider
* @typedef {object} ServiceProviderObject
* @property {ServiceProviderAbout} about - Details about the service provider
* @property {ServiceProviderProfile} profile - What the profile would look like if a claim matches this service provider
* @property {ServiceProviderClaim} claim - Details from the claim matching process
* @property {ServiceProviderProof} proof - Information for the proof verification process
*/
/**
* Details about the service provider
* @typedef {object} ServiceProviderAbout
* @property {string} id - Identifier of the service provider (no whitespace or symbols, lowercase)
* @property {string} name - Full name of the service provider
* @property {string} [homepage] - URL to the homepage of the service provider
*/
/**
* What the profile would look like if a claim matches this service provider
* @typedef {object} ServiceProviderProfile
* @property {string} display - Profile name to be displayed
* @property {string} uri - URI or URL for public access to the profile
* @property {string} [qr] -URI or URL associated with the profile usually served as a QR code
*/
/**
* Information about the claim matching process
* @typedef {object} ServiceProviderClaim
* @property {string} uriRegularExpression - Regular expression used to parse the URI
* @property {boolean} uriIsAmbiguous - Whether this match automatically excludes other matches
*/
/**
* Information for the proof verification process
* @typedef {object} ServiceProviderProof
* @property {ServiceProviderProofRequest} request - Details to request the potential proof
* @property {ServiceProviderProofResponse} response - Details about the expected response
* @property {Array<ProofTarget>} target - Details about the target located in the response
*/
/**
* Details to request the potential proof
* @typedef {object} ServiceProviderProofRequest
* @property {string} [uri] - Location of the proof
* @property {string} fetcher - Fetcher to be used to request the proof
* @property {ProofAccessRestriction} accessRestriction - Type of access restriction
* @property {object} data - Data needed by the fetcher or proxy to request the proof
*/
/**
* Details about the expected response
* @typedef {object} ServiceProviderProofResponse
* @property {ProofFormat} format - Expected format of the proof
*/
/**
* Public key for a profile
* @typedef {object} ProfilePublicKey
* @property {PublicKeyType} keyType - The type of cryptographic key
* @property {PublicKeyEncoding} encoding - The encoding of the cryptographic key
* @property {string} [fingerprint] - The fingerprint of the cryptographic key
* @property {string} [encodedKey] - The encoded cryptographic key
* @property {import('openpgp').PublicKey | import('jose').JWK} [key] - The raw cryptographic key as object (to be removed during toJSON())
* @property {ProfilePublicKeyFetch} fetch - Details on how to fetch the public key
*/
/**
* Details on how to fetch the public key
* @typedef {object} ProfilePublicKeyFetch
* @property {PublicKeyFetchMethod} method - The method to fetch the key
* @property {string} [query] - The query to fetch the key
* @property {string} [resolvedUrl] - The URL the method eventually resolved to
*/
/**
* Config used for the claim verification
* @typedef {object} VerificationConfig
* @property {ProxyVerificationConfig} [proxy] - Options related to the use of proxy servers
* @property {ClaimVerificationConfig} [claims] - Config related to the verification of supported claims
*/
/**
* Config related to the use of proxy servers
* @typedef {object} ProxyVerificationConfig
* @property {string} [scheme] - The scheme to use for proxy requests
* @property {string} [hostname] - The hostname of the proxy
* @property {ProxyPolicy} policy - The policy that defines when to use a proxy
*/
/**
* Config related to the verification of supported claims
* @typedef {object} ClaimVerificationConfig
* @property {ActivityPubClaimVerificationConfig} [activitypub] - Config related to the verification of ActivityPub claims
* @property {IrcClaimVerificationConfig} [irc] - Config related to the verification of IRC claims
* @property {MatrixClaimVerificationConfig} [matrix] - Config related to the verification of Matrix claims
* @property {TelegramClaimVerificationConfig} [telegram] - Config related to the verification of Telegram claims
* @property {XmppClaimVerificationConfig} [xmpp] - Config related to the verification of XMPP claims
*/
/**
* Config related to the verification of ActivityPub claims
* @typedef {object} ActivityPubClaimVerificationConfig
* @property {string} url - The URL of the verifier account
* @property {string} privateKey - The private key to sign the request
*/
/**
* Config related to the verification of IRC claims
* @typedef {object} IrcClaimVerificationConfig
* @property {string} nick - The nick that the library uses to connect to the IRC server
* @property {{ domainRegex: string; username: string; password: string; }[]} sasl - An array of possible SASL logins
*/
/**
* Config related to the verification of Matrix claims
* @typedef {object} MatrixClaimVerificationConfig
* @property {string} instance - The server hostname on which the library can log in
* @property {string} accessToken - The access token required to identify the library ({@link https://www.matrix.org/docs/guides/client-server-api|Matrix docs})
*/
/**
* Config related to the verification of Telegram claims
* @typedef {object} TelegramClaimVerificationConfig
* @property {string} token - The Telegram API's token ({@link https://core.telegram.org/bots/api#authorizing-your-bot|Telegram docs})
*/
/**
* Config related to the verification of XMPP claims
* @typedef {object} XmppClaimVerificationConfig
* @property {string} service - The server hostname on which the library can log in
* @property {string} username - The username used to log in
* @property {string} password - The password used to log in
*/
/**
* The online verifier instance of identity profiles like Keyoxide's web interface
* @typedef {object} ProfileVerifier
* @property {string} name - Name of the profile verifier
* @property {string} url - URL to the profile verifier
*/
/**
* Parameters needed to perform the proof verification
* @typedef {object} VerificationParams
* @property {string} target - Proof to search
* @property {ClaimFormat} claimFormat - Format of the claim
* @property {EntityEncodingFormat} proofEncodingFormat - Encoding of the data containing the proof
* @property {ClaimRelation} [claimRelation] - How to find the proof inside the JSON data
*/
/**
* Result of the proof verification
* @typedef {object} VerificationResult
* @property {boolean} result - Whether the proof was found and the claim verified
* @property {boolean} completed - Whether the verification process completed without errors
* @property {VerificationResultProof} [proof] - Details about the proof and how it was fetched
* @property {Array<any>} errors - Errors that ocurred during the verification process
*/
/**
* Information about the proof in the proof verification result
* @typedef {object} VerificationResultProof
* @property {string} fetcher - Which fetcher was used to obtain the data containing the proof
* @property {boolean} viaProxy - Whether a proxy was used to obtain the data containing the proof
*/
/**
* The method to find the proof inside the response data
* @typedef {object} ProofTarget
* @property {ClaimFormat} format - How the response data is formatted
* @property {EntityEncodingFormat} encoding - How the response data is encoded
* @property {ClaimRelation} relation - How the proof is related to the response data
* @property {Array<string>} path - Path to the proof inside the response data object
*/
export const Types = {}

View file

@ -22,10 +22,13 @@ import { ClaimFormat } from './enums.js'
/** /**
* Generate an URL to request data from a proxy server * Generate an URL to request data from a proxy server
* @param {string} type - The name of the fetcher the proxy must use * @param {string} type - The name of the fetcher the proxy must use
* @param {object} data - The data the proxy must provide to the fetcher * @param {object} data - The data the proxy must provide to the fetcher
* @param {import('./types').VerificationConfig} opts - Options to enable the request * @param {object} opts - Options to enable the request
* @returns {string} Generated proxy URL * @param {object} opts.proxy - Proxy related options
* @param {object} opts.proxy.scheme - The scheme used by the proxy server
* @param {object} opts.proxy.hostname - The hostname of the proxy server
* @returns {string}
*/ */
export function generateProxyURL (type, data, opts) { export function generateProxyURL (type, data, opts) {
try { try {
@ -40,7 +43,7 @@ export function generateProxyURL (type, data, opts) {
queryStrings.push(`${key}=${encodeURIComponent(data[key])}`) queryStrings.push(`${key}=${encodeURIComponent(data[key])}`)
}) })
const scheme = opts.proxy.scheme ?? 'https' const scheme = opts.proxy.scheme ? opts.proxy.scheme : 'https'
return `${scheme}://${opts.proxy.hostname}/api/3/get/${type}?${queryStrings.join( return `${scheme}://${opts.proxy.hostname}/api/3/get/${type}?${queryStrings.join(
'&' '&'
@ -49,9 +52,9 @@ export function generateProxyURL (type, data, opts) {
/** /**
* Generate the string that must be found in the proof to verify a claim * Generate the string that must be found in the proof to verify a claim
* @param {string} fingerprint - The fingerprint of the claim * @param {string} fingerprint - The fingerprint of the claim
* @param {ClaimFormat} format - The claim's format * @param {string} format - The claim's format (see {@link module:enums~ClaimFormat|enums.ClaimFormat})
* @returns {string} Generate claim * @returns {string}
*/ */
export function generateClaim (fingerprint, format) { export function generateClaim (fingerprint, format) {
switch (format) { switch (format) {
@ -69,8 +72,8 @@ export function generateClaim (fingerprint, format) {
/** /**
* Get the URIs from a string and return them as an array * Get the URIs from a string and return them as an array
* @param {string} text - The text that may contain URIs * @param {string} text - The text that may contain URIs
* @returns {Array<string>} List of URIs extracted from input * @returns {Array<string>}
*/ */
export function 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

View file

@ -17,7 +17,6 @@ import { generateClaim, getUriFromString } from './utils.js'
import { ClaimFormat, EntityEncodingFormat, ClaimRelation, ProofFormat } from './enums.js' import { ClaimFormat, EntityEncodingFormat, ClaimRelation, ProofFormat } from './enums.js'
import { bcryptVerify, argon2Verify } from 'hash-wasm' import { bcryptVerify, argon2Verify } from 'hash-wasm'
import { decodeHTML, decodeXML } from 'entities' import { decodeHTML, decodeXML } from 'entities'
import { ServiceProvider } from './serviceProvider.js'
/** /**
* @module verifications * @module verifications
@ -25,11 +24,14 @@ import { ServiceProvider } from './serviceProvider.js'
*/ */
/** /**
* Check if string contains the proof
* @function * @function
* @param {string} data - Data potentially containing the proof * @param {string} data
* @param {import('./types').VerificationParams} params - Verification parameters * @param {object} params
* @returns {Promise<boolean>} Whether the proof was found in the string * @param {string} params.target
* @param {string} params.claimFormat
* @param {string} params.proofEncodingFormat
* @param {string} [params.claimRelation]
* @returns {Promise<boolean>}
*/ */
const containsProof = async (data, params) => { const containsProof = async (data, params) => {
const fingerprintFormatted = generateClaim(params.target, params.claimFormat) const fingerprintFormatted = generateClaim(params.target, params.claimFormat)
@ -213,12 +215,15 @@ const containsProof = async (data, params) => {
} }
/** /**
* Run a JSON object through the verification process
* @function * @function
* @param {*} proofData - Data potentially containing the proof * @param {any} proofData
* @param {Array<string>} checkPath - Paths to check for proof * @param {string[]} checkPath
* @param {import('./types').VerificationParams} params - Verification parameters * @param {object} params
* @returns {Promise<boolean>} Whether the proof was found in the object * @param {string} params.target
* @param {string} params.claimFormat
* @param {string} params.proofEncodingFormat
* @param {string} [params.claimRelation]
* @returns {Promise<boolean>}
*/ */
const runJSON = async (proofData, checkPath, params) => { const runJSON = async (proofData, checkPath, params) => {
if (!proofData) { if (!proofData) {
@ -265,14 +270,14 @@ const runJSON = async (proofData, checkPath, params) => {
} }
/** /**
* Run the verification by searching for the proof in the fetched data * Run the verification by finding the formatted fingerprint in the proof
* @param {object} proofData - The proof data * @async
* @param {ServiceProvider} claimData - The claim data * @param {object} proofData - The proof data
* @param {string} fingerprint - The fingerprint * @param {import('./serviceProvider.js').ServiceProvider} claimData - The claim data
* @returns {Promise<import('./types').VerificationResult>} Result of the verification * @param {string} fingerprint - The fingerprint
* @returns {Promise<object>}
*/ */
export async function run (proofData, claimData, fingerprint) { export async function run (proofData, claimData, fingerprint) {
/** @type {import('./types').VerificationResult} */
const res = { const res = {
result: false, result: false,
completed: false, completed: false,

View file

@ -129,9 +129,9 @@ describe('openpgp.fetchURI', () => {
}) })
describe('openpgp.fetchHKP', () => { describe('openpgp.fetchHKP', () => {
it('should be a function (1 required argument, 1 optional argument)', () => { it('should be a function (2 arguments)', () => {
expect(openpgp.fetchHKP).to.be.a('function') expect(openpgp.fetchHKP).to.be.a('function')
expect(openpgp.fetchHKP).to.have.length(1) expect(openpgp.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 openpgp.fetchHKP(pubKeyFingerprint)).to.be.instanceOf( expect(await openpgp.fetchHKP(pubKeyFingerprint)).to.be.instanceOf(

6389
yarn.lock

File diff suppressed because it is too large Load diff