mirror of https://github.com/xwiki-labs/cryptpad
Automatic account deletion
This commit is contained in:
parent
632e6c2e6c
commit
a718603b36
|
@ -46,7 +46,8 @@
|
|||
"localforage": "^1.5.2",
|
||||
"html2canvas": "^0.4.1",
|
||||
"croppie": "^2.5.0",
|
||||
"sortablejs": "#^1.6.0"
|
||||
"sortablejs": "#^1.6.0",
|
||||
"saferphore": "^0.0.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"bootstrap": "^v4.0.0"
|
||||
|
|
|
@ -31,7 +31,7 @@ define(function () {
|
|||
|
||||
out.websocketError = 'Αδυναμία σύνδεσης στον διακομιστή...';
|
||||
out.typeError = "Αυτό το pad δεν είναι συμβατό με την επιλεγμένη εφαρμογή";
|
||||
out.onLogout = 'Έχετε αποσυνδεθεί, <a href="/" target="_blank">κάντε "κλικ" εδώ</a> για να συνδεθείτε<br>ή πατήστε <em>Escape</em> για να προσπελάσετε το έγγραφο σε λειτουργία ανάγνωσης μόνο.';
|
||||
out.onLogout = 'Έχετε αποσυνδεθεί, {0}κάντε "κλικ" εδώ{1} για να συνδεθείτε<br>ή πατήστε <em>Escape</em> για να προσπελάσετε το έγγραφο σε λειτουργία ανάγνωσης μόνο.';
|
||||
out.wrongApp = "Αδυναμία προβολής του περιεχομένου αυτής της συνεδρίας στον περιηγητή σας. Παρακαλώ δοκιμάστε επαναφόρτωση της σελίδας.";
|
||||
|
||||
out.loading = "Φόρτωση...";
|
||||
|
|
|
@ -152,7 +152,7 @@ define(function () {
|
|||
|
||||
out.websocketError = "Error al conectarse al servidor WebSocket";
|
||||
out.typeError = "Este documento no es compatible con la aplicación seleccionada";
|
||||
out.onLogout = "Tu sesión está cerrada, <a href=\"/\" target=\"_blank\">haz clic aquí</a> para iniciar sesión<br>o pulsa <em>Escape</em> para acceder al documento en modo sólo lectura.";
|
||||
out.onLogout = "Tu sesión está cerrada, {0}haz clic aquí{1} para iniciar sesión<br>o pulsa <em>Escape</em> para acceder al documento en modo sólo lectura.";
|
||||
out.loading = "Cargando...";
|
||||
out.error = "Error";
|
||||
out.language = "Idioma";
|
||||
|
|
|
@ -27,7 +27,7 @@ define(function () {
|
|||
|
||||
out.websocketError = 'Impossible de se connecter au serveur WebSocket...';
|
||||
out.typeError = "Ce pad n'est pas compatible avec l'application sélectionnée";
|
||||
out.onLogout = 'Vous êtes déconnecté de votre compte utilisateur, <a href="/" target="_blank">cliquez ici</a> pour vous authentifier<br>ou appuyez sur <em>Échap</em> pour accéder au pad en mode lecture seule.';
|
||||
out.onLogout = 'Vous êtes déconnecté de votre compte utilisateur, {0}cliquez ici{1} pour vous authentifier<br>ou appuyez sur <em>Échap</em> pour accéder au pad en mode lecture seule.';
|
||||
out.wrongApp = "Impossible d'afficher le contenu de ce document temps-réel dans votre navigateur. Vous pouvez essayer de recharger la page.";
|
||||
out.padNotPinned = 'Ce pad va expirer après 3 mois d\'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.';
|
||||
out.anonymousStoreDisabled = "L'administrateur de cette instance de CryptPad a désactivé le drive pour les utilisateurs non enregistrés. Vous devez vous connecter pour pouvoir utiliser CryptDrive.";
|
||||
|
@ -546,6 +546,8 @@ define(function () {
|
|||
out.settings_deleteHint = "La suppression de votre compte utilisateur est permanente. Votre CryptDrive et votre liste de pads seront supprimés du serveur. Le reste de vos pads sera supprimé après 90 jours d'inactivité si personne ne les a stockés dans leur CryptDrive.";
|
||||
out.settings_deleteButton = "Supprimer votre compte";
|
||||
out.settings_deleteModal = "Veuillez envoyer les informations suivantes à votre administrateur CryptPad afin que vos données soient supprimées du serveur.";
|
||||
out.settings_deleteConfirm = "Êtes-vous sûr de vouloir supprimer votre compte utilisateur ? Cette action est irréversible.";
|
||||
out.settings_deleted = "Votre compte utilisateur a été supprimé. Appuyez sur OK pour être rédirigé(e) vers la page d'accueil.";
|
||||
|
||||
out.settings_anonymous = "Vous n'êtes pas connecté. Ces préférences seront utilisées pour ce navigateur.";
|
||||
out.settings_publicSigningKey = "Clé publique de signature";
|
||||
|
|
|
@ -28,7 +28,7 @@ define(function () {
|
|||
|
||||
out.websocketError = 'Unable to connect to the websocket server...';
|
||||
out.typeError = "This pad is not compatible with the selected application";
|
||||
out.onLogout = 'You are logged out, <a href="/" target="_blank">click here</a> to log in<br>or press <em>Escape</em> to access your pad in read-only mode.';
|
||||
out.onLogout = 'You are logged out, {0}click here{1} to log in<br>or press <em>Escape</em> to access your pad in read-only mode.';
|
||||
out.wrongApp = "Unable to display the content of that realtime session in your browser. Please try to reload that page.";
|
||||
out.padNotPinned = 'This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.';
|
||||
out.anonymousStoreDisabled = "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive.";
|
||||
|
@ -550,6 +550,8 @@ define(function () {
|
|||
out.settings_deleteHint = "Account deletion is permanent. Your CryptDrive and your list of pads will be deleted from the server. The rest of your pads will be deleted in 90 days if nobody else has stored them in their CryptDrive.";
|
||||
out.settings_deleteButton = "Delete your account";
|
||||
out.settings_deleteModal = "Share the following information with your CryptPad administrator in order to have your data removed from their server.";
|
||||
out.settings_deleteConfirm = "Clicking OK will delete your account permanently. Are you sure?";
|
||||
out.settings_deleted = "Your user account is now deleted. Press OK to go to the home page.";
|
||||
|
||||
out.settings_anonymous = "You are not logged in. Settings here are specific to this browser.";
|
||||
out.settings_publicSigningKey = "Public Signing Key";
|
||||
|
|
|
@ -38,7 +38,7 @@ define(function () {
|
|||
|
||||
out.websocketError = 'Incapaz de se conectar com o servidor websocket...';
|
||||
out.typeError = "Este bloco não é compatível com a aplicação selecionada";
|
||||
out.onLogout = 'você foi desconectado, <a href="/" target="_blank">clique aqui</a> para se conectar, <br>ou pressione <em>ESC</em> para acessar seu bloco em modo somente leitura.';
|
||||
out.onLogout = 'você foi desconectado, {0}clique aqui{1} para se conectar, <br>ou pressione <em>ESC</em> para acessar seu bloco em modo somente leitura.';
|
||||
out.wrongApp = "Incapaz de mostrar o conteúdo em tempo real no seu navegador. Por favor tente recarregar a página.";
|
||||
|
||||
out.loading = "Carregando...";
|
||||
|
|
|
@ -13,7 +13,7 @@ define(function () {
|
|||
out.common_connectionLost = out.updated_0_common_connectionLost;
|
||||
out.websocketError = "Conexiune inexistentă către serverul websocket...";
|
||||
out.typeError = "Această filă nu este compatibilă cu aplicația aleasă";
|
||||
out.onLogout = "Nu mai ești autentificat, <a href=\"/\" target=\"_blank\">apasă aici</a> să te autentifici<br>sau apasă <em>Escape</em>să accesezi fila în modul citire.";
|
||||
out.onLogout = "Nu mai ești autentificat, {0}apasă aici{1} să te autentifici<br>sau apasă <em>Escape</em>să accesezi fila în modul citire.";
|
||||
out.wrongApp = "Momentan nu putem arăta conținutul sesiunii în timp real în fereastra ta. Te rugăm reîncarcă pagina.";
|
||||
out.loading = "Încarcă...";
|
||||
out.error = "Eroare";
|
||||
|
|
|
@ -31,7 +31,7 @@ define(function () {
|
|||
|
||||
out.websocketError = '無法連結上 websocket 伺服器...';
|
||||
out.typeError = "這個編輯檔與所選的應用程式並不相容";
|
||||
out.onLogout = '你已登出, <a href="/" target="_blank">點擊這裏</a> 來登入<br>或按<em>Escape</em> 來以唯讀模型使用你的編輯檔案';
|
||||
out.onLogout = '你已登出, {0}點擊這裏{1} 來登入<br>或按<em>Escape</em> 來以唯讀模型使用你的編輯檔案';
|
||||
out.wrongApp = "無法在瀏覽器顯示即時期間的內容,請試著再重新載入本頁。";
|
||||
|
||||
out.loading = "載入中...";
|
||||
|
|
2
rpc.js
2
rpc.js
|
@ -1481,7 +1481,7 @@ RPC.create = function (
|
|||
case 'REMOVE_PINS':
|
||||
return void removePins(Env, safeKey, function (e, response) {
|
||||
if (e) { return void Respond(e); }
|
||||
Respond(void 0, response);
|
||||
Respond(void 0, "OK");
|
||||
});
|
||||
// restricted to privileged users...
|
||||
case 'UPLOAD':
|
||||
|
|
|
@ -1148,7 +1148,7 @@ define([
|
|||
// so we can just use those and only check for errors
|
||||
var $container = $('<span>', {'class':'cp-limit-container'});
|
||||
var todo = function (err, data) {
|
||||
if (err) { return void console.error(err); }
|
||||
if (err || !data) { return void console.error(err || 'No data'); }
|
||||
|
||||
var usage = data.usage;
|
||||
var limit = data.limit;
|
||||
|
|
|
@ -622,6 +622,12 @@ define([
|
|||
window.location.href = '/login/';
|
||||
};
|
||||
|
||||
common.startAccountDeletion = function (cb) {
|
||||
// Logout other tabs
|
||||
LocalStore.logout(null, true);
|
||||
cb();
|
||||
};
|
||||
|
||||
var onMessage = function (cmd, data, cb) {
|
||||
cb = cb || function () {};
|
||||
switch (cmd) {
|
||||
|
@ -701,6 +707,10 @@ define([
|
|||
case 'DRIVE_REMOVE': {
|
||||
common.drive.onRemove.fire(data); break;
|
||||
}
|
||||
// Account deletion
|
||||
case 'DELETE_ACCOUNT': {
|
||||
common.startAccountDeletion(cb); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -779,11 +789,11 @@ define([
|
|||
|
||||
if (data.anonHash && !cfg.userHash) { LocalStore.setFSHash(data.anonHash); }
|
||||
|
||||
if (cfg.userHash && sessionStorage) {
|
||||
/*if (cfg.userHash && sessionStorage) {
|
||||
// copy User_hash into sessionStorage because cross-domain iframes
|
||||
// on safari replaces localStorage with sessionStorage or something
|
||||
sessionStorage.setItem(Constants.userHashKey, cfg.userHash);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (cfg.userHash) {
|
||||
var localToken = tryParsing(localStorage.getItem(Constants.tokenKey));
|
||||
|
|
|
@ -16,9 +16,11 @@ define([
|
|||
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
|
||||
'/bower_components/chainpad/chainpad.dist.js',
|
||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||
'/bower_components/nthen/index.js',
|
||||
'/bower_components/saferphore/index.js',
|
||||
], function (Sortify, UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger,
|
||||
CpNfWorker, NetConfig, AppConfig,
|
||||
Crypto, ChainPad, Listmap) {
|
||||
Crypto, ChainPad, Listmap, nThen, Saferphore) {
|
||||
var Store = {};
|
||||
|
||||
var postMessage = function () {};
|
||||
|
@ -421,28 +423,78 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
var getOwnedPads = function () {
|
||||
var list = [];
|
||||
store.userObject.getFiles([store.userObject.FILES_DATA]).forEach(function (id) {
|
||||
var data = store.userObject.getFileData(id);
|
||||
var edPublic = store.proxy.edPublic;
|
||||
|
||||
// Push channels owned by someone else or channel that should have expired
|
||||
// because of the expiration time
|
||||
if (data.owners && data.owners.length === 1 && data.owners.indexOf(edPublic) !== -1) {
|
||||
list.push(Hash.hrefToHexChannelId(data.href));
|
||||
}
|
||||
});
|
||||
return list;
|
||||
};
|
||||
var removeOwnedPads = function (waitFor) {
|
||||
// Delete owned pads
|
||||
var ownedPads = getOwnedPads();
|
||||
var sem = Saferphore.create(10);
|
||||
ownedPads.forEach(function (c) {
|
||||
var w = waitFor();
|
||||
sem.take(function (give) {
|
||||
Store.removeOwnedChannel(c, give(function (obj) {
|
||||
if (obj && obj.error) { console.error(obj.error); }
|
||||
w();
|
||||
}));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Store.deleteAccount = function (data, cb) {
|
||||
var toSign = {
|
||||
intent: 'Please delete my account.'
|
||||
};
|
||||
var edPublic = store.proxy.edPublic;
|
||||
var secret = Hash.getSecrets('drive', storeHash);
|
||||
toSign.drive = secret.channel;
|
||||
toSign.edPublic = store.proxy.edPublic;
|
||||
var signKey = Crypto.Nacl.util.decodeBase64(secret.keys.signKey);
|
||||
console.log(edPublic);
|
||||
console.log(secret.channel);
|
||||
Store.anonRpcMsg({
|
||||
msg: 'GET_METADATA',
|
||||
data: secret.channel
|
||||
}, function (data) {
|
||||
console.log(data[0]);
|
||||
var metadata = data[0];
|
||||
// Owned drive
|
||||
if (metadata && metadata.owners && metadata.owners.length === 1 &&
|
||||
metadata.owners.indexOf(edPublic) !== -1) {
|
||||
|
||||
nThen(function (waitFor) {
|
||||
var token = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
|
||||
store.proxy[Constants.tokenKey] = token;
|
||||
postMessage("DELETE_ACCOUNT", token, waitFor());
|
||||
}).nThen(function (waitFor) {
|
||||
removeOwnedPads(waitFor);
|
||||
}).nThen(function (waitFor) {
|
||||
// Delete Pin Store
|
||||
store.rpc.removePins(waitFor(function (err) {
|
||||
if (err) { console.error(err); }
|
||||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Delete Drive
|
||||
Store.removeOwnedChannel(secret.channel, waitFor());
|
||||
}).nThen(function () {
|
||||
store.network.disconnect();
|
||||
cb({
|
||||
state: true
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Not owned drive
|
||||
var toSign = {
|
||||
intent: 'Please delete my account.'
|
||||
};
|
||||
toSign.drive = secret.channel;
|
||||
toSign.edPublic = edPublic;
|
||||
var signKey = Crypto.Nacl.util.decodeBase64(secret.keys.signKey);
|
||||
var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey);
|
||||
var proofTxt = Crypto.Nacl.util.encodeBase64(proof);
|
||||
cb({
|
||||
|
@ -529,8 +581,12 @@ define([
|
|||
|
||||
// Reset the drive part of the userObject (from settings)
|
||||
Store.resetDrive = function (data, cb) {
|
||||
store.proxy.drive = store.fo.getStructure();
|
||||
onSync(cb);
|
||||
nThen(function (waitFor) {
|
||||
removeOwnedPads(waitFor);
|
||||
}).nThen(function (waitFor) {
|
||||
store.proxy.drive = store.fo.getStructure();
|
||||
onSync(cb);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -92,7 +92,7 @@ define([
|
|||
});
|
||||
};
|
||||
var logoutHandlers = [];
|
||||
LocalStore.logout = function (cb) {
|
||||
LocalStore.logout = function (cb, isDeletion) {
|
||||
[
|
||||
Constants.userNameKey,
|
||||
Constants.userHashKey,
|
||||
|
@ -112,9 +112,11 @@ define([
|
|||
}
|
||||
eraseTempSessionValues();
|
||||
|
||||
logoutHandlers.forEach(function (h) {
|
||||
if (typeof (h) === "function") { h(); }
|
||||
});
|
||||
if (!isDeletion) {
|
||||
logoutHandlers.forEach(function (h) {
|
||||
if (typeof (h) === "function") { h(); }
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof(AppConfig.customizeLogout) === 'function') {
|
||||
return void AppConfig.customizeLogout(cb);
|
||||
|
|
|
@ -165,6 +165,17 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
exp.removePins = function (cb) {
|
||||
rpc.send('REMOVE_PINS', undefined, function (e, response) {
|
||||
if (e) { return void cb(e); }
|
||||
if (response && response.length && response[0] === "OK") {
|
||||
cb();
|
||||
} else {
|
||||
cb('INVALID_RESPONSE');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exp.uploadComplete = function (cb) {
|
||||
rpc.send('UPLOAD_COMPLETE', null, function (e, res) {
|
||||
if (e) { return void cb(e); }
|
||||
|
|
|
@ -17,7 +17,7 @@ define([
|
|||
|
||||
'/bower_components/file-saver/FileSaver.min.js',
|
||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/customize/src/less2/main.less',
|
||||
], function (
|
||||
$,
|
||||
|
|
|
@ -41,7 +41,7 @@ define([
|
|||
var patchTransformer = config.patchTransformer;
|
||||
var validateContent = config.validateContent;
|
||||
var avgSyncMilliseconds = config.avgSyncMilliseconds;
|
||||
var logLevel = typeof(config.logLevel) !== 'undefined'? config.logLevel : 2;
|
||||
var logLevel = typeof(config.logLevel) !== 'undefined'? config.logLevel : 1;
|
||||
var readOnly = config.readOnly || false;
|
||||
var sframeChan = config.sframeChan;
|
||||
var metadataMgr = config.metadataMgr;
|
||||
|
|
|
@ -622,6 +622,7 @@ define([
|
|||
window.location.hash = hash;
|
||||
};
|
||||
|
||||
console.log(secret.channel);
|
||||
var cpNfCfg = {
|
||||
sframeChan: sframeChan,
|
||||
channel: secret.channel,
|
||||
|
|
|
@ -397,19 +397,6 @@ define([
|
|||
|
||||
UI.addTooltips();
|
||||
|
||||
ctx.sframeChan.on('EV_LOGOUT', function () {
|
||||
$(window).on('keyup', function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
UI.removeLoadingScreen();
|
||||
}
|
||||
});
|
||||
UI.addLoadingScreen({hideTips: true});
|
||||
UI.errorLoadingScreen(Messages.onLogout, true);
|
||||
logoutHandlers.forEach(function (h) {
|
||||
if (typeof (h) === "function") { h(); }
|
||||
});
|
||||
});
|
||||
|
||||
ctx.sframeChan.on('Q_INCOMING_FRIEND_REQUEST', function (confirmMsg, cb) {
|
||||
UI.confirm(confirmMsg, cb, null, true);
|
||||
});
|
||||
|
@ -425,6 +412,23 @@ define([
|
|||
var feedback = ctx.metadataMgr.getPrivateData().feedbackAllowed;
|
||||
Feedback.init(feedback);
|
||||
} catch (e) { Feedback.init(false); }
|
||||
|
||||
ctx.sframeChan.on('EV_LOGOUT', function () {
|
||||
$(window).on('keyup', function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
UI.removeLoadingScreen();
|
||||
}
|
||||
});
|
||||
UI.addLoadingScreen({hideTips: true});
|
||||
var origin = ctx.metadataMgr.getPrivateData().origin;
|
||||
var href = origin + "/login/";
|
||||
var onLogoutMsg = Messages._getKey('onLogout', ['<a href="' + href + '" target="_blank">', '</a>']);
|
||||
UI.errorLoadingScreen(onLogoutMsg, true);
|
||||
logoutHandlers.forEach(function (h) {
|
||||
if (typeof (h) === "function") { h(); }
|
||||
});
|
||||
});
|
||||
|
||||
ctx.sframeChan.ready();
|
||||
cb(funcs);
|
||||
});
|
||||
|
|
|
@ -326,7 +326,7 @@ define([
|
|||
$('<span>', {'class': 'cp-sidebarlayout-description'})
|
||||
.append(Messages.settings_deleteHint).appendTo($div);
|
||||
|
||||
//var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
|
||||
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'})
|
||||
|
@ -334,13 +334,26 @@ define([
|
|||
|
||||
$button.click(function () {
|
||||
$spinner.show();
|
||||
sframeChan.query("Q_SETTINGS_DELETE_ACCOUNT", null, function (err, data) {
|
||||
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();
|
||||
UI.confirm(Messages.settings_deleteConfirm, function (yes) {
|
||||
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;
|
||||
}
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
// TODO
|
||||
/*
|
||||
|
@ -356,6 +369,7 @@ define([
|
|||
});
|
||||
|
||||
$spinner.hide().appendTo($div);
|
||||
$ok.hide().appendTo($div);
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue