aladinnetwork-blockstack
Version:
The Aladin Javascript library for authentication, identity, and storage.
168 lines (154 loc) • 5.45 kB
text/typescript
// @ts-ignore: Could not find a declaration file for module
import { TokenSigner, decodeToken, SECP256K1Client } from 'jsontokens'
import 'cross-fetch/polyfill'
import { fetchPrivate } from '../fetchUtil'
/**
* Create an authentication token to be sent to the Core API server
* in order to generate a Core session JWT.
*
* @param {String} appDomain The unique application identifier (e.g. foo.app, www.foo.com, etc).
* @param {Array} appMethods The list of API methods this application will need.
* @param {String} appPrivateKey The application-specific private key
* @param {String|null} blockchainID This is the blockchain ID of the requester
* @param {String} thisDevice Identifier of the current device
*
* @return {String} a JWT signed by the app's private key
* @deprecated
* @private
* @ignore
*/
export function makeCoreSessionRequest(appDomain: string,
appMethods: Array<string>,
appPrivateKey: string,
blockchainID: string = null,
thisDevice: string = null) {
if (thisDevice === null) {
thisDevice = '.default'
}
const appPublicKey = SECP256K1Client.derivePublicKey(appPrivateKey)
const appPublicKeys = [{
public_key: appPublicKey,
device_id: thisDevice
}]
const authBody = {
version: 1,
blockchain_id: blockchainID,
app_private_key: appPrivateKey,
app_domain: appDomain,
methods: appMethods,
app_public_keys: appPublicKeys,
device_id: thisDevice
}
// make token
const tokenSigner = new TokenSigner('ES256k', appPrivateKey)
const token = tokenSigner.sign(authBody)
return token
}
/**
* Send Core a request for a session token.
*
* @param {String} coreHost host name of the core node
* @param {Number} corePort port number of the core node
* @param {String} coreAuthRequest a signed JWT encoding the authentication request
* @param {String} apiPassword the API password for Core
*
* @return {Promise} the resolves to a JWT signed with the Core API server's private key
* that authorizes the bearer to carry out the requested operations and rejects
* with an error message otherwise
* @deprecated
* @private
* @ignore
*/
export function sendCoreSessionRequest(coreHost: string,
corePort: number,
coreAuthRequest: string,
apiPassword: string) {
return Promise.resolve().then(() => {
if (!apiPassword) {
throw new Error('Missing API password')
}
})
.then(() => {
const options = {
headers: {
Authorization: `bearer ${apiPassword}`
}
}
const url = `http://${coreHost}:${corePort}/v1/auth?authRequest=${coreAuthRequest}`
return fetchPrivate(url, options)
})
.then((response) => {
if (!response.ok) {
throw new Error('HTTP status not OK')
}
return response.text()
})
.then((responseText) => {
const responseJson = JSON.parse(responseText)
const token = responseJson.token
if (!token) {
throw new Error('Failed to get Core session token')
}
return token
})
.catch((error) => {
console.error(error)
throw new Error('Invalid Core response: not JSON')
})
}
/**
* Get a core session token. Generate an auth request, sign it, send it to Core,
* and get back a session token.
*
* @param {String} coreHost Core API server's hostname
* @param {Number} corePort Core API server's port number
* @param {String} apiPassword core api password
* @param {String} appPrivateKey Application's private key
* @param {String} blockchainId blockchain ID of the user signing in.
* `null` if user has no blockchain ID
* @param {String} authRequest authentication request token
* @param {String} deviceId identifier for the current device
*
* @return {Promise} a Promise that resolves to a Core session token or rejects
* with an error message.
* @deprecated
* @private
* @ignore
*/
export function getCoreSession(coreHost: string,
corePort: number,
apiPassword: string,
appPrivateKey: string,
blockchainId: string = null,
authRequest: string = null,
deviceId: string = '0') {
if (!authRequest) {
return Promise.reject('No authRequest provided')
}
let payload = null
let authRequestObject = null
try {
authRequestObject = decodeToken(authRequest)
if (!authRequestObject) {
return Promise.reject('Invalid authRequest in URL query string')
}
if (!authRequestObject.payload) {
return Promise.reject('Invalid authRequest in URL query string')
}
payload = authRequestObject.payload
} catch (e) {
console.error(e.stack)
return Promise.reject('Failed to parse authRequest in URL')
}
const appDomain = payload.domain_name
if (!appDomain) {
return Promise.reject('No domain_name in authRequest')
}
const appMethods = payload.scopes
const coreAuthRequest = makeCoreSessionRequest(
appDomain, appMethods, appPrivateKey, blockchainId, deviceId
)
return sendCoreSessionRequest(
coreHost, corePort, coreAuthRequest, apiPassword
)
}