fluffy – Blame information for rev 9

Subversion Repositories:
Rev:
Rev Author Line No. Line
6 office 1 #!/usr/bin/env node
2  
3 /*************************************************************************/
4 /* Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 */
5 /*************************************************************************/
6  
7 const url = require('url');
8 const path = require('path');
9 const fs = require('fs');
10 const mime = require('mime');
11 const auth = require("http-auth");
12 const stream = require('stream');
13 const util = require('util');
14 var formidable = require('formidable');
15 const EventEmitter = require('events').EventEmitter;
16  
17 // Local imports.
18 const Cache = require(
19 path
20 .resolve(
21 path.dirname(require.main.filename),
22 'src/server',
23 'cache'
24 )
25 );
26 const was = require(
27 path
28 .resolve(
29 path.dirname(require.main.filename),
30 'src/server',
31 'was'
32 )
33 );
34  
35 // Constructor.
36 function POST() {
37 // Create events emitters for logging and data.
38 EventEmitter.call(this);
39 };
40  
41 // Process a request.
42 POST.prototype.process = function(config, request, response, root) {
43 EventEmitter.call(this);
44 var self = this;
45  
46 // Get client details.
47 const address = request.socket.address();
48 // Get requested URL.
49 const requestURL = url.parse(
50 request.url, true
51 );
52  
53 // Perform URL re-writes.
54 Object.keys(config.site.rewrite).forEach((key, index) => {
55 if (config.site.rewrite[key].test(requestURL.path)) {
56 const originalPath = requestURL.path;
57 requestURL.path = requestURL
58 .path
59 .replace(
60 config.site.rewrite[key], key
61 );
62 requestURL.pathname = url.parse(
63 requestURL
64 .pathname
65 .replace(
66 config.site.rewrite[key], key
67 ),
68 true
69 )
70 .pathname;
71 self.emit('log', {
72 message: 'Rewrite path: ' +
73 originalPath +
74 ' to: ' +
75 requestURL.path,
76 severity: 'info'
77 });
78 }
79 });
80  
81 const trimmedPath = requestURL
82 .pathname
83 .split('/')
84 .filter(Boolean)
85 .join('/');
86 const requestPath = trimmedPath === '/' ?
87 path.join(root, trimmedPath) :
88 path.resolve(root, trimmedPath);
89  
90 var form = new formidable.IncomingForm(),
91 properfields = {};
92  
93 // Workaround for formidable not parsing multiple filed options.
94 form.on('field', function(name, value) {
95 if (!properfields[name]) {
96 properfields[name] = value;
97 } else {
98 if (properfields[name].constructor.toString().indexOf("Array") > -1) { // is array
99 properfields[name].push(value);
100 } else { // not array
101 var tmp = properfields[name];
102 properfields[name] = [];
103 properfields[name].push(tmp);
104 properfields[name].push(value);
105 }
106 }
107 });
108  
109 form.parse(request, function(error, fields, files) {
110 // If the form data could not be parsed.
111 if (error) {
112 self.emit('log', {
113 message: 'Could not parse form data from: ' +
114 address.address + ':' +
115 address.port +
116 ' requesting: ' +
117 requestURL.pathname,
118 severity: 'warning'
119 });
120 self.emit('data', {
121 status: 404,
122 data: new stream.Readable({
123 read(size) {
124 this.push(null);
125 }
126 }),
127 type: 'text/plain'
128 });
129 return;
130 }
131  
132 switch(trimmedPath) {
133 case 'add':
134 // Write the icon file.
9 office 135 var iconPath = path.join(root, 'services/' + fields['service-name'] + '.png');
6 office 136 var formFile = fs.createReadStream(files['service-icon'].path)
137 .on('open', () => {
138 formFile.pipe(
139 fs.createWriteStream(iconPath)
140 .on('error', (error) => {
141 if (error) {
142 self.emit('log', {
143 message: 'Unable to create file at: ' + iconPath,
144 severity: 'error'
145 });
146 self.emit('data', {
147 status: 404,
148 data: new stream.Readable({
149 read(size) {
150 this.push(null);
151 }
152 }),
153 type: 'text/plain'
154 });
155 return;
156 }
157 })
158 );
159 })
160 .on('error', (error) => {
161 if (error) {
162 self.emit('log', {
163 message: 'Unable to create file at: ' + iconPath,
164 severity: 'error'
165 });
166 self.emit('data', {
167 status: 404,
168 data: new stream.Readable({
169 read(size) {
170 this.push(null);
171 }
172 }),
173 type: 'text/plain'
174 });
175 return;
176 }
177 });
178  
9 office 179 var templatePath = path.join(root, 'templates/service.html');
180 fs.readFile(templatePath, 'utf8', function(error, data) {
181 // Could not read data file.
6 office 182 if (error) {
183 self.emit('log', {
9 office 184 message: 'Unable to read data file.',
6 office 185 severity: 'error'
186 });
187 self.emit('data', {
188 status: 404,
189 data: new stream.Readable({
190 read(size) {
191 this.push(null);
192 }
193 }),
194 type: 'text/plain'
195 });
196 return;
197 }
9 office 198  
199 data = data.replace(/FLUFFY_SERVICE_NAME/g, fields['service-name']);
200 data = data.replace(/FLUFFY_SERVICE_URL/g, fields['service-url'])
201  
202 var htmlPath = path.join(root, 'services/' + fields['service-name'] + '.html');
203 fs.writeFile(htmlPath, data, (error) => {
204 // Could not write data file.
6 office 205 if (error) {
206 self.emit('log', {
9 office 207 message: 'Unable to write data file.',
6 office 208 severity: 'error'
209 });
210 self.emit('data', {
211 status: 404,
212 data: new stream.Readable({
213 read(size) {
214 this.push(null);
215 }
216 }),
217 type: 'text/plain'
218 });
219 return;
220 }
9 office 221  
222 // Send the main site index.
223 self.emit('log', {
224 message: 'Added new service.',
225 severity: 'info'
6 office 226 });
9 office 227 self.emit('data', {
228 status: 200,
229 data: fs.createReadStream(path.join(root, config.site.index)),
230 type: 'text/html'
231 });
232  
233 });
234  
235 });
236 break;
237 case 'remove':
238 [ properfields['remove-services'] ].forEach((service) => {
239 var service_assets = [
240 path.join(root, 'services/' + service + '.html'),
241 path.join(root, 'services/' + service + '.png')
242 ]
243 service_assets.forEach((asset) => {
244 fs.realpath(asset, (error, dataPath) => {
245 // If the path does not exist, then return early.
6 office 246 if (error) {
247 self.emit('log', {
9 office 248 message: 'Unable to access data path: ' + dataPath + ' error: ' + error,
6 office 249 severity: 'error'
250 });
251 self.emit('data', {
252 status: 404,
253 data: new stream.Readable({
254 read(size) {
255 this.push(null);
256 }
257 }),
258 type: 'text/plain'
259 });
260 return;
261 }
9 office 262  
263 fs.unlink(dataPath, (error) => {
264 if(error) {
265 self.emit('log', {
266 message: 'Could not remove image file.',
267 severity: 'warning'
268 });
269 self.emit('data', {
270 status: 404,
271 data: new stream.Readable({
272 read(size) {
273 this.push(null);
274 }
275 }),
276 type: 'text/plain'
277 });
278 }
6 office 279 });
280 });
281 });
282 });
9 office 283  
284 // Send the main site index.
285 self.emit('log', {
286 message: 'Removed services.',
287 severity: 'info'
288 });
289 self.emit('data', {
290 status: 200,
291 data: fs.createReadStream(path.join(root, config.site.index)),
292 type: 'text/html'
293 });
6 office 294 break;
295 default:
296 self.emit('log', {
297 message: 'No such path.',
298 severity: 'error'
299 });
300 self.emit('data', {
301 status: 404,
302 data: new stream.Readable({
303 read(size) {
304 this.push(null);
305 }
306 }),
307 type: 'text/plain'
308 });
309 return;
310 }
311 });
312  
313 return this;
314 };
315  
316 util.inherits(POST, EventEmitter);
317 util.inherits(Cache, EventEmitter);
318 module.exports = POST;