Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6259083
copyFile: actually write the data that got read
dckc Feb 26, 2016
cb23cf2
Proxy.set: return true to indicate success
dckc Feb 26, 2016
87ab202
caplib: explict access to random, files
dckc Feb 26, 2016
caa3c54
saver: explicit access to files, random, loading
dckc Feb 26, 2016
fcaedb4
server: move getObj(), vowAnsToVowJSONString()
dckc Feb 26, 2016
08e5aac
server: authority derives from CLI invocation
dckc Feb 26, 2016
f768691
oops... left-over require("fs") at top level of saver
dckc Feb 26, 2016
7d59d72
oops: don't shadow sslOptions; bind vowAnsToVowJSONString
dckc Feb 26, 2016
20f7d37
Merge branch 'proxy-set-return' into flowtype
dckc Feb 26, 2016
06a638c
Merge branch 'copyFile-data' into flowtype
dckc Feb 26, 2016
34aeed7
annotations and minor tweaks for static typechecking
dckc Feb 26, 2016
755c3cc
update indentation to match ocap scope changes
dckc Feb 29, 2016
7d51296
oops... makeApp() takes a sturdy, not a domain
dckc Mar 4, 2016
e00e401
makeSaver only needs reviverToMaker, not require
dckc Mar 4, 2016
ae0e16b
caplib.js: delete trailing whitespace
dckc Mar 4, 2016
ccc5912
caplib.js: normalize whitespace; prune makeFileUtils dead code
dckc Mar 4, 2016
65cbdb5
avoid strange typechecking errors in .json files
dckc Mar 4, 2016
afa5465
toward type declarations for express
dckc Mar 4, 2016
7ef485a
Capper organized as library: complete draft
dckc Mar 4, 2016
b3fe94f
do not version control the .db
dckc Mar 5, 2016
0dc2836
use separate names for version-controlled and edited config
dckc Mar 5, 2016
892cdde
refactor makeUnique(crypto).unique to makeUnique(randomBytes)
dckc Mar 5, 2016
ba50b8e
export caplib from Capper
dckc Mar 5, 2016
271d79b
missing ssl/server.key was a silent failure
dckc Mar 5, 2016
ce76307
use sendUI() to send all the app's files
dckc Mar 5, 2016
931e18a
delete-trailing-whitespace; ensure newlines at EOF
dckc Mar 6, 2016
3d102ac
consolidate saver dependencies
dckc Mar 6, 2016
e1cc2da
update tests, sealer app w.r.t. ocap discipline
dckc Mar 6, 2016
48288eb
don't use overly powerful ezSaver in server main()
dckc Mar 6, 2016
c502d7e
export makeSaver and io routines
dckc Mar 6, 2016
09509a4
bootstrap.html ref was sensitive to cwd
dckc Mar 6, 2016
103f8bd
route paths with multiple segments
dckc Mar 6, 2016
c6c8fc4
add runNaked() for use in sandstorm
dckc Dec 10, 2016
234bd60
Proxy.create() obsolete in favor of new Proxy()
dckc Dec 10, 2016
bf677c5
log objects, not just strings
dckc Dec 11, 2016
0249834
caplib: export makeParseArg
dckc Sep 27, 2017
547dba9
saver: conform to JS Proxy handler API
dckc Oct 22, 2017
d510356
`flow check` issues: Proxy has, Promise.done() etc.
dckc Oct 22, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[libs]
interfaces/

[ignore]
.*node_modules/.*/test/.*\.json
.*node_modules/.*/tables/.*\.json
.*node_modules/resolve/lib/.*\.json
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
capper.config

#################
## Eclipse
#################
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ or

which will do the same thing.

Next, you must modify the capper.config file to suit your needs. To conduct client-server testing on your development machine, you probably want to set "domain" to "localhost"; it will certainly not work if you leave the domain unchanged. Select a port you can open on your machine (beware of firewalls blocking ports, you may have to configure the firewall as well). At this time you must use protocol https. The self-signed certificate embodied in the "ssl" folder will be adequate for simple testing, though you will have to click OK through the cert monolog boxes in your browser.
Next, you must make a `capper.config` file to suit your needs (se `capper.config.example` as a pattern). To conduct client-server testing on your development machine, you probably want to set "domain" to "localhost"; it will certainly not work if you leave the domain unchanged. Select a port you can open on your machine (beware of firewalls blocking ports, you may have to configure the firewall as well). At this time you must use protocol https. The self-signed certificate embodied in the "ssl" folder will be adequate for simple testing, though you will have to click OK through the cert monolog boxes in your browser.

In a command window, change directories to the Capper folder and startup the server from the command line with
>node --harmony-proxies server
Expand Down
15 changes: 8 additions & 7 deletions apps/sealer/server/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"use strict";

var caplib = require("../../../caplib");
var unique = caplib.makeUnique(require("crypto").randomBytes);
module.exports = Object.freeze({
makeSealerPair: function(context) {
return Object.freeze({
Expand All @@ -16,33 +17,33 @@ module.exports = Object.freeze({
makeSealer: function(context) {
var mem = context.state;
var self;
self = Object.freeze({
self = Object.freeze({
init: function(share) {
if ("share" in mem) {return;} //already initialized
mem.share = share;
},
seal: function(x) {
var box = caplib.unique();
var box = unique();
mem.share.state[box] = x;
return box;
}
});
});
return self;
},
makeUnsealer: function(context) {
var mem = context.state;
var self;
self = Object.freeze({
self = Object.freeze({
init: function(share) {
if ("share" in mem) {return;} //already initialized
mem.share = share;
},
unseal: function(box) {
unseal: function(box) {
var x = mem.share.state[box];
// delete mem.share.state[box] //uncomment to create an open-only-once unsealer
return x;
}
});
});
return self;
}
});
});
165 changes: 79 additions & 86 deletions caplib.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
Copyright 2011 Hewlett-Packard Company. This library is free software;
you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License (LGPL) as published by the Free Software
Expand All @@ -12,17 +12,17 @@ with this library; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Please contact the Hewlett-Packard Company <www.hp.com> for
information regarding how to obtain the source code for this library.

@flow
*/

/*global console, require, module */
module.exports = function() {
/*global console, module */
/* jshint esversion: 6, node: true */

"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
* arguments to a function. The function using typeCheck should pass in its
* arguments plus a character specifying a type for each argument to be
* tested. The types are:
* {
Expand All @@ -41,63 +41,70 @@ var crypto = require("crypto");
* If the first two arguments to add were not numbers, typeCheck logs to console and returns false.
*
* Additional rules:
* Duck will throw an exception if there are more tests than arguments.
* Duck will throw an exception if there are more tests than arguments.
* However, if there are additional arguments for which there are not tests, it will pass.
* Duck will throw if it gets a null or undefined for any argument.
**/
function typeCheck(args, validTypes) {
function typeCheck(args /*:Array<any>*/, validTypes /*: string*/) /*:bool*/ {
var types = {
n: "number",
s: "string",
f: "function",
o: "object",
b: "boolean"
};
};
//you can have untested args, but not tests for which there are no args
if (args.length < validTypes.length) {throw "typeCheck has more tests than args";}
if (args.length < validTypes.length) {throw "typeCheck has more tests than args";}
for (var i = 0; i < validTypes.length; i++) {
if (args[i] === null) {console.log("typeCheck found null"); return false;}
var typ = validTypes[i];
if (typeof(args[i]) !== types[typ]) {
console.log("typeCheck bad arg " + i + " should be: " + typ +
" was " + typeof(args[i]));
console.log("typeCheck bad arg " + i + " should be: " + typ +
" was " + typeof(args[i]));
return false;
}
}
return true;
}

function valid(test, errMsg) {
function valid(test /*: any*/, errMsg /*: string*/) /*: bool*/ {
if (test) {return true;}
console.log("invalid: " + errMsg);
throw("invalid: " + errMsg);
}

function tvalid(args, types, additionalTest, errMsg) {
function tvalid(args /*:Array<any>*/, types /*: string*/, additionalTest /*:bool*/, errMsg /*: string*/) /*:bool*/ {
return valid(typeCheck(args, types) && additionalTest, errMsg);
}

function unique() {
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
var ans = "";
var buf = crypto.randomBytes(25);
for (var i = 0; i < buf.length; i++) {
var index = buf[i] % chars.length;
ans += chars[index];
function makeUnique(randomBytes /*: (qty: number) => Array<number>*/
) /*: () => string*/{

function unique() {
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
var ans = "";
var buf = randomBytes(25);
for (var i = 0; i < buf.length; i++) {
var index = buf[i] % chars.length;
ans += chars[index];
}
//while (ans.length < 30) {
// var nextI = Math.floor(Math.random()*10000) % chars.length;
// ans += chars[nextI];
//}
return ans;
}
//while (ans.length < 30) {
// var nextI = Math.floor(Math.random()*10000) % chars.length;
// ans += chars[nextI];
//}
return ans;

return unique;
}
function makeSealerPair() {
var holder = null;
function seal(x) {

function makeSealerPair/*::<T>*/() /*: SealerPair<T> */{
var holder /*:?T*/ = null;
function seal(x /*:T*/) {
var box = function() {holder = x;};
return box;
}
function unseal(box) {
function unseal(box) /*:?T*/ {
holder = null;
box();
var ans = holder;
Expand All @@ -107,26 +114,29 @@ function makeSealerPair() {
return {seal:seal, unseal:unseal};
}

function cloneMap(m) {
function cloneMap(m /*: Object*/) /*: Object*/{
var clone = {};
for (var key in m) {clone[key] = m[key];}
return clone;
}
/**
* If the obj is a persistent object, or if the obj contains a ref to a persistent
* object, or the id of a persistent obj ({"@id": cred}), replace the object with
* object, or the id of a persistent obj ({"@id": cred}), replace the object with
* a webkey object (i.e., {"@" : webkey}). If
* a function is encountered, convert to null and log it. In all other cases,
* leave it alone.
*
*
* In the end, return the json string of the result.
*
*
* TODO: the in-place replacement makes it possible for the persistent app
* that produced this array or map to see the webkeys of the live
* objects it included. Unnecessary loss of encapsulation.
* Do copy, not in-place replace.
* */
function deepObjToJSON(obj, idToWebkey, saver) {
function deepObjToJSON(obj /*:any*/,
idToWebkey /*: (id: Object) => string*/,
saver /*: Saver*/) /*: any */
{
if (obj === undefined) {return null;}
if (obj === null) {return null;}
if (typeof obj === "function") {
Expand All @@ -137,86 +147,69 @@ function deepObjToJSON(obj, idToWebkey, saver) {
if (saver.hasId(obj)) {
var webkey = idToWebkey(saver.asId(obj));
return {"@" : webkey};
}
}
if (saver.live(obj)) {return {"@": idToWebkey(obj)};}
var clone = obj instanceof Array ? [] : {};
var clone /*: any*/= obj instanceof Array ? [] : {};
for (var key in obj) {
clone[key] = deepObjToJSON(obj[key], idToWebkey, saver);
}
return clone;
}


/**
* finding commands such as drop and make, if a command line has an arg
* finding commands such as drop and make, if a command line has an arg
* after "server" make the rest of the args elements in map
* Returns map with one entry, the first post=server element as key,
* Returns map with one entry, the first post=server element as key,
* following args as list
* Converts args preceded with "#" to numbers
* Converts args preceded with "@" to live refs
* */
function argMap(argv, webkeyStringToLive) {
var args = {};
function argMap(argv /*: Array<string>*/,
webkeyStringToLive /*: (webkey: string) => any */) /*: Object*/
{
var args = {};
var serverIndex;
for (serverIndex = 0;
serverIndex < argv.length && argv[serverIndex].indexOf ("server") < 0;
serverIndex++) {}
for (serverIndex = 0;
serverIndex < argv.length && argv[serverIndex].indexOf ("server") < 0;
serverIndex++) {
// next arg...
}
if (serverIndex === argv.length - 1) {return args;}
var parseArg = makeParseArg(webkeyStringToLive);
var command = argv[serverIndex+1];
var commandArgs = argv.splice(serverIndex+2);
commandArgs.forEach(function(next, i) {
if (next.indexOf("#") === 0) {
commandArgs[i] = parseFloat(next.substring(1));
} else if (next.indexOf("@") === 0) {
commandArgs[i] = webkeyStringToLive(next.substring(1));
}
var commandArgs /*: Array<string|number|Object>*/ = [];
argv.splice(serverIndex+2).forEach(function(next, i) {
commandArgs[i] = parseArg(next);
});
args[command] = commandArgs;
return args;
}

function copyFile(src, dest) {
var data = fs.readFileSync(src);
fs.writeFileSync(dest);
}
function copyRecurse(src, dest) {
var exists = fs.existsSync(src);
var stats = exists && fs.statSync(src);
var isDirectory = exists && stats.isDirectory();
if (exists && isDirectory) {
fs.mkdirSync(dest);
fs.readdirSync(src).forEach(function(childItemName) {
copyRecurse(path.join(src, childItemName),
path.join(dest, childItemName));
});
} else if (exists) {copyFile(src, dest);}
}
function makeNewServer() {
function copyIfAbsent(dest) {
var srcDir = path.dirname(module.filename);
if (!fs.existsSync(dest)) {
copyRecurse(path.join(srcDir, dest), dest);
function makeParseArg(webkeyStringToLive /*: (webkey: string) => any */) /*: (string) => any */{
return parseArg;

function parseArg(next /*: string*/) {
if (next.indexOf("#") === 0) {
return parseFloat(next.substring(1));
} else if (next.indexOf("@") === 0) {
return webkeyStringToLive(next.substring(1));
}
return next;
}
copyIfAbsent("capper.db");
copyIfAbsent("capper.config");
copyIfAbsent("apps");
copyIfAbsent("test");
copyIfAbsent("views");
copyIfAbsent("ssl");
}


var self = {
typeCheck: typeCheck,
unique: unique,
makeUnique: makeUnique,
valid: valid,
tvalid: tvalid,
makeSealerPair: makeSealerPair,
cloneMap: cloneMap,
argMap:argMap,
deepObjToJSON: deepObjToJSON,
makeNewServer: makeNewServer,
copyRecurse: copyRecurse
argMap: argMap,
makeParseArg: makeParseArg,
deepObjToJSON: deepObjToJSON
};
return self;

}();
module.exports = self;
File renamed without changes.
1 change: 0 additions & 1 deletion capper.db

This file was deleted.

15 changes: 15 additions & 0 deletions interfaces/express.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type Application = any;

/* TODO:
type Application = {
get(route: string, ...handers: RequestHandler[]): void;
};
*/

type RequestHandler = (req: Request, res: Response, next: NextFunction) => any;
type NextFunction = (err: any) => void;
type Request = { };
type Response = {
sendfile(path: string): void;
}

Loading