From 87ab2022e7769a97e9f4f8928a91f65b8ff1eff7 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Thu, 25 Feb 2016 21:20:38 -0600 Subject: [PATCH 1/6] caplib: explict access to random, files rather than ambient --- caplib.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/caplib.js b/caplib.js index f5cab22..5af6264 100644 --- a/caplib.js +++ b/caplib.js @@ -17,9 +17,6 @@ information regarding how to obtain the source code for this library. /*global console, require, module */ module.exports = function() { "use strict"; -var fs = require("fs"); -var path = require("path"); -var crypto = require("crypto"); /** * Function typeCheck allows a quick, concise limited form of duck typing of the * arguments to a function. The function using typeCheck should pass in its @@ -77,6 +74,8 @@ function tvalid(args, types, additionalTest, errMsg) { return valid(typeCheck(args, types) && additionalTest, errMsg); } +function makeUnique(crypto) { + function unique() { var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; var ans = ""; @@ -91,6 +90,12 @@ function unique() { //} return ans; } + + return { + unique: unique + }; +} + function makeSealerPair() { var holder = null; function seal(x) { @@ -174,6 +179,9 @@ function argMap(argv, webkeyStringToLive) { return args; } + +function makeFileUtils(fs, path) { + function copyFile(src, dest) { var data = fs.readFileSync(src); fs.writeFileSync(dest); @@ -205,17 +213,22 @@ function makeNewServer() { copyIfAbsent("ssl"); } + return { + makeNewServer: makeNewServer, + copyRecurse: copyRecurse + }; +} + var self = { typeCheck: typeCheck, - unique: unique, + makeUnique: makeUnique, valid: valid, tvalid: tvalid, makeSealerPair: makeSealerPair, cloneMap: cloneMap, argMap:argMap, deepObjToJSON: deepObjToJSON, - makeNewServer: makeNewServer, - copyRecurse: copyRecurse + makeFileUtils: makeFileUtils }; return self; From caa3c5497e4e4af22561acd9cef2292420ec44fd Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Thu, 25 Feb 2016 21:29:37 -0600 Subject: [PATCH 2/6] saver: explicit access to files, random, loading --- saver.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/saver.js b/saver.js index 04d97db..d83ea47 100644 --- a/saver.js +++ b/saver.js @@ -21,6 +21,9 @@ var caplib = require("./caplib"); module.exports = function(){ "use strict"; + + function makeSaver(unique, fs, fss, require) { + var dbfile = "capper.db"; function log(text) {console.log(text);} @@ -79,8 +82,8 @@ module.exports = function(){ **/ var sysState = {}; function loadSysState(){ - if (!fs.existsSync(dbfile)) {fs.writeFileSync(dbfile, "{}");} - var jsonState = fs.readFileSync(dbfile, 'utf8'); + if (!fss.existsSync(dbfile)) {fss.writeFileSync(dbfile, "{}");} + var jsonState = fss.readFileSync(dbfile, 'utf8'); if (jsonState.length === 0) {jsonState = "{}";} sysState = JSON.parse(jsonState); } @@ -250,7 +253,7 @@ module.exports = function(){ } make = function(makerLocation, optInitArgs) { setupCheckpoint(); - var cred = caplib.unique(); + var cred = unique(); var newId = credToId(cred); sysState[cred] = {data: {}, reviver: makerLocation}; var newContext = makeContext(newId); @@ -326,4 +329,7 @@ module.exports = function(){ drop: drop }; return Object.freeze(self); -}(); \ No newline at end of file +} + + return makeSaver; +}(); From fcaedb44979ab4a5126fc53006facdaa1fa0e2b8 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Thu, 25 Feb 2016 21:39:57 -0600 Subject: [PATCH 3/6] server: move getObj(), vowAnsToVowJSONString() Move them closer to other functions that need similar authority. --- server.js | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/server.js b/server.js index 582d9a5..30ce197 100644 --- a/server.js +++ b/server.js @@ -65,18 +65,18 @@ function reviverToUIPath(reviver) { revstring += filename + ".html"; return revstring; } -function getObj(req) { - var cred = req.query.s; - var id = saver.credToId(cred); - var reviver = saver.reviver(id); - var live = saver.live(id); - return { - cred: cred, - reviver: reviver, - live: live, - id: id, - method: req.query.q - }; + +function vowAnsToVowJSONString(vowAns) { + return vowAns.then(function(ans) { + var result = caplib.deepObjToJSON(ans, idToWebkey, saver); + log(JSON.stringify(result)); + if (result !== null && typeof result === "object" && ("@" in result)) { + return JSON.stringify(result); + } else {return JSON.stringify({"=": result});} + }, function(err){ + log("vowAnsToVowJSONString err " + err); + return JSON.stringify({"!": err}); + }); } /** * webkeyToLive(wkeyObj) looks to see if the arg is a webkeyObject, if so, @@ -106,6 +106,21 @@ app.get("/apps/:theapp/ui/:filename", function(req, res) { app.get('/', function(req, res) { res.sendfile('./views/index.html'); }); + +function getObj(req) { + var cred = req.query.s; + var id = saver.credToId(cred); + var reviver = saver.reviver(id); + var live = saver.live(id); + return { + cred: cred, + reviver: reviver, + live: live, + id: id, + method: req.query.q + }; +} + function showActor(req, res) { if (!req.query.s ) { res.sendfile("./bootstrap.html"); @@ -125,19 +140,6 @@ function showActor(req, res) { } app.get("/ocaps/", showActor); -function vowAnsToVowJSONString(vowAns) { - return vowAns.then(function(ans) { - var result = caplib.deepObjToJSON(ans, idToWebkey, saver); - log(JSON.stringify(result)) - if (result !== null && typeof result === "object" && ("@" in result)) { - return JSON.stringify(result); - } else {return JSON.stringify({"=": result});} - }, function(err){ - log("vowAnsToVowJSONString err " + err); - return JSON.stringify({"!": err}); - }); -} - function invokeActor(req, res){ log("post query " + JSON.stringify(req.query)); log("post body: " + JSON.stringify(req.body)); From 08e5aac02c7f7eb3c99db4df2c38e506f068435d Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Thu, 25 Feb 2016 21:53:39 -0600 Subject: [PATCH 4/6] server: authority derives from CLI invocation - import powerful objects only if (require.main == module), i.e. only when this module is invoked from the command line - pass access to files, network, randomness explicitly rather than using ambient authority - to makeConfig(), sslOptions(), makeSturdy(), makeApp() --- server.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/server.js b/server.js index 30ce197..00d59cf 100644 --- a/server.js +++ b/server.js @@ -16,14 +16,13 @@ information regarding how to obtain the source code for this library. /*global require, console, process */ "use strict"; -var https = require("https"); -var fs = require("fs"); -var express = require("express"); var Q = require("q"); var caplib = require("./caplib"); -var saver = require("./saver"); +var makeSaver = require("./saver"); var log = function(text) {console.log(text);}; +function makeConfig(fs) { + var domain; var port; var deferStart = Q.defer(); @@ -33,8 +32,13 @@ fs.readFile("capper.config", "utf8", function(err, data) { port = config.port; domain = config.protocol + "://" + config.domain + ":" + config.port + "/"; log("config domain " + domain); - deferStart.resolve(true); + deferStart.resolve({domain: domain, port: port}); }); + + return deferStart.promise; +} + +function sslOptions(fs) { var sslOptions = { key: fs.readFileSync('./ssl/server.key'), cert: fs.readFileSync('./ssl/server.crt'), @@ -42,7 +46,10 @@ var sslOptions = { requestCert: true, rejectUnauthorized: false }; -var app = express(); + return sslOptions; +} + + function parseBody(req, res, next) { req.rawBody = ''; req.setEncoding('utf8'); @@ -66,6 +73,8 @@ function reviverToUIPath(reviver) { return revstring; } +function makeSturdy(saver, domain) { + function vowAnsToVowJSONString(vowAns) { return vowAns.then(function(ans) { var result = caplib.deepObjToJSON(ans, idToWebkey, saver); @@ -94,6 +103,26 @@ function webkeyToLive(wkeyObj) { function idToWebkey(id) { return domain + "ocaps/#s=" + saver.idToCred(id); } + +function wkeyStringToLive(keyString) { + return webkeyToLive({"@": keyString}); +} + + return { + idToWebkey: idToWebkey, + vowAnsToVowJSONString: vowAnsToVowJSONString, + webkeyToLive: webkeyToLive, + wkeyStringToLive + }; +} + +// express is *nearly* powerless, but it seems to appeal +// to at least path.resolve() +function makeApp(express, saver, sturdy) { + var webkeyToLive = sturdy.webkeyToLive; + var vowAnsToVowJSONString = sturdy.vowAnsToVowJSONString; + +var app = express(); app.get("/views/:filename", function(req, res) { res.sendfile("./views/" + req.params.filename); }); @@ -160,11 +189,20 @@ function invokeActor(req, res){ } app.post("/ocaps/", parseBody, invokeActor); -function wkeyStringToLive(keyString) { - return webkeyToLive({"@": keyString}); + return app; } -deferStart.promise.then(function(){ - var argMap = caplib.argMap(process.argv, wkeyStringToLive); + + +function main(argv, require, crypto, fs, fsSync, https, express) { + const unique = caplib.makeUnique(crypto); + const saver = makeSaver(unique.unique, fs, fsSync, require); + + makeConfig(fs).then(config => { + const sturdy = makeSturdy(saver, config.domain); + const wkeyStringToLive = sturdy.wkeyStringToLive; + const idToWebkey = sturdy.idToWebkey; + + var argMap = caplib.argMap(argv, wkeyStringToLive); if ("-drop" in argMap) { saver.drop(saver.credToId(argMap["-drop"][0])); saver.checkpoint().then(function() {console.log("drop done");}); @@ -188,7 +226,25 @@ deferStart.promise.then(function(){ }); } } else { + const app = makeApp(express, saver, config.domain); + const sslOptions = sslOptions(fsSync); + const port = config.port; + var s = https.createServer(sslOptions, app); s.listen(port); } -}); + }); +} + + +if (require.main == module) { + main(process.argv, + require, // to load app modules + require("crypto"), + { readFile: require("fs").readFile, + writeFile: require("fs").writeFile }, + require("fs"), + { createServer: require("https").createServer }, + require("express") + ); +} From f768691afa1ec1729a3078d6876bd79db81c69d9 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Thu, 25 Feb 2016 23:46:35 -0600 Subject: [PATCH 5/6] oops... left-over require("fs") at top level of saver --- saver.js | 1 - 1 file changed, 1 deletion(-) diff --git a/saver.js b/saver.js index d83ea47..4ce8f0b 100644 --- a/saver.js +++ b/saver.js @@ -15,7 +15,6 @@ information regarding how to obtain the source code for this library. */ /*global require, Map, console, Proxy, setImmediate */ -var fs = require("fs"); var Q = require("q"); var caplib = require("./caplib"); From 7d59d72d7cd052ca1c6e38df618acc9b5aa18fbd Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Thu, 25 Feb 2016 23:53:52 -0600 Subject: [PATCH 6/6] oops: don't shadow sslOptions; bind vowAnsToVowJSONString --- server.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 00d59cf..abc2626 100644 --- a/server.js +++ b/server.js @@ -201,6 +201,7 @@ function main(argv, require, crypto, fs, fsSync, https, express) { const sturdy = makeSturdy(saver, config.domain); const wkeyStringToLive = sturdy.wkeyStringToLive; const idToWebkey = sturdy.idToWebkey; + const vowAnsToVowJSONString = sturdy.vowAnsToVowJSONString; var argMap = caplib.argMap(argv, wkeyStringToLive); if ("-drop" in argMap) { @@ -227,10 +228,10 @@ function main(argv, require, crypto, fs, fsSync, https, express) { } } else { const app = makeApp(express, saver, config.domain); - const sslOptions = sslOptions(fsSync); + const sslOpts = sslOptions(fsSync); const port = config.port; - var s = https.createServer(sslOptions, app); + var s = https.createServer(sslOpts, app); s.listen(port); } });