fluffy – Rev 9
?pathlinks?
#!/usr/bin/env node
/*************************************************************************/
/* Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 */
/*************************************************************************/
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');
const auth = require("http-auth");
const stream = require('stream');
const util = require('util');
var formidable = require('formidable');
const EventEmitter = require('events').EventEmitter;
// Local imports.
const Cache = require(
path
.resolve(
path.dirname(require.main.filename),
'src/server',
'cache'
)
);
const was = require(
path
.resolve(
path.dirname(require.main.filename),
'src/server',
'was'
)
);
// Constructor.
function POST() {
// Create events emitters for logging and data.
EventEmitter.call(this);
};
// Process a request.
POST.prototype.process = function(config, request, response, root) {
EventEmitter.call(this);
var self = this;
// Get client details.
const address = request.socket.address();
// Get requested URL.
const requestURL = url.parse(
request.url, true
);
// Perform URL re-writes.
Object.keys(config.site.rewrite).forEach((key, index) => {
if (config.site.rewrite[key].test(requestURL.path)) {
const originalPath = requestURL.path;
requestURL.path = requestURL
.path
.replace(
config.site.rewrite[key], key
);
requestURL.pathname = url.parse(
requestURL
.pathname
.replace(
config.site.rewrite[key], key
),
true
)
.pathname;
self.emit('log', {
message: 'Rewrite path: ' +
originalPath +
' to: ' +
requestURL.path,
severity: 'info'
});
}
});
const trimmedPath = requestURL
.pathname
.split('/')
.filter(Boolean)
.join('/');
const requestPath = trimmedPath === '/' ?
path.join(root, trimmedPath) :
path.resolve(root, trimmedPath);
var form = new formidable.IncomingForm(),
properfields = {};
// Workaround for formidable not parsing multiple filed options.
form.on('field', function(name, value) {
if (!properfields[name]) {
properfields[name] = value;
} else {
if (properfields[name].constructor.toString().indexOf("Array") > -1) { // is array
properfields[name].push(value);
} else { // not array
var tmp = properfields[name];
properfields[name] = [];
properfields[name].push(tmp);
properfields[name].push(value);
}
}
});
form.parse(request, function(error, fields, files) {
// If the form data could not be parsed.
if (error) {
self.emit('log', {
message: 'Could not parse form data from: ' +
address.address + ':' +
address.port +
' requesting: ' +
requestURL.pathname,
severity: 'warning'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
switch(trimmedPath) {
case 'add':
// Write the icon file.
var iconPath = path.join(root, 'services/' + fields['service-name'] + '.png');
var formFile = fs.createReadStream(files['service-icon'].path)
.on('open', () => {
formFile.pipe(
fs.createWriteStream(iconPath)
.on('error', (error) => {
if (error) {
self.emit('log', {
message: 'Unable to create file at: ' + iconPath,
severity: 'error'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
})
);
})
.on('error', (error) => {
if (error) {
self.emit('log', {
message: 'Unable to create file at: ' + iconPath,
severity: 'error'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
});
var templatePath = path.join(root, 'templates/service.html');
fs.readFile(templatePath, 'utf8', function(error, data) {
// Could not read data file.
if (error) {
self.emit('log', {
message: 'Unable to read data file.',
severity: 'error'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
data = data.replace(/FLUFFY_SERVICE_NAME/g, fields['service-name']);
data = data.replace(/FLUFFY_SERVICE_URL/g, fields['service-url'])
var htmlPath = path.join(root, 'services/' + fields['service-name'] + '.html');
fs.writeFile(htmlPath, data, (error) => {
// Could not write data file.
if (error) {
self.emit('log', {
message: 'Unable to write data file.',
severity: 'error'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
// Send the main site index.
self.emit('log', {
message: 'Added new service.',
severity: 'info'
});
self.emit('data', {
status: 200,
data: fs.createReadStream(path.join(root, config.site.index)),
type: 'text/html'
});
});
});
break;
case 'remove':
[ properfields['remove-services'] ].forEach((service) => {
var service_assets = [
path.join(root, 'services/' + service + '.html'),
path.join(root, 'services/' + service + '.png')
]
service_assets.forEach((asset) => {
fs.realpath(asset, (error, dataPath) => {
// If the path does not exist, then return early.
if (error) {
self.emit('log', {
message: 'Unable to access data path: ' + dataPath + ' error: ' + error,
severity: 'error'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
fs.unlink(dataPath, (error) => {
if(error) {
self.emit('log', {
message: 'Could not remove image file.',
severity: 'warning'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
}
});
});
});
});
// Send the main site index.
self.emit('log', {
message: 'Removed services.',
severity: 'info'
});
self.emit('data', {
status: 200,
data: fs.createReadStream(path.join(root, config.site.index)),
type: 'text/html'
});
break;
default:
self.emit('log', {
message: 'No such path.',
severity: 'error'
});
self.emit('data', {
status: 404,
data: new stream.Readable({
read(size) {
this.push(null);
}
}),
type: 'text/plain'
});
return;
}
});
return this;
};
util.inherits(POST, EventEmitter);
util.inherits(Cache, EventEmitter);
module.exports = POST;
Generated by GNU Enscript 1.6.5.90.