Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging
This commit is contained in:
commit
ba74f9d37a
54 changed files with 2418 additions and 1586 deletions
|
@ -7,7 +7,6 @@
|
||||||
"iterator": true,
|
"iterator": true,
|
||||||
"latedef": true,
|
"latedef": true,
|
||||||
"nocomma": true,
|
"nocomma": true,
|
||||||
"notypeof": true,
|
|
||||||
"shadow": false,
|
"shadow": false,
|
||||||
"undef": true,
|
"undef": true,
|
||||||
"unused": true,
|
"unused": true,
|
||||||
|
|
|
@ -44,7 +44,8 @@
|
||||||
"open-sans-fontface": "^1.4.2",
|
"open-sans-fontface": "^1.4.2",
|
||||||
"bootstrap-tokenfield": "^0.12.1",
|
"bootstrap-tokenfield": "^0.12.1",
|
||||||
"localforage": "^1.5.2",
|
"localforage": "^1.5.2",
|
||||||
"html2canvas": "^0.4.1"
|
"html2canvas": "^0.4.1",
|
||||||
|
"croppie": "^2.5.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"bootstrap": "v4.0.0-alpha.6"
|
"bootstrap": "v4.0.0-alpha.6"
|
||||||
|
|
|
@ -159,6 +159,24 @@ module.exports = {
|
||||||
*/
|
*/
|
||||||
defaultStorageLimit: 50 * 1024 * 1024,
|
defaultStorageLimit: 50 * 1024 * 1024,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CryptPad allows administrators to give custom limits to their friends.
|
||||||
|
* add an entry for each friend, identified by their user id,
|
||||||
|
* which can be found on the settings page. Include a 'limit' (number of bytes),
|
||||||
|
* a 'plan' (string), and a 'note' (string).
|
||||||
|
*
|
||||||
|
* hint: 1GB is 1024 * 1024 * 1024 bytes
|
||||||
|
*/
|
||||||
|
customLimits: {
|
||||||
|
/*
|
||||||
|
"https://my.awesome.website/user/#/1/cryptpad-user/YZgXQxKR0Rcb6r6CmxHPdAGLVludrAF2lEnkbx1vVOo=": {
|
||||||
|
limit: 20 * 1024 * 1024 * 1024,
|
||||||
|
plan: 'insider',
|
||||||
|
note: 'storage space donated by my.awesome.website'
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By default, CryptPad also contacts our accounts server once a day to check for changes in
|
* 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
|
* the people who have accounts. This check-in will also send the version of your CryptPad
|
||||||
|
|
16
customize.dist/404.html
Normal file
16
customize.dist/404.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="cp" id="four-oh-four">
|
||||||
|
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
|
||||||
|
<head>
|
||||||
|
<title data-localization="main_title">CryptPad: Zero Knowledge, Collaborative Real Time Editing</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
|
||||||
|
<script async data-bootload="/customize/four-oh-four.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
</head>
|
||||||
|
<body class="html">
|
||||||
|
<noscript>
|
||||||
|
<h1>404</h1>
|
||||||
|
<h3>We couldn't find the page you were looking for</h3>
|
||||||
|
|
||||||
|
</noscript>
|
78
customize.dist/four-oh-four.js
Normal file
78
customize.dist/four-oh-four.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
define([
|
||||||
|
'/api/config',
|
||||||
|
'/common/hyperscript.js',
|
||||||
|
'/common/outer/local-store.js',
|
||||||
|
'/customize/messages.js',
|
||||||
|
|
||||||
|
'less!/customize/src/less2/pages/page-404.less',
|
||||||
|
], function (Config, h, LocalStore, Messages) {
|
||||||
|
var urlArgs = Config.requireConf.urlArgs;
|
||||||
|
var img = h('img#cp-logo', {
|
||||||
|
src: '/customize/cryptpad-new-logo-colors-logoonly.png?' + urlArgs
|
||||||
|
});
|
||||||
|
|
||||||
|
var brand = h('h1#cp-brand', 'CryptPad');
|
||||||
|
var message = h('h2#cp-scramble', Messages.four04_pageNotFound);
|
||||||
|
var title = h('h2#cp-title', "404");
|
||||||
|
|
||||||
|
var loggedIn = LocalStore.isLoggedIn();
|
||||||
|
var link = h('a#cp-link', {
|
||||||
|
href: loggedIn? '/drive/': '/',
|
||||||
|
}, loggedIn? Messages.header_logoTitle: Messages.header_homeTitle);
|
||||||
|
|
||||||
|
var content = h('div#cp-main', [
|
||||||
|
img,
|
||||||
|
brand,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
link,
|
||||||
|
]);
|
||||||
|
document.body.appendChild(content);
|
||||||
|
|
||||||
|
var die = function (n) { return Math.floor(Math.random() * n); };
|
||||||
|
var randomChar = function () {
|
||||||
|
return String.fromCharCode(die(94) + 34);
|
||||||
|
};
|
||||||
|
var mutate = function (S, i, c) {
|
||||||
|
var A = S.split("");
|
||||||
|
A[i] = c;
|
||||||
|
return A.join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
var take = function (A) {
|
||||||
|
var n = die(A.length);
|
||||||
|
var choice = A[n];
|
||||||
|
A.splice(n, 1);
|
||||||
|
return choice;
|
||||||
|
};
|
||||||
|
|
||||||
|
var makeDecryptor = function (el, t, difficulty, cb) {
|
||||||
|
var Orig = el.innerText;
|
||||||
|
var options = [];
|
||||||
|
el.innerText = el.innerText.split("").map(function (c, i) {
|
||||||
|
Orig[i] = c;
|
||||||
|
options.push(i);
|
||||||
|
return randomChar();
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
return function f () {
|
||||||
|
if (die(difficulty) === 0) {
|
||||||
|
var choice = take(options);
|
||||||
|
el.innerText = mutate(el.innerText, choice, Orig.charAt(choice));
|
||||||
|
} else { // make a superficial change
|
||||||
|
el.innerText = mutate(el.innerText,
|
||||||
|
options[die(options.length)],
|
||||||
|
randomChar());
|
||||||
|
}
|
||||||
|
setTimeout(options.length > 0? f: cb, t);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
makeDecryptor(brand, 70, 2, function () { })();
|
||||||
|
makeDecryptor(title, 50, 14, function () { })();
|
||||||
|
makeDecryptor(link, 20, 4, function () {})();
|
||||||
|
makeDecryptor(message, 12, 3, function () {
|
||||||
|
console.log('done');
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ var map = {
|
||||||
|
|
||||||
var messages = {};
|
var messages = {};
|
||||||
var LS_LANG = "CRYPTPAD_LANG";
|
var LS_LANG = "CRYPTPAD_LANG";
|
||||||
var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); };
|
var getStoredLanguage = function () { return localStorage && localStorage.getItem(LS_LANG); };
|
||||||
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage || ''; };
|
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage || ''; };
|
||||||
var getLanguage = messages._getLanguage = function () {
|
var getLanguage = messages._getLanguage = function () {
|
||||||
if (window.cryptpadLanguage) { return window.cryptpadLanguage; }
|
if (window.cryptpadLanguage) { return window.cryptpadLanguage; }
|
||||||
|
@ -24,19 +24,17 @@ var getLanguage = messages._getLanguage = function () {
|
||||||
};
|
};
|
||||||
var language = getLanguage();
|
var language = getLanguage();
|
||||||
|
|
||||||
var req = ['jquery', '/customize/translations/messages.js'];
|
var req = ['/common/common-util.js', '/customize/translations/messages.js'];
|
||||||
if (language && map[language]) { req.push('/customize/translations/messages.' + language + '.js'); }
|
if (language && map[language]) { req.push('/customize/translations/messages.' + language + '.js'); }
|
||||||
|
|
||||||
define(req, function($, Default, Language) {
|
define(req, function(Util, Default, Language) {
|
||||||
map.en = 'English';
|
map.en = 'English';
|
||||||
var defaultLanguage = 'en';
|
var defaultLanguage = 'en';
|
||||||
|
|
||||||
if (!Language || language === defaultLanguage || !map[language]) {
|
Util.extend(messages, Default);
|
||||||
messages = $.extend(true, messages, Default);
|
if (Language && language !== defaultLanguage) {
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Add the translated keys to the returned object
|
// Add the translated keys to the returned object
|
||||||
messages = $.extend(true, messages, Default, Language);
|
Util.extend(messages, Language);
|
||||||
}
|
}
|
||||||
|
|
||||||
messages._languages = map;
|
messages._languages = map;
|
||||||
|
|
40
customize.dist/src/less2/404.less
Normal file
40
customize.dist/src/less2/404.less
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
@import (once) './include/font.less';
|
||||||
|
.font_neuropolitical();
|
||||||
|
.font_open-sans();
|
||||||
|
|
||||||
|
body.cp-page-index { @import "./pages/page-index.less"; }
|
||||||
|
body.cp-page-contact { @import "./pages/page-contact.less"; }
|
||||||
|
body.cp-page-login { @import "./pages/page-login.less"; }
|
||||||
|
body.cp-page-register { @import "./pages/page-register.less"; }
|
||||||
|
body.cp-page-what-is-cryptpad { @import "./pages/page-what-is-cryptpad.less"; }
|
||||||
|
body.cp-page-about { @import "./pages/page-about.less"; }
|
||||||
|
body.cp-page-privacy { @import "./pages/page-privacy.less"; }
|
||||||
|
body.cp-page-terms { @import "./pages/page-terms.less"; }
|
||||||
|
|
||||||
|
// Set the HTML style for the apps which shouldn't have a body scrollbar
|
||||||
|
html.cp-app-noscroll {
|
||||||
|
@import "./include/app-noscroll.less";
|
||||||
|
.app-noscroll_main();
|
||||||
|
}
|
||||||
|
// Set the HTML style for printing slides
|
||||||
|
html.cp-app-print {
|
||||||
|
@import "./include/app-print.less";
|
||||||
|
.app-print_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
body.cp-readonly .cp-hidden-if-readonly { display:none !important; }
|
||||||
|
|
||||||
|
body.cp-app-drive { @import "../../../drive/app-drive.less"; }
|
||||||
|
body.cp-app-pad { @import "../../../pad/app-pad.less"; }
|
||||||
|
body.cp-app-code { @import "../../../code/app-code.less"; }
|
||||||
|
body.cp-app-slide { @import "../../../slide/app-slide.less"; }
|
||||||
|
body.cp-app-file { @import "../../../file/app-file.less"; }
|
||||||
|
body.cp-app-filepicker { @import "../../../filepicker/app-filepicker.less"; }
|
||||||
|
body.cp-app-contacts { @import "../../../contacts/app-contacts.less"; }
|
||||||
|
body.cp-app-poll { @import "../../../poll/app-poll.less"; }
|
||||||
|
body.cp-app-whiteboard { @import "../../../whiteboard/app-whiteboard.less"; }
|
||||||
|
body.cp-app-todo { @import "../../../todo/app-todo.less"; }
|
||||||
|
body.cp-app-profile { @import "../../../profile/app-profile.less"; }
|
||||||
|
body.cp-app-settings { @import "../../../settings/app-settings.less"; }
|
||||||
|
body.cp-app-debug { @import "../../../debug/app-debug.less"; }
|
||||||
|
|
37
customize.dist/src/less2/pages/page-404.less
Normal file
37
customize.dist/src/less2/pages/page-404.less
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
@import (once) "../include/colortheme.less";
|
||||||
|
@import (once) "../include/font.less";
|
||||||
|
.font_neuropolitical();
|
||||||
|
.font_open-sans();
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
#cp-main {
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0px;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 5%;
|
||||||
|
text-align: center;
|
||||||
|
#cp-logo {
|
||||||
|
display: block;
|
||||||
|
max-width: 15%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
#cp-brand {
|
||||||
|
font-family: neuropolitical;
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
#cp-title {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
#cp-scramble, #cp-link {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
#cp-title, #cp-scramble, #cp-link {
|
||||||
|
//font-family: 'Open Sans';
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -298,6 +298,8 @@ define(function () {
|
||||||
out.profile_namePlaceholder = 'Nom ou pseudo pour le profil';
|
out.profile_namePlaceholder = 'Nom ou pseudo pour le profil';
|
||||||
out.profile_avatar = "Avatar";
|
out.profile_avatar = "Avatar";
|
||||||
out.profile_upload = " Importer un nouvel avatar";
|
out.profile_upload = " Importer un nouvel avatar";
|
||||||
|
out.profile_uploadSizeError = "Erreur : votre avatar doit avoir une taille inférieure à {0}";
|
||||||
|
out.profile_uploadTypeError = "Erreur : le format de votre avatar est invalide. Les formats autorisés sont : {0}";
|
||||||
out.profile_error = "Erreur lors de la création du profil : {0}";
|
out.profile_error = "Erreur lors de la création du profil : {0}";
|
||||||
out.profile_register = "Vous devez vous inscrire pour pouvoir créer un profil !";
|
out.profile_register = "Vous devez vous inscrire pour pouvoir créer un profil !";
|
||||||
out.profile_create = "Créer un profil";
|
out.profile_create = "Créer un profil";
|
||||||
|
@ -681,10 +683,8 @@ define(function () {
|
||||||
out.tos_logs = "Les meta-données fournies par votre navigateur au serveur peuvent être enregistrées dans le but de maintenir le service.";
|
out.tos_logs = "Les meta-données fournies par votre navigateur au serveur peuvent être enregistrées dans le but de maintenir le service.";
|
||||||
out.tos_3rdparties = "Nous ne fournissons aucune donnée individuelle à des tierces parties à moins d'y être contraints par la loi.";
|
out.tos_3rdparties = "Nous ne fournissons aucune donnée individuelle à des tierces parties à moins d'y être contraints par la loi.";
|
||||||
|
|
||||||
// BottomBar.html
|
// 404 page
|
||||||
|
out.four04_pageNotFound = "Nous n'avons pas trouvé la page que vous cherchez.";
|
||||||
out.bottom_france = '<a href="http://www.xwiki.com/fr" target="_blank" rel="noopener noreferrer">Fait avec <img class="bottom-bar-heart" src="/customize/heart.png" alt="amour" /> en <img class="bottom-bar-fr" src="/customize/fr.png" alt="France" /></a>';
|
|
||||||
out.bottom_support = '<a href="http://labs.xwiki.com/" title="XWiki Labs" target="_blank" rel="noopener noreferrer">Un projet <img src="/customize/logo-xwiki2.png" alt="XWiki SAS" class="bottom-bar-xwiki"/> Labs</a> avec le soutien de <a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
|
|
||||||
|
|
||||||
// Header.html
|
// Header.html
|
||||||
|
|
||||||
|
|
|
@ -302,6 +302,8 @@ define(function () {
|
||||||
out.profile_namePlaceholder = 'Name displayed in your profile';
|
out.profile_namePlaceholder = 'Name displayed in your profile';
|
||||||
out.profile_avatar = "Avatar";
|
out.profile_avatar = "Avatar";
|
||||||
out.profile_upload = " Upload a new avatar";
|
out.profile_upload = " Upload a new avatar";
|
||||||
|
out.profile_uploadSizeError = "Error: your avatar must be smaller than {0}";
|
||||||
|
out.profile_uploadTypeError = "Error: your avatar type is not allowed. Allowed types are: {0}";
|
||||||
out.profile_error = "Error while creating your profile: {0}";
|
out.profile_error = "Error while creating your profile: {0}";
|
||||||
out.profile_register = "You have to sign up to create a profile!";
|
out.profile_register = "You have to sign up to create a profile!";
|
||||||
out.profile_create = "Create a profile";
|
out.profile_create = "Create a profile";
|
||||||
|
@ -689,10 +691,13 @@ define(function () {
|
||||||
out.tos_logs = "Metadata provided by your browser to the server may be logged for the purpose of maintaining the service.";
|
out.tos_logs = "Metadata provided by your browser to the server may be logged for the purpose of maintaining the service.";
|
||||||
out.tos_3rdparties = "We do not provide individualized data to third parties unless required to by law.";
|
out.tos_3rdparties = "We do not provide individualized data to third parties unless required to by law.";
|
||||||
|
|
||||||
|
// 404 page
|
||||||
|
out.four04_pageNotFound = "We couldn't find the page you were looking for.";
|
||||||
|
|
||||||
// BottomBar.html
|
// BottomBar.html
|
||||||
|
|
||||||
out.bottom_france = '<a href="http://www.xwiki.com/" target="_blank" rel="noopener noreferrer">Made with <img class="bottom-bar-heart" src="/customize/heart.png" alt="love" /> in <img class="bottom-bar-fr" src="/customize/fr.png" alt="France" /></a>';
|
//out.bottom_france = '<a href="http://www.xwiki.com/" target="_blank" rel="noopener noreferrer">Made with <img class="bottom-bar-heart" src="/customize/heart.png" alt="love" /> in <img class="bottom-bar-fr" src="/customize/fr.png" alt="France" /></a>';
|
||||||
out.bottom_support = '<a href="http://labs.xwiki.com/" title="XWiki Labs" target="_blank" rel="noopener noreferrer">An <img src="/customize/logo-xwiki2.png" alt="XWiki SAS" class="bottom-bar-xwiki"/> Labs Project </a> with the support of <a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
|
//out.bottom_support = '<a href="http://labs.xwiki.com/" title="XWiki Labs" target="_blank" rel="noopener noreferrer">An <img src="/customize/logo-xwiki2.png" alt="XWiki SAS" class="bottom-bar-xwiki"/> Labs Project </a> with the support of <a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
|
||||||
|
|
||||||
// Header.html
|
// Header.html
|
||||||
|
|
||||||
|
|
27
rpc.js
27
rpc.js
|
@ -427,6 +427,28 @@ var updateLimits = function (config, publicKey, cb /*:(?string, ?any[])=>void*/)
|
||||||
"Content-Length": Buffer.byteLength(body)
|
"Content-Length": Buffer.byteLength(body)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// read custom limits from the config
|
||||||
|
var customLimits = (function (custom) {
|
||||||
|
var limits = {};
|
||||||
|
Object.keys(custom).forEach(function (k) {
|
||||||
|
k.replace(/\/([^\/]+)$/, function (all, safeKey) {
|
||||||
|
var id = unescapeKeyCharacters(safeKey || '');
|
||||||
|
limits[id] = custom[k];
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return limits;
|
||||||
|
}(config.customLimits || {}));
|
||||||
|
|
||||||
|
var isLimit = function (o) {
|
||||||
|
var valid = o && typeof(o) === 'object' &&
|
||||||
|
typeof(o.limit) === 'number' &&
|
||||||
|
typeof(o.plan) === 'string' &&
|
||||||
|
typeof(o.note) === 'string';
|
||||||
|
return valid;
|
||||||
|
};
|
||||||
|
|
||||||
var req = Https.request(options, function (response) {
|
var req = Https.request(options, function (response) {
|
||||||
if (!('' + response.statusCode).match(/^2\d\d$/)) {
|
if (!('' + response.statusCode).match(/^2\d\d$/)) {
|
||||||
return void cb('SERVER ERROR ' + response.statusCode);
|
return void cb('SERVER ERROR ' + response.statusCode);
|
||||||
|
@ -441,6 +463,11 @@ var updateLimits = function (config, publicKey, cb /*:(?string, ?any[])=>void*/)
|
||||||
try {
|
try {
|
||||||
var json = JSON.parse(str);
|
var json = JSON.parse(str);
|
||||||
limits = json;
|
limits = json;
|
||||||
|
Object.keys(customLimits).forEach(function (k) {
|
||||||
|
if (!isLimit(customLimits[k])) { return; }
|
||||||
|
limits[k] = customLimits[k];
|
||||||
|
});
|
||||||
|
|
||||||
var l;
|
var l;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
var limit = limits[userId];
|
var limit = limits[userId];
|
||||||
|
|
16
server.js
16
server.js
|
@ -157,6 +157,22 @@ app.get('/api/config', function(req, res){
|
||||||
].join(';\n'));
|
].join(';\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var four04_path = Path.resolve(__dirname + '/customize.dist/404.html');
|
||||||
|
var custom_four04_path = Path.resolve(__dirname + '/customize/404.html');
|
||||||
|
|
||||||
|
var send404 = function (res, path) {
|
||||||
|
if (!path && path !== four04_path) { path = four04_path; }
|
||||||
|
Fs.exists(path, function (exists) {
|
||||||
|
if (exists) { return Fs.createReadStream(path).pipe(res); }
|
||||||
|
send404(res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
res.status(404);
|
||||||
|
send404(res, custom_four04_path);
|
||||||
|
});
|
||||||
|
|
||||||
var httpServer = httpsOpts ? Https.createServer(httpsOpts, app) : Http.createServer(app);
|
var httpServer = httpsOpts ? Https.createServer(httpsOpts, app) : Http.createServer(app);
|
||||||
|
|
||||||
httpServer.listen(config.httpPort,config.httpAddress,function(){
|
httpServer.listen(config.httpPort,config.httpAddress,function(){
|
||||||
|
|
|
@ -5,9 +5,11 @@ define([
|
||||||
'/drive/tests.js',
|
'/drive/tests.js',
|
||||||
'/common/test.js',
|
'/common/test.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
|
'/common/common-util.js',
|
||||||
'/common/common-thumbnail.js',
|
'/common/common-thumbnail.js',
|
||||||
|
'/common/wire.js',
|
||||||
'/common/flat-dom.js',
|
'/common/flat-dom.js',
|
||||||
], function ($, Hyperjson, Sortify, Drive, Test, Hash, Thumb, Flat) {
|
], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat) {
|
||||||
window.Hyperjson = Hyperjson;
|
window.Hyperjson = Hyperjson;
|
||||||
window.Sortify = Sortify;
|
window.Sortify = Sortify;
|
||||||
|
|
||||||
|
@ -30,7 +32,7 @@ define([
|
||||||
|
|
||||||
ASSERTS.forEach(function (f, index) {
|
ASSERTS.forEach(function (f, index) {
|
||||||
f(function (err) {
|
f(function (err) {
|
||||||
console.log("test " + index);
|
//console.log("test " + index);
|
||||||
done(err, index);
|
done(err, index);
|
||||||
}, index);
|
}, index);
|
||||||
});
|
});
|
||||||
|
@ -235,6 +237,54 @@ define([
|
||||||
return cb(true);
|
return cb(true);
|
||||||
}, "version 2 hash failed to parse correctly");
|
}, "version 2 hash failed to parse correctly");
|
||||||
|
|
||||||
|
assert(function (cb) {
|
||||||
|
Wire.create({
|
||||||
|
constructor: function (cb) {
|
||||||
|
var service = function (type, data, cb) {
|
||||||
|
switch (type) {
|
||||||
|
case "HEY_BUDDY":
|
||||||
|
return cb(void 0, "SALUT!");
|
||||||
|
default:
|
||||||
|
cb("ERROR");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var evt = Util.mkEvent();
|
||||||
|
var respond = function (e, out) {
|
||||||
|
evt.fire(e, out);
|
||||||
|
};
|
||||||
|
cb(void 0, {
|
||||||
|
send: function (raw /*, cb */) {
|
||||||
|
try {
|
||||||
|
var parsed = JSON.parse(raw);
|
||||||
|
var txid = parsed.txid;
|
||||||
|
var message = parsed.message;
|
||||||
|
setTimeout(function () {
|
||||||
|
service(message.command, message.content, function (e, result) {
|
||||||
|
respond(JSON.stringify({
|
||||||
|
txid: txid,
|
||||||
|
error: e,
|
||||||
|
content: result,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e) { console.error("PEWPEW"); }
|
||||||
|
},
|
||||||
|
receive: function (f) {
|
||||||
|
evt.reg(f);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, function (e, rpc) {
|
||||||
|
if (e) { return cb(false); }
|
||||||
|
rpc.send('HEY_BUDDY', null, function (e, out) {
|
||||||
|
if (e) { return void cb(false); }
|
||||||
|
if (out === 'SALUT!') { cb(true); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "Test rpc factory");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
assert(function (cb) {
|
assert(function (cb) {
|
||||||
var getBlob = function (url, cb) {
|
var getBlob = function (url, cb) {
|
||||||
|
|
|
@ -4,8 +4,9 @@ define([
|
||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
'/common/outer/local-store.js',
|
'/common/outer/local-store.js',
|
||||||
'/common/test.js',
|
'/common/test.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
'/bower_components/tweetnacl/nacl-fast.min.js'
|
'/bower_components/tweetnacl/nacl-fast.min.js'
|
||||||
], function ($, Cryptpad, Constants, LocalStore, Test) {
|
], function ($, Cryptpad, Constants, LocalStore, Test, nThen) {
|
||||||
var Nacl = window.nacl;
|
var Nacl = window.nacl;
|
||||||
|
|
||||||
var signMsg = function (msg, privKey) {
|
var signMsg = function (msg, privKey) {
|
||||||
|
@ -25,11 +26,18 @@ define([
|
||||||
localStorage[Constants.userHashKey] = localStorage[Constants.userHashKey] ||
|
localStorage[Constants.userHashKey] = localStorage[Constants.userHashKey] ||
|
||||||
sessionStorage[Constants.userHashKey];
|
sessionStorage[Constants.userHashKey];
|
||||||
|
|
||||||
Cryptpad.ready(function () {
|
var proxy;
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
Cryptpad.ready(waitFor());
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
Cryptpad.getUserObject(waitFor(function (obj) {
|
||||||
|
proxy = obj;
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
console.log('IFRAME READY');
|
console.log('IFRAME READY');
|
||||||
Test(function () {
|
Test(function () {
|
||||||
// This is only here to maybe trigger an error.
|
// This is only here to maybe trigger an error.
|
||||||
window.drive = Cryptpad.getStore().getProxy().proxy['drive'];
|
window.drive = proxy['drive'];
|
||||||
Test.passed();
|
Test.passed();
|
||||||
});
|
});
|
||||||
$(window).on("message", function (jqe) {
|
$(window).on("message", function (jqe) {
|
||||||
|
@ -46,7 +54,6 @@ define([
|
||||||
} else if (!LocalStore.isLoggedIn()) {
|
} else if (!LocalStore.isLoggedIn()) {
|
||||||
ret.error = "NOT_LOGGED_IN";
|
ret.error = "NOT_LOGGED_IN";
|
||||||
} else {
|
} else {
|
||||||
var proxy = Cryptpad.getStore().getProxy().proxy;
|
|
||||||
var sig = signMsg(data.data, proxy.edPrivate);
|
var sig = signMsg(data.data, proxy.edPrivate);
|
||||||
ret.res = {
|
ret.res = {
|
||||||
uname: proxy.login_name,
|
uname: proxy.login_name,
|
||||||
|
|
|
@ -10,5 +10,6 @@ define(function () {
|
||||||
displayNameKey: 'cryptpad.username',
|
displayNameKey: 'cryptpad.username',
|
||||||
oldStorageKey: 'CryptPad_RECENTPADS',
|
oldStorageKey: 'CryptPad_RECENTPADS',
|
||||||
storageKey: 'filesData',
|
storageKey: 'filesData',
|
||||||
|
tokenKey: 'loginToken',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,6 @@ define([
|
||||||
|
|
||||||
// Add handler to the language selector
|
// Add handler to the language selector
|
||||||
Msg.setLanguage = function (l, sframeChan, cb) {
|
Msg.setLanguage = function (l, sframeChan, cb) {
|
||||||
console.log(sframeChan);
|
|
||||||
if (sframeChan) {
|
if (sframeChan) {
|
||||||
// We're in the sandbox
|
// We're in the sandbox
|
||||||
sframeChan.query("Q_LANGUAGE_SET", l, cb);
|
sframeChan.query("Q_LANGUAGE_SET", l, cb);
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
define([
|
define([
|
||||||
'jquery',
|
|
||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
'/common/curve.js',
|
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
|
|
||||||
'/bower_components/marked/marked.min.js',
|
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
], function ($, Crypto, Curve, Hash, Util, Constants, Messages, Marked, Realtime) {
|
], function (Crypto, Hash, Util, Constants, Messages, Realtime) {
|
||||||
var Msg = {
|
var Msg = {
|
||||||
inputs: [],
|
inputs: [],
|
||||||
};
|
};
|
||||||
|
@ -51,9 +48,8 @@ define([
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Msg.getFriendChannelsList = function (common) {
|
Msg.getFriendChannelsList = function (proxy) {
|
||||||
var list = [];
|
var list = [];
|
||||||
var proxy = common.getProxy();
|
|
||||||
eachFriend(proxy.friends, function (friend) {
|
eachFriend(proxy.friends, function (friend) {
|
||||||
list.push(friend.channel);
|
list.push(friend.channel);
|
||||||
});
|
});
|
||||||
|
@ -61,7 +57,7 @@ define([
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO make this internal to the messenger
|
// TODO make this internal to the messenger
|
||||||
var channels = Msg.channels = window.channels = {};
|
var channels = Msg.channels = {};
|
||||||
|
|
||||||
Msg.getLatestMessages = function () {
|
Msg.getLatestMessages = function () {
|
||||||
Object.keys(channels).forEach(function (id) {
|
Object.keys(channels).forEach(function (id) {
|
||||||
|
@ -74,8 +70,8 @@ define([
|
||||||
|
|
||||||
// Invitation
|
// Invitation
|
||||||
// FIXME there are too many functions with this name
|
// FIXME there are too many functions with this name
|
||||||
var addToFriendList = Msg.addToFriendList = function (common, data, cb) {
|
var addToFriendList = Msg.addToFriendList = function (cfg, data, cb) {
|
||||||
var proxy = common.getProxy();
|
var proxy = cfg.proxy;
|
||||||
var friends = getFriendList(proxy);
|
var friends = getFriendList(proxy);
|
||||||
var pubKey = data.curvePublic; // todo validata data
|
var pubKey = data.curvePublic; // todo validata data
|
||||||
|
|
||||||
|
@ -83,19 +79,19 @@ define([
|
||||||
|
|
||||||
friends[pubKey] = data;
|
friends[pubKey] = data;
|
||||||
|
|
||||||
Realtime.whenRealtimeSyncs(common.getRealtime(), function () {
|
Realtime.whenRealtimeSyncs(cfg.realtime, function () {
|
||||||
cb();
|
cb();
|
||||||
common.pinPads([data.channel], function (e) {
|
cfg.pinPads([data.channel], function (res) {
|
||||||
if (e) { console.error(e); }
|
if (res.error) { console.error(res.error); }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
common.changeDisplayName(proxy[Constants.displayNameKey]);
|
cfg.updateMetadata();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used to accept friend requests within apps other than /contacts/ */
|
/* Used to accept friend requests within apps other than /contacts/ */
|
||||||
Msg.addDirectMessageHandler = function (common) {
|
Msg.addDirectMessageHandler = function (cfg) {
|
||||||
var network = common.getNetwork();
|
var network = cfg.network;
|
||||||
var proxy = common.getProxy();
|
var proxy = cfg.proxy;
|
||||||
if (!network) { return void console.error('Network not ready'); }
|
if (!network) { return void console.error('Network not ready'); }
|
||||||
network.on('message', function (message, sender) {
|
network.on('message', function (message, sender) {
|
||||||
var msg;
|
var msg;
|
||||||
|
@ -138,8 +134,7 @@ define([
|
||||||
var confirmMsg = Messages._getKey('contacts_request', [
|
var confirmMsg = Messages._getKey('contacts_request', [
|
||||||
Util.fixHTML(msgData.displayName)
|
Util.fixHTML(msgData.displayName)
|
||||||
]);
|
]);
|
||||||
common.onFriendRequest(confirmMsg, todo);
|
cfg.friendRequest(confirmMsg, todo);
|
||||||
//UI.confirm(confirmMsg, todo, null, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msg[0] === "FRIEND_REQ_OK") {
|
if (msg[0] === "FRIEND_REQ_OK") {
|
||||||
|
@ -147,14 +142,14 @@ define([
|
||||||
if (idx !== -1) { pendingRequests.splice(idx, 1); }
|
if (idx !== -1) { pendingRequests.splice(idx, 1); }
|
||||||
|
|
||||||
// FIXME clarify this function's name
|
// FIXME clarify this function's name
|
||||||
addToFriendList(common, msgData, function (err) {
|
addToFriendList(cfg, msgData, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return void common.onFriendComplete({
|
return void cfg.friendComplete({
|
||||||
logText: Messages.contacts_addError,
|
logText: Messages.contacts_addError,
|
||||||
netfluxId: sender
|
netfluxId: sender
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
common.onFriendComplete({
|
cfg.friendComplete({
|
||||||
logText: Messages.contacts_added,
|
logText: Messages.contacts_added,
|
||||||
netfluxId: sender
|
netfluxId: sender
|
||||||
});
|
});
|
||||||
|
@ -167,24 +162,24 @@ define([
|
||||||
if (msg[0] === "FRIEND_REQ_NOK") {
|
if (msg[0] === "FRIEND_REQ_NOK") {
|
||||||
var i = pendingRequests.indexOf(sender);
|
var i = pendingRequests.indexOf(sender);
|
||||||
if (i !== -1) { pendingRequests.splice(i, 1); }
|
if (i !== -1) { pendingRequests.splice(i, 1); }
|
||||||
common.onFriendComplete({
|
cfg.friendComplete({
|
||||||
logText: Messages.contacts_rejected,
|
logText: Messages.contacts_rejected,
|
||||||
netfluxId: sender
|
netfluxId: sender
|
||||||
});
|
});
|
||||||
common.changeDisplayName(proxy[Constants.displayNameKey]);
|
cfg.updateMetadata();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msg[0] === "FRIEND_REQ_ACK") {
|
if (msg[0] === "FRIEND_REQ_ACK") {
|
||||||
var data = pending[sender];
|
var data = pending[sender];
|
||||||
if (!data) { return; }
|
if (!data) { return; }
|
||||||
addToFriendList(common, data, function (err) {
|
addToFriendList(cfg, data, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return void common.onFriendComplete({
|
return void cfg.friendComplete({
|
||||||
logText: Messages.contacts_addError,
|
logText: Messages.contacts_addError,
|
||||||
netfluxId: sender
|
netfluxId: sender
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
common.onFriendComplete({
|
cfg.friendComplete({
|
||||||
logText: Messages.contacts_added,
|
logText: Messages.contacts_added,
|
||||||
netfluxId: sender
|
netfluxId: sender
|
||||||
});
|
});
|
||||||
|
@ -198,17 +193,14 @@ define([
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Msg.getPending = function () {
|
Msg.inviteFromUserlist = function (cfg, data, cb) {
|
||||||
return pendingRequests;
|
var network = cfg.network;
|
||||||
};
|
var netfluxId = data.netfluxId;
|
||||||
|
var parsed = Hash.parsePadUrl(data.href);
|
||||||
Msg.inviteFromUserlist = function (common, netfluxId) {
|
|
||||||
var network = common.getNetwork();
|
|
||||||
var parsed = Hash.parsePadUrl(window.location.href);
|
|
||||||
if (!parsed.hashData) { return; }
|
if (!parsed.hashData) { return; }
|
||||||
// Message
|
// Message
|
||||||
var chan = parsed.hashData.channel;
|
var chan = parsed.hashData.channel;
|
||||||
var myData = createData(common.getProxy());
|
var myData = createData(cfg.proxy);
|
||||||
var msg = ["FRIEND_REQ", chan, myData];
|
var msg = ["FRIEND_REQ", chan, myData];
|
||||||
// Encryption
|
// Encryption
|
||||||
var keyStr = parsed.hashData.key;
|
var keyStr = parsed.hashData.key;
|
||||||
|
@ -218,12 +210,10 @@ define([
|
||||||
// Send encrypted message
|
// Send encrypted message
|
||||||
if (pendingRequests.indexOf(netfluxId) === -1) {
|
if (pendingRequests.indexOf(netfluxId) === -1) {
|
||||||
pendingRequests.push(netfluxId);
|
pendingRequests.push(netfluxId);
|
||||||
var proxy = common.getProxy();
|
cfg.updateMetadata(); // redraws the userlist in pad
|
||||||
// this redraws the userlist after a change has occurred
|
|
||||||
// TODO rename this function to reflect its purpose
|
|
||||||
common.changeDisplayName(proxy[Constants.displayNameKey]);
|
|
||||||
}
|
}
|
||||||
network.sendto(netfluxId, msgStr);
|
network.sendto(netfluxId, msgStr);
|
||||||
|
cb();
|
||||||
};
|
};
|
||||||
|
|
||||||
return Msg;
|
return Msg;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
define([
|
define([
|
||||||
'jquery',
|
|
||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
'/common/curve.js',
|
'/common/curve.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
], function ($, Crypto, Curve, Hash, Util, Realtime) {
|
'/common/common-constants.js',
|
||||||
|
], function (Crypto, Curve, Hash, Util, Realtime, Constants) {
|
||||||
'use strict';
|
'use strict';
|
||||||
var Msg = {
|
var Msg = {
|
||||||
inputs: [],
|
inputs: [],
|
||||||
|
@ -28,7 +28,7 @@ define([
|
||||||
var createData = Msg.createData = function (proxy, hash) {
|
var createData = Msg.createData = function (proxy, hash) {
|
||||||
return {
|
return {
|
||||||
channel: hash || Hash.createChannelId(),
|
channel: hash || Hash.createChannelId(),
|
||||||
displayName: proxy['cryptpad.username'],
|
displayName: proxy[Constants.displayNameKey],
|
||||||
profile: proxy.profile && proxy.profile.view,
|
profile: proxy.profile && proxy.profile.view,
|
||||||
edPublic: proxy.edPublic,
|
edPublic: proxy.edPublic,
|
||||||
curvePublic: proxy.curvePublic,
|
curvePublic: proxy.curvePublic,
|
||||||
|
@ -56,7 +56,7 @@ define([
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Msg.messenger = function (common) {
|
Msg.messenger = function (store) {
|
||||||
var messenger = {
|
var messenger = {
|
||||||
handlers: {
|
handlers: {
|
||||||
message: [],
|
message: [],
|
||||||
|
@ -89,9 +89,9 @@ define([
|
||||||
var joining = {};
|
var joining = {};
|
||||||
|
|
||||||
// declare common variables
|
// declare common variables
|
||||||
var network = common.getNetwork();
|
var network = store.network;
|
||||||
var proxy = common.getProxy();
|
var proxy = store.proxy;
|
||||||
var realtime = common.getRealtime();
|
var realtime = store.realtime;
|
||||||
Msg.hk = network.historyKeeper;
|
Msg.hk = network.historyKeeper;
|
||||||
var friends = getFriendList(proxy);
|
var friends = getFriendList(proxy);
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ define([
|
||||||
};
|
};
|
||||||
var msg = ['GET_HISTORY', chan.id, cfg];
|
var msg = ['GET_HISTORY', chan.id, cfg];
|
||||||
network.sendto(network.historyKeeper, JSON.stringify(msg))
|
network.sendto(network.historyKeeper, JSON.stringify(msg))
|
||||||
.then($.noop, function (err) {
|
.then(function () {}, function (err) {
|
||||||
throw new Error(err);
|
throw new Error(err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -629,14 +629,7 @@ define([
|
||||||
messenger.getMyInfo = function (cb) {
|
messenger.getMyInfo = function (cb) {
|
||||||
cb(void 0, {
|
cb(void 0, {
|
||||||
curvePublic: proxy.curvePublic,
|
curvePublic: proxy.curvePublic,
|
||||||
displayName: common.getDisplayName(),
|
displayName: proxy[Constants.displayNameKey]
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
messenger.clearOwnedChannel = function (channel, cb) {
|
|
||||||
common.clearOwnedChannel(channel, function (e) {
|
|
||||||
if (e) { return void cb(e); }
|
|
||||||
cb();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,6 @@
|
||||||
define([
|
define([], function () {
|
||||||
'/customize/application_config.js',
|
|
||||||
'/customize/messages.js',
|
|
||||||
'/common/common-interface.js',
|
|
||||||
], function (AppConfig, Messages, UI) {
|
|
||||||
var common = {};
|
var common = {};
|
||||||
|
|
||||||
common.infiniteSpinnerDetected = false;
|
|
||||||
var BAD_STATE_TIMEOUT = typeof(AppConfig.badStateTimeout) === 'number'?
|
|
||||||
AppConfig.badStateTimeout: 30000;
|
|
||||||
|
|
||||||
var connected = false;
|
|
||||||
var intr;
|
|
||||||
var infiniteSpinnerHandlers = [];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO make this not blow up when disconnected or lagging...
|
TODO make this not blow up when disconnected or lagging...
|
||||||
*/
|
*/
|
||||||
|
@ -20,7 +8,7 @@ define([
|
||||||
if (typeof(realtime.getAuthDoc) !== 'function') {
|
if (typeof(realtime.getAuthDoc) !== 'function') {
|
||||||
return void console.error('improper use of this function');
|
return void console.error('improper use of this function');
|
||||||
}
|
}
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (realtime.getAuthDoc() === realtime.getUserDoc()) {
|
if (realtime.getAuthDoc() === realtime.getUserDoc()) {
|
||||||
return void cb();
|
return void cb();
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,36 +17,5 @@ define([
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
common.beginDetectingInfiniteSpinner = function (realtime) {
|
|
||||||
if (intr) { return; }
|
|
||||||
intr = window.setInterval(function () {
|
|
||||||
var l;
|
|
||||||
try {
|
|
||||||
l = realtime.getLag();
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error("ChainPad.getLag() does not exist, please `bower update`");
|
|
||||||
}
|
|
||||||
if (l.lag < BAD_STATE_TIMEOUT || !connected) { return; }
|
|
||||||
realtime.abort();
|
|
||||||
// don't launch more than one popup
|
|
||||||
if (common.infiniteSpinnerDetected) { return; }
|
|
||||||
infiniteSpinnerHandlers.forEach(function (ish) { ish(); });
|
|
||||||
|
|
||||||
// inform the user their session is in a bad state
|
|
||||||
UI.confirm(Messages.realtime_unrecoverableError, function (yes) {
|
|
||||||
if (!yes) { return; }
|
|
||||||
window.parent.location.reload();
|
|
||||||
});
|
|
||||||
common.infiniteSpinnerDetected = true;
|
|
||||||
}, 2000);
|
|
||||||
};
|
|
||||||
|
|
||||||
common.onInfiniteSpinner = function (f) { infiniteSpinnerHandlers.push(f); };
|
|
||||||
|
|
||||||
common.setConnectionState = function (bool) {
|
|
||||||
if (typeof(bool) !== 'boolean') { return; }
|
|
||||||
connected = bool;
|
|
||||||
};
|
|
||||||
|
|
||||||
return common;
|
return common;
|
||||||
});
|
});
|
||||||
|
|
|
@ -98,7 +98,13 @@ define([
|
||||||
target: data.target
|
target: data.target
|
||||||
};
|
};
|
||||||
if (data.filter && !data.filter(file)) {
|
if (data.filter && !data.filter(file)) {
|
||||||
UI.log('Invalid avatar (type or size)');
|
return;
|
||||||
|
}
|
||||||
|
if (data.transformer) {
|
||||||
|
data.transformer(file, function (newFile) {
|
||||||
|
data.FM.handleFile(newFile, ev);
|
||||||
|
if (callback) { callback(); }
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.FM.handleFile(file, ev);
|
data.FM.handleFile(file, ev);
|
||||||
|
@ -571,12 +577,7 @@ define([
|
||||||
// getPinnedUsage updates common.account.usage, and other values
|
// getPinnedUsage updates common.account.usage, and other values
|
||||||
// so we can just use those and only check for errors
|
// so we can just use those and only check for errors
|
||||||
var $container = $('<span>', {'class':'cp-limit-container'});
|
var $container = $('<span>', {'class':'cp-limit-container'});
|
||||||
var todo;
|
var todo = function (err, data) {
|
||||||
var updateUsage = Util.notAgainForAnother(function () {
|
|
||||||
common.getPinUsage(todo);
|
|
||||||
}, LIMIT_REFRESH_RATE);
|
|
||||||
|
|
||||||
todo = function (err, data) {
|
|
||||||
if (err) { return void console.error(err); }
|
if (err) { return void console.error(err); }
|
||||||
|
|
||||||
var usage = data.usage;
|
var usage = data.usage;
|
||||||
|
@ -645,6 +646,10 @@ define([
|
||||||
$limit.append($usage).append($text);
|
$limit.append($usage).append($text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var updateUsage = Util.notAgainForAnother(function () {
|
||||||
|
common.getPinUsage(todo);
|
||||||
|
}, LIMIT_REFRESH_RATE);
|
||||||
|
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
updateUsage();
|
updateUsage();
|
||||||
}, LIMIT_REFRESH_RATE * 3);
|
}, LIMIT_REFRESH_RATE * 3);
|
||||||
|
|
|
@ -209,6 +209,43 @@ define([], function () {
|
||||||
xhr.send();
|
xhr.send();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if an element is a plain object
|
||||||
|
Util.isObject = function (o) {
|
||||||
|
return typeof (o) === "object" &&
|
||||||
|
Object.prototype.toString.call(o) === '[object Object]';
|
||||||
|
};
|
||||||
|
|
||||||
|
Util.isCircular = function (o) {
|
||||||
|
try {
|
||||||
|
JSON.stringify(o);
|
||||||
|
return false;
|
||||||
|
} catch (e) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* recursively adds the properties of an object 'b' to 'a'
|
||||||
|
arrays are only shallow copies, so references to the original
|
||||||
|
might still be present. Be mindful if you will modify 'a' in the future */
|
||||||
|
Util.extend = function (a, b) {
|
||||||
|
if (!Util.isObject(a) || !Util.isObject(b)) {
|
||||||
|
return void console.log("Extend only works with 2 objects");
|
||||||
|
}
|
||||||
|
if (Util.isCircular(b)) {
|
||||||
|
return void console.log("Extend doesn't accept circular objects");
|
||||||
|
}
|
||||||
|
for (var k in b) {
|
||||||
|
if (Util.isObject(b[k])) {
|
||||||
|
a[k] = {};
|
||||||
|
Util.extend(a[k], b[k]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Array.isArray(b[k])) {
|
||||||
|
a[k] = b[k].slice();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
a[k] = b[k];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return Util;
|
return Util;
|
||||||
});
|
});
|
||||||
}(self));
|
}(self));
|
||||||
|
|
|
@ -73,12 +73,12 @@ define([
|
||||||
|
|
||||||
realtime.contentUpdate(doc);
|
realtime.contentUpdate(doc);
|
||||||
|
|
||||||
var to = window.setTimeout(function () {
|
var to = setTimeout(function () {
|
||||||
cb(new Error("Timeout"));
|
cb(new Error("Timeout"));
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
Realtime.whenRealtimeSyncs(realtime, function () {
|
Realtime.whenRealtimeSyncs(realtime, function () {
|
||||||
window.clearTimeout(to);
|
clearTimeout(to);
|
||||||
realtime.abort();
|
realtime.abort();
|
||||||
finish(Session, void 0);
|
finish(Session, void 0);
|
||||||
});
|
});
|
||||||
|
|
File diff suppressed because it is too large
Load diff
10
www/common/dom-ready.js
Normal file
10
www/common/dom-ready.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
define(function () {
|
||||||
|
return {
|
||||||
|
onReady: function (cb) {
|
||||||
|
if (document.readyState === 'complete') { return void cb(); }
|
||||||
|
document.onreadystatechange = function () {
|
||||||
|
if (document.readyState === 'complete') { cb(); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -33,7 +33,7 @@ define([], function () {
|
||||||
data.map[id] = el.textContent;
|
data.map[id] = el.textContent;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
if (!el || !el.attributes) { return void console.error(el); }
|
if (!el || !el.attributes) { return; }
|
||||||
id = uid();
|
id = uid();
|
||||||
data.map[id] = [
|
data.map[id] = [
|
||||||
el.tagName,
|
el.tagName,
|
||||||
|
|
|
@ -1,359 +0,0 @@
|
||||||
define([
|
|
||||||
'jquery',
|
|
||||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
|
||||||
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
|
|
||||||
'/common/userObject.js',
|
|
||||||
'/common/common-interface.js',
|
|
||||||
'/common/common-hash.js',
|
|
||||||
'/common/common-util.js',
|
|
||||||
'/common/common-constants.js',
|
|
||||||
'/common/migrate-user-object.js',
|
|
||||||
'/bower_components/chainpad/chainpad.dist.js',
|
|
||||||
'/common/outer/network-config.js',
|
|
||||||
'/common/outer/local-store.js',
|
|
||||||
], function ($, Listmap, Crypto, FO, UI, Hash, Util, Constants, Migrate, ChainPad, NetConfig,
|
|
||||||
LocalStore) {
|
|
||||||
/*
|
|
||||||
This module uses localStorage, which is synchronous, but exposes an
|
|
||||||
asyncronous API. This is so that we can substitute other storage
|
|
||||||
methods.
|
|
||||||
|
|
||||||
To override these methods, create another file at:
|
|
||||||
/customize/storage.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Store = {};
|
|
||||||
var store;
|
|
||||||
|
|
||||||
var initStore = function (filesOp, storeObj, exp) {
|
|
||||||
var ret = {};
|
|
||||||
|
|
||||||
var safeSet = function (key, val) {
|
|
||||||
storeObj[key] = val;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Store uses nodebacks...
|
|
||||||
ret.set = function (key, val, cb) {
|
|
||||||
safeSet(key, val);
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
// implement in alternative store
|
|
||||||
ret.setBatch = function (map, cb) {
|
|
||||||
Object.keys(map).forEach(function (key) {
|
|
||||||
safeSet(key, map[key]);
|
|
||||||
});
|
|
||||||
cb(void 0, map);
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.setDrive = function (key, val, cb) {
|
|
||||||
storeObj.drive[key] = val;
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
var safeGet = function (key) {
|
|
||||||
return storeObj[key];
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.get = function (key, cb) {
|
|
||||||
cb(void 0, safeGet(key));
|
|
||||||
};
|
|
||||||
|
|
||||||
// implement in alternative store
|
|
||||||
ret.getBatch = function (keys, cb) {
|
|
||||||
var res = {};
|
|
||||||
keys.forEach(function (key) {
|
|
||||||
res[key] = safeGet(key);
|
|
||||||
});
|
|
||||||
cb(void 0, res);
|
|
||||||
};
|
|
||||||
|
|
||||||
var getAttributeObject = function (attr) {
|
|
||||||
if (typeof attr === "string") {
|
|
||||||
console.error('DEPRECATED: use setAttribute with an array, not a string');
|
|
||||||
return {
|
|
||||||
obj: storeObj.settings,
|
|
||||||
key: attr
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!Array.isArray(attr)) { throw new Error("Attribute must be string or array"); }
|
|
||||||
if (attr.length === 0) { throw new Error("Attribute can't be empty"); }
|
|
||||||
var obj = storeObj.settings;
|
|
||||||
attr.forEach(function (el, i) {
|
|
||||||
if (i === attr.length-1) { return; }
|
|
||||||
if (!obj[el]) {
|
|
||||||
obj[el] = {};
|
|
||||||
}
|
|
||||||
else if (typeof obj[el] !== "object") { throw new Error("Wrong attribute"); }
|
|
||||||
obj = obj[el];
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
obj: obj,
|
|
||||||
key: attr[attr.length-1]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
ret.setAttribute = function (attr, value, cb) {
|
|
||||||
try {
|
|
||||||
var object = getAttributeObject(attr);
|
|
||||||
object.obj[object.key] = value;
|
|
||||||
} catch (e) { return void cb(e); }
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
ret.getAttribute = function (attr, cb) {
|
|
||||||
var object;
|
|
||||||
try {
|
|
||||||
object = getAttributeObject(attr);
|
|
||||||
} catch (e) { return void cb(e); }
|
|
||||||
cb(null, object.obj[object.key]);
|
|
||||||
};
|
|
||||||
ret.setPadAttribute = filesOp.setPadAttribute;
|
|
||||||
ret.getPadAttribute = filesOp.getPadAttribute;
|
|
||||||
ret.getIdFromHref = filesOp.getIdFromHref;
|
|
||||||
|
|
||||||
ret.getDrive = function (key, cb) {
|
|
||||||
cb(void 0, storeObj.drive[key]);
|
|
||||||
};
|
|
||||||
|
|
||||||
var safeRemove = function (key) {
|
|
||||||
delete storeObj[key];
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.remove = function (key, cb) {
|
|
||||||
safeRemove(key);
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
// implement in alternative store
|
|
||||||
ret.removeBatch = function (keys, cb) {
|
|
||||||
keys.forEach(function (key) {
|
|
||||||
safeRemove(key);
|
|
||||||
});
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.keys = function (cb) {
|
|
||||||
cb(void 0, Object.keys(storeObj));
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.removeData = filesOp.removeData;
|
|
||||||
ret.pushData = filesOp.pushData;
|
|
||||||
ret.addPad = filesOp.add;
|
|
||||||
|
|
||||||
ret.forgetPad = function (href, cb) {
|
|
||||||
filesOp.forget(href);
|
|
||||||
cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.listTemplates = function () {
|
|
||||||
var templateFiles = filesOp.getFiles(['template']);
|
|
||||||
var res = [];
|
|
||||||
templateFiles.forEach(function (f) {
|
|
||||||
var data = filesOp.getFileData(f);
|
|
||||||
res.push(JSON.parse(JSON.stringify(data)));
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.getProxy = function () {
|
|
||||||
return exp;
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.getLoginName = function () {
|
|
||||||
return storeObj.login_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.repairDrive = function () {
|
|
||||||
filesOp.fixFiles();
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.getEmptyObject = function () {
|
|
||||||
return filesOp.getStructure();
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.replace = filesOp.replace;
|
|
||||||
|
|
||||||
ret.restoreHref = filesOp.restoreHref;
|
|
||||||
|
|
||||||
ret.changeHandlers = [];
|
|
||||||
|
|
||||||
ret.change = function () {};
|
|
||||||
|
|
||||||
ret.getProfile = function () {
|
|
||||||
return storeObj.profile;
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
var tryParsing = function (x) {
|
|
||||||
try { return JSON.parse(x); }
|
|
||||||
catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var onReady = function (f, proxy, Cryptpad, exp) {
|
|
||||||
var fo = exp.fo = FO.init(proxy.drive, {
|
|
||||||
Cryptpad: Cryptpad,
|
|
||||||
loggedIn: LocalStore.isLoggedIn()
|
|
||||||
});
|
|
||||||
var todo = function () {
|
|
||||||
fo.fixFiles();
|
|
||||||
|
|
||||||
Migrate(proxy, Cryptpad);
|
|
||||||
|
|
||||||
store = initStore(fo, proxy, exp);
|
|
||||||
if (typeof(f) === 'function') {
|
|
||||||
f(void 0, store);
|
|
||||||
}
|
|
||||||
//storeObj = proxy;
|
|
||||||
|
|
||||||
var requestLogin = function () {
|
|
||||||
// log out so that you don't go into an endless loop...
|
|
||||||
LocalStore.logout();
|
|
||||||
|
|
||||||
// redirect them to log in, and come back when they're done.
|
|
||||||
sessionStorage.redirectTo = window.location.href;
|
|
||||||
window.location.href = '/login/';
|
|
||||||
};
|
|
||||||
|
|
||||||
var tokenKey = 'loginToken';
|
|
||||||
if (LocalStore.isLoggedIn()) {
|
|
||||||
/* This isn't truly secure, since anyone who can read the user's object can
|
|
||||||
set their local loginToken to match that in the object. However, it exposes
|
|
||||||
a UI that will work most of the time. */
|
|
||||||
|
|
||||||
// every user object should have a persistent, random number
|
|
||||||
if (typeof(proxy.loginToken) !== 'number') {
|
|
||||||
proxy[tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy User_hash into sessionStorage because cross-domain iframes
|
|
||||||
// on safari replaces localStorage with sessionStorage or something
|
|
||||||
if (sessionStorage) { sessionStorage.setItem('User_hash', localStorage.getItem('User_hash')); }
|
|
||||||
|
|
||||||
var localToken = tryParsing(localStorage.getItem(tokenKey));
|
|
||||||
if (localToken === null) {
|
|
||||||
// if that number hasn't been set to localStorage, do so.
|
|
||||||
localStorage.setItem(tokenKey, proxy.loginToken);
|
|
||||||
} else if (localToken !== proxy[tokenKey]) {
|
|
||||||
// if it has been, and the local number doesn't match that in
|
|
||||||
// the user object, request that they reauthenticate.
|
|
||||||
return void requestLogin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!proxy.settings || !proxy.settings.general ||
|
|
||||||
typeof(proxy.settings.general.allowUserFeedback) !== 'boolean') {
|
|
||||||
proxy.settings = proxy.settings || {};
|
|
||||||
proxy.settings.general = proxy.settings.general || {};
|
|
||||||
proxy.settings.general.allowUserFeedback = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) {
|
|
||||||
// even anonymous users should have a persistent, unique-ish id
|
|
||||||
console.log('generating a persistent identifier');
|
|
||||||
proxy.uid = Hash.createChannelId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the user is logged in, but does not have signing keys...
|
|
||||||
if (LocalStore.isLoggedIn() && (!Cryptpad.hasSigningKeys(proxy) ||
|
|
||||||
!Cryptpad.hasCurveKeys(proxy))) {
|
|
||||||
return void requestLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy.on('change', [Constants.displayNameKey], function (o, n) {
|
|
||||||
if (typeof(n) !== "string") { return; }
|
|
||||||
Cryptpad.changeDisplayName(n);
|
|
||||||
});
|
|
||||||
proxy.on('change', ['profile'], function () {
|
|
||||||
// Trigger userlist update when the avatar has changed
|
|
||||||
Cryptpad.changeDisplayName(proxy[Constants.displayNameKey]);
|
|
||||||
});
|
|
||||||
proxy.on('change', ['friends'], function () {
|
|
||||||
// Trigger userlist update when the avatar has changed
|
|
||||||
Cryptpad.changeDisplayName(proxy[Constants.displayNameKey]);
|
|
||||||
});
|
|
||||||
proxy.on('change', [tokenKey], function () {
|
|
||||||
var localToken = tryParsing(localStorage.getItem(tokenKey));
|
|
||||||
if (localToken !== proxy[tokenKey]) {
|
|
||||||
return void requestLogin();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
fo.migrate(todo);
|
|
||||||
};
|
|
||||||
|
|
||||||
var initialized = false;
|
|
||||||
|
|
||||||
var init = function (f, Cryptpad) {
|
|
||||||
if (!Cryptpad || initialized) { return; }
|
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
var hash = LocalStore.getUserHash() || LocalStore.getFSHash() || Hash.createRandomHash();
|
|
||||||
if (!hash) {
|
|
||||||
throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...');
|
|
||||||
}
|
|
||||||
var secret = Hash.getSecrets('drive', hash);
|
|
||||||
var listmapConfig = {
|
|
||||||
data: {},
|
|
||||||
websocketURL: NetConfig.getWebsocketURL(),
|
|
||||||
channel: secret.channel,
|
|
||||||
readOnly: false,
|
|
||||||
validateKey: secret.keys.validateKey || undefined,
|
|
||||||
crypto: Crypto.createEncryptor(secret.keys),
|
|
||||||
userName: 'fs',
|
|
||||||
logLevel: 1,
|
|
||||||
ChainPad: ChainPad,
|
|
||||||
classic: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var exp = {};
|
|
||||||
|
|
||||||
var rt = window.rt = Listmap.create(listmapConfig);
|
|
||||||
|
|
||||||
exp.realtime = rt.realtime;
|
|
||||||
exp.proxy = rt.proxy;
|
|
||||||
rt.proxy.on('create', function (info) {
|
|
||||||
exp.info = info;
|
|
||||||
if (!LocalStore.getUserHash()) {
|
|
||||||
LocalStore.setFSHash(Hash.getEditHashFromKeys(info.channel, secret.keys));
|
|
||||||
}
|
|
||||||
}).on('ready', function () {
|
|
||||||
if (store) { return; } // the store is already ready, it is a reconnection
|
|
||||||
if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; }
|
|
||||||
var drive = rt.proxy.drive;
|
|
||||||
// Creating a new anon drive: import anon pads from localStorage
|
|
||||||
if ((!drive[Constants.oldStorageKey] || !Array.isArray(drive[Constants.oldStorageKey]))
|
|
||||||
&& !drive['filesData']) {
|
|
||||||
drive[Constants.oldStorageKey] = [];
|
|
||||||
onReady(f, rt.proxy, Cryptpad, exp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Drive already exist: return the existing drive, don't load data from legacy store
|
|
||||||
onReady(f, rt.proxy, Cryptpad, exp);
|
|
||||||
})
|
|
||||||
.on('change', ['drive', 'migrate'], function () {
|
|
||||||
var path = arguments[2];
|
|
||||||
var value = arguments[1];
|
|
||||||
if (path[0] === 'drive' && path[1] === "migrate" && value === 1) {
|
|
||||||
rt.network.disconnect();
|
|
||||||
rt.realtime.abort();
|
|
||||||
UI.alert(Cryptpad.Messages.fs_migration, null, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Store.ready = function (f, Cryptpad) {
|
|
||||||
if (store) { // Store.ready probably called twice, store already ready
|
|
||||||
if (typeof(f) === 'function') {
|
|
||||||
f(void 0, store);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
init(f, Cryptpad);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return Store;
|
|
||||||
});
|
|
|
@ -2,8 +2,8 @@ define([
|
||||||
'/common/cryptget.js',
|
'/common/cryptget.js',
|
||||||
'/common/userObject.js',
|
'/common/userObject.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/common/outer/local-store.js',
|
'/common/common-realtime.js',
|
||||||
], function (Crypt, FO, Hash, LocalStore) {
|
], function (Crypt, FO, Hash, Realtime) {
|
||||||
var exp = {};
|
var exp = {};
|
||||||
|
|
||||||
var getType = function (el) {
|
var getType = function (el) {
|
||||||
|
@ -86,7 +86,7 @@ define([
|
||||||
|
|
||||||
exp.anonDriveIntoUser = function (proxyData, fsHash, cb) {
|
exp.anonDriveIntoUser = function (proxyData, fsHash, cb) {
|
||||||
// Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
|
// Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
|
||||||
if (!fsHash || !LocalStore.isLoggedIn()) {
|
if (!fsHash || !proxyData.loggedIn) {
|
||||||
if (typeof(cb) === "function") { return void cb(); }
|
if (typeof(cb) === "function") { return void cb(); }
|
||||||
}
|
}
|
||||||
// Get the content of FS_hash and then merge the objects, remove the migration key and cb
|
// Get the content of FS_hash and then merge the objects, remove the migration key and cb
|
||||||
|
@ -105,11 +105,11 @@ define([
|
||||||
if (parsed) {
|
if (parsed) {
|
||||||
var proxy = proxyData.proxy;
|
var proxy = proxyData.proxy;
|
||||||
var oldFo = FO.init(parsed.drive, {
|
var oldFo = FO.init(parsed.drive, {
|
||||||
loggedIn: LocalStore.isLoggedIn()
|
loggedIn: proxyData.loggedIn
|
||||||
});
|
});
|
||||||
var onMigrated = function () {
|
var onMigrated = function () {
|
||||||
oldFo.fixFiles();
|
oldFo.fixFiles();
|
||||||
var newFo = proxyData.fo;
|
var newFo = proxyData.userObject;
|
||||||
var oldRecentPads = parsed.drive[newFo.FILES_DATA];
|
var oldRecentPads = parsed.drive[newFo.FILES_DATA];
|
||||||
var newRecentPads = proxy.drive[newFo.FILES_DATA];
|
var newRecentPads = proxy.drive[newFo.FILES_DATA];
|
||||||
var oldFiles = oldFo.getFiles([newFo.FILES_DATA]);
|
var oldFiles = oldFo.getFiles([newFo.FILES_DATA]);
|
||||||
|
@ -154,7 +154,9 @@ define([
|
||||||
proxy.FS_hashes = [];
|
proxy.FS_hashes = [];
|
||||||
}
|
}
|
||||||
proxy.FS_hashes.push(fsHash);
|
proxy.FS_hashes.push(fsHash);
|
||||||
if (typeof(cb) === "function") { cb(); }
|
if (typeof(cb) === "function") {
|
||||||
|
Realtime.whenRealtimeSyncs(proxyData.realtime, cb);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
oldFo.migrate(onMigrated);
|
oldFo.migrate(onMigrated);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -59,7 +59,6 @@ define(['json.sortify'], function (Sortify) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadataObj.title !== rememberedTitle) {
|
if (metadataObj.title !== rememberedTitle) {
|
||||||
console.log("Title update\n" + metadataObj.title + '\n');
|
|
||||||
rememberedTitle = metadataObj.title;
|
rememberedTitle = metadataObj.title;
|
||||||
titleChangeHandlers.forEach(function (f) { f(metadataObj.title); });
|
titleChangeHandlers.forEach(function (f) { f(metadataObj.title); });
|
||||||
}
|
}
|
||||||
|
@ -73,30 +72,45 @@ define(['json.sortify'], function (Sortify) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var netfluxId;
|
||||||
|
var isReady = false;
|
||||||
|
var readyHandlers = [];
|
||||||
sframeChan.on('EV_METADATA_UPDATE', function (ev) {
|
sframeChan.on('EV_METADATA_UPDATE', function (ev) {
|
||||||
meta = ev;
|
meta = ev;
|
||||||
if (ev.priv) {
|
if (ev.priv) {
|
||||||
priv = ev.priv;
|
priv = ev.priv;
|
||||||
}
|
}
|
||||||
|
if (netfluxId) {
|
||||||
|
meta.user.netfluxId = netfluxId;
|
||||||
|
}
|
||||||
|
if (!isReady) {
|
||||||
|
isReady = true;
|
||||||
|
readyHandlers.forEach(function (f) { f(); });
|
||||||
|
}
|
||||||
change(true);
|
change(true);
|
||||||
});
|
});
|
||||||
sframeChan.on('EV_RT_CONNECT', function (ev) {
|
sframeChan.on('EV_RT_CONNECT', function (ev) {
|
||||||
meta.user.netfluxId = ev.myID;
|
netfluxId = ev.myID;
|
||||||
members = ev.members;
|
members = ev.members;
|
||||||
|
if (!meta.user) { return; }
|
||||||
|
meta.user.netfluxId = netfluxId;
|
||||||
change(true);
|
change(true);
|
||||||
});
|
});
|
||||||
sframeChan.on('EV_RT_JOIN', function (ev) {
|
sframeChan.on('EV_RT_JOIN', function (ev) {
|
||||||
members.push(ev);
|
members.push(ev);
|
||||||
|
if (!meta.user) { return; }
|
||||||
change(false);
|
change(false);
|
||||||
});
|
});
|
||||||
sframeChan.on('EV_RT_LEAVE', function (ev) {
|
sframeChan.on('EV_RT_LEAVE', function (ev) {
|
||||||
var idx = members.indexOf(ev);
|
var idx = members.indexOf(ev);
|
||||||
if (idx === -1) { console.log('Error: ' + ev + ' not in members'); return; }
|
if (idx === -1) { console.log('Error: ' + ev + ' not in members'); return; }
|
||||||
members.splice(idx, 1);
|
members.splice(idx, 1);
|
||||||
|
if (!meta.user) { return; }
|
||||||
change(false);
|
change(false);
|
||||||
});
|
});
|
||||||
sframeChan.on('EV_RT_DISCONNECT', function () {
|
sframeChan.on('EV_RT_DISCONNECT', function () {
|
||||||
members = [];
|
members = [];
|
||||||
|
if (!meta.user) { return; }
|
||||||
change(true);
|
change(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -140,6 +154,10 @@ define(['json.sortify'], function (Sortify) {
|
||||||
},
|
},
|
||||||
getNetfluxId : function () {
|
getNetfluxId : function () {
|
||||||
return meta.user.netfluxId;
|
return meta.user.netfluxId;
|
||||||
|
},
|
||||||
|
onReady: function (f) {
|
||||||
|
if (isReady) { return void f(); }
|
||||||
|
readyHandlers.push(f);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
924
www/common/outer/async-store.js
Normal file
924
www/common/outer/async-store.js
Normal file
|
@ -0,0 +1,924 @@
|
||||||
|
define([
|
||||||
|
'/common/userObject.js',
|
||||||
|
'/common/migrate-user-object.js',
|
||||||
|
'/common/common-hash.js',
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/common/common-constants.js',
|
||||||
|
'/common/common-feedback.js',
|
||||||
|
'/common/common-realtime.js',
|
||||||
|
'/common/common-messaging.js',
|
||||||
|
'/common/common-messenger.js',
|
||||||
|
'/common/outer/network-config.js',
|
||||||
|
|
||||||
|
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
|
||||||
|
'/bower_components/chainpad/chainpad.dist.js',
|
||||||
|
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||||
|
], function (UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger,
|
||||||
|
NetConfig,
|
||||||
|
Crypto, ChainPad, Listmap) {
|
||||||
|
var Store = {};
|
||||||
|
|
||||||
|
var postMessage = function () {};
|
||||||
|
|
||||||
|
var storeHash;
|
||||||
|
|
||||||
|
var store = {};
|
||||||
|
|
||||||
|
|
||||||
|
var onSync = function (cb) {
|
||||||
|
Realtime.whenRealtimeSyncs(store.realtime, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Store.get = function (key, cb) {
|
||||||
|
cb(Util.find(store.proxy, key));
|
||||||
|
};
|
||||||
|
Store.set = function (data, cb) {
|
||||||
|
var path = data.key.slice();
|
||||||
|
var key = path.pop();
|
||||||
|
var obj = Util.find(store.proxy, path);
|
||||||
|
if (!obj || typeof(obj) !== "object") { return void cb({error: 'INVALID_PATH'}); }
|
||||||
|
if (typeof data.value === "undefined") {
|
||||||
|
delete obj[key];
|
||||||
|
} else {
|
||||||
|
obj[key] = data.value;
|
||||||
|
}
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.hasSigningKeys = function () {
|
||||||
|
if (!store.proxy) { return; }
|
||||||
|
return typeof(store.proxy.edPrivate) === 'string' &&
|
||||||
|
typeof(store.proxy.edPublic) === 'string';
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.hasCurveKeys = function () {
|
||||||
|
if (!store.proxy) { return; }
|
||||||
|
return typeof(store.proxy.curvePrivate) === 'string' &&
|
||||||
|
typeof(store.proxy.curvePublic) === 'string';
|
||||||
|
};
|
||||||
|
|
||||||
|
var getUserChannelList = function () {
|
||||||
|
// start with your userHash...
|
||||||
|
var userHash = storeHash;
|
||||||
|
if (!userHash) { return null; }
|
||||||
|
|
||||||
|
var userParsedHash = Hash.parseTypeHash('drive', userHash);
|
||||||
|
var userChannel = userParsedHash && userParsedHash.channel;
|
||||||
|
if (!userChannel) { return null; }
|
||||||
|
|
||||||
|
var list = store.userObject.getFiles([store.userObject.FILES_DATA]).map(function (id) {
|
||||||
|
return Hash.hrefToHexChannelId(store.userObject.getFileData(id).href);
|
||||||
|
})
|
||||||
|
.filter(function (x) { return x; });
|
||||||
|
|
||||||
|
// Get the avatar
|
||||||
|
var profile = store.proxy.profile;
|
||||||
|
if (profile) {
|
||||||
|
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit) : null;
|
||||||
|
if (profileChan) { list.push(profileChan); }
|
||||||
|
var avatarChan = profile.avatar ? Hash.hrefToHexChannelId(profile.avatar) : null;
|
||||||
|
if (avatarChan) { list.push(avatarChan); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.proxy.friends) {
|
||||||
|
var fList = Messaging.getFriendChannelsList(store.proxy);
|
||||||
|
list = list.concat(fList);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.push(Util.base64ToHex(userChannel));
|
||||||
|
list.sort();
|
||||||
|
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getCanonicalChannelList = function () {
|
||||||
|
return Util.deduplicateString(getUserChannelList()).sort();
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////// RPC //////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Store.pinPads = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
if (typeof(cb) !== 'function') {
|
||||||
|
console.error('expected a callback');
|
||||||
|
}
|
||||||
|
|
||||||
|
store.rpc.pin(data, function (e, hash) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
cb({hash: hash});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.unpinPads = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
|
||||||
|
store.rpc.unpin(data, function (e, hash) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
cb({hash: hash});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var account = {};
|
||||||
|
|
||||||
|
Store.getPinnedUsage = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
|
||||||
|
store.rpc.getFileListSize(function (err, bytes) {
|
||||||
|
if (typeof(bytes) === 'number') {
|
||||||
|
account.usage = bytes;
|
||||||
|
}
|
||||||
|
cb({bytes: bytes});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update for all users from accounts and return current user limits
|
||||||
|
Store.updatePinLimit = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
store.rpc.updatePinLimits(function (e, limit, plan, note) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
account.limit = limit;
|
||||||
|
account.plan = plan;
|
||||||
|
account.note = note;
|
||||||
|
cb(account);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// Get current user limits
|
||||||
|
Store.getPinLimit = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
|
||||||
|
var ALWAYS_REVALIDATE = true;
|
||||||
|
if (ALWAYS_REVALIDATE || typeof(account.limit) !== 'number' ||
|
||||||
|
typeof(account.plan) !== 'string' ||
|
||||||
|
typeof(account.note) !== 'string') {
|
||||||
|
return void store.rpc.getLimit(function (e, limit, plan, note) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
account.limit = limit;
|
||||||
|
account.plan = plan;
|
||||||
|
account.note = note;
|
||||||
|
cb(account);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cb(account);
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.clearOwnedChannel = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
store.rpc.clearOwnedChannel(data, function (err) {
|
||||||
|
cb({error:err});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.uploadComplete = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
store.rpc.uploadComplete(function (err, res) {
|
||||||
|
if (err) { return void cb({error:err}); }
|
||||||
|
cb(res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.uploadStatus = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
store.rpc.uploadStatus(data.size, function (err, res) {
|
||||||
|
if (err) { return void cb({error:err}); }
|
||||||
|
cb(res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.uploadCancel = function (data, cb) {
|
||||||
|
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||||
|
store.rpc.uploadCancel(function (err, res) {
|
||||||
|
if (err) { return void cb({error:err}); }
|
||||||
|
cb(res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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({
|
||||||
|
error: e,
|
||||||
|
msg: msg
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.initRpc = function (data, cb) {
|
||||||
|
require(['/common/pinpad.js'], function (Pinpad) {
|
||||||
|
Pinpad.create(store.network, store.proxy, function (e, call) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
|
||||||
|
store.rpc = call;
|
||||||
|
|
||||||
|
Store.getPinLimit(null, function (obj) {
|
||||||
|
if (obj.error) { console.error(obj.error); }
|
||||||
|
account.limit = obj.limit;
|
||||||
|
account.plan = obj.plan;
|
||||||
|
account.note = obj.note;
|
||||||
|
cb(obj);
|
||||||
|
});
|
||||||
|
|
||||||
|
arePinsSynced(function (err, yes) {
|
||||||
|
if (!yes) {
|
||||||
|
resetPins(function (err) {
|
||||||
|
if (err) { return console.error(err); }
|
||||||
|
console.log('RESET DONE');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
////////////////// ANON RPC //////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
Store.anonRpcMsg = function (data, cb) {
|
||||||
|
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||||
|
store.anon_rpc.send(data.msg, data.data, function (err, res) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.getFileSize = function (data, cb) {
|
||||||
|
console.log(data, cb);
|
||||||
|
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||||
|
|
||||||
|
var channelId = Hash.hrefToHexChannelId(data.href);
|
||||||
|
store.anon_rpc.send("GET_FILE_SIZE", channelId, function (e, response) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
if (response && response.length && typeof(response[0]) === 'number') {
|
||||||
|
return void cb({size: response[0]});
|
||||||
|
} else {
|
||||||
|
cb({error: 'INVALID_RESPONSE'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.getMultipleFileSize = function (data, cb) {
|
||||||
|
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||||
|
if (!Array.isArray(data.files)) {
|
||||||
|
return void cb({error: 'INVALID_FILE_LIST'});
|
||||||
|
}
|
||||||
|
|
||||||
|
store.anon_rpc.send('GET_MULTIPLE_FILE_SIZE', data.files, function (e, res) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
if (res && res.length && typeof(res[0]) === 'object') {
|
||||||
|
cb({size: res[0]});
|
||||||
|
} else {
|
||||||
|
cb({error: 'UNEXPECTED_RESPONSE'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.initAnonRpc = function (data, cb) {
|
||||||
|
require([
|
||||||
|
'/common/rpc.js',
|
||||||
|
], function (Rpc) {
|
||||||
|
Rpc.createAnonymous(store.network, function (e, call) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
store.anon_rpc = call;
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////// Store ////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Get the metadata for sframe-common-outer
|
||||||
|
Store.getMetadata = function (data, cb) {
|
||||||
|
var metadata = {
|
||||||
|
// "user" is shared with everybody via the userlist
|
||||||
|
user: {
|
||||||
|
name: store.proxy[Constants.displayNameKey],
|
||||||
|
uid: store.proxy.uid,
|
||||||
|
avatar: Util.find(store.proxy, ['profile', 'avatar']),
|
||||||
|
profile: Util.find(store.proxy, ['profile', 'view']),
|
||||||
|
curvePublic: store.proxy.curvePublic,
|
||||||
|
},
|
||||||
|
// "priv" is not shared with other users but is needed by the apps
|
||||||
|
priv: {
|
||||||
|
edPublic: store.proxy.edPublic,
|
||||||
|
friends: store.proxy.friends,
|
||||||
|
settings: store.proxy.settings,
|
||||||
|
thumbnails: !Util.find(store.proxy, ['settings', 'general', 'disableThumbnails'])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cb(JSON.parse(JSON.stringify(metadata)));
|
||||||
|
};
|
||||||
|
|
||||||
|
var makePad = function (href, title) {
|
||||||
|
var now = +new Date();
|
||||||
|
return {
|
||||||
|
href: href,
|
||||||
|
atime: now,
|
||||||
|
ctime: now,
|
||||||
|
title: title || Hash.getDefaultName(Hash.parsePadUrl(href)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.addPad = function (data, cb) {
|
||||||
|
if (!data.href) { return void cb({error:'NO_HREF'}); }
|
||||||
|
var pad = makePad(data.href, data.title);
|
||||||
|
store.userObject.pushData(pad, function (e, id) {
|
||||||
|
if (e) { return void cb({error: "Error while adding a template:"+ e}); }
|
||||||
|
var path = data.path || ['root'];
|
||||||
|
store.userObject.add(id, path);
|
||||||
|
onSync(cb);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a "What is CryptPad?" pad in the drive
|
||||||
|
* data
|
||||||
|
* - driveReadme
|
||||||
|
* - driveReadmeTitle
|
||||||
|
*/
|
||||||
|
Store.createReadme = function (data, cb) {
|
||||||
|
require(['/common/cryptget.js'], function (Crypt) {
|
||||||
|
var hash = Hash.createRandomHash();
|
||||||
|
Crypt.put(hash, data.driveReadme, function (e) {
|
||||||
|
if (e) {
|
||||||
|
return void cb({ error: "Error while creating the default pad:"+ e});
|
||||||
|
}
|
||||||
|
var href = '/pad/#' + hash;
|
||||||
|
var fileData = {
|
||||||
|
href: href,
|
||||||
|
title: data.driveReadmeTitle,
|
||||||
|
atime: +new Date(),
|
||||||
|
ctime: +new Date()
|
||||||
|
};
|
||||||
|
store.userObject.pushData(fileData, function (e, id) {
|
||||||
|
if (e) {
|
||||||
|
return void cb({ error: "Error while creating the default pad:"+ e});
|
||||||
|
}
|
||||||
|
store.userObject.add(id);
|
||||||
|
onSync(cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the anonymous drive into the user drive at registration
|
||||||
|
* data
|
||||||
|
* - anonHash
|
||||||
|
*/
|
||||||
|
Store.migrateAnonDrive = function (data, cb) {
|
||||||
|
require(['/common/mergeDrive.js'], function (Merge) {
|
||||||
|
var hash = data.anonHash;
|
||||||
|
Merge.anonDriveIntoUser(store, hash, cb);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var getAttributeObject = function (attr) {
|
||||||
|
if (typeof attr === "string") {
|
||||||
|
console.error('DEPRECATED: use setAttribute with an array, not a string');
|
||||||
|
return {
|
||||||
|
obj: store.proxy.settings,
|
||||||
|
key: attr
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!Array.isArray(attr)) { return void console.error("Attribute must be string or array"); }
|
||||||
|
if (attr.length === 0) { return void console.error("Attribute can't be empty"); }
|
||||||
|
var obj = store.proxy.settings;
|
||||||
|
attr.forEach(function (el, i) {
|
||||||
|
if (i === attr.length-1) { return; }
|
||||||
|
if (!obj[el]) {
|
||||||
|
obj[el] = {};
|
||||||
|
}
|
||||||
|
else if (typeof obj[el] !== "object") { return void console.error("Wrong attribute"); }
|
||||||
|
obj = obj[el];
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
obj: obj,
|
||||||
|
key: attr[attr.length-1]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the display name (username) in the proxy
|
||||||
|
Store.setDisplayName = function (value, cb) {
|
||||||
|
store.proxy[Constants.displayNameKey] = value;
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset the drive part of the userObject (from settings)
|
||||||
|
Store.resetDrive = function (data, cb) {
|
||||||
|
store.proxy.drive = store.fo.getStructure();
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings & pad attributes
|
||||||
|
* data
|
||||||
|
* - href (String)
|
||||||
|
* - attr (Array)
|
||||||
|
* - value (String)
|
||||||
|
*/
|
||||||
|
Store.setPadAttribute = function (data, cb) {
|
||||||
|
store.userObject.setPadAttribute(data.href, data.attr, data.value, function () {
|
||||||
|
onSync(cb);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Store.getPadAttribute = function (data, cb) {
|
||||||
|
store.userObject.getPadAttribute(data.href, data.attr, function (err, val) {
|
||||||
|
if (err) { return void cb({error: err}); }
|
||||||
|
cb(val);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Store.setAttribute = function (data, cb) {
|
||||||
|
try {
|
||||||
|
var object = getAttributeObject(data.attr);
|
||||||
|
object.obj[object.key] = data.value;
|
||||||
|
} catch (e) { return void cb({error: e}); }
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
Store.getAttribute = function (data, cb) {
|
||||||
|
var object;
|
||||||
|
try {
|
||||||
|
object = getAttributeObject(data.attr);
|
||||||
|
} catch (e) { return void cb({error: e}); }
|
||||||
|
cb(object.obj[object.key]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tags
|
||||||
|
Store.listAllTags = function (data, cb) {
|
||||||
|
var all = [];
|
||||||
|
var files = Util.find(store.proxy, ['drive', 'filesData']);
|
||||||
|
|
||||||
|
if (typeof(files) !== 'object') { return cb({error: 'invalid_drive'}); }
|
||||||
|
Object.keys(files).forEach(function (k) {
|
||||||
|
var file = files[k];
|
||||||
|
if (!Array.isArray(file.tags)) { return; }
|
||||||
|
file.tags.forEach(function (tag) {
|
||||||
|
if (all.indexOf(tag) === -1) { all.push(tag); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
cb(all);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Templates
|
||||||
|
Store.getTemplates = function (data, cb) {
|
||||||
|
var templateFiles = store.userObject.getFiles(['template']);
|
||||||
|
var res = [];
|
||||||
|
templateFiles.forEach(function (f) {
|
||||||
|
var data = store.userObject.getFileData(f);
|
||||||
|
res.push(JSON.parse(JSON.stringify(data)));
|
||||||
|
});
|
||||||
|
cb(res);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pads
|
||||||
|
Store.moveToTrash = function (data, cb) {
|
||||||
|
var href = Hash.getRelativeHref(data.href);
|
||||||
|
store.userObject.forget(href);
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
Store.setPadTitle = function (data, cb) {
|
||||||
|
var title = data.title;
|
||||||
|
var href = data.href;
|
||||||
|
var p = Hash.parsePadUrl(href);
|
||||||
|
var h = p.hashData;
|
||||||
|
|
||||||
|
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {};
|
||||||
|
var isStronger;
|
||||||
|
|
||||||
|
// If we don't find the new channel in our existing pads, we'll have to add the pads
|
||||||
|
// to filesData
|
||||||
|
var contains;
|
||||||
|
|
||||||
|
// Update all pads that use the same channel but with a weaker hash
|
||||||
|
// Edit > Edit (present) > View > View (present)
|
||||||
|
for (var id in allPads) {
|
||||||
|
var pad = allPads[id];
|
||||||
|
if (!pad.href) { continue; }
|
||||||
|
|
||||||
|
var p2 = Hash.parsePadUrl(pad.href);
|
||||||
|
var h2 = p2.hashData;
|
||||||
|
|
||||||
|
// Different types, proceed to the next one
|
||||||
|
// No hash data: corrupted pad?
|
||||||
|
if (p.type !== p2.type || !h2) { continue; }
|
||||||
|
|
||||||
|
var shouldUpdate = p.hash.replace(/\/$/, '') === p2.hash.replace(/\/$/, '');
|
||||||
|
|
||||||
|
// If the hash is different but represents the same channel, check if weaker or stronger
|
||||||
|
if (!shouldUpdate &&
|
||||||
|
h.version === 1 && h2.version === 1 &&
|
||||||
|
h.channel === h2.channel) {
|
||||||
|
// We had view & now we have edit, update
|
||||||
|
if (h2.mode === 'view' && h.mode === 'edit') { shouldUpdate = true; }
|
||||||
|
// Same mode and we had present URL, update
|
||||||
|
else if (h.mode === h2.mode && h2.present) { shouldUpdate = true; }
|
||||||
|
// If we're here it means we have a weaker URL:
|
||||||
|
// update the date but keep the existing hash
|
||||||
|
else {
|
||||||
|
pad.atime = +new Date();
|
||||||
|
contains = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldUpdate) {
|
||||||
|
contains = true;
|
||||||
|
pad.atime = +new Date();
|
||||||
|
pad.title = title;
|
||||||
|
|
||||||
|
// If the href is different, it means we have a stronger one
|
||||||
|
if (href !== pad.href) { isStronger = true; }
|
||||||
|
pad.href = href;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStronger) {
|
||||||
|
// If we have a stronger url, remove the possible weaker from the trash.
|
||||||
|
// If all of the weaker ones were in the trash, add the stronger to ROOT
|
||||||
|
store.userObject.restoreHref(href);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the pad if it does not exist in our drive
|
||||||
|
if (!contains) {
|
||||||
|
Store.addPad({
|
||||||
|
href: href,
|
||||||
|
title: title,
|
||||||
|
path: data.path || (store.data && store.data.initialPath)
|
||||||
|
}, cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onSync(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filepicker app
|
||||||
|
Store.getSecureFilesList = function (query, cb) {
|
||||||
|
var list = {};
|
||||||
|
var hashes = [];
|
||||||
|
var types = query.types;
|
||||||
|
var where = query.where;
|
||||||
|
var filter = query.filter || {};
|
||||||
|
var isFiltered = function (type, data) {
|
||||||
|
var filtered;
|
||||||
|
var fType = filter.fileType || [];
|
||||||
|
if (type === 'file' && fType.length) {
|
||||||
|
if (!data.fileType) { return true; }
|
||||||
|
filtered = !fType.some(function (t) {
|
||||||
|
return data.fileType.indexOf(t) === 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
};
|
||||||
|
store.userObject.getFiles(where).forEach(function (id) {
|
||||||
|
var data = store.userObject.getFileData(id);
|
||||||
|
var parsed = Hash.parsePadUrl(data.href);
|
||||||
|
if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) &&
|
||||||
|
hashes.indexOf(parsed.hash) === -1 &&
|
||||||
|
!isFiltered(parsed.type, data)) {
|
||||||
|
hashes.push(parsed.hash);
|
||||||
|
list[id] = data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb(list);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Messaging (manage friends from the userlist)
|
||||||
|
var getMessagingCfg = function () {
|
||||||
|
return {
|
||||||
|
proxy: store.proxy,
|
||||||
|
realtime: store.realtime,
|
||||||
|
network: store.network,
|
||||||
|
updateMetadata: function () {
|
||||||
|
postMessage("UPDATE_METADATA");
|
||||||
|
},
|
||||||
|
pinPads: Store.pinPads,
|
||||||
|
friendComplete: function (data, cb) {
|
||||||
|
postMessage("Q_FRIEND_COMPLETE", data, cb);
|
||||||
|
},
|
||||||
|
friendRequest: function (data) {
|
||||||
|
postMessage("EV_FRIEND_REQUEST", data);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Store.inviteFromUserlist = function (data, cb) {
|
||||||
|
var messagingCfg = getMessagingCfg();
|
||||||
|
Messaging.inviteFromUserlist(messagingCfg, data, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Messenger
|
||||||
|
|
||||||
|
// Get hashes for the share button
|
||||||
|
Store.getStrongerHash = function (data, cb) {
|
||||||
|
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {};
|
||||||
|
|
||||||
|
// If we have a stronger version in drive, add it and add a redirect button
|
||||||
|
var stronger = Hash.findStronger(data.href, allPads);
|
||||||
|
if (stronger) {
|
||||||
|
var parsed2 = Hash.parsePadUrl(stronger);
|
||||||
|
return void cb(parsed2.hash);
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.messenger = {
|
||||||
|
getFriendList: function (data, cb) {
|
||||||
|
store.messenger.getFriendList(function (e, keys) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
data: keys,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getMyInfo: function (data, cb) {
|
||||||
|
store.messenger.getMyInfo(function (e, info) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
data: info,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getFriendInfo: function (data, cb) {
|
||||||
|
store.messenger.getFriendInfo(data, function (e, info) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
data: info,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeFriend: function (data, cb) {
|
||||||
|
store.messenger.removeFriend(data, function (e, info) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
data: info,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openFriendChannel: function (data, cb) {
|
||||||
|
store.messenger.openFriendChannel(data, function (e) {
|
||||||
|
cb({ error: e, });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getFriendStatus: function (data, cb) {
|
||||||
|
store.messenger.getStatus(data, function (e, online) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
data: online,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getMoreHistory: function (data, cb) {
|
||||||
|
store.messenger.getMoreHistory(data.curvePublic, data.sig, data.count, function (e, history) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
data: history,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sendMessage: function (data, cb) {
|
||||||
|
store.messenger.sendMessage(data.curvePublic, data.content, function (e) {
|
||||||
|
cb({
|
||||||
|
error: e,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setChannelHead: function (data, cb) {
|
||||||
|
store.messenger.setChannelHead(data.curvePublic, data.sig, function (e) {
|
||||||
|
cb({
|
||||||
|
error: e
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var onReady = function (returned, cb) {
|
||||||
|
var proxy = store.proxy;
|
||||||
|
var userObject = store.userObject = UserObject.init(proxy.drive, {
|
||||||
|
pinPads: Store.pinPads,
|
||||||
|
loggedIn: store.loggedIn
|
||||||
|
});
|
||||||
|
var todo = function () {
|
||||||
|
userObject.fixFiles();
|
||||||
|
|
||||||
|
Migrate(proxy);
|
||||||
|
|
||||||
|
var requestLogin = function () {
|
||||||
|
postMessage("REQUEST_LOGIN");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (store.loggedIn) {
|
||||||
|
/* This isn't truly secure, since anyone who can read the user's object can
|
||||||
|
set their local loginToken to match that in the object. However, it exposes
|
||||||
|
a UI that will work most of the time. */
|
||||||
|
|
||||||
|
// every user object should have a persistent, random number
|
||||||
|
if (typeof(proxy.loginToken) !== 'number') {
|
||||||
|
proxy[Constants.tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
|
||||||
|
}
|
||||||
|
returned[Constants.tokenKey] = proxy[Constants.tokenKey];
|
||||||
|
|
||||||
|
if (store.data.localToken && store.data.localToken !== proxy[Constants.tokenKey]) {
|
||||||
|
// the local number doesn't match that in
|
||||||
|
// the user object, request that they reauthenticate.
|
||||||
|
return void requestLogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!proxy.settings || !proxy.settings.general ||
|
||||||
|
typeof(proxy.settings.general.allowUserFeedback) !== 'boolean') {
|
||||||
|
proxy.settings = proxy.settings || {};
|
||||||
|
proxy.settings.general = proxy.settings.general || {};
|
||||||
|
proxy.settings.general.allowUserFeedback = true;
|
||||||
|
}
|
||||||
|
returned.feedback = proxy.settings.general.allowUserFeedback;
|
||||||
|
|
||||||
|
if (typeof(cb) === 'function') { cb(returned); }
|
||||||
|
|
||||||
|
if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) {
|
||||||
|
// even anonymous users should have a persistent, unique-ish id
|
||||||
|
console.log('generating a persistent identifier');
|
||||||
|
proxy.uid = Hash.createChannelId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the user is logged in, but does not have signing keys...
|
||||||
|
if (store.loggedIn && (!Store.hasSigningKeys() ||
|
||||||
|
!Store.hasCurveKeys())) {
|
||||||
|
return void requestLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy.on('change', [Constants.displayNameKey], function (o, n) {
|
||||||
|
if (typeof(n) !== "string") { return; }
|
||||||
|
postMessage("UPDATE_METADATA");
|
||||||
|
});
|
||||||
|
proxy.on('change', ['profile'], function () {
|
||||||
|
// Trigger userlist update when the avatar has changed
|
||||||
|
postMessage("UPDATE_METADATA");
|
||||||
|
});
|
||||||
|
proxy.on('change', ['friends'], function () {
|
||||||
|
// Trigger userlist update when the friendlist has changed
|
||||||
|
postMessage("UPDATE_METADATA");
|
||||||
|
});
|
||||||
|
proxy.on('change', ['settings'], function () {
|
||||||
|
postMessage("UPDATE_METADATA");
|
||||||
|
});
|
||||||
|
proxy.on('change', [Constants.tokenKey], function () {
|
||||||
|
postMessage("UPDATE_TOKEN", { token: proxy[Constants.tokenKey] });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
userObject.migrate(todo);
|
||||||
|
};
|
||||||
|
|
||||||
|
var connect = function (data, cb) {
|
||||||
|
var hash = data.userHash || data.anonHash || Hash.createRandomHash();
|
||||||
|
storeHash = hash;
|
||||||
|
if (!hash) {
|
||||||
|
throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...');
|
||||||
|
}
|
||||||
|
var secret = Hash.getSecrets('drive', hash);
|
||||||
|
var listmapConfig = {
|
||||||
|
data: {},
|
||||||
|
websocketURL: NetConfig.getWebsocketURL(),
|
||||||
|
channel: secret.channel,
|
||||||
|
readOnly: false,
|
||||||
|
validateKey: secret.keys.validateKey || undefined,
|
||||||
|
crypto: Crypto.createEncryptor(secret.keys),
|
||||||
|
userName: 'fs',
|
||||||
|
logLevel: 1,
|
||||||
|
ChainPad: ChainPad,
|
||||||
|
classic: true,
|
||||||
|
};
|
||||||
|
var rt = Listmap.create(listmapConfig);
|
||||||
|
store.proxy = rt.proxy;
|
||||||
|
store.loggedIn = typeof(data.userHash) !== "undefined";
|
||||||
|
|
||||||
|
var returned = {};
|
||||||
|
rt.proxy.on('create', function (info) {
|
||||||
|
store.realtime = info.realtime;
|
||||||
|
store.network = info.network;
|
||||||
|
if (!data.userHash) {
|
||||||
|
returned.anonHash = Hash.getEditHashFromKeys(info.channel, secret.keys);
|
||||||
|
}
|
||||||
|
}).on('ready', function () {
|
||||||
|
if (store.userObject) { return; } // the store is already ready, it is a reconnection
|
||||||
|
if (!rt.proxy.drive || typeof(rt.proxy.drive) !== 'object') { rt.proxy.drive = {}; }
|
||||||
|
var drive = rt.proxy.drive;
|
||||||
|
// Creating a new anon drive: import anon pads from localStorage
|
||||||
|
if ((!drive[Constants.oldStorageKey] || !Array.isArray(drive[Constants.oldStorageKey]))
|
||||||
|
&& !drive['filesData']) {
|
||||||
|
drive[Constants.oldStorageKey] = [];
|
||||||
|
}
|
||||||
|
// Drive already exist: return the existing drive, don't load data from legacy store
|
||||||
|
onReady(returned, cb);
|
||||||
|
})
|
||||||
|
.on('change', ['drive', 'migrate'], function () {
|
||||||
|
var path = arguments[2];
|
||||||
|
var value = arguments[1];
|
||||||
|
if (path[0] === 'drive' && path[1] === "migrate" && value === 1) {
|
||||||
|
rt.network.disconnect();
|
||||||
|
rt.realtime.abort();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data:
|
||||||
|
* - userHash or anonHash
|
||||||
|
* Todo in cb
|
||||||
|
* - LocalStore.setFSHash if needed
|
||||||
|
* - sessionStorage.User_Hash
|
||||||
|
* - stuff with tokenKey
|
||||||
|
* Event to outer
|
||||||
|
* - requestLogin
|
||||||
|
*/
|
||||||
|
var initialized = false;
|
||||||
|
Store.init = function (data, callback) {
|
||||||
|
if (initialized) {
|
||||||
|
return void callback({
|
||||||
|
error: 'ALREADY_INIT'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
postMessage = function (cmd, d, cb) {
|
||||||
|
setTimeout(function () {
|
||||||
|
data.query(cmd, d, cb); // TODO temporary, will be replaced by webworker channel
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
store.data = data;
|
||||||
|
connect(data, function (ret) {
|
||||||
|
if (Object.keys(store.proxy).length === 1) {
|
||||||
|
Feedback.send("FIRST_APP_USE", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(ret);
|
||||||
|
|
||||||
|
var messagingCfg = getMessagingCfg();
|
||||||
|
Messaging.addDirectMessageHandler(messagingCfg);
|
||||||
|
|
||||||
|
if (data.messenger) {
|
||||||
|
var messenger = store.messenger = Messenger.messenger(store); // TODO
|
||||||
|
messenger.on('message', function (message) {
|
||||||
|
postMessage('CONTACTS_MESSAGE', message);
|
||||||
|
});
|
||||||
|
messenger.on('join', function (curvePublic, channel) {
|
||||||
|
postMessage('CONTACTS_JOIN', {
|
||||||
|
curvePublic: curvePublic,
|
||||||
|
channel: channel,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
messenger.on('leave', function (curvePublic, channel) {
|
||||||
|
postMessage('CONTACTS_LEAVE', {
|
||||||
|
curvePublic: curvePublic,
|
||||||
|
channel: channel,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
messenger.on('update', function (info, curvePublic) {
|
||||||
|
postMessage('CONTACTS_UPDATE', {
|
||||||
|
curvePublic: curvePublic,
|
||||||
|
info: info,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
messenger.on('friend', function (curvePublic) {
|
||||||
|
postMessage('CONTACTS_FRIEND', {
|
||||||
|
curvePublic: curvePublic,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
messenger.on('unfriend', function (curvePublic) {
|
||||||
|
postMessage('CONTACTS_UNFRIEND', {
|
||||||
|
curvePublic: curvePublic,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.disconnect = function () {
|
||||||
|
if (!store.network) { return; }
|
||||||
|
store.network.disconnect();
|
||||||
|
};
|
||||||
|
return Store;
|
||||||
|
});
|
159
www/common/outer/store-rpc.js
Normal file
159
www/common/outer/store-rpc.js
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
define([
|
||||||
|
'/common/outer/async-store.js'
|
||||||
|
], function (Store) {
|
||||||
|
var Rpc = {};
|
||||||
|
|
||||||
|
Rpc.query = function (cmd, data, cb) {
|
||||||
|
switch (cmd) {
|
||||||
|
// READY
|
||||||
|
case 'CONNECT': {
|
||||||
|
Store.init(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'DISCONNECT': {
|
||||||
|
Store.disconnect(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CREATE_README': {
|
||||||
|
Store.createReadme(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'MIGRATE_ANON_DRIVE': {
|
||||||
|
Store.migrateAnonDrive(data, cb); break;
|
||||||
|
}
|
||||||
|
// RPC
|
||||||
|
case 'INIT_RPC': {
|
||||||
|
Store.initRpc(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'UPDATE_PIN_LIMIT': {
|
||||||
|
Store.updatePinLimit(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_PIN_LIMIT': {
|
||||||
|
Store.getPinLimit(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CLEAR_OWNED_CHANNEL': {
|
||||||
|
Store.clearOwnedChannel(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'UPLOAD_CHUNK': {
|
||||||
|
Store.uploadChunk(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'UPLOAD_COMPLETE': {
|
||||||
|
Store.uploadComplete(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'UPLOAD_STATUS': {
|
||||||
|
Store.uploadStatus(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'UPLOAD_CANCEL': {
|
||||||
|
Store.uploadCancel(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'PIN_PADS': {
|
||||||
|
Store.pinPads(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'UNPIN_PADS': {
|
||||||
|
Store.unpinPads(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_PINNED_USAGE': {
|
||||||
|
Store.getPinnedUsage(data, cb); break;
|
||||||
|
}
|
||||||
|
// ANON RPC
|
||||||
|
case 'INIT_ANON_RPC': {
|
||||||
|
Store.initAnonRpc(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'ANON_RPC_MESSAGE': {
|
||||||
|
Store.anonRpcMsg(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_FILE_SIZE': {
|
||||||
|
Store.getFileSize(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_MULTIPLE_FILE_SIZE': {
|
||||||
|
Store.getMultipleFileSize(data, cb); break;
|
||||||
|
}
|
||||||
|
// Store
|
||||||
|
case 'GET': {
|
||||||
|
Store.get(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'SET': {
|
||||||
|
Store.set(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'ADD_PAD': {
|
||||||
|
Store.addPad(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'SET_PAD_TITLE': {
|
||||||
|
Store.setPadTitle(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'MOVE_TO_TRASH': {
|
||||||
|
Store.moveToTrash(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'RESET_DRIVE': {
|
||||||
|
Store.resetDrive(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_METADATA': {
|
||||||
|
Store.getMetadata(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'SET_DISPLAY_NAME': {
|
||||||
|
Store.setDisplayName(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'SET_PAD_ATTRIBUTE': {
|
||||||
|
Store.setPadAttribute(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_PAD_ATTRIBUTE': {
|
||||||
|
Store.getPadAttribute(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'SET_ATTRIBUTE': {
|
||||||
|
Store.setAttribute(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_ATTRIBUTE': {
|
||||||
|
Store.getAttribute(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'LIST_ALL_TAGS': {
|
||||||
|
Store.listAllTags(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_TEMPLATES': {
|
||||||
|
Store.getTemplates(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_SECURE_FILES_LIST': {
|
||||||
|
Store.getSecureFilesList(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'GET_STRONGER_HASH': {
|
||||||
|
Store.getStrongerHash(data, cb); break;
|
||||||
|
}
|
||||||
|
// Messaging
|
||||||
|
case 'INVITE_FROM_USERLIST': {
|
||||||
|
Store.inviteFromUserlist(data, cb); break;
|
||||||
|
}
|
||||||
|
// Messenger
|
||||||
|
case 'CONTACTS_GET_FRIEND_LIST': {
|
||||||
|
Store.messenger.getFriendList(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_GET_MY_INFO': {
|
||||||
|
Store.messenger.getMyInfo(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_GET_FRIEND_INFO': {
|
||||||
|
Store.messenger.getFriendInfo(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_REMOVE_FRIEND': {
|
||||||
|
Store.messenger.removeFriend(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_OPEN_FRIEND_CHANNEL': {
|
||||||
|
Store.messenger.openFriendChannel(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_GET_FRIEND_STATUS': {
|
||||||
|
Store.messenger.getFriendStatus(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_GET_MORE_HISTORY': {
|
||||||
|
Store.messenger.getMoreHistory(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_SEND_MESSAGE': {
|
||||||
|
Store.messenger.sendMessage(data, cb); break;
|
||||||
|
}
|
||||||
|
case 'CONTACTS_SET_CHANNEL_HEAD': {
|
||||||
|
Store.messenger.setChannelHead(data, cb); break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return Rpc;
|
||||||
|
});
|
||||||
|
|
|
@ -20,7 +20,7 @@ define([
|
||||||
|
|
||||||
var sendChunk = function (box, cb) {
|
var sendChunk = function (box, cb) {
|
||||||
var enc = Nacl.util.encodeBase64(box);
|
var enc = Nacl.util.encodeBase64(box);
|
||||||
common.rpc.send.unauthenticated('UPLOAD', enc, function (e, msg) {
|
common.uploadChunk(enc, function (e, msg) {
|
||||||
cb(e, msg);
|
cb(e, msg);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -58,8 +58,7 @@ define([
|
||||||
|
|
||||||
if (noStore) { return void onComplete(href); }
|
if (noStore) { return void onComplete(href); }
|
||||||
|
|
||||||
common.initialPath = path;
|
common.setPadTitle(title || "", href, path, function (err) {
|
||||||
common.renamePad(title || "", href, function (err) {
|
|
||||||
if (err) { return void console.error(err); }
|
if (err) { return void console.error(err); }
|
||||||
onComplete(href);
|
onComplete(href);
|
||||||
common.setPadAttribute('fileType', metadata.type, null, href);
|
common.setPadAttribute('fileType', metadata.type, null, href);
|
||||||
|
|
|
@ -3,13 +3,13 @@ define([
|
||||||
], function (Rpc) {
|
], function (Rpc) {
|
||||||
var create = function (network, proxy, cb) {
|
var create = function (network, proxy, cb) {
|
||||||
if (!network) {
|
if (!network) {
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
cb('INVALID_NETWORK');
|
cb('INVALID_NETWORK');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!proxy) {
|
if (!proxy) {
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
cb('INVALID_PROXY');
|
cb('INVALID_PROXY');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
var edPublic = proxy.edPublic;
|
var edPublic = proxy.edPublic;
|
||||||
|
|
||||||
if (!(edPrivate && edPublic)) {
|
if (!(edPrivate && edPublic)) {
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
cb('INVALID_KEYS');
|
cb('INVALID_KEYS');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +39,7 @@ define([
|
||||||
// you can ask the server to pin a particular channel for you
|
// you can ask the server to pin a particular channel for you
|
||||||
exp.pin = function (channels, cb) {
|
exp.pin = function (channels, cb) {
|
||||||
if (!Array.isArray(channels)) {
|
if (!Array.isArray(channels)) {
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
cb('[TypeError] pin expects an array');
|
cb('[TypeError] pin expects an array');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -50,7 +50,7 @@ define([
|
||||||
// you can also ask to unpin a particular channel
|
// you can also ask to unpin a particular channel
|
||||||
exp.unpin = function (channels, cb) {
|
exp.unpin = function (channels, cb) {
|
||||||
if (!Array.isArray(channels)) {
|
if (!Array.isArray(channels)) {
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
cb('[TypeError] pin expects an array');
|
cb('[TypeError] pin expects an array');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -71,7 +71,7 @@ define([
|
||||||
// if local and remote hashes don't match, send a reset
|
// if local and remote hashes don't match, send a reset
|
||||||
exp.reset = function (channels, cb) {
|
exp.reset = function (channels, cb) {
|
||||||
if (!Array.isArray(channels)) {
|
if (!Array.isArray(channels)) {
|
||||||
window.setTimeout(function () {
|
setTimeout(function () {
|
||||||
cb('[TypeError] pin expects an array');
|
cb('[TypeError] pin expects an array');
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -163,7 +163,7 @@ define([
|
||||||
|
|
||||||
exp.uploadStatus = function (size, cb) {
|
exp.uploadStatus = function (size, cb) {
|
||||||
if (typeof(size) !== 'number') {
|
if (typeof(size) !== 'number') {
|
||||||
return void window.setTimeout(function () {
|
return void setTimeout(function () {
|
||||||
cb('INVALID_SIZE');
|
cb('INVALID_SIZE');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ types of messages:
|
||||||
|
|
||||||
var send = ctx.send = function (type, msg, cb) {
|
var send = ctx.send = function (type, msg, cb) {
|
||||||
if (!ctx.connected && type !== 'COOKIE') {
|
if (!ctx.connected && type !== 'COOKIE') {
|
||||||
return void window.setTimeout(function () {
|
return void setTimeout(function () {
|
||||||
cb('DISCONNECTED');
|
cb('DISCONNECTED');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ types of messages:
|
||||||
|
|
||||||
send.unauthenticated = function (type, msg, cb) {
|
send.unauthenticated = function (type, msg, cb) {
|
||||||
if (!ctx.connected) {
|
if (!ctx.connected) {
|
||||||
return void window.setTimeout(function () {
|
return void setTimeout(function () {
|
||||||
cb('DISCONNECTED');
|
cb('DISCONNECTED');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ types of messages:
|
||||||
|
|
||||||
var send = ctx.send = function (type, msg, cb) {
|
var send = ctx.send = function (type, msg, cb) {
|
||||||
if (!ctx.connected) {
|
if (!ctx.connected) {
|
||||||
return void window.setTimeout(function () {
|
return void setTimeout(function () {
|
||||||
cb('DISCONNECTED');
|
cb('DISCONNECTED');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -18,7 +18,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + window.location.pathname + 'inner.html?' +
|
ApiConfig.httpSafeOrigin + window.location.pathname + 'inner.html?' +
|
||||||
requireConfig.urlArgs + '#' + encodeURIComponent(JSON.stringify(req)));
|
requireConfig.urlArgs + '#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,9 @@ define([
|
||||||
queue.next();
|
queue.next();
|
||||||
};
|
};
|
||||||
|
|
||||||
var showNamePrompt = true;
|
// Don't show the rename prompt if we don't want to store the file in the drive (avatar)
|
||||||
|
var showNamePrompt = !config.noStore;
|
||||||
|
|
||||||
var promptName = function (file, cb) {
|
var promptName = function (file, cb) {
|
||||||
var extIdx = file.name.lastIndexOf('.');
|
var extIdx = file.name.lastIndexOf('.');
|
||||||
var name = extIdx !== -1 ? file.name.slice(0,extIdx) : file.name;
|
var name = extIdx !== -1 ? file.name.slice(0,extIdx) : file.name;
|
||||||
|
|
|
@ -9,6 +9,7 @@ define([
|
||||||
common.start = function (cfg) {
|
common.start = function (cfg) {
|
||||||
cfg = cfg || {};
|
cfg = cfg || {};
|
||||||
var realtime = !cfg.noRealtime;
|
var realtime = !cfg.noRealtime;
|
||||||
|
var network;
|
||||||
var secret;
|
var secret;
|
||||||
var hashes;
|
var hashes;
|
||||||
var CpNfOuter;
|
var CpNfOuter;
|
||||||
|
@ -18,7 +19,7 @@ define([
|
||||||
var SFrameChannel;
|
var SFrameChannel;
|
||||||
var sframeChan;
|
var sframeChan;
|
||||||
var FilePicker;
|
var FilePicker;
|
||||||
var Messenger;
|
//var Messenger;
|
||||||
var Messaging;
|
var Messaging;
|
||||||
var Notifier;
|
var Notifier;
|
||||||
var Utils = {};
|
var Utils = {};
|
||||||
|
@ -32,7 +33,6 @@ define([
|
||||||
'/common/cryptget.js',
|
'/common/cryptget.js',
|
||||||
'/common/sframe-channel.js',
|
'/common/sframe-channel.js',
|
||||||
'/filepicker/main.js',
|
'/filepicker/main.js',
|
||||||
'/common/common-messenger.js',
|
|
||||||
'/common/common-messaging.js',
|
'/common/common-messaging.js',
|
||||||
'/common/common-notifier.js',
|
'/common/common-notifier.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
|
@ -41,16 +41,17 @@ define([
|
||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
'/common/common-feedback.js',
|
'/common/common-feedback.js',
|
||||||
'/common/outer/local-store.js',
|
'/common/outer/local-store.js',
|
||||||
|
'/common/outer/network-config.js',
|
||||||
|
'/bower_components/netflux-websocket/netflux-client.js',
|
||||||
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel,
|
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel,
|
||||||
_FilePicker, _Messenger, _Messaging, _Notifier, _Hash, _Util, _Realtime,
|
_FilePicker, _Messaging, _Notifier, _Hash, _Util, _Realtime,
|
||||||
_Constants, _Feedback, _LocalStore) {
|
_Constants, _Feedback, _LocalStore, NetConfig, Netflux) {
|
||||||
CpNfOuter = _CpNfOuter;
|
CpNfOuter = _CpNfOuter;
|
||||||
Cryptpad = _Cryptpad;
|
Cryptpad = _Cryptpad;
|
||||||
Crypto = _Crypto;
|
Crypto = _Crypto;
|
||||||
Cryptget = _Cryptget;
|
Cryptget = _Cryptget;
|
||||||
SFrameChannel = _SFrameChannel;
|
SFrameChannel = _SFrameChannel;
|
||||||
FilePicker = _FilePicker;
|
FilePicker = _FilePicker;
|
||||||
Messenger = _Messenger;
|
|
||||||
Messaging = _Messaging;
|
Messaging = _Messaging;
|
||||||
Notifier = _Notifier;
|
Notifier = _Notifier;
|
||||||
Utils.Hash = _Hash;
|
Utils.Hash = _Hash;
|
||||||
|
@ -84,7 +85,15 @@ define([
|
||||||
SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) {
|
SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) {
|
||||||
sframeChan = sfc;
|
sframeChan = sfc;
|
||||||
}), false, { cache: cache, localStore: localStore, language: Cryptpad.getLanguage() });
|
}), false, { cache: cache, localStore: localStore, language: Cryptpad.getLanguage() });
|
||||||
Cryptpad.ready(waitFor());
|
Cryptpad.ready(waitFor(), {
|
||||||
|
messenger: cfg.messaging
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!cfg.newNetwork) {
|
||||||
|
Netflux.connect(NetConfig.getWebsocketURL()).then(waitFor(function (nw) {
|
||||||
|
network = nw;
|
||||||
|
}));
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
$('#sbox-iframe').focus();
|
$('#sbox-iframe').focus();
|
||||||
|
@ -104,12 +113,23 @@ define([
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
secret = cfg.getSecrets ? cfg.getSecrets(Cryptpad, Utils) : Utils.Hash.getSecrets();
|
if (cfg.getSecrets) {
|
||||||
|
var w = waitFor();
|
||||||
|
cfg.getSecrets(Cryptpad, Utils, waitFor(function (err, s) {
|
||||||
|
secret = s;
|
||||||
|
Cryptpad.getShareHashes(secret, function (err, h) {
|
||||||
|
hashes = h;
|
||||||
|
w();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
secret = Utils.Hash.getSecrets();
|
||||||
if (!secret.channel) {
|
if (!secret.channel) {
|
||||||
// New pad: create a new random channel id
|
// New pad: create a new random channel id
|
||||||
secret.channel = Utils.Hash.createChannelId();
|
secret.channel = Utils.Hash.createChannelId();
|
||||||
}
|
}
|
||||||
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
|
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
|
||||||
|
}
|
||||||
|
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
var readOnly = secret.keys && !secret.keys.editKeyStr;
|
var readOnly = secret.keys && !secret.keys.editKeyStr;
|
||||||
|
@ -117,59 +137,50 @@ define([
|
||||||
var parsed = Utils.Hash.parsePadUrl(window.location.href);
|
var parsed = Utils.Hash.parsePadUrl(window.location.href);
|
||||||
if (!parsed.type) { throw new Error(); }
|
if (!parsed.type) { throw new Error(); }
|
||||||
var defaultTitle = Utils.Hash.getDefaultName(parsed);
|
var defaultTitle = Utils.Hash.getDefaultName(parsed);
|
||||||
var proxy = Cryptpad.getProxy();
|
|
||||||
var updateMeta = function () {
|
var updateMeta = function () {
|
||||||
//console.log('EV_METADATA_UPDATE');
|
//console.log('EV_METADATA_UPDATE');
|
||||||
var name;
|
var metaObj, isTemplate;
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
Cryptpad.getLastName(waitFor(function (err, n) {
|
Cryptpad.getMetadata(waitFor(function (err, m) {
|
||||||
if (err) { console.log(err); }
|
if (err) { console.log(err); }
|
||||||
name = n;
|
metaObj = m;
|
||||||
|
}));
|
||||||
|
Cryptpad.isTemplate(window.location.href, waitFor(function (err, t) {
|
||||||
|
if (err) { console.log(err); }
|
||||||
|
isTemplate = t;
|
||||||
}));
|
}));
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
var metaObj = {
|
metaObj.doc = {
|
||||||
doc: {
|
|
||||||
defaultTitle: defaultTitle,
|
defaultTitle: defaultTitle,
|
||||||
type: parsed.type
|
type: parsed.type
|
||||||
},
|
};
|
||||||
user: {
|
var additionalPriv = {
|
||||||
name: name,
|
|
||||||
uid: Cryptpad.getUid(),
|
|
||||||
avatar: Cryptpad.getAvatarUrl(),
|
|
||||||
profile: Cryptpad.getProfileUrl(),
|
|
||||||
curvePublic: proxy.curvePublic,
|
|
||||||
netfluxId: Cryptpad.getNetwork().webChannels[0].myID,
|
|
||||||
},
|
|
||||||
priv: {
|
|
||||||
edPublic: proxy.edPublic,
|
|
||||||
accountName: Utils.LocalStore.getAccountName(),
|
accountName: Utils.LocalStore.getAccountName(),
|
||||||
origin: window.location.origin,
|
origin: window.location.origin,
|
||||||
pathname: window.location.pathname,
|
pathname: window.location.pathname,
|
||||||
fileHost: ApiConfig.fileHost,
|
fileHost: ApiConfig.fileHost,
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
availableHashes: hashes,
|
availableHashes: hashes,
|
||||||
isTemplate: Cryptpad.isTemplate(window.location.href),
|
isTemplate: isTemplate,
|
||||||
feedbackAllowed: Utils.Feedback.state,
|
feedbackAllowed: Utils.Feedback.state,
|
||||||
friends: proxy.friends || {},
|
|
||||||
settings: proxy.settings || {},
|
|
||||||
isPresent: parsed.hashData && parsed.hashData.present,
|
isPresent: parsed.hashData && parsed.hashData.present,
|
||||||
isEmbed: parsed.hashData && parsed.hashData.embed,
|
isEmbed: parsed.hashData && parsed.hashData.embed,
|
||||||
thumbnails: !((proxy.settings || {}).general || {}).disableThumbnails,
|
|
||||||
accounts: {
|
accounts: {
|
||||||
donateURL: Cryptpad.donateURL,
|
donateURL: Cryptpad.donateURL,
|
||||||
upgradeURL: Cryptpad.upgradeURL
|
upgradeURL: Cryptpad.upgradeURL
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
|
||||||
|
|
||||||
if (cfg.addData) {
|
if (cfg.addData) {
|
||||||
cfg.addData(metaObj.priv, Cryptpad);
|
cfg.addData(metaObj.priv, Cryptpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
sframeChan.event('EV_METADATA_UPDATE', metaObj);
|
sframeChan.event('EV_METADATA_UPDATE', metaObj);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Cryptpad.onDisplayNameChanged(updateMeta);
|
Cryptpad.onMetadataChanged(updateMeta);
|
||||||
sframeChan.onReg('EV_METADATA_UPDATE', updateMeta);
|
sframeChan.onReg('EV_METADATA_UPDATE', updateMeta);
|
||||||
proxy.on('change', 'settings', updateMeta);
|
|
||||||
|
|
||||||
Utils.LocalStore.onLogout(function () {
|
Utils.LocalStore.onLogout(function () {
|
||||||
sframeChan.event('EV_LOGOUT');
|
sframeChan.event('EV_LOGOUT');
|
||||||
|
@ -223,7 +234,7 @@ define([
|
||||||
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newTitle, cb) {
|
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newTitle, cb) {
|
||||||
currentTitle = newTitle;
|
currentTitle = newTitle;
|
||||||
setDocumentTitle();
|
setDocumentTitle();
|
||||||
Cryptpad.renamePad(newTitle, undefined, function (err) {
|
Cryptpad.setPadTitle(newTitle, undefined, undefined, function (err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -241,7 +252,7 @@ define([
|
||||||
cb('ERROR');
|
cb('ERROR');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Cryptpad.changeDisplayName(newName, true);
|
Cryptpad.changeMetadata();
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -287,7 +298,6 @@ define([
|
||||||
};
|
};
|
||||||
|
|
||||||
sframeChan.on('Q_GET_FULL_HISTORY', function (data, cb) {
|
sframeChan.on('Q_GET_FULL_HISTORY', function (data, cb) {
|
||||||
var network = Cryptpad.getNetwork();
|
|
||||||
var hkn = network.historyKeeper;
|
var hkn = network.historyKeeper;
|
||||||
var crypto = Crypto.createEncryptor(secret.keys);
|
var crypto = Crypto.createEncryptor(secret.keys);
|
||||||
// Get the history messages and send them to the iframe
|
// Get the history messages and send them to the iframe
|
||||||
|
@ -445,8 +455,9 @@ define([
|
||||||
Cryptpad.useTemplate(href, Cryptget, cb);
|
Cryptpad.useTemplate(href, Cryptget, cb);
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_TEMPLATE_EXIST', function (type, cb) {
|
sframeChan.on('Q_TEMPLATE_EXIST', function (type, cb) {
|
||||||
var hasTemplate = Cryptpad.listTemplates(type).length > 0;
|
Cryptpad.listTemplates(type, function (err, templates) {
|
||||||
cb(hasTemplate);
|
cb(templates.length > 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
sframeChan.on('EV_GOTO_URL', function (url) {
|
sframeChan.on('EV_GOTO_URL', function (url) {
|
||||||
|
@ -494,117 +505,58 @@ define([
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg.messaging) {
|
if (cfg.messaging) {
|
||||||
var messenger = Messenger.messenger(Cryptpad);
|
|
||||||
|
|
||||||
sframeChan.on('Q_CONTACTS_GET_FRIEND_LIST', function (data, cb) {
|
sframeChan.on('Q_CONTACTS_GET_FRIEND_LIST', function (data, cb) {
|
||||||
messenger.getFriendList(function (e, keys) {
|
Cryptpad.messenger.getFriendList(cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
data: keys,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_CONTACTS_GET_MY_INFO', function (data, cb) {
|
sframeChan.on('Q_CONTACTS_GET_MY_INFO', function (data, cb) {
|
||||||
messenger.getMyInfo(function (e, info) {
|
Cryptpad.messenger.getMyInfo(cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
data: info,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_CONTACTS_GET_FRIEND_INFO', function (curvePublic, cb) {
|
sframeChan.on('Q_CONTACTS_GET_FRIEND_INFO', function (curvePublic, cb) {
|
||||||
messenger.getFriendInfo(curvePublic, function (e, info) {
|
Cryptpad.messenger.getFriendInfo(curvePublic, cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
data: info,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_CONTACTS_REMOVE_FRIEND', function (curvePublic, cb) {
|
sframeChan.on('Q_CONTACTS_REMOVE_FRIEND', function (curvePublic, cb) {
|
||||||
messenger.removeFriend(curvePublic, function (e, info) {
|
Cryptpad.messenger.removeFriend(curvePublic, cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
data: info,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_CONTACTS_OPEN_FRIEND_CHANNEL', function (curvePublic, cb) {
|
sframeChan.on('Q_CONTACTS_OPEN_FRIEND_CHANNEL', function (curvePublic, cb) {
|
||||||
messenger.openFriendChannel(curvePublic, function (e) {
|
Cryptpad.messenger.openFriendChannel(curvePublic, cb);
|
||||||
cb({ error: e, });
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_CONTACTS_GET_STATUS', function (curvePublic, cb) {
|
sframeChan.on('Q_CONTACTS_GET_STATUS', function (curvePublic, cb) {
|
||||||
messenger.getStatus(curvePublic, function (e, online) {
|
Cryptpad.messenger.getFriendStatus(curvePublic, cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
data: online,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_CONTACTS_GET_MORE_HISTORY', function (opt, cb) {
|
sframeChan.on('Q_CONTACTS_GET_MORE_HISTORY', function (opt, cb) {
|
||||||
messenger.getMoreHistory(opt.curvePublic, opt.sig, opt.count, function (e, history) {
|
Cryptpad.messenger.getMoreHistory(opt, cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
data: history,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_CONTACTS_SEND_MESSAGE', function (opt, cb) {
|
sframeChan.on('Q_CONTACTS_SEND_MESSAGE', function (opt, cb) {
|
||||||
messenger.sendMessage(opt.curvePublic, opt.content, function (e) {
|
Cryptpad.messenger.sendMessage(opt, cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_CONTACTS_SET_CHANNEL_HEAD', function (opt, cb) {
|
sframeChan.on('Q_CONTACTS_SET_CHANNEL_HEAD', function (opt, cb) {
|
||||||
messenger.setChannelHead(opt.curvePublic, opt.sig, function (e) {
|
Cryptpad.messenger.setChannelHead(opt, cb);
|
||||||
cb({
|
|
||||||
error: e
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_CONTACTS_CLEAR_OWNED_CHANNEL', function (channel, cb) {
|
sframeChan.on('Q_CONTACTS_CLEAR_OWNED_CHANNEL', function (channel, cb) {
|
||||||
messenger.clearOwnedChannel(channel, function (e) {
|
Cryptpad.clearOwnedChannel(channel, cb);
|
||||||
cb({
|
|
||||||
error: e,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
messenger.on('message', function (message) {
|
Cryptpad.messenger.onMessageEvent.reg(function (data) {
|
||||||
sframeChan.event('EV_CONTACTS_MESSAGE', message);
|
sframeChan.event('EV_CONTACTS_MESSAGE', data);
|
||||||
});
|
});
|
||||||
messenger.on('join', function (curvePublic, channel) {
|
Cryptpad.messenger.onJoinEvent.reg(function (data) {
|
||||||
sframeChan.event('EV_CONTACTS_JOIN', {
|
sframeChan.event('EV_CONTACTS_JOIN', data);
|
||||||
curvePublic: curvePublic,
|
|
||||||
channel: channel,
|
|
||||||
});
|
});
|
||||||
|
Cryptpad.messenger.onLeaveEvent.reg(function (data) {
|
||||||
|
sframeChan.event('EV_CONTACTS_LEAVE', data);
|
||||||
});
|
});
|
||||||
messenger.on('leave', function (curvePublic, channel) {
|
Cryptpad.messenger.onUpdateEvent.reg(function (data) {
|
||||||
sframeChan.event('EV_CONTACTS_LEAVE', {
|
sframeChan.event('EV_CONTACTS_UPDATE', data);
|
||||||
curvePublic: curvePublic,
|
|
||||||
channel: channel,
|
|
||||||
});
|
});
|
||||||
|
Cryptpad.messenger.onFriendEvent.reg(function (data) {
|
||||||
|
sframeChan.event('EV_CONTACTS_FRIEND', data);
|
||||||
});
|
});
|
||||||
messenger.on('update', function (info, curvePublic) {
|
Cryptpad.messenger.onUnfriendEvent.reg(function (data) {
|
||||||
sframeChan.event('EV_CONTACTS_UPDATE', {
|
sframeChan.event('EV_CONTACTS_UNFRIEND', data);
|
||||||
curvePublic: curvePublic,
|
|
||||||
info: info,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
messenger.on('friend', function (curvePublic) {
|
|
||||||
sframeChan.event('EV_CONTACTS_FRIEND', {
|
|
||||||
curvePublic: curvePublic,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
messenger.on('unfriend', function (curvePublic) {
|
|
||||||
sframeChan.event('EV_CONTACTS_UNFRIEND', {
|
|
||||||
curvePublic: curvePublic,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +581,7 @@ define([
|
||||||
CpNfOuter.start({
|
CpNfOuter.start({
|
||||||
sframeChan: sframeChan,
|
sframeChan: sframeChan,
|
||||||
channel: secret.channel,
|
channel: secret.channel,
|
||||||
network: cfg.newNetwork || Cryptpad.getNetwork(),
|
network: cfg.newNetwork || network,
|
||||||
validateKey: secret.keys.validateKey || undefined,
|
validateKey: secret.keys.validateKey || undefined,
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
crypto: Crypto.createEncryptor(secret.keys),
|
crypto: Crypto.createEncryptor(secret.keys),
|
||||||
|
|
|
@ -328,7 +328,7 @@ define([
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
SFrameChannel.create(window.parent, waitFor(function (sfc) { ctx.sframeChan = sfc; }), true);
|
SFrameChannel.create(window.parent, waitFor(function (sfc) { ctx.sframeChan = sfc; }), true);
|
||||||
// CpNfInner.start() should be here....
|
// CpNfInner.start() should be here....
|
||||||
}).nThen(function () {
|
}).nThen(function (waitFor) {
|
||||||
localForage.clear();
|
localForage.clear();
|
||||||
|
|
||||||
ctx.metadataMgr = MetadataMgr.create(ctx.sframeChan);
|
ctx.metadataMgr = MetadataMgr.create(ctx.sframeChan);
|
||||||
|
@ -373,10 +373,6 @@ define([
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.sframeChan.on('EV_RT_CONNECT', function () { CommonRealtime.setConnectionState(true); });
|
|
||||||
ctx.sframeChan.on('EV_RT_DISCONNECT', function () { CommonRealtime.setConnectionState(false); });
|
|
||||||
|
|
||||||
|
|
||||||
ctx.sframeChan.on('Q_INCOMING_FRIEND_REQUEST', function (confirmMsg, cb) {
|
ctx.sframeChan.on('Q_INCOMING_FRIEND_REQUEST', function (confirmMsg, cb) {
|
||||||
UI.confirm(confirmMsg, cb, null, true);
|
UI.confirm(confirmMsg, cb, null, true);
|
||||||
});
|
});
|
||||||
|
@ -393,6 +389,8 @@ define([
|
||||||
} catch (e) { Feedback.init(false); }
|
} catch (e) { Feedback.init(false); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ctx.metadataMgr.onReady(waitFor());
|
||||||
|
}).nThen(function () {
|
||||||
ctx.sframeChan.ready();
|
ctx.sframeChan.ready();
|
||||||
cb(funcs);
|
cb(funcs);
|
||||||
});
|
});
|
||||||
|
|
|
@ -767,7 +767,7 @@ define([
|
||||||
var origin = privateData.origin;
|
var origin = privateData.origin;
|
||||||
var pathname = privateData.pathname;
|
var pathname = privateData.pathname;
|
||||||
var href = inDrive.test(pathname) ? origin+'/index.html' : origin+'/drive/';
|
var href = inDrive.test(pathname) ? origin+'/index.html' : origin+'/drive/';
|
||||||
var buttonTitle = inDrive ? Messages.header_homeTitle : Messages.header_logoTitle;
|
var buttonTitle = inDrive.test(pathname) ? Messages.header_homeTitle : Messages.header_logoTitle;
|
||||||
|
|
||||||
var $aTag = $('<a>', {
|
var $aTag = $('<a>', {
|
||||||
href: href,
|
href: href,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
define([
|
define([
|
||||||
'jquery',
|
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/common-hash.js',
|
'/common/common-hash.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
'/customize/messages.js'
|
'/customize/messages.js'
|
||||||
], function ($, AppConfig, Util, Hash, Realtime, Constants, Messages) {
|
], function (AppConfig, Util, Hash, Realtime, Constants, Messages) {
|
||||||
var module = {};
|
var module = {};
|
||||||
|
|
||||||
var ROOT = module.ROOT = "root";
|
var ROOT = module.ROOT = "root";
|
||||||
|
@ -21,13 +20,13 @@ define([
|
||||||
|
|
||||||
module.init = function (files, config) {
|
module.init = function (files, config) {
|
||||||
var exp = {};
|
var exp = {};
|
||||||
var Cryptpad = config.Cryptpad;
|
var pinPads = config.pinPads;
|
||||||
var loggedIn = config.loggedIn;
|
var loggedIn = config.loggedIn;
|
||||||
|
|
||||||
var FILES_DATA = module.FILES_DATA = exp.FILES_DATA = Constants.storageKey;
|
var FILES_DATA = module.FILES_DATA = exp.FILES_DATA = Constants.storageKey;
|
||||||
var OLD_FILES_DATA = module.OLD_FILES_DATA = exp.OLD_FILES_DATA = Constants.oldStorageKey;
|
var OLD_FILES_DATA = module.OLD_FILES_DATA = exp.OLD_FILES_DATA = Constants.oldStorageKey;
|
||||||
var NEW_FOLDER_NAME = Messages.fm_newFolder;
|
var NEW_FOLDER_NAME = Messages.fm_newFolder || 'New folder';
|
||||||
var NEW_FILE_NAME = Messages.fm_newFile;
|
var NEW_FILE_NAME = Messages.fm_newFile || 'New file';
|
||||||
|
|
||||||
exp.ROOT = ROOT;
|
exp.ROOT = ROOT;
|
||||||
exp.UNSORTED = UNSORTED;
|
exp.UNSORTED = UNSORTED;
|
||||||
|
@ -101,7 +100,7 @@ define([
|
||||||
};
|
};
|
||||||
for (var f in element) {
|
for (var f in element) {
|
||||||
if (trashRoot) {
|
if (trashRoot) {
|
||||||
if ($.isArray(element[f])) {
|
if (Array.isArray(element[f])) {
|
||||||
element[f].forEach(addSubfolder);
|
element[f].forEach(addSubfolder);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,7 +118,7 @@ define([
|
||||||
};
|
};
|
||||||
for (var f in element) {
|
for (var f in element) {
|
||||||
if (trashRoot) {
|
if (trashRoot) {
|
||||||
if ($.isArray(element[f])) {
|
if (Array.isArray(element[f])) {
|
||||||
element[f].forEach(addFile);
|
element[f].forEach(addFile);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,14 +147,14 @@ define([
|
||||||
return data.filename || data.title || NEW_FILE_NAME;
|
return data.filename || data.title || NEW_FILE_NAME;
|
||||||
};
|
};
|
||||||
exp.getPadAttribute = function (href, attr, cb) {
|
exp.getPadAttribute = function (href, attr, cb) {
|
||||||
cb = cb || $.noop;
|
cb = cb || function () {};
|
||||||
var id = exp.getIdFromHref(href);
|
var id = exp.getIdFromHref(href);
|
||||||
if (!id) { return void cb(null, undefined); }
|
if (!id) { return void cb(null, undefined); }
|
||||||
var data = getFileData(id);
|
var data = getFileData(id);
|
||||||
cb(null, clone(data[attr]));
|
cb(null, clone(data[attr]));
|
||||||
};
|
};
|
||||||
exp.setPadAttribute = function (href, attr, value, cb) {
|
exp.setPadAttribute = function (href, attr, value, cb) {
|
||||||
cb = cb || $.noop;
|
cb = cb || function () {};
|
||||||
var id = exp.getIdFromHref(href);
|
var id = exp.getIdFromHref(href);
|
||||||
if (!id) { return void cb("E_INVAL_HREF"); }
|
if (!id) { return void cb("E_INVAL_HREF"); }
|
||||||
if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); }
|
if (!attr || !attr.trim()) { return void cb("E_INVAL_ATTR"); }
|
||||||
|
@ -167,7 +166,7 @@ define([
|
||||||
// PATHS
|
// PATHS
|
||||||
|
|
||||||
var comparePath = exp.comparePath = function (a, b) {
|
var comparePath = exp.comparePath = function (a, b) {
|
||||||
if (!a || !b || !$.isArray(a) || !$.isArray(b)) { return false; }
|
if (!a || !b || !Array.isArray(a) || !Array.isArray(b)) { return false; }
|
||||||
if (a.length !== b.length) { return false; }
|
if (a.length !== b.length) { return false; }
|
||||||
var result = true;
|
var result = true;
|
||||||
var i = a.length - 1;
|
var i = a.length - 1;
|
||||||
|
@ -265,7 +264,7 @@ define([
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (var e in root) {
|
for (var e in root) {
|
||||||
if (!$.isArray(root[e])) {
|
if (!Array.isArray(root[e])) {
|
||||||
error("Trash contains a non-array element");
|
error("Trash contains a non-array element");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -487,8 +486,6 @@ define([
|
||||||
|
|
||||||
// FILES DATA
|
// FILES DATA
|
||||||
exp.pushData = function (data, cb) {
|
exp.pushData = function (data, cb) {
|
||||||
// TODO: can only be called from outside atm
|
|
||||||
if (!Cryptpad) { return; }
|
|
||||||
if (typeof cb !== "function") { cb = function () {}; }
|
if (typeof cb !== "function") { cb = function () {}; }
|
||||||
var todo = function () {
|
var todo = function () {
|
||||||
var id = Util.createRandomInteger();
|
var id = Util.createRandomInteger();
|
||||||
|
@ -498,8 +495,9 @@ define([
|
||||||
if (!loggedIn || !AppConfig.enablePinning || config.testMode) {
|
if (!loggedIn || !AppConfig.enablePinning || config.testMode) {
|
||||||
return void todo();
|
return void todo();
|
||||||
}
|
}
|
||||||
Cryptpad.pinPads([Hash.hrefToHexChannelId(data.href)], function (e) {
|
if (!pinPads) { return; }
|
||||||
if (e) { return void cb(e); }
|
pinPads([Hash.hrefToHexChannelId(data.href)], function (obj) {
|
||||||
|
if (obj && obj.error) { return void cb(obj.error); }
|
||||||
todo();
|
todo();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -968,7 +966,7 @@ define([
|
||||||
var addToClean = function (obj, idx, el) {
|
var addToClean = function (obj, idx, el) {
|
||||||
if (typeof(obj) !== "object") { toClean.push(idx); return; }
|
if (typeof(obj) !== "object") { toClean.push(idx); return; }
|
||||||
if (!isFile(obj.element, true) && !isFolder(obj.element)) { toClean.push(idx); return; }
|
if (!isFile(obj.element, true) && !isFolder(obj.element)) { toClean.push(idx); return; }
|
||||||
if (!$.isArray(obj.path)) { toClean.push(idx); return; }
|
if (!Array.isArray(obj.path)) { toClean.push(idx); return; }
|
||||||
if (typeof obj.element === "string") {
|
if (typeof obj.element === "string") {
|
||||||
// We have an old file (href) which is not in filesData: add it
|
// We have an old file (href) which is not in filesData: add it
|
||||||
var id = Util.createRandomInteger();
|
var id = Util.createRandomInteger();
|
||||||
|
|
94
www/common/wire.js
Normal file
94
www/common/wire.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
define([
|
||||||
|
|
||||||
|
], function () {
|
||||||
|
var Wire = {};
|
||||||
|
|
||||||
|
/* MISSION: write a generic RPC framework
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
|
||||||
|
* some transmission methods can be interrupted
|
||||||
|
* handle disconnects and reconnects
|
||||||
|
* handle callbacks
|
||||||
|
* configurable timeout
|
||||||
|
* Service should expose 'addClient' method
|
||||||
|
* and handle broadcast
|
||||||
|
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var uid = function () {
|
||||||
|
return Number(Math.floor(Math.random () *
|
||||||
|
Number.MAX_SAFE_INTEGER)).toString(32);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
opt = {
|
||||||
|
send: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
receive: function () {
|
||||||
|
|
||||||
|
},
|
||||||
|
constructor: function (cb) {
|
||||||
|
cb(void 0 , {
|
||||||
|
send: function (content, cb) {
|
||||||
|
|
||||||
|
},
|
||||||
|
receive: function () {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
Wire.create = function (opt, cb) {
|
||||||
|
var ctx = {};
|
||||||
|
var pending = ctx.pending = {};
|
||||||
|
ctx.connected = false;
|
||||||
|
|
||||||
|
var rpc = {};
|
||||||
|
|
||||||
|
opt.constructor(function (e, service) {
|
||||||
|
if (e) { return setTimeout(function () { cb(e); }); }
|
||||||
|
|
||||||
|
rpc.send = function (type, data, cb) {
|
||||||
|
var txid = uid();
|
||||||
|
if (typeof(cb) !== 'function') {
|
||||||
|
throw new Error('expected callback');
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.pending[txid] = function (err, response) {
|
||||||
|
cb(err, response);
|
||||||
|
};
|
||||||
|
|
||||||
|
service.send(JSON.stringify({
|
||||||
|
txid: txid,
|
||||||
|
message: {
|
||||||
|
command: type,
|
||||||
|
content: data,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
service.receive(function (raw) {
|
||||||
|
try {
|
||||||
|
var data = JSON.parse(raw);
|
||||||
|
var txid = data.txid;
|
||||||
|
if (!txid) { throw new Error('NO_TXID'); }
|
||||||
|
var cb = pending[txid];
|
||||||
|
if (data.error) { return void cb(data.error); }
|
||||||
|
cb(void 0, data.content);
|
||||||
|
} catch (e) { console.error("UNHANDLED_MESSAGE", raw); }
|
||||||
|
});
|
||||||
|
|
||||||
|
cb(void 0, rpc);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return Wire;
|
||||||
|
});
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/contacts/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/contacts/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
define([
|
define([
|
||||||
'jquery',
|
'jquery',
|
||||||
'/bower_components/chainpad-crypto/crypto.js',
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
'/bower_components/textpatcher/TextPatcher.js',
|
|
||||||
'/common/toolbar3.js',
|
'/common/toolbar3.js',
|
||||||
'json.sortify',
|
'json.sortify',
|
||||||
'/bower_components/chainpad-json-validator/json-ot.js',
|
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/common/sframe-common.js',
|
'/common/sframe-common.js',
|
||||||
|
@ -22,10 +20,8 @@ define([
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
Crypto,
|
Crypto,
|
||||||
TextPatcher,
|
|
||||||
Toolbar,
|
Toolbar,
|
||||||
JSONSortify,
|
JSONSortify,
|
||||||
JsonOT,
|
|
||||||
Util,
|
Util,
|
||||||
nThen,
|
nThen,
|
||||||
SFCommon,
|
SFCommon,
|
||||||
|
@ -61,7 +57,6 @@ define([
|
||||||
|
|
||||||
var config = APP.config = {
|
var config = APP.config = {
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
transformFunction: JsonOT.validate,
|
|
||||||
// cryptpad debug logging (default is 1)
|
// cryptpad debug logging (default is 1)
|
||||||
// logLevel: 0,
|
// logLevel: 0,
|
||||||
validateContent: function (content) {
|
validateContent: function (content) {
|
||||||
|
@ -123,11 +118,7 @@ define([
|
||||||
|
|
||||||
config.onReady = function (info) {
|
config.onReady = function (info) {
|
||||||
if (APP.realtime !== info.realtime) {
|
if (APP.realtime !== info.realtime) {
|
||||||
var realtime = APP.realtime = info.realtime;
|
APP.realtime = info.realtime;
|
||||||
APP.patchText = TextPatcher.create({
|
|
||||||
realtime: realtime,
|
|
||||||
//logging: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var userDoc = APP.realtime.getUserDoc();
|
var userDoc = APP.realtime.getUserDoc();
|
||||||
|
|
|
@ -2,17 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js',
|
'/common/sframe-common-outer.js',
|
||||||
'/common/outer/network-config.js',
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
'/bower_components/netflux-websocket/netflux-client.js',
|
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO, NetConfig, Netflux) {
|
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -21,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/drive/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/drive/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
@ -38,10 +36,10 @@ define([
|
||||||
};
|
};
|
||||||
window.addEventListener('message', onMsg);
|
window.addEventListener('message', onMsg);
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
var getSecrets = function (Cryptpad, Utils) {
|
var getSecrets = function (Cryptpad, Utils, cb) {
|
||||||
var hash = window.location.hash.slice(1) || Utils.LocalStore.getUserHash() ||
|
var hash = window.location.hash.slice(1) || Utils.LocalStore.getUserHash() ||
|
||||||
Utils.LocalStore.getFSHash();
|
Utils.LocalStore.getFSHash();
|
||||||
return Utils.Hash.getSecrets('drive', hash);
|
cb(null, Utils.Hash.getSecrets('drive', hash));
|
||||||
};
|
};
|
||||||
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
||||||
sframeChan.on('EV_BURN_ANON_DRIVE', function () {
|
sframeChan.on('EV_BURN_ANON_DRIVE', function () {
|
||||||
|
@ -51,13 +49,13 @@ define([
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Netflux.connect(NetConfig.getWebsocketURL()).then(function (network) {
|
//Netflux.connect(NetConfig.getWebsocketURL()).then(function (network) {
|
||||||
SFCommonO.start({
|
SFCommonO.start({
|
||||||
getSecrets: getSecrets,
|
getSecrets: getSecrets,
|
||||||
newNetwork: network,
|
//newNetwork: network,
|
||||||
noHash: true,
|
noHash: true,
|
||||||
addRpc: addRpc
|
addRpc: addRpc
|
||||||
});
|
});
|
||||||
}, function (err) { console.error(err); });
|
//}, function (err) { console.error(err); });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,7 +70,7 @@ define([
|
||||||
|
|
||||||
module.test = function (assert) {
|
module.test = function (assert) {
|
||||||
var config = {
|
var config = {
|
||||||
Cryptpad: Cryptpad,
|
pinPads: Cryptpad.pinPads,
|
||||||
workgroup: false,
|
workgroup: false,
|
||||||
testMode: true,
|
testMode: true,
|
||||||
loggedIn: false
|
loggedIn: false
|
||||||
|
@ -325,7 +325,12 @@ define([
|
||||||
var fo = FO.init(files, config);
|
var fo = FO.init(files, config);
|
||||||
fo.fixFiles();
|
fo.fixFiles();
|
||||||
|
|
||||||
var data = Cryptpad.makePad(href5, 'Title5');
|
var data = {
|
||||||
|
href: href5,
|
||||||
|
title: 'Title5',
|
||||||
|
atime: +new Date(),
|
||||||
|
ctime: +new Date()
|
||||||
|
};
|
||||||
var res;
|
var res;
|
||||||
var id5;
|
var id5;
|
||||||
// pushData is synchronous in test mode (no pinning)
|
// pushData is synchronous in test mode (no pinning)
|
||||||
|
|
|
@ -120,7 +120,6 @@ define([
|
||||||
decrypted.callback();
|
decrypted.callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(decrypted);
|
|
||||||
$dlview.show();
|
$dlview.show();
|
||||||
$dlform.hide();
|
$dlform.hide();
|
||||||
var $dlButton = $dlview.find('media-tag button');
|
var $dlButton = $dlview.find('media-tag button');
|
||||||
|
@ -174,7 +173,6 @@ define([
|
||||||
var progress = e.originalEvent;
|
var progress = e.originalEvent;
|
||||||
var p = progress.percent +'%';
|
var p = progress.percent +'%';
|
||||||
$progress.width(p);
|
$progress.width(p);
|
||||||
console.log(progress.percent);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/file/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/file/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
|
|
@ -46,41 +46,30 @@ define([
|
||||||
sframeChan = sfc;
|
sframeChan = sfc;
|
||||||
}));
|
}));
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
var proxy = Cryptpad.getProxy();
|
|
||||||
var updateMeta = function () {
|
var updateMeta = function () {
|
||||||
//console.log('EV_METADATA_UPDATE');
|
//console.log('EV_METADATA_UPDATE');
|
||||||
var name;
|
var metaObj;
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
Cryptpad.getLastName(waitFor(function (err, n) {
|
Cryptpad.getMetadata(waitFor(function (err, n) {
|
||||||
if (err) { console.log(err); }
|
if (err) { console.log(err); }
|
||||||
name = n;
|
metaObj = n;
|
||||||
}));
|
}));
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
sframeChan.event('EV_METADATA_UPDATE', {
|
metaObj.doc = {};
|
||||||
doc: {},
|
var additionalPriv = {
|
||||||
user: {
|
|
||||||
name: name,
|
|
||||||
uid: Cryptpad.getUid(),
|
|
||||||
avatar: Cryptpad.getAvatarUrl(),
|
|
||||||
profile: Cryptpad.getProfileUrl(),
|
|
||||||
curvePublic: proxy.curvePublic,
|
|
||||||
netfluxId: Cryptpad.getNetwork().webChannels[0].myID,
|
|
||||||
},
|
|
||||||
priv: {
|
|
||||||
accountName: Utils.LocalStore.getAccountName(),
|
accountName: Utils.LocalStore.getAccountName(),
|
||||||
origin: window.location.origin,
|
origin: window.location.origin,
|
||||||
pathname: window.location.pathname,
|
pathname: window.location.pathname,
|
||||||
feedbackAllowed: Utils.Feedback.state,
|
feedbackAllowed: Utils.Feedback.state,
|
||||||
friends: proxy.friends || {},
|
|
||||||
settings: proxy.settings || {},
|
|
||||||
types: config.types
|
types: config.types
|
||||||
}
|
};
|
||||||
});
|
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
|
||||||
|
|
||||||
|
sframeChan.event('EV_METADATA_UPDATE', metaObj);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Cryptpad.onDisplayNameChanged(updateMeta);
|
Cryptpad.onMetadataChanged(updateMeta);
|
||||||
sframeChan.onReg('EV_METADATA_UPDATE', updateMeta);
|
sframeChan.onReg('EV_METADATA_UPDATE', updateMeta);
|
||||||
proxy.on('change', 'settings', updateMeta);
|
|
||||||
|
|
||||||
config.addCommonRpc(sframeChan);
|
config.addCommonRpc(sframeChan);
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js',
|
'/common/sframe-common-outer.js',
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/poll/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/poll/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,9 @@
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.cp-app-profile-resizer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
#cp-app-profile-displayname, #cp-app-profile-link {
|
#cp-app-profile-displayname, #cp-app-profile-link {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
|
@ -20,6 +20,8 @@ define([
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
|
'/bower_components/croppie/croppie.min.js',
|
||||||
|
'css!/bower_components/croppie/croppie.css',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
Crypto,
|
Crypto,
|
||||||
|
@ -253,12 +255,44 @@ define([
|
||||||
createEditableInput($block, LINK_ID, placeholder, getValue, setValue);
|
createEditableInput($block, LINK_ID, placeholder, getValue, setValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var AVATAR_SIZE_LIMIT = 0.5;
|
||||||
var allowedMediaTypes = [
|
var allowedMediaTypes = [
|
||||||
'image/png',
|
'image/png',
|
||||||
'image/jpeg',
|
'image/jpeg',
|
||||||
'image/jpg',
|
'image/jpg',
|
||||||
'image/gif',
|
'image/gif',
|
||||||
];
|
];
|
||||||
|
var transformAvatar = function (file, cb) {
|
||||||
|
if (file.type === 'image/gif') { return void cb(file); }
|
||||||
|
var $croppie = $('<div>', {
|
||||||
|
'class': 'cp-app-profile-resizer'
|
||||||
|
});
|
||||||
|
|
||||||
|
var todo = function () {
|
||||||
|
UI.confirm($croppie[0], function (yes) {
|
||||||
|
if (!yes) { return; }
|
||||||
|
$croppie.croppie('result', {
|
||||||
|
type: 'blob',
|
||||||
|
size: {width: 300, height: 300}
|
||||||
|
}).then(function(blob) {
|
||||||
|
blob.lastModifiedDate = new Date();
|
||||||
|
blob.name = 'avatar';
|
||||||
|
cb(blob);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
$croppie.croppie({
|
||||||
|
url: e.target.result,
|
||||||
|
viewport: { width: 100, height: 100 },
|
||||||
|
boundary: { width: 400, height: 300 },
|
||||||
|
});
|
||||||
|
todo();
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
};
|
||||||
var addAvatar = function ($container) {
|
var addAvatar = function ($container) {
|
||||||
var $block = $('<div>', {id: AVATAR_ID}).appendTo($container);
|
var $block = $('<div>', {id: AVATAR_ID}).appendTo($container);
|
||||||
var $span = $('<span>').appendTo($block);
|
var $span = $('<span>').appendTo($block);
|
||||||
|
@ -318,14 +352,30 @@ define([
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
APP.FM = common.createFileManager(fmConfig);
|
APP.FM = common.createFileManager(fmConfig);
|
||||||
|
var accepted = ".gif,.jpg,.jpeg,.png";
|
||||||
var data = {
|
var data = {
|
||||||
FM: APP.FM,
|
FM: APP.FM,
|
||||||
filter: function (file) {
|
filter: function (file) {
|
||||||
var sizeMB = Util.bytesToMegabytes(file.size);
|
var sizeMB = Util.bytesToMegabytes(file.size);
|
||||||
var type = file.type;
|
var type = file.type;
|
||||||
return sizeMB <= 0.5 && allowedMediaTypes.indexOf(type) !== -1;
|
// We can't resize .gif so we have to display an error if it is too big
|
||||||
|
if (sizeMB > AVATAR_SIZE_LIMIT && type === 'image/gif') {
|
||||||
|
UI.log(Messages._getKey('profile_uploadSizeError', [
|
||||||
|
Messages._getKey('formattedMB', [AVATAR_SIZE_LIMIT])
|
||||||
|
]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Display an error if the image type is not allowed
|
||||||
|
if (allowedMediaTypes.indexOf(type) === -1) {
|
||||||
|
UI.log(Messages._getKey('profile_uploadTypeError', [
|
||||||
|
accepted.split(',').join(', ')
|
||||||
|
]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
accept: ".gif,.jpg,.jpeg,.png"
|
transformer: transformAvatar,
|
||||||
|
accept: accepted
|
||||||
};
|
};
|
||||||
var $upButton = common.createButton('upload', false, data);
|
var $upButton = common.createButton('upload', false, data);
|
||||||
$upButton.text(Messages.profile_upload);
|
$upButton.text(Messages.profile_upload);
|
||||||
|
@ -395,15 +445,6 @@ define([
|
||||||
var onReady = function () {
|
var onReady = function () {
|
||||||
APP.$container.find('#'+CREATE_ID).remove();
|
APP.$container.find('#'+CREATE_ID).remove();
|
||||||
|
|
||||||
/*var obj = APP.lm && APP.lm.proxy;
|
|
||||||
if (!APP.readOnly) {
|
|
||||||
var pubKeys = Cryptpad.getPublicKeys();
|
|
||||||
if (pubKeys && pubKeys.curve) {
|
|
||||||
obj.curveKey = pubKeys.curve;
|
|
||||||
obj.edKey = pubKeys.ed;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (!APP.initialized) {
|
if (!APP.initialized) {
|
||||||
var $header = $('<div>', {id: HEADER_ID}).appendTo(APP.$rightside);
|
var $header = $('<div>', {id: HEADER_ID}).appendTo(APP.$rightside);
|
||||||
addAvatar($header);
|
addAvatar($header);
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js',
|
'/common/sframe-common-outer.js',
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/profile/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/profile/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
@ -36,19 +36,24 @@ define([
|
||||||
};
|
};
|
||||||
window.addEventListener('message', onMsg);
|
window.addEventListener('message', onMsg);
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
var getSecrets = function (Cryptpad, Utils) {
|
var getSecrets = function (Cryptpad, Utils, cb) {
|
||||||
var Hash = Utils.Hash;
|
var Hash = Utils.Hash;
|
||||||
// 1st case: visiting someone else's profile with hash in the URL
|
// 1st case: visiting someone else's profile with hash in the URL
|
||||||
if (window.location.hash) {
|
if (window.location.hash) {
|
||||||
return Hash.getSecrets('profile', window.location.hash.slice(1));
|
return void cb(null, Hash.getSecrets('profile', window.location.hash.slice(1)));
|
||||||
}
|
}
|
||||||
|
var editHash;
|
||||||
|
nThen(function (waitFor) {
|
||||||
// 2nd case: visiting our own existing profile
|
// 2nd case: visiting our own existing profile
|
||||||
var obj = Cryptpad.getProxy();
|
Cryptpad.getProfileEditUrl(waitFor(function (hash) {
|
||||||
if (obj.profile && obj.profile.view && obj.profile.edit) {
|
editHash = hash;
|
||||||
return Hash.getSecrets('profile', obj.profile.edit);
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
if (editHash) {
|
||||||
|
return void cb(null, Hash.getSecrets('profile', editHash));
|
||||||
}
|
}
|
||||||
// 3rd case: profile creation (create a new random hash, store it later if needed)
|
// 3rd case: profile creation (create a new random hash, store it later if needed)
|
||||||
if (!Utils.LocalStore.isLoggedIn()) { return; }
|
if (!Utils.LocalStore.isLoggedIn()) { return void cb(); }
|
||||||
var hash = Hash.createRandomHash();
|
var hash = Hash.createRandomHash();
|
||||||
var secret = Hash.getSecrets('profile', hash);
|
var secret = Hash.getSecrets('profile', hash);
|
||||||
Cryptpad.pinPads([secret.channel], function (e) {
|
Cryptpad.pinPads([secret.channel], function (e) {
|
||||||
|
@ -59,11 +64,13 @@ define([
|
||||||
return;
|
return;
|
||||||
//return void UI.log(Messages._getKey('profile_error', [e])) // TODO
|
//return void UI.log(Messages._getKey('profile_error', [e])) // TODO
|
||||||
}
|
}
|
||||||
obj.profile = {};
|
var profile = {};
|
||||||
obj.profile.edit = Utils.Hash.getEditHashFromKeys(secret.channel, secret.keys);
|
profile.edit = Utils.Hash.getEditHashFromKeys(secret.channel, secret.keys);
|
||||||
obj.profile.view = Utils.Hash.getViewHashFromKeys(secret.channel, secret.keys);
|
profile.view = Utils.Hash.getViewHashFromKeys(secret.channel, secret.keys);
|
||||||
|
Cryptpad.setNewProfile(profile);
|
||||||
|
});
|
||||||
|
cb(null, secret);
|
||||||
});
|
});
|
||||||
return secret;
|
|
||||||
};
|
};
|
||||||
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
||||||
// Adding a new avatar from the profile: pin it and store it in the object
|
// Adding a new avatar from the profile: pin it and store it in the object
|
||||||
|
@ -71,18 +78,14 @@ define([
|
||||||
var chanId = Utils.Hash.hrefToHexChannelId(data);
|
var chanId = Utils.Hash.hrefToHexChannelId(data);
|
||||||
Cryptpad.pinPads([chanId], function (e) {
|
Cryptpad.pinPads([chanId], function (e) {
|
||||||
if (e) { return void cb(e); }
|
if (e) { return void cb(e); }
|
||||||
Cryptpad.getProxy().profile.avatar = data;
|
Cryptpad.setAvatar(data, cb);
|
||||||
Utils.Realtime.whenRealtimeSyncs(Cryptpad.getRealtime(), function () {
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// Removing the avatar from the profile: unpin it
|
// Removing the avatar from the profile: unpin it
|
||||||
sframeChan.on('Q_PROFILE_AVATAR_REMOVE', function (data, cb) {
|
sframeChan.on('Q_PROFILE_AVATAR_REMOVE', function (data, cb) {
|
||||||
var chanId = Utils.Hash.hrefToHexChannelId(data);
|
var chanId = Utils.Hash.hrefToHexChannelId(data);
|
||||||
Cryptpad.unpinPads([chanId], function (e) {
|
Cryptpad.unpinPads([chanId], function () {
|
||||||
delete Cryptpad.getProxy().profile.avatar;
|
Cryptpad.setAvatar(undefined, cb);
|
||||||
cb(e);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/settings/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/settings/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ define([
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_DRIVE_GET', function (d, cb) {
|
sframeChan.on('Q_SETTINGS_DRIVE_GET', function (d, cb) {
|
||||||
cb(Cryptpad.getProxy());
|
Cryptpad.getUserObject(cb);
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_DRIVE_SET', function (data, cb) {
|
sframeChan.on('Q_SETTINGS_DRIVE_SET', function (data, cb) {
|
||||||
var sjson = JSON.stringify(data);
|
var sjson = JSON.stringify(data);
|
||||||
|
@ -57,26 +57,13 @@ define([
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_DRIVE_RESET', function (data, cb) {
|
sframeChan.on('Q_SETTINGS_DRIVE_RESET', function (data, cb) {
|
||||||
var proxy = Cryptpad.getProxy();
|
Cryptpad.resetDrive(cb);
|
||||||
var realtime = Cryptpad.getRealtime();
|
|
||||||
proxy.drive = Cryptpad.getStore().getEmptyObject();
|
|
||||||
Utils.Realtime.whenRealtimeSyncs(realtime, cb);
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_LOGOUT', function (data, cb) {
|
sframeChan.on('Q_SETTINGS_LOGOUT', function (data, cb) {
|
||||||
var proxy = Cryptpad.getProxy();
|
Cryptpad.logoutFromAll(cb);
|
||||||
var realtime = Cryptpad.getRealtime();
|
|
||||||
var token = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
|
|
||||||
localStorage.setItem('loginToken', token);
|
|
||||||
proxy.loginToken = token;
|
|
||||||
Utils.Realtime.whenRealtimeSyncs(realtime, cb);
|
|
||||||
});
|
});
|
||||||
sframeChan.on('Q_SETTINGS_IMPORT_LOCAL', function (data, cb) {
|
sframeChan.on('Q_SETTINGS_IMPORT_LOCAL', function (data, cb) {
|
||||||
var proxyData = Cryptpad.getStore().getProxy();
|
Cryptpad.mergeAnonDrive(cb);
|
||||||
require([
|
|
||||||
'/common/mergeDrive.js',
|
|
||||||
], function (Merge) {
|
|
||||||
Merge.anonDriveIntoUser(proxyData, Utils.LocalStore.getFSHash(), cb);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
SFCommonO.start({
|
SFCommonO.start({
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/todo/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/todo/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
@ -36,12 +36,12 @@ define([
|
||||||
};
|
};
|
||||||
window.addEventListener('message', onMsg);
|
window.addEventListener('message', onMsg);
|
||||||
}).nThen(function (/*waitFor*/) {
|
}).nThen(function (/*waitFor*/) {
|
||||||
var getSecrets = function (Cryptpad, Utils) {
|
var getSecrets = function (Cryptpad, Utils, cb) {
|
||||||
var proxy = Cryptpad.getProxy();
|
Cryptpad.getTodoHash(function (hash) {
|
||||||
var hash = proxy.todo || Utils.Hash.createRandomHash();
|
var nHash = hash || Utils.Hash.createRandomHash();
|
||||||
if (!proxy.todo) { proxy.todo = hash; }
|
if (!hash) { Cryptpad.setTodoHash(nHash); }
|
||||||
|
cb(null, Utils.Hash.getSecrets('todo', hash));
|
||||||
return Utils.Hash.getSecrets('todo', hash);
|
});
|
||||||
};
|
};
|
||||||
SFCommonO.start({
|
SFCommonO.start({
|
||||||
getSecrets: getSecrets,
|
getSecrets: getSecrets,
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
define([
|
define([
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
'jquery',
|
'/common/dom-ready.js',
|
||||||
'/common/requireconfig.js',
|
'/common/requireconfig.js',
|
||||||
'/common/sframe-common-outer.js'
|
'/common/sframe-common-outer.js'
|
||||||
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
var requireConfig = RequireConfig();
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
// Loaded in load #2
|
// Loaded in load #2
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
$(waitFor());
|
DomReady.onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
var req = {
|
var req = {
|
||||||
cfg: requireConfig,
|
cfg: requireConfig,
|
||||||
|
@ -19,7 +19,7 @@ define([
|
||||||
};
|
};
|
||||||
window.rc = requireConfig;
|
window.rc = requireConfig;
|
||||||
window.apiconf = ApiConfig;
|
window.apiconf = ApiConfig;
|
||||||
$('#sbox-iframe').attr('src',
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
ApiConfig.httpSafeOrigin + '/whiteboard/inner.html?' + requireConfig.urlArgs +
|
ApiConfig.httpSafeOrigin + '/whiteboard/inner.html?' + requireConfig.urlArgs +
|
||||||
'#' + encodeURIComponent(JSON.stringify(req)));
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue