From a21a6c595a4ae9fd0ddf29fd4c2260c85501bb90 Mon Sep 17 00:00:00 2001 From: Jack Hadrill Date: Mon, 8 Jun 2020 20:56:17 +0100 Subject: [PATCH] Simplify for Butlersaurus --- Dockerfile | 5 + Jenkinsfile | 0 about.md | 61 --- config.js | 38 +- lib/document_handler.js | 103 ++--- lib/document_store.js | 47 +++ lib/document_stores/amazon-s3.js | 56 --- lib/document_stores/file.js | 63 --- lib/document_stores/memcached.js | 52 --- lib/document_stores/postgres.js | 79 ---- lib/document_stores/redis.js | 89 ----- lib/document_stores/rethinkdb.js | 46 --- lib/key_generator.js | 19 + lib/key_generators/dictionary.js | 32 -- lib/key_generators/phonetic.js | 27 -- lib/key_generators/random.js | 20 - package-lock.json | 527 +++++++------------------ package.json | 33 +- server.js | 162 +++----- test/document_handler_spec.js | 26 -- test/key_generators/dictionary_spec.js | 33 -- test/key_generators/phonetic_spec.js | 27 -- test/key_generators/random_spec.js | 19 - test/redis_document_store_spec.js | 54 --- 24 files changed, 311 insertions(+), 1307 deletions(-) create mode 100644 Dockerfile create mode 100644 Jenkinsfile delete mode 100644 about.md create mode 100644 lib/document_store.js delete mode 100644 lib/document_stores/amazon-s3.js delete mode 100644 lib/document_stores/file.js delete mode 100644 lib/document_stores/memcached.js delete mode 100644 lib/document_stores/postgres.js delete mode 100644 lib/document_stores/redis.js delete mode 100644 lib/document_stores/rethinkdb.js create mode 100644 lib/key_generator.js delete mode 100644 lib/key_generators/dictionary.js delete mode 100644 lib/key_generators/phonetic.js delete mode 100644 lib/key_generators/random.js delete mode 100644 test/document_handler_spec.js delete mode 100644 test/key_generators/dictionary_spec.js delete mode 100644 test/key_generators/phonetic_spec.js delete mode 100644 test/key_generators/random_spec.js delete mode 100644 test/redis_document_store_spec.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1aef86f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM node:alpine +WORKDIR /app +COPY . /app +RUN npm install +CMD [ "npm", "start" ] \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..e69de29 diff --git a/about.md b/about.md deleted file mode 100644 index c446934..0000000 --- a/about.md +++ /dev/null @@ -1,61 +0,0 @@ -# Haste - -Sharing code is a good thing, and it should be _really_ easy to do it. -A lot of times, I want to show you something I'm seeing - and that's where we -use pastebins. - -Haste is the prettiest, easiest to use pastebin ever made. - -## Basic Usage - -Type what you want me to see, click "Save", and then copy the URL. Send that -URL to someone and they'll see what you see. - -To make a new entry, click "New" (or type 'control + n') - -## From the Console - -Most of the time I want to show you some text, it's coming from my current -console session. We should make it really easy to take code from the console -and send it to people. - -`cat something | haste` # https://hastebin.com/1238193 - -You can even take this a step further, and cut out the last step of copying the -URL with: - -* osx: `cat something | haste | pbcopy` -* linux: `cat something | haste | xsel` -* windows: check out [WinHaste](https://github.com/ajryan/WinHaste) - -After running that, the STDOUT output of `cat something` will show up at a URL -which has been conveniently copied to your clipboard. - -That's all there is to that, and you can install it with `gem install haste` -right now. - * osx: you will need to have an up to date version of Xcode - * linux: you will need to have rubygems and ruby-devel installed - -## Duration - -Pastes will stay for 30 days from their last view. They may be removed earlier -and without notice. - -## Privacy - -While the contents of hastebin.com are not directly crawled by any search robot -that obeys "robots.txt", there should be no great expectation of privacy. Post -things at your own risk. Not responsible for any loss of data or removed -pastes. - -## Open Source - -Haste can easily be installed behind your network, and it's all open source! - -* [haste-client](https://github.com/seejohnrun/haste-client) -* [haste-server](https://github.com/seejohnrun/haste-server) - -## Author - -Code by John Crepezzi -Key Design by Brian Dawson diff --git a/config.js b/config.js index 4b33e28..bf70bf6 100644 --- a/config.js +++ b/config.js @@ -1,46 +1,14 @@ { - "host": "0.0.0.0", "port": 7777, - - "keyLength": 10, - - "maxLength": 400000, - + "keyLength": 5, + "keySpace": "abcdefghijklmnopqrstuvwxyz0123456789", "staticMaxAge": 86400, - - "recompressStaticAssets": true, - "logging": [ { "level": "verbose", "type": "Console", "colorize": true } - ], - - "keyGenerator": { - "type": "phonetic" - }, - - "rateLimits": { - "categories": { - "normal": { - "totalRequests": 500, - "every": 60000 - } - } - }, - - "storage": { - "type": "memcached", - "host": "127.0.0.1", - "port": 11211, - "expire": 2592000 - }, - - "documents": { - "about": "./about.md" - } - + ] } diff --git a/lib/document_handler.js b/lib/document_handler.js index 83eb141..934e684 100644 --- a/lib/document_handler.js +++ b/lib/document_handler.js @@ -1,119 +1,102 @@ -var winston = require('winston'); var Busboy = require('busboy'); +var Winston = require('winston'); -// For handling serving stored documents +// For handling serving stored documents. -var DocumentHandler = function(options) { - if (!options) { - options = {}; - } - this.keyLength = options.keyLength || DocumentHandler.defaultKeyLength; - this.maxLength = options.maxLength; // none by default +var DocumentHandler = function(options = {}) { this.store = options.store; this.keyGenerator = options.keyGenerator; }; -DocumentHandler.defaultKeyLength = 10; -// Handle retrieving a document -DocumentHandler.prototype.handleGet = function(key, response, skipExpire) { +// Handle retrieving a document. +DocumentHandler.prototype.handleGet = function(key, response) { this.store.get(key, function(ret) { if (ret) { - winston.verbose('retrieved document', { key: key }); - response.writeHead(200, { 'content-type': 'application/json' }); + Winston.verbose("Retrieved document.", { key: key }); + response.writeHead(200, { "content-type": "application/json" }); response.end(JSON.stringify({ data: ret, key: key })); } else { - winston.warn('document not found', { key: key }); - response.writeHead(404, { 'content-type': 'application/json' }); - response.end(JSON.stringify({ message: 'Document not found.' })); + Winston.warn("Document not found.", { key: key }); + response.writeHead(404, { "content-type": "application/json" }); + response.end(JSON.stringify({ message: "Document not found." })); } - }, skipExpire); + }); }; -// Handle retrieving the raw version of a document -DocumentHandler.prototype.handleRawGet = function(key, response, skipExpire) { +// Handle retrieving the raw version of a document. +DocumentHandler.prototype.handleRawGet = function(key, response) { this.store.get(key, function(ret) { if (ret) { - winston.verbose('retrieved raw document', { key: key }); - response.writeHead(200, { 'content-type': 'text/plain; charset=UTF-8' }); + Winston.verbose("Retrieved raw document.", { key: key }); + response.writeHead(200, { "content-type": "text/plain; charset=UTF-8" }); response.end(ret); } else { - winston.warn('raw document not found', { key: key }); - response.writeHead(404, { 'content-type': 'application/json' }); - response.end(JSON.stringify({ message: 'Document not found.' })); + Winston.warn("Raw document not found.", { key: key }); + response.writeHead(404, { "content-type": "application/json" }); + response.end(JSON.stringify({ message: "Document not found." })); } - }, skipExpire); + }); }; -// Handle adding a new Document +// Handle adding a new document. DocumentHandler.prototype.handlePost = function (request, response) { var _this = this; - var buffer = ''; + var buffer = ""; var cancelled = false; - // What to do when done + // If success... var onSuccess = function () { - // Check length - if (_this.maxLength && buffer.length > _this.maxLength) { - cancelled = true; - winston.warn('document >maxLength', { maxLength: _this.maxLength }); - response.writeHead(400, { 'content-type': 'application/json' }); - response.end( - JSON.stringify({ message: 'Document exceeds maximum length.' }) - ); - return; - } - // And then save if we should _this.chooseKey(function (key) { _this.store.set(key, buffer, function (res) { if (res) { - winston.verbose('added document', { key: key }); - response.writeHead(200, { 'content-type': 'application/json' }); + Winston.verbose("Added document.", { key: key }); + response.writeHead(200, { "content-type": "application/json" }); response.end(JSON.stringify({ key: key })); } else { - winston.verbose('error adding document'); - response.writeHead(500, { 'content-type': 'application/json' }); - response.end(JSON.stringify({ message: 'Error adding document.' })); + Winston.verbose("Error adding document"); + response.writeHead(500, { "content-type": "application/json" }); + response.end(JSON.stringify({ message: "Error adding document." })); } }); }); }; - // If we should, parse a form to grab the data - var ct = request.headers['content-type']; - if (ct && ct.split(';')[0] === 'multipart/form-data') { + // Parse form to grab the data. + var ct = request.headers["content-type"]; + if (ct && ct.split(";")[0] === "multipart/form-data") { var busboy = new Busboy({ headers: request.headers }); - busboy.on('field', function (fieldname, val) { - if (fieldname === 'data') { + busboy.on("field", function (fieldname, val) { + if (fieldname === "data") { buffer = val; } }); - busboy.on('finish', function () { + busboy.on("finish", function () { onSuccess(); }); request.pipe(busboy); - // Otherwise, use our own and just grab flat data from POST body + // Otherwise, use our own and just grab flat data from POST body. } else { - request.on('data', function (data) { + request.on("data", function (data) { buffer += data.toString(); }); - request.on('end', function () { + request.on("end", function () { if (cancelled) { return; } onSuccess(); }); - request.on('error', function (error) { - winston.error('connection error: ' + error.message); - response.writeHead(500, { 'content-type': 'application/json' }); - response.end(JSON.stringify({ message: 'Connection error.' })); + request.on("error", function (error) { + Winston.error("Connection error: " + error.message); + response.writeHead(500, { "content-type": "application/json" }); + response.end(JSON.stringify({ message: "Connection error." })); cancelled = true; }); } }; -// Keep choosing keys until one isn't taken +// Keep choosing keys until we find one that isn't taken. DocumentHandler.prototype.chooseKey = function(callback) { var key = this.acceptableKey(); var _this = this; @@ -123,11 +106,11 @@ DocumentHandler.prototype.chooseKey = function(callback) { } else { callback(key); } - }, true); // Don't bump expirations when key searching + }, true); // Don't bump expirations when key searching. }; DocumentHandler.prototype.acceptableKey = function() { - return this.keyGenerator.createKey(this.keyLength); + return this.keyGenerator.createKey(); }; module.exports = DocumentHandler; diff --git a/lib/document_store.js b/lib/document_store.js new file mode 100644 index 0000000..1c2e546 --- /dev/null +++ b/lib/document_store.js @@ -0,0 +1,47 @@ +var fs = require("fs"); +var crypto = require("crypto"); + +var FileDocumentStore = function() { + this.basePath = "/data"; + this.expire = null; +}; + +FileDocumentStore.md5 = function(str) { + var md5sum = crypto.createHash("md5"); + md5sum.update(str); + return md5sum.digest("hex"); +}; + +FileDocumentStore.prototype.set = function(key, data, callback) { + try { + var _this = this; + fs.mkdir(this.basePath, "700", function() { + var fn = _this.basePath + "/" + FileDocumentStore.md5(key); + fs.writeFile(fn, data, "utf8", function(err) { + if (err) { + callback(false); + } + else { + callback(true); + } + }); + }); + } catch(err) { + callback(false); + } +}; + +FileDocumentStore.prototype.get = function(key, callback) { + var _this = this; + var fn = _this.basePath + "/" + FileDocumentStore.md5(key); + fs.readFile(fn, "utf8", function(err, data) { + if (err) { + callback(false); + } + else { + callback(data); + } + }); +}; + +module.exports = FileDocumentStore; diff --git a/lib/document_stores/amazon-s3.js b/lib/document_stores/amazon-s3.js deleted file mode 100644 index 11dd85d..0000000 --- a/lib/document_stores/amazon-s3.js +++ /dev/null @@ -1,56 +0,0 @@ -/*global require,module,process*/ - -var AWS = require('aws-sdk'); -var winston = require('winston'); - -var AmazonS3DocumentStore = function(options) { - this.expire = options.expire; - this.bucket = options.bucket; - this.client = new AWS.S3({region: options.region}); -}; - -AmazonS3DocumentStore.prototype.get = function(key, callback, skipExpire) { - var _this = this; - - var req = { - Bucket: _this.bucket, - Key: key - }; - - _this.client.getObject(req, function(err, data) { - if(err) { - callback(false); - } - else { - callback(data.Body.toString('utf-8')); - if (_this.expire && !skipExpire) { - winston.warn('amazon s3 store cannot set expirations on keys'); - } - } - }); -} - -AmazonS3DocumentStore.prototype.set = function(key, data, callback, skipExpire) { - var _this = this; - - var req = { - Bucket: _this.bucket, - Key: key, - Body: data, - ContentType: 'text/plain' - }; - - _this.client.putObject(req, function(err, data) { - if (err) { - callback(false); - } - else { - callback(true); - if (_this.expire && !skipExpire) { - winston.warn('amazon s3 store cannot set expirations on keys'); - } - } - }); -} - -module.exports = AmazonS3DocumentStore; diff --git a/lib/document_stores/file.js b/lib/document_stores/file.js deleted file mode 100644 index 7fd5995..0000000 --- a/lib/document_stores/file.js +++ /dev/null @@ -1,63 +0,0 @@ -var fs = require('fs'); -var crypto = require('crypto'); - -var winston = require('winston'); - -// For storing in files -// options[type] = file -// options[path] - Where to store - -var FileDocumentStore = function(options) { - this.basePath = options.path || './data'; - this.expire = options.expire; -}; - -// Generate md5 of a string -FileDocumentStore.md5 = function(str) { - var md5sum = crypto.createHash('md5'); - md5sum.update(str); - return md5sum.digest('hex'); -}; - -// Save data in a file, key as md5 - since we don't know what we could -// be passed here -FileDocumentStore.prototype.set = function(key, data, callback, skipExpire) { - try { - var _this = this; - fs.mkdir(this.basePath, '700', function() { - var fn = _this.basePath + '/' + FileDocumentStore.md5(key); - fs.writeFile(fn, data, 'utf8', function(err) { - if (err) { - callback(false); - } - else { - callback(true); - if (_this.expire && !skipExpire) { - winston.warn('file store cannot set expirations on keys'); - } - } - }); - }); - } catch(err) { - callback(false); - } -}; - -// Get data from a file from key -FileDocumentStore.prototype.get = function(key, callback, skipExpire) { - var _this = this; - var fn = this.basePath + '/' + FileDocumentStore.md5(key); - fs.readFile(fn, 'utf8', function(err, data) { - if (err) { - callback(false); - } - else { - callback(data); - if (_this.expire && !skipExpire) { - winston.warn('file store cannot set expirations on keys'); - } - } - }); -}; - -module.exports = FileDocumentStore; diff --git a/lib/document_stores/memcached.js b/lib/document_stores/memcached.js deleted file mode 100644 index be10db6..0000000 --- a/lib/document_stores/memcached.js +++ /dev/null @@ -1,52 +0,0 @@ -const memcached = require('memcached'); -const winston = require('winston'); - -class MemcachedDocumentStore { - - // Create a new store with options - constructor(options) { - this.expire = options.expire; - - const host = options.host || '127.0.0.1'; - const port = options.port || 11211; - const url = `${host}:${port}`; - this.connect(url); - } - - // Create a connection - connect(url) { - this.client = new memcached(url); - - winston.info(`connecting to memcached on ${url}`); - - this.client.on('failure', function(error) { - winston.info('error connecting to memcached', {error}); - }); - } - - // Save file in a key - set(key, data, callback, skipExpire) { - this.client.set(key, data, skipExpire ? 0 : this.expire, (error) => { - callback(!error); - }); - } - - // Get a file from a key - get(key, callback, skipExpire) { - this.client.get(key, (error, data) => { - callback(error ? false : data); - - // Update the key so that the expiration is pushed forward - if (!skipExpire) { - this.set(key, data, (updateSucceeded) => { - if (!updateSucceeded) { - winston.error('failed to update expiration on GET', {key}); - } - }, skipExpire); - } - }); - } - -} - -module.exports = MemcachedDocumentStore; diff --git a/lib/document_stores/postgres.js b/lib/document_stores/postgres.js deleted file mode 100644 index dbb471c..0000000 --- a/lib/document_stores/postgres.js +++ /dev/null @@ -1,79 +0,0 @@ -/*global require,module,process*/ - -var postgres = require('pg'); -var winston = require('winston'); - -// create table entries (id serial primary key, key varchar(255) not null, value text not null, expiration int, unique(key)); - -// A postgres document store -var PostgresDocumentStore = function (options) { - this.expireJS = options.expire; - this.connectionUrl = process.env.DATABASE_URL || options.connectionUrl; -}; - -PostgresDocumentStore.prototype = { - - // Set a given key - set: function (key, data, callback, skipExpire) { - var now = Math.floor(new Date().getTime() / 1000); - var that = this; - this.safeConnect(function (err, client, done) { - if (err) { return callback(false); } - client.query('INSERT INTO entries (key, value, expiration) VALUES ($1, $2, $3)', [ - key, - data, - that.expireJS && !skipExpire ? that.expireJS + now : null - ], function (err) { - if (err) { - winston.error('error persisting value to postgres', { error: err }); - return callback(false); - } - callback(true); - done(); - }); - }); - }, - - // Get a given key's data - get: function (key, callback, skipExpire) { - var now = Math.floor(new Date().getTime() / 1000); - var that = this; - this.safeConnect(function (err, client, done) { - if (err) { return callback(false); } - client.query('SELECT id,value,expiration from entries where KEY = $1 and (expiration IS NULL or expiration > $2)', [key, now], function (err, result) { - if (err) { - winston.error('error retrieving value from postgres', { error: err }); - return callback(false); - } - callback(result.rows.length ? result.rows[0].value : false); - if (result.rows.length && that.expireJS && !skipExpire) { - client.query('UPDATE entries SET expiration = $1 WHERE ID = $2', [ - that.expireJS + now, - result.rows[0].id - ], function (err) { - if (!err) { - done(); - } - }); - } else { - done(); - } - }); - }); - }, - - // A connection wrapper - safeConnect: function (callback) { - postgres.connect(this.connectionUrl, function (err, client, done) { - if (err) { - winston.error('error connecting to postgres', { error: err }); - callback(err); - } else { - callback(undefined, client, done); - } - }); - } - -}; - -module.exports = PostgresDocumentStore; diff --git a/lib/document_stores/redis.js b/lib/document_stores/redis.js deleted file mode 100644 index eed07e7..0000000 --- a/lib/document_stores/redis.js +++ /dev/null @@ -1,89 +0,0 @@ -var redis = require('redis'); -var winston = require('winston'); - -// For storing in redis -// options[type] = redis -// options[host] - The host to connect to (default localhost) -// options[port] - The port to connect to (default 5379) -// options[db] - The db to use (default 0) -// options[expire] - The time to live for each key set (default never) - -var RedisDocumentStore = function(options, client) { - this.expire = options.expire; - if (client) { - winston.info('using predefined redis client'); - RedisDocumentStore.client = client; - } else if (!RedisDocumentStore.client) { - winston.info('configuring redis'); - RedisDocumentStore.connect(options); - } -}; - -// Create a connection according to config -RedisDocumentStore.connect = function(options) { - var host = options.host || '127.0.0.1'; - var port = options.port || 6379; - var index = options.db || 0; - RedisDocumentStore.client = redis.createClient(port, host); - // authenticate if password is provided - if (options.password) { - RedisDocumentStore.client.auth(options.password); - } - - RedisDocumentStore.client.on('error', function(err) { - winston.error('redis disconnected', err); - }); - - RedisDocumentStore.client.select(index, function(err) { - if (err) { - winston.error( - 'error connecting to redis index ' + index, - { error: err } - ); - process.exit(1); - } - else { - winston.info('connected to redis on ' + host + ':' + port + '/' + index); - } - }); -}; - -// Save file in a key -RedisDocumentStore.prototype.set = function(key, data, callback, skipExpire) { - var _this = this; - RedisDocumentStore.client.set(key, data, function(err) { - if (err) { - callback(false); - } - else { - if (!skipExpire) { - _this.setExpiration(key); - } - callback(true); - } - }); -}; - -// Expire a key in expire time if set -RedisDocumentStore.prototype.setExpiration = function(key) { - if (this.expire) { - RedisDocumentStore.client.expire(key, this.expire, function(err) { - if (err) { - winston.error('failed to set expiry on key: ' + key); - } - }); - } -}; - -// Get a file from a key -RedisDocumentStore.prototype.get = function(key, callback, skipExpire) { - var _this = this; - RedisDocumentStore.client.get(key, function(err, reply) { - if (!err && !skipExpire) { - _this.setExpiration(key); - } - callback(err ? false : reply); - }); -}; - -module.exports = RedisDocumentStore; diff --git a/lib/document_stores/rethinkdb.js b/lib/document_stores/rethinkdb.js deleted file mode 100644 index ca825af..0000000 --- a/lib/document_stores/rethinkdb.js +++ /dev/null @@ -1,46 +0,0 @@ -const crypto = require('crypto'); -const rethink = require('rethinkdbdash'); -const winston = require('winston'); - -const md5 = (str) => { - const md5sum = crypto.createHash('md5'); - md5sum.update(str); - return md5sum.digest('hex'); -}; - -class RethinkDBStore { - constructor(options) { - this.client = rethink({ - silent: true, - host: options.host || '127.0.0.1', - port: options.port || 28015, - db: options.db || 'haste', - user: options.user || 'admin', - password: options.password || '' - }); - } - - set(key, data, callback) { - this.client.table('uploads').insert({ id: md5(key), data: data }).run((error) => { - if (error) { - callback(false); - winston.error('failed to insert to table', error); - return; - } - callback(true); - }); - } - - get(key, callback) { - this.client.table('uploads').get(md5(key)).run((error, result) => { - if (error || !result) { - callback(false); - if (error) winston.error('failed to insert to table', error); - return; - } - callback(result.data); - }); - } -} - -module.exports = RethinkDBStore; diff --git a/lib/key_generator.js b/lib/key_generator.js new file mode 100644 index 0000000..35640a8 --- /dev/null +++ b/lib/key_generator.js @@ -0,0 +1,19 @@ +module.exports = class KeyGenerator { + + // Initialise a new generator with the given key space. + constructor(options = {}) { + this.keyLength = options.keyLength; + this.keySpace = options.keySpace; + } + + // Generate a key of the given length. + createKey() { + var text = ""; + for (var i = 0; i < this.keyLength; i++) { + const index = Math.floor(Math.random() * this.keySpace.length); + text += this.keySpace.charAt(index); + } + return text; + } + +}; diff --git a/lib/key_generators/dictionary.js b/lib/key_generators/dictionary.js deleted file mode 100644 index 0bcbc2e..0000000 --- a/lib/key_generators/dictionary.js +++ /dev/null @@ -1,32 +0,0 @@ -const fs = require('fs'); - -module.exports = class DictionaryGenerator { - - constructor(options, readyCallback) { - // Check options format - if (!options) throw Error('No options passed to generator'); - if (!options.path) throw Error('No dictionary path specified in options'); - - // Load dictionary - fs.readFile(options.path, 'utf8', (err, data) => { - if (err) throw err; - - this.dictionary = data.split(/[\n\r]+/); - - if (readyCallback) readyCallback(); - }); - } - - // Generates a dictionary-based key, of keyLength words - createKey(keyLength) { - let text = ''; - - for (let i = 0; i < keyLength; i++) { - const index = Math.floor(Math.random() * this.dictionary.length); - text += this.dictionary[index]; - } - - return text; - } - -}; diff --git a/lib/key_generators/phonetic.js b/lib/key_generators/phonetic.js deleted file mode 100644 index f281f6b..0000000 --- a/lib/key_generators/phonetic.js +++ /dev/null @@ -1,27 +0,0 @@ -// Draws inspiration from pwgen and http://tools.arantius.com/password - -const randOf = (collection) => { - return () => { - return collection[Math.floor(Math.random() * collection.length)]; - }; -}; - -// Helper methods to get an random vowel or consonant -const randVowel = randOf('aeiou'); -const randConsonant = randOf('bcdfghjklmnpqrstvwxyz'); - -module.exports = class PhoneticKeyGenerator { - - // Generate a phonetic key of alternating consonant & vowel - createKey(keyLength) { - let text = ''; - const start = Math.round(Math.random()); - - for (let i = 0; i < keyLength; i++) { - text += (i % 2 == start) ? randConsonant() : randVowel(); - } - - return text; - } - -}; diff --git a/lib/key_generators/random.js b/lib/key_generators/random.js deleted file mode 100644 index 767e26b..0000000 --- a/lib/key_generators/random.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = class RandomKeyGenerator { - - // Initialize a new generator with the given keySpace - constructor(options = {}) { - this.keyspace = options.keyspace || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - } - - // Generate a key of the given length - createKey(keyLength) { - var text = ''; - - for (var i = 0; i < keyLength; i++) { - const index = Math.floor(Math.random() * this.keyspace.length); - text += this.keyspace.charAt(index); - } - - return text; - } - -}; diff --git a/package-lock.json b/package-lock.json index 14685ee..71af983 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "haste", + "name": "butlerbin", "version": "0.1.0", "lockfileVersion": 1, "requires": true, @@ -10,75 +10,43 @@ "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=" }, "async-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-cache/-/async-cache-1.0.0.tgz", - "integrity": "sha1-yH9tgMcrOU7g+QYe3rJNjEtiKto=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/async-cache/-/async-cache-1.1.0.tgz", + "integrity": "sha1-SppaidBl7F2OUlS9nulrp2xTK1o=", "requires": { - "lru-cache": "2.3.1" + "lru-cache": "^4.0.0" } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", - "integrity": "sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", "requires": { - "readable-stream": "2.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - } - } + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", - "dev": true - }, - "buffer-writer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.0.tgz", - "integrity": "sha1-bCnDst6gyeRVofJhoZmkigT4iwg=" - }, "busboy": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.4.tgz", - "integrity": "sha1-GXfpbh7ohGSWUevfVIypAHWLp/M=", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", + "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", "requires": { - "dicer": "0.2.3", - "readable-stream": "1.1.14" + "dicer": "0.3.0" } }, "colors": { @@ -86,248 +54,121 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "1.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, "connect": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.4.1.tgz", - "integrity": "sha1-ohNh0/QJnvdhzabcSpc7seuwo00=", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "requires": { - "debug": "2.2.0", - "finalhandler": "0.4.1", - "parseurl": "1.3.1", - "utils-merge": "1.0.0" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" } }, - "connect-ratelimit": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/connect-ratelimit/-/connect-ratelimit-0.0.7.tgz", - "integrity": "sha1-5uCclQZJ6ElJnKsYcKQVoH9zFWg=" - }, "connect-route": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/connect-route/-/connect-route-0.1.5.tgz", "integrity": "sha1-48IYMZ0uiKiprgsOD+Cacpw5dEo=" }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" }, "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { - "ms": "0.7.1" + "ms": "2.0.0" } }, "dicer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.3.tgz", - "integrity": "sha1-8AKBGJpVwjUe+ASQpP6fssWcSTk=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", + "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", "requires": { - "readable-stream": "1.1.14", "streamsearch": "0.1.2" } }, - "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", - "dev": true - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, "eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" }, "fd": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fd/-/fd-0.0.2.tgz", - "integrity": "sha1-4O2yvXqIzIbdnxY5HLqDJBj9h+4=" + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/fd/-/fd-0.0.3.tgz", + "integrity": "sha512-iAHrIslQb3U68OcMSP0kkNWabp7sSN6d2TBSb2JO3gcLJVDd4owr/hKM4SFJovFOUeeXeItjYgouEDTMWiVAnA==" }, "finalhandler": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.1.tgz", - "integrity": "sha1-haF8bFmpRxfSYtYSMNSw6+PUoU0=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "requires": { - "debug": "2.2.0", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "unpipe": "1.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "generic-pool": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.1.1.tgz", - "integrity": "sha1-rwTcLDJc/Ll1Aj+lK/zpYXp0Nf0=" - }, - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" } }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "optional": true }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "lru-cache": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.3.1.tgz", - "integrity": "sha1-s632s9hW6VTiw5DmzvIggSRaU9Y=" + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } }, "mime": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", - "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz", - "integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==", - "dev": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.2.0", - "diff": "3.2.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "he": "1.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - } + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" }, "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "on-finished": { "version": "2.3.0", @@ -337,95 +178,29 @@ "ee-first": "1.1.1" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "packet-reader": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.2.0.tgz", - "integrity": "sha1-gZ300BC4LV6lZx+KGjrPA5vNdwA=" - }, "parseurl": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", - "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "pg": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-4.1.1.tgz", - "integrity": "sha1-mEgKz8089qP5Yhyl1FiUFVgqVzI=", - "requires": { - "buffer-writer": "1.0.0", - "generic-pool": "2.1.1", - "packet-reader": "0.2.0", - "pg-connection-string": "0.1.3", - "pg-types": "1.6.0", - "pgpass": "0.0.3", - "semver": "4.3.6" - } - }, - "pg-connection-string": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", - "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" - }, - "pg-types": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.6.0.tgz", - "integrity": "sha1-OHKg8ZkUMCVJf07ipl/a8A1+qLM=" - }, - "pgpass": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-0.0.3.tgz", - "integrity": "sha1-EuZ+NDsxicLzEgbrycwL7//PkUA=", - "requires": { - "split": "0.3.3" - } + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "pkginfo": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", "integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg=" }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "redis": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/redis/-/redis-0.8.1.tgz", - "integrity": "sha1-FZ8hMFmaL3GeRLA/C0t2EvmS/LI=" - }, - "redis-url": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/redis-url/-/redis-url-0.1.0.tgz", - "integrity": "sha1-TaXlsYG2wMrW4aVcf1Co5u53ebs=", - "requires": { - "redis": "0.8.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "request": { @@ -433,35 +208,22 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.9.203.tgz", "integrity": "sha1-bBcRpUB/uUoRQhlWPkQUW8v0cjo=" }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "requires": { - "through": "2.3.8" - } + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "st": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/st/-/st-1.1.0.tgz", - "integrity": "sha1-c7ltsLdkTZp4zjg0o+T37G6Hz3Y=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/st/-/st-2.0.0.tgz", + "integrity": "sha512-drN+aGYnrZPNYIymmNwIY7LXYJ8MqsqXj4fMRue3FOgGMdGjSX10fhJ3qx0sVQPhcWxhEaN4U/eWM4O4dbYNAw==", "requires": { - "async-cache": "1.0.0", - "bl": "1.0.3", - "fd": "0.0.2", - "graceful-fs": "4.1.11", - "mime": "1.3.6", - "negotiator": "0.6.1" + "async-cache": "^1.1.0", + "bl": "^4.0.0", + "fd": "~0.0.2", + "graceful-fs": "^4.2.3", + "mime": "^2.4.4", + "negotiator": "~0.6.2" } }, "stack-trace": { @@ -469,44 +231,22 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "streamsearch": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "supports-color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, + "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": { - "has-flag": "1.0.0" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "uglify-js": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.6.tgz", - "integrity": "sha512-/rseyxEKEVMBo8279lqpoJgD6C/i/CIi+9TJDvWmb+Xo6mqMKwjA8Io3IMHlcXQzj99feR6zrN8m3wqqvm/nYA==", - "requires": { - "commander": "2.11.0", - "source-map": "0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" - } + "safe-buffer": "~5.2.0" } }, "unpipe": { @@ -520,29 +260,28 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "winston": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/winston/-/winston-0.6.2.tgz", "integrity": "sha1-QUT+JYbNwZphK/jANVkBMskGS9I=", "requires": { - "async": "0.1.22", - "colors": "0.6.2", - "cycle": "1.0.3", - "eyes": "0.1.8", - "pkginfo": "0.2.3", - "request": "2.9.203", - "stack-trace": "0.0.10" + "async": "0.1.x", + "colors": "0.x.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "pkginfo": "0.2.x", + "request": "2.9.x", + "stack-trace": "0.0.x" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 9453b1e..9e7ae2d 100644 --- a/package.json +++ b/package.json @@ -1,37 +1,29 @@ { - "name": "haste", + "name": "butlerbin", "version": "0.1.0", "private": true, - "description": "Private Pastebin Server", + "description": "Butlersaurus Pastebin", "keywords": [ "paste", "pastebin" ], "author": { - "name": "John Crepezzi", - "email": "john.crepezzi@gmail.com", - "url": "http://seejohncode.com/" + "name": "Butlersaurus", + "url": "https://butlersaur.us/", + "credits": "Orignal source courtesy of John Crepezzi, Hastebin developer. https://seejohncode.com/" }, - "main": "haste", + "main": "butlerbin", "dependencies": { - "connect-ratelimit": "0.0.7", "connect-route": "0.1.5", - "connect": "3.4.1", - "st": "1.1.0", + "connect": "3.7.0", + "st": "2.0.0", "winston": "0.6.2", - "redis-url": "0.1.0", - "redis": "0.8.1", - "uglify-js": "3.1.6", - "busboy": "0.2.4", - "pg": "4.1.1" - }, - "devDependencies": { - "mocha": "^4.0.1" + "busboy": "0.3.1" }, "bundledDependencies": [], "engines": { - "node": "8.1.4", - "npm": "5.2.0" + "node": "14.4.0", + "npm": "6.14.5" }, "bin": { "haste-server": "./server.js" @@ -45,7 +37,6 @@ "lib": "./lib" }, "scripts": { - "start": "node server.js", - "test": "mocha --recursive" + "start": "node server.js" } } diff --git a/server.js b/server.js index 57bd3da..5d815f3 100644 --- a/server.js +++ b/server.js @@ -1,155 +1,91 @@ -var http = require('http'); -var fs = require('fs'); +var Connect = require("connect"); +var ConnectSt = require("st"); +var Fs = require("fs"); +var Http = require("http"); +var Route = require("connect-route"); +var Winston = require("winston"); -var uglify = require('uglify-js'); -var winston = require('winston'); -var connect = require('connect'); -var route = require('connect-route'); -var connect_st = require('st'); -var connect_rate_limit = require('connect-ratelimit'); +var DocumentHandler = require("./lib/document_handler"); +var KeyGenerator = require("./lib/key_generator"); +var Store = require("./lib/document_store"); -var DocumentHandler = require('./lib/document_handler'); +// Load the configuration and set some defaults. +var config = JSON.parse(Fs.readFileSync("./config.js", "utf8")); +config.host = config.host || "127.0.0.1"; +config.port = config.port || 7777; -// Load the configuration and set some defaults -var config = JSON.parse(fs.readFileSync('./config.js', 'utf8')); -config.port = process.env.PORT || config.port || 7777; -config.host = process.env.HOST || config.host || 'localhost'; - -// Set up the logger +// Set up the logger. if (config.logging) { try { - winston.remove(winston.transports.Console); + Winston.remove(Winston.transports.Console); } catch(e) { - /* was not present */ + // This is fine. } - var detail, type; for (var i = 0; i < config.logging.length; i++) { detail = config.logging[i]; type = detail.type; delete detail.type; - winston.add(winston.transports[type], detail); + Winston.add(Winston.transports[type], detail); } } -// build the store from the config on-demand - so that we don't load it -// for statics -if (!config.storage) { - config.storage = { type: 'file' }; -} -if (!config.storage.type) { - config.storage.type = 'file'; -} +// Configure the data store. +store = new Store(); -var Store, preferredStore; +// Pick up a key generator. +var keyGenerator = new KeyGenerator({ + keyLength: config.keyLength, + keySpace: config.keySpace +}); -if (process.env.REDISTOGO_URL && config.storage.type === 'redis') { - var redisClient = require('redis-url').connect(process.env.REDISTOGO_URL); - Store = require('./lib/document_stores/redis'); - preferredStore = new Store(config.storage, redisClient); -} -else { - Store = require('./lib/document_stores/' + config.storage.type); - preferredStore = new Store(config.storage); -} - -// Compress the static javascript assets -if (config.recompressStaticAssets) { - var list = fs.readdirSync('./static'); - for (var j = 0; j < list.length; j++) { - var item = list[j]; - if ((item.indexOf('.js') === item.length - 3) && (item.indexOf('.min.js') === -1)) { - var dest = item.substring(0, item.length - 3) + '.min' + item.substring(item.length - 3); - var orig_code = fs.readFileSync('./static/' + item, 'utf8'); - - fs.writeFileSync('./static/' + dest, uglify.minify(orig_code).code, 'utf8'); - winston.info('compressed ' + item + ' into ' + dest); - } - } -} - -// Send the static documents into the preferred store, skipping expirations -var path, data; -for (var name in config.documents) { - path = config.documents[name]; - data = fs.readFileSync(path, 'utf8'); - winston.info('loading static document', { name: name, path: path }); - if (data) { - preferredStore.set(name, data, function(cb) { - winston.debug('loaded static document', { success: cb }); - }, true); - } - else { - winston.warn('failed to load static document', { name: name, path: path }); - } -} - -// Pick up a key generator -var pwOptions = config.keyGenerator || {}; -pwOptions.type = pwOptions.type || 'random'; -var gen = require('./lib/key_generators/' + pwOptions.type); -var keyGenerator = new gen(pwOptions); - -// Configure the document handler +// Configure the document handler. var documentHandler = new DocumentHandler({ - store: preferredStore, - maxLength: config.maxLength, + store: store, keyLength: config.keyLength, keyGenerator: keyGenerator }); -var app = connect(); +var app = Connect(); -// Rate limit all requests -if (config.rateLimits) { - config.rateLimits.end = true; - app.use(connect_rate_limit(config.rateLimits)); -} - -// first look at API calls -app.use(route(function(router) { - // get raw documents - support getting with extension - router.get('/raw/:id', function(request, response) { - var key = request.params.id.split('.')[0]; - var skipExpire = !!config.documents[key]; - return documentHandler.handleRawGet(key, response, skipExpire); +// Configure the API routes. +app.use(Route(function(router) { + router.get("/raw/:id", function(request, response) { + var key = request.params.id.split(".")[0]; + return documentHandler.handleRawGet(key, response); }); - // add documents - router.post('/documents', function(request, response) { + router.post("/documents", function(request, response) { return documentHandler.handlePost(request, response); }); - // get documents - router.get('/documents/:id', function(request, response) { - var key = request.params.id.split('.')[0]; - var skipExpire = !!config.documents[key]; - return documentHandler.handleGet(key, response, skipExpire); + router.get("/documents/:id", function(request, response) { + var key = request.params.id.split(".")[0]; + return documentHandler.handleGet(key, response); }); })); -// Otherwise, try to match static files -app.use(connect_st({ - path: __dirname + '/static', +// Route static files. +app.use(ConnectSt({ + path: __dirname + "/static", content: { maxAge: config.staticMaxAge }, passthrough: true, index: false })); -// Then we can loop back - and everything else should be a token, -// so route it back to / -app.use(route(function(router) { - router.get('/:id', function(request, response, next) { - request.sturl = '/'; +// All the pastebin IDs. +app.use(Route(function(router) { + router.get("/:id", function(request, response, next) { + request.sturl = "/"; next(); }); })); -// And match index -app.use(connect_st({ - path: __dirname + '/static', +// Route index.html. +app.use(ConnectSt({ + path: __dirname + "/static", content: { maxAge: config.staticMaxAge }, - index: 'index.html' + index: "index.html" })); -http.createServer(app).listen(config.port, config.host); +Http.createServer(app).listen(config.port, config.host); -winston.info('listening on ' + config.host + ':' + config.port); +Winston.info("Listening on " + config.host + ":" + config.port); diff --git a/test/document_handler_spec.js b/test/document_handler_spec.js deleted file mode 100644 index f84f066..0000000 --- a/test/document_handler_spec.js +++ /dev/null @@ -1,26 +0,0 @@ -/* global describe, it */ - -var assert = require('assert'); - -var DocumentHandler = require('../lib/document_handler'); -var Generator = require('../lib/key_generators/random'); - -describe('document_handler', function() { - - describe('randomKey', function() { - - it('should choose a key of the proper length', function() { - var gen = new Generator(); - var dh = new DocumentHandler({ keyLength: 6, keyGenerator: gen }); - assert.equal(6, dh.acceptableKey().length); - }); - - it('should choose a default key length', function() { - var gen = new Generator(); - var dh = new DocumentHandler({ keyGenerator: gen }); - assert.equal(dh.keyLength, DocumentHandler.defaultKeyLength); - }); - - }); - -}); diff --git a/test/key_generators/dictionary_spec.js b/test/key_generators/dictionary_spec.js deleted file mode 100644 index 72718c7..0000000 --- a/test/key_generators/dictionary_spec.js +++ /dev/null @@ -1,33 +0,0 @@ -/* global describe, it */ - -const assert = require('assert'); - -const fs = require('fs'); - -const Generator = require('../../lib/key_generators/dictionary'); - -describe('RandomKeyGenerator', function() { - describe('randomKey', function() { - it('should throw an error if given no options', () => { - assert.throws(() => { - new Generator(); - }, Error); - }); - - it('should throw an error if given no path', () => { - assert.throws(() => { - new Generator({}); - }, Error); - }); - - it('should return a key of the proper number of words from the given dictionary', () => { - const path = '/tmp/haste-server-test-dictionary'; - const words = ['cat']; - fs.writeFileSync(path, words.join('\n')); - - const gen = new Generator({path}, () => { - assert.equal('catcatcat', gen.createKey(3)); - }); - }); - }); -}); diff --git a/test/key_generators/phonetic_spec.js b/test/key_generators/phonetic_spec.js deleted file mode 100644 index 14ad9e8..0000000 --- a/test/key_generators/phonetic_spec.js +++ /dev/null @@ -1,27 +0,0 @@ -/* global describe, it */ - -const assert = require('assert'); - -const Generator = require('../../lib/key_generators/phonetic'); - -const vowels = 'aeiou'; -const consonants = 'bcdfghjklmnpqrstvwxyz'; - -describe('RandomKeyGenerator', () => { - describe('randomKey', () => { - it('should return a key of the proper length', () => { - const gen = new Generator(); - assert.equal(6, gen.createKey(6).length); - }); - - it('should alternate consonants and vowels', () => { - const gen = new Generator(); - - const key = gen.createKey(3); - - assert.ok(consonants.includes(key[0])); - assert.ok(consonants.includes(key[2])); - assert.ok(vowels.includes(key[1])); - }); - }); -}); diff --git a/test/key_generators/random_spec.js b/test/key_generators/random_spec.js deleted file mode 100644 index 537a809..0000000 --- a/test/key_generators/random_spec.js +++ /dev/null @@ -1,19 +0,0 @@ -/* global describe, it */ - -const assert = require('assert'); - -const Generator = require('../../lib/key_generators/random'); - -describe('RandomKeyGenerator', () => { - describe('randomKey', () => { - it('should return a key of the proper length', () => { - const gen = new Generator(); - assert.equal(6, gen.createKey(6).length); - }); - - it('should use a key from the given keyset if given', () => { - const gen = new Generator({keyspace: 'A'}); - assert.equal('AAAAAA', gen.createKey(6)); - }); - }); -}); diff --git a/test/redis_document_store_spec.js b/test/redis_document_store_spec.js deleted file mode 100644 index 873c296..0000000 --- a/test/redis_document_store_spec.js +++ /dev/null @@ -1,54 +0,0 @@ -/* global it, describe, afterEach */ - -var assert = require('assert'); - -var winston = require('winston'); -winston.remove(winston.transports.Console); - -var RedisDocumentStore = require('../lib/document_stores/redis'); - -describe('redis_document_store', function() { - - /* reconnect to redis on each test */ - afterEach(function() { - if (RedisDocumentStore.client) { - RedisDocumentStore.client.quit(); - RedisDocumentStore.client = false; - } - }); - - describe('set', function() { - - it('should be able to set a key and have an expiration set', function(done) { - var store = new RedisDocumentStore({ expire: 10 }); - store.set('hello1', 'world', function() { - RedisDocumentStore.client.ttl('hello1', function(err, res) { - assert.ok(res > 1); - done(); - }); - }); - }); - - it('should not set an expiration when told not to', function(done) { - var store = new RedisDocumentStore({ expire: 10 }); - store.set('hello2', 'world', function() { - RedisDocumentStore.client.ttl('hello2', function(err, res) { - assert.equal(-1, res); - done(); - }); - }, true); - }); - - it('should not set an expiration when expiration is off', function(done) { - var store = new RedisDocumentStore({ expire: false }); - store.set('hello3', 'world', function() { - RedisDocumentStore.client.ttl('hello3', function(err, res) { - assert.equal(-1, res); - done(); - }); - }); - }); - - }); - -});