Merge branch 'sfPassword' into ro
This commit is contained in:
commit
b2f89e289d
@ -118,6 +118,16 @@ define([], function () {
|
|||||||
#cp-loading-password-prompt .cp-password-form button:hover {
|
#cp-loading-password-prompt .cp-password-form button:hover {
|
||||||
background-color: #326599;
|
background-color: #326599;
|
||||||
}
|
}
|
||||||
|
#cp-loading-password-prompt ::placeholder {
|
||||||
|
color: #d9d9d9;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt :-ms-input-placeholder {
|
||||||
|
color: #d9d9d9;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt ::-ms-input-placeholder {
|
||||||
|
color: #d9d9d9;
|
||||||
|
}
|
||||||
#cp-loading .cp-loading-spinner-container {
|
#cp-loading .cp-loading-spinner-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
|
|||||||
@ -116,7 +116,7 @@
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog, .alert {
|
.dialog {
|
||||||
& > div {
|
& > div {
|
||||||
background-color: @alertify-dialog-bg;
|
background-color: @alertify-dialog-bg;
|
||||||
&.half {
|
&.half {
|
||||||
@ -205,6 +205,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||||
|
color: darken(@alertify-input-fg, 15%);
|
||||||
|
opacity: 1; /* Firefox */
|
||||||
|
}
|
||||||
|
:-ms-input-placeholder { /* Internet Explorer 10-11 */
|
||||||
|
color: darken(@alertify-input-fg, 15%);
|
||||||
|
}
|
||||||
|
::-ms-input-placeholder { /* Microsoft Edge */
|
||||||
|
color: darken(@alertify-input-fg, 15%);
|
||||||
|
}
|
||||||
input:not(.form-control), textarea {
|
input:not(.form-control), textarea {
|
||||||
background-color: @alertify-input-bg;
|
background-color: @alertify-input-bg;
|
||||||
color: @alertify-input-fg;
|
color: @alertify-input-fg;
|
||||||
|
|||||||
@ -18,5 +18,10 @@
|
|||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
|
||||||
|
.cp-support-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -170,10 +170,36 @@ define([
|
|||||||
var supportKey = ApiConfig.supportMailbox;
|
var supportKey = ApiConfig.supportMailbox;
|
||||||
create['support-list'] = function () {
|
create['support-list'] = function () {
|
||||||
if (!supportKey || !APP.privateKey) { return; }
|
if (!supportKey || !APP.privateKey) { return; }
|
||||||
var $div = makeBlock('support-list');
|
var $container = makeBlock('support-list');
|
||||||
$div.addClass('cp-support-container');
|
var $div = $(h('div.cp-support-container')).appendTo($container);
|
||||||
var hashesById = {};
|
var hashesById = {};
|
||||||
|
|
||||||
|
var reorder = function () {
|
||||||
|
var order = Object.keys(hashesById);
|
||||||
|
order.sort(function (id1, id2) {
|
||||||
|
var t1 = hashesById[id1];
|
||||||
|
var t2 = hashesById[id2];
|
||||||
|
if (!Array.isArray(t1)) { return 1; }
|
||||||
|
if (!Array.isArray(t2)) { return -1; }
|
||||||
|
var lastMsg1 = t1[t1.length - 1];
|
||||||
|
var lastMsg2 = t2[t2.length - 1];
|
||||||
|
var time1 = Util.find(lastMsg1, ['content', 'msg', 'content', 'time']);
|
||||||
|
var time2 = Util.find(lastMsg2, ['content', 'msg', 'content', 'time']);
|
||||||
|
var authorEd1 = Util.find(lastMsg1, ['content', 'msg', 'content', 'sender', 'edPublic']);
|
||||||
|
var authorEd2 = Util.find(lastMsg2, ['content', 'msg', 'content', 'sender', 'edPublic']);
|
||||||
|
var admin1 = ApiConfig.adminKeys.indexOf(authorEd1) !== -1;
|
||||||
|
var admin2 = ApiConfig.adminKeys.indexOf(authorEd2) !== -1;
|
||||||
|
// If one is answered and not the other, put the unanswered first
|
||||||
|
if (admin1 && !admin2) { return 1; }
|
||||||
|
if (!admin1 && admin2) { return -1; }
|
||||||
|
// Otherwise, sort them by time
|
||||||
|
return time2 - time1;
|
||||||
|
});
|
||||||
|
order.forEach(function (id, i) {
|
||||||
|
$div.find('[data-id="'+id+'"]').css('order', i);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Register to the "support" mailbox
|
// Register to the "support" mailbox
|
||||||
common.mailbox.subscribe(['supportadmin'], {
|
common.mailbox.subscribe(['supportadmin'], {
|
||||||
onMessage: function (data) {
|
onMessage: function (data) {
|
||||||
@ -219,11 +245,13 @@ define([
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
$ticket.append(APP.support.makeMessage(content, hash));
|
$ticket.append(APP.support.makeMessage(content, hash));
|
||||||
|
reorder();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return $div;
|
return $container;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var checkAdminKey = function (priv) {
|
var checkAdminKey = function (priv) {
|
||||||
if (!supportKey) { return; }
|
if (!supportKey) { return; }
|
||||||
return Hash.checkBoxKeyPair(priv, supportKey);
|
return Hash.checkBoxKeyPair(priv, supportKey);
|
||||||
|
|||||||
@ -147,16 +147,24 @@ define(function() {
|
|||||||
// Workers allow us to run the websockets connection and open the user drive in a separate thread.
|
// Workers allow us to run the websockets connection and open the user drive in a separate thread.
|
||||||
// SharedWorkers allow us to load only one websocket and one user drive for all the browser tabs,
|
// SharedWorkers allow us to load only one websocket and one user drive for all the browser tabs,
|
||||||
// making it much faster to open new tabs.
|
// making it much faster to open new tabs.
|
||||||
// Warning: This is an experimental feature. It will be enabled by default once we're sure it's stable.
|
|
||||||
config.disableWorkers = false;
|
config.disableWorkers = false;
|
||||||
|
|
||||||
// Shared folder are in a beta-test state. They are likely to disappear from a user's drive
|
|
||||||
// spontaneously, resulting in the deletion of the entire folder's content.
|
|
||||||
// We highly recommend to keep them disabled until they are stable enough to be enabled
|
|
||||||
// by default by the CryptPad developers.
|
|
||||||
config.disableSharedFolders = false;
|
|
||||||
|
|
||||||
config.surveyURL = "https://survey.cryptpad.fr/index.php/672782";
|
config.surveyURL = "https://survey.cryptpad.fr/index.php/672782";
|
||||||
|
|
||||||
|
// Teams are always loaded during the initial loading screen (for the first tab only if
|
||||||
|
// SharedWorkers are available). Allowing users to be members of multiple teams can
|
||||||
|
// make them have a very slow loading time. To avoid impacting the user experience
|
||||||
|
// significantly, we're limiting the number of teams per user to 3 by default.
|
||||||
|
// You can change this value here.
|
||||||
|
//config.maxTeamsSlots = 3;
|
||||||
|
|
||||||
|
// Each team is considered as a registered user by the server. Users and teams are indistinguishable
|
||||||
|
// in the database so teams will offer the same storage limits as users by default.
|
||||||
|
// It means that each team created by a user can increase their storage limit by +100%.
|
||||||
|
// We're limiting the number of teams each user is able to own to 1 in order to make sure
|
||||||
|
// users don't use "fake" teams (1 member) just to increase their storage limit.
|
||||||
|
// You can change the value here.
|
||||||
|
// config.maxTeamsOwned = 1;
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
define(function () {
|
define(['/customize/application_config.js'], function (AppConfig) {
|
||||||
return {
|
return {
|
||||||
// localStorage
|
// localStorage
|
||||||
userHashKey: 'User_hash',
|
userHashKey: 'User_hash',
|
||||||
@ -16,7 +16,8 @@ define(function () {
|
|||||||
tokenKey: 'loginToken',
|
tokenKey: 'loginToken',
|
||||||
displayPadCreationScreen: 'displayPadCreationScreen',
|
displayPadCreationScreen: 'displayPadCreationScreen',
|
||||||
deprecatedKey: 'deprecated',
|
deprecatedKey: 'deprecated',
|
||||||
MAX_TEAMS_SLOTS: 3,
|
MAX_TEAMS_SLOTS: AppConfig.maxTeamsSlots || 3,
|
||||||
|
MAX_TEAMS_OWNED: AppConfig.maxTeamsOwned || 1,
|
||||||
// Sub
|
// Sub
|
||||||
plan: 'CryptPad_plan',
|
plan: 'CryptPad_plan',
|
||||||
// Apps
|
// Apps
|
||||||
|
|||||||
@ -548,6 +548,7 @@ define([
|
|||||||
var sframeChan = common.getSframeChannel();
|
var sframeChan = common.getSframeChannel();
|
||||||
var changePwTitle = Messages.properties_changePassword;
|
var changePwTitle = Messages.properties_changePassword;
|
||||||
var changePwConfirm = Messages.properties_confirmChange;
|
var changePwConfirm = Messages.properties_confirmChange;
|
||||||
|
var isSharedFolder = parsed.type === 'drive';
|
||||||
if (!hasPassword) {
|
if (!hasPassword) {
|
||||||
changePwTitle = Messages.properties_addPassword;
|
changePwTitle = Messages.properties_addPassword;
|
||||||
changePwConfirm = Messages.properties_confirmNew;
|
changePwConfirm = Messages.properties_confirmNew;
|
||||||
@ -577,6 +578,7 @@ define([
|
|||||||
password: newPass
|
password: newPass
|
||||||
}, function (err, data) {
|
}, function (err, data) {
|
||||||
if (err || data.error) {
|
if (err || data.error) {
|
||||||
|
console.error(err || data.error);
|
||||||
return void UI.alert(Messages.properties_passwordError);
|
return void UI.alert(Messages.properties_passwordError);
|
||||||
}
|
}
|
||||||
UI.findOKButton().click();
|
UI.findOKButton().click();
|
||||||
@ -589,7 +591,9 @@ define([
|
|||||||
}, {force: true});
|
}, {force: true});
|
||||||
}
|
}
|
||||||
return void UI.alert(Messages.properties_passwordSuccess, function () {
|
return void UI.alert(Messages.properties_passwordSuccess, function () {
|
||||||
common.gotoURL(hasPassword && newPass ? undefined : (data.href || data.roHref));
|
if (!isSharedFolder) {
|
||||||
|
common.gotoURL(hasPassword && newPass ? undefined : (data.href || data.roHref));
|
||||||
|
}
|
||||||
}, {force: true});
|
}, {force: true});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -2564,7 +2568,7 @@ define([
|
|||||||
'target': '_blank',
|
'target': '_blank',
|
||||||
'rel': 'noopener',
|
'rel': 'noopener',
|
||||||
'href': AppConfig.surveyURL,
|
'href': AppConfig.surveyURL,
|
||||||
'class': 'fa fa-graduation-cap'
|
'class': 'cp-toolbar-survey fa fa-graduation-cap'
|
||||||
},
|
},
|
||||||
content: h('span', Messages.survey)
|
content: h('span', Messages.survey)
|
||||||
});
|
});
|
||||||
@ -2679,6 +2683,9 @@ define([
|
|||||||
window.parent.location = origin+'/admin/';
|
window.parent.location = origin+'/admin/';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$userAdmin.find('a.cp-toolbar-survey').click(function () {
|
||||||
|
Feedback.send('SURVEY_CLICKED');
|
||||||
|
});
|
||||||
$userAdmin.find('a.cp-toolbar-menu-profile').click(function () {
|
$userAdmin.find('a.cp-toolbar-menu-profile').click(function () {
|
||||||
if (padType) {
|
if (padType) {
|
||||||
window.open(origin+'/profile/');
|
window.open(origin+'/profile/');
|
||||||
|
|||||||
@ -869,13 +869,15 @@ define([
|
|||||||
}
|
}
|
||||||
var newHref = '/' + parsed.type + '/#' + newHash;
|
var newHref = '/' + parsed.type + '/#' + newHash;
|
||||||
|
|
||||||
|
var isSharedFolder = parsed.type === 'drive';
|
||||||
|
|
||||||
var optsGet = {};
|
var optsGet = {};
|
||||||
var optsPut = {
|
var optsPut = {
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
metadata: {}
|
metadata: {},
|
||||||
|
initialState: isSharedFolder ? '{}' : undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Nthen(function (waitFor) {
|
Nthen(function (waitFor) {
|
||||||
if (parsed.hashData && parsed.hashData.password) {
|
if (parsed.hashData && parsed.hashData.password) {
|
||||||
common.getPadAttribute('password', waitFor(function (err, password) {
|
common.getPadAttribute('password', waitFor(function (err, password) {
|
||||||
@ -935,7 +937,9 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var expire = oldMetadata.expire;
|
var expire = oldMetadata.expire;
|
||||||
optsPut.metadata.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds
|
if (expire) {
|
||||||
|
optsPut.metadata.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds
|
||||||
|
}
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
Crypt.get(parsed.hash, waitFor(function (err, val) {
|
Crypt.get(parsed.hash, waitFor(function (err, val) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -950,23 +954,22 @@ define([
|
|||||||
}), optsPut);
|
}), optsPut);
|
||||||
}), optsGet);
|
}), optsGet);
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
|
if (isSharedFolder) {
|
||||||
|
postMessage("UPDATE_SHARED_FOLDER_PASSWORD", {
|
||||||
|
href: href,
|
||||||
|
oldChannel: oldChannel,
|
||||||
|
password: newPassword
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
console.error(obj);
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
pad.leavePad({
|
pad.leavePad({
|
||||||
channel: oldChannel
|
channel: oldChannel
|
||||||
}, waitFor());
|
}, waitFor());
|
||||||
pad.onDisconnectEvent.fire(true);
|
pad.onDisconnectEvent.fire(true);
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
common.removeOwnedChannel({
|
// Set the new password to our pad data
|
||||||
channel: oldChannel,
|
|
||||||
teamId: teamId
|
|
||||||
}, waitFor(function (obj) {
|
|
||||||
if (obj && obj.error) {
|
|
||||||
waitFor.abort();
|
|
||||||
return void cb(obj);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
common.unpinPads([oldChannel], waitFor(), teamId);
|
|
||||||
common.pinPads([newSecret.channel], waitFor(), teamId);
|
|
||||||
}).nThen(function (waitFor) {
|
|
||||||
common.setPadAttribute('password', newPassword, waitFor(function (err) {
|
common.setPadAttribute('password', newPassword, waitFor(function (err) {
|
||||||
if (err) { warning = true; }
|
if (err) { warning = true; }
|
||||||
}), href);
|
}), href);
|
||||||
@ -983,6 +986,21 @@ define([
|
|||||||
common.setPadAttribute('href', newHref, waitFor(function (err) {
|
common.setPadAttribute('href', newHref, waitFor(function (err) {
|
||||||
if (err) { warning = true; }
|
if (err) { warning = true; }
|
||||||
}), href);
|
}), href);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// delete the old pad
|
||||||
|
common.removeOwnedChannel({
|
||||||
|
channel: oldChannel,
|
||||||
|
teamId: teamId
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb(obj);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if (!isSharedFolder) {
|
||||||
|
common.unpinPads([oldChannel], waitFor(), teamId);
|
||||||
|
common.pinPads([newSecret.channel], waitFor(), teamId);
|
||||||
|
}
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
cb({
|
cb({
|
||||||
warning: warning,
|
warning: warning,
|
||||||
|
|||||||
@ -3799,7 +3799,7 @@ define([
|
|||||||
if (manager.isSharedFolder(el)) {
|
if (manager.isSharedFolder(el)) {
|
||||||
delete data.roHref;
|
delete data.roHref;
|
||||||
//data.noPassword = true;
|
//data.noPassword = true;
|
||||||
data.noEditPassword = true;
|
//data.noEditPassword = true;
|
||||||
data.noExpiration = true;
|
data.noExpiration = true;
|
||||||
// this is here to allow users to check the channel id of a shared folder
|
// this is here to allow users to check the channel id of a shared folder
|
||||||
// we should remove it at some point
|
// we should remove it at some point
|
||||||
@ -4443,6 +4443,7 @@ define([
|
|||||||
refresh();
|
refresh();
|
||||||
UI.removeLoadingScreen();
|
UI.removeLoadingScreen();
|
||||||
|
|
||||||
|
/*
|
||||||
if (!APP.team) {
|
if (!APP.team) {
|
||||||
sframeChan.query('Q_DRIVE_GETDELETED', null, function (err, data) {
|
sframeChan.query('Q_DRIVE_GETDELETED', null, function (err, data) {
|
||||||
var ids = manager.findChannels(data);
|
var ids = manager.findChannels(data);
|
||||||
@ -4457,6 +4458,79 @@ define([
|
|||||||
UI.log(Messages._getKey('fm_deletedPads', [titles.join(', ')]));
|
UI.log(Messages._getKey('fm_deletedPads', [titles.join(', ')]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
var deprecated = files.sharedFoldersTemp;
|
||||||
|
var nt = nThen;
|
||||||
|
var passwordModal = function (fId, data, cb) {
|
||||||
|
var content = [];
|
||||||
|
var folderName = '<b>'+ (data.lastTitle || Messages.fm_newFolder) +'</b>';
|
||||||
|
content.push(UI.setHTML(h('p'), Messages._getKey('drive_sfPassword', [folderName])));
|
||||||
|
var newPassword = UI.passwordInput({
|
||||||
|
id: 'cp-app-prop-change-password',
|
||||||
|
placeholder: Messages.settings_changePasswordNew,
|
||||||
|
style: 'flex: 1;'
|
||||||
|
});
|
||||||
|
var passwordOk = h('button', Messages.properties_changePasswordButton);
|
||||||
|
var changePass = h('span.cp-password-container', [
|
||||||
|
newPassword,
|
||||||
|
passwordOk
|
||||||
|
]);
|
||||||
|
content.push(changePass);
|
||||||
|
var div = h('div', content);
|
||||||
|
|
||||||
|
var locked = false;
|
||||||
|
$(passwordOk).click(function () {
|
||||||
|
if (locked) { return; }
|
||||||
|
var pw = $(newPassword).find('.cp-password-input').val();
|
||||||
|
locked = true;
|
||||||
|
$(div).find('.alert').remove();
|
||||||
|
$(passwordOk).html('').append(h('span.fa.fa-spinner.fa-spin', {style: 'margin-left: 0'}));
|
||||||
|
manager.restoreSharedFolder(fId, pw, function (err, obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
var wrong = h('div.alert.alert-danger', Messages.drive_sfPasswordError);
|
||||||
|
$(div).prepend(wrong);
|
||||||
|
$(passwordOk).text(Messages.properties_changePasswordButton);
|
||||||
|
locked = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UI.findCancelButton($(div).closest('.alertify')).click();
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var buttons = [{
|
||||||
|
className: 'primary',
|
||||||
|
name: Messages.forgetButton,
|
||||||
|
onClick: function () {
|
||||||
|
manager.delete([['sharedFoldersTemp', fId]], function () { });
|
||||||
|
},
|
||||||
|
keys: []
|
||||||
|
}, {
|
||||||
|
className: 'cancel',
|
||||||
|
name: Messages.later,
|
||||||
|
onClick: function () {},
|
||||||
|
keys: [27]
|
||||||
|
}];
|
||||||
|
return UI.dialog.customModal(div, {
|
||||||
|
buttons: buttons,
|
||||||
|
onClose: cb
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (typeof (deprecated) === "object") {
|
||||||
|
Object.keys(deprecated).forEach(function (fId) {
|
||||||
|
var data = deprecated[fId];
|
||||||
|
var sfId = manager.user.userObject.getSFIdFromHref(data.href);
|
||||||
|
if (folders[fId] || sfId) { // This shared folder is already stored in the drive...
|
||||||
|
return void manager.delete([['sharedFoldersTemp', fId]], function () { });
|
||||||
|
}
|
||||||
|
nt = nt(function (waitFor) {
|
||||||
|
UI.openCustomModal(passwordModal(fId, data, waitFor()));
|
||||||
|
}).nThen;
|
||||||
|
});
|
||||||
|
nt(function () {
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
|
|||||||
@ -435,9 +435,14 @@
|
|||||||
return mediaObject;
|
return mediaObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaObject.tag.innerHTML = '<img style="width: 100px; height: 100px;">';
|
||||||
|
|
||||||
// Download the encrypted blob
|
// Download the encrypted blob
|
||||||
download(src, function (err, u8Encrypted) {
|
download(src, function (err, u8Encrypted) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
if (err === "XHR_ERROR 404") {
|
||||||
|
mediaObject.tag.innerHTML = '<img style="width: 100px; height: 100px;" src="/images/broken.png">';
|
||||||
|
}
|
||||||
return void emit('error', err);
|
return void emit('error', err);
|
||||||
}
|
}
|
||||||
// Decrypt the blob
|
// Decrypt the blob
|
||||||
|
|||||||
@ -95,9 +95,7 @@ define([
|
|||||||
if (msg.content.isTemplate) {
|
if (msg.content.isTemplate) {
|
||||||
common.sessionStorage.put(Constants.newPadPathKey, ['template'], waitFor());
|
common.sessionStorage.put(Constants.newPadPathKey, ['template'], waitFor());
|
||||||
}
|
}
|
||||||
if (msg.content.password) {
|
common.sessionStorage.put('newPadPassword', msg.content.password || '', waitFor());
|
||||||
common.sessionStorage.put('newPadPassword', msg.content.password, waitFor());
|
|
||||||
}
|
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
todo();
|
todo();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -453,7 +453,7 @@ define([
|
|||||||
|
|
||||||
Store.isNewChannel = function (clientId, data, cb) {
|
Store.isNewChannel = function (clientId, data, cb) {
|
||||||
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||||
var channelId = Hash.hrefToHexChannelId(data.href, data.password);
|
var channelId = data.channel || Hash.hrefToHexChannelId(data.href, data.password);
|
||||||
store.anon_rpc.send("IS_NEW_CHANNEL", channelId, function (e, response) {
|
store.anon_rpc.send("IS_NEW_CHANNEL", channelId, function (e, response) {
|
||||||
if (e) { return void cb({error: e}); }
|
if (e) { return void cb({error: e}); }
|
||||||
if (response && response.length && typeof(response[0]) === 'boolean') {
|
if (response && response.length && typeof(response[0]) === 'boolean') {
|
||||||
@ -1773,21 +1773,24 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
Store.loadSharedFolder = function (teamId, id, data, cb) {
|
Store.loadSharedFolder = function (teamId, id, data, cb, isNew) {
|
||||||
var s = getStore(teamId);
|
var s = getStore(teamId);
|
||||||
if (!s) { return void cb({ error: 'ENOTFOUND' }); }
|
if (!s) { return void cb({ error: 'ENOTFOUND' }); }
|
||||||
var rt = SF.load({
|
SF.load({
|
||||||
|
isNew: isNew,
|
||||||
network: store.network,
|
network: store.network,
|
||||||
store: s
|
store: s,
|
||||||
|
isNewChannel: Store.isNewChannel
|
||||||
}, id, data, cb);
|
}, id, data, cb);
|
||||||
return rt;
|
|
||||||
};
|
};
|
||||||
var loadSharedFolder = function (id, data, cb) {
|
var loadSharedFolder = function (id, data, cb, isNew) {
|
||||||
Store.loadSharedFolder(null, id, data, cb);
|
Store.loadSharedFolder(null, id, data, cb, isNew);
|
||||||
};
|
};
|
||||||
Store.loadSharedFolderAnon = function (clientId, data, cb) {
|
Store.loadSharedFolderAnon = function (clientId, data, cb) {
|
||||||
Store.loadSharedFolder(null, data.id, data.data, function () {
|
Store.loadSharedFolder(null, data.id, data.data, function (rt) {
|
||||||
cb();
|
cb({
|
||||||
|
error: rt ? undefined : 'EDELETED'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Store.addSharedFolder = function (clientId, data, cb) {
|
Store.addSharedFolder = function (clientId, data, cb) {
|
||||||
@ -1800,6 +1803,9 @@ define([
|
|||||||
cb(id);
|
cb(id);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
Store.updateSharedFolderPassword = function (clientId, data, cb) {
|
||||||
|
SF.updatePassword(Store, data, store.network, cb);
|
||||||
|
};
|
||||||
|
|
||||||
// Drive
|
// Drive
|
||||||
Store.userObjectCommand = function (clientId, cmdData, cb) {
|
Store.userObjectCommand = function (clientId, cmdData, cb) {
|
||||||
@ -1884,6 +1890,27 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
registerProxyEvents = function (proxy, fId) {
|
registerProxyEvents = function (proxy, fId) {
|
||||||
|
if (!fId) {
|
||||||
|
// Listen for shared folder password change
|
||||||
|
proxy.on('change', ['drive', UserObject.SHARED_FOLDERS], function (o, n, p) {
|
||||||
|
if (p.length > 3 && p[3] === 'password') {
|
||||||
|
var id = p[2];
|
||||||
|
var data = proxy.drive[UserObject.SHARED_FOLDERS][id];
|
||||||
|
var href = store.manager.user.userObject.getHref ?
|
||||||
|
store.manager.user.userObject.getHref(data) : data.href;
|
||||||
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, o);
|
||||||
|
SF.updatePassword({
|
||||||
|
oldChannel: secret.channel,
|
||||||
|
password: n,
|
||||||
|
href: href
|
||||||
|
}, store.network, function () {
|
||||||
|
console.log('Shared folder password changed');
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
proxy.on('change', [], function (o, n, p) {
|
proxy.on('change', [], function (o, n, p) {
|
||||||
if (fId) {
|
if (fId) {
|
||||||
// Pin the new pads
|
// Pin the new pads
|
||||||
@ -2035,6 +2062,7 @@ define([
|
|||||||
unpin: unpin,
|
unpin: unpin,
|
||||||
loadSharedFolder: loadSharedFolder,
|
loadSharedFolder: loadSharedFolder,
|
||||||
settings: proxy.settings,
|
settings: proxy.settings,
|
||||||
|
Store: Store
|
||||||
}, {
|
}, {
|
||||||
outer: true,
|
outer: true,
|
||||||
removeOwnedChannel: function (channel, cb) { Store.removeOwnedChannel('', channel, cb); },
|
removeOwnedChannel: function (channel, cb) { Store.removeOwnedChannel('', channel, cb); },
|
||||||
@ -2117,6 +2145,7 @@ define([
|
|||||||
proxy.settings.general.allowUserFeedback = true;
|
proxy.settings.general.allowUserFeedback = true;
|
||||||
}
|
}
|
||||||
returned.feedback = proxy.settings.general.allowUserFeedback;
|
returned.feedback = proxy.settings.general.allowUserFeedback;
|
||||||
|
Feedback.init(returned.feedback);
|
||||||
|
|
||||||
if (typeof(cb) === 'function') { cb(returned); }
|
if (typeof(cb) === 'function') { cb(returned); }
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,9 @@ define([
|
|||||||
var cb = Util.once(_cb);
|
var cb = Util.once(_cb);
|
||||||
var network = config.network;
|
var network = config.network;
|
||||||
var store = config.store;
|
var store = config.store;
|
||||||
var teamId = store.id || -1;
|
var isNew = config.isNew;
|
||||||
|
var isNewChannel = config.isNewChannel;
|
||||||
|
var teamId = store.id;
|
||||||
var handler = store.handleSharedFolder;
|
var handler = store.handleSharedFolder;
|
||||||
|
|
||||||
var href = store.manager.user.userObject.getHref(data);
|
var href = store.manager.user.userObject.getHref(data);
|
||||||
@ -76,85 +78,109 @@ define([
|
|||||||
var secret = Hash.getSecrets('drive', parsed.hash, data.password);
|
var secret = Hash.getSecrets('drive', parsed.hash, data.password);
|
||||||
var secondaryKey = secret.keys.secondaryKey;
|
var secondaryKey = secret.keys.secondaryKey;
|
||||||
|
|
||||||
var sf = allSharedFolders[secret.channel];
|
// If we try to load an existing shared folder (isNew === false) but this folder
|
||||||
if (sf && sf.readOnly && secondaryKey) {
|
// doesn't exist in the database, abort and cb
|
||||||
// We were in readOnly mode and now we know the edit keys!
|
nThen(function (waitFor) {
|
||||||
SF.upgrade(secret.channel, secret);
|
isNewChannel(null, { channel: secret.channel }, waitFor(function (obj) {
|
||||||
}
|
if (obj.isNew && !isNew) {
|
||||||
if (sf && sf.ready && sf.rt) {
|
store.manager.deprecateProxy(id, secret.channel);
|
||||||
// The shared folder is already loaded, return its data
|
waitFor.abort();
|
||||||
setTimeout(function () {
|
return void cb(null);
|
||||||
var leave = function () { SF.leave(secret.channel, teamId); };
|
}
|
||||||
var uo = store.manager.addProxy(id, sf.rt, leave, secondaryKey);
|
}));
|
||||||
SF.checkMigration(secondaryKey, sf.rt.proxy, uo, function () {
|
}).nThen(function () {
|
||||||
cb(sf.rt, sf.metadata);
|
var sf = allSharedFolders[secret.channel];
|
||||||
|
if (sf && sf.readOnly && secondaryKey) {
|
||||||
|
// We were in readOnly mode and now we know the edit keys!
|
||||||
|
SF.upgrade(secret.channel, secret);
|
||||||
|
}
|
||||||
|
if (sf && sf.ready && sf.rt) {
|
||||||
|
// The shared folder is already loaded, return its data
|
||||||
|
setTimeout(function () {
|
||||||
|
var leave = function () { SF.leave(secret.channel, teamId); };
|
||||||
|
var uo = store.manager.addProxy(id, sf.rt, leave, secondaryKey);
|
||||||
|
SF.checkMigration(secondaryKey, sf.rt.proxy, uo, function () {
|
||||||
|
cb(sf.rt, sf.metadata);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
sf.teams.push(store);
|
||||||
sf.team.push(teamId);
|
if (handler) { handler(id, sf.rt); }
|
||||||
if (handler) { handler(id, sf.rt); }
|
return sf.rt;
|
||||||
return sf.rt;
|
|
||||||
}
|
|
||||||
if (sf && sf.queue && sf.rt) {
|
|
||||||
// The shared folder is loading, add our callbacks to the queue
|
|
||||||
sf.queue.push({
|
|
||||||
cb: cb,
|
|
||||||
store: store,
|
|
||||||
id: id
|
|
||||||
});
|
|
||||||
sf.team.push(teamId);
|
|
||||||
if (handler) { handler(id, sf.rt); }
|
|
||||||
return sf.rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
sf = allSharedFolders[secret.channel] = {
|
|
||||||
queue: [{
|
|
||||||
cb: cb,
|
|
||||||
store: store,
|
|
||||||
id: id
|
|
||||||
}],
|
|
||||||
team: [store.id || -1],
|
|
||||||
readOnly: Boolean(secondaryKey)
|
|
||||||
};
|
|
||||||
|
|
||||||
var owners = data.owners;
|
|
||||||
var listmapConfig = {
|
|
||||||
data: {},
|
|
||||||
channel: secret.channel,
|
|
||||||
readOnly: Boolean(secondaryKey),
|
|
||||||
crypto: Crypto.createEncryptor(secret.keys),
|
|
||||||
userName: 'sharedFolder',
|
|
||||||
logLevel: 1,
|
|
||||||
ChainPad: ChainPad,
|
|
||||||
classic: true,
|
|
||||||
network: network,
|
|
||||||
metadata: {
|
|
||||||
validateKey: secret.keys.validateKey || undefined,
|
|
||||||
owners: owners
|
|
||||||
}
|
}
|
||||||
};
|
if (sf && sf.queue && sf.rt) {
|
||||||
var rt = sf.rt = Listmap.create(listmapConfig);
|
// The shared folder is loading, add our callbacks to the queue
|
||||||
rt.proxy.on('ready', function (info) {
|
sf.queue.push({
|
||||||
if (!Object.keys(rt.proxy).length) {
|
cb: cb,
|
||||||
// New Shared folder: no migration required
|
store: store,
|
||||||
rt.proxy.version = 2;
|
id: id
|
||||||
}
|
|
||||||
if (!sf.queue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sf.leave = info.leave;
|
|
||||||
sf.metadata = info.metadata;
|
|
||||||
sf.queue.forEach(function (obj) {
|
|
||||||
var leave = function () { SF.leave(secret.channel, teamId); };
|
|
||||||
var uo = obj.store.manager.addProxy(obj.id, rt, leave, secondaryKey);
|
|
||||||
SF.checkMigration(secondaryKey, rt.proxy, uo, function () {
|
|
||||||
obj.cb(sf.rt, sf.metadata);
|
|
||||||
});
|
});
|
||||||
|
sf.teams.push(store);
|
||||||
|
if (handler) { handler(id, sf.rt); }
|
||||||
|
return sf.rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf = allSharedFolders[secret.channel] = {
|
||||||
|
queue: [{
|
||||||
|
cb: cb,
|
||||||
|
store: store,
|
||||||
|
id: id
|
||||||
|
}],
|
||||||
|
teams: [store],
|
||||||
|
readOnly: Boolean(secondaryKey)
|
||||||
|
};
|
||||||
|
|
||||||
|
var owners = data.owners;
|
||||||
|
var listmapConfig = {
|
||||||
|
data: {},
|
||||||
|
channel: secret.channel,
|
||||||
|
readOnly: Boolean(secondaryKey),
|
||||||
|
crypto: Crypto.createEncryptor(secret.keys),
|
||||||
|
userName: 'sharedFolder',
|
||||||
|
logLevel: 1,
|
||||||
|
ChainPad: ChainPad,
|
||||||
|
classic: true,
|
||||||
|
network: network,
|
||||||
|
metadata: {
|
||||||
|
validateKey: secret.keys.validateKey || undefined,
|
||||||
|
owners: owners
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var rt = sf.rt = Listmap.create(listmapConfig);
|
||||||
|
rt.proxy.on('ready', function (info) {
|
||||||
|
if (isNew && !Object.keys(rt.proxy).length) {
|
||||||
|
// New Shared folder: no migration required
|
||||||
|
rt.proxy.version = 2;
|
||||||
|
}
|
||||||
|
if (!sf.queue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sf.queue.forEach(function (obj) {
|
||||||
|
var leave = function () { SF.leave(secret.channel, teamId); };
|
||||||
|
var uo = obj.store.manager.addProxy(obj.id, rt, leave, secondaryKey);
|
||||||
|
SF.checkMigration(secondaryKey, rt.proxy, uo, function () {
|
||||||
|
obj.cb(sf.rt, info.metadata);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
sf.metadata = info.metadata;
|
||||||
|
sf.ready = true;
|
||||||
|
delete sf.queue;
|
||||||
});
|
});
|
||||||
sf.ready = true;
|
rt.proxy.on('error', function (info) {
|
||||||
delete sf.queue;
|
if (info && info.error) {
|
||||||
|
if (info.error === "EDELETED" ) {
|
||||||
|
try {
|
||||||
|
// Deprecate the shared folder from each team
|
||||||
|
sf.teams.forEach(function (store) {
|
||||||
|
store.manager.deprecateProxy(id, secret.channel);
|
||||||
|
});
|
||||||
|
} catch (e) {}
|
||||||
|
delete allSharedFolders[secret.channel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (handler) { handler(id, rt); }
|
||||||
});
|
});
|
||||||
if (handler) { handler(id, rt); }
|
|
||||||
return rt;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SF.upgrade = function (channel, secret) {
|
SF.upgrade = function (channel, secret) {
|
||||||
@ -173,8 +199,14 @@ define([
|
|||||||
if (!sf) { return; }
|
if (!sf) { return; }
|
||||||
var clients = sf.teams;
|
var clients = sf.teams;
|
||||||
if (!Array.isArray(clients)) { return; }
|
if (!Array.isArray(clients)) { return; }
|
||||||
var idx = clients.indexOf(teamId);
|
var idx;
|
||||||
if (idx === -1) { return; }
|
clients.some(function (store, i) {
|
||||||
|
if (store.id === teamId) {
|
||||||
|
idx = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (typeof (idx) === "undefined") { return; }
|
||||||
// Remove the selected team
|
// Remove the selected team
|
||||||
clients.splice(idx, 1);
|
clients.splice(idx, 1);
|
||||||
|
|
||||||
@ -185,6 +217,38 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SF.updatePassword = function (Store, data, network, cb) {
|
||||||
|
var oldChannel = data.oldChannel;
|
||||||
|
var href = data.href;
|
||||||
|
var password = data.password;
|
||||||
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, password);
|
||||||
|
var sf = allSharedFolders[oldChannel];
|
||||||
|
if (!sf) { return void cb({ error: 'ENOTFOUND' }); }
|
||||||
|
if (sf.rt && sf.rt.stop) {
|
||||||
|
sf.rt.stop();
|
||||||
|
}
|
||||||
|
var nt = nThen;
|
||||||
|
sf.teams.forEach(function (s) {
|
||||||
|
nt = nt(function (waitFor) {
|
||||||
|
var sfId = s.manager.user.userObject.getSFIdFromHref(href);
|
||||||
|
var shared = Util.find(s.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
|
||||||
|
if (!sfId || !shared[sfId]) { return; }
|
||||||
|
var sf = JSON.parse(JSON.stringify(shared[sfId]));
|
||||||
|
sf.password = password;
|
||||||
|
SF.load({
|
||||||
|
network: network,
|
||||||
|
store: s,
|
||||||
|
isNewChannel: Store.isNewChannel
|
||||||
|
}, sfId, sf, waitFor());
|
||||||
|
if (!s.rpc) { return; }
|
||||||
|
s.rpc.unpin([oldChannel], waitFor());
|
||||||
|
s.rpc.pin([secret.channel], waitFor());
|
||||||
|
}).nThen;
|
||||||
|
});
|
||||||
|
nt(cb);
|
||||||
|
};
|
||||||
|
|
||||||
/* loadSharedFolders
|
/* loadSharedFolders
|
||||||
load all shared folder stored in a given drive
|
load all shared folder stored in a given drive
|
||||||
- store: user or team main store
|
- store: user or team main store
|
||||||
@ -193,35 +257,13 @@ define([
|
|||||||
*/
|
*/
|
||||||
SF.loadSharedFolders = function (Store, network, store, userObject, waitFor) {
|
SF.loadSharedFolders = function (Store, network, store, userObject, waitFor) {
|
||||||
var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
|
var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
|
||||||
// Check if any of our shared folder is expired or deleted by its owner.
|
|
||||||
// If we don't check now, Listmap will create an empty proxy if it no longer exists on
|
|
||||||
// the server.
|
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
var checkExpired = Object.keys(shared).map(function (fId) {
|
|
||||||
return shared[fId].channel;
|
|
||||||
});
|
|
||||||
Store.getDeletedPads(null, {list: checkExpired}, waitFor(function (chans) {
|
|
||||||
if (chans && chans.error) { return void console.error(chans.error); }
|
|
||||||
if (!Array.isArray(chans) || !chans.length) { return; }
|
|
||||||
var toDelete = [];
|
|
||||||
Object.keys(shared).forEach(function (fId) {
|
|
||||||
if (chans.indexOf(shared[fId].channel) !== -1
|
|
||||||
&& toDelete.indexOf(fId) === -1) {
|
|
||||||
toDelete.push(fId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
toDelete.forEach(function (fId) {
|
|
||||||
var paths = userObject.findFile(Number(fId));
|
|
||||||
userObject.delete(paths, waitFor(), true);
|
|
||||||
delete shared[fId];
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}).nThen(function (waitFor) {
|
|
||||||
Object.keys(shared).forEach(function (id) {
|
Object.keys(shared).forEach(function (id) {
|
||||||
var sf = shared[id];
|
var sf = shared[id];
|
||||||
SF.load({
|
SF.load({
|
||||||
network: network,
|
network: network,
|
||||||
store: store
|
store: store,
|
||||||
|
isNewChannel: Store.isNewChannel
|
||||||
}, id, sf, waitFor());
|
}, id, sf, waitFor());
|
||||||
});
|
});
|
||||||
}).nThen(waitFor());
|
}).nThen(waitFor());
|
||||||
|
|||||||
@ -56,6 +56,7 @@ define([
|
|||||||
ADD_SHARED_FOLDER: Store.addSharedFolder,
|
ADD_SHARED_FOLDER: Store.addSharedFolder,
|
||||||
LOAD_SHARED_FOLDER: Store.loadSharedFolderAnon,
|
LOAD_SHARED_FOLDER: Store.loadSharedFolderAnon,
|
||||||
RESTORE_SHARED_FOLDER: Store.restoreSharedFolder,
|
RESTORE_SHARED_FOLDER: Store.restoreSharedFolder,
|
||||||
|
UPDATE_SHARED_FOLDER_PASSWORD: Store.updateSharedFolderPassword,
|
||||||
// Messaging
|
// Messaging
|
||||||
ANSWER_FRIEND_REQUEST: Store.answerFriendRequest,
|
ANSWER_FRIEND_REQUEST: Store.answerFriendRequest,
|
||||||
SEND_FRIEND_REQUEST: Store.sendFriendRequest,
|
SEND_FRIEND_REQUEST: Store.sendFriendRequest,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ define([
|
|||||||
'/common/outer/sharedfolder.js',
|
'/common/outer/sharedfolder.js',
|
||||||
'/common/outer/roster.js',
|
'/common/outer/roster.js',
|
||||||
'/common/common-messaging.js',
|
'/common/common-messaging.js',
|
||||||
|
'/common/common-feedback.js',
|
||||||
|
|
||||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
@ -18,7 +19,7 @@ define([
|
|||||||
'/bower_components/saferphore/index.js',
|
'/bower_components/saferphore/index.js',
|
||||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||||
], function (Util, Hash, Constants, Realtime,
|
], function (Util, Hash, Constants, Realtime,
|
||||||
ProxyManager, UserObject, SF, Roster, Messaging,
|
ProxyManager, UserObject, SF, Roster, Messaging, Feedback,
|
||||||
Listmap, Crypto, CpNetflux, ChainPad, nThen, Saferphore) {
|
Listmap, Crypto, CpNetflux, ChainPad, nThen, Saferphore) {
|
||||||
var Team = {};
|
var Team = {};
|
||||||
|
|
||||||
@ -30,6 +31,27 @@ define([
|
|||||||
|
|
||||||
var registerChangeEvents = function (ctx, team, proxy, fId) {
|
var registerChangeEvents = function (ctx, team, proxy, fId) {
|
||||||
if (!team) { return; }
|
if (!team) { return; }
|
||||||
|
if (!fId) {
|
||||||
|
// Listen for shared folder password change
|
||||||
|
proxy.on('change', ['drive', UserObject.SHARED_FOLDERS], function (o, n, p) {
|
||||||
|
if (p.length > 3 && p[3] === 'password') {
|
||||||
|
var id = p[2];
|
||||||
|
var data = proxy.drive[UserObject.SHARED_FOLDERS][id];
|
||||||
|
var href = team.manager.user.userObject.getHref ?
|
||||||
|
team.manager.user.userObject.getHref(data) : data.href;
|
||||||
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, o);
|
||||||
|
SF.updatePassword(ctx.Store, {
|
||||||
|
oldChannel: secret.channel,
|
||||||
|
password: n,
|
||||||
|
href: href
|
||||||
|
}, ctx.store.network, function () {
|
||||||
|
console.log('Shared folder password changed');
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
proxy.on('change', [], function (o, n, p) {
|
proxy.on('change', [], function (o, n, p) {
|
||||||
if (fId) {
|
if (fId) {
|
||||||
// Pin the new pads
|
// Pin the new pads
|
||||||
@ -216,13 +238,13 @@ define([
|
|||||||
}));
|
}));
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
// Create the proxy manager
|
// Create the proxy manager
|
||||||
var loadSharedFolder = function (id, data, cb) {
|
var loadSharedFolder = function (id, data, cb, isNew) {
|
||||||
SF.load({
|
SF.load({
|
||||||
|
isNew: isNew,
|
||||||
network: ctx.store.network,
|
network: ctx.store.network,
|
||||||
store: team
|
store: team,
|
||||||
}, id, data, function (id, rt) {
|
isNewChannel: ctx.Store.isNewChannel
|
||||||
cb(id, rt);
|
}, id, data, cb);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
var teamData = ctx.store.proxy.teams[team.id];
|
var teamData = ctx.store.proxy.teams[team.id];
|
||||||
var hash = teamData.hash || teamData.roHash;
|
var hash = teamData.hash || teamData.roHash;
|
||||||
@ -236,6 +258,7 @@ define([
|
|||||||
settings: {
|
settings: {
|
||||||
drive: Util.find(ctx.store, ['proxy', 'settings', 'drive'])
|
drive: Util.find(ctx.store, ['proxy', 'settings', 'drive'])
|
||||||
},
|
},
|
||||||
|
Store: ctx.Store
|
||||||
}, {
|
}, {
|
||||||
outer: true,
|
outer: true,
|
||||||
removeOwnedChannel: function (channel, cb) {
|
removeOwnedChannel: function (channel, cb) {
|
||||||
@ -567,6 +590,7 @@ define([
|
|||||||
proxy.drive = {};
|
proxy.drive = {};
|
||||||
|
|
||||||
onReady(ctx, id, lm, roster, keys, cId, function () {
|
onReady(ctx, id, lm, roster, keys, cId, function () {
|
||||||
|
Feedback.send('TEAM_CREATION');
|
||||||
ctx.updateMetadata();
|
ctx.updateMetadata();
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
@ -682,6 +706,7 @@ define([
|
|||||||
if (err) { console.error(err); }
|
if (err) { console.error(err); }
|
||||||
}));
|
}));
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
|
Feedback.send('TEAM_DELETION');
|
||||||
closeTeam(ctx, teamId);
|
closeTeam(ctx, teamId);
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -30,6 +30,7 @@ define([
|
|||||||
var TRASH = exp.TRASH;
|
var TRASH = exp.TRASH;
|
||||||
var TEMPLATE = exp.TEMPLATE;
|
var TEMPLATE = exp.TEMPLATE;
|
||||||
var SHARED_FOLDERS = exp.SHARED_FOLDERS;
|
var SHARED_FOLDERS = exp.SHARED_FOLDERS;
|
||||||
|
var SHARED_FOLDERS_TEMP = exp.SHARED_FOLDERS_TEMP;
|
||||||
|
|
||||||
var debug = exp.debug;
|
var debug = exp.debug;
|
||||||
|
|
||||||
@ -109,6 +110,15 @@ define([
|
|||||||
cb(null, id);
|
cb(null, id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exp.deprecateSharedFolder = function (id) {
|
||||||
|
var data = files[SHARED_FOLDERS][id];
|
||||||
|
if (!data) { return; }
|
||||||
|
files[SHARED_FOLDERS_TEMP][id] = JSON.parse(JSON.stringify(data));
|
||||||
|
var paths = exp.findFile(Number(id));
|
||||||
|
exp.delete(paths, null, true);
|
||||||
|
delete files[SHARED_FOLDERS][id];
|
||||||
|
};
|
||||||
|
|
||||||
// FILES DATA
|
// FILES DATA
|
||||||
var spliceFileData = function (id) {
|
var spliceFileData = function (id) {
|
||||||
if (readOnly) { return; }
|
if (readOnly) { return; }
|
||||||
@ -868,6 +878,22 @@ define([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var fixSharedFoldersTemp = function () {
|
||||||
|
if (sharedFolder) { return; }
|
||||||
|
if (typeof(files[SHARED_FOLDERS_TEMP]) !== "object") {
|
||||||
|
debug("SHARED_FOLDER_TEMP was not an object");
|
||||||
|
files[SHARED_FOLDERS_TEMP] = {};
|
||||||
|
}
|
||||||
|
// Remove deprecated shared folder if they were already added back
|
||||||
|
var sft = files[SHARED_FOLDERS_TEMP];
|
||||||
|
var sf = files[SHARED_FOLDERS];
|
||||||
|
for (var id in sft) {
|
||||||
|
if (sf[id]) {
|
||||||
|
delete sft[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var fixDrive = function () {
|
var fixDrive = function () {
|
||||||
Object.keys(files).forEach(function (key) {
|
Object.keys(files).forEach(function (key) {
|
||||||
@ -881,6 +907,7 @@ define([
|
|||||||
fixFilesData();
|
fixFilesData();
|
||||||
fixDrive();
|
fixDrive();
|
||||||
fixSharedFolders();
|
fixSharedFolders();
|
||||||
|
fixSharedFoldersTemp();
|
||||||
|
|
||||||
var ms = (+new Date() - t0) + 'ms';
|
var ms = (+new Date() - t0) + 'ms';
|
||||||
if (JSON.stringify(files) !== before) {
|
if (JSON.stringify(files) !== before) {
|
||||||
|
|||||||
@ -27,6 +27,13 @@ define([
|
|||||||
// Only in outer
|
// Only in outer
|
||||||
userObject.fixFiles();
|
userObject.fixFiles();
|
||||||
}
|
}
|
||||||
|
var proxy = lm.proxy;
|
||||||
|
if (proxy.metadata && proxy.metadata.title) {
|
||||||
|
var sf = Env.user.proxy[UserObject.SHARED_FOLDERS][id];
|
||||||
|
if (sf) {
|
||||||
|
sf.lastTitle = proxy.metadata.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
Env.folders[id] = {
|
Env.folders[id] = {
|
||||||
proxy: lm.proxy,
|
proxy: lm.proxy,
|
||||||
userObject: userObject,
|
userObject: userObject,
|
||||||
@ -43,6 +50,12 @@ define([
|
|||||||
delete Env.folders[id];
|
delete Env.folders[id];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Password may have changed
|
||||||
|
var deprecateProxy = function (Env, id, channel) {
|
||||||
|
Env.unpinPads([channel], function () {});
|
||||||
|
Env.user.userObject.deprecateSharedFolder(id);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tools
|
Tools
|
||||||
*/
|
*/
|
||||||
@ -488,6 +501,11 @@ define([
|
|||||||
|
|
||||||
// 2b. load the proxy
|
// 2b. load the proxy
|
||||||
Env.loadSharedFolder(id, folderData, waitFor(function (rt, metadata) {
|
Env.loadSharedFolder(id, folderData, waitFor(function (rt, metadata) {
|
||||||
|
if (!rt) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: 'EDELETED' });
|
||||||
|
}
|
||||||
|
|
||||||
if (!rt.proxy.metadata) { // Creating a new shared folder
|
if (!rt.proxy.metadata) { // Creating a new shared folder
|
||||||
rt.proxy.metadata = { title: data.name || Messages.fm_newFolder };
|
rt.proxy.metadata = { title: data.name || Messages.fm_newFolder };
|
||||||
}
|
}
|
||||||
@ -497,7 +515,7 @@ define([
|
|||||||
if (metadata.owners) { fData.owners = metadata.owners; }
|
if (metadata.owners) { fData.owners = metadata.owners; }
|
||||||
if (metadata.expire) { fData.expire = +metadata.expire; }
|
if (metadata.expire) { fData.expire = +metadata.expire; }
|
||||||
}
|
}
|
||||||
}));
|
}), !Boolean(data.folderData));
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
Env.onSync(function () {
|
Env.onSync(function () {
|
||||||
cb(id);
|
cb(id);
|
||||||
@ -505,6 +523,42 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var _restoreSharedFolder = function (Env, _data, cb) {
|
||||||
|
var fId = _data.id;
|
||||||
|
var newPassword = _data.password;
|
||||||
|
var temp = Util.find(Env, ['user', 'proxy', UserObject.SHARED_FOLDERS_TEMP]);
|
||||||
|
var data = temp && temp[fId];
|
||||||
|
if (!data) { return void cb({ error: 'EINVAL' }); }
|
||||||
|
if (!Env.Store) { return void cb({ error: 'ESTORE' }); }
|
||||||
|
var href = Env.user.userObject.getHref ? Env.user.userObject.getHref(data) : data.href;
|
||||||
|
var isNew = false;
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
Env.Store.isNewChannel(null, {
|
||||||
|
href: href,
|
||||||
|
password: newPassword
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
if (!obj || obj.error) {
|
||||||
|
isNew = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isNew = obj.isNew;
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
if (isNew) {
|
||||||
|
return void cb({ error: 'ENOTFOUND' });
|
||||||
|
}
|
||||||
|
data.password = newPassword;
|
||||||
|
_addSharedFolder(Env, {
|
||||||
|
path: ['root'],
|
||||||
|
folderData: data,
|
||||||
|
}, function () {
|
||||||
|
delete temp[fId];
|
||||||
|
Env.onSync(cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// convert a folder to a Shared Folder
|
// convert a folder to a Shared Folder
|
||||||
var _convertFolderToSharedFolder = function (Env, data, cb) {
|
var _convertFolderToSharedFolder = function (Env, data, cb) {
|
||||||
return void cb({
|
return void cb({
|
||||||
@ -611,6 +665,13 @@ define([
|
|||||||
return void cb({error: 'E_NOTFOUND'});
|
return void cb({error: 'E_NOTFOUND'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deleted or password changed for a shared folder
|
||||||
|
if (data.paths.length === 1 && data.paths[0][0] === UserObject.SHARED_FOLDERS_TEMP) {
|
||||||
|
var temp = Util.find(Env, ['user', 'proxy', UserObject.SHARED_FOLDERS_TEMP]);
|
||||||
|
delete temp[data.paths[0][1]];
|
||||||
|
return void Env.onSync(cb);
|
||||||
|
}
|
||||||
|
|
||||||
var toUnpin = [];
|
var toUnpin = [];
|
||||||
var ownedRemoved;
|
var ownedRemoved;
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
@ -707,6 +768,7 @@ define([
|
|||||||
var el = Env.user.userObject.find(resolved.path);
|
var el = Env.user.userObject.find(resolved.path);
|
||||||
if (Env.user.userObject.isSharedFolder(el) && Env.folders[el]) {
|
if (Env.user.userObject.isSharedFolder(el) && Env.folders[el]) {
|
||||||
Env.folders[el].proxy.metadata.title = data.newName;
|
Env.folders[el].proxy.metadata.title = data.newName;
|
||||||
|
Env.user.proxy[UserObject.SHARED_FOLDERS][el].lastTitle = data.value;
|
||||||
return void cb();
|
return void cb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -740,6 +802,8 @@ define([
|
|||||||
_addFolder(Env, data, cb); break;
|
_addFolder(Env, data, cb); break;
|
||||||
case 'addSharedFolder':
|
case 'addSharedFolder':
|
||||||
_addSharedFolder(Env, data, cb); break;
|
_addSharedFolder(Env, data, cb); break;
|
||||||
|
case 'restoreSharedFolder':
|
||||||
|
_restoreSharedFolder(Env, data, cb); break;
|
||||||
case 'convertFolderToSharedFolder':
|
case 'convertFolderToSharedFolder':
|
||||||
_convertFolderToSharedFolder(Env, data, cb); break;
|
_convertFolderToSharedFolder(Env, data, cb); break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
@ -966,6 +1030,7 @@ define([
|
|||||||
pinPads: data.pin,
|
pinPads: data.pin,
|
||||||
unpinPads: data.unpin,
|
unpinPads: data.unpin,
|
||||||
onSync: data.onSync,
|
onSync: data.onSync,
|
||||||
|
Store: data.Store,
|
||||||
loadSharedFolder: data.loadSharedFolder,
|
loadSharedFolder: data.loadSharedFolder,
|
||||||
cfg: uoConfig,
|
cfg: uoConfig,
|
||||||
edPublic: data.edPublic,
|
edPublic: data.edPublic,
|
||||||
@ -988,6 +1053,7 @@ define([
|
|||||||
// Manager
|
// Manager
|
||||||
addProxy: callWithEnv(addProxy),
|
addProxy: callWithEnv(addProxy),
|
||||||
removeProxy: callWithEnv(removeProxy),
|
removeProxy: callWithEnv(removeProxy),
|
||||||
|
deprecateProxy: callWithEnv(deprecateProxy),
|
||||||
addSharedFolder: callWithEnv(_addSharedFolder),
|
addSharedFolder: callWithEnv(_addSharedFolder),
|
||||||
// Drive
|
// Drive
|
||||||
command: callWithEnv(onCommand),
|
command: callWithEnv(onCommand),
|
||||||
@ -1059,6 +1125,15 @@ define([
|
|||||||
}
|
}
|
||||||
}, cb);
|
}, cb);
|
||||||
};
|
};
|
||||||
|
var restoreSharedFolderInner = function (Env, fId, password, cb) {
|
||||||
|
return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", {
|
||||||
|
cmd: "restoreSharedFolder",
|
||||||
|
data: {
|
||||||
|
id: fId,
|
||||||
|
password: password
|
||||||
|
}
|
||||||
|
}, cb);
|
||||||
|
};
|
||||||
var convertFolderToSharedFolderInner = function (Env, path, owned, password, cb) {
|
var convertFolderToSharedFolderInner = function (Env, path, owned, password, cb) {
|
||||||
return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", {
|
return void Env.sframeChan.query("Q_DRIVE_USEROBJECT", {
|
||||||
cmd: "convertFolderToSharedFolder",
|
cmd: "convertFolderToSharedFolder",
|
||||||
@ -1262,6 +1337,7 @@ define([
|
|||||||
emptyTrash: callWithEnv(emptyTrashInner),
|
emptyTrash: callWithEnv(emptyTrashInner),
|
||||||
addFolder: callWithEnv(addFolderInner),
|
addFolder: callWithEnv(addFolderInner),
|
||||||
addSharedFolder: callWithEnv(addSharedFolderInner),
|
addSharedFolder: callWithEnv(addSharedFolderInner),
|
||||||
|
restoreSharedFolder: callWithEnv(restoreSharedFolderInner),
|
||||||
convertFolderToSharedFolder: callWithEnv(convertFolderToSharedFolderInner),
|
convertFolderToSharedFolder: callWithEnv(convertFolderToSharedFolderInner),
|
||||||
delete: callWithEnv(deleteInner),
|
delete: callWithEnv(deleteInner),
|
||||||
restore: callWithEnv(restoreInner),
|
restore: callWithEnv(restoreInner),
|
||||||
|
|||||||
@ -379,13 +379,14 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
exp.mkIndentSettings = function (metadataMgr) {
|
exp.mkIndentSettings = function (metadataMgr) {
|
||||||
var setIndentation = function (units, useTabs, fontSize, spellcheck) {
|
var setIndentation = function (units, useTabs, fontSize, spellcheck, brackets) {
|
||||||
if (typeof(units) !== 'number') { return; }
|
if (typeof(units) !== 'number') { return; }
|
||||||
var doc = editor.getDoc();
|
var doc = editor.getDoc();
|
||||||
editor.setOption('indentUnit', units);
|
editor.setOption('indentUnit', units);
|
||||||
editor.setOption('tabSize', units);
|
editor.setOption('tabSize', units);
|
||||||
editor.setOption('indentWithTabs', useTabs);
|
editor.setOption('indentWithTabs', useTabs);
|
||||||
editor.setOption('spellcheck', spellcheck);
|
editor.setOption('spellcheck', spellcheck);
|
||||||
|
editor.setOption('autoCloseBrackets', brackets);
|
||||||
editor.setOption("extraKeys", {
|
editor.setOption("extraKeys", {
|
||||||
Tab: function() {
|
Tab: function() {
|
||||||
if (doc.somethingSelected()) {
|
if (doc.somethingSelected()) {
|
||||||
@ -415,11 +416,13 @@ define([
|
|||||||
var useTabs = data[useTabsKey];
|
var useTabs = data[useTabsKey];
|
||||||
var fontSize = data[fontKey];
|
var fontSize = data[fontKey];
|
||||||
var spellcheck = data[spellcheckKey];
|
var spellcheck = data[spellcheckKey];
|
||||||
|
var brackets = data.brackets;
|
||||||
setIndentation(
|
setIndentation(
|
||||||
typeof(indentUnit) === 'number'? indentUnit : 2,
|
typeof(indentUnit) === 'number'? indentUnit : 2,
|
||||||
typeof(useTabs) === 'boolean'? useTabs : false,
|
typeof(useTabs) === 'boolean'? useTabs : false,
|
||||||
typeof(fontSize) === 'number' ? fontSize : 12,
|
typeof(fontSize) === 'number' ? fontSize : 12,
|
||||||
typeof(spellcheck) === 'boolean' ? spellcheck : false);
|
typeof(spellcheck) === 'boolean' ? spellcheck : false,
|
||||||
|
typeof(brackets) === 'boolean' ? brackets : true);
|
||||||
};
|
};
|
||||||
metadataMgr.onChangeLazy(updateIndentSettings);
|
metadataMgr.onChangeLazy(updateIndentSettings);
|
||||||
updateIndentSettings();
|
updateIndentSettings();
|
||||||
|
|||||||
@ -118,7 +118,7 @@ define([
|
|||||||
msgEv.fire(msg);
|
msgEv.fire(msg);
|
||||||
});
|
});
|
||||||
SFrameChannel.create(msgEv, postMsg, waitFor(function (sfc) {
|
SFrameChannel.create(msgEv, postMsg, waitFor(function (sfc) {
|
||||||
sframeChan = sfc;
|
Utils.sframeChan = sframeChan = sfc;
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
window.addEventListener('message', whenReady);
|
window.addEventListener('message', whenReady);
|
||||||
@ -177,75 +177,88 @@ define([
|
|||||||
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
|
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prompt the password here if we have a hash containing /p/
|
if (!parsed.hashData) { // No hash, no need to check for a password
|
||||||
// or get it from the pad attributes
|
return void todo();
|
||||||
var needPassword = parsed.hashData && parsed.hashData.password;
|
|
||||||
if (needPassword) {
|
|
||||||
// Check if we have a password, and check if it is correct (file exists).
|
|
||||||
// It we don't have a correct password, display the password prompt.
|
|
||||||
// Maybe the file has been deleted from the server or the password has been changed.
|
|
||||||
Cryptpad.getPadAttribute('password', waitFor(function (err, val) {
|
|
||||||
var askPassword = function (wrongPasswordStored) {
|
|
||||||
// Ask for the password and check if the pad exists
|
|
||||||
// If the pad doesn't exist, it means the password isn't correct
|
|
||||||
// or the pad has been deleted
|
|
||||||
var correctPassword = waitFor();
|
|
||||||
sframeChan.on('Q_PAD_PASSWORD_VALUE', function (data, cb) {
|
|
||||||
password = data;
|
|
||||||
var next = function (e, isNew) {
|
|
||||||
if (Boolean(isNew)) {
|
|
||||||
// Ask again in the inner iframe
|
|
||||||
// We should receive a new Q_PAD_PASSWORD_VALUE
|
|
||||||
cb(false);
|
|
||||||
} else {
|
|
||||||
todo();
|
|
||||||
if (wrongPasswordStored) {
|
|
||||||
// Store the correct password
|
|
||||||
Cryptpad.setPadAttribute('password', password, function () {
|
|
||||||
correctPassword();
|
|
||||||
}, parsed.getUrl());
|
|
||||||
} else {
|
|
||||||
correctPassword();
|
|
||||||
}
|
|
||||||
cb(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (parsed.type === "file") {
|
|
||||||
// `isNewChannel` doesn't work for files (not a channel)
|
|
||||||
// `getFileSize` is not adapted to channels because of metadata
|
|
||||||
Cryptpad.getFileSize(window.location.href, password, function (e, size) {
|
|
||||||
next(e, size === 0);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Not a file, so we can use `isNewChannel`
|
|
||||||
Cryptpad.isNewChannel(window.location.href, password, next);
|
|
||||||
});
|
|
||||||
sframeChan.event("EV_PAD_PASSWORD");
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!val && sessionStorage.newPadPassword) {
|
|
||||||
val = sessionStorage.newPadPassword;
|
|
||||||
delete sessionStorage.newPadPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val) {
|
|
||||||
password = val;
|
|
||||||
Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) {
|
|
||||||
if (size !== 0) {
|
|
||||||
return void todo();
|
|
||||||
}
|
|
||||||
// Wrong password or deleted file?
|
|
||||||
askPassword(true);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
askPassword();
|
|
||||||
}
|
|
||||||
}), parsed.getUrl());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// If no password, continue...
|
|
||||||
todo();
|
// We now need to check if there is a password and if we know the correct password.
|
||||||
|
// We'll use getFileSize and isNewChannel to detect incorrect passwords.
|
||||||
|
|
||||||
|
// First we'll get the password value from our drive (getPadAttribute), and we'll check
|
||||||
|
// if the channel is valid. If the pad is not stored in our drive, we'll test with an
|
||||||
|
// empty password instead.
|
||||||
|
|
||||||
|
// If this initial check returns a valid channel, open the pad.
|
||||||
|
// If the channel is invalid:
|
||||||
|
// Option 1: this is a password-protected pad not stored in our drive --> password prompt
|
||||||
|
// Option 2: this is a pad stored in our drive
|
||||||
|
// 2a: 'edit' pad or file --> password-prompt
|
||||||
|
// 2b: 'view' pad no '/p/' --> the seed is incorrect
|
||||||
|
// 2c: 'view' pad and '/p/' and a wrong password stored --> the seed is incorrect
|
||||||
|
// 2d: 'view' pad and '/p/' and password never stored (security feature) --> password-prompt
|
||||||
|
|
||||||
|
Cryptpad.getPadAttribute('password', waitFor(function (err, val) {
|
||||||
|
var askPassword = function (wrongPasswordStored) {
|
||||||
|
// Ask for the password and check if the pad exists
|
||||||
|
// If the pad doesn't exist, it means the password isn't correct
|
||||||
|
// or the pad has been deleted
|
||||||
|
var correctPassword = waitFor();
|
||||||
|
sframeChan.on('Q_PAD_PASSWORD_VALUE', function (data, cb) {
|
||||||
|
password = data;
|
||||||
|
var next = function (e, isNew) {
|
||||||
|
if (Boolean(isNew)) {
|
||||||
|
// Ask again in the inner iframe
|
||||||
|
// We should receive a new Q_PAD_PASSWORD_VALUE
|
||||||
|
cb(false);
|
||||||
|
} else {
|
||||||
|
todo();
|
||||||
|
if (wrongPasswordStored) {
|
||||||
|
// Store the correct password
|
||||||
|
nThen(function (w) {
|
||||||
|
Cryptpad.setPadAttribute('password', password, w(), parsed.getUrl());
|
||||||
|
Cryptpad.setPadAttribute('channel', secret.channel, w(), parsed.getUrl());
|
||||||
|
}).nThen(correctPassword);
|
||||||
|
} else {
|
||||||
|
correctPassword();
|
||||||
|
}
|
||||||
|
cb(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (parsed.type === "file") {
|
||||||
|
// `isNewChannel` doesn't work for files (not a channel)
|
||||||
|
// `getFileSize` is not adapted to channels because of metadata
|
||||||
|
Cryptpad.getFileSize(window.location.href, password, function (e, size) {
|
||||||
|
next(e, size === 0);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Not a file, so we can use `isNewChannel`
|
||||||
|
Cryptpad.isNewChannel(window.location.href, password, next);
|
||||||
|
});
|
||||||
|
sframeChan.event("EV_PAD_PASSWORD");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!val && sessionStorage.newPadPassword) {
|
||||||
|
val = sessionStorage.newPadPassword;
|
||||||
|
delete sessionStorage.newPadPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
password = val;
|
||||||
|
Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) {
|
||||||
|
if (size !== 0) {
|
||||||
|
return void todo();
|
||||||
|
}
|
||||||
|
if (parsed.hashData.mode === 'view' && (val || !parsed.hashData.password)) {
|
||||||
|
// Error, wrong password stored, the view seed has changed with the password
|
||||||
|
// password will never work
|
||||||
|
sframeChan.event("EV_PAD_PASSWORD_ERROR");
|
||||||
|
waitFor.abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Wrong password or deleted file?
|
||||||
|
askPassword(true);
|
||||||
|
}));
|
||||||
|
}), parsed.getUrl());
|
||||||
}
|
}
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
if (cfg.afterSecrets) {
|
if (cfg.afterSecrets) {
|
||||||
|
|||||||
@ -599,6 +599,10 @@ define([
|
|||||||
UIElements.displayPasswordPrompt(funcs);
|
UIElements.displayPasswordPrompt(funcs);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ctx.sframeChan.on("EV_PAD_PASSWORD_ERROR", function () {
|
||||||
|
UI.errorLoadingScreen(Messages.password_error_seed);
|
||||||
|
});
|
||||||
|
|
||||||
ctx.sframeChan.on('EV_LOADING_INFO', function (data) {
|
ctx.sframeChan.on('EV_LOADING_INFO', function (data) {
|
||||||
UI.updateLoadingProgress(data, 'drive');
|
UI.updateLoadingProgress(data, 'drive');
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1220,5 +1220,6 @@
|
|||||||
"survey": "CryptPad-Umfrage",
|
"survey": "CryptPad-Umfrage",
|
||||||
"team_title": "Team: {0}",
|
"team_title": "Team: {0}",
|
||||||
"team_quota": "Speicherplatzbegrenzung deines Teams",
|
"team_quota": "Speicherplatzbegrenzung deines Teams",
|
||||||
"drive_quota": "Deine Speicherplatzbegrenzung"
|
"drive_quota": "Deine Speicherplatzbegrenzung",
|
||||||
|
"settings_codeBrackets": "Klammern automatisch schließen"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1220,5 +1220,6 @@
|
|||||||
"team_demoteMeConfirm": "Vous êtes sur le point de renoncer à vos droits. Vous ne serez pas en mesure d'annuler cette action. Continuer ?",
|
"team_demoteMeConfirm": "Vous êtes sur le point de renoncer à vos droits. Vous ne serez pas en mesure d'annuler cette action. Continuer ?",
|
||||||
"team_title": "Équipe : {0}",
|
"team_title": "Équipe : {0}",
|
||||||
"team_quota": "Limite de stockage de votre équipe",
|
"team_quota": "Limite de stockage de votre équipe",
|
||||||
"drive_quota": "Votre limite de stockage"
|
"drive_quota": "Votre limite de stockage",
|
||||||
|
"settings_codeBrackets": "Fermer automatiquement les parenthèses"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1220,5 +1220,6 @@
|
|||||||
"team_demoteMeConfirm": "You are about to give up your rights. You will not be able to undo this action. Are you sure?",
|
"team_demoteMeConfirm": "You are about to give up your rights. You will not be able to undo this action. Are you sure?",
|
||||||
"team_title": "Team: {0}",
|
"team_title": "Team: {0}",
|
||||||
"team_quota": "Your team's storage limit",
|
"team_quota": "Your team's storage limit",
|
||||||
"drive_quota": "Your storage limit"
|
"drive_quota": "Your storage limit",
|
||||||
|
"settings_codeBrackets": "Auto-close brackets"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ define([
|
|||||||
var TRASH = module.TRASH = "trash";
|
var TRASH = module.TRASH = "trash";
|
||||||
var TEMPLATE = module.TEMPLATE = "template";
|
var TEMPLATE = module.TEMPLATE = "template";
|
||||||
var SHARED_FOLDERS = module.SHARED_FOLDERS = "sharedFolders";
|
var SHARED_FOLDERS = module.SHARED_FOLDERS = "sharedFolders";
|
||||||
|
var SHARED_FOLDERS_TEMP = module.SHARED_FOLDERS_TEMP = "sharedFoldersTemp"; // Maybe deleted or new password
|
||||||
|
|
||||||
// Create untitled documents when no name is given
|
// Create untitled documents when no name is given
|
||||||
var getLocaleDate = function () {
|
var getLocaleDate = function () {
|
||||||
@ -93,6 +94,7 @@ define([
|
|||||||
exp.TRASH = TRASH;
|
exp.TRASH = TRASH;
|
||||||
exp.TEMPLATE = TEMPLATE;
|
exp.TEMPLATE = TEMPLATE;
|
||||||
exp.SHARED_FOLDERS = SHARED_FOLDERS;
|
exp.SHARED_FOLDERS = SHARED_FOLDERS;
|
||||||
|
exp.SHARED_FOLDERS_TEMP = SHARED_FOLDERS_TEMP;
|
||||||
|
|
||||||
var sharedFolder = exp.sharedFolder = config.sharedFolder;
|
var sharedFolder = exp.sharedFolder = config.sharedFolder;
|
||||||
exp.id = config.id;
|
exp.id = config.id;
|
||||||
@ -447,11 +449,17 @@ define([
|
|||||||
return Util.deduplicateString(ret);
|
return Util.deduplicateString(ret);
|
||||||
};
|
};
|
||||||
|
|
||||||
var getIdFromHref = exp.getIdFromHref = function (href) {
|
var getIdFromHref = exp.getIdFromHref = function (_href) {
|
||||||
var result;
|
var result;
|
||||||
|
var noPassword = function (str) {
|
||||||
|
if (!str) { return; }
|
||||||
|
var value = str.replace(/\/p\/?/, '/');
|
||||||
|
return Hash.getRelativeHref(value);
|
||||||
|
};
|
||||||
|
var href = noPassword(_href);
|
||||||
getFiles([FILES_DATA]).some(function (id) {
|
getFiles([FILES_DATA]).some(function (id) {
|
||||||
if (getHref(files[FILES_DATA][id]) === href ||
|
if (noPassword(getHref(files[FILES_DATA][id])) === href ||
|
||||||
files[FILES_DATA][id].roHref === href) {
|
noPassword(files[FILES_DATA][id].roHref) === href) {
|
||||||
result = id;
|
result = id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -459,11 +467,17 @@ define([
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
exp.getSFIdFromHref = function (href) {
|
exp.getSFIdFromHref = function (_href) {
|
||||||
var result;
|
var result;
|
||||||
|
var noPassword = function (str) {
|
||||||
|
if (!str) { return; }
|
||||||
|
var value = str.replace(/\/p\/?/, '/');
|
||||||
|
return Hash.getRelativeHref(value);
|
||||||
|
};
|
||||||
|
var href = noPassword(_href);
|
||||||
getFiles([SHARED_FOLDERS]).some(function (id) {
|
getFiles([SHARED_FOLDERS]).some(function (id) {
|
||||||
if (getHref(files[SHARED_FOLDERS][id]) === href ||
|
if (noPassword(getHref(files[SHARED_FOLDERS][id])) === href ||
|
||||||
files[SHARED_FOLDERS][id].roHref === href) {
|
noPassword(files[SHARED_FOLDERS][id].roHref) === href) {
|
||||||
result = id;
|
result = id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,14 @@ define([
|
|||||||
sframeChan.query('Q_DRIVE_GETOBJECT', {
|
sframeChan.query('Q_DRIVE_GETOBJECT', {
|
||||||
sharedFolder: fId
|
sharedFolder: fId
|
||||||
}, waitFor(function (err, newObj) {
|
}, waitFor(function (err, newObj) {
|
||||||
|
if (!APP.loggedIn && APP.newSharedFolder) {
|
||||||
|
if (!newObj || !Object.keys(newObj).length) {
|
||||||
|
// Empty anon drive: deleted
|
||||||
|
var msg = Messages.deletedError + '<br>' + Messages.errorRedirectToHome;
|
||||||
|
setTimeout(function () { UI.errorLoadingScreen(msg, false, function () {}); });
|
||||||
|
APP.newSharedFolder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
folders[fId] = folders[fId] || {};
|
folders[fId] = folders[fId] || {};
|
||||||
copyObjectValue(folders[fId], newObj);
|
copyObjectValue(folders[fId], newObj);
|
||||||
folders[fId].readOnly = !secret.keys.secondaryKey;
|
folders[fId].readOnly = !secret.keys.secondaryKey;
|
||||||
|
|||||||
@ -85,6 +85,7 @@ define([
|
|||||||
'code': [
|
'code': [
|
||||||
'cp-settings-code-indent-unit',
|
'cp-settings-code-indent-unit',
|
||||||
'cp-settings-code-indent-type',
|
'cp-settings-code-indent-type',
|
||||||
|
'cp-settings-code-brackets',
|
||||||
'cp-settings-code-font-size',
|
'cp-settings-code-font-size',
|
||||||
'cp-settings-code-spellcheck',
|
'cp-settings-code-spellcheck',
|
||||||
],
|
],
|
||||||
@ -1445,6 +1446,35 @@ define([
|
|||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
create['code-brackets'] = function () {
|
||||||
|
var key = 'brackets';
|
||||||
|
|
||||||
|
var $div = $('<div>', {
|
||||||
|
'class': 'cp-settings-code-brackets cp-sidebarlayout-element'
|
||||||
|
});
|
||||||
|
$('<label>').text(Messages.settings_codeBrackets).appendTo($div);
|
||||||
|
|
||||||
|
var $inputBlock = $('<div>', {
|
||||||
|
'class': 'cp-sidebarlayout-input-block',
|
||||||
|
}).css('flex-flow', 'column')
|
||||||
|
.appendTo($div);
|
||||||
|
|
||||||
|
|
||||||
|
var $cbox = $(UI.createCheckbox('cp-settings-codebrackets'));
|
||||||
|
var $checkbox = $cbox.find('input').on('change', function () {
|
||||||
|
var val = $checkbox.is(':checked');
|
||||||
|
if (typeof(val) !== 'boolean') { return; }
|
||||||
|
common.setAttribute(['codemirror', key], val);
|
||||||
|
});
|
||||||
|
$cbox.appendTo($inputBlock);
|
||||||
|
|
||||||
|
common.getAttribute(['codemirror', key], function (e, val) {
|
||||||
|
if (e) { return void console.error(e); }
|
||||||
|
$checkbox[0].checked = typeof(val) !== "boolean" || val;
|
||||||
|
});
|
||||||
|
return $div;
|
||||||
|
};
|
||||||
|
|
||||||
create['code-font-size'] = function () {
|
create['code-font-size'] = function () {
|
||||||
var key = 'fontSize';
|
var key = 'fontSize';
|
||||||
|
|
||||||
|
|||||||
@ -396,9 +396,9 @@ define([
|
|||||||
var privateData = metadataMgr.getPrivateData();
|
var privateData = metadataMgr.getPrivateData();
|
||||||
var content = [];
|
var content = [];
|
||||||
|
|
||||||
var isOwner = Object.keys(privateData.teams || {}).some(function (id) {
|
var isOwner = Object.keys(privateData.teams || {}).filter(function (id) {
|
||||||
return privateData.teams[id].owner;
|
return privateData.teams[id].owner;
|
||||||
}) && !privateData.devMode;
|
}).length >= Constants.MAX_TEAMS_OWNED; // && !privateData.devMode;
|
||||||
|
|
||||||
var getWarningBox = function () {
|
var getWarningBox = function () {
|
||||||
return h('div.alert.alert-warning', {
|
return h('div.alert.alert-warning', {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user