capability-sdk-js
Version:
Capability SDK for Node.js
284 lines (273 loc) • 9.26 kB
JavaScript
/*
* Copyright 2017 Capability LLC. All Rights Reserved.
*
* 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.
*/
"use strict";
const events = require("events");
const http = require("http");
const Joi = require("joi");
const pkg = require("../package.json");
const querystring = require("querystring");
const regex = require("../regex.js");
const request = require("../request.js");
const util = require("util");
const Membrane = module.exports = function()
{
if (!(this instanceof Membrane))
{
return new Membrane();
}
const self = this;
events.EventEmitter.call(self);
self.name = `${pkg.name}:membrane`;
self.version = pkg.version
};
util.inherits(Membrane, events.EventEmitter);
Membrane.SCHEMA =
{
create:
{
membrane: Joi.object().keys(
{
id: Joi.string().max(256).required()
}
).required()
},
export:
{
config: Joi.object().keys(
{
allowQuery: Joi.boolean(),
headers: Joi.object(),
hmac: Joi.object().keys(
{
"cap1-hmac-sha512": Joi.object().keys(
{
key: Joi.string().regex(new RegExp(`^${regex.base64url.source}$`)).required(),
keyId: Joi.string().max(256).required()
}
)
}
),
method: Joi.string().valid(http.METHODS),
timeoutMs: Joi.number().integer(),
tls: Joi.object().keys(
{
ca: Joi.string(),
cert: Joi.string(),
key: Joi.string(),
rejectUnauthorized: Joi.boolean()
}
),
uri: Joi.string().uri(
{
scheme: [ "http", "https" ]
}
).required()
}
).required()
},
query: Joi.object().keys(
{
id: Joi.string().max(256),
lastId: Joi.string().max(256),
limit: Joi.number().integer()
}
)
};
/*
* `createCapability`: _Capability URI_ Capability to create membranes.
* `membrane`: _Object_ Membrane to create.
* `id`: _String_ Unique id to assign to the membrane.
* `callback`: _Function_ `(error, response) => {}`
* `error`: _Error_ Error, if any.
* `response`: _Object_ Response.
* `id`: _String_ Membrane id.
* `capabilities`: _Object_ Membrane capabilities.
*/
Membrane.prototype.create = function(createCapability, membrane, callback)
{
const self = this;
const validation = Joi.validate(
membrane,
Membrane.SCHEMA.create.membrane,
{
convert: false
}
);
if (validation.error)
{
return callback(validation.error);
}
const body = JSON.stringify(membrane);
const options =
{
headers:
{
"content-length": Buffer.byteLength(body)
},
method: "POST"
};
request(
createCapability,
options,
body,
callback
);
};
/*
* `deleteSelfCapability`: _Capability URI_ Capability to delete self.
* `callback`: _Function_ `(error) => {}`
* `error`: _Error_ Error, if any.
*/
Membrane.prototype.deleteSelf = function(deleteSelfCapability, callback)
{
request(
deleteSelfCapability,
null,
null,
callback
);
};
/*
* `exportCapability`: _Capability URI_ Capability to export capability through
membrane.
* `config`: _Object_ Configuration of the capability to export through membrane.
* `capability`: _Capability URI_ **Mutually exclusive with `uri`.** An
already existing capability to re-export through this membrane. If this
membrane is revoked, the original capability will not be revoked. Only
the capability created during this re-export and any of its descendants
will be revoked.
* `uri`: _String_ **Mutually exclusive with `capability`.** Fully qualified
URI, for example https://example.com/path/to/something
* `allowQuery` (`uri` option): _Boolean_ _(Default: false)_ Optionally allow
requester's URI query string to be appended to the `uri` in membrane
request.
* `headers` (`uri` option): _Object_ _(Default: undefined)_ Optional headers
to include with the membrane request to the URI. Hop-by-hop headers will
be ignored.
* `hmac` (`uri` option): _Object_ _(Default: undefined)_ Optional selector
for which signature scheme to use to sign membrane request to URI.
* `cap1-hmac-sha512`: _Object_ Use CAP1-HMAC-SHA512 signature.
* `key`: _String_ Base64url encoded secret key bytes.
* `keyId`: _String_ Secret key id.
* `method` (`uri` option): _String_ _(Default: undefined)_ Optional HTTP
method to use in the membrane request to the URI. This overrides the
method specified by the requester.
* `timeoutMs` (`uri` option): _Number_ _(Default: undefined)_ Optional
timeout in milliseconds to end idle connection between membrane and URI.
Will be ignored if greater than membrane's configured internal timeout.
* `tls` (`uri` option): _Object_ _(Default: undefined)_ TLS options.
* `ca`: _String_ _(Default: undefined)_ Optionally, override default trusted
Certificate Authorities (CAs). Default is to trust the well-known CAs
curated by Mozilla. Mozilla's CAs are completely replaced when CA is
explicitly specified using this option.
* `cert`: _String_ _(Default: undefined)_ Optional certificate chain in
PEM format.
* `key`: _String_ _(Default: undefined)_ Optional private key in PEM
format.
* `rejectUnauthorized`: _Boolean_ _(Default: true)_ If not `false`,
membrane request verifies responding server against the list of
supplied Certificate Authorities.
* `callback`: _Function_ `(error, response) => {}`
* `error`: _Error_ Error, if any.
* `response`: _Object_ Response.
* `capability`: _Capability URI_ Created capability.
*/
Membrane.prototype.export = function(exportCapability, config, callback)
{
const self = this;
const validation = Joi.validate(
config,
Membrane.SCHEMA.export.config,
{
convert: false
}
);
if (validation.error)
{
return callback(validation.error);
}
const body = JSON.stringify(config);
const options =
{
headers:
{
"content-length": Buffer.byteLength(body)
},
method: "POST"
};
request(
exportCapability,
options,
body,
callback
);
};
/*
* `queryCapability`: _Capability URI_ Capability to query membranes.
* `query`: _Object_ _(Default: {})_ Query to execute.
* `id`: _String_ _(Default: undefined)_ Id of the membrane to query.
* `lastId`: _String_ _(Default: undefined)_ Id of the last membrane from
previous query, used to return more results if there are more results
to retrieve.
* `limit`: _Number_ _(Default: 1)_ Limit on the number of results. The
number of results will be less than or equal to the `limit`.
* `callback`: _Function_ `(error, response) => {}`
* `error`: _Error_ Error, if any.
* `response`: _Object_ Response object.
* `membranes`: _Array_ An array of membranes ordered by 'id'. Each result
contains `id` and `capabilities` corresponding to the membrane.
* `completed`: _Boolean_ `true` if no more results, `false` otherwise.
*/
Membrane.prototype.query = function(queryCapability, query = {}, callback)
{
const self = this;
const validation = Joi.validate(
query,
Membrane.SCHEMA.query,
{
convert: false
}
);
if (validation.error)
{
return callback(validation.error);
}
const options = {};
if (query.id || query.lastId || query.limit)
{
options.path = `/?${querystring.stringify(query)}`;
};
request(
queryCapability,
options,
undefined,
callback
);
};
/*
* `revokeCapability`: _Capability URI_ Capability to revoke a membrane.
* `callback`: _Function_ `(error) => {}`
* `error`: _Error_ Error, if any.
*/
Membrane.prototype.revoke = function(revokeCapability, callback)
{
request(
revokeCapability,
null,
null,
callback
);
};