Compare commits

..

1 Commits

Author SHA1 Message Date
6271da2ff3 Simplify for Butlersaurus
All checks were successful
TerribleCodeClub/ButlerBin/pipeline/head This commit looks good
2020-06-08 23:18:36 +01:00
6 changed files with 96 additions and 116 deletions

View File

@ -1,10 +1,9 @@
{
"host": "0.0.0.0",
"port": 7777,
"keyLength": 10,
"maxLength": 400000,
"keyLength": 5,
"keySpace": "abcdefghijklmnopqrstuvwxyz0123456789",
"staticMaxAge": 86400,
"recompressStaticAssets": true,
"logging": [
{
"level": "verbose",

View File

@ -1,119 +1,102 @@
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
// 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." }));
}
});
};
// Handle retrieving the raw version of a document
// 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." }));
}
});
};
// 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;

View File

@ -1,23 +1,23 @@
var fs = require('fs');
var crypto = require('crypto');
var fs = require("fs");
var crypto = require("crypto");
var FileDocumentStore = function() {
this.basePath = '/data';
this.basePath = "/data";
this.expire = null;
};
FileDocumentStore.md5 = function(str) {
var md5sum = crypto.createHash('md5');
var md5sum = crypto.createHash("md5");
md5sum.update(str);
return md5sum.digest('hex');
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) {
fs.mkdir(this.basePath, "700", function() {
var fn = _this.basePath + "/" + FileDocumentStore.md5(key);
fs.writeFile(fn, data, "utf8", function(err) {
if (err) {
callback(false);
}
@ -33,8 +33,8 @@ FileDocumentStore.prototype.set = function(key, data, callback) {
FileDocumentStore.prototype.get = function(key, callback) {
var _this = this;
var fn = _this.basePath + '/' + FileDocumentStore.md5(key);
fs.readFile(fn, 'utf8', function(err, data) {
var fn = _this.basePath + "/" + FileDocumentStore.md5(key);
fs.readFile(fn, "utf8", function(err, data) {
if (err) {
callback(false);
}

View File

@ -1,19 +1,18 @@
module.exports = class KeyGenerator {
// Initialize a new generator with the given keySpace
constructor() {
this.keyspace = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
// 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(keyLength) {
var text = '';
for (var i = 0; i < keyLength; i++) {
const index = Math.floor(Math.random() * this.keyspace.length);
text += this.keyspace.charAt(index);
// 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;
}

View File

@ -18,9 +18,6 @@
"connect": "3.4.1",
"st": "1.1.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"
},

View File

@ -1,25 +1,25 @@
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 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 DocumentHandler = require('./lib/document_handler');
var KeyGenerator = require('./lib/key_generator');
var Store = require('./lib/document_store');
var DocumentHandler = require("./lib/document_handler");
var KeyGenerator = require("./lib/key_generator");
var Store = require("./lib/document_store");
// Load the configuration and set some defaults
var config = JSON.parse(Fs.readFileSync('./config.js', 'utf8'));
config.host = config.host || '127.0.0.1';
// 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;
// Set up the logger
// Set up the logger.
if (config.logging) {
try {
Winston.remove(Winston.transports.Console);
} catch(e) {
// This is fine
// This is fine.
}
var detail, type;
for (var i = 0; i < config.logging.length; i++) {
@ -30,60 +30,62 @@ if (config.logging) {
}
}
// Configure the data store
// Configure the data store.
store = new Store();
// Pick up a key generator
var keyGenerator = new KeyGenerator();
// Pick up a key generator.
var keyGenerator = new KeyGenerator({
keyLength: config.keyLength,
keySpace: config.keySpace
});
// Configure the document handler
// Configure the document handler.
var documentHandler = new DocumentHandler({
store: store,
maxLength: config.maxLength,
keyLength: config.keyLength,
keyGenerator: keyGenerator
});
var app = Connect();
// API
// Configure the API routes.
app.use(Route(function(router) {
router.get('/raw/:id', function(request, response) {
var key = request.params.id.split('.')[0];
router.get("/raw/:id", function(request, response) {
var key = request.params.id.split(".")[0];
return documentHandler.handleRawGet(key, response);
});
router.post('/documents', function(request, response) {
router.post("/documents", function(request, response) {
return documentHandler.handlePost(request, response);
});
router.get('/documents/:id', function(request, response) {
var key = request.params.id.split('.')[0];
router.get("/documents/:id", function(request, response) {
var key = request.params.id.split(".")[0];
return documentHandler.handleGet(key, response);
});
}));
// Static files
// Route static files.
app.use(ConnectSt({
path: __dirname + '/static',
path: __dirname + "/static",
content: { maxAge: config.staticMaxAge },
passthrough: true,
index: false
}));
// All the pastebin IDs
// All the pastebin IDs.
app.use(Route(function(router) {
router.get('/:id', function(request, response, next) {
request.sturl = '/';
router.get("/:id", function(request, response, next) {
request.sturl = "/";
next();
});
}));
// Index
// Route index.html.
app.use(ConnectSt({
path: __dirname + '/static',
path: __dirname + "/static",
content: { maxAge: config.staticMaxAge },
index: 'index.html'
index: "index.html"
}));
Http.createServer(app).listen(config.port, config.host);
Winston.info('Listening on ' + config.host + ':' + config.port);
Winston.info("Listening on " + config.host + ":" + config.port);