ripe-commons
Version:
The RIPE Commons library
1,486 lines (1,290 loc) • 90.1 kB
JavaScript
/**
* RIPE Commons (for Javascript) 0.13.0.
*
* Copyright (c) 2014-2023 Platforme International.
*
* This source code is licensed under the Apache 2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var fs = require('fs');
var path = require('path');
var process$1 = require('process');
var fetch = require('node-fetch');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
/**
* Splits the provided array (or iterable that uses `slice`) into
* array chunks of the provided size.
*
* @param {Array} array The array that is going to be split into
* chunks of the provided size.
* @param {Number} size The size of each chunk as an integer.
* @returns {Array} An array containing arrays of the provided size
* with the contents of each chunk.
*/
const splitArray = (array, size = 1) => {
const result = [];
for (let index = 0; index < array.length; index += size) {
const chunk = array.slice(index, index + size);
result.push(chunk);
}
return result;
};
/**
* Yonius 0.11.7.
*
* Copyright (c) 2008-2022 Hive Solutions Lda.
*
* This source code is licensed under the Apache 2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const verify$1 = function(
condition,
message = null,
code = null,
exception = null,
kwargs = {},
safeKeys = ["message"]
) {
if (condition) return;
message = message || "Verification failed";
const Exception = exception || Error;
kwargs = Object.assign({}, kwargs);
if (message !== null && message !== undefined) kwargs.message = message;
if (code !== null && message !== undefined) kwargs.code = code;
const throwable = new Exception(kwargs.message || undefined);
throwable.kwargs = kwargs;
for (const [key, value] of Object.entries(kwargs)) {
if (safeKeys.includes(key) && throwable[key] !== undefined) {
continue;
}
throwable[key] = value;
}
throw throwable;
};
const globals$1 =
typeof global === "undefined"
? typeof window === "undefined"
? typeof self === "undefined"
? {}
: self
: window
: global;
globals$1.CONFIGS = globals$1.CONFIGS === undefined ? {} : globals$1.CONFIGS;
globals$1.CONFIG_F = globals$1.CONFIG_F === undefined ? [] : globals$1.CONFIG_F;
globals$1.HOMES = globals$1.HOMES === undefined ? [] : globals$1.HOMES;
globals$1.LOADED = globals$1.LOADED === undefined ? false : globals$1.LOADED;
class YoniusError extends Error {
constructor(message, code = 500) {
super(message);
this.name = this.constructor.name;
this.code = code;
}
get isClient() {
return Math.floor(this.code / 100) === 4;
}
get isServer() {
return Math.floor(this.code / 100) === 5;
}
}
class OperationalError extends YoniusError {
constructor(message = "Operational error", code = 500) {
super(message, code);
}
}
const buildGetAgent$1 = (AgentHttp, AgentHttps, set = true, options = {}) => {
const httpAgent = new AgentHttp({
keepAlive: options.keepAlive === undefined ? true : options.keepAlive,
keepAliveMsecs: options.keepAliveMsecs || 120000,
timeout: options.timeout || 60000,
scheduling: options.scheduling || "fifo"
});
const httpsAgent = new AgentHttps({
keepAlive: options.keepAlive === undefined ? true : options.keepAlive,
keepAliveMsecs: options.keepAliveMsecs || 120000,
timeout: options.timeout || 60000,
scheduling: options.scheduling || "fifo"
});
const getAgent = parsedURL => (parsedURL.protocol === "http:" ? httpAgent : httpsAgent);
if (set) globals$1.getAgent = getAgent;
return getAgent;
};
/**
* Tries to patch the global environment with a proper `getAgent`
* function that can handle HTTP and HTTP connection polling.
*
* This can only be performed in a node.js environment (uses `require`).
*
* @returns {Function} The `getAgent` function that has just been
* built and set in the globals.
*/
const patchAgent$1 = () => {
if (typeof require !== "function") return;
if (globals$1.getAgent) return;
let http, https;
try {
http = require("http");
https = require("https");
} catch (err) {
return;
}
if (!http || !https) return;
if (!http.Agent || !https.Agent) return;
return buildGetAgent$1(http.Agent, https.Agent, true);
};
// patches the global agent if possible, using the
// global dynamic require statements
patchAgent$1();
/**
* RIPE ID API (for Javascript) 0.7.2.
*
* Copyright (c) 2014-2022 Platforme International.
*
* This source code is licensed under the Apache 2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const AccountAPI = superclass =>
class extends superclass {
async selfAccount() {
const url = this.baseUrl + "accounts/me";
const contents = await this.get(url);
return contents;
}
async updateSelfAccount(account) {
const url = this.baseUrl + "accounts/me";
account = Object.assign({}, account);
if (account.meta_extra) {
account.meta_extra = JSON.stringify(account.meta_extra);
}
const contents = await this.put(url, {
dataM: account
});
return contents;
}
async aclAccount() {
const url = this.baseUrl + "accounts/acl";
const contents = await this.get(url);
return contents;
}
async listAccounts(options = {}) {
const url = this.baseUrl + "accounts";
const contents = await this.get(url, options);
return contents;
}
async createAccount(account, sendEmail = false) {
const url = this.baseUrl + "accounts";
const contents = await this.post(url, {
params: { send_email: sendEmail },
dataJ: account
});
return contents;
}
async createAccountMultipart(account, sendEmail = false) {
const url = this.baseUrl + "accounts";
const contents = await this.post(url, {
params: { send_email: sendEmail },
dataM: account
});
return contents;
}
async getAccount(username) {
const url = this.baseUrl + `accounts/${username}`;
const contents = await this.get(url);
return contents;
}
async notifyAccount(username, engine, payload) {
payload =
typeof payload === "string"
? { subject: payload, title: payload, contents: payload }
: payload;
const url = this.baseUrl + `accounts/${username}/notify`;
const contents = await this.put(url, {
dataJ: Object.apply({}, payload, { engine: engine })
});
return contents;
}
async recoverAccount(username) {
const url = this.baseUrl + `accounts/${username}/recover`;
const contents = await this.post(url, {
kwargs: {
auth: false
}
});
return contents;
}
showUrlAccount(username) {
return this.loginUrl + `accounts/${username}`;
}
avatarUrlAccount(
username,
{ size = undefined, width = undefined, height = undefined, cache = undefined } = {}
) {
const baseUrl = this.loginUrl + `accounts/${username}/avatar`;
const params = [];
if (size !== undefined) params.push(["size", size]);
if (width !== undefined) params.push(["width", width]);
if (height !== undefined) params.push(["height", height]);
if (cache !== undefined) params.push(["cache", cache ? "1" : "0"]);
const extraUrl = this._generateExtraUrl(params);
return `${baseUrl}${extraUrl}`;
}
};
/**
* Yonius 0.8.3.
*
* Copyright (c) 2008-2021 Hive Solutions Lda.
*
* This source code is licensed under the Apache 2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
class Observable {
constructor() {
this.callbacks = {};
}
bind(event, callback) {
const callbacks = this.callbacks[event] || [];
callbacks.push(callback);
this.callbacks[event] = callbacks;
return callback;
}
unbind(event, callback) {
const callbacks = this.callbacks[event] || [];
if (!callback) {
delete this.callbacks[event];
return;
}
const index = callbacks.indexOf(callback);
if (index === -1) {
return;
}
callbacks.splice(index, 1);
this.callbacks[event] = callbacks;
}
trigger(event) {
const callbacks = this.callbacks[event] || [];
const results = [];
for (const callback of callbacks) {
const result = callback.apply(this, Array.prototype.slice.call(arguments, 1));
result !== undefined && result !== null && results.push(result);
}
return Promise.all(results);
}
}
const verify = function(
condition,
message = null,
code = null,
exception = null,
kwargs = {}
) {
if (condition) return;
message = message || "Verification failed";
const Exception = exception || Error;
kwargs = Object.assign({}, kwargs);
if (message !== null && message !== undefined) kwargs.message = message;
if (code !== null && message !== undefined) kwargs.code = code;
const throwable = new Exception(kwargs.message || undefined);
throwable.kwargs = kwargs;
for (const [key, value] of Object.entries(kwargs)) {
if (throwable[key] !== undefined) continue;
throwable[key] = value;
}
throw throwable;
};
const verifyMany = function(
sequence,
message = null,
code = null,
exception = null,
kwargs = {}
) {
sequence.forEach(element => {
verify(element, message, code, exception, kwargs);
});
};
let HOME_DIR = null;
const pathExists = async function(path) {
try {
await fs__namespace.promises.access(path);
} catch (error) {
return false;
}
return true;
};
const expandUser = function(path$1) {
if (!path$1) return path$1;
if (path$1 === "~") return _homeDir();
if (path$1.slice(0, 2) !== "~/") return path$1;
return path.join(HOME_DIR, path$1.slice(2));
};
const getEnv = function(name) {
// eslint-disable-next-line no-undef
if (typeof Deno !== "undefined") return Deno.env.get(name);
return process$1.env[name];
};
const getEnvObject = function() {
// eslint-disable-next-line no-undef
if (typeof Deno !== "undefined") return Deno.env.toObject();
return process$1.env;
};
const _homeDir = function() {
if (HOME_DIR !== null) return HOME_DIR;
const isWindows = Boolean(typeof process !== "undefined" && process.platform === "win32");
HOME_DIR = getEnv(isWindows ? "USERPROFILE" : "HOME") || "/";
return HOME_DIR;
};
const FILE_NAME = "yonius.json";
const HOME_FILE = "~/.home";
const IMPORT_NAMES = ["$import", "$include", "$IMPORT", "$INCLUDE"];
const CASTS = {
int: v => (typeof v === "number" ? v : parseInt(v)),
float: v => (typeof v === "number" ? v : parseFloat(v)),
bool: v => (typeof v === "boolean" ? v : ["1", "true", "True"].includes(v)),
list: v => (Array.isArray(v) ? v : v.split(";")),
tuple: v => (Array.isArray(v) ? v : v.split(";"))
};
const globals =
typeof global === "undefined"
? typeof window === "undefined"
? typeof self === "undefined"
? {}
: self
: window
: global;
globals.CONFIGS = globals.CONFIGS === undefined ? {} : globals.CONFIGS;
globals.CONFIG_F = globals.CONFIG_F === undefined ? [] : globals.CONFIG_F;
globals.HOMES = globals.HOMES === undefined ? [] : globals.HOMES;
globals.LOADED = globals.LOADED === undefined ? false : globals.LOADED;
const conf = function(name, fallback = undefined, cast = null, ctx = null) {
const configs = ctx ? ctx.configs : globals.CONFIGS;
cast = _castR(cast);
let value = configs[name] === undefined ? fallback : configs[name];
if (cast && value !== undefined && value !== null) value = cast(value);
return value;
};
const load$1 = async function(
names = [FILE_NAME],
path$1 = null,
encoding = "utf-8",
force = false,
ctx = null
) {
if (globals.LOADED && !force) return;
let paths = [];
const homes = await getHomes();
for (const home of homes) {
paths = paths.concat([path.join(home), path.join(home, ".config")]);
}
paths.push(path$1);
for (const path of paths) {
for (const name of names) {
await loadFile(name, path, encoding, ctx);
}
}
await loadEnv(ctx);
globals.LOADED = true;
};
const loadFile = async function(
name = FILE_NAME,
path$1 = null,
encoding = "utf-8",
ctx = null
) {
const configs = ctx ? ctx.configs : globals.CONFIGS;
const configF = ctx ? ctx.configF : globals.CONFIG_F;
let key;
let value;
let exists;
let filePath;
if (path$1) path$1 = path.normalize(path$1);
if (path$1) filePath = path.join(path$1, name);
else filePath = name;
filePath = path.resolve(filePath);
filePath = path.normalize(filePath);
const basePath = path.dirname(filePath);
exists = await pathExists(filePath);
if (!exists) return;
exists = configF.includes(filePath);
if (exists) configF.splice(configF.indexOf(filePath), 1);
configF.push(filePath);
const data = await fs__namespace.promises.readFile(filePath, { encoding: encoding });
const dataJ = JSON.parse(data);
await _loadIncludes(basePath, dataJ, encoding);
for ([key, value] of Object.entries(dataJ)) {
if (!_isValid(key)) continue;
configs[key] = value;
}
};
const loadEnv = async function(ctx = null) {
const env = getEnvObject();
const configs = ctx ? ctx.configs : globals.CONFIGS;
if (env === undefined || env === null) return;
Object.entries(env).forEach(function([key, value]) {
configs[key] = value;
});
};
const getHomes = async function(
filePath = HOME_FILE,
fallback = "~",
encoding = "utf-8",
forceDefault = false
) {
if (globals.HOMES.length > 0) return globals.HOMES;
const env = getEnvObject();
globals.HOMES = env.HOMES === undefined ? null : env.HOMES;
globals.HOMES = globals.HOMES ? globals.HOMES.split(";") : globals.HOMES;
if (globals.HOMES !== null) return globals.HOMES;
fallback = expandUser(fallback);
fallback = path.normalize(fallback);
globals.HOMES = [fallback];
filePath = expandUser(filePath);
filePath = path.normalize(filePath);
const exists = await pathExists(filePath);
if (!exists) return globals.HOMES;
if (!forceDefault) globals.HOMES.splice(0, globals.HOMES.length);
let data = await fs__namespace.promises.readFile(filePath, { encoding: encoding });
data = data.trim();
let paths = data.split(/\r?\n/);
paths = paths.map(v => v.trim());
for (let path$1 of paths) {
path$1 = path$1.trim();
if (!path$1) continue;
path$1 = expandUser(path$1);
path$1 = path.normalize(path$1);
globals.HOMES.push(path$1);
}
return globals.HOMES;
};
const _castR = function(cast) {
return CASTS[cast] === undefined ? cast : CASTS[cast];
};
const _loadIncludes = async function(basePath, config, encoding = "utf-8") {
let includes = [];
for (const alias of IMPORT_NAMES) {
includes = config[alias] === undefined ? includes : config[alias];
}
if (typeof includes === "string") {
includes = includes.split(";");
}
for (const include of includes) {
await loadFile(include, basePath, encoding);
}
};
const _isValid = function(key) {
if (IMPORT_NAMES.includes(key)) return false;
return true;
};
class MixinBuilder {
constructor(superclass) {
this.superclass = superclass;
}
with(...mixins) {
return mixins.reduce((c, mixin) => mixin(c), this.superclass);
}
}
const mix = superclass => new MixinBuilder(superclass);
/**
* Encodes the multiple values as and encoded URI component, the
* values can be wither defined as an array (order is preserved)
* or as an object (where sequence order is not preserved).
*
* The value of each item can be either a primitive type or a sequence
* in case it's of sequence the values are going to be encoded as
* multiple parameters separated by the '&' character.
*
* @param {(Array|Object[])} values The values to be encoded as an
* URI component (like GET params).
* @returns {String} A string with the query encoded values.
*/
const urlEncode = function(values) {
// constructs the parts array that is going to
// store the multiple and values
const parts = [];
// in case the provided value is not an array
// then assumes it's an object and retrieve entries
if (!Array.isArray(values)) {
values = Object.entries(values);
}
// iterates over the complete set of pairs available
// from the key value pairs to be able to encode them
// properly, notice that the values themselves can be
// sequences allowing multiple repetition of key
values.forEach(([key, value]) => {
if (!Array.isArray(value)) {
value = [value];
}
const keyEncoded = encodeURIComponent(key);
value.forEach(_value => {
if (_value === undefined || _value === null) {
return;
}
const valueEncoded = encodeURIComponent(_value);
parts.push(`${keyEncoded}=${valueEncoded}`);
});
});
// joins the complete set of parts with the and
// separator and then returns the final string value
return parts.join("&");
};
const AUTH_ERRORS = [401, 403, 440, 499];
class API$1 extends Observable {
constructor(kwargs = {}) {
super();
this.kwargs = kwargs;
}
async build(method, url, options = {}) {}
async authCallback(params, headers) {}
async get(url, options = {}) {
const result = await this.methodBasic("GET", url, options);
return result;
}
async post(url, options = {}) {
const result = await this.methodPayload("POST", url, options);
return result;
}
async put(url, options = {}) {
const result = await this.methodPayload("PUT", url, options);
return result;
}
async delete(url, options = {}) {
const result = await this.methodBasic("DELETE", url, options);
return result;
}
async patch(url, options = {}) {
const result = await this.methodPayload("PATCH", url, options);
return result;
}
async options(url, options = {}) {
const result = await this.methodBasic("OPTIONS", url, options);
return result;
}
async methodBasic(method, url, options = {}) {
options.params = options.params !== undefined ? options.params : {};
options.headers = options.headers !== undefined ? options.headers : {};
try {
return await this._methodBasic(method, url, options);
} catch (err) {
if (AUTH_ERRORS.includes(err.code)) {
await this.authCallback(options.params, options.headers);
return await this._methodBasic(method, url, options);
} else {
throw err;
}
}
}
async methodPayload(method, url, options = {}) {
options.params = options.params !== undefined ? options.params : {};
options.headers = options.headers !== undefined ? options.headers : {};
try {
return await this._methodPayload(method, url, options);
} catch (err) {
if (AUTH_ERRORS.includes(err.code)) {
await this.authCallback(options.params, options.headers);
return await this._methodPayload(method, url, options);
} else {
throw err;
}
}
}
async _methodBasic(method, url, options = {}) {
const params = options.params !== undefined ? options.params : {};
const headers = options.headers !== undefined ? options.headers : {};
const kwargs = options.kwargs !== undefined ? options.kwargs : {};
const handle = options.handle !== undefined ? options.handle : true;
const getAgent = options.getAgent !== undefined ? options.getAgent : undefined;
await this.build(method, url, {
params: params,
headers: headers,
kwargs: kwargs
});
const query = urlEncode(params || {});
if (query) url += url.includes("?") ? "&" + query : "?" + query;
const response = await fetch__default["default"](url, {
method: method,
headers: headers || {},
agent: getAgent || globals.getAgent || undefined
});
const result = handle ? await this._handleResponse(response) : response;
return result;
}
async _methodPayload(method, url, options = {}) {
const params = options.params !== undefined ? options.params : {};
let headers = options.headers !== undefined ? options.headers : {};
let data = options.data !== undefined ? options.data : null;
const dataJ = options.dataJ !== undefined ? options.dataJ : null;
const dataM = options.dataM !== undefined ? options.dataM : null;
let mime = options.mime !== undefined ? options.mime : null;
const kwargs = options.kwargs !== undefined ? options.kwargs : {};
const handle = options.handle !== undefined ? options.handle : true;
const getAgent = options.getAgent !== undefined ? options.getAgent : undefined;
await this.build(method, url, {
params: params,
headers: headers,
data: data,
dataJ: dataJ,
dataM: dataM,
mime: mime,
kwargs: kwargs
});
const query = urlEncode(params || {});
if (data !== null) {
if (query) url += url.includes("?") ? "&" + query : "?" + query;
} else if (dataJ !== null) {
data = JSON.stringify(dataJ);
if (query) url += url.includes("?") ? "&" + query : "?" + query;
mime = mime || "application/json";
} else if (dataM !== null) {
if (query) url += url.includes("?") ? "&" + query : "?" + query;
[mime, data] = this._encodeMultipart(dataM, mime, true);
} else if (query) {
data = query;
mime = mime || "application/x-www-form-urlencoded";
}
headers = Object.assign({}, headers);
if (mime) headers["Content-Type"] = mime;
const response = await fetch__default["default"](url, {
method: method,
headers: headers || {},
body: data,
agent: getAgent || global.getAgent || undefined
});
const result = handle ? await this._handleResponse(response) : response;
return result;
}
async _handleResponse(response, errorMessage = "Problem in request") {
let result = null;
if (
response.headers.get("content-type") &&
response.headers.get("content-type").toLowerCase().startsWith("application/json")
) {
result = await response.json();
} else if (
response.headers.get("content-type") &&
response.headers.get("content-type").toLowerCase().startsWith("text/")
) {
result = await response.text();
} else {
result = await response.blob();
}
verify(response.ok, result.error || errorMessage, response.status || 500);
return result;
}
_encodeMultipart(fields, mime = null, doseq = false) {
mime = mime || "multipart/form-data";
const boundary = this._createBoundary(fields, undefined, doseq);
const encoder = new TextEncoder("utf-8");
const buffer = [];
for (let [key, values] of Object.entries(fields)) {
const isList = doseq && Array.isArray(values);
values = isList ? values : [values];
for (let value of values) {
if (value === null) continue;
let header;
if (
typeof value === "object" &&
!(value instanceof Array) &&
value.constructor !== Uint8Array
) {
const headerL = [];
let data = null;
for (const [key, item] of Object.entries(value)) {
if (key === "data") data = item;
else headerL.push(`${key}: ${item}`);
}
value = data;
header = headerL.join("\r\n");
} else if (value instanceof Array) {
let name = null;
let contents = null;
let contentTypeD = null;
if (value.length === 2) [name, contents] = value;
else [name, contentTypeD, contents] = value;
header = `Content-Disposition: form-data; name="${key}"; filename="${name}"`;
if (contentTypeD) header += `\r\nContent-Type: ${contentTypeD}`;
value = contents;
} else {
header = `Content-Disposition: form-data; name="${key}"`;
value = value.constructor === Uint8Array ? value : encoder.encode(value);
}
buffer.push(encoder.encode("--" + boundary + "\r\n"));
buffer.push(encoder.encode(header + "\r\n"));
buffer.push(encoder.encode("\r\n"));
buffer.push(value);
buffer.push(encoder.encode("\r\n"));
}
}
buffer.push(encoder.encode("--" + boundary + "--\r\n"));
buffer.push(encoder.encode("\r\n"));
const body = this._joinBuffer(buffer);
const contentType = `${mime}; boundary=${boundary}`;
return [contentType, body];
}
_createBoundary(fields, size = 32, doseq = false) {
return "Vq2xNWWHbmWYF644q9bC5T2ALtj5CynryArNQRXGYsfm37vwFKMNsqPBrpPeprFs";
}
_joinBuffer(bufferArray) {
const bufferSize = bufferArray.map(item => item.byteLength).reduce((a, v) => a + v, 0);
const buffer = new Uint8Array(bufferSize);
let offset = 0;
for (const item of bufferArray) {
buffer.set(item, offset);
offset += item.byteLength;
}
return buffer;
}
}
const buildGetAgent = (AgentHttp, AgentHttps, set = true, options = {}) => {
const httpAgent = new AgentHttp({
keepAlive: options.keepAlive === undefined ? true : options.keepAlive,
keepAliveMsecs: options.keepAliveMsecs || 120000,
timeout: options.timeout || 60000,
scheduling: options.scheduling || "fifo"
});
const httpsAgent = new AgentHttps({
keepAlive: options.keepAlive === undefined ? true : options.keepAlive,
keepAliveMsecs: options.keepAliveMsecs || 120000,
timeout: options.timeout || 60000,
scheduling: options.scheduling || "fifo"
});
const getAgent = parsedURL => (parsedURL.protocol === "http:" ? httpAgent : httpsAgent);
if (set) globals.getAgent = getAgent;
return getAgent;
};
/**
* Tries to patch the global environment with a proper `getAgent`
* function that can handle HTTP and HTTP connection polling.
*
* This can only be performed in a node.js environment (uses `require`).
*
* @returns {Function} The `getAgent` function that has just been
* built and set in the globals.
*/
const patchAgent = () => {
if (typeof require !== "function") return;
if (globals.getAgent) return;
let http, https;
try {
http = require("http");
https = require("https");
} catch (err) {
return;
}
if (!http || !https) return;
if (!http.Agent || !https.Agent) return;
return buildGetAgent(http.Agent, https.Agent, true);
};
// patches the global agent if possible, using the
// global dynamic require statements
patchAgent();
class OAuthAPI extends API$1 {}
class OAuth2API extends OAuthAPI {
constructor(kwargs = {}) {
super(kwargs);
this.accessToken = null;
}
async build(method, url, options = {}) {
await super.build(method, url, options);
const params = options.params !== undefined ? options.params : {};
const headers = options.headers !== undefined ? options.headers : {};
const kwargs = options.kwargs !== undefined ? options.kwargs : {};
const token = kwargs.token === undefined ? this.tokenDefault : kwargs.token;
delete kwargs.token;
if (token && this.oauthTypes.includes("param")) {
params[this.oauthParam] = this.getAccessToken();
}
if (token && this.oauthTypes.includes("header")) {
headers.Authorization = `Bearer ${this.getAccessToken()}`;
}
}
getAccessToken() {
if (this.accessToken) return this.accessToken;
throw new Error("No access token found must re-authorize");
}
get oauthTypes() {
return ["param", "header"];
}
get oauthParam() {
return "access_token";
}
get tokenDefault() {
return true;
}
}
const load = async function() {
await load$1();
};
const RoleAPI = superclass =>
class extends superclass {
async listRoles(options = {}) {
const url = this.baseUrl + "roles";
const contents = await this.get(url, options);
return contents;
}
async getRole(name) {
const url = this.baseUrl + `roles/${name}`;
const contents = await this.get(url);
return contents;
}
};
const SecretAPI = superclass =>
class extends superclass {
async createSecret(secret) {
const url = this.baseUrl + "secrets";
const contents = await this.post(url, { dataJ: secret });
return contents;
}
async getSecret(name) {
const url = this.baseUrl + `secrets/${name}`;
const contents = await this.get(url);
return contents;
}
};
const TokenAPI = superclass =>
class extends superclass {
async issueToken() {
const url = this.baseUrl + "tokens/issue";
const contents = await this.post(url);
return contents;
}
async redeemToken(token) {
const url = this.baseUrl + "tokens/redeem";
const contents = await this.post(url, {
params: {
token: token
},
kwargs: {
token: false,
auth: false
}
});
return contents;
}
};
const RIPEID_BASE_URL = "https://id.platforme.com/api/";
const RIPEID_LOGIN_URL = "https://id.platforme.com/";
const RIPEID_SCOPE = ["account.me", "account.acl"];
class API extends mix(OAuth2API).with(AccountAPI, RoleAPI, SecretAPI, TokenAPI) {
constructor(kwargs = {}) {
super(kwargs);
this.baseUrl = conf("RIPEID_BASE_URL", RIPEID_BASE_URL);
this.loginUrl = conf("RIPEID_LOGIN_URL", RIPEID_LOGIN_URL);
this.secretKey = conf("RIPEID_SECRET_KEY", null);
this.clientId = conf("RIPEID_ID", null);
this.clientSecret = conf("RIPEID_SECRET", null);
this.redirectUrl = conf("RIPEID_REDIRECT_URL", null);
this.baseUrl = kwargs.baseUrl === undefined ? this.baseUrl : kwargs.baseUrl;
this.loginUrl = kwargs.loginUrl === undefined ? this.loginUrl : kwargs.loginUrl;
this.secretKey = kwargs.secretKey === undefined ? this.secretKey : kwargs.secretKey;
this.clientId = kwargs.clientId === undefined ? this.clientId : kwargs.clientId;
this.clientSecret =
kwargs.clientSecret === undefined ? this.clientSecret : kwargs.clientSecret;
this.redirectUrl = kwargs.redirectUrl === undefined ? this.redirectUrl : kwargs.redirectUrl;
this.scope = kwargs.scope === undefined ? RIPEID_SCOPE : kwargs.scope;
this.accessToken = kwargs.accessToken === undefined ? null : kwargs.accessToken;
this.refreshToken = kwargs.refreshToken === undefined ? null : kwargs.refreshToken;
this.sessionId = kwargs.sessionId === undefined ? null : kwargs.sessionId;
}
static async load() {
await load();
}
async build(method, url, options = {}) {
await super.build(method, url, options);
options.params = options.params !== undefined ? options.params : {};
options.kwargs = options.kwargs !== undefined ? options.kwargs : {};
options.headers = options.headers !== undefined ? options.headers : {};
const auth = options.kwargs.auth === undefined ? true : options.kwargs.auth;
delete options.kwargs.auth;
if (auth && !this.secretKey) options.params.sid = await this.getSessionId();
if (this.secretKey) options.headers["X-Secret-Key"] = this.secretKey;
}
async authCallback(params, headers) {
if (this.refreshToken && params.access_token) {
await this.oauthRefresh();
params.access_token = this.getAccessToken();
}
if (this.sessionId && params.sid) {
this.sessionId = null;
const sessionId = await this.getSessionId();
params.sid = sessionId;
}
}
async getSessionId() {
if (this.sessionId) return this.sessionId;
await this.oauthLogin();
return this.sessionId;
}
async oauthAuthorize(state = null) {
let url = this.loginUrl + "oauth2/auth";
verifyMany([this.clientId, this.redirectUrl, this.scope]);
const values = {
client_id: this.clientId,
redirect_uri: this.redirectUrl,
response_type: "code",
scope: this.scope.join(" ")
};
if (state) values.state = state;
const data = urlEncode(values);
url = url + "?" + data;
return url;
}
async oauthAccess(code) {
const url = this.loginUrl + "oauth2/token";
const contents = await this.post(url, {
params: {
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: "authorization_code",
redirect_uri: this.redirectUrl,
code: code
},
kwargs: {
token: false,
auth: false
}
});
this.accessToken = contents.access_token;
this.refreshToken = contents.refresh_token || null;
this.trigger("access_token", this.accessToken);
this.trigger("refresh_token", this.refreshToken);
return this.accessToken;
}
async oauthRefresh() {
const url = this.loginUrl + "oauth2/token";
const contents = await this.post(url, {
callback: false,
params: {
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: "refresh_token",
redirect_uri: this.redirectUrl,
refresh_token: this.refreshToken
},
kwargs: {
token: false,
auth: false
}
});
this.accessToken = contents.access_token;
this.trigger("access_token", this.accessToken);
return this.accessToken;
}
async oauthLogin() {
const url = this.loginUrl + "oauth2/login";
const contents = await this.post(url, {
callback: false,
kwargs: { token: true, auth: false }
});
this.sessionId = contents.session_id || null;
this.tokens = contents.tokens || null;
this.trigger("auth", contents);
return this.sessionId;
}
async login(username, password) {
const url = this.baseUrl + "login";
const contents = await this.post(url, {
callback: false,
params: {
username: username,
password: password
},
kwargs: {
auth: false
}
});
return contents;
}
_generateExtraUrl(params) {
return params.length > 0 ? "?" + params.map(([k, v]) => `${k}=${String(v)}`).join("&") : "";
}
get oauthTypes() {
return ["param"];
}
get tokenDefault() {
return false;
}
}
/**
* Tries to obtain a RIPE authorization object (username and ACL)
* for the current request context, using the (redeem) token in context
* as the basis for the retrieval of the authorization.
*
* In case the process fails an exception is raised indicating the source
* of such problem.
*
* @param {Request} req The request object that is going to be used
* as the context provided and from which the (redeem) token is going
* to be retrieved and the authorization stored.
* @returns The resulting RIPE authorization object for the current
* context, exception is raised in case it's not possible to redeem one.
*/
const getRipeAuth = async req => {
// checks the current request's cache to check if there's
// an authorization information already present in it
if (req.ripeAuth) return req.ripeAuth;
// allocates space for the (redeem) token value that is going
// to be "gathered" from all possible request sources
let token = null;
// tries to "find" the token in the route parameters
if (req.params.token) token = req.params.token;
// tries to "find" the token in the GET parameters
if (req.query.token) token = req.query.token;
// tries to verify if the authorization header is present and
// if that's the case unpacks the token from it
if (req.headers.authorization) {
[, token] = req.headers.authorization.split(" ", 2);
}
// in case no redeem token has been found on request must throw an error
// indicating such issue (as expected)
if (!token) {
throw new OperationalError("No (redeem) token available", 401);
}
// creates a new instance of the RIPE ID API client to be used for
// the "redeem" operation of the redeem token
const api = new API();
// tries to redeem the token and then reacts to the most usual problems
// in the expected manner, the redeem operation represents the guarantee
// that the 3rd party who provided this token has effectively access to the
// ACL and username that is provided as part of the resulting authorization
const auth = await api.redeemToken(token);
if (auth.code === 404) {
throw new OperationalError("Token not found", 401);
}
// stores the (redeem) token associated with the request in the authorization,
// so that it can be easily retrieved latter if needed (no need to find the
// token among the multiple possible request locations: GET or POST params)
auth.token = token;
// updates the current request with the authorization information
// retrieved from the provided token (avoids new calls, it's a cache)
req.ripeAuth = auth;
return req.ripeAuth;
};
/**
* The characters that are going to be used as the shift
* ones in the encoding operation.
*/
const SHIFT_CHARS = ["Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê"];
/**
* Encodes the given value following the Code 128 Set B
* guidelines, so that the value can be shown using the
* barcode 128 font.
*
* This function contains limitations when more than 3
* consecutive numbers are present in the value.
*
* @param {String} value The string value to be encoded.
* @returns {String} The Code 128 Set B value to be used with the
* barcode 128 font family.
* @see https://www.precisionid.com/code-128-faq/
*/
const encodeBarcode128B = value => {
// builds the checksum for the encoded barcode value
// 128 Set B by summing the START code (104) and the
// product of each data character with its position
// within the data
const length = value.length;
let checksumValue = 104;
for (let i = 0; i < length; i++) {
const encodedChar = value.charCodeAt(i) - 32;
checksumValue += (i + 1) * encodedChar;
}
// the checksum value is finally calculated by
// doing the remainder of the total by 103
// (Modulus 103 Checksum) and replacing shift
// characters code with the respective characters
const checksumInt = parseInt(checksumValue % 103, 10);
const checksum =
checksumInt > 94 ? SHIFT_CHARS[checksumInt - 95] : String.fromCharCode(checksumInt + 32);
// builds the encoded barcode value by adding the
// START and STOP code, the value and the checksum
const startCodeB = "Ì";
const stopCodeB = "Î";
return `${startCodeB}${value}${checksum}${stopCodeB}`;
};
const features = { "*": true };
const listeners = [];
const hasFeature = (name, fallback = false, source = null) => {
source = source || features;
fallback = source["*"] === undefined ? fallback : source["*"];
return Boolean(source[name] === undefined ? fallback : source[name]);
};
const setFeature = (name, value) => {
features[name] = value;
listeners.forEach(callable => callable(name, value));
};
const setFeatures = _features => {
Object.keys(features).forEach(k => delete features[k]);
Object.entries(_features).forEach(([k, v]) => {
features[k] = v;
});
};
const bindFeature = callable => {
listeners.push(callable);
return callable;
};
const unbindFeature = callable => {
listeners.splice(listeners.indexOf(callable), 1);
return callable;
};
const serializeContext = context => {
const result = {};
for (const [key, value] of Object.entries(context)) {
switch (typeof value) {
case "boolean":
result[key] = value ? "1" : "0";
break;
case "string":
result[key] = value;
break;
default:
result[key] = String(value);
break;
}
}
return result;
};
/**
* Creates the contents of the CSV file with the data given
* as an array of rows and the headers.
*
* @param {Array} data Array of rows with cell data.
* @param {Array} headers List of headers for the CSV file.
* @param {Object} options The options that are going to be
* used to build the CSV text stricture.
* @returns {String} The generated CSV string from the provided
* structure of arrays.
*/
const buildCsv = (
data,
headers = [],
{ delimiter = ",", eol = "\n", useHeaders = true } = {}
) => {
data = useHeaders ? [headers, ...data] : data;
return data.map(row => row.map(r => _toString(r, delimiter)).join(delimiter)).join(eol);
};
const dumpsCsv = buildCsv;
const arraysToCsv = (data, headers = [], options = {}) => {
return buildCsv(data, headers, options);
};
const arrayToCsv = (data, headers = [], options = {}) => {
return arraysToCsv([data], headers, options);
};
const objectsToCsv = (data, headers = [], options = {}) => {
headers =
Object.keys(headers).length === 0 && data.length > 0
? Object.keys(data[0]).sort()
: headers;
const dataArray = data.map(d => headers.map(h => d[h]));
return buildCsv(dataArray, headers, options);
};
const objectToCsv = (data, headers = [], options = {}) => {
return objectsToCsv([data], headers, options);
};
/**
* Parses a CSV file and returns a sequence of arrays
* containing the multiple lines of data (table).
*
* @param {Blob|File} file The file object that is going
* to be read and have its contents parsed as CSV.
* @param {Object} options The options that are going to be
* used in the parsing operation.
* @returns {Array} An array containing the multiple parsed
* CSV lines.
*/
const parseCsvFile = (file, options = undefined) => {
const parser = options.parser || _parseCsvComplex;
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = e => resolve(parser(e.target.result, options));
reader.onerror = e => reject(e);
reader.readAsText(file);
});
};
const parseCsv = (dataS, options = {}) => {
const parser = options.parser || _parseCsvComplex;
return parser(dataS, options);
};
const loadsCsv = parseCsv;
const _parseCsvSimple = (
dataS,
{ object = false, sanitize = true, delimiter = ",", eol = "\n" } = {}
) => {
// in case the sanitize operation has been requested runs a pre-operation
// to make sure no extra information exist at the end of the lines and
// that only the valid lines are taken into account
if (sanitize) {
dataS = dataS
.split(eol)
.filter(row => Boolean(row))
.map(row => row.trim())
.join(eol);
}
const data = dataS.split(eol).map(row => row.split(delimiter));
if (!object) return data;
return _toObject(data);
};
const _parseCsvComplex = (
dataS,
{ object = false, sanitize = true, delimiter = ",", eol = "\n" } = {}
) => {
// in case the sanitize operation has been required runs a pre-operation
// to make sure no extra information exist at the end of the lines and
// that only the valid lines are taken into account
if (sanitize) {
dataS = dataS
.split(eol)
.filter(row => Boolean(row))
.map(row => row.trim())
.join(eol);
}
// builds the custom pattern that is going to try to
// match the delimiter and the escaped and non escaped
// values to properly pars the CSV values
const pattern = new RegExp(
"(\\" +
delimiter +
"|\\r?\\n|\\r|^)" +
'(?:"([^"]*(?:""[^"]*)*)"|' +
'([^"\\' +
delimiter +
"\\r\\n]*))",
"gi"
);
// creates the initial data structure already populated
// with an initial value as we need to "look-back"
const data = [[]];
// creates an array to hold our individual pattern
// matching groups
let matches = null;
// keeps looping over the regular expression matches
// until we can no longer find a match
while ((matches = pattern.exec(dataS))) {
// retrieves the delimiter that was found, this will
// affect the newline operation
const matchedDelimiter = matches[1];
// checks to see if the given delimiter has a length
// (if it0s not the start of string) and if it matches
// field delimiter, if id does not, then we know
// that this delimiter is a row delimiter
if (matchedDelimiter.length && matchedDelimiter !== delimiter) {
// since we have reached a new row of data,
// adds an empty row to our data array