resolve merge-conflict with accounting branch
This commit is contained in:
commit
306f6ce806
@ -209,6 +209,21 @@ const handleMessage = function (ctx, user, msg) {
|
|||||||
let parsedMsg = {state: 1, channel: parsed[1]};
|
let parsedMsg = {state: 1, channel: parsed[1]};
|
||||||
sendMsg(ctx, user, [0, HISTORY_KEEPER_ID, 'MSG', user.id, JSON.stringify(parsedMsg)]);
|
sendMsg(ctx, user, [0, HISTORY_KEEPER_ID, 'MSG', user.id, JSON.stringify(parsedMsg)]);
|
||||||
});
|
});
|
||||||
|
} else if (ctx.rpc) {
|
||||||
|
/* RPC Calls... */
|
||||||
|
var rpc_call = parsed.slice(1);
|
||||||
|
|
||||||
|
// slice off the sequence number and pass in the rest of the message
|
||||||
|
ctx.rpc(rpc_call, function (err, output) {
|
||||||
|
if (err) {
|
||||||
|
console.error('[' + err + ']', output); // TODO make this disableable
|
||||||
|
sendMsg(ctx, user, [seq, 'ACK']);
|
||||||
|
sendMsg(ctx, user, [0, HISTORY_KEEPER_ID, 'MSG', user.id, JSON.stringify([parsed[0], 'ERROR', err])]);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sendMsg(ctx, user, [seq, 'ACK']);
|
||||||
|
sendMsg(ctx, user, [0, HISTORY_KEEPER_ID, 'MSG', user.id, JSON.stringify([parsed[0]].concat(output))]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -251,7 +266,7 @@ const handleMessage = function (ctx, user, msg) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let run = module.exports.run = function (storage, socketServer, config) {
|
let run = module.exports.run = function (storage, socketServer, config, rpc) {
|
||||||
/* Channel removal timeout defaults to 60000ms (one minute) */
|
/* Channel removal timeout defaults to 60000ms (one minute) */
|
||||||
config.channelRemovalTimeout =
|
config.channelRemovalTimeout =
|
||||||
typeof(config.channelRemovalTimeout) === 'number'?
|
typeof(config.channelRemovalTimeout) === 'number'?
|
||||||
@ -263,7 +278,8 @@ let run = module.exports.run = function (storage, socketServer, config) {
|
|||||||
channels: {},
|
channels: {},
|
||||||
timeouts: {},
|
timeouts: {},
|
||||||
store: storage,
|
store: storage,
|
||||||
config: config
|
config: config,
|
||||||
|
rpc: rpc,
|
||||||
};
|
};
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
Object.keys(ctx.users).forEach(function (userId) {
|
Object.keys(ctx.users).forEach(function (userId) {
|
||||||
|
|||||||
@ -130,6 +130,13 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
openFileLimit: 2048,
|
openFileLimit: 2048,
|
||||||
|
|
||||||
|
/* Cryptpad's socket server can be extended to respond to RPC calls
|
||||||
|
* you can configure it to respond to custom RPC calls if you like.
|
||||||
|
* provide the path to your RPC module here, or `false` if you would
|
||||||
|
* like to disable the RPC interface completely
|
||||||
|
*/
|
||||||
|
rpc: './rpc.js',
|
||||||
|
|
||||||
/* it is recommended that you serve cryptpad over https
|
/* it is recommended that you serve cryptpad over https
|
||||||
* the filepaths below are used to configure your certificates
|
* the filepaths below are used to configure your certificates
|
||||||
*/
|
*/
|
||||||
|
|||||||
37
rpc.js
Normal file
37
rpc.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* Use Nacl for checking signatures of messages
|
||||||
|
|
||||||
|
*/
|
||||||
|
var Nacl = require("tweetnacl");
|
||||||
|
|
||||||
|
var RPC = module.exports;
|
||||||
|
|
||||||
|
var pin = function (ctx, cb) { };
|
||||||
|
var unpin = function (ctx, cb) { };
|
||||||
|
var getHash = function (ctx, cb) { };
|
||||||
|
var getTotalSize = function (ctx, cb) { };
|
||||||
|
var getFileSize = function (ctx, cb) { };
|
||||||
|
|
||||||
|
RPC.create = function (config, cb) {
|
||||||
|
// load pin-store...
|
||||||
|
|
||||||
|
console.log('loading rpc module...');
|
||||||
|
rpc = function (msg, respond) {
|
||||||
|
switch (msg[0]) {
|
||||||
|
case 'ECHO':
|
||||||
|
respond(void 0, msg);
|
||||||
|
break;
|
||||||
|
case 'PIN':
|
||||||
|
case 'UNPIN':
|
||||||
|
case 'GET_HASH':
|
||||||
|
case 'GET_TOTAL_SIZE':
|
||||||
|
case 'GET_FILE_SIZE':
|
||||||
|
|
||||||
|
default:
|
||||||
|
respond('UNSUPPORTED_RPC_CALL', msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cb(void 0, rpc);
|
||||||
|
};
|
||||||
|
|
||||||
37
server.js
37
server.js
@ -117,13 +117,32 @@ httpServer.listen(config.httpPort,config.httpAddress,function(){
|
|||||||
|
|
||||||
var wsConfig = { server: httpServer };
|
var wsConfig = { server: httpServer };
|
||||||
|
|
||||||
if(!config.useExternalWebsocket) {
|
var createSocketServer = function (err, rpc) {
|
||||||
if (websocketPort !== config.httpPort) {
|
if(!config.useExternalWebsocket) {
|
||||||
console.log("setting up a new websocket server");
|
if (websocketPort !== config.httpPort) {
|
||||||
wsConfig = { port: websocketPort};
|
console.log("setting up a new websocket server");
|
||||||
|
wsConfig = { port: websocketPort};
|
||||||
|
}
|
||||||
|
var wsSrv = new WebSocketServer(wsConfig);
|
||||||
|
Storage.create(config, function (store) {
|
||||||
|
NetfluxSrv.run(store, wsSrv, config, rpc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
var wsSrv = new WebSocketServer(wsConfig);
|
};
|
||||||
Storage.create(config, function (store) {
|
|
||||||
NetfluxSrv.run(store, wsSrv, config);
|
var loadRPC = function (cb) {
|
||||||
});
|
config.rpc = typeof(config.rpc) === 'undefined'? './rpc.js' : config.rpc;
|
||||||
}
|
|
||||||
|
if (typeof(config.rpc) === 'string') {
|
||||||
|
// load pin store...
|
||||||
|
var Rpc = require(config.rpc);
|
||||||
|
Rpc.create(config, function (e, rpc) {
|
||||||
|
if (e) { throw e; }
|
||||||
|
cb(void 0, rpc);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadRPC(createSocketServer);
|
||||||
|
|||||||
19
www/common/encode.js
Normal file
19
www/common/encode.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
define([], function () {
|
||||||
|
var exports = {};
|
||||||
|
|
||||||
|
var hexToUint8Array = exports.hexToUint8Array = function (s) {
|
||||||
|
// if not hex or odd number of characters
|
||||||
|
if (!/[a-fA-F0-9]+/.test(s) || s.length % 2) { throw new Error("string is not hex"); }
|
||||||
|
return s.split(/([0-9a-fA-F]{2})/)
|
||||||
|
.filter(function (x) { return x; })
|
||||||
|
.map(function (x) { return Number('0x' + x); });
|
||||||
|
};
|
||||||
|
|
||||||
|
var uint8ArrayToHex = exports.uint8ArrayToHex = function (a) {
|
||||||
|
return a.reduce(function(memo, i) {
|
||||||
|
return memo + ((i < 16) ? '0' : '') + i.toString(16);
|
||||||
|
}, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
});
|
||||||
57
www/common/pinpad.js
Normal file
57
www/common/pinpad.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
define([
|
||||||
|
'/common/cryptpad-common.js',
|
||||||
|
'/common/rpc.js',
|
||||||
|
|
||||||
|
'/bower_components/tweetnacl/nacl-fast.min.js'
|
||||||
|
], function (Cryptpad, Rpc) {
|
||||||
|
|
||||||
|
var Nacl = window.nacl;
|
||||||
|
|
||||||
|
var deduplicate = function (array) {
|
||||||
|
var a = array.slice();
|
||||||
|
for(var i=0; i<a.length; i++) {
|
||||||
|
for(var j=i+1; j<a.length; j++) {
|
||||||
|
if(a[i] === a[j]) { a.splice(j--, 1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
|
||||||
|
var create = function (network, ed) {
|
||||||
|
var exp = {};
|
||||||
|
var rpc = Rpc.create(network, ed);
|
||||||
|
|
||||||
|
var checkHash = exp.checkHash = function (fileList) {
|
||||||
|
//var fileList = fo.getFilesDataFiles();
|
||||||
|
var channelIdList = [];
|
||||||
|
fileList.forEach(function (href) {
|
||||||
|
var parsedHref = Cryptpad.parsePadUrl(href);
|
||||||
|
if (!parsedHref || !parsedHref.hash) { return; }
|
||||||
|
var parsedHash = Cryptpad.parseHash(parsedHref.hash);
|
||||||
|
if (!parsedHash || !parsedHash.channel) { return; }
|
||||||
|
channelIdList.push(Cryptpad.base64ToHex(parsedHash.channel));
|
||||||
|
});
|
||||||
|
var uniqueList = deduplicate(channelIdList).sort();
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. every time you want to pin or unpid a pad you send a message to the server
|
||||||
|
2. the server sends back a hash of the sorted list of your pinned pads
|
||||||
|
3. you hash your sorted list of pinned pads that you should have according to your drive
|
||||||
|
4. compare them, if same
|
||||||
|
AWESOME
|
||||||
|
if they are not
|
||||||
|
UNPIN all, send all
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var hash = Nacl.util.encodeBase64(Nacl.hash(Nacl.util.decodeUTF8( JSON.stringify(uniqueList) )));
|
||||||
|
|
||||||
|
console.log(hash);
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
return exp;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { create: create };
|
||||||
|
});
|
||||||
106
www/common/rpc.js
Normal file
106
www/common/rpc.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
define([
|
||||||
|
'/common/encode.js',
|
||||||
|
|
||||||
|
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||||
|
], function (Encode) {
|
||||||
|
var MAX_LAG_BEFORE_TIMEOUT = 30000;
|
||||||
|
|
||||||
|
var uid = function () {
|
||||||
|
return Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
|
||||||
|
.toString(32).replace(/\./g, '');
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
types of messages:
|
||||||
|
pin -> hash
|
||||||
|
unpin -> hash
|
||||||
|
getHash -> hash
|
||||||
|
getTotalSize -> bytes
|
||||||
|
getFileSize -> bytes
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* RPC communicates only with the history keeper
|
||||||
|
messages have the format:
|
||||||
|
[TYPE, txid, msg]
|
||||||
|
*/
|
||||||
|
var sendMsg = function (ctx, type, msg, cb) {
|
||||||
|
var network = ctx.network;
|
||||||
|
var hkn = network.historyKeeper;
|
||||||
|
var txid = uid();
|
||||||
|
|
||||||
|
ctx.pending[txid] = cb;
|
||||||
|
|
||||||
|
return network.sendto(hkn, JSON.stringify([txid, type, msg]));
|
||||||
|
};
|
||||||
|
|
||||||
|
var parse = function (msg) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(msg);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returning messages have the format:
|
||||||
|
[txid, {}]
|
||||||
|
*/
|
||||||
|
var onMsg = function (ctx, msg) {
|
||||||
|
var parsed = parse(msg);
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
// TODO handle error
|
||||||
|
console.log(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txid = parsed[0];
|
||||||
|
var pending = ctx.pending[txid];
|
||||||
|
var response = parsed.slice(1);
|
||||||
|
|
||||||
|
if (typeof(pending) === 'function') {
|
||||||
|
if (response[0] === 'ERROR') {
|
||||||
|
return void pending(response[1]);
|
||||||
|
}
|
||||||
|
pending(void 0, response);
|
||||||
|
} else {
|
||||||
|
console.log("No callback provided");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var cookie = function (ctx, cb) {
|
||||||
|
// TODO txid
|
||||||
|
};
|
||||||
|
|
||||||
|
var signMsg = function (msg, secKey) {
|
||||||
|
// TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
var create = function (network, edPrivateKey) {
|
||||||
|
if (!/[0-9a-f]{64}/.test(edPrivateKey)) {
|
||||||
|
//throw new Error("private signing key is not valid");
|
||||||
|
}
|
||||||
|
var ctx = {
|
||||||
|
//privateKey: Encode.hexToUint8Array(edPrivateKey),
|
||||||
|
seq: new Date().getTime(),
|
||||||
|
network: network,
|
||||||
|
timeouts: {}, // timeouts
|
||||||
|
pending: {}, // callbacks
|
||||||
|
};
|
||||||
|
|
||||||
|
var pin = function (channel, cb) { };
|
||||||
|
|
||||||
|
var send = function (type, msg, cb) {
|
||||||
|
return sendMsg(ctx, type, msg, cb);
|
||||||
|
};
|
||||||
|
network.on('message', function (msg, sender) {
|
||||||
|
onMsg(ctx, msg);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
cookie: function (cb) { cookie(ctx, cb); },
|
||||||
|
send: send,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return { create: create };
|
||||||
|
});
|
||||||
13
www/examples/rpc/index.html
Normal file
13
www/examples/rpc/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="cp slide">
|
||||||
|
<head>
|
||||||
|
<title>CryptPad</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="iframe-container">
|
||||||
|
<iframe id="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
8
www/examples/rpc/inner.html
Normal file
8
www/examples/rpc/inner.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>PEWPEW
|
||||||
35
www/examples/rpc/main.js
Normal file
35
www/examples/rpc/main.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
|
||||||
|
define([
|
||||||
|
'/common/cryptpad-common.js',
|
||||||
|
'/common/rpc.js',
|
||||||
|
'/bower_components/jquery/dist/jquery.min.js',
|
||||||
|
], function (Cryptpad, RPC) {
|
||||||
|
var $ = window.jQuery;
|
||||||
|
var APP = window.APP = {
|
||||||
|
Cryptpad: Cryptpad,
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
Cryptpad.ready(function (err, env) {
|
||||||
|
var network = Cryptpad.getNetwork();
|
||||||
|
var rpc = RPC.create(network); // TODO signing key
|
||||||
|
|
||||||
|
var payload = {
|
||||||
|
a: Math.floor(Math.random() * 1000),
|
||||||
|
b: 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log(payload);
|
||||||
|
rpc.send('ECHO', payload, function (e, msg) {
|
||||||
|
if (e) { return void console.error(e); }
|
||||||
|
console.log(msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
// test a non-existent RPC call
|
||||||
|
rpc.send('PEWPEW', ['pew'], function (e, msg) {
|
||||||
|
if (e) { return void console.error(e); }
|
||||||
|
console.log(msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user