manual merge

pull/1/head
Caleb James DeLisle 7 years ago
commit e78cc4ce7e

1
.gitignore vendored

@ -1,4 +1,5 @@
datastore
tasks
www/bower_components/*
node_modules
/config.js

@ -194,6 +194,18 @@ module.exports = {
*/
},
/* some features may require that the server be able to schedule tasks
far into the future, such as:
> "three months from now, this channel should expire"
To disable these features, set 'enableTaskScheduling' to false
*/
enableTaskScheduling: true,
/* if you would like the list of scheduled tasks to be stored in
a custom location, change the path below:
*/
taskPath: './tasks',
/*
* By default, CryptPad also contacts our accounts server once a day to check for changes in
* the people who have accounts. This check-in will also send the version of your CryptPad

@ -79,7 +79,7 @@ define(req, function(Util, Default, Language) {
});
Object.keys(translation).forEach(function (k) {
if (/^_/.test(k) || k === 'driveReadme') { return; }
if (!Default[k]) {
if (typeof Default[k] === "undefined") {
missing.push([code, k, 0]);
}
});

@ -100,6 +100,7 @@ define([
h('div.collapse.navbar-collapse.justify-content-end#menuCollapse', [
h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.topbar_whatIsCryptpad),
h('a.nav-item.nav-link', { href: 'https://blog.cryptpad.fr/'}, Msg.blog),
h('a.nav-item.nav-link', { href: '/features.html'}, Msg.features),
h('a.nav-item.nav-link', { href: '/contact.html'}, Msg.contact),
h('a.nav-item.nav-link', { href: '/about.html'}, Msg.about),
].concat(rightLinks))
@ -332,6 +333,11 @@ define([
h('td')
]),
])
]),
h('div#cp-features-register', [
h('a', {
href: '/register/'
}, h('button.cp-features-register-button', 'Register for free'))
])
]),
infopageFooter()
@ -601,6 +607,9 @@ define([
setHTML(h('p.register-explanation'), Msg.register_explanation)
]),
h('div#userForm.form-group.hidden.col-md-6', [
h('a', {
href: '/features.html'
}, Msg.register_whyRegister),
h('input.form-control#username', {
type: 'text',
autocomplete: 'off',

@ -139,5 +139,14 @@
}
}
}
.cp-creation-settings {
justify-content: left;
a {
color: #0275d8;
&:hover {
color: lighten(#0275d8, 10%);
}
}
}
}
}

@ -8,9 +8,10 @@
width: 100%;
margin-top: 20px;
.cp-limit-bar {
padding: 5px;
display: inline-flex;
justify-content: center;
align-items: center;
display: inline-block;
max-width: 100%;
margin: 3px;
box-sizing: border-box;
@ -18,7 +19,6 @@
background: white;
position: relative;
text-align: center;
vertical-align: middle;
width: ~"calc(100% - 6px)";
height: 35px;
line-height: 25px;

@ -50,3 +50,18 @@ table#cp-features-table {
}
}
#cp-features-register {
text-align: center;
padding: 20px;
}
.cp-features-register-button {
font-size: 20px;
color: #fff;
background: @cryptpad_color_blue;
border: 2px solid @cryptpad_color_blue;
border-radius: 0;
&:hover {
transform: scale(1.05);
}
}

@ -377,7 +377,8 @@ define(function () {
out.fm_emptyTrashDialog = "Êtes-vous sûr de vouloir vider la corbeille ?";
out.fm_removeSeveralPermanentlyDialog = "Êtes-vous sûr de vouloir supprimer ces {0} éléments de votre CryptDrive de manière permanente ?";
out.fm_removePermanentlyDialog = "Êtes-vous sûr de vouloir supprimer cet élément de votre CryptDrive de manière permanente ?";
out.fm_deleteOwnedPads = "Êtes-vous sûr de vouloir supprimer définitivement ce pad du serveur ?";
out.fm_deleteOwnedPad = "Êtes-vous sûr de vouloir supprimer définitivement ce pad du serveur ?";
out.fm_deleteOwnedPads = "Êtes-vous sûr de vouloir supprimer définitivement ces pads du serveur ?";
out.fm_restoreDialog = "Êtes-vous sûr de vouloir restaurer {0} à son emplacement précédent ?";
out.fm_removeSeveralDialog = "Êtes-vous sûr de vouloir déplacer ces {0} éléments vers la corbeille ?";
out.fm_removeDialog = "Êtes-vous sûr de vouloir déplacer {0} vers la corbeille ?";
@ -392,7 +393,8 @@ define(function () {
out.updated_0_fm_info_trash = "Vider la corbeille permet de libérer de l'espace dans votre CryptDrive";
out.fm_info_trash = out.updated_0_fm_info_trash;
out.fm_info_allFiles = 'Contient tous les fichiers de "Documents", "Fichiers non triés" et "Corbeille". Vous ne pouvez pas supprimer ou déplacer des fichiers depuis cet endroit.'; // Same here
out.fm_info_anonymous = 'Vous n\'êtes pas connecté, ces pads risquent donc d\'être supprimés (<a href="https://blog.cryptpad.fr/2017/05/17/You-gotta-log-in/" target="_blank">découvrez pourquoi</a>). ' +
out.fm_info_anonymous = 'Vous n\'êtes pas connecté, ces pads seront donc supprimés après 3 mois d\'inactivité (<a href="https://blog.cryptpad.fr/2017/05/17/You-gotta-log-in/" target="_blank">découvrez pourquoi</a>). ' +
'Ils sont stockés dans votre navigateur donc nettoyer votre historique peut les faire disparaître.<br>' +
'<a href="/register/">Inscrivez-vous</a> ou <a href="/login/">connectez-vous</a> pour les maintenir en vie.';
out.fm_info_owned = "Vous êtes propriétaire des pads affichés dans cette catégorie. Cela signifie que vous pouvez choisir de les supprimer définitivement du serveur à n'importe quel moment. Ils seront alors inaccessibles pour tous les autres utilisateurs.";
out.fm_alert_backupUrl = "Lien de secours pour ce CryptDrive.<br>" +
@ -415,6 +417,7 @@ define(function () {
"Cette action supprimera votre CryptDrive et son historique de votre navigateur, mais les pads existeront toujours (de manière chiffrée) sur notre serveur.";
out.fm_padIsOwned = "Vous êtes le propriétaire de ce pad";
out.fm_padIsOwnedOther = "Ce pad est la propriété d'un autre utilisateur";
out.fm_deletedPads = "Ces pads n'existent plus sur le serveur, ils ont été supprimés de votre CryptDrive: {0}";
// File - Context menu
out.fc_newfolder = "Nouveau dossier";
out.fc_rename = "Renommer";
@ -474,6 +477,7 @@ define(function () {
out.register_warning = "Zero Knowledge signifie que nous ne pouvons pas récupérer vos données si vous perdez vos identifiants.";
out.register_alreadyRegistered = "Cet utilisateur existe déjà, souhaitez-vous vous connecter ?";
out.register_whyRegister = "Pourquoi s'inscrire ?";
out.register_header = "Bienvenue dans CryptPad";
out.register_explanation = [
"<p>Faisons d'abord le point sur certaines choses</p>",
@ -567,7 +571,9 @@ define(function () {
out.upload_uploadPending = "Vous avez déjà un fichier en cours d'importation. Souhaitez-vous l'annuler et importer ce nouveau fichier ?";
out.upload_success = "Votre fichier ({0}) a été importé avec succès et ajouté à votre CryptDrive.";
out.upload_notEnoughSpace = "Il n'y a pas assez d'espace libre dans votre CryptDrive pour ce fichier.";
out.upload_notEnoughSpaceBrief = "Pas assez d'espace";
out.upload_tooLarge = "Ce fichier dépasse la taille maximale autorisée.";
out.upload_tooLargeBrief = 'Fichier trop volumineux';
out.upload_choose = "Choisir un fichier";
out.upload_pending = "En attente";
out.upload_cancelled = "Annulé";
@ -577,6 +583,7 @@ define(function () {
out.upload_mustLogin = "Vous devez vous connecter pour importer un fichier";
out.download_button = "Déchiffrer et télécharger";
out.download_mt_button = "Télécharger";
out.download_resourceNotAvailable = "Le fichier demandé n'est pas disponible...";
out.todo_title = "CryptTodo";
out.todo_newTodoNamePlaceholder = "Décrivez votre tâche...";
@ -707,6 +714,7 @@ define(function () {
// features.html
out.features = "Fonctionnalités";
out.features_title = "Tableau des fonctionnalités";
out.features_feature = "Fonctionnalité";
out.features_anon = "Utilisateur anonyme";
@ -839,6 +847,24 @@ define(function () {
out.feedback_optout = "Si vous le souhaitez, vous pouvez désactiver ces requêtes en vous rendant dans <a href='/settings/'>votre page de préférences</a>, où vous trouverez une case à cocher pour désactiver le retour d'expérience.";
// Creation page
out.creation_404 = "Le pad auquel vous souhaitez accéder 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 <b>possédé</b> est un pad que vous pouvez supprimer du serveur à n'importe quel moment depuis votre CryptDrive. Une fois supprimé, personne d'autre ne peut y accéder, même si le pad est stocké dans un autre CryptDrive.";
out.creation_owned2 = "Un pad <b>ouvert</b> n'a pas de propriétaire et ne peut donc pas être supprimé du serveur par un utilisateur. Il pourra tout de même être supprimé automatiquement si sa date d'expiration est dépassée.";
out.creation_expireTitle = "Durée de vie";
out.creation_expireTrue = "Ajouter durée de vie";
out.creation_expireFalse = "Illimitée";
out.creation_expireHours = "Heures";
out.creation_expireDays = "Jours";
out.creation_expireMonths = "Mois";
out.creation_expire1 = "Par défault, un pad stocké dans le CryptDrive d'un utilisateur enregistré ne sera jamais supprimé du serveur, même s'il est inactif (à moins qu'il possède un propriétaire souhaitement le supprimer).";
out.creation_expire2 = "Si vous le souhaitez, vous pouvez ajouter une durée de vie au pad afin d'être sûr qu'il soit supprimé du serveur, de manière permanente, à la date voulue.";
out.creation_createTitle = "Créer un pad";
out.creation_createFromTemplate = "Depuis un modèle";
out.creation_createFromScratch = "Nouveau pad vide";
out.creation_settings = "Préférences des nouveaux pads";
// Properties about creation data
out.creation_owners = "Propriétaires";
out.creation_ownedByOther = "Possédé par un autre utilisateur";

@ -381,7 +381,8 @@ define(function () {
out.fm_removePermanentlyDialog = "Are you sure you want to remove that element from your CryptDrive permanently?";
out.fm_removeSeveralDialog = "Are you sure you want to move these {0} elements to the trash?";
out.fm_removeDialog = "Are you sure you want to move {0} to the trash?";
out.fm_deleteOwnedPads = "Are you sure you want to remove permanently this pad from the server?";
out.fm_deleteOwnedPad = "Are you sure you want to remove permanently this pad from the server?";
out.fm_deleteOwnedPads = "Are you sure you want to remove permanently these pads from the server?";
out.fm_restoreDialog = "Are you sure you want to restore {0} to its previous location?";
out.fm_unknownFolderError = "The selected or last visited directory no longer exist. Opening the parent folder...";
out.fm_contextMenuError = "Unable to open the context menu for that element. If the problem persist, try to reload the page.";
@ -395,7 +396,8 @@ define(function () {
out.fm_info_trash = out.updated_0_fm_info_trash;
out.fm_info_allFiles = 'Contains all the files from "Documents", "Unsorted" and "Trash". You can\'t move or remove files from here.'; // Same here
out.fm_info_anonymous = 'You are not logged in so your pads will expire after 3 months (<a href="https://blog.cryptpad.fr/2017/05/17/You-gotta-log-in/" target="_blank">find out more</a>). ' +
'<a href="/register/">Sign up</a> or <a href="/login/">Log in</a> to keep them alive.';
'They are stored in your browser so clearing history may make them disappear.<br>' +
'<a href="/register/">Sign up</a> or <a href="/login/">Log in</a> to keep them alive.<br>';
out.fm_info_owned = "You are the owner of the pads displayed here. This means you can remove them permanently from the server whenever you want. If you do so, other users won't be able to access them anymore.";
out.fm_alert_backupUrl = "Backup link for this drive.<br>" +
"It is <strong>highly recommended</strong> that you keep it secret.<br>" +
@ -417,6 +419,7 @@ define(function () {
"This will remove your CryptDrive and its history from your browser, but your pads will still exist (encrypted) on our server.";
out.fm_padIsOwned = "You are the owner of this pad";
out.fm_padIsOwnedOther = "This pad is owned by another user";
out.fm_deletedPads = "These pads no longer exist on the server, they've been removed from your CryptDrive: {0}";
// File - Context menu
out.fc_newfolder = "New folder";
out.fc_rename = "Rename";
@ -472,6 +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_header = "Welcome to CryptPad";
out.register_explanation = [
"<h3>Lets go over a couple things first:</h3>",
@ -717,6 +721,7 @@ define(function () {
// features.html
out.features = "Features";
out.features_title = "Features table";
out.features_feature = "Feature";
out.features_anon = "Anonymous user";
@ -738,6 +743,7 @@ define(function () {
out.features_f_multiple = "Use on multiple devices";
out.features_f_multiple_notes = "Easy way to access your pads from any device";
out.features_f_logoutEverywhere = "Log out from other devices";
out.features_f_logoutEverywhere_notes = ""; // Used in the French translation to explain
out.features_f_templates = "Use templates";
out.features_f_templates_notes = "Create templates and create new pads from your templates";
out.features_f_profile = "Create a profile";
@ -873,6 +879,7 @@ define(function () {
out.creation_createTitle = "Create a pad";
out.creation_createFromTemplate = "From template";
out.creation_createFromScratch = "From scratch";
out.creation_settings = "New Pad settings";
// Properties about creation data
out.creation_owners = "Owners";
out.creation_ownedByOther = "Owned by another user";

@ -11,6 +11,8 @@ var Path = require("path");
var Https = require("https");
const Package = require('./package.json');
const Pinned = require('./pinned');
const Saferphore = require("saferphore");
const nThen = require("nthen");
var RPC = module.exports;
@ -355,6 +357,37 @@ var getMultipleFileSize = function (Env, channels, cb) {
});
};
/* accepts a list, and returns a sublist of channel or file ids which seem
to have been deleted from the server (file size 0)
we might consider that we should only say a file is gone if fs.stat returns
ENOENT, but for now it's simplest to just rely on getFileSize...
*/
var getDeletedPads = function (Env, channels, cb) {
if (!Array.isArray(channels)) { return cb('INVALID_LIST'); }
var L = channels.length;
var sem = Saferphore.create(10);
var absentees = [];
var job = function (channel, wait) {
return function (give) {
getFileSize(Env, channel, wait(give(function (e, size) {
if (e) { return; }
if (size === 0) { absentees.push(channel); }
})));
};
};
nThen(function (w) {
for (var i = 0; i < L; i++) {
sem.take(job(channels[i], w));
}
}).nThen(function () {
cb(void 0, absentees);
});
};
var getTotalSize = function (Env, publicKey, cb) {
var bytes = 0;
return void getChannelList(Env, publicKey, function (channels) {
@ -1004,7 +1037,8 @@ var isUnauthenticatedCall = function (call) {
'GET_MULTIPLE_FILE_SIZE',
'IS_CHANNEL_PINNED',
'IS_NEW_CHANNEL',
'GET_HISTORY_OFFSET'
'GET_HISTORY_OFFSET',
'GET_DELETED_PADS',
].indexOf(call) !== -1;
};
@ -1133,6 +1167,14 @@ RPC.create = function (
}
respond(e, [null, dict, null]);
});
case 'GET_DELETED_PADS':
return void getDeletedPads(Env, msg[1], function (e, list) {
if (e) {
WARN(e, msg[1]);
return respond(e);
}
respond(e, [null, list, null]);
});
case 'IS_CHANNEL_PINNED':
return void isChannelPinned(Env, msg[1], function (isPinned) {
respond(null, [null, isPinned, null]);

@ -9,6 +9,7 @@ var WebSocketServer = require('ws').Server;
var NetfluxSrv = require('./node_modules/chainpad-server/NetfluxWebsocketSrv');
var Package = require('./package.json');
var Path = require("path");
var nThen = require("nthen");
var config;
try {
@ -213,35 +214,38 @@ if (config.httpSafePort) {
var wsConfig = { server: httpServer };
var createSocketServer = function (err, rpc) {
if(!config.useExternalWebsocket) {
if (websocketPort !== config.httpPort) {
console.log("setting up a new websocket server");
wsConfig = { port: websocketPort};
}
var wsSrv = new WebSocketServer(wsConfig);
Storage.create(config, function (store) {
NetfluxSrv.run(store, wsSrv, config, rpc);
});
}
};
var rpc;
var loadRPC = function (cb) {
var nt = nThen(function (w) {
if (!config.enableTaskScheduling) { return; }
var Tasks = require("./storage/tasks");
console.log("loading task scheduler");
Tasks.create(config, w(function (e, tasks) {
config.tasks = tasks;
}));
}).nThen(function (w) {
config.rpc = typeof(config.rpc) === 'undefined'? './rpc.js' : config.rpc;
if (typeof(config.rpc) === 'string') {
// load pin store...
var Rpc = require(config.rpc);
Rpc.create(config, debuggable, function (e, rpc) {
if (e) { throw e; }
cb(void 0, rpc);
});
} else {
cb();
if (typeof(config.rpc) !== 'string') { return; }
// load pin store...
var Rpc = require(config.rpc);
Rpc.create(config, debuggable, w(function (e, _rpc) {
if (e) {
w.abort();
throw e;
}
rpc = _rpc;
}));
}).nThen(function () {
if(config.useExternalWebsocket) { return; }
if (websocketPort !== config.httpPort) {
console.log("setting up a new websocket server");
wsConfig = { port: websocketPort};
}
};
loadRPC(createSocketServer);
var wsSrv = new WebSocketServer(wsConfig);
Storage.create(config, function (store) {
NetfluxSrv.run(store, wsSrv, config, rpc);
});
});
if (config.debugReplName) {
require('replify')({ name: config.debugReplName, app: debuggableStore });

@ -0,0 +1,94 @@
var Fs = require("fs");
var Path = require("path");
var nacl = require("tweetnacl");
var nThen = require("nthen");
var Tasks = module.exports;
var encode = function (time, command, args) {
if (typeof(time) !== 'number') { return null; }
if (typeof(command) !== 'string') { return null; }
if (!Array.isArray(args)) { return [time, command]; }
return [time, command].concat(args);
};
var randomId = function () {
var bytes = Array.prototype.slice.call(nacl.randomBytes(16));
return bytes.map(function (b) {
var n = Number(b & 0xff).toString(16);
return n.length === 1? '0' + n: n;
}).join('');
};
var mkPath = function (env, id) {
return Path.join(env.root, id.slice(0, 2), id) + '.ndjson';
};
var getFreeId = function (env, cb, tries) {
if (tries > 5) { return void cb('ETOOMANYTRIES'); }
// generate a unique id
var id = randomId();
// derive a path from that id
var path = mkPath(env, id);
Fs.stat(path, function (err) {
if (err && err.code === "ENOENT") {
cb(void 0, id);
} else {
getFreeId(env, cb);
}
});
};
var write = function (env, task, cb) {
var str = JSON.stringify(task) + '\n';
var id = nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(str))).replace(/\//g, '-');
var path = mkPath(env, id);
nThen(function (w) {
// check if the file already exists...
Fs.stat(path, w(function (err) {
if (err && err.code === 'ENOENT') { return; }
w.abort(); cb();
}));
}).nThen(function (w) {
// create the parent directory if it does not exist
var dir = id.slice(0, 2);
var dirpath = Path.join(env.root, dir);
Fs.mkdir(dirpath, 0x1ff, w(function (err) {
if (err && err.code !== 'EEXIST') {
return void cb(err);
}
}));
}).nThen(function () {
// write the file to the path
Fs.writeFile(mkPath(env, id), str, function (e) {
if (e) { return void cb(e); }
cb();
});
});
};
Tasks.create = function (config, cb) {
var env = {
root: config.taskPath || './tasks',
};
// make sure the path exists...
Fs.mkdir(env.root, 0x1ff, function (err) {
if (err && err.code !== 'EEXIST') {
throw err;
}
cb(void 0, {
write: function (time, command, args, cb) {
var task = encode(time, command, args);
write(env, task, cb);
},
});
});
};

@ -42,6 +42,11 @@ define(function() {
'#800080', // purple
];
// Background color in the apps with centered content:
// - file app in view mode
// - rich text app when editor's width reduced in settings
config.appBackgroundColor = '#666';
// Set enableTemplates to false to remove the button allowing users to save a pad as a template
// and remove the template category in CryptDrive
config.enableTemplates = true;

@ -6,7 +6,7 @@ define([
], function (Util, Messages, Crypto) {
var Nacl = window.nacl;
var Hash = {};
var Hash = window.CryptPad_Hash = {};
var uint8ArrayToHex = Util.uint8ArrayToHex;
var hexToBase64 = Util.hexToBase64;
@ -176,7 +176,7 @@ Version 1
secret.keys = Crypto.createEditCryptor();
secret.key = Crypto.createEditCryptor().editKeyStr;
};
if (!secretHash && !/#/.test(window.location.href)) {
if (!secretHash && !window.location.hash) { //!/#/.test(window.location.href)) {
generate();
return secret;
} else {
@ -300,6 +300,8 @@ Version 1
var rHref = href || getRelativeHref(window.location.href);
var parsed = parsePadUrl(rHref);
if (!parsed.hash) { return false; }
// We can't have a stronger hash if we're already in edit mode
if (parsed.hashData && parsed.hashData.mode === 'edit') { return; }
var stronger;
Object.keys(recents).some(function (id) {
var pad = recents[id];

@ -317,11 +317,11 @@ define([
message = dialog.message(msg);
}
var close = Util.once(function (el) {
var close = function (el) {
var $el = $(el).fadeOut(150, function () {
$el.remove();
$el.detach();
});
});
};
var navs = [];
opt.buttons.forEach(function (b) {
@ -329,7 +329,7 @@ define([
var button = h('button', { tabindex: '1', 'class': b.className || '' }, b.name);
$(button).click(function () {
b.onClick();
close($(this).parents('.alertify').first());
close($(button).parents('.alertify').first());
});
if (b.keys && b.keys.length) { $(button).attr('data-keys', JSON.stringify(b.keys)); }
navs.push(button);

@ -1816,6 +1816,13 @@ define([
$button.click(function () {
create();
});
// Settings button
var origin = common.getMetadataMgr().getPrivateData().origin;
$(h('div.cp-creation-settings', h('a', {
href: origin + '/settings/#creation',
target: '_blank'
}, Messages.creation_settings))).appendTo($creation);
};
return UIElements;

@ -1,6 +1,6 @@
(function (window) {
define([], function () {
var Util = {};
var Util = window.CryptPad_Util = {};
// If once is true, after the event has been fired, any further handlers which are
// registered will fire immediately, and this type of event cannot be fired twice.

@ -195,6 +195,16 @@ define([
common.clearOwnedChannel = function (channel, cb) {
postMessage("CLEAR_OWNED_CHANNEL", channel, cb);
};
common.removeOwnedChannel = function (channel, cb) {
postMessage("REMOVE_OWNED_CHANNEL", channel, cb);
};
common.getDeletedPads = function (cb) {
postMessage("GET_DELETED_PADS", null, function (obj) {
if (obj && obj.error) { return void cb(obj.error); }
cb(null, obj);
});
};
common.uploadComplete = function (cb) {
postMessage("UPLOAD_COMPLETE", null, function (obj) {
@ -550,6 +560,11 @@ define([
return void cb(null, hashes);
}
if (hashes.editHash) {
// no need to find stronger if we already have edit hash
return void cb(null, hashes);
}
postMessage("GET_STRONGER_HASH", {
href: window.location.href
}, function (hash) {

@ -94,9 +94,27 @@ define([
return list;
};
var getCanonicalChannelList = function () {
return Util.deduplicateString(getUserChannelList()).sort();
var getExpirableChannelList = 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 && data.owners.indexOf(edPublic) === -1) ||
(data.expire && data.expire < (+new Date()))) {
list.push(Hash.hrefToHexChannelId(data.href));
}
});
return list;
};
var getCanonicalChannelList = function (expirable) {
var list = expirable ? getExpirableChannelList() : getUserChannelList();
return Util.deduplicateString(list).sort();
};
//////////////////////////////////////////////////////////////////
/////////////////////// RPC //////////////////////////////////////
//////////////////////////////////////////////////////////////////
@ -172,6 +190,34 @@ define([
});
};
Store.removeOwnedChannel = function (data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.removeOwnedChannel(data, function (err) {
cb({error:err});
});
};
var arePinsSynced = function (cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var list = getCanonicalChannelList(false);
var local = Hash.hashChannelList(list);
store.rpc.getServerHash(function (e, hash) {
if (e) { return void cb(e); }
cb(null, hash === local);
});
};
var resetPins = function (cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var list = getCanonicalChannelList(false);
store.rpc.reset(list, function (e, hash) {
if (e) { return void cb(e); }
cb(null, hash);
});
};
Store.uploadComplete = function (data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
store.rpc.uploadComplete(function (err, res) {
@ -196,27 +242,6 @@ define([
});
};
var arePinsSynced = function (cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var list = getCanonicalChannelList();
var local = Hash.hashChannelList(list);
store.rpc.getServerHash(function (e, hash) {
if (e) { return void cb(e); }
cb(null, hash === local);
});
};
var resetPins = function (cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
var list = getCanonicalChannelList();
store.rpc.reset(list, function (e, hash) {
if (e) { return void cb(e); }
cb(null, hash);
});
};
Store.uploadChunk = function (data, cb) {
store.rpc.send.unauthenticated('UPLOAD', data.chunk, function (e, msg) {
cb({
@ -309,6 +334,23 @@ define([
});
};
Store.getDeletedPads = function (data, cb) {
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
var list = getCanonicalChannelList(true);
if (!Array.isArray(list)) {
return void cb({error: 'INVALID_FILE_LIST'});
}
store.anon_rpc.send('GET_DELETED_PADS', list, function (e, res) {
if (e) { return void cb({error: e}); }
if (res && res.length && Array.isArray(res[0])) {
cb(res[0]);
} else {
cb({error: 'UNEXPECTED_RESPONSE'});
}
});
};
Store.initAnonRpc = function (data, cb) {
require([
'/common/rpc.js',
@ -321,8 +363,6 @@ define([
});
};
//////////////////////////////////////////////////////////////////
/////////////////////// Store ////////////////////////////////////
//////////////////////////////////////////////////////////////////
@ -579,6 +619,8 @@ define([
contains = true;
pad.atime = +new Date();
pad.title = title;
pad.owners = owners;
pad.expire = expire;
// If the href is different, it means we have a stronger one
if (href !== pad.href) { isStronger = true; }
@ -871,6 +913,8 @@ define([
var userObject = store.userObject = UserObject.init(proxy.drive, {
pinPads: Store.pinPads,
unpinPads: Store.unpinPads,
removeOwnedChannel: Store.removeOwnedChannel,
edPublic: store.proxy.edPublic,
loggedIn: store.loggedIn,
log: function (msg) {
postMessage("DRIVE_LOG", msg);

@ -57,27 +57,11 @@ define([], function () {
// shim between chainpad and netflux
var msgIn = function (peerId, msg) {
return msg.replace(/^cp\|/, '');
/*try {
var decryptedMsg = Crypto.decrypt(msg, validateKey);
return decryptedMsg;
} catch (err) {
console.error(err);
return msg;
}*/
};
var msgOut = function (msg) {
if (readOnly) { return; }
return msg;
/*try {
var cmsg = Crypto.encrypt(msg);
if (msg.indexOf('[4') === 0) { cmsg = 'cp|' + cmsg; }
return cmsg;
} catch (err) {
console.log(msg);
throw err;
}*/
};
var onMsg = function(peer, msg, wc, network, direct) {
@ -93,7 +77,9 @@ define([], function () {
if (parsed.channel === wc.id && !validateKey) {
validateKey = parsed.validateKey;
}
padData = parsed;
if (parsed.channel === wc.id) {
padData = parsed;
}
// We have to return even if it is not the current channel:
// we don't want to continue with other channels messages here
return;

@ -31,6 +31,9 @@ define([
case 'CLEAR_OWNED_CHANNEL': {
Store.clearOwnedChannel(data, cb); break;
}
case 'REMOVE_OWNED_CHANNEL': {
Store.removeOwnedChannel(data, cb); break;
}
case 'UPLOAD_CHUNK': {
Store.uploadChunk(data, cb); break;
}
@ -49,6 +52,9 @@ define([
case 'UNPIN_PADS': {
Store.unpinPads(data, cb); break;
}
case 'GET_DELETED_PADS': {
Store.getDeletedPads(data, cb); break;
}
case 'GET_PINNED_USAGE': {
Store.getPinnedUsage(data, cb); break;
}

@ -17,8 +17,12 @@ define([
console.error("unpinPads was not provided");
};
var pinPads = config.pinPads;
var removeOwnedChannel = config.removeOwnedChannel || function () {
console.error("removeOwnedChannel was not provided");
};
var loggedIn = config.loggedIn;
var workgroup = config.workgroup;
var edPublic = config.edPublic;
var ROOT = exp.ROOT;
var FILES_DATA = exp.FILES_DATA;
@ -90,9 +94,14 @@ define([
exp.getFiles([FILES_DATA]).forEach(function (id) {
if (filesList.indexOf(id) === -1) {
var fd = exp.getFileData(id);
if (fd && fd.href) {
toClean.push(Hash.hrefToHexChannelId(fd.href));
var channelId = fd && fd.href && Hash.hrefToHexChannelId(fd.href);
// If trying to remove an owned pad, remove it from server also
if (fd.owners && fd.owners.indexOf(edPublic) !== -1 && channelId) {
removeOwnedChannel(channelId, function (obj) {
if (obj && obj.error) { console.error(obj.error); }
});
}
if (channelId) { toClean.push(channelId); }
spliceFileData(id);
}
});

@ -145,7 +145,22 @@ define([
if (response && response.length) {
cb(void 0, response[0]);
} else {
cb();
cb('INVALID_RESPONSE');
}
});
};
exp.removeOwnedChannel = function (channel, cb) {
if (typeof(channel) !== 'string' || channel.length !== 32) {
// can't use this on files because files can't be owned...
return void cb('INVALID_ARGUMENTS');
}
rpc.send('REMOVE_OWNED_CHANNEL', channel, function (e, response) {
if (e) { return void cb(e); }
if (response && response.length) {
cb(void 0, response[0]); // I haven't tested this...
} else {
cb('INVALID_RESPONSE');
}
});
};

@ -501,6 +501,9 @@ define([
sframeChan.on('Q_CONTACTS_CLEAR_OWNED_CHANNEL', function (channel, cb) {
Cryptpad.clearOwnedChannel(channel, cb);
});
sframeChan.on('Q_REMOVE_OWNED_CHANNEL', function (channel, cb) {
Cryptpad.removeOwnedChannel(channel, cb);
});
if (cfg.addRpc) {
cfg.addRpc(sframeChan, Cryptpad, Utils);

@ -392,15 +392,12 @@ define([
UI.log(data.logText);
});
ctx.metadataMgr.onChange(function () {
try {
var feedback = ctx.metadataMgr.getPrivateData().feedbackAllowed;
Feedback.init(feedback);
} catch (e) { Feedback.init(false); }
});
ctx.metadataMgr.onReady(waitFor());
}).nThen(function () {
try {
var feedback = ctx.metadataMgr.getPrivateData().feedbackAllowed;
Feedback.init(feedback);
} catch (e) { Feedback.init(false); }
ctx.sframeChan.ready();
cb(funcs);
});

@ -201,12 +201,17 @@ define({
// Inner drive needs to send command and receive updates from the async store
'Q_DRIVE_USEROBJECT': true,
'Q_DRIVE_GETOBJECT': true,
// Get the pads deleted from the server by other users to remove them from the drive
'Q_DRIVE_GETDELETED': true,
// Store's userObject need to send log messages to inner to display them in the UI
'EV_DRIVE_LOG': true,
// Refresh the drive when the drive has changed ('change' or 'remove' events)
'EV_DRIVE_CHANGE': true,
'EV_DRIVE_REMOVE': true,
// Remove an owned pad from the server
'Q_REMOVE_OWNED_CHANNEL': true,
// Notifications about connection and disconnection from the network
'EV_NETWORK_DISCONNECT': true,
'EV_NETWORK_RECONNECT': true,

@ -380,6 +380,18 @@ define([
var trashpaths = _findFileInTrash([TRASH], file);
return rootpaths.concat(templatepaths, trashpaths);
};
// Get drive ids of files from their channel ids
exp.findChannels = function (channels) {
var allFilesList = files[FILES_DATA];
var channels64 = channels.slice().map(Util.hexToBase64);
return getFiles([FILES_DATA]).filter(function (k) {
var data = allFilesList[k];
var parsed = Hash.parsePadUrl(data.href);
return parsed.hashData && channels64.indexOf(parsed.hashData.channel) !== -1;
});
};
exp.search = function (value) {
if (typeof(value) !== "string") { return []; }
value = value.trim();

@ -802,6 +802,7 @@ define([
hide.push('properties');
hide.push('rename');
hide.push('openparent');
hide.push('hashtag');
}
if (containsFolder && paths.length > 1) {
// Cannot open multiple folders
@ -911,6 +912,7 @@ define([
//var actions = [];
var toShow = filterContextMenu(menuType, paths);
var $actions = $contextMenu.find('a');
$contextMenu.data('paths', paths);
$actions = $actions.filter(function (i, el) {
return toShow.some(function (className) { return $(el).is(className); });
});
@ -922,9 +924,6 @@ define([
} else {
$a.text($(el).text());
}
$(el).data('paths', paths);
//$(el).data('path', path);
//:$(el).data('element', $element);
$container.append($a);
$a.click(function() { $(el).click(); });
});
@ -1435,6 +1434,7 @@ define([
case FILES_DATA: pName = FILES_DATA_NAME; break;
case SEARCH: pName = SEARCH_NAME; break;
case RECENT: pName = RECENT_NAME; break;
case OWNED: pName = OWNED_NAME; break;
default: pName = name;
}
return pName;
@ -1509,6 +1509,11 @@ define([
if (!APP.loggedIn) {
msg = Messages.fm_info_anonymous;
$box.html(msg);
$box.find('a[target!="_blank"]').click(function (e) {
e.preventDefault();
var href = $(this).attr('href');
common.gotoURL(href);
});
return $box;
}
if (!msg || APP.store['hide-info-' + path[0]] === '1') {
@ -2682,11 +2687,13 @@ define([
$contextMenu.find('.cp-app-drive-context-delete').text(Messages.fc_remove)
.attr('data-icon', 'fa-eraser');
}
var deletePaths = function (paths) {
var pathsList = [];
paths.forEach(function (p) { pathsList.push(p.path); });
var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [paths.length]);
if (paths.length === 1) {
var deletePaths = function (paths, pathsList) {
pathsList = pathsList || [];
if (paths) {
paths.forEach(function (p) { pathsList.push(p.path); });
}
var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [pathsList.length]);
if (pathsList.length === 1) {
msg = Messages.fm_removePermanentlyDialog;
}
UI.confirm(msg, function(res) {
@ -2695,6 +2702,33 @@ define([
filesOp.delete(pathsList, refresh);
});
};
var deleteOwnedPaths = function (paths, pathsList) {
pathsList = pathsList || [];
if (paths) {
paths.forEach(function (p) { pathsList.push(p.path); });
}
var msgD = pathsList.length === 1 ? Messages.fm_deleteOwnedPad :
Messages.fm_deleteOwnedPads;
UI.confirm(msgD, function(res) {
$(window).focus();
if (!res) { return; }
// Try to delete each selected pad from server, and delete from drive if no error
var n = nThen(function () {});
pathsList.forEach(function (p) {
var el = filesOp.find(p);
var data = filesOp.getFileData(el);
var parsed = Hash.parsePadUrl(data.href);
var channel = Util.base64ToHex(parsed.hashData.channel);
n = n.nThen(function (waitFor) {
sframeChan.query('Q_REMOVE_OWNED_CHANNEL', channel,
waitFor(function (e) {
if (e) { return void console.error(e); }
filesOp.delete([p], refresh);
}));
});
});
});
};
$contextMenu.on("click", "a", function(e) {
e.stopPropagation();
var paths = $contextMenu.data('paths');
@ -2720,27 +2754,7 @@ define([
moveElements(pathsList, [TRASH], false, refresh);
}
else if ($(this).hasClass('cp-app-drive-context-deleteowned')) {
var msgD = Messages.fm_deleteOwnedPads;
UI.confirm(msgD, function(res) {
$(window).focus();
if (!res) { return; }
// Try to delete each selected pad from server, and delete from drive if no error
var n = nThen(function () {});
paths.forEach(function (p) {
var el = filesOp.find(p.path);
var data = filesOp.getFileData(el);
var parsed = Hash.parsePadUrl(data.href);
var channel = Util.base64ToHex(parsed.hashData.channel);
n = n.nThen(function (waitFor) {
sframeChan.query('Q_CONTACTS_CLEAR_OWNED_CHANNEL', channel,
waitFor(function (e) {
if (e) { return void console.error(e); }
filesOp.delete([p.path], refresh);
}));
});
});
});
return;
deleteOwnedPaths(paths);
}
else if ($(this).hasClass('cp-app-drive-context-open')) {
paths.forEach(function (p) {
@ -2878,18 +2892,11 @@ define([
if (!$(elmt).data('path')) { return; }
paths.push($(elmt).data('path'));
});
// If we are in the trash or anon pad or if we are holding the "shift" key, delete permanently,
if (!paths.length) { return; }
// If we are in the trash or anon pad or if we are holding the "shift" key,
// delete permanently
if (!APP.loggedIn || isTrash || e.shiftKey) {
var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [paths.length]);
if (paths.length === 1) {
msg = Messages.fm_removePermanentlyDialog;
}
UI.confirm(msg, function(res) {
$(window).focus();
if (!res) { return; }
filesOp.delete(paths, refresh);
});
deletePaths(null, paths);
return;
}
// else move to trash
@ -2975,6 +2982,19 @@ define([
refresh();
UI.removeLoadingScreen();
sframeChan.query('Q_DRIVE_GETDELETED', null, function (err, data) {
var ids = filesOp.findChannels(data);
var titles = [];
ids.forEach(function (id) {
var title = filesOp.getTitle(id);
titles.push(title);
var paths = filesOp.findFile(id);
filesOp.delete(paths, refresh);
});
if (!titles.length) { return; }
UI.log(Messages._getKey('fm_deletedPads', [titles.join(', ')]));
});
};
var setHistory = function (bool, update) {
@ -3091,7 +3111,6 @@ define([
throw new Error("Corrupted drive");
}
andThen(common, proxy);
UI.removeLoadingScreen();
var onDisconnect = APP.onDisconnect = function (noAlert) {
setEditable(false);

@ -56,6 +56,12 @@ define([
cb(obj);
});
});
sframeChan.on('Q_DRIVE_GETDELETED', function (data, cb) {
Cryptpad.getDeletedPads(function (err, obj) {
if (err) { return void console.error(err); }
cb(obj);
});
});
Cryptpad.onNetworkDisconnect.reg(function () {
sframeChan.event('EV_NETWORK_DISCONNECT');
});

@ -224,6 +224,8 @@ define([
if (decrypting) { return; }
decrypting = true;
displayFile(ev, sizeMb, function (err) {
$appContainer.css('background-color',
common.getAppConfig().appBackgroundColor);
if (err) { UI.alert(err); }
});
};

@ -31,6 +31,7 @@ define([
'/common/common-hash.js',
'/common/common-util.js',
'/bower_components/chainpad/chainpad.dist.js',
'/customize/application_config.js',
'/bower_components/diff-dom/diffDOM.js',
@ -50,7 +51,8 @@ define([
ApiConfig,
Hash,
Util,
ChainPad)
ChainPad,
AppConfig)
{
var DiffDom = window.diffDOM;
@ -592,7 +594,8 @@ define([
}
// Used in ckeditor-config.js
Ckeditor.CRYPTPAD_URLARGS = ApiConfig.requireConf.urlArgs;
var newCss = '.cke_body_width { background: #666; height: 100%; }' +
var backColor = AppConfig.appBackgroundColor;
var newCss = '.cke_body_width { background: '+ backColor +'; height: 100%; }' +
'.cke_body_width body {' +
'max-width: 50em; padding: 10px 30px; margin: 0 auto; min-height: 100%;'+
'box-sizing: border-box;'+

@ -75,7 +75,7 @@ define([
}
};
if (!AppConfig.dislayCreationScreen) {
if (!AppConfig.displayCreationScreen) {
delete categories.creation;
}
if (AppConfig.disableFeedback) {
@ -789,7 +789,7 @@ define([
var $categories = $('<div>', {'class': 'cp-sidebarlayout-categories'})
.appendTo(APP.$leftside);
APP.$usage = $('<div>', {'class': 'usage'}).appendTo(APP.$leftside);
var active = 'account';
var active = privateData.category || 'account';
Object.keys(categories).forEach(function (key) {
var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories);
if (key === 'account') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }

@ -66,9 +66,18 @@ define([
Cryptpad.mergeAnonDrive(cb);
});
};
var category;
if (window.location.hash) {
category = window.location.hash.slice(1);
window.location.hash = '';
}
var addData = function (obj) {
if (category) { obj.category = category; }
};
SFCommonO.start({
noRealtime: true,
addRpc: addRpc
addRpc: addRpc,
addData: addData
});
});
});

@ -70,6 +70,10 @@ define([
var makeCheckbox = function (id, cb) {
var entry = APP.lm.proxy.data[id];
if (!entry || typeof(entry) !== 'object') {
return void console.log('entry undefined');
}
var checked = entry.state === 1 ?
'cp-app-todo-task-checkbox-checked fa-check-square-o':
'cp-app-todo-task-checkbox-unchecked fa-square-o';
@ -108,6 +112,9 @@ define([
.appendTo($taskDiv);
var entry = APP.lm.proxy.data[el];
if (!entry || typeof(entry) !== 'object') {
return void console.log('entry undefined');
}
if (entry.state) {
$taskDiv.addClass('cp-app-todo-task-complete');

@ -32,6 +32,7 @@ define([
sFrameChan.onReady(waitFor());
}).nThen(function (/*waitFor*/) {
var $container = $('#cp-app-worker-container');
$('<a>', {href:'http://localhost:3000/worker/', target:'_blank'}).text('other').appendTo($container);
var $bar = $('.cp-toolbar-container');
var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle'];

@ -29,16 +29,17 @@ require.config({
});
var i = 0;
var id = Math.floor(Math.random()*100000);
onconnect = function(e) {
console.log(e);
console.log(i);
var port = e.ports[0];
console.log('here');
require([
'/common/outer/async-store.js'
], function (Store) {
console.log(Store);
//require([
// '/common/outer/async-store.js'
//], function (Store) {
//console.log(Store);
console.log(self.Proxy);
var n = i;
port.postMessage({state: 'READY'});
@ -46,8 +47,9 @@ onconnect = function(e) {
console.log('worker received');
console.log(e.data);
port.postMessage('hello CryptPad'+n);
port.postMessage('This is '+id);
};
var data = {
/*var data = {
query: function (cmd, data, cb) {
console.log(cmd, data);
},
@ -64,7 +66,7 @@ onconnect = function(e) {
});
port.postMessage('Store is connected!');
port.postMessage('Your username is ' + ret.store.proxy['cryptpad.username']);
});
});*/
i++;
});
//});
};

Loading…
Cancel
Save