/*
* Copyright (c) 2018-2019 Zippie Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
const axios = require('axios')
const AuthedMessage = require('./message')
const secp256k1 = require('secp256k1')
/**
* Normalize public key parameter by ensuring compressed Buffer instance.
* @protected
* @param {Buffer|String} pubkey
*/
function PublicKey (pubkey) {
pubkey = typeof pubkey === 'string' ? Buffer.from(pubkey, 'hex') : pubkey
pubkey = secp256k1.publicKeyConvert(pubkey, false)
return pubkey
}
/**
* Initialize a new dashboard api connection to URI
* @class
* @public
*
* @param {string} [uri='https://dashboard-service.zippie.org'] Dashboard service URI
*
* @example
* const Dashboard = require('../lib/dashboard.js')
* const api = new Dashboard('https://dashboard-service.zippie.org')
* api.initWithKey(SERVICE_KEY)
*
* api.CheckAllowed(some_key, permission)
* .then(isAllowed => {
* console.info(some_key, permission, isAllowed)
* })
* .catch(error => {
* console.error('Error:', error)
* })
*/
function Dashboard (__uri) {
__uri = __uri || 'https://dashboard-service.zippie.org'
let __signer
/**
* Initialize dashboard API connection using provided user private key.
* @public
* @method Dashboard#initWithKey
*
* @param {*} key
*
* @example
* const Dashboard = require('../lib/dashboard.js')
* const api = new Dashboard('https://dashboard-service.zippie.org')
* api.initWithKey(SERVICE_KEY)
*
* api.CheckAllowed(some_key, permission)
* .then(isAllowed => {
* console.info(some_key, permission, isAllowed)
* })
* .catch(error => {
* console.error('Error:', error)
* })
*/
const initWithKey = (key) => {
__signer = signWithKey(key)
}
/**
* Initialize dashboard API connection using vault and key derivation path.
* @public
* @method Dashboard#initWithVault
*
* @param {*} vault
* @param {*} derive
*
* @example
* const Dashboard = require('../lib/dashboard.js')
* const api = new Dashboard('https://dashboard-service.zippie.org')
* api.initWithVault(vault, 'm/0')
*
* api.CheckAllowed(some_key, permission)
* .then(isAllowed => {
* console.info(some_key, permission, isAllowed)
* })
* .catch(error => {
* console.error('Error:', error)
* })
*/
const initWithVault = (vault, derive) => {
__signer = signWithVault(vault, derive)
}
/** @private */
const signWithKey = (key) => {
return function (mesg) {
return Promise.resolve(mesg.sign(key))
}
}
/** @private */
const signWithVault = (vault, derive) => {
return function (mesg) {
return mesg.signWithVault(vault, derive)
}
}
/** @private */
const signAndSend = async (action, mesg) => {
try {
const result = await axios.post(__uri + '/api/v1' + action, (await __signer(mesg)).serialize())
if ('error' in result.data) {
return Promise.reject(result.data.error)
}
return Promise.resolve(result.data.result)
} catch (e) {
if (e.response.data.error) return Promise.reject(e.response.status + ' - ' + JSON.stringify(e.response.data))
if (e.response) return Promise.reject(e.response.status + ' - ' + e.response.statusText)
if (e.errno) return Promise.reject(e.errno)
return Promise.reject(e)
}
}
/**
* Get a list of all organisations in database, or if pubkey supplied, get organisations
* that the user is a part of.
*
* @method Dashboard#ListOrganisations
* @public
*
* @param {PublicKey} userpub Users public key.
*
* @returns {OrganisationListItem[]}
*/
this.ListOrganisations = (userpub) => {
userpub = userpub ? PublicKey(userpub).toString('hex') : undefined
return signAndSend('/ListOrganisations', new AuthedMessage({ userpub }))
}
/**
* Create a new empty named organisation.
*
* @method Dashboard#CreateOrganisation
* @public
*
* @param {String} name The name of the organisation
*
* @returns {String} Organisation public key
*/
this.CreateOrganisation = (name) => {
return signAndSend('/CreateOrganisation', new AuthedMessage({
name,
}))
}
/**
* Get the organisation metadata
*
* @method Dashboard#GetOrganisationInfo
* @public
*
* @param {PublicKey} orgpub Organisation public key
*
* @returns {OrganisationInfo} Organisation metadata
*/
this.GetOrganisationInfo = (orgpub) => {
const pubkey = PublicKey(orgpub).toString('hex')
return signAndSend('/GetOrganisationInfo', new AuthedMessage({
pubkey,
}))
}
/**
* Set the organisation metadata. (Setting a field to null removes it)
*
* @method Dashboard#SetOrganisationInfo
* @public
*
* @param {PublicKey} orgpub Organisation public key
* @param {Object} info Changes to metadata
*
* @returns {Boolean}
*/
this.SetOrganisationInfo = (pubkey, info) => {
pubkey = PublicKey(pubkey).toString('hex')
console.info(pubkey.length)
return signAndSend('/SetOrganisationInfo', new AuthedMessage({
pubkey,
info
}))
}
/**
* Remove an organistaion from the database
*
* @method Dashboard#RemoveOrganisation
* @public
*
* @param {PublicKey} pubkey
*
* @returns {Boolean}
*/
this.RemoveOrganisation = (pubkey) => {
pubkey = PublicKey(pubkey).toString('hex')
return signAndSend('/RemoveOrganisation', new AuthedMessage({
pubkey,
}))
}
/**
* Generate an authenticated message which expires in 1 hour.
* This is then sent to the supplied email via FMS.
*
* @method Dashboard#InviteUser
* @public
*
* @param {String} email
* @param {PublicKey} orgpub
* @param {String} role
*
* @returns {String} Invitation URL
*/
this.InviteUser = (email, orgpub, role, expires) => {
orgpub = PublicKey(orgpub).toString('hex')
return signAndSend('/InviteUser', new AuthedMessage({
email,
organisation: orgpub,
role,
}, { expires }))
}
/**
* @method Dashboard#AcceptInvite
* @public
*
* @param {String} name
* @param {String} email
* @param {Object} invite
*
* @returns {PublicKey} user pubkey
*/
this.AcceptInvite = (name, email, invite) => {
return signAndSend('/CreateUser', new AuthedMessage({ name, email, invite }))
}
/**
* @method Dashboard#ListUsers
* @public
*
* @param {PublicKey} orgpub Organisation public key
*
* @returns {UserListItem[]}
*/
this.ListUsers = (orgpub) => {
orgpub = PublicKey(orgpub).toString('hex')
return signAndSend('/ListUsers', new AuthedMessage({
organisation: orgpub
}))
}
/**
* Get user metadata
*
* @method Dashboard#GetUserInfo
* @public
*
* @param {Buffer} pubkey User public key
*
* @returns {UserInfo} User metadata
*/
this.GetUserInfo = (pubkey) => {
pubkey = PublicKey(pubkey).toString('hex')
return signAndSend('/GetUserInfo', new AuthedMessage({
pubkey,
}))
}
/**
* Set user metadata, setting property to null removes it.
*
* @method Dashboard#SetUserInfo
* @public
*
* @param {Buffer} pubkey User public key
* @param {Object} info User metadata modifications
*
* @returns {Boolean}
*/
this.SetUserInfo = (pubkey, info) => {
pubkey = PublicKey(pubkey).toString('hex')
return signAndSend('/SetUserInfo', new AuthedMessage({
pubkey,
info
}))
}
/**
* Remove a user from the database
*
* @method Dashboard#RemoveUser
* @public
*
* @param {PublicKey} orgpub
* @param {PublicKey} pubkey
*
* @returns {Boolean}
*/
this.RemoveUser = (orgpub, pubkey) => {
orgpub = PublicKey(orgpub).toString('hex')
pubkey = PublicKey(pubkey).toString('hex')
return signAndSend('/RemoveUser', new AuthedMessage({
organisation: orgpub,
pubkey,
}))
}
/**
* List application members of an organisation.
*
* @method Dashboard#ListApplications
* @public
*
* @param {PublicKey} orgpub Organisation public key
*
* @returns {ApplicationListItem[]} Organisation user list
*/
this.ListApplications = (orgpub) => {
orgpub = PublicKey(orgpub).toString('hex')
return signAndSend('/ListApplications', new AuthedMessage({
organisation: orgpub,
}))
}
/**
* Create a new organisation application
*
* @method Dashboard#CreateApplication
* @public
*
* @param {PublicKey} orgpub
* @param {String} name
* @param {ApplicationInfo} info
*
* @returns {PublicKey}
*/
this.CreateApplication = (orgpub, name, info) => {
orgpub = PublicKey(orgpub).toString('hex')
return signAndSend('/CreateApplication', new AuthedMessage({
name,
orgpub: orgpub,
info
}))
}
/**
* Get application metadata
*
* @method Dashboard#GetApplicationInfo
* @public
*
* @param {PublicKey} pubkey
*
* @returns {ApplicationInfo}
*/
this.GetApplicationInfo = (pubkey) => {
return signAndSend('/GetApplicationInfo', new AuthedMessage({
pubkey: pubkey.toString('hex'),
}))
}
/**
* Set application metadata
*
* @method Dashboard#SetApplicationInfo
* @public
*
* @param {PublicKey} pubkey
* @param {ApplicationInfo} info
*
* @return {Boolean}
*/
this.SetApplicationInfo = (pubkey, info) => {
return signAndSend('/SetApplicationInfo', new AuthedMessage({
pubkey: pubkey.toString('hex'),
info
}))
}
/**
* Remove an application from the database
*
* @method Dashboard#RemoveApplication
* @public
*
* @param {PublicKey} orgpub
* @param {PublicKey} pubkey
*
* @returns {Boolean}
*/
this.RemoveApplication = (orgpub, pubkey) => {
orgpub = PublicKey(orgpub).toString('hex')
pubkey = PublicKey(pubkey).toString('hex')
return signAndSend('/RemoveApplication', new AuthedMessage({
organisation: orgpub,
pubkey,
}))
}
/**
* @method Dashboard#CheckAllowed
* @public
*
* @param {PublicKey} pubkey
* @param {String} tag
*
* @returns {Boolean}
*/
this.CheckAllowed = (pubkey, tag) => {
return signAndSend('/CheckAllowed', new AuthedMessage({
pubkey: pubkey.toString('hex'), tag: tag,
}))
}
/**
* @method Dashboard#AssignPermission
* @public
*
* @param {PublicKey} pubkey
* @param {String} tag
*
* @returns {Boolean}
*/
this.AssignPermission = (pubkey, tag) => {
return signAndSend('/AssignPermission', new AuthedMessage({
pubkey: pubkey.toString('hex'), tag,
}))
}
/**
* @method Dashboard#RemovePermission
* @public
*
* @param {PublicKey} pubkey
* @param {String} tag
*
* @returns {Boolean}
*/
this.RemovePermission = (pubkey, tag) => {
return signAndSend('/RemovePermission', new AuthedMessage({
pubkey: pubkey.toString('hex'), tag,
}))
}
// Interface
this.initWithKey = initWithKey.bind(this)
this.initWithVault = initWithVault.bind(this)
}
module.exports = Dashboard