Skip to content

Instantly share code, notes, and snippets.

@joelpurra
Created October 21, 2018 13:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelpurra/90a1f2d877e46b7a9eea45154da9645a to your computer and use it in GitHub Desktop.
Save joelpurra/90a1f2d877e46b7a9eea45154da9645a to your computer and use it in GitHub Desktop.
monolith was taken so heres the makings to stonehenge
((dev) => {
"use strict";
const fs = require('fs');
const path = require('path');
const express = require('express');
const log_color = {
clear: "\x1b[0m",
read: "\x1b[34m",
write: "\x1b[33m",
error: "\x1b[31m",
preparing: "\x1b[36m",
server_up: "\x1b[32m"
};
class Monolith {
constructor(
page = {
fpath: null,
title: null,
head: null,
styles: null,
content: null,
scripts: null
}, write = false) {
let { fpath = __dirname, title = 'sanity', head = '', styles = '', content = '', scripts = '' } = page;
this.title = title;
this.fpath = fpath;
this.head = this.concatonate(head);
this.styles = this.concatonate(styles);
this.content = this.concatonate(content);
this.scripts = this.concatonate(scripts);
this.page = null;
if (write === true) {
this.init();
this.write();
}
};
init() {
console.log(log_color.preparing, `Preparing page for: ${this.title}`, log_color.clear);
// Template strings respect whitespace.
this.page = (
`<!DOCTYPE html>
<html>
<head>${this.head}
<title>${this.title}</title>
<style>${this.styles}
</style>
</head>
<body>${ !!this.content ? "\n" + this.content : '' }
<script>${this.scripts}</script>
</body>
</html>
`);
};
check(filepath) {
try { fs.accessSync(filepath, fs.F_OK); }
catch (e) { return false; }
return true;
}
read(
file,
type = null,
encoding = 'utf8'
) {
const fp = path.join(__dirname, file);
if (this.check(fp) == true) {
const data = fs.readFileSync(fp, encoding);
if (!type) { return data; }
else {
this.reassign(
{ [type]: (`${(typeof this[type] === 'string' ? this[type] : '')}${ data }`) }
);
}
console.log(log_color.read, `imported successfully: ${fp}`, log_color.clear);
} else console.log(log_color.error, `Unable to find: ${fp}`, log_color.clear);
}
write(output_path = null) {
output_path = (
output_path != null
? output_path
: path.join(this.fpath, this.title, '.html')
);
fs.writeFileSync(output_path, this.page);
console.log(log_color.write, `file write to path at: ${output_path}\n`, log_color.clear);
};
concatonate(data, indent='\n ') {
return (data instanceof Array ? data.join(indent) : data);
};
reassign({
title = null,
fpath = null,
head = null,
styles = null,
content = null,
scripts = null
},
write = false
) {
const fields = arguments[0];
const keys = Object.keys(fields);
for (
let current_field = 0;
current_field < keys.length;
current_field++
) {
let key_i = keys[current_field];
this[key_i] = this.concatonate(
(typeof fields[key_i] === 'string')
? fields[key_i]
: this[key_i]
);
}
if (write == true) this.write();
};
}
class Ritual {
constructor(
pages = [
{ path: '/', page: 'Hello World' },
{ path: '/*', page: 'This endpoint has not been set.' }
],
router = express.Router()
) {
this.pages = pages;
for (
let iter_pages = 0;
iter_pages < this.pages.length;
iter_pages++
) {
let {
path = '',
page = '',
get = null,
post = null,
update = null,
remove = null } = this.pages[iter_pages];
let dev_get = (req, res) => { res.send(page); };
let dev_log = (req, res) => { console.log(req); };
router.get( path, get || dev_get);
router.post( path, post || dev_log);
router.put( path, update || dev_log);
router.delete(path, remove || dev_log);
} this.ritual = router;
}
}
// Monolith test
let Homepage = new Monolith({content: 'lalalala it works'});
// Filepath Type
Homepage.read(path.join('assets', 'general', 'includes.html'), 'head');
Homepage.read(path.join('assets', 'general', 'index.css'), 'styles');
Homepage.read(path.join('assets', 'general', 'basic-html.html'), 'content');
Homepage.read(path.join('assets', 'general', 'scratch.js'), 'scripts');
Homepage.init();
// Ritual test
let FirstPage = {
path: '/' + Homepage.title,
page: Homepage.page,
get: (req, res) => { res.status(200).send(Homepage.page); }
};
let TheUninitiated = new Ritual([
FirstPage,
{
path: '/',
page: 'It works, just goto ' + FirstPage.path
},
{
path: '/*',
page: '404 Page not found.'
}
]);
const port = process.env.PORT || 3000;
let client = express();
client.use(express.static(path.join(__dirname, 'dist')))
client.use(TheUninitiated.ritual);
client.listen(port, () => {
console.log(log_color.server_up, `Server initiated port: ${port}`, log_color.clear);
});
Homepage.read('package.json', 'scripts');
Homepage.init();
})(true);
Copy link

ghost commented Oct 23, 2018

I'm made some progress by decoupling all dependencies and resolved the platform paths with the naive ternary on process so it will be runnable in the browser.

I believe a couple milestones I can set for myself are enforced https by default and the api for self modification in the context of the payload and user interface.
Authentication for a proper admin portal to access the cached version. No strategy in plan for writes back to the server.

How would you evaluate the attack surface area of express and eventually reaching confidence to allow a copy on write feature?
I'm content with a copy paste of browser view source as it maintains some semblance of security by not exposing fs to the internet.
It also forces manual audit.

I'v never shared code, any advice for placing my repo on npm?

Copy link

ghost commented Oct 25, 2018

I'v updated with ssl support and should be pushing changes tonight if you have any interest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment