1
0
Fork 0
mirror of https://github.com/SunRed/haste-server.git synced 2024-12-27 06:30:11 +01:00

Huge refactor, switched to express

This commit is contained in:
zneix 2020-08-26 04:54:58 +02:00
parent 06315a91a8
commit c585e3b815
22 changed files with 813 additions and 406 deletions

7
.gitignore vendored
View file

@ -2,8 +2,9 @@ node_modules
.vscode
data
npm-debug.log
*.swp
*.swo
*.DS_Store
*.DS_Store
npm-debug.log
static/application.min.js

View file

@ -22,7 +22,7 @@ STDOUT. Check the README there for more details and usages.
## Tested Browsers
* Firefox 8
* Firefox 81
* Chrome 17
* Safari 5.3
@ -41,7 +41,7 @@ STDOUT. Check the README there for more details and usages.
* `maxLength` - maximum length of a paste (default 400000)
* `staticMaxAge` - max age for static assets (86400)
* `recompressStaticAssets` - whether or not to compile static js assets (true)
* `documents` - static documents to serve (ex: http://hastebin.com/about.com)
* `documents` - static documents to serve (ex: http://hastebin.com/about.md)
in addition to static assets. These will never expire.
* `storage` - storage options (see below)
* `logging` - logging preferences
@ -51,10 +51,10 @@ STDOUT. Check the README there for more details and usages.
## Rate Limiting
When present, the `rateLimits` option enables built-in rate limiting courtesy
of `connect-ratelimit`. Any of the options supported by that library can be
used and set in `config.json`.
of `express-rate-limit`. Any of the options supported by that library can be
used and set in `config.js`.
See the README for [connect-ratelimit](https://github.com/dharmafly/connect-ratelimit)
See the README for [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)
for more information!
## Key Generation
@ -92,8 +92,8 @@ something like:
``` json
{
"path": "./data",
"type": "file"
"type": "file",
"path": "./data"
}
```

View file

@ -53,9 +53,10 @@ pastes.
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)
* [haste-server](https://github.com/zneix/haste-server)
## Author
Code by John Crepezzi <john.crepezzi@gmail.com>
Original Code by John Crepezzi <john.crepezzi@gmail.com>
Continued by zneix <zzneix@gmail.com>
Key Design by Brian Dawson <bridawson@gmail.com>

31
config.js Normal file
View file

@ -0,0 +1,31 @@
module.exports = {
"host": "127.0.0.1",
"port": 4200,
"keyLength": 10,
"maxLength": 400000,
"staticMaxAge": 60 * 60 * 24,
"recompressStaticAssets": true,
"logging": [], //re-add this feature later
"keyGenerator": {
"type": "phonetic"
},
"rateLimits": {
"windowMs": 60 * 60 * 1000,
"max": 500
},
"storage": {
"type": "file",
"path": "./data"
},
"documents": {
"about": "./about.md"
}
}

View file

@ -1,44 +0,0 @@
{
"host": "127.0.0.1",
"port": 7777,
"keyLength": 10,
"maxLength": 400000,
"staticMaxAge": 86400,
"recompressStaticAssets": true,
"logging": [
{
"level": "verbose",
"type": "Console",
"colorize": true
}
],
"keyGenerator": {
"type": "phonetic"
},
"rateLimits": {
"categories": {
"normal": {
"totalRequests": 500,
"every": 60000
}
}
},
"storage": {
"type": "file",
"path": "./data"
},
"documents": {
"about": "./about.md"
}
}

View file

@ -1,12 +1,10 @@
var winston = require('winston');
var Busboy = require('busboy');
const winston = require('winston');
const Busboy = require('busboy');
// For handling serving stored documents
var DocumentHandler = function(options) {
if (!options) {
options = {};
}
const DocumentHandler = function(options) {
if (!options) options = new Object;
this.keyLength = options.keyLength || DocumentHandler.defaultKeyLength;
this.maxLength = options.maxLength; // none by default
this.store = options.store;
@ -16,98 +14,98 @@ var DocumentHandler = function(options) {
DocumentHandler.defaultKeyLength = 10;
// Handle retrieving a document
DocumentHandler.prototype.handleGet = function(key, response, skipExpire) {
DocumentHandler.prototype.handleGet = function(key, res, skipExpire) {
this.store.get(key, function(ret) {
if (ret) {
winston.verbose('retrieved document', { key: key });
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify({ data: ret, key: key }));
res.writeHead(200, { 'content-type': 'application/json' });
res.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.' }));
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ message: 'Document not found.' }));
}
}, skipExpire);
};
// Handle retrieving the raw version of a document
DocumentHandler.prototype.handleRawGet = function(key, response, skipExpire) {
DocumentHandler.prototype.handleGetRaw = function(key, res, skipExpire) {
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' });
response.end(ret);
res.writeHead(200, { 'content-type': 'text/plain; charset=UTF-8' });
res.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.' }));
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ message: 'Document not found.' }));
}
}, skipExpire);
};
// Handle adding a new Document
DocumentHandler.prototype.handlePost = function (request, response) {
var _this = this;
var buffer = '';
var cancelled = false;
DocumentHandler.prototype.handlePost = function (req, res) {
let _this = this;
let buffer = '';
let cancelled = false;
// What to do when done
var onSuccess = function () {
let 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(
res.writeHead(400, { 'content-type': 'application/json' });
res.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) {
_this.store.set(key, buffer, function (resp) {
if (resp) {
winston.verbose('added document', { key: key });
response.writeHead(200, { 'content-type': 'application/json' });
response.end(JSON.stringify({ key: key }));
res.writeHead(200, { 'content-type': 'application/json' });
res.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.' }));
res.writeHead(500, { 'content-type': 'application/json' });
res.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') {
var busboy = new Busboy({ headers: request.headers });
let ct = req.headers['content-type'];
if (ct && ct.split(';')[0] == 'multipart/form-data') {
let busboy = new Busboy({ headers: req.headers });
busboy.on('field', function (fieldname, val) {
if (fieldname === 'data') {
if (fieldname == 'data') {
buffer = val;
}
});
busboy.on('finish', function () {
onSuccess();
});
request.pipe(busboy);
req.pipe(busboy);
// Otherwise, use our own and just grab flat data from POST body
} else {
request.on('data', function (data) {
req.on('data', function (data) {
buffer += data.toString();
});
request.on('end', function () {
req.on('end', function () {
if (cancelled) { return; }
onSuccess();
});
request.on('error', function (error) {
req.on('error', function (error) {
winston.error('connection error: ' + error.message);
response.writeHead(500, { 'content-type': 'application/json' });
response.end(JSON.stringify({ message: 'Connection error.' }));
res.writeHead(500, { 'content-type': 'application/json' });
res.end(JSON.stringify({ message: 'Connection error.' }));
cancelled = true;
});
}
@ -115,8 +113,8 @@ DocumentHandler.prototype.handlePost = function (request, response) {
// Keep choosing keys until one isn't taken
DocumentHandler.prototype.chooseKey = function(callback) {
var key = this.acceptableKey();
var _this = this;
let key = this.acceptableKey();
let _this = this;
this.store.get(key, function(ret) {
if (ret) {
_this.chooseKey(callback);

View file

@ -1,18 +1,18 @@
/*global require,module,process*/
var AWS = require('aws-sdk');
var winston = require('winston');
const AWS = require('aws-sdk');
const winston = require('winston');
var AmazonS3DocumentStore = function(options) {
const 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;
const _this = this;
var req = {
const req = {
Bucket: _this.bucket,
Key: key
};
@ -31,9 +31,9 @@ AmazonS3DocumentStore.prototype.get = function(key, callback, skipExpire) {
}
AmazonS3DocumentStore.prototype.set = function(key, data, callback, skipExpire) {
var _this = this;
const _this = this;
var req = {
const req = {
Bucket: _this.bucket,
Key: key,
Body: data,

View file

@ -1,20 +1,20 @@
var fs = require('fs');
var crypto = require('crypto');
const fs = require('fs');
const crypto = require('crypto');
var winston = require('winston');
const winston = require('winston');
// For storing in files
// options[type] = file
// options[path] - Where to store
var FileDocumentStore = function(options) {
const 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');
let md5sum = crypto.createHash('md5');
md5sum.update(str);
return md5sum.digest('hex');
};
@ -23,9 +23,9 @@ FileDocumentStore.md5 = function(str) {
// be passed here
FileDocumentStore.prototype.set = function(key, data, callback, skipExpire) {
try {
var _this = this;
const _this = this;
fs.mkdir(this.basePath, '700', function() {
var fn = _this.basePath + '/' + FileDocumentStore.md5(key);
const fn = _this.basePath + '/' + FileDocumentStore.md5(key);
fs.writeFile(fn, data, 'utf8', function(err) {
if (err) {
callback(false);
@ -45,8 +45,8 @@ FileDocumentStore.prototype.set = function(key, data, callback, skipExpire) {
// Get data from a file from key
FileDocumentStore.prototype.get = function(key, callback, skipExpire) {
var _this = this;
var fn = this.basePath + '/' + FileDocumentStore.md5(key);
const _this = this;
const fn = this.basePath + '/' + FileDocumentStore.md5(key);
fs.readFile(fn, 'utf8', function(err, data) {
if (err) {
callback(false);

View file

@ -1,12 +1,12 @@
/*global require,module,process*/
var postgres = require('pg');
var winston = require('winston');
const postgres = require('pg');
const 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) {
const PostgresDocumentStore = function (options) {
this.expireJS = options.expire;
this.connectionUrl = process.env.DATABASE_URL || options.connectionUrl;
};
@ -15,8 +15,8 @@ PostgresDocumentStore.prototype = {
// Set a given key
set: function (key, data, callback, skipExpire) {
var now = Math.floor(new Date().getTime() / 1000);
var that = this;
const now = Math.floor(Date.now() / 1000);
const 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)', [
@ -36,8 +36,8 @@ PostgresDocumentStore.prototype = {
// Get a given key's data
get: function (key, callback, skipExpire) {
var now = Math.floor(new Date().getTime() / 1000);
var that = this;
const now = Math.floor(Date.now() / 1000);
const 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) {

View file

@ -1,5 +1,5 @@
var redis = require('redis');
var winston = require('winston');
const redis = require('redis');
const winston = require('winston');
// For storing in redis
// options[type] = redis

View file

@ -4,7 +4,7 @@ module.exports = class DictionaryGenerator {
constructor(options, readyCallback) {
// Check options format
if (!options) throw Error('No options passed to generator');
if (!options) throw Error('No options passed to generator');
if (!options.path) throw Error('No dictionary path specified in options');
// Load dictionary

View file

@ -15,7 +15,7 @@ module.exports = class PhoneticKeyGenerator {
// Generate a phonetic key of alternating consonant & vowel
createKey(keyLength) {
let text = '';
const start = Math.round(Math.random());
const start = Math.floor(Math.random() * 2);
for (let i = 0; i < keyLength; i++) {
text += (i % 2 == start) ? randConsonant() : randVowel();

View file

@ -7,9 +7,9 @@ module.exports = class RandomKeyGenerator {
// Generate a key of the given length
createKey(keyLength) {
var text = '';
let text = '';
for (var i = 0; i < keyLength; i++) {
for (let i = 0; i < keyLength; i++) {
const index = Math.floor(Math.random() * this.keyspace.length);
text += this.keyspace.charAt(index);
}

13
lib/util.js Normal file
View file

@ -0,0 +1,13 @@
module.exports = class HasteUtils {
//init class
constructor(options = {}){
//xd no options for now
}
//stringify json objects from winston message to cool "key=value" format
stringifyJSONMessagetoLogs(info){
//really KKona solution, but works for now
let keys = Object.keys(info).filter(k => k != 'message' && k != 'level');
return keys.map(k => `${k}=${info[k]}`).join(', ');
}
}

614
package-lock.json generated
View file

@ -4,12 +4,31 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@dabh/diagnostics": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz",
"integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==",
"requires": {
"colorspace": "1.1.x",
"enabled": "2.0.x",
"kuler": "^2.0.0"
}
},
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@ -51,6 +70,11 @@
"sprintf-js": "~1.0.2"
}
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"array.prototype.map": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz",
@ -64,9 +88,9 @@
}
},
"async": {
"version": "0.1.22",
"resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz",
"integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE="
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"async-cache": {
"version": "1.1.0",
@ -107,27 +131,26 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.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"
}
}
}
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -175,6 +198,11 @@
"dicer": "0.3.0"
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@ -246,6 +274,30 @@
}
}
},
"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"
},
"dependencies": {
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -258,13 +310,30 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"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"
}
},
"colors": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
"integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w="
"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"
}
},
"concat-map": {
"version": "0.0.1",
@ -272,31 +341,40 @@
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"connect": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
"integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"requires": {
"debug": "2.6.9",
"finalhandler": "1.1.2",
"parseurl": "~1.3.3",
"utils-merge": "1.0.1"
"safe-buffer": "5.1.2"
},
"dependencies": {
"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=="
}
}
},
"connect-ratelimit": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/connect-ratelimit/-/connect-ratelimit-0.0.7.tgz",
"integrity": "sha1-5uCclQZJ6ElJnKsYcKQVoH9zFWg="
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"connect-route": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/connect-route/-/connect-route-0.1.5.tgz",
"integrity": "sha1-48IYMZ0uiKiprgsOD+Cacpw5dEo="
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cycle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
"integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"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="
},
"debug": {
"version": "2.6.9",
@ -326,6 +404,16 @@
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dicer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz",
@ -351,6 +439,11 @@
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"enabled": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@ -432,16 +525,75 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"eyes": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"dependencies": {
"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=="
}
}
},
"express-rate-limit": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz",
"integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA=="
},
"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=="
},
"fd": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/fd/-/fd-0.0.3.tgz",
"integrity": "sha512-iAHrIslQb3U68OcMSP0kkNWabp7sSN6d2TBSb2JO3gcLJVDd4owr/hKM4SFJovFOUeeXeItjYgouEDTMWiVAnA=="
},
"fecha": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz",
"integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@ -484,6 +636,21 @@
"is-buffer": "~2.0.3"
}
},
"fn.name": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -571,6 +738,26 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
@ -589,8 +776,12 @@
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"is-arguments": {
"version": "1.0.4",
@ -598,6 +789,11 @@
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
"dev": true
},
"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-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@ -679,6 +875,11 @@
"integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==",
"dev": true
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw=="
},
"is-string": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
@ -694,6 +895,11 @@
"has-symbols": "^1.0.1"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -726,6 +932,11 @@
"esprima": "^4.0.0"
}
},
"kuler": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
},
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@ -744,6 +955,25 @@
"chalk": "^4.0.0"
}
},
"logform": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz",
"integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==",
"requires": {
"colors": "^1.2.1",
"fast-safe-stringify": "^2.0.4",
"fecha": "^4.2.0",
"ms": "^2.1.1",
"triple-beam": "^1.3.0"
},
"dependencies": {
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@ -753,10 +983,38 @@
"yallist": "^2.1.2"
}
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
"integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA=="
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"requires": {
"mime-db": "1.44.0"
}
},
"minimatch": {
"version": "3.0.4",
@ -874,6 +1132,14 @@
"wrappy": "1"
}
},
"one-time": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
"requires": {
"fn.name": "1.x.x"
}
},
"p-limit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz",
@ -920,6 +1186,11 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"pg": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.3.2.tgz",
@ -981,11 +1252,6 @@
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"dev": true
},
"pkginfo": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz",
"integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg="
},
"postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
@ -1009,6 +1275,11 @@
"xtend": "^4.0.0"
}
},
"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=="
},
"promise.allsettled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz",
@ -1022,11 +1293,25 @@
"iterate-value": "^1.0.0"
}
},
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
}
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -1036,6 +1321,32 @@
"safe-buffer": "^5.1.0"
}
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"readdirp": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
@ -1082,11 +1393,6 @@
"redis": ">= 0.0.1"
}
},
"request": {
"version": "2.9.203",
"resolved": "https://registry.npmjs.org/request/-/request-2.9.203.tgz",
"integrity": "sha1-bBcRpUB/uUoRQhlWPkQUW8v0cjo="
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -1104,11 +1410,43 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
"integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c="
},
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
@ -1118,16 +1456,35 @@
"randombytes": "^2.1.0"
}
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
}
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"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"
}
},
"split": {
"version": "1.0.1",
@ -1154,6 +1511,13 @@
"graceful-fs": "^4.2.3",
"mime": "^2.4.4",
"negotiator": "~0.6.2"
},
"dependencies": {
"mime": {
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
"integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA=="
}
}
},
"stack-trace": {
@ -1201,6 +1565,14 @@
"es-abstract": "^1.17.5"
}
},
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
@ -1225,6 +1597,11 @@
"has-flag": "^4.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=="
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@ -1239,22 +1616,30 @@
"is-number": "^7.0.0"
}
},
"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==",
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"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=="
}
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"uglify-js": {
"version": "3.10.2",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.2.tgz",
"integrity": "sha512-GXCYNwqoo0MbLARghYjxVBxDCnU0tLqN7IPLdHHbibCb1NI5zBkU2EPcy/GaVxc0BtTjqyGXJCINe6JMR2Dpow=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -1270,6 +1655,11 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -1295,17 +1685,57 @@
}
},
"winston": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/winston/-/winston-0.6.2.tgz",
"integrity": "sha1-QUT+JYbNwZphK/jANVkBMskGS9I=",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
"integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==",
"requires": {
"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"
"@dabh/diagnostics": "^2.0.2",
"async": "^3.1.0",
"is-stream": "^2.0.0",
"logform": "^2.2.0",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.4.0"
}
},
"winston-transport": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz",
"integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==",
"requires": {
"readable-stream": "^2.3.7",
"triple-beam": "^1.2.0"
},
"dependencies": {
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"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"
}
}
}
},
"workerpool": {

View file

@ -1,47 +1,46 @@
{
"name": "haste",
"version": "0.1.0",
"private": false,
"description": "Private Pastebin Server - continued by zneix",
"keywords": [
"paste",
"pastebin"
],
"author": {
"name": "John Crepezzi",
"email": "john.crepezzi@gmail.com",
"url": "http://seejohncode.com/"
},
"main": "server.js",
"dependencies": {
"busboy": "^0.3.1",
"connect": "^3.7.0",
"connect-ratelimit": "0.0.7",
"connect-route": "0.1.5",
"pg": "^8.3.2",
"redis": "^3.0.2",
"redis-url": "^1.2.1",
"st": "^2.0.0",
"uglify-js": "3.1.6",
"winston": "^0.6.2"
},
"devDependencies": {
"mocha": "^8.1.2"
},
"bundledDependencies": [],
"bin": {
"haste-server": "./server.js"
},
"files": [
"server.js",
"lib",
"static"
],
"directories": {
"lib": "./lib"
},
"scripts": {
"start": "node server.js",
"test": "mocha --recursive"
}
"name": "haste",
"version": "0.2.0",
"description": "Private Pastebin Server - continued by zneix",
"keywords": [
"paste",
"pastebin",
"haste",
"hastebin"
],
"author": {
"name": "John Crepezzi",
"email": "john.crepezzi@gmail.com",
"url": "http://seejohncode.com/"
},
"main": "server.js",
"dependencies": {
"busboy": "^0.3.1",
"express": "^4.17.1",
"express-rate-limit": "^5.1.3",
"pg": "^8.3.2",
"redis": "^3.0.2",
"redis-url": "^1.2.1",
"st": "^2.0.0",
"uglify-js": "^3.10.2",
"winston": "^3.3.3"
},
"devDependencies": {
"mocha": "^8.1.2"
},
"bin": {
"haste-server": "./server.js"
},
"files": [
"server.js",
"lib",
"static"
],
"directories": {
"lib": "./lib"
},
"scripts": {
"start": "node server.js",
"test": "mocha --recursive"
}
}

223
server.js
View file

@ -1,155 +1,134 @@
const http = require('http');
const fs = require('fs');
const uglify = require('uglify-js');
const winston = require('winston');
const connect = require('connect');
const route = require('connect-route');
const connect_st = require('st');
const connect_rate_limit = require('connect-ratelimit');
const uglify = require('uglify-js');
const st = require('st');
const app = require('express')();
const expressRateLimit = require('express-rate-limit');
const DocumentHandler = require('./lib/document_handler');
const HasteUtils = require('./lib/util');
// Load the configuration and set some defaults
const config = require('./config.json');
config.port = process.env.PORT || config.port || 7777;
config.host = process.env.HOST || config.host || 'localhost';
const utils = new HasteUtils();
// Set up the logger
if (config.logging) {
try {
winston.remove(winston.transports.Console);
} catch(e) {
/* was not present */
}
//set up logger
//only Console for now, gotta utilize config.json in the future
winston.add(new winston.transports.Console({
level: 'silly',
format: winston.format.combine(
winston.format.colorize(),
winston.format.printf(info => `${info.level}: ${info.message} ${utils.stringifyJSONMessagetoLogs(info)}`)
),
}));
let detail, type;
for (let i = 0; i < config.logging.length; i++) {
detail = config.logging[i];
type = detail.type;
delete detail.type;
winston.add(winston.transports[type], detail);
}
//load config and set some defaults
const config = require('./config');
config.port = config.port || 7777;
config.host = config.host || '127.0.0.1';
//defaulting storage type to file
if (!config.storage){
config.storage = {
type: 'file',
path: './data'
};
}
if (!config.storage.type) config.storage.type = 'file';
// 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';
}
let Store, preferredStore;
if (process.env.REDISTOGO_URL && config.storage.type === 'redis') {
let redisClient = require('redis-url').connect(process.env.REDISTOGO_URL);
Store = require('./lib/document_stores/redis');
preferredStore = new Store(config.storage, redisClient);
let preferredStore;
if (process.env.REDISTOGO_URL && config.storage.type == 'redis'){
let redisClient = require('redis-url').connect(process.env.REDISTOGO_URL);
let 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);
let Store = require(`./lib/document_stores/${config.storage.type}`);
preferredStore = new Store(config.storage);
}
// Compress the static javascript assets
if (config.recompressStaticAssets) {
let list = fs.readdirSync('./static');
for (let j = 0; j < list.length; j++) {
let item = list[j];
if ((item.indexOf('.js') === item.length - 3) && (item.indexOf('.min.js') === -1)) {
let dest = item.substring(0, item.length - 3) + '.min' + item.substring(item.length - 3);
let orig_code = fs.readFileSync('./static/' + item, 'utf8');
//compress static javascript assets
if (config.recompressStaticAssets){
let files = fs.readdirSync('./static');
for (const file of files){
if ((file.indexOf('.js') == file.length - 3) && (file.indexOf('.min.js') == -1)){
let dest = `${file.substring(0, file.length - 3)}.min${file.substring(file.length - 3)}`;
let origCode = fs.readFileSync(`./static/${file}`, 'utf8');
fs.writeFileSync('./static/' + dest, uglify.minify(orig_code).code, 'utf8');
winston.info('compressed ' + item + ' into ' + dest);
fs.writeFileSync(`./static/${dest}`, uglify.minify(origCode).code, 'utf8');
winston.info(`compressed ${file} into ${dest}`);
}
}
}
}
// Send the static documents into the preferred store, skipping expirations
let path, data;
for (let 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 });
}
//send the static documents into the preferred store, skipping expirations
for (const name in config.documents){
let path = config.documents[name];
winston.info('loading static document', { name: name, path: path });
let data = fs.readFileSync(path, 'utf8');
if (data){
preferredStore.set(name, data, doc => winston.debug('loaded static document', { success: doc }), true);
}
else {
winston.warn('failed to load static document', { name: name, path: path });
}
}
// Pick up a key generator
let pwOptions = config.keyGenerator || {};
//pick up a key generator
let pwOptions = config.keyGenerator || new Object;
pwOptions.type = pwOptions.type || 'random';
let gen = require('./lib/key_generators/' + pwOptions.type);
let keyGenerator = new gen(pwOptions);
let Gen = require(`./lib/key_generators/${pwOptions.type}`);
let keyGenerator = new Gen(pwOptions);
// Configure the document handler
//configure the document handler
let documentHandler = new DocumentHandler({
store: preferredStore,
maxLength: config.maxLength,
keyLength: config.keyLength,
keyGenerator: keyGenerator
store: preferredStore,
maxLength: config.maxLength,
keyLength: config.keyLength,
keyGenerator: keyGenerator
});
let app = connect();
//rate limit all requests
if (config.rateLimits) app.use(expressRateLimit(config.rateLimits));
// Rate limit all requests
if (config.rateLimits) {
config.rateLimits.end = true;
app.use(connect_rate_limit(config.rateLimits));
}
//try API first
// first look at API calls
app.use(route(function(router) {
// get raw documents - support getting with extension
router.get('/raw/:id', function(request, response) {
let key = request.params.id.split('.')[0];
let skipExpire = !!config.documents[key];
return documentHandler.handleRawGet(key, response, skipExpire);
});
// add documents
router.post('/documents', function(request, response) {
return documentHandler.handlePost(request, response);
});
// get documents
router.get('/documents/:id', function(request, response) {
let key = request.params.id.split('.')[0];
let skipExpire = !!config.documents[key];
return documentHandler.handleGet(key, response, skipExpire);
});
//get raw documents
app.get('/raw/:id', (req, res) => {
const key = req.params.id.split('.')[0];
const skipExpire = Boolean(config.documents[key]);
return documentHandler.handleGetRaw(key, res, skipExpire);
});
//add documents
app.post('/documents', (req, res) => {
return documentHandler.handlePost(req, res);
});
//get documents
app.get('/documents/:id', (req, res) => {
const key = req.params.id.split('.')[0];
const skipExpire = Boolean(config.documents[key]);
return documentHandler.handleGet(key, res, skipExpire);
});
//try static next
app.use(st({
path: './static',
passthrough: true,
index: false
}));
// Otherwise, try to match static files
app.use(connect_st({
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 = '/';
//then we can loop back - and everything else should be a token,
//so route it back to /
app.get('/:id', (req, res, next) => {
req.sturl = '/';
next();
});
}));
});
// And match index
app.use(connect_st({
path: __dirname + '/static',
//and match index
app.use(st({
content: { maxAge: config.staticMaxAge },
index: 'index.html'
path: './static',
index: 'index.html'
}));
http.createServer(app).listen(config.port, config.host);
winston.info('listening on ' + config.host + ':' + config.port);
app.listen(config.port, config.host, () => winston.info(`listening on ${config.host}:${config.port}`));

View file

@ -27,7 +27,7 @@ haste_document.prototype.load = function(key, callback, lang) {
_this.data = res.data;
try {
var high;
if (lang === 'txt') {
if (lang == 'txt') {
high = { value: _this.htmlEscape(res.data) };
}
else if (lang) {
@ -178,7 +178,7 @@ haste.extensionMap = {
// If not found, return the type itself - which we'll place as the extension
haste.prototype.lookupExtensionByType = function(type) {
for (var key in haste.extensionMap) {
if (haste.extensionMap[key] === type) return key;
if (haste.extensionMap[key] == type) return key;
}
return type;
};
@ -266,7 +266,7 @@ haste.prototype.configureButtons = function() {
label: 'Save',
shortcutDescription: 'control + s',
shortcut: function(evt) {
return evt.ctrlKey && (evt.keyCode === 83);
return evt.ctrlKey && (evt.keyCode == 83);
},
action: function() {
if (_this.$textarea.val().replace(/^\s+|\s+$/g, '') !== '') {
@ -278,7 +278,7 @@ haste.prototype.configureButtons = function() {
$where: $('#box2 .new'),
label: 'New',
shortcut: function(evt) {
return evt.ctrlKey && evt.keyCode === 78;
return evt.ctrlKey && evt.keyCode == 78;
},
shortcutDescription: 'control + n',
action: function() {
@ -289,7 +289,7 @@ haste.prototype.configureButtons = function() {
$where: $('#box2 .duplicate'),
label: 'Duplicate & Edit',
shortcut: function(evt) {
return _this.doc.locked && evt.ctrlKey && evt.keyCode === 68;
return _this.doc.locked && evt.ctrlKey && evt.keyCode == 68;
},
shortcutDescription: 'control + d',
action: function() {
@ -300,7 +300,7 @@ haste.prototype.configureButtons = function() {
$where: $('#box2 .raw'),
label: 'Just Text',
shortcut: function(evt) {
return evt.ctrlKey && evt.shiftKey && evt.keyCode === 82;
return evt.ctrlKey && evt.shiftKey && evt.keyCode == 82;
},
shortcutDescription: 'control + shift + r',
action: function() {
@ -366,7 +366,7 @@ haste.prototype.configureShortcuts = function() {
$(function() {
$('textarea').keydown(function(evt) {
if (evt.keyCode === 9) {
if (evt.keyCode == 9) {
evt.preventDefault();
var myValue = ' ';
// http://stackoverflow.com/questions/946534/insert-text-into-textarea-with-jquery

View file

@ -1 +0,0 @@
var haste_document=function(){this.locked=!1};haste_document.prototype.htmlEscape=function(t){return t.replace(/&/g,"&amp;").replace(/>/g,"&gt;").replace(/</g,"&lt;").replace(/"/g,"&quot;")},haste_document.prototype.load=function(t,e,o){var n=this;$.ajax("/documents/"+t,{type:"get",dataType:"json",success:function(s){n.locked=!0,n.key=t,n.data=s.data;try{var i;i="txt"===o?{value:n.htmlEscape(s.data)}:o?hljs.highlight(o,s.data):hljs.highlightAuto(s.data)}catch(t){i=hljs.highlightAuto(s.data)}e({value:i.value,key:t,language:i.language||o,lineCount:s.data.split("\n").length})},error:function(){e(!1)}})},haste_document.prototype.save=function(t,e){if(this.locked)return!1;this.data=t;var o=this;$.ajax("/documents",{type:"post",data:t,dataType:"json",contentType:"application/json; charset=utf-8",success:function(n){o.locked=!0,o.key=n.key;var s=hljs.highlightAuto(t);e(null,{value:s.value,key:n.key,language:s.language,lineCount:t.split("\n").length})},error:function(t){try{e($.parseJSON(t.responseText))}catch(t){e({message:"Something went wrong!"})}}})};var haste=function(t,e){this.appName=t,this.$textarea=$("textarea"),this.$box=$("#box"),this.$code=$("#box code"),this.$linenos=$("#linenos"),this.options=e,this.configureShortcuts(),this.configureButtons(),e.twitter||$("#box2 .twitter").hide()};haste.prototype.setTitle=function(t){var e=t?this.appName+" - "+t:this.appName;document.title=e},haste.prototype.showMessage=function(t,e){var o=$('<li class="'+(e||"info")+'">'+t+"</li>");$("#messages").prepend(o),setTimeout(function(){o.slideUp("fast",function(){$(this).remove()})},3e3)},haste.prototype.lightKey=function(){this.configureKey(["new","save"])},haste.prototype.fullKey=function(){this.configureKey(["new","duplicate","twitter","raw"])},haste.prototype.configureKey=function(t){var e,o=0;$("#box2 .function").each(function(){for(e=$(this),o=0;o<t.length;o++)if(e.hasClass(t[o]))return e.addClass("enabled"),!0;e.removeClass("enabled")})},haste.prototype.newDocument=function(t){this.$box.hide(),this.doc=new haste_document,t||window.history.pushState(null,this.appName,"/"),this.setTitle(),this.lightKey(),this.$textarea.val("").show("fast",function(){this.focus()}),this.removeLineNumbers()},haste.extensionMap={rb:"ruby",py:"python",pl:"perl",php:"php",scala:"scala",go:"go",xml:"xml",html:"xml",htm:"xml",css:"css",js:"javascript",vbs:"vbscript",lua:"lua",pas:"delphi",java:"java",cpp:"cpp",cc:"cpp",m:"objectivec",vala:"vala",sql:"sql",sm:"smalltalk",lisp:"lisp",ini:"ini",diff:"diff",bash:"bash",sh:"bash",tex:"tex",erl:"erlang",hs:"haskell",md:"markdown",txt:"",coffee:"coffee",json:"javascript",swift:"swift"},haste.prototype.lookupExtensionByType=function(t){for(var e in haste.extensionMap)if(haste.extensionMap[e]===t)return e;return t},haste.prototype.lookupTypeByExtension=function(t){return haste.extensionMap[t]||t},haste.prototype.addLineNumbers=function(t){for(var e="",o=0;o<t;o++)e+=(o+1).toString()+"<br/>";$("#linenos").html(e)},haste.prototype.removeLineNumbers=function(){$("#linenos").html("&gt;")},haste.prototype.loadDocument=function(t){var e=t.split(".",2),o=this;o.doc=new haste_document,o.doc.load(e[0],function(t){t?(o.$code.html(t.value),o.setTitle(t.key),o.fullKey(),o.$textarea.val("").hide(),o.$box.show().focus(),o.addLineNumbers(t.lineCount)):o.newDocument()},this.lookupTypeByExtension(e[1]))},haste.prototype.duplicateDocument=function(){if(this.doc.locked){var t=this.doc.data;this.newDocument(),this.$textarea.val(t)}},haste.prototype.lockDocument=function(){var t=this;this.doc.save(this.$textarea.val(),function(e,o){if(e)t.showMessage(e.message,"error");else if(o){t.$code.html(o.value),t.setTitle(o.key);var n="/"+o.key;o.language&&(n+="."+t.lookupExtensionByType(o.language)),window.history.pushState(null,t.appName+"-"+o.key,n),t.fullKey(),t.$textarea.val("").hide(),t.$box.show().focus(),t.addLineNumbers(o.lineCount)}})},haste.prototype.configureButtons=function(){var t=this;this.buttons=[{$where:$("#box2 .save"),label:"Save",shortcutDescription:"control + s",shortcut:function(t){return t.ctrlKey&&83===t.keyCode},action:function(){""!==t.$textarea.val().replace(/^\s+|\s+$/g,"")&&t.lockDocument()}},{$where:$("#box2 .new"),label:"New",shortcut:function(t){return t.ctrlKey&&78===t.keyCode},shortcutDescription:"control + n",action:function(){t.newDocument(!t.doc.key)}},{$where:$("#box2 .duplicate"),label:"Duplicate & Edit",shortcut:function(e){return t.doc.locked&&e.ctrlKey&&68===e.keyCode},shortcutDescription:"control + d",action:function(){t.duplicateDocument()}},{$where:$("#box2 .raw"),label:"Just Text",shortcut:function(t){return t.ctrlKey&&t.shiftKey&&82===t.keyCode},shortcutDescription:"control + shift + r",action:function(){window.location.href="/raw/"+t.doc.key}},{$where:$("#box2 .twitter"),label:"Twitter",shortcut:function(e){return t.options.twitter&&t.doc.locked&&e.shiftKey&&e.ctrlKey&&84==e.keyCode},shortcutDescription:"control + shift + t",action:function(){window.open("https://twitter.com/share?url="+encodeURI(window.location.href))}}];for(var e=0;e<this.buttons.length;e++)this.configureButton(this.buttons[e])},haste.prototype.configureButton=function(t){t.$where.click(function(e){e.preventDefault(),!t.clickDisabled&&$(this).hasClass("enabled")&&t.action()}),t.$where.mouseenter(function(){$("#box3 .label").text(t.label),$("#box3 .shortcut").text(t.shortcutDescription||""),$("#box3").show(),$(this).append($("#pointer").remove().show())}),t.$where.mouseleave(function(){$("#box3").hide(),$("#pointer").hide()})},haste.prototype.configureShortcuts=function(){var t=this;$(document.body).keydown(function(e){for(var o,n=0;n<t.buttons.length;n++)if((o=t.buttons[n]).shortcut&&o.shortcut(e))return e.preventDefault(),void o.action()})},$(function(){$("textarea").keydown(function(t){if(9===t.keyCode){t.preventDefault();if(document.selection)this.focus(),document.selection.createRange().text=" ",this.focus();else if(this.selectionStart||"0"==this.selectionStart){var e=this.selectionStart,o=this.selectionEnd,n=this.scrollTop;this.value=this.value.substring(0,e)+" "+this.value.substring(o,this.value.length),this.focus(),this.selectionStart=e+" ".length,this.selectionEnd=e+" ".length,this.scrollTop=n}else this.value+=" ",this.focus()}})});

View file

@ -14,23 +14,23 @@
<meta name="robots" content="noindex,nofollow"/>
<script type="text/javascript">
var app = null;
let app = null;
// Handle pops
var handlePop = function(evt) {
var path = evt.target.location.pathname;
if (path === '/') { app.newDocument(true); }
let handlePop = function(evt){
let path = evt.target.location.pathname;
if (path == '/') { app.newDocument(true); }
else { app.loadDocument(path.substring(1, path.length)); }
};
// Set up the pop state to handle loads, skipping the first load
// to make chrome behave like others:
// http://code.google.com/p/chromium/issues/detail?id=63040
setTimeout(function() {
window.onpopstate = function(evt) {
setTimeout(function(){
window.onpopstate = function(evt){
try { handlePop(evt); } catch(err) { /* not loaded yet */ }
};
}, 1000);
// Construct app and load initial path
$(function() {
$(function(){
app = new haste('hastebin', { twitter: true });
handlePop({ target: window });
});

View file

@ -1,9 +1,9 @@
/* global describe, it */
var assert = require('assert');
const assert = require('assert');
var DocumentHandler = require('../lib/document_handler');
var Generator = require('../lib/key_generators/random');
const DocumentHandler = require('../lib/document_handler');
const Generator = require('../lib/key_generators/random');
describe('document_handler', function() {

View file

@ -1,11 +1,11 @@
/* global it, describe, afterEach */
var assert = require('assert');
const assert = require('assert');
var winston = require('winston');
const winston = require('winston');
winston.remove(winston.transports.Console);
var RedisDocumentStore = require('../lib/document_stores/redis');
const RedisDocumentStore = require('../lib/document_stores/redis');
describe('redis_document_store', function() {