Merge release v1.1.0 to master #10

Manually merged
warricksothr merged 26 commits from develop into master 5 years ago
  1. 8
      .dockerignore
  2. 9
      .gitignore
  3. 16
      Dockerfile
  4. 27
      README.md
  5. 138
      bot/bot.js
  6. 28
      bot/config.js
  7. 147
      bot/engine.js
  8. 30
      bot/logging.js
  9. 10
      bot/message.js
  10. 176
      bot/module/abstract.js
  11. 19
      bot/module/admin.js
  12. 46
      bot/module/giphy.js
  13. 50
      bot/module/help.js
  14. 15
      bot/module/index.js
  15. 85
      bot/utility.js
  16. 4
      data/giphy-config.json.example
  17. 7
      entrypoint.sh
  18. 12
      index.js
  19. 288
      package-lock.json
  20. 7
      package.json
  21. 176
      pipeline.yml
  22. 2
      scripts/get_tag.sh
  23. 21
      scripts/run_development_docker.sh

8
.dockerignore

@ -1 +1,7 @@
data/config.json
node_modules/
log/
*.swp
pipeline.yml
README.md
CONTRIBUTING.md
test/

9
.gitignore

@ -2,7 +2,14 @@
node_modules/ node_modules/
# Config files # Config files
data/config.json
data/*config.json
# Log files
log/
*.log
# Mac Files # Mac Files
.DS_Store .DS_Store
# Swap files
*.swp

16
Dockerfile

@ -1,6 +1,16 @@
FROM node:12.14-stretch FROM node:12.14-stretch
COPY . /opt/baphomet COPY . /opt/baphomet
RUN npm install
ENV NODE_ENV=production
ENV LOG_LEVEL=warn
RUN mkdir /opt/baphomet/log
RUN cd /opt/baphomet \
&& npm install --only=prod \
&& chmod +x entrypoint.sh
WORKDIR /opt/baphomet WORKDIR /opt/baphomet
ENTRYPOINT entrypoint.sh
CMD run
ENTRYPOINT [ "./entrypoint.sh" ]
CMD [ "run" ]

27
README.md

@ -1,5 +1,9 @@
# Baphomet # Baphomet
Development Branch Tests: [![Concourse](https://concourse.nulloctet.com/api/v1/teams/nulloctet/pipelines/baphomet-js/jobs/test-develop/badge)](https://concourse.nulloctet.com/teams/nulloctet/pipelines/baphomet-js)
Master Branch Tests: [![Concourse](https://concourse.nulloctet.com/api/v1/teams/nulloctet/pipelines/baphomet-js/jobs/test-release/badge)](https://concourse.nulloctet.com/teams/nulloctet/pipelines/baphomet-js)
Baphomet is a bot to provide extended functionality to a matrix server Baphomet is a bot to provide extended functionality to a matrix server
## Configuration ## Configuration
@ -10,12 +14,31 @@ Copy data/config.json.example to data/config.json and replace the relevent confi
```bash ```bash
npm install npm install
node index.js
./entrypoint.sh run
``` ```
## Development ## Development
TBD
### Requirements:
Nodejs 12 LTS
OR
Docker
#### Local:
```bash
npm install
#<make changes>
./entrypoint.sh run
```
#### Docker:
```bash
./scripts/run_development_docker.sh
```
## Contributing ## Contributing

138
bot/bot.js

@ -1,62 +1,108 @@
let sdk = require("matrix-js-sdk");
let message = require("./message.js");
let sdk = require('matrix-js-sdk');
let message = require('./message');
let utility = require('./utility');
let { logger } = require('./logging');
class Bot { class Bot {
constructor(config) {
this.config = config
constructor(config, buildInfo) {
this.config = config;
this.buildInfo = buildInfo;
this.connected = false;
} }
}
function create(configFile) {
let config = require(configFile);
console.log("Running with config:");
console.log(config);
return new Bot(config);
}
/**
* Initialize the bot connection
*/
init(messageCallback) {
logger.info("Creating Matrix Client")
this.client = sdk.createClient({
baseUrl: this.config.baseUrl,
accessToken: this.config.accessToken,
userId: this.config.userId
});
function init(bot) {
console.log("Creating Matrix Client")
bot.client = sdk.createClient({
baseUrl: bot.config.baseUrl,
accessToken: bot.config.accessToken,
userId: bot.config.userId
});
function sendClientStatusUpdate() {
bot.config.statusRooms.forEach(roomId => {
console.log("Notifying %s", roomId);
bot.client.sendMessage(roomId, message.createBasic("Started!")).done(function () {
console.log("Notified %s", roomId);
})
this.client.on("sync", async (state, previousState, data) => {
switch (state) {
case "PREPARED":
this.connected = true;
await this.sendStatusStartup();
this.client.getJoinedRooms()
.done((rooms) => {
logger.info("Connected to: %o", rooms)
});
break;
case "SYNCING":
logger.debug("Syncing")
break;
case "RECONNECTING":
logger.debug("Reconnecting");
break;
default:
logger.error("Unexpected sync state: %s", state);
process.exit(1);
}
}); });
this.client.on("RoomMember.membership", (event, member) => {
if (member.membership === "invite"
&& this.config.admin.indexOf(ember.userId) >= 0) {
this.client.joinRoom(member.roomId).done(() => {
logger.info("Auto-joined %s", member.roomId);
});
}
});
this.client.on("Room.timeline", messageCallback);
return this;
} }
// Prep the bot
bot.client.on("sync", function (state, previousState, data) {
switch (state) {
case "PREPARED":
sendClientStatusUpdate();
break;
}
});
// auto join rooms that an admin user has invited the bot to
bot.client.on("RoomMember.membership", function (event, member) {
if (member.membership === "invite"
&& bot.config.admin.indexOf(ember.userId) >= 0) {
bot.client.joinRoom(member.roomId).done(function () {
console.log("Auto-joined %s", member.roomId);
async connect() {
// logger.info("Initializing Crypto");
// await bot.client.initCrypto();
logger.info("Starting Matrix SDK Client");
await this.client.startClient();
}
sendStatusStartup() {
let promises = [Promise.resolve(true)]
if (this.connected) {
this.config.statusRooms.forEach(roomId => {
logger.debug("Notifying %s of startup", roomId);
promises.push(this.client.sendMessage(
roomId, message.createBasic("Started with version: " + this.buildInfo, message.types.NOTICE)
).then(() => {
logger.debug("Notified %s of startup", roomId);
}));
}); });
} else {
logger.warn("Attempting to send startup message while disconnected");
} }
});
return Promise.all(promises);
}
return bot;
sendStatusShutdown() {
let promises = [Promise.resolve(true)]
if (this.connected) {
this.config.statusRooms.forEach(roomId => {
logger.debug("Notifying %s of shutdown", roomId);
promises.push(this.client.sendMessage(
roomId, message.createBasic("Shutting down", message.types.NOTICE)
).then(() => {
logger.debug("Notified %s of shutdown", roomId);
}));
});
} else {
logger.warn("Attempting to send shutdown message while disconnected");
}
return Promise.all(promises);
}
} }
function run(bot) {
bot.client.startClient()
function create(config) {
let buildInfo = utility.getBuildInfo("../build.info")
logger.info("Running version: %s", buildInfo);
return new Bot(config, buildInfo);
} }
exports.create = create; exports.create = create;
exports.init = init;
exports.run = run;

28
bot/config.js

@ -0,0 +1,28 @@
let fs = require('fs');
let { logger } = require('./logging');
let loadedConfigs = new Map();
function sanitizeConfig(config, fields=[]) {
let clonedConfig = { ...config };
fields.forEach((field) => {
clonedConfig[field] = '******'
})
return clonedConfig;
}
function getConfig(configFile, sanitizedFields=[]) {
if (!loadedConfigs.has(configFile)) {
logger.info("Reading config: %s", configFile);
let rawConfigData = fs.readFileSync(configFile);
let config = JSON.parse(rawConfigData);
logger.info("Loaded config: %s", configFile);
logger.debug("%o", sanitizeConfig(config, sanitizedFields));
loadedConfigs.set(configFile, config);
return config;
} else {
return loadedConfigs.get(configFile);
}
}
exports.getConfig = getConfig

147
bot/engine.js

@ -0,0 +1,147 @@
let { logger } = require('./logging');
let { modules } = require('./module/index');
let trie = require('trie-prefix-tree');
let { getShortestPrefix } = require('./utility');
let help = require('./module/help');
let message = require('./message');
let utility = require('./utility');
let { initModule } = require('./module/abstract');
let sentinelValue = '!';
class Engine {
constructor(config, bot, modules) {
this.config = config;
this.bot = bot;
this.modules = modules;
this.moduleMap = new Map();
this.commands = [];
this.commandMap = new Map();
this.commandRadixTree = trie([]);
}
initModules() {
this.modules.forEach((mod) => {
logger.info("Loading module: %s", mod.name);
initModule(mod);
console.log("Recognized commands: %s", mod.getRecognizedCommands())
this.moduleMap.set(mod.command, mod);
this.commandMap.set(mod.command, mod);
this.commandRadixTree.addWord(mod.command);
});
this.modules.forEach((mod) => {
let shortCharCommand = getShortestPrefix(this.commandRadixTree, mod.command, 1);
let short3CharCommand = getShortestPrefix(this.commandRadixTree, mod.command, 3);
let shortCommandAliases = [shortCharCommand, short3CharCommand];
logger.info("Adding short command %s for module: %s", shortCommandAliases, mod.name);
shortCommandAliases.forEach((commandAlias) => {
this.commandMap.set(commandAlias, mod);
})
});
this.helpModule = help.create(this.moduleMap)
initModule(this.helpModule);
this.moduleMap.set(this.helpModule.command, this.helpModule);
this.commandMap.set('help', this.helpModule);
this.commands = Array.from(this.commandMap.keys()).sort()
logger.info("Bound modules to keywords: %o", this.moduleMap);
}
init() {
logger.info("Initializing modules");
this.initModules();
/* Bind Message Parsing */
let engine = this;
let handleMessages = (event, room, toStartOfTimeline) => {
/* Don't process messages from self */
if (event.sender.userId !== this.config.userId) {
/* don't process messages that aren't of type m.room.message */
if (event.getType() !== "m.room.message") {
logger.debug("Recieved message of type: %s", event.getType());
return;
} else {
let messageBody = event.event.content.body;
logger.debug("[%s] %s", room.name, messageBody);
if (messageBody.indexOf(sentinelValue) === 0) {
let command = messageBody.split(' ')[0].substring(1);
if (engine.commandMap.has(command)) {
engine.commandMap.get(command).handleMessage(event, room, sendResponseMessageCallback(engine.bot));
} else {
let responseMessage = "The following commands are recognized"
responseMessage += "\n" + engine.commands.join(", ")
responseMessage += "\nAdditional information can be discovered with !help <command>"
sendResponseMessage(engine.bot, room, responseMessage);
}
}
}
}
}
this.bot.init(handleMessages);
/* Capture Exit Conditions */
["SIGINT", "SIGTERM"].forEach((signature) => {
process.on(signature, async () => {
await this.bot.sendStatusShutdown()
.then(() => {
logger.info("Gracefully stopping Matrix SDK Client")
this.bot.client.stopClient();
});
process.exit(0);
});
});
process.on('exit', () => {
logger.info("Shutting Down");
});
return this;
}
run() {
this.bot.connect();
return this;
}
}
/**
* Handle the callback sending messages via the bot
*
* @param {*} bot
* @param {*} room
* @param {*} responseMessage
*/
function sendResponseMessage(bot, room, responseMessage) {
logger.debug("Responding to room: %s with %o", room.roomId, responseMessage);
Promise.resolve(responseMessage).then((promisedMessage) => {
logger.debug("Sending message: %s", promisedMessage);
if (promisedMessage instanceof Object) {
bot.client.sendMessage(room.roomId, promisedMessage);
} else if (utility.isString(promisedMessage)) {
bot.client.sendMessage(room.roomId, message.createBasic(promisedMessage));
} else {
logger.error("Unable to process response message: %s", promisedMessage);
}
})
}
/**
* Wrapper to produce a callback function that can be passed to the modules
*
* @param {*} bot
*/
function sendResponseMessageCallback(bot) {
return (room, responseMessage) => {
sendResponseMessage(bot, room, responseMessage);
}
}
function create(config, bot) {
return new Engine(config, bot, modules)
}
exports.create = create;

30
bot/logging.js

@ -0,0 +1,30 @@
let winston = require('winston');
let logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.splat(),
winston.format.json()
),
defaultMeta: { service: 'baphomet-js' },
transports: [
new winston.transports.File({ filename: 'log/error.log', level: 'error' }),
new winston.transports.File({ filename: 'log/combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.simple()
)
}));
}
if ('LOG_LEVEL' in process.env) {
logger.info('LOG_LEVEL:', process.env.LOG_LEVEL)
logger.level = process.env.LOG_LEVEL
}
exports.logger = logger;

10
bot/message.js

@ -1,8 +1,14 @@
function createBasicMessage(body) {
let messageTypes = {
TEXT: 'm.text',
NOTICE: 'm.notice'
}
function createBasicMessage(body, msgtype=messageTypes.TEXT) {
return { return {
"body": body, "body": body,
"msgtype": "m.text"
"msgtype": msgtype
} }
} }
exports.types = messageTypes;
exports.createBasic = createBasicMessage; exports.createBasic = createBasicMessage;

176
bot/module/abstract.js

@ -0,0 +1,176 @@
/**
* Base module that all modules extend
*/
let { logger } = require('../logging');
let message = require('../message');
let { isFunction, getObjectKeysToPrototype } = require('../utility');
let { getConfig } = require('../config');
class AbstractModule {
/*
Name of the module used in help documentation and logging.
*/
name = "AbstractModule";
/*
Short description of the module functionality.
*/
description = "Base Module That All Other Modules Extend";
/*
A helpful multiline string that defines the module usage
*/
helpAndUsage = `Example: !abstract_module <command>
!abstract_module <boo> : scares people`
/*
The exported command used to invoke the module directly.
*/
command = "abstract_module";
/*
The default method to call when a command word is not recognized.
*/
defaultCommand = null;
/*
The module should be hidden from help and command dialogs.
*/
hidden = false;
/*
This module should receive all messages, regardless of whether
the module was directly referenced with a command.
*/
canHandleIndirectMessages = false;
/*
Indicates if the module requires a readable config file.
*/
needConfig = false;
/* internal */
/*
The loaded config file, if it exists.
*/
_config = null;
constructor(name, description, command) {
this.name = name;
this.description = description;
this.command = command;
this._recognizedCommands = [];
this._recognizedCommandMap = new Map();
}
addRecognizedCommand(command, methodName) {
this._recognizedCommands.push(command);
this._recognizedCommandMap.set(command, methodName);
}
getRecognizedCommands() {
return this._recognizedCommandMap.keys();
}
getConfigFilePath() {
return process.env.NODE_PATH + '/data/' + this.name.toLowerCase().replace(' ', '_') + '-config.json';
}
getConfigSensitiveFields() {
return [];
}
/**
* Default functionality for receiving and processing a message.
*
* Override this if the module needs to do more complicated message processing.
*/
handleMessage(event, room, callback) {
logger.debug("[%s] [%s] [%s]", this.name, room.name, event.event.content.body);
let messageBody = event.event.content.body;
let bodyParts = messageBody.split(' ');
let trigger = bodyParts[0];
let command = bodyParts[1];
var args = [];
if (bodyParts.length > 2) {
args = bodyParts.slice(2);
}
logger.debug("Attempting to call %s with %s", command, args);
let responseMessage = this.processMessage(command, ...args);
callback(
room,
responseMessage
);
}
/*
Call the command method with the args
*/
processMessage(command, ...args) {
if (this._recognizedCommands.includes(command)) {
logger.debug("Calling %s with %s", this._recognizedCommandMap.get(command), args);
return this[this._recognizedCommandMap.get(command)](...args);
} else {
if (this.defaultCommand != null) {
logger.debug("Attempting to use default command %s", this.defaultCommand);
try {
let newArgs = [command].concat(...args);
logger.debug("Calling %s with %s", this._recognizedCommandMap.get(this.defaultCommand), newArgs);
return this[this._recognizedCommandMap.get(this.defaultCommand)](...newArgs);
} catch (e) {
logger.error("Error while calling default command %s %s", this.defaultCommand, e);
return this.cmd_help();
}
} else {
logger.debug("Unrecognized command %s", command);
return this.cmd_help();
}
}
}
/* Basic cmd methods */
/*
return basic help information,.
*/
cmd_help(...args) {
return message.createBasic(this.helpAndUsage);
}
}
let abstractModulePrototype = Object.getPrototypeOf(new AbstractModule('', '', ''));
/*
Initialization of a module.
*/
function init(mod) {
logger.debug("Initializing module %s", mod.name);
if (mod.needConfig) {
logger.debug("Loading config file %s", mod.getConfigFilePath());
try {
mod._config = getConfig(mod.getConfigFilePath(), mod.getConfigSensitiveFields());
} catch (e) {
logger.error("Module %s needs a valid config file at %s", mod.name, mod.getConfigFilePath());
process.exit(1);
}
}
logger.debug("Detecting command methods.");
let commandMethods = getObjectKeysToPrototype(mod, abstractModulePrototype, (key) => {
return key.startsWith('cmd_') && isFunction(mod[key]);
})
// let commandMethods = objectKeys.filter();
logger.debug("Identified command methods: %s", commandMethods);
commandMethods.forEach((commandMethodName) => {
let command = commandMethodName.substring(4);
mod.addRecognizedCommand(command, commandMethodName);
})
logger.debug("Bound command methods for %s as %s", mod.name, mod.getRecognizedCommands());
}
exports.AbstractModule = AbstractModule
exports.initModule = init;

19
bot/module/admin.js

@ -0,0 +1,19 @@
/**
* Administration module
*/
let { AbstractModule } = require('./abstract');
class AdminModule extends AbstractModule {
constructor() {
super(
"Administration",
"Support administration tasks",
"admin"
);
this.helpAndUsage = `Usage: admin <command>
...`;
}
}
exports.module = new AdminModule();

46
bot/module/giphy.js

@ -0,0 +1,46 @@
/**
* Giphy module
*/
let { AbstractModule } = require('./abstract');
let axios = require('axios');
let { logger } = require('../logging');
class GiphyModule extends AbstractModule {
constructor() {
super(
"Giphy",
"Insert Giphy Links/Media",
"giphy"
);
this.helpAndUsage = `Usage: !giphy itsworking
...`;
this.needConfig = true;
this.defaultCommand = 'search';
}
getConfigSensitiveFields() {
return ["apiKey"];
}
getGiphySearch(term) {
let url = this._config.endpoint + '/gifs/search?api_key=' + this._config.apiKey + '&q=' + term + '&limit=1';
logger.debug("Requesting: %s", url.replace(this._config.apiKey, '******'));
return axios.get(url);
}
/**
* Return the top item for the search terms.
*
* @param {...any} args
*/
cmd_search(...args) {
return this.getGiphySearch(args[0])
.then((response) => {
// logger.debug("Giphy response: %o", response.data.data[0].url);
return response.data.data[0].embed_url;
})
}
}
exports.module = new GiphyModule();

50
bot/module/help.js

@ -0,0 +1,50 @@
/**
* Help module
*/
let { AbstractModule } = require('./abstract');
let { logger } = require('../logging');
class HelpModule extends AbstractModule {
constructor(commandMap) {
super(
"Help",
"Provide helpful information about other modules.",
"help"
);
this._commandMap = commandMap;
this._commandList = Array.from(commandMap.keys()).sort();
this.defaultCommand = 'help';
}
_default_help_message() {
let help = `!help <command>`;
for (let command of this._commandList) {
help += "\n!help " + command + " : " + this._commandMap.get(command).description;
}
return help;
}
cmd_help(...args) {
logger.debug("%o", args)
if (args.length < 1) {
return this._default_help_message();
} else {
let command = args[0];
logger.debug("Looking up help for %s from %o", command, this._commandMap);
if (this._commandList.includes(command)) {
return this._commandMap.get(command).cmd_help();
} else {
let help = command + " is an unrecognized module\n";
help += this._default_help_message();
return help;
}
}
}
}
function create(commandMap) {
return new HelpModule(commandMap);
}
exports.create = create;

15
bot/module/index.js

@ -0,0 +1,15 @@
/**
* Manage the registered modules
*/
let admin = require('./admin');
let giphy = require('./giphy')
function getModules() {
return [
admin.module,
giphy.module
];
}
exports.modules = getModules();

85
bot/utility.js

@ -0,0 +1,85 @@
let fs = require('fs');
let { logger } = require('./logging');
function getShortestPrefix(radixTree, key, sliceSize) {
let shortKey = key.substring(0, sliceSize);
let keyCount = radixTree.countPrefix(shortKey);
if (keyCount < 1) {
return null;
}
if (key.length === sliceSize && radixTree.getPrefix(shortKey).includes(key)) {
return null;
}
if (keyCount === 1) {
return shortKey;
}
return getShortestPrefix(radixTree, key, sliceSize + 1);
}
function toISODateString(d) {
function pad(n) { return n < 10 ? '0' + n : n }
return d.getUTCFullYear() + '-'
+ pad(d.getUTCMonth() + 1) + '-'
+ pad(d.getUTCDate()) + 'T'
+ pad(d.getUTCHours()) + ':'
+ pad(d.getUTCMinutes()) + ':'
+ pad(d.getUTCSeconds()) + 'Z'
}
function getBuildInfo(buildInfoPath) {
try {
return fs.readFileSync(buildInfoPath, "utf8");
} catch (err) {
if (err.code === 'ENOENT') {
return "UNKNOWN_" + toISODateString(new Date());
} else {
logger.error("Unexpected Error!", err);
}
}
}
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
}
function isString(s) {
return typeof (s) === 'string' || s instanceof String;
}
function isFunction(f) {
return f && {}.toString.call(f) === '[object Function]';
}
/**
* Parse the prototype tree to return all accessible properties till
* reaching a sentinelPrototype.
*
* Optionally provide a filtering function to return only the names that match.
*
* @param {*} initialObj The starting object to derive the from
* @param {*} sentinelPrototype The prototype that represents the end of the line
* @param {*} filterFunc A fioltering function for the return names
*/
function getObjectKeysToPrototype(initialObj, sentinelPrototype, filterFunc = (e) => true) {
let prototypeChain = []
var targetPrototype = initialObj;
while (Object.getPrototypeOf(targetPrototype) && targetPrototype !== sentinelPrototype) {
targetPrototype = Object.getPrototypeOf(targetPrototype);
prototypeChain.push(targetPrototype);
}
// console.log("Prototype chain: %s", prototypeChain);
let completePropertyNames = prototypeChain.map((obj) => {
return Object.getOwnPropertyNames(obj);
})
return [Object.getOwnPropertyNames(initialObj)].concat.apply([], completePropertyNames).filter(filterFunc);
}
exports.getShortestPrefix = getShortestPrefix;
exports.toISODateString = toISODateString;
exports.getBuildInfo = getBuildInfo;
exports.sleep = sleep;
exports.isString = isString;
exports.isFunction = isFunction;
exports.getObjectKeysToPrototype = getObjectKeysToPrototype;

4
data/giphy-config.json.example

@ -0,0 +1,4 @@
{
"endpoint": "api.giphy.com/v1",
"apiKey": "<Your API Key Here>"
}

7
entrypoint.sh

@ -1,5 +1,12 @@
#! /usr/bin/env sh #! /usr/bin/env sh
DIR="$( cd "$( dirname "${0}" )" >/dev/null 2>&1 && pwd )"
export NODE_PATH="${DIR}"
echo "NODE_ENV: ${NODE_ENV}"
echo "NODE_PATH: ${NODE_PATH}"
echo "LOG_LEVEL: ${LOG_LEVEL}"
case $1 in case $1 in
run) run)
node index.js node index.js

12
index.js

@ -1,2 +1,10 @@
let bot = require('./bot/bot.js');
bot.run(bot.init(bot.create("../data/config.json")));
let bot = require('./bot/bot');
let { getConfig } = require('./bot/config');
let engine = require('./bot/engine');
let config = getConfig(process.env.NODE_PATH + "/data/config.json", ['accessToken'])
engine.create(
config,
bot.create(config)
).init().run();

288
package-lock.json

@ -63,6 +63,14 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
}, },
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"requires": {
"lodash": "^4.17.14"
}
},
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -78,6 +86,15 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
"integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A=="
}, },
"axios": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz",
"integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==",
"requires": {
"follow-redirects": "1.5.10",
"is-buffer": "^2.0.2"
}
},
"babel-runtime": { "babel-runtime": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
@ -215,11 +232,19 @@
} }
} }
}, },
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": { "color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": { "requires": {
"color-name": "1.1.3" "color-name": "1.1.3"
} }
@ -227,8 +252,35 @@
"color-name": { "color-name": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y="
},
"colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
},
"colorspace": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz",
"integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==",
"requires": {
"color": "3.0.x",
"text-hex": "1.0.x"
}
}, },
"combined-stream": { "combined-stream": {
"version": "1.0.8", "version": "1.0.8",
@ -296,6 +348,16 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
}, },
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
"requires": {
"colorspace": "1.1.x",
"enabled": "1.0.x",
"kuler": "1.0.x"
}
},
"diff": { "diff": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
@ -317,6 +379,19 @@
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true "dev": true
}, },
"enabled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"requires": {
"env-variable": "0.0.x"
}
},
"env-variable": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA=="
},
"es-abstract": { "es-abstract": {
"version": "1.16.3", "version": "1.16.3",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.3.tgz", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.3.tgz",
@ -374,9 +449,19 @@
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
}, },
"fast-json-stable-stringify": { "fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-safe-stringify": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
"integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA=="
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
}, },
"find-up": { "find-up": {
"version": "3.0.0", "version": "3.0.0",
@ -396,6 +481,29 @@
"is-buffer": "~2.0.3" "is-buffer": "~2.0.3"
} }
}, },
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@ -521,14 +629,17 @@
"inherits": { "inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
}, },
"is-buffer": { "is-buffer": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
"dev": true
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
}, },
"is-callable": { "is-callable": {
"version": "1.1.4", "version": "1.1.4",
@ -557,6 +668,11 @@
"has": "^1.0.1" "has": "^1.0.1"
} }
}, },
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"is-symbol": { "is-symbol": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
@ -571,6 +687,11 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
}, },
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": { "isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -623,6 +744,14 @@
"verror": "1.10.0" "verror": "1.10.0"
} }
}, },
"kuler": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
"integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==",
"requires": {
"colornames": "^1.1.1"
}
},
"locate-path": { "locate-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@ -636,8 +765,7 @@
"lodash": { "lodash": {
"version": "4.17.15", "version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
}, },
"log-symbols": { "log-symbols": {
"version": "2.2.0", "version": "2.2.0",
@ -648,6 +776,18 @@
"chalk": "^2.0.1" "chalk": "^2.0.1"
} }
}, },
"logform": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz",
"integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==",
"requires": {
"colors": "^1.2.1",
"fast-safe-stringify": "^2.0.4",
"fecha": "^2.3.3",
"ms": "^2.1.1",
"triple-beam": "^1.3.0"
}
},
"loglevel": { "loglevel": {
"version": "1.6.6", "version": "1.6.6",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz",
@ -741,8 +881,7 @@
"ms": { "ms": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}, },
"node-environment-flags": { "node-environment-flags": {
"version": "1.0.5", "version": "1.0.5",
@ -802,6 +941,11 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"one-time": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4="
},
"p-limit": { "p-limit": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
@ -843,10 +987,15 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
}, },
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"psl": { "psl": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz",
"integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA=="
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
}, },
"punycode": { "punycode": {
"version": "2.1.1", "version": "2.1.1",
@ -858,6 +1007,16 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz",
"integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA=="
}, },
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.11.1", "version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
@ -931,6 +1090,14 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true "dev": true
}, },
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
}
},
"sprintf-js": { "sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@ -953,6 +1120,11 @@
"tweetnacl": "~0.14.0" "tweetnacl": "~0.14.0"
} }
}, },
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"string-width": { "string-width": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
@ -983,6 +1155,14 @@
"function-bind": "^1.1.1" "function-bind": "^1.1.1"
} }
}, },
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"strip-ansi": { "strip-ansi": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -1007,6 +1187,11 @@
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
} }
}, },
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
"tough-cookie": { "tough-cookie": {
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@ -1023,6 +1208,16 @@
} }
} }
}, },
"trie-prefix-tree": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/trie-prefix-tree/-/trie-prefix-tree-1.5.1.tgz",
"integrity": "sha512-Jjvj/dA97wXnabG/NLJUgo4IQMj6vucH+Qxm7of/omfWSmZlPqdRU6Ta4GmQqCZH+n3/iYZUwfvUoEhB0Hs83Q=="
},
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
},
"tunnel-agent": { "tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -1049,6 +1244,11 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": { "uuid": {
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
@ -1088,6 +1288,60 @@
"string-width": "^1.0.2 || 2" "string-width": "^1.0.2 || 2"
} }
}, },
"winston": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz",
"integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==",
"requires": {
"async": "^2.6.1",
"diagnostics": "^1.1.1",
"is-stream": "^1.1.0",
"logform": "^2.1.1",
"one-time": "0.0.4",
"readable-stream": "^3.1.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.3.0"
}
},
"winston-transport": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz",
"integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==",
"requires": {
"readable-stream": "^2.3.6",
"triple-beam": "^1.2.0"
},
"dependencies": {
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",

7
package.json

@ -4,11 +4,16 @@
"main": "index.js", "main": "index.js",
"author": "Drew Short <warrick@sothr.com>", "author": "Drew Short <warrick@sothr.com>",
"license": "MIT", "license": "MIT",
"description": "A Matrix bot written on top of the matrix-js-sdk",
"repository": "https://git.nulloctet.com/warricksothr/baphomet-js",
"scripts": { "scripts": {
"test": "mocha" "test": "mocha"
}, },
"dependencies": { "dependencies": {
"matrix-js-sdk": "2.4.5"
"axios": "^0.19.0",
"matrix-js-sdk": "2.4.5",
"trie-prefix-tree": "^1.5.1",
"winston": "^3.2.1"
}, },
"devDependencies": { "devDependencies": {
"mocha": "^6.2.2" "mocha": "^6.2.2"

176
pipeline.yml

@ -1,48 +1,132 @@
--- ---
resources: resources:
- name: baphomet-js-git
- name: git-develop
type: git type: git
icon: git icon: git
source: source:
uri: ssh://git@git.nulloctet.com:8437/warricksothr/baphomet-js.git uri: ssh://git@git.nulloctet.com:8437/warricksothr/baphomet-js.git
private_key: | private_key: |
((pull_key)) ((pull_key))
branch: master
- name: baphomet-js-git-develop
branch: develop
ignore_paths:
- pipeline.yml
- scripts/upload_pipeline.sh
- README.md
- CONTRIBUTING.md
- LICENSE.md
- name: git-master
type: git type: git
icon: git icon: git
source: source:
uri: ssh://git@git.nulloctet.com:8437/warricksothr/baphomet-js.git uri: ssh://git@git.nulloctet.com:8437/warricksothr/baphomet-js.git
private_key: | private_key: |
((pull_key)) ((pull_key))
branch: develop
branch: master
ignore_paths:
- pipeline.yml
- scripts/upload_pipeline.sh
- README.md
- CONTRIBUTING.md
- LICENSE.md
- name: docker-image
type: docker-image
icon: docker
source:
repository: ((nexus_docker_write.host))/nulloctet/baphomet-js
username: ((nexus_docker_write.username))
password: ((nexus_docker_write.password))
jobs: jobs:
- name: test
# Development Pipeline
- name: test-develop
plan: plan:
- get: baphomet-js-git
- get: git-develop
trigger: true
- task: run-tests
config:
platform: linux
image_resource:
type: registry-image
source: { repository: node, tag: "12.14-stretch" }
inputs:
- name: git-develop
run:
path: /bin/sh
args:
- -c
- |
echo "Node Version: $(node --version)"
echo "NPM Version: $(npm --version)"
cd git-develop
npm install
npm test
- name: deploy-develop-image
plan:
- get: git-develop
passed: [test-develop]
trigger: true trigger: true
- task: run-tests
- task: capture-version
config: config:
platform: linux platform: linux
image_resource: image_resource:
type: registry-image type: registry-image
source: { repository: node, tag: "12.14-stretch" }
source: { repository: bitnami/git, tag: "2-debian-9" }
inputs: inputs:
- name: baphomet-js-git
- name: git-develop
outputs:
- name: version
run: run:
path: /bin/sh path: /bin/sh
args: args:
- -c - -c
- | - |
echo "Node Version: $(node --version)"
echo "NPM Version: $(npm --version)"
cd baphomet-js-git
npm install
npm test
- name: test-develop
cd git-develop
chmod +x ././scripts/get_*.sh
echo $(./scripts/get_build.sh) > ../version/build.info
echo $(./scripts/get_version.sh) > ../version/version.info
echo $(./scripts/get_tag.sh) > ../version/tag.info
echo "dev" > ../version/tag
echo "Build Information: $(cat ../version/build.info)"
echo "Version Information: $(cat ../version/version.info)"
echo "Tag Information: $(cat ../version/tag.info)"
echo "Docker Image Tag: $(cat ../version/tag)"
- task: package
config:
platform: linux
image_resource:
type: registry-image
source: { repository: debian, tag: "stretch-slim" }
inputs:
- name: git-develop
- name: version
outputs:
- name: package
run:
path: /bin/sh
args:
- -c
- |
cd package
cp ../version/* .
cp ../git-develop/package*.json .
cp ../git-develop/index.js .
cp -r ../git-develop/assets .
cp -r ../git-develop/bot .
cp -r ../git-develop/data .
cp ../git-develop/entrypoint.sh .
cp ../git-develop/Dockerfile .
cp ../git-develop/README.md .
cp ../git-develop/LICENSE.md .
ls -al .
- put: docker-image
params:
build: package
tag_file: package/tag
tag_as_latest: false
# Release Pipeline
- name: test-release
plan: plan:
- get: baphomet-js-git-develop
- get: git-master
trigger: true trigger: true
- task: run-tests - task: run-tests
config: config:
@ -51,7 +135,7 @@ jobs:
type: registry-image type: registry-image
source: { repository: node, tag: "12.14-stretch" } source: { repository: node, tag: "12.14-stretch" }
inputs: inputs:
- name: baphomet-js-git-develop
- name: git-master
run: run:
path: /bin/sh path: /bin/sh
args: args:
@ -59,13 +143,13 @@ jobs:
- | - |
echo "Node Version: $(node --version)" echo "Node Version: $(node --version)"
echo "NPM Version: $(npm --version)" echo "NPM Version: $(npm --version)"
cd baphomet-js-git-develop
cd git-master
npm install npm install
npm test npm test
- name: package
- name: deploy-release-image
plan: plan:
- get: baphomet-js-git
passed: [test]
- get: git-master
passed: [test-release]
trigger: true trigger: true
- task: capture-version - task: capture-version
config: config:
@ -74,19 +158,24 @@ jobs:
type: registry-image type: registry-image
source: { repository: bitnami/git, tag: "2-debian-9" } source: { repository: bitnami/git, tag: "2-debian-9" }
inputs: inputs:
- name: baphomet-js-git
- name: git-master
outputs: outputs:
- name: baphomet-js-version
- name: version
run: run:
path: /bin/sh path: /bin/sh
args: args:
- -c - -c
- | - |
cd baphomet-js-git
cd git-master
chmod +x ././scripts/get_*.sh chmod +x ././scripts/get_*.sh
echo $(./scripts/get_build.sh) > ../baphomet-js-version/build.info
echo $(./scripts/get_version.sh) > ../baphomet-js-version/version.info
cat ../baphomet-js-version/build.info
echo $(./scripts/get_build.sh) > ../version/build.info
echo $(./scripts/get_version.sh) > ../version/version.info
echo $(./scripts/get_tag.sh) > ../version/tag.info
cp ../version/tag.info ../version/tag
echo "Build Information: $(cat ../version/build.info)"
echo "Version Information: $(cat ../version/version.info)"
echo "Tag Information: $(cat ../version/tag.info)"
echo "Docker Image Tag: $(cat ../version/tag)"
- task: package - task: package
config: config:
platform: linux platform: linux
@ -94,8 +183,8 @@ jobs:
type: registry-image type: registry-image
source: { repository: debian, tag: "stretch-slim" } source: { repository: debian, tag: "stretch-slim" }
inputs: inputs:
- name: baphomet-js-git
- name: baphomet-js-version
- name: git-master
- name: version
outputs: outputs:
- name: package - name: package
run: run:
@ -103,15 +192,20 @@ jobs:
args: args:
- -c - -c
- | - |
mkdir tmp
cd tmp
cp ../baphomet-js-version/version.info .
cp ../baphomet-js-version/build.info .
cp ../baphomet-js-git/package*.json .
cp ../baphomet-js-git/index.js .
cp -r ../baphomet-js-git/assets .
cp -r ../baphomet-js-git/bot .
cp -r ../baphomet-js-git/data .
cp ../baphomet-js-git/README.md .
cp ../baphomet-js-git/LICENSE.md .
tar -zcvf ../package/baphomet-js-$(cat version.info).tgz ./*
cd package
cp ../version/* .
cp ../git-master/package*.json .
cp ../git-master/index.js .
cp -r ../git-master/assets .
cp -r ../git-master/bot .
cp -r ../git-master/data .
cp ../git-master/entrypoint.sh .
cp ../git-master/Dockerfile .
cp ../git-master/README.md .
cp ../git-master/LICENSE.md .
ls -al .
- put: docker-image
params:
build: package
tag_file: package/tag
tag_as_latest: true

2
scripts/get_tag.sh

@ -0,0 +1,2 @@
#!/usr/bin/env sh
echo "$(git describe --tags | awk '{split($0,a,"-"); print a[1]}')"

21
scripts/run_development_docker.sh

@ -0,0 +1,21 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
pushd "${DIR}/.."
CONTAINER_NAME=baphomet-dev
IMAGE_NAME=baphomet-js
IMAGE_TAG=dev
IMAGE_BUILD_DIR=.
docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_BUILD_DIR}
docker rm ${CONTAINER_NAME}
docker run -it \
-e NODE_ENV=development \
-e LOG_LEVEL=debug \
--name ${CONTAINER_NAME} \
${IMAGE_NAME}:${IMAGE_TAG}
popd
Loading…
Cancel
Save