From 336d717c67d14e1250ea26df4e7d8332ff686dc8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 31 Jan 2018 15:29:57 +0100 Subject: [PATCH 01/12] fix text --- customize.dist/translations/messages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 32c61825f..1ec8d708e 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -475,7 +475,7 @@ define(function () { out.register_mustAcceptTerms = "You must accept the terms of service."; out.register_mustRememberPass = "We cannot reset your password if you forget it. It's very important that you remember it! Please check the checkbox to confirm."; - out.register_whyRegister = "Why signing up?"; + out.register_whyRegister = "Why sign up?"; out.register_header = "Welcome to CryptPad"; out.register_explanation = [ "

Lets go over a couple things first:

", From be0842c66dbc731eb7215a6bfab2a00f5f5fd7e6 Mon Sep 17 00:00:00 2001 From: Sven Neuhaus Date: Wed, 14 Feb 2018 15:47:17 +0100 Subject: [PATCH 02/12] add license to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index b9cac6c82..624e45aec 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", "version": "1.25.0", + "license": "AGPL-3.0-only", "dependencies": { "chainpad-server": "^2.0.0", "express": "~4.10.1", From 15a81960373ba66ff855385ec6e49d0c5173f8a6 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 20 Feb 2018 10:39:02 +0100 Subject: [PATCH 03/12] Enable pad creation screen --- www/common/application_config_internal.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 91520c99a..f6760f897 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -83,8 +83,9 @@ define(function() { contacts: 'fa-users', }; - // EXPERIMENTAL: Enabling "displayCreationScreen" may cause UI issues and possible loss of data - config.displayCreationScreen = false; + // Ability to create owned pads and expiring pads through a new pad creation screen. + // The new screen can be disabled by the users in their settings page + config.displayCreationScreen = true; // Prevent anonymous users from storing pads in their drive config.disableAnonymousStore = false; From c409cac2805c3dae671d47a1b07912c66cf93dfd Mon Sep 17 00:00:00 2001 From: Sven Neuhaus Date: Thu, 22 Feb 2018 13:03:53 +0100 Subject: [PATCH 04/12] changed to AGPL-3.0-or-later --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 624e45aec..f8fec3fd7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", "version": "1.25.0", - "license": "AGPL-3.0-only", + "license": "AGPL-3.0-or-later", "dependencies": { "chainpad-server": "^2.0.0", "express": "~4.10.1", From d2b3e078d53f7e357aeaf41bd4bb8e894b416b14 Mon Sep 17 00:00:00 2001 From: Sven Neuhaus Date: Thu, 22 Feb 2018 13:05:00 +0100 Subject: [PATCH 05/12] updated version to resolve conflict --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f8fec3fd7..484bd77cf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "1.25.0", + "version": "1.26.0", "license": "AGPL-3.0-or-later", "dependencies": { "chainpad-server": "^2.0.0", From 9b94c9b7624458b80f72b730862e5d52bdf14cfb Mon Sep 17 00:00:00 2001 From: sairim <35785003+sairim@users.noreply.github.com> Date: Sun, 25 Feb 2018 16:54:49 +0200 Subject: [PATCH 06/12] Update readme.md include a link to Docker wiki page under the 'Setup using Docker' section --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 9d32288ce..150d21bba 100644 --- a/readme.md +++ b/readme.md @@ -22,7 +22,7 @@ The most recent version and all past release notes can be found [here](https://g ## Setup using Docker -See [Cryptpad-Docker](docs/cryptpad-docker.md). +See [Cryptpad-Docker](docs/cryptpad-docker.md) and the community wiki's [Docker](https://github.com/xwiki-labs/cryptpad/wiki/Docker-(with-Nginx-and-Traefik)) page for details on how to get up-and-running with Cryptpad in Docker. ## Setup using Ansible From 64afcb7c0b37c798fe5a296047d1bafcf7a74c21 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 9 Mar 2018 10:12:12 +0100 Subject: [PATCH 07/12] comment out busyloop workaround for tippyjs --- www/common/common-interface.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index d10b289cd..9517971e7 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -674,7 +674,7 @@ define([ }; // This is the robust solution to remove dangling tooltips // The mutation observer does not always find removed nodes. - setInterval(UI.clearTooltips, delay); + //setInterval(UI.clearTooltips, delay); var checkRemoved = function (x) { var out = false; var xId = $(x).attr('aria-describedby'); From 7dc7d5d95081cc2101026a92570b0c10ab4f979c Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 9 Mar 2018 12:12:47 +0100 Subject: [PATCH 08/12] lint compliance --- customize.dist/src/less2/include/help.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/src/less2/include/help.less b/customize.dist/src/less2/include/help.less index 7e22b713a..90f23119b 100644 --- a/customize.dist/src/less2/include/help.less +++ b/customize.dist/src/less2/include/help.less @@ -18,7 +18,7 @@ margin: 0; padding: 15px; a { - color: darken(@colortheme_link-color, 30%); + //color: darken(@colortheme_link-color, 30%); @spin: spin(lighten(@bg-color, 15%), 180); color: contrast(lighten(@bg-color, 15%), lighten(@spin, 10%), darken(@spin, 10%)); //color: darken(spin(lighten(@bg-color, 15%), 180), 10%); From b2df2ba341ceffdd876679188c1e355fcb1c014a Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 12 Mar 2018 17:50:47 +0100 Subject: [PATCH 09/12] prototype owned file upload --- package.json | 1 + rpc.js | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/package.json b/package.json index 3ab228851..e94c51a14 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "dependencies": { "chainpad-server": "^2.0.0", "express": "~4.16.0", + "mkdirp": "^0.5.1", "nthen": "~0.1.0", "pull-stream": "^3.6.1", "replify": "^1.2.0", diff --git a/rpc.js b/rpc.js index 465413fd1..3ad1a9a42 100644 --- a/rpc.js +++ b/rpc.js @@ -13,6 +13,7 @@ const Package = require('./package.json'); const Pinned = require('./pinned'); const Saferphore = require("saferphore"); const nThen = require("nthen"); +const Mkdirp = require("mkdirp"); var RPC = module.exports; @@ -980,6 +981,93 @@ var upload_complete = function (Env, publicKey, cb) { tryRandomLocation(handleMove); }; +var owned_upload_complete = function (Env, safeKey, cb) { + var session = getSession(Env.Sessions, safeKey); + + // the file has already been uploaded to the staging area + // close the pending writestream + if (session.blobstage && session.blobstage.close) { + session.blobstage.close(); + delete session.blobstage; + } + + var oldPath = makeFilePath(Env.paths.staging, safeKey); + + // construct relevant paths + var root = Env.paths.staging; + + //var safeKey = escapeKeyCharacters(safeKey); + var safeKeyPrefix = safeKey.slice(0, 2); + + var blobId = createFileId(); + var blobIdPrefix = blobId.slice(0, 2); + + var plannedPath = Path.join(root, safeKeyPrefix, safeKey, blobIdPrefix); + + var tries = 0; + + var chooseSafeId = function (cb) { + if (tries >= 3) { + // you've already failed three times in a row + // give up and return an error + cb('E_REPEATED_FAILURE'); + } + + var path = Path.join(plannedPath, blobId); + Fs.access(path, Fs.constants.R_OK | Fs.constants.W_OK, function (e) { + if (!e) { + // generate a new id (with the same prefix) and recurse + blobId = blobIdPrefix + createFileId().slice(2); + return void chooseSafeId(cb); + } else if (e.code === 'ENOENT') { + // no entry, so it's safe for us to proceed + return void cb(void 0, path); + } else { + // it failed in an unexpected way. log it + // try again, but no more than a fixed number of times... + tries++; + chooseSafeId(cb); + } + }); + }; + + // the user wants to move it into their own space + // /blob/safeKeyPrefix/safeKey/blobPrefix/blobID + + var finalPath; + nThen(function (w) { + // make the requisite directory structure using Mkdirp + Mkdirp(plannedPath, w(function (e /*, path */) { + if (e) { // does not throw error if the directory already existed + w.abort(); + return void cb(e); // XXX do we export Errors or strings? + } + })); + }).nThen(function (w) { + // produce an id which confirmably does not collide with another + chooseSafeId(w(function (e, path) { + if (e) { + w.abort(); + return void cb(e); + } + finalPath = path; // this is where you'll put the new file + })); + }).nThen(function (w) { + // move the existing file to its new path + Fs.rename(oldPath /* XXX */, finalPath, w(function (e) { + if (e) { + w.abort(); + return void cb(e.code); + } + // otherwise it worked... + })); + }).nThen(function () { + // clean up their session when you're done + // call back with the blob id... + cb(void 0, blobId); + }); +}; + var upload_status = function (Env, publicKey, filesize, cb) { var paths = Env.paths; @@ -1054,6 +1142,7 @@ var isAuthenticatedCall = function (call) { 'GET_LIMIT', 'UPLOAD_STATUS', 'UPLOAD_COMPLETE', + 'OWNED_UPLOAD_COMPLETE', 'UPLOAD_CANCEL', 'EXPIRE_SESSION', 'CLEAR_OWNED_CHANNEL', @@ -1128,6 +1217,7 @@ RPC.create = function ( var pinPath = paths.pin = keyOrDefaultString('pinPath', './pins'); var blobPath = paths.blob = keyOrDefaultString('blobPath', './blob'); var blobStagingPath = paths.staging = keyOrDefaultString('blobStagingPath', './blobstage'); + console.log(blobStagingPath); var isUnauthenticateMessage = function (msg) { return msg && msg.length === 2 && isUnauthenticatedCall(msg[0]); @@ -1375,6 +1465,12 @@ RPC.create = function ( WARN(e, hash); Respond(e, hash); }); + case 'OWNED_UPLOAD_COMPLETE': + if (!privileged) { return deny(); } + return void owned_upload_complete(Env, safeKey, function (e, blobId) { + WARN(e, blobId); + Respond(e, blobId); + }); case 'UPLOAD_CANCEL': if (!privileged) { return deny(); } return void upload_cancel(Env, safeKey, function (e) { From e56d7624091bc1406bd30b88807d30c004c7db82 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 13 Mar 2018 14:38:56 +0100 Subject: [PATCH 10/12] Catch chainpad errors and display it in the UI --- customize.dist/translations/messages.fr.js | 4 +++- customize.dist/translations/messages.js | 4 +++- www/common/common-ui-elements.js | 4 ++-- www/common/sframe-app-framework.js | 21 ++++++++++++++++++--- www/common/toolbar3.js | 1 + www/whiteboard/inner.js | 11 ++++++++++- 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 24299e422..9dc0e21db 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -32,9 +32,11 @@ define(function () { 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."; out.expiredError = "Ce pad a atteint sa date d'expiration est n'est donc plus disponible."; - out.expiredErrorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur Échap.
Dés que vous aurez quitté la page, il sera impossible de le récupérer.'; out.deletedError = 'Ce pad a été supprimé par son propriétaire et n\'est donc plus disponible.'; out.inactiveError = 'Ce pad a été supprimé en raison de son inactivité. Appuyez sur Échap pour créer un nouveau pad.'; + out.chainpadError = 'Une erreur critique est survenue lors de la mise à jour du contenu. Le pad est désormais en mode lecture seule afin de s\'assurer que vous ne perdiez pas davantage de données.
' + + 'Appuyez sur Échap pour voir le pad ou rechargez la page pour pouvoir le modifier à nouveau.'; + out.errorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur Échap.
Dés que vous aurez quitté la page, il sera impossible de le récupérer.'; out.loading = "Chargement..."; out.error = "Erreur"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index f0eeda3bc..ac90a1d3b 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -33,9 +33,11 @@ define(function () { 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."; out.expiredError = 'This pad has reached its expiration time and is no longer available.'; - out.expiredErrorCopy = ' You can still copy the content to another location by pressing Esc.
Once you leave this page, it will disappear forever!'; out.deletedError = 'This pad has been deleted by its owner and is no longer available.'; out.inactiveError = 'This pad has been deleted due to inactivity. Press Esc to create a new pad.'; + out.chainpadError = 'A critical error occurred when updating your content. This page is in read-only mode to make sure you won\'t lose your work.
' + + 'Hit Esc to continue to view this pad, or reload to try editing again.'; + out.errorCopy = ' You can still copy the content to another location by pressing Esc.
Once you leave this page, it will disappear forever!'; out.loading = "Loading..."; out.error = "Error"; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 3d6b33964..07ad3d98d 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2066,12 +2066,12 @@ define([ if (err.type === 'EEXPIRED') { msg = Messages.expiredError; if (err.loaded) { - msg += Messages.expiredErrorCopy; + msg += Messages.errorCopy; } } else if (err.type === 'EDELETED') { msg = Messages.deletedError; if (err.loaded) { - msg += Messages.expiredErrorCopy; + msg += Messages.errorCopy; } } if (toolbar && typeof toolbar.deleted === "function") { toolbar.deleted(); } diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index a095122d6..cbf31bb6e 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -45,6 +45,7 @@ define([ FORGOTTEN: 'FORGOTTEN', DELETED: 'DELETED', INFINITE_SPINNER: 'INFINITE_SPINNER', + ERROR: 'ERROR', INITIALIZING: 'INITIALIZING', HISTORY_MODE: 'HISTORY_MODE', READY: 'READY' @@ -118,9 +119,9 @@ define([ return; }; - var stateChange = function (newState) { + var stateChange = function (newState, text) { var wasEditable = (state === STATE.READY); - if (state === STATE.DELETED) { return; } + if (state === STATE.DELETED || state === STATE.ERROR) { return; } if (state === STATE.INFINITE_SPINNER && newState !== STATE.READY) { return; } if (newState === STATE.INFINITE_SPINNER || newState === STATE.DELETED) { state = newState; @@ -147,6 +148,14 @@ define([ evStart.reg(function () { toolbar.failed(); }); break; } + case STATE.ERROR: { + evStart.reg(function () { + toolbar.errorState(true, text); + var msg = Messages.chainpadError; + UI.errorLoadingScreen(msg, true, true); + }); + break; + } case STATE.FORGOTTEN: { evStart.reg(function () { toolbar.forgotten(); }); break; @@ -249,7 +258,12 @@ define([ } var contentStr = JSONSortify(content); - cpNfInner.chainpad.contentUpdate(contentStr); + try { + cpNfInner.chainpad.contentUpdate(contentStr); + } catch (e) { + stateChange(STATE.ERROR, e.message); + console.error(e); + } if (cpNfInner.chainpad.getUserDoc() !== contentStr) { console.error("realtime.getUserDoc() !== shjson"); } @@ -463,6 +477,7 @@ define([ window.setInterval(function () { if (state === STATE.DISCONNECTED) { return; } if (state === STATE.DELETED) { return; } + if (state === STATE.ERROR) { return; } var l; try { l = cpNfInner.chainpad.getLag(); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index 0c9d3c8f3..652047615 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -1061,6 +1061,7 @@ define([ toolbar.errorState = function (state, error) { toolbar.isErrorState = state; + if (state) { toolbar.connected = false; } if (toolbar.spinner) { if (!state) { return void kickSpinner(toolbar, config); diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 7e132ae18..489637e10 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -346,7 +346,16 @@ define([ var content = stringifyInner(canvas.toDatalessJSON()); - APP.realtime.contentUpdate(content); + try { + APP.realtime.contentUpdate(content); + } catch (e) { + APP.unrecoverable = true; + setEditable(false); + APP.toolbar.errorState(true, e.message); + var msg = Messages.chainpadError; + UI.errorLoadingScreen(msg, true, true); + console.error(e); + } }; var addImageToCanvas = function (img) { From 645e47bd7260ac7b004fec01bdf1176f3285761a Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 13 Mar 2018 15:10:33 +0100 Subject: [PATCH 11/12] Catch chainpad errors in polls --- www/poll/inner.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/www/poll/inner.js b/www/poll/inner.js index a6e9b8bd8..9222d90a0 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -1106,6 +1106,25 @@ define([ } }; + var onError = function (info) { + if (info && info.type) { + if (info.type === 'CHAINPAD') { + APP.unrecoverable = true; + setEditable(false); + APP.toolbar.errorState(true, info.error); + var msg = Messages.chainpadError; + UI.errorLoadingScreen(msg, true, true); + console.error(info.error); + return; + } + // Server error + return void common.onServerError(info, APP.toolbar, function () { + APP.unrecoverable = true; + setEditable(false); + }); + } + }; + // Manage disconnections because of network or error var onDisconnect = function (info) { if (APP.unrecoverable) { return; } @@ -1318,7 +1337,8 @@ define([ }); }) .on('disconnect', onDisconnect) - .on('reconnect', onReconnect); + .on('reconnect', onReconnect) + .on('error', onError); }); }; main(); From e977b14c1b33da840ae28c4e2ddbc38ecaea87e3 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 14 Mar 2018 11:50:17 +0100 Subject: [PATCH 12/12] Update French translation --- customize.dist/translations/messages.fr.js | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 9dc0e21db..e1e8c59ba 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -363,7 +363,7 @@ define(function () { out.fm_templateName = "Modèles"; out.fm_searchName = "Recherche"; out.fm_recentPadsName = "Pads récents"; - out.fm_ownedPadsName = "Pads possédés"; + out.fm_ownedPadsName = "Pads en votre possession"; out.fm_searchPlaceholder = "Rechercher..."; out.fm_newButton = "Nouveau"; out.fm_newButtonTitle = "Créer un nouveau pad ou un dossier, importer un fichier dans le dossier courant"; @@ -771,13 +771,13 @@ define(function () { 'Il désigne un document que vous pouvez modifier dans votre navigateur et, en général, vous pouvez voir les modifications effectuées par les autres utilisateurs de manière quasiment instantanée.' }, owned: { - q: "Qu'est-ce qu'un pad possédé ?", - a: "Un pad possédé est un pad créé avec un propriétaire explicite, identifié sur le serveur par sa clé de signature publique.
" + + q: "Qu'est-ce qu'un pad avec propriétaire ?", + a: "Être propriétaire d'un pad signifie que vous êtes identifié comme tel par le serveur avec à votre clé de signature publique.
" + "Le propriétaire d'un pad peut décider de supprimer ce pad du serveur de manière permanente, afin de le rendre inaccessible aux autres collaborateurs même s'ils possédent le lien dans leur CryptDrive." }, expiring: { - q: "Qu'est-ce qu'un pad expirant ?", - a: "Un pad expirant est un pad créé avec une date définie à partir de laquelle il sera supprimé automatiquement du serveur. Les pads expirants peuvent être configurés pour avoir une durée de vie comprise entre une heure et cent mois. Le pad et tout son historique sera alors inaccessible, de manière permanente, même s'il est en cours d'édition à sa date d'expiration.
" + + q: "Qu'est-ce qu'un pad à durée de vie ?", + a: "Un pad à durée de vie est un pad créé avec une date définie à partir de laquelle il sera supprimé automatiquement du serveur. Ils peuvent être configurés pour avoir une durée de vie comprise entre une heure et cent mois. Le pad et tout son historique sera alors inaccessible, de manière permanente, même s'il est en cours d'édition à sa date d'expiration.
" + "Si un pad possède une date d'expiration, vous pouvez la vérifier en regardant les propriétés du pad, soit avec un clic-droit sur le pad dans votre CryptDrive, ou soit en cliquant sur Propriétés dans le sous-menu de la barre d'outils de l'application." }, tag: { @@ -871,9 +871,9 @@ define(function () { }, remove: { q: "J'ai supprimé un pad ou un fichier de mon CryptDrive, mais le contenu est encore disponible. Comment le supprimer ?", - a: "Seuls les pads possédés (introduits en février 2018) peuvent être supprimés du serveur. Ils ne peuvent d'ailleurs être supprimés du serveur que par leur propriétaire (l'utilisateur ayant créé le pad).
" + + a: "Seuls les pads avec propriétaire (introduits en février 2018) peuvent être supprimés du serveur. Ils ne peuvent d'ailleurs être supprimés du serveur que par leur propriétaire (l'utilisateur ayant créé le pad).
" + "Si vous n'êtes pas le créateur du pad, vous devrez demander au propriétaire de le supprimer pour vous.
" + - "Pour les pads que vous possédez, vous pouvez effectuer un clic-droit sur le pad dans votre CryptDrive, et sélectionner Supprimer du serveur." + "Pour les pads dont vous êtes le propriétaire, vous pouvez effectuer un clic-droit sur le pad dans votre CryptDrive, et sélectionner Supprimer du serveur." }, forget: { q: "Que faire si j'oublie mon mot de passe ?", @@ -1062,10 +1062,10 @@ define(function () { // Creation page out.creation_404 = "Ce pad n'existe plus. Vous pouvez créer un nouveau pad en utilisant le formulaire suivant."; out.creation_ownedTitle = "Type de pad"; - out.creation_ownedTrue = "Pad possédé"; - out.creation_ownedFalse = "Pad ouvert"; - out.creation_owned1 = "Un pad possédé peut être supprimé du serveur à tout moment quand son propriétaire le souhaite. Une fois supprimé, il disparaît du CryptDrive des autres utilisateurs."; - out.creation_owned2 = "Un pad ouvert n'a pas de propriétaire et ne peut donc pas être supprimé du serveur à moins d'avoir dépassé sa date d'expiration."; + out.creation_ownedTrue = "Être propriétaire"; + out.creation_ownedFalse = "Pas de propriétaire"; + out.creation_owned1 = "Être propriétaire d'un pad signifie que vous pouvez le supprimer du serveur à tout moment. Une fois supprimé, il disparaît du CryptDrive des autres utilisateurs."; + out.creation_owned2 = "Un pad sans propriétaire ne peut pas être supprimé du serveur à moins d'avoir dépassé son éventuelle date d'expiration."; out.creation_expireTitle = "Durée de vie"; out.creation_expireTrue = "Ajouter durée de vie"; out.creation_expireFalse = "Illimité"; @@ -1073,21 +1073,21 @@ define(function () { out.creation_expireDays = "Jour(s)"; out.creation_expireMonths = "Mois"; out.creation_expire1 = "Un pad illimité ne sera pas supprimé du serveur à moins que son propriétaire ne le décide."; - out.creation_expire2 = "Un pad expirant a une durée de vie définie, après laquelle il sera supprimé automatiquement du serveur et du CryptDrive des utilisateurs."; + out.creation_expire2 = "Un pad à durée de vie sera supprimé automatiquement du serveur et du CryptDrive des utilisateurs lorsque cette durée sera dépassée."; out.creation_createTitle = "Créer un pad"; - out.creation_createFromTemplate = "Depuis un modèle"; - out.creation_createFromScratch = "Nouveau pad vide"; + out.creation_createFromTemplate = "Utiliser un modèle"; + out.creation_createFromScratch = "Créer un pad vide"; out.creation_settings = "Préférences des nouveaux pads"; out.creation_saveSettings = "Sauver les préférences"; // Properties about creation data out.creation_owners = "Propriétaires"; - out.creation_ownedByOther = "Possédé par un autre utilisateur"; + out.creation_ownedByOther = "Appartient à un autre utilisateur"; out.creation_noOwner = "Pas de propriétaire"; out.creation_expiration = "Date d'expiration"; out.creation_propertiesTitle = "Disponibilité"; out.creation_appMenuName = "Mode avancé (Ctrl + E)"; out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez aussi appuyer sur Tab pour sélectionner un type et appuyer sur Entrée pour valider."; - out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads possédés ou à date d'expiration). Vous pouvez appuyer sur Espace pour changer sa valeur."; + out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads avec propriétaire ou à durée de vie). Vous pouvez appuyer sur Espace pour changer sa valeur."; out.creation_newPadModalAdvanced = "Afficher l'écran de création de pads"; // New share modal