diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js
index 72897680c..d4c1954e4 100644
--- a/www/common/application_config_internal.js
+++ b/www/common/application_config_internal.js
@@ -20,7 +20,7 @@ define(function() {
* users and these users will be redirected to the login page if they still try to access
* the app
*/
- config.registeredOnlyTypes = ['teams', 'file', 'contacts', 'oodoc', 'ooslide', 'sheet', 'notifications'];
+ config.registeredOnlyTypes = ['file', 'contacts', 'oodoc', 'ooslide', 'sheet', 'notifications'];
/* CryptPad is available is multiple languages, but only English and French are maintained
* by the developers. The other languages may be outdated, and any missing string for a langauge
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index 2fa3fb308..c67181574 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -1651,7 +1651,7 @@ define([
}),
h('br'),
linkMessage = h('textarea', {
- placeholder: 'note...'
+ placeholder: 'note...' // XXX
})
]),
linkSpin = h('div', {
@@ -1677,7 +1677,6 @@ define([
var hash = Hash.createRandomHash('invite', pw);
var hashData = Hash.parseTypeHash('invite', hash);
href = origin + '/teams/#' + hash;
- console.log(hashData);
if (!name || !name.trim()) {
$(linkError).text('empty name...').show(); // XXX
return true;
@@ -1707,7 +1706,7 @@ define([
password: pw,
message: msg,
bytes64: bytes64,
- href: href,
+ hash: hash,
teamId: config.teamId,
}, waitFor(function (obj) {
if (obj && obj.error) {
diff --git a/www/common/outer/team.js b/www/common/outer/team.js
index 3bb86cd4b..884c92598 100644
--- a/www/common/outer/team.js
+++ b/www/common/outer/team.js
@@ -1267,7 +1267,7 @@ define([
var name = data.name;
var password = data.password;
var msg = data.message;
- var href = data.href;
+ var hash = data.hash;
var bytes64 = data.bytes64;
*/
return void cb();
@@ -1277,6 +1277,20 @@ define([
});
*/
};
+ var getLinkData = function (ctx, data, cId, cb) {
+ /*
+ var password = data.password;
+ var hash = data.hash;
+ var bytes64 = data.bytes64;
+ */
+ return void cb();
+ /*
+ cb({
+ error: 'NOT_IMPLEMENTED'
+ });
+ */
+ };
+
Team.init = function (cfg, waitFor, emit) {
var team = {};
@@ -1434,6 +1448,9 @@ define([
if (cmd === 'CREATE_INVITE_LINK') {
return void createInviteLink(ctx, data, clientId, cb);
}
+ if (cmd === 'GET_LINK_DATA') {
+ return void getLinkData(ctx, data, clientId, cb);
+ }
};
return team;
diff --git a/www/teams/inner.js b/www/teams/inner.js
index 4ba4cf2f4..626f5ddcd 100644
--- a/www/teams/inner.js
+++ b/www/teams/inner.js
@@ -17,6 +17,7 @@ define([
'/common/messenger-ui.js',
'/customize/messages.js',
+ '/bower_components/scrypt-async/scrypt-async.min.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/teams/app-team.less',
@@ -42,6 +43,7 @@ define([
var APP = {};
var driveAPP = {};
//var SHARED_FOLDER_NAME = Messages.fm_sharedFolderName;
+ var Scrypt = window.scrypt;
var copyObjectValue = function (objRef, objToCopy) {
for (var k in objRef) { delete objRef[k]; }
@@ -137,6 +139,9 @@ define([
'general': [
'cp-team-info',
],
+ 'link': [
+ 'cp-team-link',
+ ],
};
var teamCategories = {
'back': {
@@ -179,8 +184,10 @@ define([
var $categories = $('
', {'class': 'cp-sidebarlayout-categories'})
.appendTo(APP.$leftside);
+ var hash = common.getMetadataMgr().getPrivateData().teamInviteHash;
+
var categories = team ? teamCategories : mainCategories;
- var active = team ? 'drive' : 'list';
+ var active = team ? 'drive' : (hash ? 'link' : 'list');
if (team && APP.team) {
var $category = $('
', {'class': 'cp-sidebarlayout-category cp-team-cat-header'}).appendTo($categories);
@@ -1012,6 +1019,90 @@ define([
]);
}, true);
+ makeBlock('link', function (common, cb) {
+ // XXX get team data first or login first?
+ if (!driveAPP.loggedIn) {
+ var anonLogin, anonRegister;
+ var anonContent = h('div', [
+ h('p', "You've been invited to a team. Only registered users can join a team. Login or register..."), // XXX
+ h('div', [
+ anonLogin = h('button.btn.btn-primary', Messages.login_login),
+ anonRegister = h('button.btn.btn-secondary', Messages.login_register),
+ ])
+ ]);
+ $(anonLogin).click(function () {
+ common.setLoginRedirect(function () {
+ common.gotoURL('/login/');
+ });
+ });
+ $(anonRegister).click(function () {
+ common.setLoginRedirect(function () {
+ common.gotoURL('/register/');
+ });
+ });
+ return void cb(anonContent);
+ }
+ var hash = common.getMetadataMgr().getPrivateData().teamInviteHash;
+ var hashData = Hash.parseTypeHash('invite', hash);
+ var password = hashData.password;
+
+ var div;
+
+ var process = function (pw) {
+ var $div = $(div);
+ $div.empty();
+ var bytes64;
+ nThen(function (waitFor) {
+ $div.append(h('div', [
+ h('i.fa.fa-spin.fa-spinner'),
+ h('span', 'Scrypt...') // XXX
+ ]));
+ setTimeout(waitFor(), 150);
+ }).nThen(function (waitFor) {
+ Scrypt(hashData.key,
+ (pw || '') + (AppConfig.loginSalt || ''), // salt
+ 8, // memoryCost (n)
+ 1024, // block size parameter (r)
+ 192, // dkLen
+ 200, // interruptStep
+ waitFor(function (_bytes) {
+ bytes64 = _bytes;
+ }),
+ 'base64'); // format, could be 'base64'
+ }).nThen(function (waitFor) {
+ APP.module.execCommand('GET_LINK_DATA', {
+ bytes64: bytes64,
+ hash: hash,
+ pw: pw,
+ }, waitFor(function () {
+ $div.empty();
+ // TODO
+ // Accept/decline/decide later UI
+ }));
+ });
+ };
+
+ var content = [];
+ if (password) {
+ // XXX XXX
+ content.push(h('p', "You've been invited to join a CryptPad Team, but the person who created the invitation protected it with a secret passphrase that they expect you to know."));
+ content.push(h('p', "Entering the correct phrase will decrypt the team's info and allow you to accept or decline the invitation."));
+ var pwInput = UI.passwordInput();
+ content.push(pwInput);
+ var submitPw = h('button.btn.btn-secondary', Messages.password_submit);
+ $(submitPw).click(function () {
+ var val = $(pwInput).find('input').val();
+ if (!val) { return; }
+ process(val);
+ });
+ content.push(submitPw);
+ }
+ div = h('div', content);
+ cb(div);
+
+ if (!password) { process(); }
+ });
+
var redrawTeam = function (common) {
if (!APP.team) { return; }
var teamId = APP.team;
@@ -1053,7 +1144,7 @@ define([
readOnly = driveAPP.readOnly = metadataMgr.getPrivateData().readOnly;
driveAPP.loggedIn = common.isLoggedIn();
- if (!driveAPP.loggedIn) { throw new Error('NOT_LOGGED_IN'); }
+ //if (!driveAPP.loggedIn) { throw new Error('NOT_LOGGED_IN'); }
common.setTabTitle(Messages.type.teams);
@@ -1103,6 +1194,22 @@ define([
onEvent: onEvent
});
+ var hash = privateData.teamInviteHash;
+ if (!hash && !driveAPP.loggedIn) {
+ UI.alert(Messages.mustLogin, function () {
+ common.setLoginRedirect(function () {
+ common.gotoURL('/login/');
+ });
+ }, {forefront: true});
+ return;
+ }
+ if (!hash) {
+ delete mainCategories.link;
+ } else if (!driveAPP.loggedIn) {
+ delete mainCategories.list;
+ delete mainCategories.create;
+ }
+
$('body').css('display', '');
loadMain(common);
diff --git a/www/teams/main.js b/www/teams/main.js
index f12308207..559e90c7c 100644
--- a/www/teams/main.js
+++ b/www/teams/main.js
@@ -37,6 +37,7 @@ define([
window.addEventListener('message', onMsg);
}).nThen(function (/*waitFor*/) {
var teamId;
+ var hash = window.location.hash.slice(1);
var addRpc = function (sframeChan, Cryptpad) {
sframeChan.on('Q_SET_TEAM', function (data, cb) {
teamId = data;
@@ -86,11 +87,23 @@ define([
}
});
};
+ var getSecrets = function (Cryptpad, Utils, cb) {
+ var Hash = Utils.Hash;
+ var hash = Hash.createRandomHash('profile');
+ var secret = Hash.getSecrets('team', hash);
+ cb(null, secret);
+ };
+ var addData = function (meta) {
+ if (!hash) { return; }
+ meta.teamInviteHash = hash;
+ };
SFCommonO.start({
+ getSecrets: getSecrets,
noHash: true,
noRealtime: true,
//driveEvents: true,
addRpc: addRpc,
+ addData: addData,
isDrive: true, // Used for history...
});
});