Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging
commit
a5232b6cdb
|
@ -22,6 +22,7 @@ define([
|
|||
Feedback, LocalStore, Messages, nThen, Block, Hash) {
|
||||
var Exports = {
|
||||
Cred: Cred,
|
||||
Block: Block,
|
||||
// this is depended on by non-customizable files
|
||||
// be careful when modifying login.js
|
||||
requiredBytes: 192,
|
||||
|
@ -92,7 +93,7 @@ define([
|
|||
};
|
||||
|
||||
|
||||
var loginOptionsFromBlock = function (blockInfo) {
|
||||
var loginOptionsFromBlock = Exports.loginOptionsFromBlock = function (blockInfo) {
|
||||
var opt = {};
|
||||
var parsed = Hash.getSecrets('pad', blockInfo.User_hash);
|
||||
opt.channelHex = parsed.channel;
|
||||
|
@ -102,7 +103,7 @@ define([
|
|||
return opt;
|
||||
};
|
||||
|
||||
var loadUserObject = function (opt, cb) {
|
||||
var loadUserObject = Exports.loadUserObject = function (opt, cb) {
|
||||
var config = {
|
||||
websocketURL: NetConfig.getWebsocketURL(),
|
||||
channel: opt.channelHex,
|
||||
|
@ -527,8 +528,6 @@ define([
|
|||
if (!proxy[Constants.displayNameKey]) {
|
||||
proxy[Constants.displayNameKey] = uname;
|
||||
}
|
||||
LocalStore.eraseTempSessionValues();
|
||||
|
||||
|
||||
if (result.blockHash) {
|
||||
LocalStore.setBlockHash(result.blockHash);
|
||||
|
|
|
@ -20,6 +20,12 @@ html, body {
|
|||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.pending {
|
||||
border: 1px solid white;
|
||||
.fa {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
.success {
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
@ -53,5 +59,9 @@ html, body {
|
|||
background-color: @cp_alerts-danger-bg;
|
||||
color: @cp_alerts-danger-text;
|
||||
}
|
||||
|
||||
iframe {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,10 @@ define([], function () {
|
|||
});
|
||||
};
|
||||
|
||||
assert.run = function (cb) {
|
||||
assert.run = function (cb, progress) {
|
||||
progress = progress || function () {};
|
||||
var count = ASSERTS.length;
|
||||
var total = ASSERTS.length;
|
||||
var done = function (err) {
|
||||
count--;
|
||||
if (err) { failMessages.push(err); }
|
||||
|
@ -38,6 +40,7 @@ define([], function () {
|
|||
ASSERTS.forEach(function (f, index) {
|
||||
f(function (err) {
|
||||
//console.log("test " + index);
|
||||
progress(index, total);
|
||||
done(err, index);
|
||||
}, index);
|
||||
});
|
||||
|
|
|
@ -6,4 +6,6 @@
|
|||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="cp-progress"></div>
|
||||
<iframe-placeholder>
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="cp-app-noscroll cp-app-print">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<script async data-bootload="/checkup/inner.js" data-main="/common/sframe-boot.js?ver=1.7" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||
</head>
|
||||
<body class="cp-app-checkup">
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
define([
|
||||
], function () {
|
||||
console.log('inner loaded');
|
||||
});
|
|
@ -4,12 +4,21 @@ define([
|
|||
'/assert/assertions.js',
|
||||
'/common/hyperscript.js',
|
||||
'/customize/messages.js',
|
||||
'/common/dom-ready.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
'/common/sframe-common-outer.js',
|
||||
|
||||
'/customize/login.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/pinpad.js',
|
||||
'/common/outer/network-config.js',
|
||||
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/customize/src/less2/pages/page-checkup.less',
|
||||
], function ($, ApiConfig, Assertions, h, Messages /*, SFCommonO*/) {
|
||||
], function ($, ApiConfig, Assertions, h, Messages, DomReady,
|
||||
nThen, SFCommonO, Login, Hash, Util, Pinpad,
|
||||
NetConfig) {
|
||||
var assert = Assertions();
|
||||
|
||||
var trimSlashes = function (s) {
|
||||
|
@ -41,7 +50,7 @@ define([
|
|||
var checkAvailability = function (url, cb) {
|
||||
$.ajax({
|
||||
url: url,
|
||||
date: {},
|
||||
data: {},
|
||||
complete: function (xhr) {
|
||||
cb(xhr.status === 200);
|
||||
},
|
||||
|
@ -52,10 +61,141 @@ define([
|
|||
checkAvailability(trimmedUnsafe, cb);
|
||||
}, _alert("Main domain is not available"));
|
||||
|
||||
// Try loading an iframe on the safe domain
|
||||
assert(function (cb) {
|
||||
console.log(trimmedSafe);
|
||||
checkAvailability(trimmedSafe, cb);
|
||||
}, _alert("Sandbox domain is not available")); // FIXME Blocked by CSP. try loading it via sframe ?
|
||||
var to;
|
||||
nThen(function (waitFor) {
|
||||
DomReady.onReady(waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
to = setTimeout(function () {
|
||||
console.error('TIMEOUT loading iframe on the safe domain');
|
||||
cb(false);
|
||||
}, 5000);
|
||||
SFCommonO.initIframe(waitFor);
|
||||
}).nThen(function () {
|
||||
// Iframe is loaded
|
||||
clearTimeout(to);
|
||||
cb(true);
|
||||
});
|
||||
}, _alert("Sandbox domain is not available"));
|
||||
|
||||
// Test Websocket
|
||||
var evWSError = Util.mkEvent(true);
|
||||
assert(function (cb) {
|
||||
var ws = new WebSocket(NetConfig.getWebsocketURL());
|
||||
var to = setTimeout(function () {
|
||||
console.error('Websocket TIMEOUT');
|
||||
evWSError.fire();
|
||||
cb('TIMEOUT (5 seconds)');
|
||||
}, 5000);
|
||||
ws.onopen = function () {
|
||||
clearTimeout(to);
|
||||
cb(true);
|
||||
};
|
||||
ws.onerror = function (err) {
|
||||
clearTimeout(to);
|
||||
console.error('Websocket error', err);
|
||||
evWSError.fire();
|
||||
cb('WebSocket error: check your console');
|
||||
};
|
||||
}, _alert("Websocket is not available"));
|
||||
|
||||
// Test login block
|
||||
assert(function (cb) {
|
||||
var bytes = new Uint8Array(Login.requiredBytes);
|
||||
|
||||
var opt = Login.allocateBytes(bytes);
|
||||
|
||||
var blockUrl = Login.Block.getBlockUrl(opt.blockKeys);
|
||||
var blockRequest = Login.Block.serialize("{}", opt.blockKeys);
|
||||
var removeRequest = Login.Block.remove(opt.blockKeys);
|
||||
console.log('Test block URL:', blockUrl);
|
||||
|
||||
var userHash = '/2/drive/edit/000000000000000000000000';
|
||||
var secret = Hash.getSecrets('drive', userHash);
|
||||
opt.keys = secret.keys;
|
||||
opt.channelHex = secret.channel;
|
||||
|
||||
var RT, rpc, exists;
|
||||
|
||||
nThen(function (waitFor) {
|
||||
Util.fetch(blockUrl, waitFor(function (err) {
|
||||
if (err) { return; } // No block found
|
||||
exists = true;
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// If WebSockets aren't working, don't wait forever here
|
||||
evWSError.reg(function () {
|
||||
waitFor.abort();
|
||||
cb("No WebSocket (test number 6)");
|
||||
});
|
||||
// Create proxy
|
||||
Login.loadUserObject(opt, waitFor(function (err, rt) {
|
||||
if (err) {
|
||||
waitFor.abort();
|
||||
console.error("Can't create new channel. This may also be a websocket issue.");
|
||||
return void cb(false);
|
||||
}
|
||||
RT = rt;
|
||||
var proxy = rt.proxy;
|
||||
proxy.edPublic = opt.edPublic;
|
||||
proxy.edPrivate = opt.edPrivate;
|
||||
proxy.curvePublic = opt.curvePublic;
|
||||
proxy.curvePrivate = opt.curvePrivate;
|
||||
rt.realtime.onSettle(waitFor());
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Init RPC
|
||||
Pinpad.create(RT.network, RT.proxy, waitFor(function (e, _rpc) {
|
||||
if (e) {
|
||||
waitFor.abort();
|
||||
console.error("Can't initialize RPC", e); // INVALID_KEYS
|
||||
return void cb(false);
|
||||
}
|
||||
rpc = _rpc;
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Write block
|
||||
if (exists) { return; }
|
||||
rpc.writeLoginBlock(blockRequest, waitFor(function (e) {
|
||||
if (e) {
|
||||
waitFor.abort();
|
||||
console.error("Can't write login block", e);
|
||||
return void cb(false);
|
||||
}
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Read block
|
||||
Util.fetch(blockUrl, waitFor(function (e) {
|
||||
if (e) {
|
||||
waitFor.abort();
|
||||
console.error("Can't read login block", e);
|
||||
return void cb(false);
|
||||
}
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Remove block
|
||||
rpc.removeLoginBlock(removeRequest, waitFor(function (e) {
|
||||
if (e) {
|
||||
waitFor.abort();
|
||||
console.error("Can't remove login block", e);
|
||||
console.error(blockRequest);
|
||||
return void cb(false);
|
||||
}
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
rpc.removeOwnedChannel(secret.channel, waitFor(function (e) {
|
||||
if (e) {
|
||||
waitFor.abort();
|
||||
console.error("Can't remove channel", e);
|
||||
return void cb(false);
|
||||
}
|
||||
}));
|
||||
}).nThen(function () {
|
||||
cb(true);
|
||||
});
|
||||
|
||||
}, _alert("Login block is not working (write/read/remove)"));
|
||||
|
||||
var row = function (cells) {
|
||||
return h('tr', cells.map(function (cell) {
|
||||
|
@ -73,6 +213,8 @@ define([
|
|||
]);
|
||||
};
|
||||
|
||||
var completed = 0;
|
||||
var $progress = $('#cp-progress');
|
||||
assert.run(function (state) {
|
||||
var errors = state.errors;
|
||||
var failed = errors.length;
|
||||
|
@ -94,6 +236,17 @@ define([
|
|||
h('div.failures', errors.map(failureReport)),
|
||||
]);
|
||||
|
||||
$progress.remove();
|
||||
$('body').prepend(report);
|
||||
}, function (i, total) {
|
||||
console.log('test '+ i +' completed');
|
||||
completed++;
|
||||
Messages.assert_numberOfTestsCompleted = "{0} / {1} tests completed.";
|
||||
$progress.html('').append(h('div.report.pending.summary', [
|
||||
h('p', [
|
||||
h('i.fa.fa-spinner.fa-pulse'),
|
||||
h('span', Messages._getKey('assert_numberOfTestsCompleted', [completed, total]))
|
||||
])
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -232,17 +232,6 @@ define([
|
|||
};
|
||||
postMessage("MIGRATE_ANON_DRIVE", data, cb);
|
||||
};
|
||||
// Settings
|
||||
common.deleteAccount = function (cb) {
|
||||
postMessage("DELETE_ACCOUNT", null, function (obj) {
|
||||
if (obj.state) {
|
||||
Feedback.send('DELETE_ACCOUNT_AUTOMATIC');
|
||||
} else {
|
||||
Feedback.send('DELETE_ACCOUNT_MANUAL');
|
||||
}
|
||||
cb(obj);
|
||||
});
|
||||
};
|
||||
// Drive
|
||||
common.userObjectCommand = function (data, cb) {
|
||||
postMessage("DRIVE_USEROBJECT", data, cb);
|
||||
|
@ -1674,6 +1663,79 @@ define([
|
|||
};
|
||||
|
||||
|
||||
var getBlockKeys = function (data, cb) {
|
||||
var accountName = LocalStore.getAccountName();
|
||||
var password = data.password;
|
||||
var Cred, Block, Login;
|
||||
var blockKeys;
|
||||
|
||||
var hash = LocalStore.getUserHash();
|
||||
if (!hash) { return void cb({ error: 'E_NOT_LOGGED_IN' }); }
|
||||
var blockHash = LocalStore.getBlockHash();
|
||||
|
||||
Nthen(function (waitFor) {
|
||||
require([
|
||||
'/common/common-credential.js',
|
||||
'/common/outer/login-block.js',
|
||||
'/customize/login.js'
|
||||
], waitFor(function (_Cred, _Block, _Login) {
|
||||
Cred = _Cred;
|
||||
Block = _Block;
|
||||
Login = _Login;
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// confirm that the provided password is correct
|
||||
Cred.deriveFromPassphrase(accountName, password, Login.requiredBytes,
|
||||
waitFor(function (bytes) {
|
||||
var allocated = Login.allocateBytes(bytes);
|
||||
blockKeys = allocated.blockKeys;
|
||||
if (blockHash) {
|
||||
if (blockHash !== allocated.blockHash) {
|
||||
// incorrect password
|
||||
console.log("provided password did not yield the correct blockHash");
|
||||
waitFor.abort();
|
||||
return void cb({ error: 'INVALID_PASSWORD', });
|
||||
}
|
||||
} else {
|
||||
// otherwise they're a legacy user, and we should check against the User_hash
|
||||
if (hash !== allocated.userHash) {
|
||||
// incorrect password
|
||||
console.log("provided password did not yield the correct userHash");
|
||||
waitFor.abort();
|
||||
return void cb({ error: 'INVALID_PASSWORD', });
|
||||
}
|
||||
}
|
||||
}));
|
||||
}).nThen(function () {
|
||||
cb({
|
||||
Cred: Cred,
|
||||
Block: Block,
|
||||
Login: Login,
|
||||
blockKeys: blockKeys
|
||||
});
|
||||
});
|
||||
};
|
||||
common.deleteAccount = function (data, cb) {
|
||||
data = data || {};
|
||||
|
||||
// Confirm that the provided password is corrct and get the block keys
|
||||
getBlockKeys(data, function (obj) {
|
||||
if (obj && obj.error) { return void cb(obj); }
|
||||
var blockKeys = obj.blockKeys;
|
||||
var removeData = obj.Block.remove(blockKeys);
|
||||
|
||||
postMessage("DELETE_ACCOUNT", {
|
||||
removeData: removeData
|
||||
}, function (obj) {
|
||||
if (obj.state) {
|
||||
Feedback.send('DELETE_ACCOUNT_AUTOMATIC');
|
||||
} else {
|
||||
Feedback.send('DELETE_ACCOUNT_MANUAL');
|
||||
}
|
||||
cb(obj);
|
||||
});
|
||||
});
|
||||
};
|
||||
common.changeUserPassword = function (Crypt, edPublic, data, cb) {
|
||||
if (!edPublic) {
|
||||
return void cb({
|
||||
|
@ -1699,40 +1761,15 @@ define([
|
|||
|
||||
var Cred, Block, Login;
|
||||
Nthen(function (waitFor) {
|
||||
require([
|
||||
'/common/common-credential.js',
|
||||
'/common/outer/login-block.js',
|
||||
'/customize/login.js'
|
||||
], waitFor(function (_Cred, _Block, _Login) {
|
||||
Cred = _Cred;
|
||||
Block = _Block;
|
||||
Login = _Login;
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// confirm that the provided password is correct
|
||||
Cred.deriveFromPassphrase(accountName, password, Login.requiredBytes, waitFor(function (bytes) {
|
||||
var allocated = Login.allocateBytes(bytes);
|
||||
oldBlockKeys = allocated.blockKeys;
|
||||
if (blockHash) {
|
||||
if (blockHash !== allocated.blockHash) {
|
||||
console.log("provided password did not yield the correct blockHash");
|
||||
// incorrect password probably
|
||||
waitFor.abort();
|
||||
return void cb({
|
||||
error: 'INVALID_PASSWORD',
|
||||
});
|
||||
}
|
||||
// the user has already created a block, so you should compare against that
|
||||
} else {
|
||||
// otherwise they're a legacy user, and we should check against the User_hash
|
||||
if (hash !== allocated.userHash) {
|
||||
console.log("provided password did not yield the correct userHash");
|
||||
waitFor.abort();
|
||||
return void cb({
|
||||
error: 'INVALID_PASSWORD',
|
||||
});
|
||||
}
|
||||
getBlockKeys(data, waitFor(function (obj) {
|
||||
if (obj && obj.error) {
|
||||
waitFor.abort();
|
||||
return void cb(obj);
|
||||
}
|
||||
oldBlockKeys = obj.blockKeys;
|
||||
Cred = obj.Cred;
|
||||
Login = obj.Login;
|
||||
Block = obj.Block;
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Check if our drive is already owned
|
||||
|
|
|
@ -741,6 +741,7 @@ define([
|
|||
|
||||
Store.deleteAccount = function (clientId, data, cb) {
|
||||
var edPublic = store.proxy.edPublic;
|
||||
var removeData = data && data.removeData;
|
||||
Store.anonRpcMsg(clientId, {
|
||||
msg: 'GET_METADATA',
|
||||
data: store.driveChannel
|
||||
|
@ -769,8 +770,11 @@ define([
|
|||
channel: store.driveChannel,
|
||||
force: true
|
||||
}, waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
if (!removeData) { return; }
|
||||
// Delete the block. Don't abort if it fails, it doesn't leak any data.
|
||||
store.rpc.removeLoginBlock(removeData, waitFor());
|
||||
}).nThen(function () {
|
||||
// TODO delete block
|
||||
// Log out current worker
|
||||
postMessage(clientId, "DELETE_ACCOUNT", token, function () {});
|
||||
store.network.disconnect();
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cp-settings-change-password, .cp-settings-own-drive {
|
||||
.cp-settings-change-password, .cp-settings-own-drive, .cp-settings-delete {
|
||||
[type="password"], [type="text"] {
|
||||
width: @sidebar_button-width;
|
||||
flex: unset;
|
||||
|
|
|
@ -469,63 +469,65 @@ define([
|
|||
});
|
||||
}, true);
|
||||
|
||||
create['delete'] = function() {
|
||||
if (!common.isLoggedIn()) { return; }
|
||||
var $div = $('<div>', { 'class': 'cp-settings-delete cp-sidebarlayout-element' });
|
||||
makeBlock('delete', function(cb) { // Msg.settings_deleteHint, .settings_deleteTitle
|
||||
if (!common.isLoggedIn()) { return cb(false); }
|
||||
|
||||
$('<span>', { 'class': 'label' }).text(Messages.settings_deleteTitle).appendTo($div);
|
||||
var button = h('button.btn.btn-danger', Messages.settings_deleteButton);
|
||||
var form = h('div', [
|
||||
UI.passwordInput({
|
||||
id: 'cp-settings-delete-account',
|
||||
placeholder: Messages.settings_changePasswordCurrent
|
||||
}, true),
|
||||
button
|
||||
]);
|
||||
var $form = $(form);
|
||||
var $button = $(button);
|
||||
var spinner = UI.makeSpinner($form);
|
||||
|
||||
$('<span>', { 'class': 'cp-sidebarlayout-description' })
|
||||
.append(Messages.settings_deleteHint).appendTo($div);
|
||||
|
||||
var $ok = $('<span>', { 'class': 'fa fa-check', title: Messages.saved });
|
||||
var $spinner = $('<span>', { 'class': 'fa fa-spinner fa-pulse' });
|
||||
|
||||
var $button = $('<button>', { 'id': 'cp-settings-delete', 'class': 'btn btn-danger' })
|
||||
.text(Messages.settings_deleteButton).appendTo($div);
|
||||
|
||||
$button.click(function() {
|
||||
$spinner.show();
|
||||
UI.confirm(Messages.settings_deleteConfirm, function(yes) {
|
||||
if (!yes) { return void $spinner.hide(); }
|
||||
sframeChan.query("Q_SETTINGS_DELETE_ACCOUNT", null, function(err, data) {
|
||||
// Owned drive
|
||||
if (data.state === true) {
|
||||
sframeChan.query('Q_SETTINGS_LOGOUT', null, function() {});
|
||||
UI.alert(Messages.settings_deleted, function() {
|
||||
common.gotoURL('/');
|
||||
});
|
||||
$ok.show();
|
||||
$spinner.hide();
|
||||
return;
|
||||
UI.confirmButton(button, {
|
||||
classes: 'btn-danger',
|
||||
multiple: true
|
||||
}, function() {
|
||||
$button.prop('disabled', 'disabled');
|
||||
var password = $form.find('#cp-settings-delete-account').val();
|
||||
if (!password) {
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
spinner.spin();
|
||||
sframeChan.query("Q_SETTINGS_DELETE_ACCOUNT", {
|
||||
password: password
|
||||
}, function(err, data) {
|
||||
if (data && data.error) {
|
||||
spinner.hide();
|
||||
$button.prop('disabled', '');
|
||||
if (data.error === 'INVALID_PASSWORD') {
|
||||
return void UI.warn(Messages.drive_sfPasswordError);
|
||||
}
|
||||
// Not owned drive
|
||||
var msg = h('div.cp-app-settings-delete-alert', [
|
||||
h('p', Messages.settings_deleteModal),
|
||||
h('pre', JSON.stringify(data, 0, 2))
|
||||
]);
|
||||
UI.alert(msg);
|
||||
$spinner.hide();
|
||||
});
|
||||
console.error(data.error);
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
// Owned drive
|
||||
if (data.state === true) {
|
||||
sframeChan.query('Q_SETTINGS_LOGOUT', null, function() {});
|
||||
UI.alert(Messages.settings_deleted, function() {
|
||||
common.gotoURL('/');
|
||||
});
|
||||
spinner.done();
|
||||
return;
|
||||
}
|
||||
// Not owned drive
|
||||
var msg = h('div.cp-app-settings-delete-alert', [
|
||||
h('p', Messages.settings_deleteModal),
|
||||
h('pre', JSON.stringify(data, 0, 2))
|
||||
]);
|
||||
UI.alert(msg);
|
||||
spinner.hide();
|
||||
$button.prop('disabled', '');
|
||||
});
|
||||
// TODO
|
||||
/*
|
||||
UI.confirm("Are you sure?", function (yes) {
|
||||
// Logout everywhere
|
||||
// Disconnect other tabs
|
||||
// Remove owned pads
|
||||
// Remove owned drive
|
||||
// Remove pinstore
|
||||
// Alert: "Account deleted", press OK to be redirected to the home page
|
||||
$spinner.hide();
|
||||
});*/
|
||||
});
|
||||
|
||||
$spinner.hide().appendTo($div);
|
||||
$ok.hide().appendTo($div);
|
||||
|
||||
return $div;
|
||||
};
|
||||
cb(form);
|
||||
}, true);
|
||||
|
||||
create['change-password'] = function() {
|
||||
if (!common.isLoggedIn()) { return; }
|
||||
|
|
|
@ -67,7 +67,7 @@ define([
|
|||
Cryptpad.mergeAnonDrive(cb);
|
||||
});
|
||||
sframeChan.on('Q_SETTINGS_DELETE_ACCOUNT', function (data, cb) {
|
||||
Cryptpad.deleteAccount(cb);
|
||||
Cryptpad.deleteAccount(data, cb);
|
||||
});
|
||||
sframeChan.on('Q_COLORTHEME_CHANGE', function (data, cb) {
|
||||
localStorage['CRYPTPAD_STORE|colortheme'] = data.theme;
|
||||
|
|
Loading…
Reference in New Issue