Comparing version 0.4.2 to 0.5.1
{ | ||
"name": "uport", | ||
"version": "0.4.2", | ||
"version": "0.5.1", | ||
"description": "Library for interacting with uport profiles and attestations", | ||
@@ -15,3 +15,6 @@ "main": "lib/index.js", | ||
"build:browser": "./node_modules/.bin/webpack --config webpack.config.js", | ||
"build": "yarn build:es5 && yarn test && yarn build:browser" | ||
"build": "yarn build:es5 && yarn test && yarn build:browser", | ||
"build:docs:html": "./node_modules/.bin/jsdoc src/* README.md -d docs", | ||
"build:docs:md": "./node_modules/jsdoc-to-markdown/bin/cli.js src/* > DOCS.md", | ||
"build:docs": "npm run build:docs:html && npm run build:docs:md" | ||
}, | ||
@@ -46,4 +49,6 @@ "author": "Pelle Braendgaard <pelle.braendgaard@consensys.net>", | ||
"body-parser": "^1.17.1", | ||
"express" : "^4.15.2", | ||
"express": "^4.15.2", | ||
"jest": "^18.1.0", | ||
"jsdoc": "^3.4.3", | ||
"jsdoc-to-markdown": "^1.3.7", | ||
"json-loader": "^0.5.4", | ||
@@ -50,0 +55,0 @@ "mockdate": "^2.0.1", |
@@ -29,3 +29,3 @@ # uport-js | ||
When interacting privately with a user you will be interchanging signed JWT. To verify the signature of the JWT you and your users will be fetching your public key from the public profile. | ||
When interacting privately with a user you will be interchanging signed JWT([JSON Web Token](https://jwt.io/)). To verify the signature of the JWT you and your users will be fetching your public key from the public profile. | ||
@@ -42,3 +42,3 @@ ## Configure your application | ||
appName: 'App Name', | ||
address: 'MNID Encoded uPort Address For Your App' | ||
address: 'MNID Encoded uPort Address For Your App', | ||
signer: signer, | ||
@@ -110,5 +110,12 @@ networks: networks | ||
``` | ||
For more information about the contents of the profile object see the uport-persona documentation. | ||
### Stateless Challenge/Response | ||
To ensure that the response received was created as a response to your selective disclosure request above, the original request is included in the response from the mobile app. | ||
The default verification rule is that the issuer of the embedded request must match the clientId in your Credentials object and that the original request has not yet expired. | ||
Some applications that exclusively live in the browser are unable to sign the original request. In those cases the request token verification is ignored. | ||
### Requesting Push notification tokens from your users | ||
@@ -115,0 +122,0 @@ |
import { createJWT, verifyJWT } from './JWT' | ||
import { decodeToken } from 'jsontokens' | ||
import UportLite from 'uport-lite' | ||
import nets from 'nets' | ||
export default class Credentials { | ||
/** | ||
* The Credentials class allows you to easily create the signed payloads used in uPort inlcuding | ||
* credentials and signed mobile app requests (ex. selective disclosure requests | ||
* for private data). It also provides signature verification over signed payloads and | ||
* allows you to send push notifications to users. | ||
*/ | ||
class Credentials { | ||
/** | ||
* Instantiates a new uPort Credentials object | ||
* | ||
* @example | ||
* import { Credentials, SimpleSigner } from 'uport' | ||
* const networks = { '0x94365e3b': { rpcUrl: 'https://private.chain/rpc', address: '0x0101.... }} | ||
* const setttings = { networks, address: '5A8bRWU3F7j3REx3vkJ...', signer: new SimpleSigner(process.env.PRIVATE_KEY)} | ||
* const credentials = new Credentials(settings) | ||
* | ||
* @example | ||
* import { Credentials } from 'uport' | ||
* const credentials = new Credentials() | ||
* | ||
* @param {Object} [settings] setttings | ||
* @param {Object} settings.networks networks config object, ie. { '0x94365e3b': { rpcUrl: 'https://private.chain/rpc', address: '0x0101.... }} | ||
* @param {UportLite} settings.registry a registry object from UportLite | ||
* @param {SimpleSigner} settings.signer a signer object, see SimpleSigner.js | ||
* @param {Address} settings.address your uPort address (may be the address of your application's uPort identity) | ||
* @return {Credentials} self | ||
*/ | ||
constructor (settings = {}) { | ||
@@ -20,3 +48,25 @@ this.settings = settings | ||
// Create request token | ||
/** | ||
* Creates a signed request token (JWT) given a request params object. | ||
* | ||
* @example | ||
* const req = { requested: ['name', 'country'], | ||
* callbackUrl: 'https://myserver.com', | ||
* notifications: true } | ||
* credentials.createRequest(req).then(jwt => { | ||
* ... | ||
* }) | ||
requested: ['name','phone','identity_no'], | ||
callbackUrl: 'https://....' // URL to send the response of the request to | ||
notifications: true | ||
* | ||
* @param {Object} [params={}] request params object | ||
* @param {Array} params.requested an array of attributes for which you are requesting credentials to be shared for | ||
* @param {String} params.callbackUrl the url which you want to receive the response of this request | ||
* @param {Boolean} params.notifications boolean if you want to request the ability to send push notifications | ||
* @return {Promise<Object, Error>} a promise which resolves with a signed JSON Web Token or rejects with an error | ||
*/ | ||
createRequest (params = {}) { | ||
@@ -39,18 +89,54 @@ const payload = {} | ||
} | ||
if (params.exp) { //checks for expiration on requests, if none is provided the default is 10 min | ||
payload.exp = params.exp | ||
} else { | ||
payload.exp = Date().getTime() + 600000 | ||
} | ||
return createJWT(this.settings, {...payload, type: 'shareReq'}) | ||
} | ||
// Receive response token from user and return data to promise | ||
/** | ||
* Receive signed response token from mobile app. Verifies and parses the given response token. | ||
* | ||
* @example | ||
* const resToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJyZXF1Z....' | ||
* credentials.receive(resToken).then(res => { | ||
* const credentials = res.verified | ||
const name = res.name | ||
* ... | ||
* }) | ||
* | ||
* @param {String} token a response token | ||
* @param {String} [callbackUrl=null] callbackUrl | ||
* @return {Promise<Object, Error>} a promise which resolves with a parsed response or rejects with an error. | ||
*/ | ||
receive (token, callbackUrl = null) { | ||
return verifyJWT(this.settings, token, callbackUrl).then(({payload, profile}) => { | ||
const credentials = {...profile, ...(payload.own || {}), ...(payload.capabilities && payload.capabilities.length === 1 ? {pushToken: payload.capabilities[0]} : {}), address: payload.iss} | ||
if (payload.nad) { | ||
credentials.networkAddress = payload.nad | ||
function processPayload(settings) { | ||
const credentials = {...profile, ...(payload.own || {}), ...(payload.capabilities && payload.capabilities.length === 1 ? {pushToken: payload.capabilities[0]} : {}), address: payload.iss} | ||
if (payload.nad) { | ||
credentials.networkAddress = payload.nad | ||
} | ||
if (payload.verified) { | ||
return Promise.all(payload.verified.map(token => verifyJWT(settings, token))).then(verified => { | ||
return {...credentials, verified: verified.map(v => ({...v.payload, jwt: v.jwt}))} | ||
}) | ||
} else { | ||
return credentials | ||
} | ||
} | ||
if (payload.verified) { | ||
return Promise.all(payload.verified.map(token => verifyJWT(this.settings, token))).then(verified => { | ||
return {...credentials, verified: verified.map(v => ({...v.payload, jwt: v.jwt}))} | ||
}) | ||
if(this.settings.address) { | ||
if(payload.req) { | ||
return verifyJWT(this.settings, payload.req).then((challenge) => { | ||
if(challenge.payload.iss === this.settings.address && challenge.payload.type === 'shareReq') { | ||
return processPayload(this.settings) | ||
} | ||
}) | ||
} else { | ||
console.log('Challenge was not included in response') | ||
} | ||
} else { | ||
return credentials | ||
return processPayload(this.settings) | ||
} | ||
@@ -60,2 +146,9 @@ }) | ||
/** | ||
* Send a push notification to a user, consumes a token which allows you to send push notifications | ||
* and a url/uri request you want to send to the user. | ||
* | ||
* @param {String} token a push notification token (get a pn token by requesting push permissions in a request) | ||
* @return {Promise<Object, Error>} a promise which resolves with successful status or rejects with an error | ||
*/ | ||
push (token, {url}) { | ||
@@ -92,3 +185,20 @@ return new Promise((resolve, reject) => { | ||
// Create attestation | ||
/** | ||
* Create a credential (a signed JSON Web Token) | ||
* | ||
* @example | ||
* credentials.attest({ | ||
* sub: '5A8bRWU3F7j3REx3vkJ...', // uPort address of user, likely a MNID | ||
* exp: <future timestamp>, | ||
* claim: { name: 'John Smith' } | ||
* }).then( credential => { | ||
* ... | ||
* }) | ||
* | ||
* @param {Object} [credential] a unsigned credential object | ||
* @param {String} credential.sub subject of credential (a uPort address) | ||
* @param {String} credential.claim claim about subject single key value or key mapping to object with multiple values (ie { address: {street: ..., zip: ..., country: ...}}) | ||
* @param {String} credential.exp time at which this claim expires and is no longer valid | ||
* @return {Promise<Object, Error>} a promise which resolves with a credential (JWT) or rejects with an error | ||
*/ | ||
attest ({sub, claim, exp}) { | ||
@@ -98,3 +208,15 @@ return createJWT(this.settings, {sub: sub, claim, exp}) | ||
// Lookup public uport address of any user | ||
/** | ||
* Look up a profile in the registry for a given uPort address. Address must be MNID encoded. | ||
* | ||
* @example | ||
* credentials.lookup('5A8bRWU3F7j3REx3vkJ...').then(profile => { | ||
* const name = profile.name | ||
* const pubkey = profile.pubkey | ||
* ... | ||
* }) | ||
* | ||
* @param {String} address a MNID encoded address | ||
* @return {Promise<Object, Error>} a promise which resolves with parsed profile or rejects with an error | ||
*/ | ||
lookup (address) { | ||
@@ -118,1 +240,3 @@ return this.settings.registry(address) | ||
} | ||
export default Credentials |
@@ -6,2 +6,19 @@ import { createUnsignedToken, TokenVerifier, decodeToken } from 'jsontokens' | ||
/** @module uport-js/JWT */ | ||
/** | ||
* Creates a signed JWT given an address which becomes the issuer, a signer, and a payload for which the signature is over. | ||
* | ||
* @example | ||
* const signer = SimpleSigner(process.env.PRIVATE_KEY) | ||
* createJWT({address: '5A8bRWU3F7j3REx3vkJ...', signer}, {key1: 'value', key2: ..., ... }).then(jwt => { | ||
* ... | ||
* }) | ||
* | ||
* @param {Object} [config] an unsigned credential object | ||
* @param {String} config.address address, typically the uPort address of the signer which becomes the issuer | ||
* @param {SimpleSigner} config.signer a signer, reference our SimpleSigner.js | ||
* @param {Object} payload payload object | ||
* @return {Promise<Object, Error>} a promise which resolves with a signed JSON Web Token or rejects with an error | ||
*/ | ||
export function createJWT ({address, signer}, payload) { | ||
@@ -22,2 +39,23 @@ const signingInput = createUnsignedToken( | ||
/** | ||
* Verifies given JWT. Registry is used to resolve uPort address to public key for verification. | ||
* If the JWT is valid, the promise returns an object including the JWT, the payload of the JWT, | ||
* and the profile of the issuer of the JWT. | ||
* | ||
* @example | ||
* const registry = new UportLite() | ||
* verifyJWT({registry, address: '5A8bRWU3F7j3REx3vkJ...'}, 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJyZXF1Z....').then(obj => { | ||
* const payload = obj.payload | ||
* const profile = obj.profile | ||
* const jwt = obj.jwt | ||
* ... | ||
* }) | ||
* | ||
* @param {Object} [config] an unsigned credential object | ||
* @param {String} config.address address, typically the uPort address of the signer which becomes the issuer | ||
* @param {UportLite} config.registry a uPort registry, reference our uport-lite library | ||
* @param {String} jwt a JSON Web Token to verify | ||
* @param {String} callbackUrl callback url in JWT | ||
* @return {Promise<Object, Error>} a promise which resolves with a response object or rejects with an error | ||
*/ | ||
export function verifyJWT ({registry, address}, jwt, callbackUrl = null) { | ||
@@ -61,2 +99,1 @@ return new Promise((resolve, reject) => { | ||
} | ||
import { SECP256K1Client } from 'jsontokens' | ||
/** | ||
* The SimpleSigner returns a configured function for signing data. It also defines | ||
* an interface that you can also implement yourself and use in our other modules. | ||
* | ||
* @example | ||
* const signer = SimpleSigner(process.env.PRIVATE_KEY) | ||
* signer(data, (err, signature) => { | ||
* ... | ||
* }) | ||
* | ||
* @param {String} privateKey a private key | ||
* @return {Function} a configured signer function | ||
*/ | ||
export default function SimpleSigner (privateKey) { | ||
@@ -9,2 +23,2 @@ return (data, callback) => { | ||
} | ||
} | ||
} |
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
658998
19256
214
19
8