Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging
This commit is contained in:
commit
a530776ba8
@ -4,7 +4,7 @@ define([
|
|||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/outer/network-config.js',
|
'/common/outer/network-config.js',
|
||||||
'/customize/credential.js',
|
'/common/common-credential.js',
|
||||||
'/bower_components/chainpad/chainpad.dist.js',
|
'/bower_components/chainpad/chainpad.dist.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
;(function () { 'use strict';
|
;(function () { 'use strict';
|
||||||
|
|
||||||
const nThen = require('nthen');
|
const nThen = require('nthen');
|
||||||
const Nacl = require('tweetnacl');
|
const Nacl = require('tweetnacl/nacl-fast');
|
||||||
const Crypto = require('crypto');
|
const Crypto = require('crypto');
|
||||||
const Once = require("./lib/once");
|
const Once = require("./lib/once");
|
||||||
const Meta = require("./lib/metadata");
|
const Meta = require("./lib/metadata");
|
||||||
|
|||||||
@ -4,7 +4,7 @@ var nThen = require("nthen");
|
|||||||
|
|
||||||
var Util = require("../../www/common/common-util");
|
var Util = require("../../www/common/common-util");
|
||||||
|
|
||||||
var Nacl = require("tweetnacl");
|
var Nacl = require("tweetnacl/nacl-fast");
|
||||||
|
|
||||||
var Client = module.exports;
|
var Client = module.exports;
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,10 @@ var deduplicate = require("./deduplicate");
|
|||||||
|
|
||||||
var commands = {};
|
var commands = {};
|
||||||
|
|
||||||
|
var isValidOwner = function (owner) {
|
||||||
|
return typeof(owner) === 'string' && owner.length === 44;
|
||||||
|
};
|
||||||
|
|
||||||
// ["ADD_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623438989]
|
// ["ADD_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623438989]
|
||||||
commands.ADD_OWNERS = function (meta, args) {
|
commands.ADD_OWNERS = function (meta, args) {
|
||||||
// bail out if args isn't an array
|
// bail out if args isn't an array
|
||||||
@ -30,6 +34,7 @@ commands.ADD_OWNERS = function (meta, args) {
|
|||||||
|
|
||||||
var changed = false;
|
var changed = false;
|
||||||
args.forEach(function (owner) {
|
args.forEach(function (owner) {
|
||||||
|
if (!isValidOwner(owner)) { return; }
|
||||||
if (meta.owners.indexOf(owner) >= 0) { return; }
|
if (meta.owners.indexOf(owner) >= 0) { return; }
|
||||||
meta.owners.push(owner);
|
meta.owners.push(owner);
|
||||||
changed = true;
|
changed = true;
|
||||||
@ -90,6 +95,7 @@ commands.ADD_PENDING_OWNERS = function (meta, args) {
|
|||||||
}
|
}
|
||||||
// or fill it
|
// or fill it
|
||||||
args.forEach(function (owner) {
|
args.forEach(function (owner) {
|
||||||
|
if (!isValidOwner(owner)) { return; }
|
||||||
if (meta.pending_owners.indexOf(owner) >= 0) { return; }
|
if (meta.pending_owners.indexOf(owner) >= 0) { return; }
|
||||||
meta.pending_owners.push(owner);
|
meta.pending_owners.push(owner);
|
||||||
changed = true;
|
changed = true;
|
||||||
@ -134,7 +140,7 @@ commands.RESET_OWNERS = function (meta, args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// overwrite the existing owners with the new one
|
// overwrite the existing owners with the new one
|
||||||
meta.owners = deduplicate(args);
|
meta.owners = deduplicate(args.filter(isValidOwner));
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
rpc.js
2
rpc.js
@ -1,7 +1,7 @@
|
|||||||
/*@flow*/
|
/*@flow*/
|
||||||
/*jshint esversion: 6 */
|
/*jshint esversion: 6 */
|
||||||
/* Use Nacl for checking signatures of messages */
|
/* Use Nacl for checking signatures of messages */
|
||||||
var Nacl = require("tweetnacl");
|
var Nacl = require("tweetnacl/nacl-fast");
|
||||||
|
|
||||||
/* globals Buffer*/
|
/* globals Buffer*/
|
||||||
/* globals process */
|
/* globals process */
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
const Fs = require('fs');
|
const Fs = require('fs');
|
||||||
const nThen = require('nthen');
|
const nThen = require('nthen');
|
||||||
const Pinned = require('./pinned');
|
const Pinned = require('./pinned');
|
||||||
const Nacl = require('tweetnacl');
|
const Nacl = require('tweetnacl/nacl-fast');
|
||||||
const Path = require('path');
|
const Path = require('path');
|
||||||
const Pins = require('../lib/pins');
|
const Pins = require('../lib/pins');
|
||||||
const Config = require('../lib/load-config');
|
const Config = require('../lib/load-config');
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* jshint esversion: 6, node: true */
|
/* jshint esversion: 6, node: true */
|
||||||
|
|
||||||
const Nacl = require('tweetnacl');
|
const Nacl = require('tweetnacl/nacl-fast');
|
||||||
|
|
||||||
const keyPair = Nacl.box.keyPair();
|
const keyPair = Nacl.box.keyPair();
|
||||||
console.log("You've just generated a new key pair for your support mailbox.");
|
console.log("You've just generated a new key pair for your support mailbox.");
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
var Client = require("../../lib/client/");
|
var Client = require("../../lib/client/");
|
||||||
var Crypto = require("../../www/bower_components/chainpad-crypto");
|
var Crypto = require("../../www/bower_components/chainpad-crypto");
|
||||||
var Mailbox = Crypto.Mailbox;
|
var Mailbox = Crypto.Mailbox;
|
||||||
var Nacl = require("tweetnacl");
|
var Nacl = require("tweetnacl/nacl-fast");
|
||||||
var nThen = require("nthen");
|
var nThen = require("nthen");
|
||||||
var Pinpad = require("../../www/common/pinpad");
|
var Pinpad = require("../../www/common/pinpad");
|
||||||
var Rpc = require("../../www/common/rpc");
|
var Rpc = require("../../www/common/rpc");
|
||||||
@ -388,6 +388,108 @@ nThen(function (w) {
|
|||||||
roster.add(data, w(function (err) {
|
roster.add(data, w(function (err) {
|
||||||
if (err) { return void console.error(err); }
|
if (err) { return void console.error(err); }
|
||||||
}));
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
role: "OWNER",
|
||||||
|
};
|
||||||
|
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.log("Members should not be able to add themselves as owners!");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Alice failed to promote herself to owner, as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
role: "ADMIN",
|
||||||
|
};
|
||||||
|
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.log("Members should not be able to add themselves as admins!");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Alice failed to promote herself to admin, as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
test: true,
|
||||||
|
};
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log("Unexpected error while describing an arbitrary attribute");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var state = alice.roster.getState();
|
||||||
|
|
||||||
|
var alice_state = state.members[alice.curveKeys.curvePublic];
|
||||||
|
//console.log(alice_state);
|
||||||
|
|
||||||
|
if (typeof(alice_state.test) !== 'boolean') {
|
||||||
|
console.error("Arbitrary boolean attribute was not set");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
test: null,
|
||||||
|
};
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
console.error("Expected removal of arbitrary attribute to be successfully applied");
|
||||||
|
console.log(alice.roster.getState());
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
notifications: null,
|
||||||
|
};
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Expected deletion of notifications channel to fail");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (err !== 'INVALID_NOTIFICATIONS') {
|
||||||
|
console.log("UNEXPECTED ERROR 1231241245");
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Deletion of notifications channel failed as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
displayName: null,
|
||||||
|
};
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Expected deletion of displayName to fail");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (err !== 'INVALID_DISPLAYNAME') {
|
||||||
|
console.log("UNEXPECTED ERROR 12352623465");
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Deletion of displayName failed as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
alice.roster.checkpoint(w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Members should not be able to send checkpoints!");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
console.error("checkpoint by member failed as expected");
|
||||||
|
}));
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
console.log("STATE =", JSON.stringify(oscar.roster.getState(), null, 2));
|
console.log("STATE =", JSON.stringify(oscar.roster.getState(), null, 2));
|
||||||
|
|
||||||
@ -399,10 +501,6 @@ nThen(function (w) {
|
|||||||
if (err) { return void console.log(err); }
|
if (err) { return void console.log(err); }
|
||||||
console.log("STATE =", JSON.stringify(oscar.roster.getState(), null, 2));
|
console.log("STATE =", JSON.stringify(oscar.roster.getState(), null, 2));
|
||||||
}));
|
}));
|
||||||
}).nThen(function () {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
// oscar sends a checkpoint
|
// oscar sends a checkpoint
|
||||||
oscar.roster.checkpoint(w(function (err) {
|
oscar.roster.checkpoint(w(function (err) {
|
||||||
@ -427,6 +525,50 @@ nThen(function (w) {
|
|||||||
}
|
}
|
||||||
console.log("Promoted Alice to ADMIN");
|
console.log("Promoted Alice to ADMIN");
|
||||||
}));
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[bob.curveKeys.curvePublic] = {
|
||||||
|
notifications: Hash.createChannelId(),
|
||||||
|
displayName: "BORB",
|
||||||
|
};
|
||||||
|
|
||||||
|
alice.roster.add(data, w(function (err) {
|
||||||
|
if (err === 'ALREADY_PRESENT' || err === 'NO_CHANGE') {
|
||||||
|
return void console.log("Duplicate add command failed as expected");
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
console.error("Unexpected error", err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (!err) {
|
||||||
|
console.log("Duplicate add succeeded unexpectedly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
alice.roster.checkpoint(w(function (err) {
|
||||||
|
if (!err) { return; }
|
||||||
|
console.error("Checkpoint by an admin failed unexpectedly");
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
oscar.roster.checkpoint(w(function (err) {
|
||||||
|
if (!err) { return; }
|
||||||
|
console.error("Checkpoint by an owner failed unexpectedly");
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
alice.roster.remove([
|
||||||
|
oscar.curveKeys.curvePublic,
|
||||||
|
], w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Removal of owner by admin succeeded unexpectedly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Removal of owner by admin failed as expected");
|
||||||
|
}));
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
// bob finally connects, this time with the lastKnownHash provided by oscar
|
// bob finally connects, this time with the lastKnownHash provided by oscar
|
||||||
var rosterKeys = Crypto.Team.deriveMemberKeys(sharedConfig.rosterSeed, bob.curveKeys);
|
var rosterKeys = Crypto.Team.deriveMemberKeys(sharedConfig.rosterSeed, bob.curveKeys);
|
||||||
@ -455,16 +597,123 @@ nThen(function (w) {
|
|||||||
roster.stop();
|
roster.stop();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var bogus = {};
|
||||||
|
var curveKeys = makeCurveKeys();
|
||||||
|
bogus[curveKeys.curvePublic] = {
|
||||||
|
displayName: "chewbacca",
|
||||||
|
notifications: Hash.createChannelId(),
|
||||||
|
};
|
||||||
|
bob.roster.add(bogus, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Expected 'add' by member to fail");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("'add' by member failed as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
bob.roster.remove([
|
||||||
|
alice.curveKeys.curvePublic,
|
||||||
|
], w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Removal of admin by member succeeded unexpectedly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Removal of admin by member failed as expected");
|
||||||
|
}));
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
bob.roster.remove([
|
bob.roster.remove([
|
||||||
oscar.curveKeys.curvePublic,
|
oscar.curveKeys.curvePublic,
|
||||||
alice.curveKeys.curvePublic
|
//alice.curveKeys.curvePublic
|
||||||
], w(function (err) {
|
], w(function (err) {
|
||||||
if (err) { return void console.log("command failed as expected"); }
|
if (err) { return void console.log("command failed as expected"); }
|
||||||
w.abort();
|
w.abort();
|
||||||
console.log("Expected command to fail!");
|
console.log("Expected command to fail!");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}));
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[bob.curveKeys.curvePublic] = {
|
||||||
|
displayName: 'BORB',
|
||||||
|
};
|
||||||
|
|
||||||
|
bob.roster.describe(data, w(function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("self-description by a member failed unexpectedly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[oscar.curveKeys.curvePublic] = {
|
||||||
|
displayName: 'NULL',
|
||||||
|
};
|
||||||
|
|
||||||
|
bob.roster.describe(data, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("description of an owner by a member succeeded unexpectedly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("description of an owner by a member failed as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[alice.curveKeys.curvePublic] = {
|
||||||
|
displayName: 'NULL',
|
||||||
|
};
|
||||||
|
|
||||||
|
bob.roster.describe(data, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("description of an admin by a member succeeded unexpectedly");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("description of an admin by a member failed as expected");
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var data = {};
|
||||||
|
data[bob.curveKeys.curvePublic] = {
|
||||||
|
displayName: "NULL",
|
||||||
|
};
|
||||||
|
|
||||||
|
alice.roster.describe(data, w(function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("Description of member by admin failed unexpectedly");
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
alice.roster.metadata({
|
||||||
|
name: "BEST TEAM",
|
||||||
|
topic: "Champions de monde!",
|
||||||
|
cheese: "Camembert",
|
||||||
|
}, w(function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("Metadata change by admin failed unexpectedly");
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
bob.roster.metadata({
|
||||||
|
name: "WORST TEAM",
|
||||||
|
topic: "not a good team",
|
||||||
|
}, w(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
console.error("Metadata change by member should have failed");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
oscar.roster.metadata({
|
||||||
|
cheese: null, // delete a field that you don't want presenet
|
||||||
|
}, w(function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
alice.roster.remove([bob.curveKeys.curvePublic], w(function (err) {
|
alice.roster.remove([bob.curveKeys.curvePublic], w(function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
var Fs = require("fs");
|
var Fs = require("fs");
|
||||||
var Fse = require("fs-extra");
|
var Fse = require("fs-extra");
|
||||||
var Path = require("path");
|
var Path = require("path");
|
||||||
var nacl = require("tweetnacl");
|
var nacl = require("tweetnacl/nacl-fast");
|
||||||
var nThen = require("nthen");
|
var nThen = require("nthen");
|
||||||
|
|
||||||
var Tasks = module.exports;
|
var Tasks = module.exports;
|
||||||
|
|||||||
@ -92,8 +92,10 @@
|
|||||||
* {
|
* {
|
||||||
max-width:100%;
|
max-width:100%;
|
||||||
}
|
}
|
||||||
iframe[type="application/pdf"] {
|
iframe[src$=".pdf"] {
|
||||||
max-height:50vh;
|
width: 100%;
|
||||||
|
height: 80vh;
|
||||||
|
max-height: 90vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.markdown_main();
|
.markdown_main();
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
define([
|
(function () {
|
||||||
'/customize/application_config.js',
|
var factory = function (AppConfig, Scrypt) {
|
||||||
'/bower_components/scrypt-async/scrypt-async.min.js',
|
|
||||||
], function (AppConfig) {
|
|
||||||
var Cred = {};
|
var Cred = {};
|
||||||
var Scrypt = window.scrypt;
|
|
||||||
|
|
||||||
Cred.MINIMUM_PASSWORD_LENGTH = typeof(AppConfig.minimumPasswordLength) === 'number'?
|
Cred.MINIMUM_PASSWORD_LENGTH = typeof(AppConfig.minimumPasswordLength) === 'number'?
|
||||||
AppConfig.minimumPasswordLength: 8;
|
AppConfig.minimumPasswordLength: 8;
|
||||||
@ -86,4 +83,19 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
return Cred;
|
return Cred;
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (typeof(module) !== 'undefined' && module.exports) {
|
||||||
|
module.exports = factory(
|
||||||
|
{}, //require("../../customize.dist/application_config.js"),
|
||||||
|
require("../bower_components/scrypt-async/scrypt-async.min.js")
|
||||||
|
);
|
||||||
|
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||||
|
define([
|
||||||
|
'/customize/application_config.js',
|
||||||
|
'/bower_components/scrypt-async/scrypt-async.min.js',
|
||||||
|
], function (AppConfig) {
|
||||||
|
return factory(AppConfig, window.scrypt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}());
|
||||||
@ -530,7 +530,7 @@ Version 1
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (typeof(module) !== 'undefined' && module.exports) {
|
if (typeof(module) !== 'undefined' && module.exports) {
|
||||||
module.exports = factory(require("./common-util"), require("chainpad-crypto"), require("tweetnacl"));
|
module.exports = factory(require("./common-util"), require("chainpad-crypto"), require("tweetnacl/nacl-fast"));
|
||||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||||
define([
|
define([
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
|
|||||||
@ -5,6 +5,10 @@
|
|||||||
window.atob = window.atob || function (str) { return Buffer.from(str, 'base64').toString('binary'); }; // jshint ignore:line
|
window.atob = window.atob || function (str) { return Buffer.from(str, 'base64').toString('binary'); }; // jshint ignore:line
|
||||||
window.btoa = window.btoa || function (str) { return new Buffer(str, 'binary').toString('base64'); }; // jshint ignore:line
|
window.btoa = window.btoa || function (str) { return new Buffer(str, 'binary').toString('base64'); }; // jshint ignore:line
|
||||||
|
|
||||||
|
Util.slice = function (A, start, end) {
|
||||||
|
return Array.prototype.slice.call(A, start, end);
|
||||||
|
};
|
||||||
|
|
||||||
Util.bake = function (f, args) {
|
Util.bake = function (f, args) {
|
||||||
if (typeof(args) === 'undefined') { args = []; }
|
if (typeof(args) === 'undefined') { args = []; }
|
||||||
if (!Array.isArray(args)) { args = [args]; }
|
if (!Array.isArray(args)) { args = [args]; }
|
||||||
@ -265,7 +269,7 @@
|
|||||||
var to;
|
var to;
|
||||||
var g = function () {
|
var g = function () {
|
||||||
window.clearTimeout(to);
|
window.clearTimeout(to);
|
||||||
to = window.setTimeout(f, ms);
|
to = window.setTimeout(Util.bake(f, Util.slice(arguments)), ms);
|
||||||
};
|
};
|
||||||
return g;
|
return g;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1016,7 +1016,7 @@ define([
|
|||||||
var Cred, Block, Login;
|
var Cred, Block, Login;
|
||||||
Nthen(function (waitFor) {
|
Nthen(function (waitFor) {
|
||||||
require([
|
require([
|
||||||
'/customize/credential.js',
|
'/common/common-credential.js',
|
||||||
'/common/outer/login-block.js',
|
'/common/outer/login-block.js',
|
||||||
'/customize/login.js'
|
'/customize/login.js'
|
||||||
], waitFor(function (_Cred, _Block, _Login) {
|
], waitFor(function (_Cred, _Block, _Login) {
|
||||||
|
|||||||
95
www/common/outer/invitation.js
Normal file
95
www/common/outer/invitation.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
(function () {
|
||||||
|
var factory = function (Util, Cred, nThen) {
|
||||||
|
nThen = nThen; // XXX
|
||||||
|
var Invite = {};
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO key derivation
|
||||||
|
|
||||||
|
scrypt(seed, passwd) => {
|
||||||
|
curve: {
|
||||||
|
private,
|
||||||
|
public,
|
||||||
|
},
|
||||||
|
ed: {
|
||||||
|
private,
|
||||||
|
public,
|
||||||
|
}
|
||||||
|
cryptKey,
|
||||||
|
channel
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
var BYTES_REQUIRED = 256;
|
||||||
|
|
||||||
|
Invite.deriveKeys = function (seed, passwd, cb) {
|
||||||
|
cb = cb; // XXX
|
||||||
|
// TODO validate has cb
|
||||||
|
// TODO onceAsync the cb
|
||||||
|
// TODO cb with err if !(seed && passwd)
|
||||||
|
|
||||||
|
Cred.deriveFromPassphrase(seed, passwd, BYTES_REQUIRED, function (bytes) {
|
||||||
|
var dispense = Cred.dispenser(bytes);
|
||||||
|
dispense = dispense; // XXX
|
||||||
|
|
||||||
|
// edPriv => edPub
|
||||||
|
// curvePriv => curvePub
|
||||||
|
// channel
|
||||||
|
// cryptKey
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Invite.createSeed = function () {
|
||||||
|
// XXX
|
||||||
|
// return a seed
|
||||||
|
};
|
||||||
|
|
||||||
|
Invite.create = function (cb) {
|
||||||
|
cb = cb; // XXX
|
||||||
|
// TODO validate has cb
|
||||||
|
// TODO onceAsync the cb
|
||||||
|
// TODO cb with err if !(seed && passwd)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// required
|
||||||
|
// password
|
||||||
|
// validateKey
|
||||||
|
// creatorEdPublic
|
||||||
|
// for owner
|
||||||
|
// ephemeral
|
||||||
|
// signingKey
|
||||||
|
// for owner to write invitation
|
||||||
|
// derived
|
||||||
|
// edPriv
|
||||||
|
// edPublic
|
||||||
|
// for invitee ownership
|
||||||
|
// curvePriv
|
||||||
|
// curvePub
|
||||||
|
// for acceptance OR
|
||||||
|
// authenticated decline message via mailbox
|
||||||
|
// channel
|
||||||
|
// for owned deletion
|
||||||
|
// for team pinning
|
||||||
|
// cryptKey
|
||||||
|
// for protecting channel content
|
||||||
|
};
|
||||||
|
|
||||||
|
return Invite;
|
||||||
|
};
|
||||||
|
if (typeof(module) !== 'undefined' && module.exports) {
|
||||||
|
module.exports = factory(
|
||||||
|
require("../common-util"),
|
||||||
|
require("../common-credential.js"),
|
||||||
|
require("nthen")
|
||||||
|
);
|
||||||
|
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||||
|
define([
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/common-credential.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
], function (Util, Cred, nThen) {
|
||||||
|
return factory(Util, nThen);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}());
|
||||||
@ -171,6 +171,10 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
// if no role was provided, assume MEMBER
|
// if no role was provided, assume MEMBER
|
||||||
if (typeof(data.role) !== 'string') { data.role = 'MEMBER'; }
|
if (typeof(data.role) !== 'string') { data.role = 'MEMBER'; }
|
||||||
|
|
||||||
|
if (!canAddRole(author, data.role, members)) {
|
||||||
|
throw new Error("INSUFFICIENT_PERMISSIONS");
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof(data.displayName) !== 'string') { throw new Error("DISPLAYNAME_REQUIRED"); }
|
if (typeof(data.displayName) !== 'string') { throw new Error("DISPLAYNAME_REQUIRED"); }
|
||||||
if (typeof(data.notifications) !== 'string') { throw new Error("NOTIFICATIONS_REQUIRED"); }
|
if (typeof(data.notifications) !== 'string') { throw new Error("NOTIFICATIONS_REQUIRED"); }
|
||||||
});
|
});
|
||||||
@ -178,12 +182,9 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
var changed = false;
|
var changed = false;
|
||||||
// then iterate again and apply it
|
// then iterate again and apply it
|
||||||
Object.keys(args).forEach(function (curve) {
|
Object.keys(args).forEach(function (curve) {
|
||||||
var data = args[curve];
|
|
||||||
if (!canAddRole(author, data.role, members)) { return; }
|
|
||||||
|
|
||||||
// this will result in a change
|
// this will result in a change
|
||||||
changed = true;
|
changed = true;
|
||||||
members[curve] = data;
|
members[curve] = args[curve];
|
||||||
});
|
});
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
@ -241,11 +242,26 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
|
|
||||||
var current = Util.clone(members[curve]);
|
var current = Util.clone(members[curve]);
|
||||||
|
|
||||||
|
if (typeof(data.role) === 'string') { // they're trying to change the role...
|
||||||
|
// throw if they're trying to upgrade to something greater
|
||||||
|
if (!canAddRole(author, data.role, members)) { throw new Error("INSUFFICIENT_PERMISSIONS"); }
|
||||||
|
}
|
||||||
// DESCRIBE commands must initialize a displayName if it isn't already present
|
// DESCRIBE commands must initialize a displayName if it isn't already present
|
||||||
if (typeof(current.displayName) !== 'string' && typeof(data.displayName) !== 'string') { throw new Error('DISPLAYNAME_REQUIRED'); }
|
if (typeof(current.displayName) !== 'string' && typeof(data.displayName) !== 'string') {
|
||||||
|
throw new Error('DISPLAYNAME_REQUIRED');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['undefined', 'string'].indexOf(typeof(data.displayName)) === -1) {
|
||||||
|
throw new Error("INVALID_DISPLAYNAME");
|
||||||
|
}
|
||||||
|
|
||||||
// DESCRIBE commands must initialize a mailbox channel if it isn't already present
|
// DESCRIBE commands must initialize a mailbox channel if it isn't already present
|
||||||
if (typeof(current.notifications) !== 'string' && typeof(data.displayName) !== 'string') { throw new Error('NOTIFICATIONS_REQUIRED'); }
|
if (typeof(current.notifications) !== 'string' && typeof(data.notifications) !== 'string') {
|
||||||
|
throw new Error('NOTIFICATIONS_REQUIRED');
|
||||||
|
}
|
||||||
|
if (['undefined', 'string'].indexOf(typeof(data.notifications)) === -1) {
|
||||||
|
throw new Error("INVALID_NOTIFICATIONS");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var changed = false;
|
var changed = false;
|
||||||
@ -256,7 +272,9 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
var data = args[curve];
|
var data = args[curve];
|
||||||
|
|
||||||
Object.keys(data).forEach(function (key) {
|
Object.keys(data).forEach(function (key) {
|
||||||
if (current[key] === data[key]) { return; }
|
// when null is passed as new data and it wasn't considered an invalid change
|
||||||
|
// remove it from the map. This is how you delete things properly
|
||||||
|
if (typeof(current[key]) !== 'undefined' && data[key] === null) { return void delete current[key]; }
|
||||||
current[key] = data[key];
|
current[key] = data[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -305,6 +323,12 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var MANDATORY_METADATA_FIELDS = [
|
||||||
|
'avatar',
|
||||||
|
'name',
|
||||||
|
'topic',
|
||||||
|
];
|
||||||
|
|
||||||
// only admin/owner can change group metadata
|
// only admin/owner can change group metadata
|
||||||
commands.METADATA = function (args, author, roster) {
|
commands.METADATA = function (args, author, roster) {
|
||||||
if (!isMap(args)) { throw new Error("INVALID_ARGS"); }
|
if (!isMap(args)) { throw new Error("INVALID_ARGS"); }
|
||||||
@ -313,6 +337,11 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
|
|
||||||
// validate inputs
|
// validate inputs
|
||||||
Object.keys(args).forEach(function (k) {
|
Object.keys(args).forEach(function (k) {
|
||||||
|
if (args[k] === null) {
|
||||||
|
if (MANDATORY_METADATA_FIELDS.indexOf(k) === -1) { return; }
|
||||||
|
throw new Error('CANNOT_REMOVE_MANDATORY_METADATA');
|
||||||
|
}
|
||||||
|
|
||||||
// can't set metadata to anything other than strings
|
// can't set metadata to anything other than strings
|
||||||
// use empty string to unset a value if you must
|
// use empty string to unset a value if you must
|
||||||
if (typeof(args[k]) !== 'string') { throw new Error("INVALID_ARGUMENTS"); }
|
if (typeof(args[k]) !== 'string') { throw new Error("INVALID_ARGUMENTS"); }
|
||||||
@ -321,6 +350,11 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
var changed = false;
|
var changed = false;
|
||||||
// {topic, name, avatar} are all strings...
|
// {topic, name, avatar} are all strings...
|
||||||
Object.keys(args).forEach(function (k) {
|
Object.keys(args).forEach(function (k) {
|
||||||
|
if (typeof(roster.state.metadata[k]) !== 'undefined' && args[k] === null) {
|
||||||
|
changed = true;
|
||||||
|
delete roster.state.metadata[k];
|
||||||
|
}
|
||||||
|
|
||||||
// ignore things that won't cause changes
|
// ignore things that won't cause changes
|
||||||
if (args[k] === roster.state.metadata[k]) { return; }
|
if (args[k] === roster.state.metadata[k]) { return; }
|
||||||
|
|
||||||
@ -608,14 +642,19 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) {
|
|||||||
if (!isMap(_data)) { return void cb("INVALID_ARGUMENTS"); }
|
if (!isMap(_data)) { return void cb("INVALID_ARGUMENTS"); }
|
||||||
var data = Util.clone(_data);
|
var data = Util.clone(_data);
|
||||||
|
|
||||||
Object.keys(data).forEach(function (curve) {
|
if (Object.keys(data).some(function (curve) {
|
||||||
var member = data[curve];
|
var member = data[curve];
|
||||||
if (!isMap(member)) { delete data[curve]; }
|
if (!isMap(member)) { delete data[curve]; }
|
||||||
|
// validate that you're trying to describe a user that is present
|
||||||
|
if (!isMap(state.members[curve])) { return true; }
|
||||||
// don't send fields that won't result in a change
|
// don't send fields that won't result in a change
|
||||||
Object.keys(member).forEach(function (k) {
|
Object.keys(member).forEach(function (k) {
|
||||||
if (member[k] === state.members[curve][k]) { delete member[k]; }
|
if (member[k] === state.members[curve][k]) { delete member[k]; }
|
||||||
});
|
});
|
||||||
});
|
})) {
|
||||||
|
// returning true in the above loop indicates that something was invalid
|
||||||
|
return void cb("INVALID_ARGUMENTS");
|
||||||
|
}
|
||||||
|
|
||||||
send(['DESCRIBE', data], cb);
|
send(['DESCRIBE', data], cb);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -404,7 +404,7 @@ var factory = function (Util, Nacl) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (typeof(module) !== 'undefined' && module.exports) {
|
if (typeof(module) !== 'undefined' && module.exports) {
|
||||||
module.exports = factory(require("./common-util"), require("tweetnacl"));
|
module.exports = factory(require("./common-util"), require("tweetnacl/nacl-fast"));
|
||||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||||
define([
|
define([
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
|
|||||||
@ -3,7 +3,7 @@ define([
|
|||||||
'/customize/login.js',
|
'/customize/login.js',
|
||||||
'/common/cryptpad-common.js',
|
'/common/cryptpad-common.js',
|
||||||
'/common/test.js',
|
'/common/test.js',
|
||||||
'/customize/credential.js', // preloaded for login.js
|
'/common/common-credential.js',
|
||||||
'/common/common-interface.js',
|
'/common/common-interface.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
|
|||||||
@ -9,7 +9,7 @@ define([
|
|||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/common/hyperscript.js',
|
'/common/hyperscript.js',
|
||||||
'/customize/credential.js',
|
'/common/common-credential.js',
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'/common/make-backup.js',
|
'/common/make-backup.js',
|
||||||
|
|||||||
@ -236,6 +236,10 @@ define([
|
|||||||
APP.$rightside = $('<div>', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container);
|
APP.$rightside = $('<div>', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container);
|
||||||
var sFrameChan = common.getSframeChannel();
|
var sFrameChan = common.getSframeChannel();
|
||||||
sFrameChan.onReady(waitFor());
|
sFrameChan.onReady(waitFor());
|
||||||
|
common.getPinUsage(null, waitFor(function (err, data) {
|
||||||
|
if (err) { return void console.error(err); }
|
||||||
|
APP.pinUsage = data;
|
||||||
|
}));
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
createToolbar();
|
createToolbar();
|
||||||
metadataMgr = common.getMetadataMgr();
|
metadataMgr = common.getMetadataMgr();
|
||||||
@ -244,7 +248,7 @@ define([
|
|||||||
|
|
||||||
APP.origin = privateData.origin;
|
APP.origin = privateData.origin;
|
||||||
APP.readOnly = privateData.readOnly;
|
APP.readOnly = privateData.readOnly;
|
||||||
APP.support = Support.create(common, false);
|
APP.support = Support.create(common, false, APP.pinUsage);
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
var $rightside = APP.$rightside;
|
var $rightside = APP.$rightside;
|
||||||
|
|||||||
@ -25,6 +25,14 @@ define([
|
|||||||
edPublic: privateData.edPublic,
|
edPublic: privateData.edPublic,
|
||||||
notifications: user.notifications,
|
notifications: user.notifications,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (typeof(ctx.pinUsage) === 'object') {
|
||||||
|
// pass pin.usage, pin.limit, and pin.plan if supplied
|
||||||
|
Object.keys(ctx.pinUsage).forEach(function (k) {
|
||||||
|
data.sender[k] = ctx.pinUsage[k];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
data.id = id;
|
data.id = id;
|
||||||
data.time = +new Date();
|
data.time = +new Date();
|
||||||
|
|
||||||
@ -169,6 +177,8 @@ define([
|
|||||||
]);
|
]);
|
||||||
$(userData).click(function () {
|
$(userData).click(function () {
|
||||||
$(userData).find('pre').toggle();
|
$(userData).find('pre').toggle();
|
||||||
|
}).find('pre').click(function (ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
var name = Util.fixHTML(content.sender.name) || Messages.anonymous;
|
var name = Util.fixHTML(content.sender.name) || Messages.anonymous;
|
||||||
@ -202,11 +212,12 @@ define([
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
var create = function (common, isAdmin) {
|
var create = function (common, isAdmin, pinUsage) {
|
||||||
var ui = {};
|
var ui = {};
|
||||||
var ctx = {
|
var ctx = {
|
||||||
common: common,
|
common: common,
|
||||||
isAdmin: isAdmin
|
isAdmin: isAdmin,
|
||||||
|
pinUsage: pinUsage || false,
|
||||||
};
|
};
|
||||||
|
|
||||||
ui.sendForm = function (id, form, dest) {
|
ui.sendForm = function (id, form, dest) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user