Merge branch 'soon' into staging

This commit is contained in:
ansuz 2022-09-08 16:57:45 +05:30
commit c522e579a5
115 changed files with 3074 additions and 598 deletions

View File

@ -14,13 +14,13 @@ body:
label: I've found a bug and checked that ...
description: Prior to placing the issue, please check following:** *(fill out each checkbox with an `X` once done)*
options:
- label: ... I understand that not following the below instructions will result in immediate closure and/or deletion of my issue.
- label: I understand that not following the below instructions will result in immediate closure and/or deletion of my issue.
required: true
- label: ... I have understood that this bug report is dedicated for bugs, and not for support-related inquiries.
- label: I have understood that this bug report is dedicated for bugs, and not for support-related inquiries.
required: true
- label: ... I have understood that answers are voluntary and community-driven, and not commercial support.
- label: I have understood that answers are voluntary and community-driven, and not commercial support.
required: true
- label: ... I have verified that my issue has not been already answered in the past. I've read the [Common issues documentation section](https://docs.cryptpad.fr/en/FAQ.html#common-issues) and I also checked [previous issues](https://github.com/xwiki-labs/cryptpad/issues).
- label: I have verified that my issue has not been already answered in the past. I've read the [Common issues documentation section](https://docs.cryptpad.fr/en/FAQ.html#common-issues) and I also checked [previous issues](https://github.com/xwiki-labs/cryptpad/issues).
required: true
- type: textarea
attributes:

View File

@ -1,7 +1,25 @@
name: Feature Request
description: Suggest an idea for CryptPad
labels: ["feature request"]
description: Suggest an idea for CryptPad.
labels: ["Feature Request"]
body:
- type: checkboxes
attributes:
label: Contribution guidelines
description: Please read the code of conduct before proceeding.
options:
- label: I've read the [code of conduct](https://github.com/xwiki-labs/cryptpad/blob/main/CODE_OF_CONDUCT.md) and wholeheartedly agree
required: true
- type: checkboxes
attributes:
label: I would like to request a new feature for CryptPad
description: Prior to creating a new issue, please check following:** *(fill out each checkbox with an `X` once done)*
options:
- label: I have searched past issues and labels to check that my question/idea does not exist
required: true
- label: I have understood that this report is dedicated for feature requests, and not for support-related inquiries.
required: true
- label: I have understood that answers are voluntary and community-driven, and not commercial support.
required: true
- type: textarea
attributes:
label: Summary

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html class="cp" id="four-oh-four">
<html 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: Collaboration suite, encrypted and open-source</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html class="cp" id="five-hundred">
<html id="five-hundred">
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>

View File

@ -1,16 +1,15 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</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/favicon/main-favicon.png" id="favicon"/>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/customize/template.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html class="cp" id="four-oh-four">
<html 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>

View File

@ -1,16 +1,14 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</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/favicon/main-favicon.png" id="favicon"/>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/customize/template.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

View File

@ -1,18 +1,14 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</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/favicon/main-favicon.png" id="favicon"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/customize/template.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

View File

@ -16,6 +16,7 @@ var map = {
//'nl': 'Nederlands'
'pl': 'Polski',
'pt-br': 'Português do Brasil',
'pt-pt': 'Português do Portugal',
'ro': 'Română',
'ru': 'Русский',
//'sv': 'Svenska',

View File

@ -95,7 +95,7 @@ define([
return h('a', attrs, [icon, text]);
};
Pages.versionString = "5.0.0";
Pages.versionString = "5.1.0";
var customURLs = Pages.customURLs = {};
(function () {
@ -150,7 +150,7 @@ define([
Pages.infopageFooter = function () {
var donateButton;
if (!ApiConfig.removeDonateButton) {
donateButton = footLink('https://opencollective.com/cryptpad/contribute/', 'footer_donate', null, 'money'); // XXX DB: add OpenCollective icon // XXX
donateButton = footLink('https://opencollective.com/cryptpad/contribute/', 'footer_donate', null, 'money'); // TODO migrate to forkawesome and use the OpenCollective icon
}
return h('footer.cp-footer', [

View File

@ -15,12 +15,44 @@ elem.innerHTML = [
'</div>'
].join('');
var key = 'CRYPTPAD_STORE|colortheme'; // handle outer
if (localStorage[key] && localStorage[key] === 'dark') {
elem.classList.add('dark-theme');
}
if (!localStorage[key] && localStorage[key+'_default'] && localStorage[key+'_default'] === 'dark') {
elem.classList.add('dark-theme');
}
var req;
try {
req = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
if ((req.theme || req.themeOS) === 'dark') { // handle inner
elem.classList.add('dark-theme');
}
} catch (e) {}
document.addEventListener('DOMContentLoaded', function() {
document.body.appendChild(elem);
window.CP_preloadingTime = +new Date();
// soft transition between inner and outer placeholders
if (req && req.time && (+new Date() - req.time > 2000)) {
try {
var logo = document.querySelector('.placeholder-logo-container');
var message = document.querySelector('.placeholder-message-container');
logo.style.opacity = 100;
message.style.opacity = 100;
logo.style.animation = 'none';
message.style.animation = 'none';
} catch (err) {}
}
// fallback if CSS animations not available
setTimeout(() => {
document.querySelector('.placeholder-logo-container').style.opacity = 100;
document.querySelector('.placeholder-message-container').style.opacity = 100;
try {
document.querySelector('.placeholder-logo-container').style.opacity = 100;
document.querySelector('.placeholder-message-container').style.opacity = 100;
} catch (e) {}
}, 3000);
});
}());

View File

@ -1,12 +1,9 @@
@font-face {
font-family: 'Open Sans';
src: url('/bower_components/open-sans-fontface/fonts/Regular/OpenSans-Regular.eot');
src: url('/bower_components/open-sans-fontface/fonts/Regular/OpenSans-Regular.eot?#iefix') format('embedded-opentype'),
url('/bower_components/open-sans-fontface/fonts/Regular/OpenSans-Regular.woff') format('woff'),
url('/bower_components/open-sans-fontface/fonts/Regular/OpenSans-Regular.ttf') format('truetype'),
url('/bower_components/open-sans-fontface/fonts/Regular/OpenSans-Regular.svg#OpenSansRegular') format('svg');
font-weight: normal;
font-style: normal;
.cp-app-noscroll body {
background: transparent;
}
.cp-app-noscroll #placeholder {
z-index: 9999999; /* loading screen -1 */
background-color: transparent;
}
#placeholder {
@ -26,14 +23,15 @@
flex-flow: column;
justify-content: center;
align-items: center;
font: 20px 'Open Sans', 'Helvetica Neue', sans-serif !important;
font: 20px 'Helvetica Neue', sans-serif !important;
}
@media (prefers-color-scheme: dark) {
#placeholder {
background-color: #212121; /* @cp_loading-bg (dark) */
color: #EEEEEE; /* @cp_loading-fg (dark) */
}
html:not(.cp-app-noscroll) #placeholder.dark-theme {
background-color: #212121; /* @cp_loading-bg (dark) */
}
#placeholder.dark-theme {
color: #EEEEEE; /* @cp_loading-fg (dark) */
}
#placeholder .placeholder-logo-container {
height: 300px;
width: 300px;
@ -61,6 +59,9 @@
opacity: 0;
animation: fadein 5s ease 2s forwards;
}
#placeholder .placeholder-message-container p {
margin-top: 0;
}
#placeholder .placeholder-logo {
margin-left: auto;
margin-right: auto;
@ -97,3 +98,17 @@
display: none;
}
}
:is(div, noscript) > p.noscript {
font-family: sans-serif;
z-index: 999;
padding: 15px;
font-size: 20px;
margin-top: 30px !important;
max-width: 800px;
margin: auto;
background-color: #424242;
color: #eee;
border-radius: 5px;
}

View File

@ -1,16 +1,14 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite,encrypted and open-source</title>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</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/favicon/main-favicon.png" id="favicon"/>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/customize/template.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

View File

@ -0,0 +1,14 @@
/*
* You can override the translation text using this file.
* The recommended method is to make a copy of this file (/customize.dist/translations/messages.{LANG}.js)
in a 'customize' directory (/customize/translations/messages.{LANG}.js).
* If you want to check all the existing translation keys, you can open the internal language file
but you should not change it directly (/common/translations/messages.{LANG}.js)
*/
define(['/common/translations/messages.pt-pt.js'], function (Messages) {
// Replace the existing keys in your copied file here:
// Messages.button_newpad = "New Rich Text Document";
return Messages;
});

View File

@ -87,7 +87,7 @@ server {
if ($args ~ ver=) {
set $cacheControl max-age=31536000;
}
if ($uri ~ ^/.*(\/|\.html)$) {
if ($uri ~ ^(\/|.*\/|.*\.html)$) {
set $cacheControl no-cache;
}
# Will not set any header if it is emptystring
@ -242,5 +242,5 @@ server {
}
# Finally, serve anything the above exceptions don't govern.
try_files /customize/www/$uri/index.html /www/$uri /www/$uri/index.html /customize/$uri;
try_files /customize/www/$uri /customize/www/$uri/index.html /www/$uri /www/$uri/index.html /customize/$uri;
}

View File

@ -6,6 +6,9 @@ const Util = require("../common-util");
const Ulimit = require("ulimit");
const Decrees = require("../decrees");
const Pinning = require("./pin-rpc");
const Core = require("./core");
const Channel = require("./channel");
const BlockStore = require("../storage/block");
var Fs = require("fs");
@ -170,13 +173,15 @@ var archiveDocument = function (Env, Server, cb, data) {
switch (id.length) {
case 32:
// TODO disconnect users from active sessions
return void Env.msgStore.archiveChannel(id, Util.both(cb, function (err) {
Env.Log.info("ARCHIVAL_CHANNEL_BY_ADMIN_RPC", {
channelId: id,
reason: reason,
status: err? String(err): "SUCCESS",
});
Channel.disconnectChannelMembers(Env, Server, id, 'EDELETED', err => {
if (err) { } // TODO
});
}));
case 48:
return void Env.blobStore.archive.blob(id, Util.both(cb, function (err) {
@ -368,11 +373,314 @@ var getLimits = function (Env, Server, cb) {
cb(void 0, Env.limits);
};
var isValidKey = key => {
return typeof(key) === 'string' && key.length === 44;
};
// CryptPad_AsyncStore.rpc.send('ADMIN', ['GET_USER_TOTAL_SIZE', "CrufexqXcY/z+eKJlEbNELVy5Sb7E/EAAEFI8GnEtZ0="], console.log)
var getUserTotalSize = function (Env, Server, cb, data) {
var signingKey = Array.isArray(data) && data[1];
if (typeof(signingKey) !== 'string' || signingKey.length < 44) { return void cb("EINVAL"); } // FIXME use a standard check for this
Pinning.getTotalSize(Env, signingKey, cb);
if (!isValidKey(signingKey)) { return void cb("EINVAL"); }
var safeKey = Util.escapeKeyCharacters(signingKey);
Pinning.getTotalSize(Env, safeKey, cb);
};
var getPinActivity = function (Env, Server, cb, data) {
var signingKey = Array.isArray(data) && data[1];
if (!isValidKey(signingKey)) { return void cb("EINVAL"); }
// the db-worker ensures the signing key is of the appropriate form
Env.getPinActivity(signingKey, function (err, response) {
if (err) { return void cb(err && err.code); }
cb(void 0, response);
});
};
var isUserOnline = function (Env, Server, cb, data) {
var key = Array.isArray(data) && data[1];
if (!isValidKey(key)) { return void cb("EINVAL"); }
key = Util.unescapeKeyCharacters(key);
var online = false;
try {
Object.keys(Env.netfluxUsers).some(function (netfluxId) {
if (!Env.netfluxUsers[netfluxId][key]) { return; }
online = true;
return true;
});
} catch (err) {
Env.Log.error('ADMIN_USER_ONLINE_CHECK', {
error: err,
key: key,
});
return void cb("SERVER_ERROR");
}
cb(void 0, online);
};
var getPinLogStatus = function (Env, Server, cb, data) {
var key = Array.isArray(data) && data[1];
if (!isValidKey(key)) { return void cb("EINVAL"); }
var safeKey = Util.escapeKeyCharacters(key);
var response = {};
nThen(function (w) {
Env.pinStore.isChannelAvailable(safeKey, w(function (err, result) {
if (err) {
return void Env.Log.error('PIN_LOG_STATUS_AVAILABLE', err);
}
response.live = result;
}));
Env.pinStore.isChannelArchived(safeKey, w(function (err, result) {
if (err) {
return void Env.Log.error('PIN_LOG_STATUS_ARCHIVED', err);
}
response.archived = result;
}));
}).nThen(function () {
cb(void 0, response);
});
};
var getDocumentStatus = function (Env, Server, cb, data) {
var id = Array.isArray(data) && data[1];
if (typeof(id) !== 'string') { return void cb("EINVAL"); }
var response = {};
if (id.length === 44) {
return void nThen(function (w) {
BlockStore.isAvailable(Env, id, w(function (err, result) {
if (err) {
return void Env.Log.error('BLOCK_STATUS_AVAILABLE', err);
}
response.live = result;
}));
BlockStore.isArchived(Env, id, w(function (err, result) {
if (err) {
return void Env.Log.error('BLOCK_STATUS_ARCHIVED', err);
}
response.archived = result;
}));
}).nThen(function () {
cb(void 0, response);
});
}
if (id.length === 48) {
return void nThen(function (w) {
Env.blobStore.isBlobAvailable(id, w(function (err, result) {
if (err) {
return void Env.Log.error('BLOB_STATUS_AVAILABLE', err);
}
response.live = result;
}));
Env.blobStore.isBlobArchived(id, w(function (err, result) {
if (err) {
return void Env.Log.error('BLOB_STATUS_ARCHIVED', err);
}
response.archived = result;
}));
}).nThen(function () {
cb(void 0, response);
});
}
if (id.length !== 32) { return void cb("EINVAL"); }
nThen(function (w) {
Env.store.isChannelAvailable(id, w(function (err, result) {
if (err) {
return void Env.Log.error('CHANNEL_STATUS_AVAILABLE', err);
}
response.live = result;
}));
Env.store.isChannelArchived(id, w(function (err, result) {
if (err) {
return void Env.Log.error('CHANNEL_STATUS_ARCHIVED', err);
}
response.archived = result;
}));
}).nThen(function () {
cb(void 0, response);
});
};
var getPinList = function (Env, Server, cb, data) {
var key = Array.isArray(data) && data[1];
if (!isValidKey(key)) { return void cb("EINVAL"); }
var safeKey = Util.escapeKeyCharacters(key);
Env.getPinState(safeKey, function (err, value) {
if (err) { return void cb(err); }
try {
return void cb(void 0, Object.keys(value).filter(k => value[k]));
} catch (err2) { }
cb("UNEXPECTED_SERVER_ERROR");
});
};
var getPinHistory = function (Env, Server, cb, data) {
Env.Log.debug('GET_PIN_HISTORY', data);
cb("NOT_IMPLEMENTED");
};
var archivePinLog = function (Env, Server, cb, data) {
var args = Array.isArray(data) && data[1];
if (!args || typeof(args) !== 'object') { return void cb("EINVAL"); }
var key = args.key;
var reason = args.reason || '';
if (!isValidKey(key)) { return void cb("EINVAL"); }
var safeKey = Util.escapeKeyCharacters(key);
Env.pinStore.archiveChannel(safeKey, function (err) {
Core.expireSession(Env.Sessions, safeKey);
if (err) {
Env.Log.error('ARCHIVE_PIN_LOG_BY_ADMIN', {
error: err,
safeKey: safeKey,
reason: reason,
});
} else {
Env.Log.info('ARCHIVE_PIN_LOG_BY_ADMIN', {
safeKey: safeKey,
reason: reason,
});
}
cb(err);
});
};
var archiveBlock = function (Env, Server, cb, data) {
var args = Array.isArray(data) && data[1];
if (!args) { return void cb("INVALID_ARGS"); }
var key = args.key;
var reason = args.reason;
if (!isValidKey(key)) { return void cb("EINVAL"); }
BlockStore.archive(Env, key, err => {
Env.Log.info("ARCHIVE_BLOCK_BY_ADMIN", {
error: err,
key: key,
reason: reason || '',
});
cb(err);
});
};
var restoreArchivedBlock = function (Env, Server, cb, data) {
var args = Array.isArray(data) && data[1];
if (!args) { return void cb("INVALID_ARGS"); }
var key = args.key;
var reason = args.reason;
if (!isValidKey(key)) { return void cb("EINVAL"); }
BlockStore.restore(Env, key, err => {
Env.Log.info("RESTORE_ARCHIVED_BLOCK_BY_ADMIN", {
error: err,
key: key,
reason: reason || '',
});
cb(err);
});
};
var restoreArchivedPinLog = function (Env, Server, cb, data) {
var args = Array.isArray(data) && data[1];
if (!args || typeof(args) !== 'object') { return void cb("EINVAL"); }
var key = args.key;
var reason = args.reason || '';
if (!isValidKey(key)) { return void cb("EINVAL"); }
var safeKey = Util.escapeKeyCharacters(key);
Env.pinStore.restoreArchivedChannel(safeKey, function (err) {
Core.expireSession(Env.Sessions, safeKey);
if (err) {
Env.Log.error("RESTORE_ARCHIVED_PIN_LOG_BY_ADMIN", {
error: err,
safeKey: safeKey,
reason: reason,
});
} else {
Env.Log.info('RESTORE_ARCHIVED_PIN_LOG_BY_ADMIN', {
safeKey: safeKey,
reason: reason,
});
}
cb(err);
});
};
var archiveOwnedDocuments = function (Env, Server, cb, data) {
Env.Log.debug('ARCHIVE_OWNED_DOCUMENTS', data);
cb("NOT_IMPLEMENTED");
};
// quotas...
var getUserQuota = function (Env, Server, cb, data) {
var key = Array.isArray(data) && data[1];
if (!isValidKey(key)) { return void cb("EINVAL"); }
Pinning.getLimit(Env, key, cb);
};
var getUserStorageStats = function (Env, Server, cb, data) {
var key = Array.isArray(data) && data[1];
if (!isValidKey(key)) { return void cb("EINVAL"); }
var safeKey = Util.escapeKeyCharacters(key);
Env.getPinState(safeKey, function (err, value) {
if (err) { return void cb(err); }
try {
var res = {
channels: 0,
files: 0,
};
Object.keys(value).forEach(k => {
switch (k.length) {
case 32: return void ((res.channels++));
case 48: return void ((res.files++));
}
});
return void cb(void 0, res);
} catch (err2) { }
cb("UNEXPECTED_SERVER_ERROR");
});
};
var getStoredMetadata = function (Env, Server, cb, data) {
var id = Array.isArray(data) && data[1];
if (!Core.isValidId(id)) { return void cb('INVALID_CHAN'); }
Env.computeMetadata(id, function (err, data) {
cb(err, data);
});
};
var getDocumentSize = function (Env, Server, cb, data) {
var id = Array.isArray(data) && data[1];
if (!Core.isValidId(id)) { return void cb('INVALID_CHAN'); }
Env.getFileSize(id, (err, size) => {
if (err) { return void cb(err); }
cb(err, size);
});
};
var getLastChannelTime = function (Env, Server, cb, data) {
var id = Array.isArray(data) && data[1];
if (!Core.isValidId(id)) { return void cb('INVALID_CHAN'); }
Env.getLastChannelTime(id, function (err, time) {
if (err) { return void cb(err && err.code); }
cb(err, time);
});
};
var getMetadataHistory = function (Env, Server, cb, data) {
var id = Array.isArray(data) && data[1];
if (!Core.isValidId(id)) { return void cb('INVALID_CHAN'); }
var lines = [];
Env.msgStore.readChannelMetadata(id, (err, line) => {
if (err) { return; }
lines.push(line);
}, err => {
if (err) {
Env.Log.error('ADMIN_GET_METADATA_HISTORY', {
error: err,
id: id,
});
return void cb(err);
}
cb(void 0, lines);
});
};
var commands = {
@ -386,6 +694,27 @@ var commands = {
GET_FILE_DESCRIPTOR_LIMIT: getFileDescriptorLimit,
GET_CACHE_STATS: getCacheStats,
GET_PIN_ACTIVITY: getPinActivity,
IS_USER_ONLINE: isUserOnline,
GET_USER_QUOTA: getUserQuota,
GET_USER_STORAGE_STATS: getUserStorageStats,
GET_PIN_LOG_STATUS: getPinLogStatus,
GET_METADATA_HISTORY: getMetadataHistory,
GET_STORED_METADATA: getStoredMetadata,
GET_DOCUMENT_SIZE: getDocumentSize,
GET_LAST_CHANNEL_TIME: getLastChannelTime,
GET_DOCUMENT_STATUS: getDocumentStatus,
GET_PIN_LIST: getPinList,
GET_PIN_HISTORY: getPinHistory,
ARCHIVE_PIN_LOG: archivePinLog,
ARCHIVE_OWNED_DOCUMENTS: archiveOwnedDocuments,
RESTORE_ARCHIVED_PIN_LOG: restoreArchivedPinLog,
ARCHIVE_BLOCK: archiveBlock,
RESTORE_ARCHIVED_BLOCK: restoreArchivedBlock,
ARCHIVE_DOCUMENT: archiveDocument,
RESTORE_ARCHIVED_DOCUMENT: restoreArchivedDocument,

View File

@ -7,6 +7,56 @@ const Core = require("./core");
const Metadata = require("./metadata");
const HK = require("../hk-util");
Channel.disconnectChannelMembers = function (Env, Server, channelId, code, cb) {
var done = Util.once(Util.mkAsync(cb));
if (!Core.isValidId(channelId)) { return done('INVALID_ID'); }
const channel_cache = Env.channel_cache;
const metadata_cache = Env.metadata_cache;
const clear = function () {
delete channel_cache[channelId];
Server.clearChannel(channelId);
delete metadata_cache[channelId];
};
// an owner of a channel deleted it
nThen(function (w) {
// close the channel in the store
Env.msgStore.closeChannel(channelId, w());
}).nThen(function (w) {
// Server.channelBroadcast would be better
// but we can't trust it to track even one callback,
// let alone many in parallel.
// so we simulate it on this side to avoid race conditions
Server.getChannelUserList(channelId).forEach(function (userId) {
Server.send(userId, [
0,
Env.historyKeeper.id,
"MSG",
userId,
JSON.stringify({
error: code, //'EDELETED',
channel: channelId,
})
], w());
});
}).nThen(function () {
// clear the channel's data from memory
// once you've sent everyone a notice that the channel has been deleted
clear();
done();
}).orTimeout(function () {
Env.Log.warn('DISCONNECT_CHANNEL_MEMBERS_TIMEOUT', {
channelId,
code,
});
clear();
done();
}, 30000);
};
Channel.clearOwnedChannel = function (Env, safeKey, channelId, cb, Server) {
if (typeof(channelId) !== 'string' || channelId.length !== 32) {
return cb('INVALID_ARGUMENTS');
@ -90,44 +140,9 @@ var archiveOwnedChannel = function (Env, safeKey, channelId, __cb, Server) {
}
cb(void 0, 'OK');
const channel_cache = Env.channel_cache;
const metadata_cache = Env.metadata_cache;
const clear = function () {
delete channel_cache[channelId];
Server.clearChannel(channelId);
delete metadata_cache[channelId];
};
// an owner of a channel deleted it
nThen(function (w) {
// close the channel in the store
Env.msgStore.closeChannel(channelId, w());
}).nThen(function (w) {
// Server.channelBroadcast would be better
// but we can't trust it to track even one callback,
// let alone many in parallel.
// so we simulate it on this side to avoid race conditions
Server.getChannelUserList(channelId).forEach(function (userId) {
Server.send(userId, [
0,
Env.historyKeeper.id,
"MSG",
userId,
JSON.stringify({
error: 'EDELETED',
channel: channelId,
})
], w());
});
}).nThen(function () {
// clear the channel's data from memory
// once you've sent everyone a notice that the channel has been deleted
clear();
}).orTimeout(function () {
Env.Log.warn('ON_CHANNEL_DELETED_TIMEOUT', channelId);
clear();
}, 30000);
Channel.disconnectChannelMembers(Env, Server, channelId, 'EDELETED', err => {
if (err) { } // TODO
});
});
});
};

View File

@ -116,6 +116,7 @@ Pinning.getTotalSize = function (Env, safeKey, cb) {
Pinning.removePins = function (Env, safeKey, cb) {
// FIXME respect the queue
Env.pinStore.archiveChannel(safeKey, function (err) {
Core.expireSession(Env.Sessions, safeKey);
Env.Log.info('ARCHIVAL_PIN_BY_OWNER_RPC', {
safeKey: safeKey,
status: err? String(err): 'SUCCESS',
@ -293,4 +294,3 @@ Pinning.getDeletedPads = function (Env, channels, cb) {
Pinning.isChannelPinned = function (Env, channel, cb) {
return void cb(void 0, true);
};

View File

@ -174,7 +174,7 @@ var queryQuotaServer = function (Env, cb) {
var body = JSON.stringify(rawBody);
var options = {
host: Env.quota_api,
host: undefined,
path: '/api/getquota',
method: 'POST',
headers: {
@ -184,11 +184,22 @@ var queryQuotaServer = function (Env, cb) {
};
var H = Https;
if (Env.quota_api === 'localhost:3002') {
H = Http;
options.host = 'localhost';
options.port = 3002;
if (typeof(Env.accounts_api) === 'string') {
try {
let url = new URL(Env.accounts_api);
if (!['https:', 'http:'].includes(url.protocol)) { throw new Error("INVALID_PROTOCOL"); }
if (url.protocol === 'http:') { H = Http; }
if (typeof(url.port) === 'number') { options.port = url.port; }
options.host = url.host;
Env.Log.info("USING_CUSTOM_ACCOUNTS_API", {
value: Env.accounts_api,
});
} catch (err) {
Env.Log.error("INVALID_CUSTOM_QUOTA_API", {
error: err.message,
value: Env.accounts_api,
});
}
}
var req = H.request(options, function (response) {
@ -230,7 +241,7 @@ Quota.updateCachedLimits = function (Env, _cb) {
Quota.applyCustomLimits(Env);
if (!Env.allowSubscriptions && !Env.quota_api) { return void cb(); }
if (!Env.allowSubscriptions && !Env.accounts_api) { return void cb(); }
Quota.queryQuotaServer(Env, function (err, json) {
if (err) { return void cb(err); }
if (!json) { return void cb(); }

View File

@ -74,7 +74,6 @@ module.exports.create = function (config) {
NO_SANDBOX: NO_SANDBOX,
httpSafePort: httpSafePort,
accounts_api: config.accounts_api || undefined, // this simplifies integration with an accounts page
quota_api: config.quota_api || undefined, // hourly check quota
shouldUpdateNode: !isRecentVersion(),

View File

@ -203,7 +203,7 @@ RPC.create = function (Env, cb) {
var updateLimitInterval = function () {
Quota.updateCachedLimits(Env, function (e) {
// failure is expected if they have not specified a quota API endpoint
if (!Env.quota_api) { return; }
if (!Env.accounts_api) { return; }
if (e) {
Env.WARN('limitUpdate', e);
}
@ -211,7 +211,7 @@ RPC.create = function (Env, cb) {
};
Quota.applyCustomLimits(Env);
updateLimitInterval();
if (Env.quota_api) {
if (Env.accounts_api) {
Env.intervals.quotaUpdate = setInterval(updateLimitInterval, 3600*1000);
}

View File

@ -585,6 +585,19 @@ BlobStore.create = function (config, _cb) {
},
},
isBlobAvailable: function (blobId, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
if (!isValidId(blobId)) { return void cb("INVALID_ID"); }
var path = makeBlobPath(Env, blobId);
isFile(path, cb);
},
isBlobArchived: function (blobId, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
if (!isValidId(blobId)) { return void cb("INVALID_ID"); }
var path = prependArchive(Env, makeBlobPath(Env, blobId));
isFile(path, cb);
},
closeBlobstage: function (safeKey) {
closeBlobstage(Env, safeKey);
},

View File

@ -55,6 +55,61 @@ Block.archive = function (Env, publicKey, _cb) {
}, cb);
};
Block.restore = function (Env, publicKey, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
// derive the filepath
var livePath = Block.mkPath(Env, publicKey);
// make sure the path is valid
if (typeof(livePath) !== 'string') {
return void cb('E_INVALID_BLOCK_PATH');
}
var archivePath = Block.mkArchivePath(Env, publicKey);
// make sure the path is valid
if (typeof(archivePath) !== 'string') {
return void cb('E_INVALID_BLOCK_ARCHIVAL_PATH');
}
// TODO Env.incrementBytesWritten
Fse.move(archivePath, livePath, {
//overwrite: true,
}, cb);
};
var isValidKey = function (publicKey) {
return typeof(publicKey) === 'string' && publicKey.length === 44;
};
var exists = function (path, cb) {
Fs.stat(path, function (err, stat) {
if (err) {
if (err.code === 'ENOENT') {
return void cb(void 0, false);
}
return void cb(err);
}
if (!stat.isFile()) { return void cb('E_NOT_FILE'); }
return void cb(void 0, true);
});
};
var checkPath = function (Env, publicKey, pathFunction, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
if (!isValidKey(publicKey)) { return void cb("INVALID_ARGS"); }
var path = pathFunction(Env, publicKey);
exists(path, cb);
};
Block.isAvailable = function (Env, publicKey, _cb) {
checkPath(Env, publicKey, Block.mkPath, _cb);
};
Block.isArchived = function (Env, publicKey, _cb) {
checkPath(Env, publicKey, Block.mkArchivePath, _cb);
};
Block.check = function (Env, publicKey, _cb) { // 'check' because 'exists' implies boolean
var cb = Util.once(Util.mkAsync(_cb));
var path = Block.mkPath(Env, publicKey);

View File

@ -381,8 +381,8 @@ const getOlderHistory = function (data, cb) {
};
const getPinState = function (data, cb) {
const safeKey = data.key;
if (typeof(data.key) !== 'string') { return void cb('INVALID_KEY'); }
const safeKey = Util.escapeKeyCharacters(data.key);
var ref = {};
var lineHandler = Pins.createLineHandler(ref, Env.Log.error);
@ -504,8 +504,9 @@ const getHashOffset = function (data, cb) {
};
const removeOwnedBlob = function (data, cb) {
if (typeof(data.safeKey) !== 'string') { return void cb("INVALID_KEY"); }
const blobId = data.blobId;
const safeKey = data.safeKey;
const safeKey = Util.escapeKeyCharacters(data.safeKey);
nThen(function (w) {
// check if you have permissions
@ -570,8 +571,9 @@ var reportStatus = function (Env, label, safeKey, err, id, size) {
const completeUpload = function (data, cb) {
if (!data) { return void cb('INVALID_ARGS'); }
if (typeof(data.safeKey) !== 'string') { return void cb("INVALID_KEY"); }
var owned = data.owned;
var safeKey = data.safeKey;
var safeKey = Util.escapeKeyCharacters(data.safeKey);
var arg = data.arg;
var size = data.size;
@ -591,6 +593,47 @@ const completeUpload = function (data, cb) {
});
};
const getPinActivity = function (data, cb) {
if (!data) { return void cb("INVALID_ARGS"); }
if (typeof(data.key) !== 'string') { return void cb("INVALID_KEY"); }
var safeKey = Util.escapeKeyCharacters(data.key);
var first;
var latest;
pinStore.getMessages(safeKey, line => {
if (!line || !line.trim()) { return; }
try {
var parsed = JSON.parse(line);
var temp = parsed[parsed.length - 1];
if (!temp || typeof(temp) !== 'number') { return; }
latest = temp;
if (first) { return; }
first = latest;
} catch (err) { }
}, function (err) {
if (err) { return void cb(err); }
cb(void 0, {
first: first,
latest: latest,
});
});
};
const getLastChannelTime = function (data, cb) {
if (!data) { return void cb("INVALID_ARGS"); }
var latest;
store.getMessages(data.channel, function (line) {
try {
var parsed = JSON.parse(line);
var temp = parsed[parsed.length - 1];
if (!temp || typeof(temp) !== 'number') { return; }
latest = temp;
} catch (err) { }
}, function (err) {
if (err) { return void cb(err); }
cb(void 0, latest);
});
};
const COMMANDS = {
COMPUTE_INDEX: computeIndex,
COMPUTE_METADATA: computeMetadata,
@ -606,6 +649,8 @@ const COMMANDS = {
WRITE_TASK: writeTask,
EVICT_INACTIVE: evictInactive,
COMPLETE_UPLOAD: completeUpload,
GET_PIN_ACTIVITY: getPinActivity,
GET_LAST_CHANNEL_TIME: getLastChannelTime,
};
COMMANDS.INLINE = function (data, cb) {

View File

@ -340,10 +340,26 @@ Workers.initialize = function (Env, config, _cb) {
});
};
Env.getPinActivity = function (safeKey, cb) {
Env.pinStore.getWeakLock(safeKey, function (next) {
sendCommand({
key: safeKey,
command: 'GET_PIN_ACTIVITY',
}, Util.both(next, cb));
});
};
Env.getLastChannelTime = function (channel, cb) {
sendCommand({
command: 'GET_LAST_CHANNEL_TIME',
channel: channel,
}, cb);
};
Env.getFileSize = function (channel, cb) {
sendCommand({
command: 'GET_FILE_SIZE',
channel: channel,
channel: channel,
}, cb);
};

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "cryptpad",
"version": "5.0.0",
"version": "5.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cryptpad",
"version": "5.0.0",
"version": "5.1.0",
"license": "AGPL-3.0+",
"dependencies": {
"@mcrowe/minibloom": "^0.2.0",

View File

@ -1,7 +1,7 @@
{
"name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server",
"version": "5.0.0",
"version": "5.1.0",
"license": "AGPL-3.0+",
"repository": {
"type": "git",
@ -49,9 +49,7 @@
"unused-translations": "node ./scripts/translations/unused-translations.js",
"test": "node scripts/TestSelenium.js",
"test-rpc": "cd scripts/tests && node test-rpc",
"template": "cd customize.dist/src && for page in ../index.html ../contact.html ../features.html ../../www/login/index.html ../../www/register/index.html ../../www/user/index.html;do echo $page; cp template.html $page; done;",
"evict-inactive": "node scripts/evict-inactive.js",
"make-opengraph": "node scripts/build.js",
"clean-opengraph": "rm -rf customize/www/"
"build": "node scripts/build.js"
}
}

View File

@ -3,29 +3,8 @@
var Fs = require("fs");
var Fse = require("fs-extra");
var Path = require("path");
var OS = require("os");
if (process.env.CRYPTPAD_CONFIG) {
/* using Fs.existsSync() function and __dirname variable here won't filter
environment variables like CRYPTPAD_CONFIG='/../docs/config2.js', while require()
inside load-config.js will, outputing some non intellegible error messages.
(plus, it won't handle missing '.js' in file names neither) */
try {
require.resolve(process.env.CRYPTPAD_CONFIG);
} catch (e) {
console.error(`The configuration file ${process.env.CRYPTPAD_CONFIG} can not
be loaded. Please review your CRYPTPAD_CONFIG environment variable.`
.replace(/\s{2,}/g, ' '));
process.exit(1);
}
} else {
if (!Fs.existsSync(__dirname + '/../config/config.js')) {
console.error(`This script needs the file config/config.js to work properly.
You can make one by copying config/config.example.js. Check the
value of httpUnsafeOrigin for this script to behave as expected.`
.replace(/\s{2,}/g, ' '));
process.exit(1);
}
}
var config = require("../lib/load-config");
var swap = function (s, o) {
@ -50,41 +29,88 @@ var swap = function (s, o) {
});
};
const ogData = `
<meta property="og:url" content="{{rootUrl}}/{{app}}/">
<meta property="og:type" content="website">
<meta property="og:title" content="{{title}}">
<meta property="og:description" content="CryptPad: end-to-end encrypted collaboration suite">
<meta property="og:image" content="{{rootUrl}}/customize/images/opengraph_preview/{{image}}">
<meta property="twitter:card" content="summary_large_image">`;
var Messages = require("../www/common/translations/messages.json");
var previewExists = function (name) {
if (Fs.existsSync(__dirname + '/../customize/images/opengraph_preview/')) {
return Fs.existsSync(__dirname + `/../customize/images/opengraph_preview/${name}`);
var types = Messages.type;
[ 'calendar', 'notifications', ].forEach(k => { types[k] = Messages[k]; });
// FIXME it would be better if these were just included in the translated list of types
types.settings = Messages.settings_title;
types.support = Messages.supportPage;
types.profile = Messages.profilePage;
var translations;
try {
translations = Fs.readdirSync('./www/common/translations/').filter(name => {
return /messages\..*\.json$/.test(name);
});
} catch (err) {
console.error(err);
}
var preferredLanguage = config.preferredLanguage;
var Preferred;
var noScriptContent = [ Messages.ui_jsRequired ];
translations.forEach(name => {
var path = `./www/common/translations/${name}`;
var content;
try {
content = JSON.parse(Fs.readFileSync(path, 'utf-8'));
} catch (err) {
return void console.error(`Failed to parse ${path}`);
}
return Fs.existsSync(__dirname + `/../customize.dist/images/opengraph_preview/${name}`);
if (name === `messages.${preferredLanguage}.json`) { Preferred = content; }
if (typeof(content.ui_jsRequired) !== 'string') { return; }
noScriptContent.push(content.ui_jsRequired);
});
var makeNoscript = (indent) => {
var lines = noScriptContent.map(s => {
return `${indent + indent}<p class="noscript">${s}</p>`;
}).join('\n');
return `${indent}<noscript>\n${lines}\n${indent}</noscript>`;
};
var templateOG = function (a, type) {
return swap(ogData, {
rootUrl: config.httpUnsafeOrigin,
app: a,
title: type && `Encrypted ${type}` || 'CryptPad',
image: previewExists(`og-${a}.png`) && `og-${a}.png` || `og-default.png`
var getKey = function (key, args) {
var source;
if (Preferred && Preferred[key]) {
source = Preferred[key];
} else if (Messages && Messages[key]) {
source = Messages[key];
} else {
return '?';
}
if (typeof(source) !== 'string') { return '?'; }
if (!Array.isArray(args)) { return source; }
return source.replace(/\{(\d+)\}/g, (str, p1) => {
if (['string', 'number'].includes(typeof(p1))) { return args[p1]; }
console.error("Only strings and numbers can be used in _getKey params.\nAborting...");
process.exit(1);
});
};
var insert = function (src, template) {
var matchs = src.match(/(<meta .*>)|(.*<\/title>)/g);
if (!matchs || !matchs.length) {
return src;
var previewExists = function (name) {
if (Fs.existsSync('./customize/images/opengraph_preview/')) {
return Fs.existsSync(`./customize/images/opengraph_preview/${name}`);
}
return src.replace(matchs.at(-1), `$& ${template}`);
return Fs.existsSync(`./customize.dist/images/opengraph_preview/${name}`);
};
var buildPath = __dirname + '/../customize/www';
var tmpPath = __dirname + '/../CRYPTPAD_TEMP_BUILD';
var imagePath = `/customize/images/opengraph_preview/`;
var appImagePath = a => {
var partial = previewExists(`og-${a}.png`) && `og-${a}.png` || `og-default.png`;
return new URL(imagePath + partial, config.httpUnsafeOrigin).href;
};
var buildPath = Path.resolve('./customize');
var tmpPath = Path.join(OS.tmpdir(), '/CRYPTPAD_TEMP_BUILD/');
var write = function (content, dest) {
console.log(`Creating ${dest}`);
@ -93,15 +119,12 @@ var write = function (content, dest) {
var dirPath = Path.dirname(path);
Fse.mkdirpSync(dirPath);
Fs.writeFileSync(path, content);
console.log();
};
console.log("Creating target directories");
// remove tmp path so we start fresh
Fse.removeSync(tmpPath);
Fse.mkdirpSync(tmpPath);
var srcAppTypes = Fs.readFileSync(__dirname + '/../www/common/translations/messages.json', 'utf8');
var types = JSON.parse(srcAppTypes).type;
var appIndexesToBuild = [
'sheet',
@ -117,24 +140,180 @@ var appIndexesToBuild = [
'file',
'calendar',
'drive',
'teams'
'teams',
'contacts',
'notifications',
'checkup',
'file',
'profile',
'settings',
'support',
// bounce ??
];
var baseAppPath = './www/';
const ogData = `
<meta property="og:url" content="{{url}}">
<meta property="og:type" content="website">
<meta property="og:title" content="{{title}}">
<meta property="og:description" content="{{description}}">
<meta property="og:image" content="{{image}}">
<meta property="twitter:card" content="summary_large_image">`;
var versionString = String(+new Date());
var processPage = (src) => {
return src
.replace(/(\s*)<noscript>([\s\S]*)<\/noscript>/, (all, space /*, content */) => {
var indent = space.split('\n').filter(Boolean);
if (indent && indent[0]) {
return '\n' + makeNoscript(indent[0] || ' ');
}
return space + makeNoscript(' ');
})
.replace(/pre\-loading\.js\?ver=([^"]+)"/, (all, content) => {
return all.replace(content, versionString);
})
.replace(/pre\-loading\.css\?ver=([^"]+)"/, (all, content) => {
return all.replace(content, versionString);
});
};
var checkPage = (built, srcPath) => {
if (!/pre\-loading\.js/.test(built)) {
console.log(`no preloading js in ${srcPath}`);
process.exit(1);
}
if (!/pre\-loading\.css/.test(built)) {
console.log(`no preloading css in ${srcPath}`);
process.exit(1);
}
if (!/noscript/i.test(built)) {
console.error(`NO NOSCRIPT TAG FOR ${srcPath}`);
process.exit(1);
}
if (/<\/html>/.test(built)) {
console.log(`weird html in ${srcPath}`);
process.exit(1);
}
};
appIndexesToBuild.forEach(function (app) {
console.log(`Parsing www/${app}/index.html`);
var src = Fs.readFileSync(__dirname + `/../www/${app}/index.html`, 'utf8');
var srcPath = Path.resolve(Path.join(baseAppPath, app, 'index.html'));
console.log(`Parsing ${srcPath}`);
var src = Fs.readFileSync(srcPath, 'utf8');
// rename types for shared documents (ones in place can sound weird)
if (app === 'drive') { types[app] = 'Drive'; }
if (app === 'teams') { types[app] = 'Team drive'; }
write(
insert(src, templateOG(app, types[app])),
`${app}/index.html`
);
if (app === 'drive') { types[app] = Messages.fm_rootName; }
if (app === 'teams') { types[app] = Messages.og_teamDrive; }
var patt = /<\/title>/;
var type = types[app];
var built = processPage(src.replace(patt, (current) => {
return current + swap(ogData, {
url: new URL(`/${app}/`, config.httpUnsafeOrigin).href,
title: type && `Encrypted ${type}` || 'CryptPad',
image: appImagePath(app),
description: Messages.og_default,
});
}));
if (!/noscript/i.test(built)) {
console.error(`NO NOSCRIPT TAG FOR ${srcPath}`);
process.exit(1);
}
write(built, `./www/${app}/index.html`);
// XXX preloading version for inner.html
});
Fse.removeSync(buildPath);
var dirPath = Path.dirname(buildPath);
Fse.mkdirpSync(dirPath);
Fse.renameSync(tmpPath, buildPath);
var instance;
try {
instance = new URL(config.httpUnsafeOrigin).hostname;
} catch (err) {
console.error("Failed to parse instance domain name\nAborting...");
return void process.exit(1);
}
[
{
src: './www/register/index.html',
dest: './www/register/index.html',
url: '/register/',
title: getKey('og_register', [instance]),
},
{
src: './www/login/index.html',
dest: './www/login/index.html',
url: '/login/',
title: getKey('og_login', [instance]),
},
{
src: './customize.dist/contact.html',
dest: './www/contact.html',
url: '/contact.html',
title: getKey('og_contact', [instance]),
},
{
src: './customize.dist/features.html',
dest: './www/features.html',
url: '/features.html',
title: getKey((config.allow_subscriptions? 'og_pricing': 'og_features'), [instance]),
},
{
src: './customize.dist/index.html',
dest: './www/index.html',
url: '/index.html',
title: getKey('og_default'),
}
// TODO 404 ?
// TODO 500 ?
// TODO down ?
].forEach(obj => {
var srcPath = obj.src;
var destPath = obj.dest;
console.log(`Parsing ${srcPath}`);
var src = Fs.readFileSync(srcPath, 'utf8');
var patt = /<\/title>/;
var href = new URL(obj.url, config.httpUnsafeOrigin).href;
var built = processPage(src.replace(patt, (current) => {
return current + swap(ogData, {
url: href,
title: obj.title || "CryptPad",
image: new URL(imagePath + 'og-default.png', config.httpUnsafeOrigin).href,
description: Messages.og_default,
});
}));
checkPage(built, srcPath);
write(built, destPath);
});
try {
console.log(`Copying built files to target directory (${buildPath})`);
Fse.copySync(tmpPath, buildPath, {
overwrite: true,
});
} catch (err) {
console.error(`Failed to copy generated content to ${buildPath}`);
console.error(err);
}
try {
console.log(`Removing temporary build directory (${tmpPath})`);
Fse.rmSync(tmpPath, {
recursive: true,
force: true,
});
console.log(`Successfully removed ${tmpPath}`);
} catch (err) {
console.error(err);
}

27
scripts/test-metadata.js Normal file
View File

@ -0,0 +1,27 @@
var Meta = require("../lib/metadata");
var lines = [
{
"validateKey":"TMsHGx/I5EWBqckKTq/9t/6Xjvl7IdA/IMg0ssn27BY=",
"owners":[
"BpL3pEyX2IlfsvxQELB9uz5qh+40re0gD6J6LOobBm8="
],
"channel":"771cefbdf2e62543388f1f7acb0338c1",
"created":1628512619236
},
{
"validateKey":"TMsHGx/I5EWBqckKTq/9t/6Xjvl7IdA/IMg0ssn27BY=",
"channel":"771cefbdf2e62543388f1f7acb0338c1",
"created":1628512619236
}
];
var ref = {};
var lineHandler = Meta.createLineHandler(ref, console.log);
lines.forEach(line => {
lineHandler(void 0, line);
});
console.log(ref);

View File

@ -115,11 +115,23 @@ var conditionallyPrintContent = function (output) {
}
};
var exceptions = `
ui_more
ui_collapse
ui_expand
ui_jsRequired
`.split(/\s+/).filter(Boolean);
var next = function () {
var key = keys[0];
if (!key) { return; }
keys.shift();
if (/^og_/.test(key) || exceptions.includes(key)) {
return void next();
}
if (!limit) { return void console.log("[DONE]"); }
limit--;

View File

@ -241,6 +241,7 @@ var serveConfig = makeRouteCache(function (host) {
fileHost: Env.fileHost,
shouldUpdateNode: Env.shouldUpdateNode || undefined,
listMyInstance: Env.listMyInstance,
accounts_api: Env.accounts_api,
}, null, '\t'),
'});'
].join(';\n')
@ -304,7 +305,7 @@ var send500 = function (res, path) {
};
app.get('/api/updatequota', function (req, res) {
if (!Env.quota_api) {
if (!Env.accounts_api) {
res.status(404);
return void send404(res);
}

View File

@ -109,6 +109,9 @@
align-items: top;
.cp-support-title-buttons {
flex-shrink: 0;
button i {
margin-right: 0px;
}
}
}
.cp-support-collapsed {
@ -327,5 +330,26 @@
.cp-charts-row.heading {
font-weight: bold;
}
table.cp-metadata-history,
table.cp-account-stats,
table.cp-block-stats,
table.cp-pin-list,
table.cp-document-stats {
@color: #777; // XXX
border: 1px solid @color;
margin: 15px;
td, pre {
color: @cryptpad_text_col;
}
td {
max-width: 60vw; // XXX
border: 1px solid @color;
padding: 5px;
.scroll {
max-width: 500px;
overflow-x: auto;
}
}
}
}

View File

@ -5,7 +5,7 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/admin/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -12,9 +12,5 @@
<body class="cp-app-admin">
<div id="cp-toolbar" class="cp-toolbar-container"></div>
<div id="cp-sidebarlayout-container"></div>
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</body>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html class="cp">
<html>
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
@ -8,8 +8,4 @@
<script async data-bootload="main.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/calendar/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -12,9 +12,5 @@
<body class="cp-app-calendar">
<div id="cp-toolbar" class="cp-toolbar-container"></div>
<div id="cp-sidebarlayout-container"></div>
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</body>

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<noscript></noscript>
<div id="cp-progress"></div>
<iframe-placeholder>
<script type="text/javascript" src="/checkup/dependency-warning.js?ver=1.0.1"></script>

View File

@ -1420,6 +1420,55 @@ define([
});
});
[
'/',
'/index.html',
'/contact.html',
'/code/',
'/pad/index.html',
].forEach(url => {
assert(function (cb, msg) {
try {
url = new URL(url, ApiConfig.httpUnsafeOrigin).href;
} catch (err) {
console.error(err);
}
Tools.common_xhr(url, xhr => {
xhr.done(res => {
var dom = new DOMParser().parseFromString(res, 'text/html');
var sels = [
'og:url',
'og:type',
'og:title',
'og:description',
'og:image',
'twitter:card',
];
var missing = [];
sels.forEach(sel => {
var selector = `meta[property="${sel}"]`;
var el = dom.querySelector(selector);
if (!el) { missing.push(selector); }
});
if (!missing.length) { return void cb(true); }
setWarningClass(msg);
msg.appendChild(h('span', [
h('p', [
link(url, url),
' is missing several attributes which provide better previews on social media sites and messengers. ',
"The administrator of this instance can generate them with ", code('npm run build'), '.',
]),
h('p', "Missing attributes: "),
h('ul', missing.map(q => h('li', h('code', q)))),
]));
cb(false);
});
});
});
});
var serverToken;
Tools.common_xhr('/', function (xhr) {
serverToken = xhr.getResponseHeader('server');

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/sframe-app-outer.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll cp-app-print">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/code/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -14,13 +14,6 @@
<body class="cp-app-code">
<div id="cme_toolbox" class="cp-toolbar-container"></div>
<div id="cp-app-code-editor">
<div id="cp-app-code-container">
<textarea id="editor1" name="editor1"></textarea>
</div>
<div id="cp-app-code-preview">
<div id="cp-app-code-preview-content"></div>
<div id="cp-app-code-print"></div>
</div>
</div>
</body>
</html>

View File

@ -583,6 +583,14 @@ define([
}
}, waitFor(function (fw) { framework = fw; }));
$('#cp-app-code-editor').append([
h('div#cp-app-code-container', h('textarea#editor1', {name:'editor1'})),
h('div#cp-app-code-preview', [
h('div#cp-app-code-preview-content'),
h('div#cp-app-code-print')
])
]);
nThen(function (waitFor) {
$(waitFor());
}).nThen(function () {

View File

@ -631,7 +631,7 @@ define([
var frame = dialog.frame([
message,
dialog.nav(ok),
]);
], opt);
if (opt.forefront) { $(frame).addClass('forefront'); }
var listener;
@ -660,7 +660,7 @@ define([
opt = opt || {};
var inputBlock = opt.password ? UI.passwordInput() :
(opt.typeInput ? dialog.textTypeInput(opt.typeInput) : dialog.textInput());
(opt.typeInput ? dialog.textTypeInput(opt.typeInput) : dialog.textInput(opt && opt.inputOpts));
var input = $(inputBlock).is('input') ? inputBlock : $(inputBlock).find('input')[0];
input.value = typeof(def) === 'string'? def: '';
@ -725,7 +725,7 @@ define([
message,
dialog.nav(opt.reverseOrder?
[ok, cancel]: [cancel, ok]),
]);
], opt);
var listener;
var close = Util.once(function (bool, ev) {
@ -1003,6 +1003,7 @@ define([
$loading.addClass("cp-loading-hidden"); // Hide the loading screen
$loading.find('.cp-loading-progress').remove(); // Remove the progress list
setTimeout(cb, 750);
$('head > link[href^="/customize/src/pre-loading.css"]').remove();
};
UI.errorLoadingScreen = function (error, transparent, exitable) {
if (error === 'Error: XDR encoding failure') {

View File

@ -1739,7 +1739,10 @@ define([
tag: 'div',
attributes: {'class': 'cp-user-menu-logo'},
content: h('span', [
h('img', {src: '/customize/CryptPad_logo_grey.svg',alt: 'CryptPad logo',}), // XXX hardcoded alt text?
h('img', {
src: '/customize/CryptPad_logo_grey.svg',
"aria-hidden": true,
}),
h('span.cp-user-menu-logo-text', "CryptPad")
]),
});

View File

@ -7,6 +7,7 @@ define([
var list = Modes.list = [
"APL apl .apl",
"ASCII-Armor asciiarmor .asc",
"AsciiDoc asciidoc .adoc",
"ASN.1 asn.1 .asn1",
"Asterisk asterisk",
"Brainfuck brainfuck .b",

View File

@ -20,6 +20,7 @@ define([
'netflux-client': '/bower_components/netflux-websocket/netflux-client',
'chainpad-netflux': '/bower_components/chainpad-netflux/chainpad-netflux',
'chainpad-listmap': '/bower_components/chainpad-listmap/chainpad-listmap',
'cm-extra': '/lib/codemirror-extra-modes'
},
map: {
'*': {

View File

@ -272,6 +272,13 @@ define([
if (/text\/x/.test(mode)) {
CMeditor.autoLoadMode(editor, 'clike');
editor.setOption('mode', mode);
} else if (mode === 'asciidoc') {
CMeditor.autoLoadMode(editor, mode, {
path: function () {
return 'cm-extra/asciidoc/asciidoc';
}
});
editor.setOption('mode', mode);
} else {
if (mode !== "text") {
CMeditor.autoLoadMode(editor, mode);

View File

@ -51,7 +51,8 @@ define([
pfx: window.location.origin,
theme: localStorage[themeKey],
themeOS: localStorage[themeKey+'_default'],
lang: lang
lang: lang,
time: window.CP_preloadingTime
};
window.rc = requireConfig;
window.apiconf = ApiConfig;

View File

@ -486,8 +486,6 @@
"pad_settings_width_large": "Plná šířka",
"pad_settings_info": "Výchozí nastavení pro tento dokument. Bude použito, když nový uživatel navštíví tento dokument.",
"pad_settings_title": "Nastavení dokumentu",
"admin_getquotaButton": "Zkontrolovat",
"admin_getquotaTitle": "Zkontrolovat úložiště účtů",
"settings_colorthemeTitle": "Barevný motiv",
"settings_colorthemeHint": "Změnit barevný motiv CryptPadu na tomto zařízení.",
"settings_colortheme_default": "Výchozí nastavení ({0})",
@ -506,7 +504,6 @@
"allowNotifications": "Povolit oznámení",
"archivedFromServer": "Dokument archivován",
"restoredFromServer": "Dokument obnoven",
"admin_archiveInval": "Neplatný dokument",
"admin_archiveInput2": "Heslo dokumentu",
"admin_archiveInput": "URL dokumentu",
"admin_unarchiveButton": "Obnovit",
@ -1287,7 +1284,6 @@
"features_noData": "Nejsou vyžadovány žádné osobní údaje",
"admin_archiveButton": "Archivovat",
"pricing": "Ceník",
"admin_archiveTitle": "Archivovat dokumenty",
"errorPopupBlocked": "Aby mohl CryptPad fungovat, musí být schopen otevírat nové karty. Povolte prosím vyskakovací okna v adresním řádku vašeho prohlížeče. Tato okna nebudou nikdy použita k zobrazení reklamy.",
"support_notification": "Administrátor odpověděl na váš požadavek",
"unableToDisplay": "Dokument nelze zobrazit. Stisknutím klávesy Esc znovu načtěte stránku. Pokud problém přetrvává, kontaktujte podporu.",
@ -1304,7 +1300,6 @@
"support_listTitle": "Požadavky na podporu",
"owner_removePendingText": "Probíhá",
"admin_unarchiveHint": "Obnovit dokument, který byl dříve archivován",
"admin_unarchiveTitle": "Obnovit dokumenty",
"fileTableHeader": "Stažené a nahrané",
"team_pcsSelectLabel": "Uložit do",
"team_pcsSelectHelp": "Vytvořením vlastněného dokumentu na Drive vašeho týmu získá váš tým jeho vlastnictví.",
@ -1381,7 +1376,6 @@
"admin_purpose_experiment": "Pro testování platformy nebo vývoj nových funkcí",
"form_preview": "Náhled formuláře",
"form_addMsg": "Přidat zprávu",
"admin_getquotaHint": "Zkontrolujte celkovou velikost položek započítanou do kvóty uživatele nebo týmu podle jejich veřejného klíče.",
"admin_performanceProfilingTitle": "Výkon",
"admin_cat_performance": "Výkon",
"redo": "Znovu",
@ -1442,4 +1436,4 @@
"ui_archive": "Archivovat",
"ui_undefined": "neznámý",
"admin_documentType": "Typ"
}
}

View File

@ -866,7 +866,7 @@
"settings_safeLinksHint": "CryptPad fügt den Dokumenten-Links die Schlüssel zum Entschlüsseln der Inhalte hinzu. Jeder, der Zugriff auf den Browserverlauf hat, kann möglicherweise die Daten lesen. Dazu gehören Browsererweiterungen und Browser, die den Verlauf geräteübergreifend synchronisieren. Die Aktivierung von \"sicheren Links\" verhindert, dass die Schlüssel in den Browserverlauf gelangen oder in der Adressleiste angezeigt werden, wann immer dies möglich ist. Wir empfehlen dringend, diese Funktion zu aktivieren und das Menü {0} Teilen zu verwenden, um für die Weitergabe geeignete Links zu erstellen.",
"dontShowAgain": "Nicht mehr anzeigen",
"profile_login": "Du musst dich einloggen, um diesen Benutzer zu deinen Kontakten hinzuzufügen",
"safeLinks_error": "Dieser Link wurde aus der Adresszeile des Browsers kopiert und ermöglicht keinen Zugriff auf das Dokument. Bitte verwende das Menü <b>Teilen</b>, um das Dokument direkt mit Kontakten zu teilen oder den Link zu kopieren. <a>Mehr zu sicheren Links</a>.",
"safeLinks_error": "Dieser Link wurde aus der Adresszeile des Browsers kopiert und ermöglicht keinen Zugriff auf das Dokument. Bitte verwende das Menü <i></i> <b>Teilen</b>, um das Dokument direkt mit Kontakten zu teilen oder den Link zu kopieren. <a>Mehr zu sicheren Links</a>.",
"settings_safeLinksCheckbox": "Sichere Links aktivieren",
"settings_safeLinksTitle": "Sichere Links",
"settings_trimHistoryHint": "Spare Speicherplatz, indem du den Verlauf deines CryptDrives und der Benachrichtigungen löschst. Dies hat keinen Einfluss auf den Verlauf deiner Dokumente. Du kannst den Verlauf der Dokumente in deren Eigenschaften-Dialog löschen.",
@ -1058,10 +1058,7 @@
"download_zip_file": "Datei {0}/{1}",
"archivedFromServer": "Dokument archiviert",
"restoredFromServer": "Dokument wiederhergestellt",
"admin_archiveInval": "Ungültiges Dokument",
"admin_unarchiveButton": "Wiederherstellen",
"admin_unarchiveTitle": "Dokumente wiederherstellen",
"admin_archiveTitle": "Dokumente archivieren",
"history_trimPrompt": "Dieses Dokument hat einen Verlauf von {0} angesammelt, was das Laden verlangsamen kann. Ziehe in Betracht, den Verlauf zu löschen, sofern er nicht benötigt wird.",
"contacts_confirmCancel": "Bist du sicher, dass du die Kontaktanfrage an <b>{0}</b> zurücknehmen möchtest?",
"admin_support_collapse": "Einklappen",
@ -1095,7 +1092,6 @@
"admin_performanceKeyHeading": "Befehl",
"settings_colortheme_custom": "Benutzerdefiniert",
"pad_settings_show": "Anzeigen",
"admin_getquotaButton": "Überprüfen",
"settings_colorthemeTitle": "Farbschema",
"settings_colortheme_default": "Systemstandard ({0})",
"settings_colortheme_light": "Hell",
@ -1109,8 +1105,6 @@
"pad_settings_outline": "Wähle aus, ob das Inhaltsverzeichnis standardmäßig angezeigt werden soll.",
"pad_settings_width_large": "Volle Breite",
"pad_settings_info": "Standardeinstellungen für dieses Dokument. Sie werden angewendet, wenn neue Benutzer dieses Dokument aufrufen.",
"admin_getquotaHint": "Überprüfe anhand des öffentlichen Schlüssels die Gesamtgröße aller Elemente, die der Quota eines Benutzers oder Teams angerechnet werden.",
"admin_getquotaTitle": "Speicherbelegung von Accounts überprüfen",
"addOptionalPassword": "Passwort hinzufügen (optional)",
"oo_lostEdits": "Leider konnten deine letzten ungespeicherten Bearbeitungen nach dem Synchronisieren neuer Inhalte nicht wiederhergestellt werden.",
"fm_cantUploadHere": "Hochladen hier nicht möglich",
@ -1466,12 +1460,12 @@
"admin_documentSize": "Größe",
"admin_currentlyOnline": "Ist derzeit online",
"admin_currentlyOpen": "Derzeit geöffnet",
"admin_documentMetadataHint": "Abfrage eines Kanals oder einer Datei über ihre ID oder URL",
"admin_documentMetadataHint": "Abfrage eines Dokuments oder einer Datei über ihre ID oder URL",
"admin_reportContent": "Inhalt des Berichts",
"admin_planlimit": "Speicherbegrenzung",
"admin_channelCount": "Anzahl der Kanäle",
"admin_channelCount": "Anzahl der Dokumente",
"admin_channelArchived": "Kanal wurde archiviert",
"admin_channelAvailable": "Kanal ist verfügbar",
"admin_channelAvailable": "Verfügbar",
"admin_accountMetadataHint": "Gib den öffentlichen Schlüssel eines Benutzers ein, um Daten über den Account abzurufen.",
"ui_fetch": "Abrufen",
"admin_blockKey": "Öffentlicher Schlüssel des Blocks",
@ -1480,5 +1474,18 @@
"admin_blockArchived": "Block wurde archiviert",
"admin_blockAvailable": "Block ist verfügbar",
"admin_blockMetadataPlaceholder": "Absolute oder relative URL des Blocks",
"admin_blockMetadataHint": "Der Login-Block ermöglicht es einem Account, sich bei CryptPad mit der Kombination aus Benutzername und Passwort anzumelden"
"admin_blockMetadataHint": "Der Login-Block ermöglicht es einem Account, sich bei CryptPad mit der Kombination aus Benutzername und Passwort anzumelden",
"admin_blockMetadataTitle": "Login-Block-Informationen",
"admin_documentMetadataTitle": "Dokument-Informationen",
"admin_accountMetadataTitle": "Account-Informationen",
"admin_uptimeHint": "Datum und Uhrzeit des Serverstarts",
"ui_none": "kein(e)",
"admin_getRawMetadata": "Historie der Metadaten",
"og_encryptedAppType": "Verschlüsselt: {0}",
"og_pricing": "{0}: Preise und Konditionen",
"og_features": "{0}: Funktionen",
"og_contact": "{0}: Kontakt",
"og_teamDrive": "Team-Drive",
"og_default": "CryptPad: Ende-zu-Ende-verschlüsselte Suite zur Zusammenarbeit",
"ui_jsRequired": "JavaScript muss aktiviert sein, um die Verschlüsselung in deinem Browser zu ermöglichen"
}

View File

@ -484,12 +484,12 @@
"uploadFolder_modal_owner": "Archivos de propiedad",
"uploadFolder_modal_forceSave": "Almacene sus archivos en su CryptDrive",
"upload_notEnoughSpaceBrief": "Sin espacio suficiente",
"upload_tooLargeBrief": "El archivo supera el límite de {0}MB",
"upload_tooLargeBrief": "El archivo supera el límite de {0}MB para esta unidad",
"upload_up": "Subir",
"download_dl": "Descargar",
"download_step1": "Descargando",
"download_step2": "Descifrando",
"pad_base64": "Este Pad contiene imágenes almacenadas de manera ineficiente. Estas imágenes aumentarán significativamente el tamaño de la Pad en su CryptDrive y harán que la carga sea más lenta. Puede migrar estos archivos a un nuevo formato que se almacenará por separado en su CryptDrive. ¿Desea migrar estas imágenes ahora?",
"pad_base64": "Este documento contiene imágenes almacenadas de manera ineficiente. Estas imágenes aumentarán significativamente el tamaño del documento en su CryptDrive y harán que la carga sea más lenta. Puede migrar estos archivos a un nuevo formato que se almacenará por separado en su CryptDrive. ¿Desea migrar estas imágenes ahora?",
"mdToolbar_defaultText": "Su texto aqui",
"mdToolbar_help": "Ayuda",
"mdToolbar_tutorial": "https://www.markdowntutorial.com/es/",
@ -516,14 +516,14 @@
"features_f_file0": "Abrir documentos",
"features_f_file0_note": "Ver y descargar documentos compartidos por otros usuarios",
"features_f_cryptdrive0": "Acceso limitado a CryptDrive",
"features_f_cryptdrive0_note": "Posibilidad de almacenar los pads visitados en su navegador para poder abrirlos más tarde",
"features_f_cryptdrive0_note": "Posibilidad de almacenar los documentos visitados en su navegador para poder abrirlos más tarde",
"features_f_storage0": "Tiempo de almacenamiento limitado",
"features_f_storage0_note": "Los documentos se eliminan después de {0} días de inactividad",
"features_f_anon": "Todas las funciones de invitado",
"features_f_anon_note": "Con funcionalidad adicional",
"features_f_cryptdrive1": "Funcionalidad completa de CryptDrive",
"features_f_cryptdrive1_note": "Carpetas, compartir carpetas, plantillas, tareas",
"features_f_devices": "Tus pads en todos tus dispositivos",
"features_f_devices": "Tus documentos en todos tus dispositivos",
"features_f_devices_note": "Acceda a su CryptDrive en todas partes con su cuenta de usuario",
"features_f_social": "Características sociales",
"features_f_social_note": "Añadir contactos para una colaboración segura, crear un perfil, controles de acceso detallados",
@ -547,17 +547,17 @@
"storageStatus": "Almacenamiento:<br><b>{0}</b> usado de <b>{1}</b>",
"settings_cursorColorTitle": "Color de puntero",
"mdToolbar_button": "Mostrar u ocultar la barra de herramientas de Markdown",
"creation_404": "Este pad ya no existe. Utilice el siguiente formulario para crear un nuevo pad.",
"creation_404": "Este documento ya no existe. Utilice el siguiente formulario para crear un nuevo documento.",
"creation_owned1": "Un objeto <b>propiedad</b> puede ser destruido cuando el propietario lo desee. La destrucción de un objeto propio hace que no esté disponible en los CryptDrives de otros usuarios.",
"settings_padNotifTitle": "Notificaciones de comentarios",
"password_info": "El documento que intenta abrir no existe o está protegido con una contraseña. Ingrese la contraseña correcta para acceder a su contenido.",
"creation_newPadModalDescription": "Haz click en un tipo de documento para crearlo. Tú también puedes presionar <b>Tab</b> para seleccionar el tipo y presiona <b>Enter</b> para confirmar.",
"creation_newPadModalDescription": "Haz clic en una aplicación para crear un nuevo documento. Tú también puedes presionar <b>Tab</b> para seleccionar la aplicación y presiona <b>Enter</b> para confirmar.",
"toolbar_degraded": "Actualmente hay más de {0} editores en este documento. La lista de usuarios y el chat están desactivados para mejorar el rendimiento.",
"oo_lostEdits": "Lamentablemente, las ediciones recientes no guardadas no se pueden recuperar después de sincronizar el nuevo contenido.",
"properties_passwordError": "Se ha producido un error al intentar cambiar la contraseña. Por favor, inténtelo de nuevo.",
"properties_passwordSame": "Las nuevas contraseñas deben diferir de la actual.",
"properties_confirmChange": "¿Está seguro? Al cambiar la contraseña se eliminará su historial. Los usuarios que no tengan la nueva contraseña perderán el acceso a este pad",
"properties_confirmNew": "¿Está seguro? Añadir una contraseña cambiará la URL de este pad y eliminará su historial. Los usuarios sin la contraseña perderán el acceso a este pad",
"properties_confirmChange": "¿Está seguro? Al cambiar la contraseña se eliminará su historial. Los usuarios que no tengan la nueva contraseña perderán el acceso a este documento",
"properties_confirmNew": "¿Está seguro? Añadir una contraseña cambiará la URL de este documento y eliminará su historial. Los usuarios sin la contraseña perderán el acceso a este documento",
"properties_changePassword": "Cambiar la contraseña",
"properties_addPassword": "Añadir una contraseña",
"password_submit": "Enviar",
@ -575,10 +575,10 @@
"creation_expireDays": "Día(s)",
"creation_expireHours": "Hora(s)",
"creation_expireFalse": "Ilimitado",
"creation_expire": "Pad expirando",
"creation_owned": "Pad propio",
"creation_expire": "Documento expirando",
"creation_owned": "Documento propio",
"share_linkCategory": "Enlace",
"sharedFolders_forget": "Este bloc sólo se almacena en una carpeta compartida, no puedes moverlo a la papelera. Puedes usar tu CryptDrive si quieres borrarlo.",
"sharedFolders_forget": "Este documento sólo se almacena en una carpeta compartida, no puedes moverlo a la papelera. Puedes usar tu CryptDrive si quieres borrarlo.",
"share_mediatagCopy": "Copiar mediatag al portapapeles",
"share_contactCategory": "Contactos",
"share_linkCopy": "Copiar enlace",
@ -586,7 +586,7 @@
"share_linkView": "Ver",
"share_linkEdit": "Editar",
"share_linkAccess": "Permisos de acceso",
"properties_passwordWarning": "La contraseña ha sido cambiada con éxito pero fue incapaz de actualizar tu CryptDrive con los nuevos datos. Es posible que tenga que eliminar la versión antigua del pad manualmente.<br>Pulse OK para recargar y actualizar sus derechos de acceso.",
"properties_passwordWarning": "La contraseña ha sido cambiada con éxito pero fue incapaz de actualizar tu CryptDrive con los nuevos datos. Es posible que tenga que eliminar la versión antigua del documento manualmente.<br>Pulse OK para recargar y actualizar sus derechos de acceso.",
"properties_passwordSuccess": "La contraseña ha sido cambiada con éxito.<br>Pulsa OK para recargar y actualizar tus derechos de acceso.",
"admin_updateLimitTitle": "Actualizar cuotas de usuarios",
"admin_registeredHint": "Número de usuarios registrados en tu instancia",
@ -687,5 +687,33 @@
"calendar_update": "Actualizar",
"admin_support_last": "Actualizado el: ",
"ui_restore": "Recuperar",
"admin_documentType": "Tipo"
}
"admin_documentType": "Tipo",
"admin_supportInitHint": "Puedes configurar un buzón de soporte para que los usuarios de tu instancia de CryptPad puedan ponerse en contacto contigo de forma segura si tienen un problema con su cuenta.",
"admin_supportInitTitle": "Apoyar la inicialización del buzón",
"admin_supportAddError": "Clave privada no válida",
"admin_supportAddKey": "Añadir clave privada",
"admin_supportInitPrivate": "Tu instancia de CryptPad está configurada para utilizar un buzón de soporte, pero tu cuenta no tiene la clave privada correcta para acceder a él. Utiliza el siguiente formulario para añadir o actualizar la clave privada a tu cuenta.",
"support_showData": "Mostrar/ocultar los datos del usuario",
"support_remove": "Eliminar el ticket",
"support_close": "Cerrar el ticket",
"support_answer": "Responder",
"support_listHint": "Aquí está la lista de tickets enviados a los administradores y sus respuestas. Un ticket cerrado no puede reabrirse, pero puedes hacer uno nuevo. Puedes ocultar los tickets que han sido cerrados.",
"support_listTitle": "Tickets de soporte técnico",
"support_cat_tickets": "Tickets existentes",
"support_formMessage": "Escribe tu mensaje…",
"support_formContentError": "Error: el contenido está vacío",
"support_formTitleError": "Error: el título está vacío",
"support_formButton": "Enviar",
"support_formHint": "Utiliza este formulario para ponerte en contacto de forma segura con los administradores sobre cuestiones y preguntas.<br>Por favor, ten en cuenta que algunas cuestiones/preguntas pueden estar ya tratadas en la <a>Guía del Usuario de CryptPad</a>. Por favor, evita crear un nuevo ticket si ya tienes un ticket abierto sobre el mismo tema. En su lugar, responde a tu mensaje original con cualquier información adicional.",
"admin_supportInitHelp": "Tu servidor aún no está configurado para tener un buzón de soporte. Si quieres un buzón de soporte para recibir mensajes de tus usuarios, debes pedirle al administrador de tu servidor que ejecute el script ubicado en «./scripts/generate-admin-keys.js», para luego almacenar la clave pública en el archivo «config.js» y enviarte la clave privada.",
"supportPage": "Soporte",
"admin_cat_support": "Soporte",
"fm_info_sharedFolderHistory": "Esto es sólo el historial de tu carpeta compartida: <b>{0}</b><br>Tu CryptDrive permanecerá en modo de sólo lectura durante la navegación.",
"share_linkFriends": "Compartir con los contactos",
"share_filterFriend": "Buscar por nombre",
"notification_folderShared": "{0} ha compartido una carpeta contigo: <b>{1}</b>",
"notification_fileShared": "{0} ha compartido un archivo contigo: <b>{1}</b>",
"notification_padShared": "{0} ha compartido un documento contigo: <b>{1}</b>",
"isNotContact": "{0} <b>no</b> es uno de tus contactos",
"isContact": "{0} es uno de tus contactos"
}

View File

@ -1113,9 +1113,6 @@
"pad_settings_width_small": "Orrialde modua",
"pad_settings_info": "Dokumentu honen ezarpen lehenetsiak. Erabiltzaile berriek dokumentu hau bisitatzen dutenean aplikatuko dira.",
"pad_settings_title": "Dokumentuen ezarpenak",
"admin_getquotaButton": "Egiaztatu",
"admin_getquotaHint": "Egiaztatu gako publikoa kontuan hartuta erabiltzaile edo talde baten kuotarekin zenbatutako elementuen guztizko tamaina.",
"admin_getquotaTitle": "Egiaztatu kontuaren biltegiratzea",
"settings_colorthemeTitle": "Itxuraren kolorea",
"settings_colorthemeHint": "Aldatu CryptPad-en kolore orokorrak gailu honetan.",
"settings_colortheme_default": "Sistemak lehenetsia ({0})",
@ -1167,15 +1164,12 @@
"allowNotifications": "Gaitu jakinarazpenak",
"archivedFromServer": "Dokumentua artxibatu da",
"restoredFromServer": "Dokumentua berreskuratu da",
"admin_archiveInval": "Dokumentu baliogabea",
"admin_archiveInput2": "Dokumentuaren pasahitza",
"admin_archiveInput": "Dokumentuaren URLa",
"admin_unarchiveButton": "Berreskuratu",
"admin_unarchiveHint": "Leheneratu aurretik artxibatuta zegoen dokumentu bat",
"admin_unarchiveTitle": "Berreskuratu dokumentuak",
"admin_archiveButton": "Artxibo",
"admin_archiveHint": "Egin dokumentu bat ez-erabilgarri behin betiko ezabatu gabe. 'Artxibo' direktorio batean jarriko da eta egun batzuen buruan ezabatuko da (zerbitzariaren ezarpenen fitxategian konfigura daiteke).",
"admin_archiveTitle": "Dokumentuak gordetzea",
"errorPopupBlocked": "CryptPad-ek fitxa berriak ireki ahal izan behar ditu funtzionatzeko. Baimendu popup-leihoak zure nabigatzailean. Leiho hauek ez dira inoiz erabiliko zuri publizitatea erakusteko.",
"unableToDisplay": "Ezin da dokumentua erakutsi. Sakatu Esc orria berriro kargatzeko. Arazoak jarraitzen badu, jarri harremanetan laguntzarekin.",
"documentID": "Dokumentua identifikatzea",

View File

@ -1059,15 +1059,12 @@
"allowNotifications": "Salli ilmoitukset",
"archivedFromServer": "Asiakirja arkistoitu",
"restoredFromServer": "Asiakirja palautettu",
"admin_archiveInval": "Virheellinen asiakirja",
"admin_archiveInput2": "Asiakirjan salasana",
"admin_archiveInput": "Asiakirjan URL",
"admin_unarchiveButton": "Palauta",
"admin_unarchiveHint": "Palauta aiemmin arkistoitu asiakirja",
"admin_unarchiveTitle": "Palauta asiakirjoja",
"admin_archiveButton": "Arkistoi",
"admin_archiveHint": "Estä asiakirjan käyttö poistamatta sitä lopullisesti. Asiakirja sijoitetaan arkistokansioon ja poistetaan sieltä muutaman päivän kuluttua (poistoaika säädettävissä palvelimen konfiguraatiotiedostosta).",
"admin_archiveTitle": "Arkistoi asiakirjoja",
"errorPopupBlocked": "CryptPadin täytyy pystyä avaamaan uusia välilehtiä toimiakseen. Ole hyvä ja salli ponnahdusikkunat selaimesi osoitekentästä. Ponnahdusikkunoita ei koskaan käytetä mainostamiseen.",
"unableToDisplay": "Asiakirjan näyttäminen epäonnistui. Paina Esc-näppäintä ladataksesi sivun uudelleen. Jos ongelma ei ratkea, ota yhteyttä käyttäjätukeen.",
"documentID": "Asiakirjan tunniste",
@ -1080,4 +1077,4 @@
"ui_archive": "Arkistoi",
"ui_undefined": "tuntematon",
"admin_documentType": "Tyyppi"
}
}

View File

@ -1049,15 +1049,12 @@
"allowNotifications": "Autoriser les notifications",
"archivedFromServer": "Document archivé",
"restoredFromServer": "Document restauré",
"admin_archiveInval": "Document invalide",
"admin_archiveInput2": "Mot de passe du document",
"admin_archiveInput": "URL du document",
"admin_unarchiveButton": "Restaurer",
"admin_unarchiveHint": "Restaurer un document qui avait été précédemment archivé",
"admin_unarchiveTitle": "Restaurer les documents",
"admin_archiveButton": "Archiver",
"admin_archiveHint": "Rendre un document indisponible sans le supprimer définitivement. Il sera placé dans un répertoire \"archive\" et supprimé après quelques jours (configurable dans le fichier de configuration du serveur).",
"admin_archiveTitle": "Archiver les documents",
"mediatag_loadButton": "Charger la pièce jointe",
"history_trimPrompt": "Ce document a accumulé {0} d'historique qui peut ralentir le temps de chargement. Envisagez de supprimer l'historique s'il n'est pas nécessaire.",
"contacts_confirmCancel": "Êtes-vous sûr de vouloir annuler votre demande de contact avec <b>{0}</b> ?",
@ -1091,9 +1088,6 @@
"pad_settings_width_small": "Mode page",
"pad_settings_info": "Paramètres par défaut pour ce document. Ils seront appliqués lorsque de nouveaux utilisateurs visiteront ce document.",
"pad_settings_title": "Paramètres du document",
"admin_getquotaButton": "Vérifier",
"admin_getquotaHint": "Vérifier la taille totale des documents comptabilisés dans le quota d'un utilisateur ou d'une équipe, en fonction de leur clé publique.",
"admin_getquotaTitle": "Vérifier le stockage d'un compte",
"settings_colorthemeTitle": "Thème",
"settings_colorthemeHint": "Changer les couleurs de CryptPad sur cet appareil.",
"settings_colortheme_default": "Défaut système ({0})",
@ -1443,5 +1437,66 @@
"ui_restore": "Restaurer",
"ui_archive": "Archiver",
"ui_undefined": "inconnu",
"admin_documentType": "Type"
}
"admin_documentType": "Type",
"ui_jsRequired": "JavaScript doit être activé pour effectuer le chiffrement dans votre navigateur",
"admin_uptimeTitle": "Temps de lancement",
"admin_uptimeHint": "Date et heure auxquelles le serveur a été lancé",
"admin_cat_database": "Base de données",
"admin_generatedAt": "Horodatage du rapport",
"ui_true": "vrai",
"ui_false": "faux",
"ui_none": "aucun",
"ui_generateReport": "Générer un rapport",
"ui_success": "Succès",
"ui_fetch": "Charger",
"ui_confirm": "Confirmer",
"admin_archiveReason": "Veuillez préciser la raison de l'archivage et confirmer que vous souhaitez poursuivre",
"admin_restoreReason": "Veuillez préciser la raison de la restitution et confirmer que vous souhaitez poursuivre",
"admin_accountMetadataTitle": "Informations sur un compte",
"admin_accountMetadataHint": "Saisissez la clé publique d'un utilisateur pour récupérer des données sur son compte.",
"admin_documentMetadataTitle": "Informations sur un document",
"admin_documentMetadataHint": "Informations sur un document ou un fichier depuis son id ou son URL",
"admin_documentSize": "Taille du document",
"admin_documentMetadata": "Métadonnées actuelles",
"admin_documentCreationTime": "Créé",
"admin_documentModifiedTime": "Dernière modification",
"admin_currentlyOpen": "Actuellement ouvert",
"admin_channelAvailable": "Disponible",
"admin_channelArchived": "Archivé",
"admin_documentMetadataPlaceholder": "URL ou id du document",
"admin_blockMetadataTitle": "Informations sur le blocage",
"admin_blockMetadataHint": "Le bloc de connexion est ce qui permet à un compte de se connecter à CryptPad avec la combinaison de nom d'utilisateur et de mot de passe",
"admin_blockMetadataPlaceholder": "URL absolue ou logique",
"admin_accountMetadataPlaceholder": "Utilisateur id (clé publique de signature)",
"admin_firstPinTime": "Première durée d'activité de la broche",
"admin_lastPinTime": "Dernière période d'activité de la broche",
"admin_currentlyOnline": "Est actuellement en ligne",
"admin_planName": "Nom du plan",
"admin_note": "Note de plan",
"admin_storageUsage": "Données stockées",
"admin_channelCount": "Nombre de documents",
"admin_fileCount": "Nombre de fichiers",
"admin_pinLogAvailable": "Liste des documents est disponible",
"admin_pinLogArchived": "Liste des documents est archivée",
"admin_blockKey": "Clé publique de bloc",
"admin_blockAvailable": "Le bloc est disponible",
"admin_blockArchived": "Le bloc est archivé",
"admin_archiveBlock": "Archiver le bloc",
"admin_restoreBlock": "Restaurer le bloc archivé",
"admin_getPinList": "Liste des documents stockés",
"admin_archivePinLog": "Archiver la liste des documents",
"admin_restoreArchivedPins": "Restaurer la liste des documents",
"admin_archiveDocument": "Archiver le document",
"admin_restoreDocument": "Restaurer le document",
"admin_planlimit": "Limite de stockage",
"admin_reportContent": "Contenu du rapport",
"admin_getRawMetadata": "Historique des métadonnées",
"og_teamDrive": "Circulation d'équipe",
"og_default": "CryptPad : suite de collaboration chiffrée de bout en bout",
"og_login": "Connectez-vous à {0}",
"og_register": "Enregistrer un compte à {0}",
"og_contact": "{0} Contact",
"og_pricing": "{0} Tarification",
"og_features": "{0} Fonctionnalités",
"og_encryptedAppType": "Chiffré {0}"
}

View File

@ -924,7 +924,6 @@
"mediatag_saveButton": "Salva",
"download_zip_file": "File {0}/{1}",
"allowNotifications": "Permetti notifiche",
"admin_archiveInval": "Documento non valido",
"admin_archiveInput": "URL del documento",
"tag_edit": "Modifica",
"tag_add": "Aggiungi",
@ -1020,10 +1019,8 @@
"admin_archiveInput2": "Password del documento",
"admin_unarchiveButton": "Ripristina",
"admin_unarchiveHint": "Ripristina un documento che era stato precedentemente archiviato",
"admin_unarchiveTitle": "Ripristina documenti",
"admin_archiveButton": "Archivio",
"admin_archiveHint": "Rendi un documento non disponibile senza eliminarlo definitivamente. Verrà inserito in una cartella 'archivio' e cancellato dopo alcuni giorni (configurabile nel file di configurazione del server).",
"admin_archiveTitle": "Archivia documenti",
"errorPopupBlocked": "CryptPad deve essere in grado di aprire nuove schede per funzionare. Si prega di consentire le finestre popup nella barra degli indirizzi del browser. Queste finestre non verranno mai utilizzate per mostrarti pubblicità.",
"unableToDisplay": "Impossibile visualizzare il documento. Premi Esc per ricaricare la pagina. Se il problema persiste, contatta l'assistenza.",
"documentID": "Identificatore del documento",
@ -1088,4 +1085,4 @@
"ui_archive": "Archivio",
"ui_undefined": "sconosciuto",
"admin_documentType": "Tipo"
}
}

View File

@ -461,11 +461,8 @@
"allowNotifications": "通知を許可",
"archivedFromServer": "ドキュメントがアーカイブされました",
"restoredFromServer": "ドキュメントが復元されました",
"admin_archiveInval": "無効なドキュメント",
"admin_archiveInput2": "ドキュメントのパスワード",
"admin_archiveInput": "ドキュメントのURL",
"admin_unarchiveTitle": "ドキュメントを復元",
"admin_archiveTitle": "ドキュメントをアーカイブ",
"fm_deletedFolder": "削除されたフォルダ",
"history_restoreDriveDone": "CryptDriveが復元されました",
"share_bar": "リンクを作成",
@ -811,9 +808,7 @@
"pad_settings_width_small": "ページモード",
"pad_settings_info": "このドキュメントの既定の設定です。新しいユーザーがドキュメントを閲覧したときに適用されます。",
"pad_settings_title": "ドキュメントの設定",
"admin_getquotaTitle": "アカウントのストレージを確認",
"settings_colorthemeTitle": "テーマ色",
"admin_getquotaButton": "確認",
"fm_cantUploadHere": "ここにはファイルをアップロードできません",
"settings_resetTipsDone": "全てのヒントが表示されます。",
"settings_resetTipsButton": "利用可能なCryptDriveのヒントをリセット",
@ -1240,7 +1235,7 @@
"form_type_multicheck": "チェックボックス式グリッド",
"form_type_multiradio": "選択式グリッド",
"form_type_sort": "番号付きリスト",
"safeLinks_error": "このリンクはブラウザーのアドレスバーからコピーされており、ドキュメントにアクセスすることはできません。<b>共有</b>メニューを使って、連絡先と直接ドキュメントを共有するか、リンクをコピーしてください。<a>セーフリンク機能についてはこちらよりご確認ください</a>。",
"safeLinks_error": "このリンクはブラウザーのアドレスバーからコピーされており、ドキュメントにアクセスすることはできません。<i></i> <b>共有</b>メニューを使って、連絡先と直接ドキュメントを共有するか、リンクをコピーしてください。<a>セーフリンク機能についてはこちらよりご確認ください</a>。",
"team_cat_general": "チームについて",
"team_ownerConfirm": "共同オーナーはチームを変更もしくは削除したり、あなたをオーナーから削除したりすることができます。続行してよろしいですか?",
"owner_request_accepted": "{0}はあなたのリクエストを承諾し、「<b>{1}</b>」のオーナーになりました",
@ -1269,7 +1264,6 @@
"admin_registrationTitle": "登録を締め切る",
"admin_defaultlimitHint": "ユーザー定義のルールが適用されていない際の最大のストレージ容量(ユーザーとチームについて)を設定できます",
"admin_limit": "現在の制限: {0}",
"admin_getquotaHint": "ユーザーもしくはチームの公開鍵を入力して、設定されているクォータに対するストレージの使用量を確認できます。",
"admin_openFilesHint": "サーバー上で現在開いているファイル記述子の数",
"admin_support_premium": "プレミアムチケット:",
"admin_maintenanceHint": "このインスタンスのメンテナンスの日程を設定し、ユーザーに通知を送ることができます。メンテナンスの日程を複数設定することはできません。",
@ -1441,20 +1435,20 @@
"ui_undefined": "不明",
"admin_documentType": "ドキュメントの種類",
"admin_documentMetadataTitle": "ドキュメントの情報",
"admin_documentMetadataHint": "IDもしくはURLでチャンネルあるいはファイルを検索",
"admin_documentMetadataHint": "IDもしくはURLでドキュメントあるいはファイルを検索",
"admin_documentModifiedTime": "最新更新日時",
"admin_accountMetadataPlaceholder": "ユーザーID署名用の公開鍵",
"admin_storageUsage": "保存されたデータ",
"admin_planName": "プラン名",
"admin_currentlyOnline": "は現在オンラインです",
"admin_channelCount": "チャンネル数",
"admin_channelCount": "ドキュメント数",
"admin_fileCount": "ファイル数",
"admin_archiveDocument": "ドキュメントをアーカイブ",
"admin_restoreDocument": "ドキュメントを復元",
"admin_planlimit": "ストレージの制限",
"admin_documentMetadataPlaceholder": "ドキュメントのURLあるいはID",
"admin_channelArchived": "チャンネルはアーカイブされています",
"admin_channelAvailable": "チャンネルは利用可能です",
"admin_channelArchived": "アーカイブ済",
"admin_channelAvailable": "利用可能",
"admin_documentCreationTime": "作成",
"admin_documentMetadata": "現在のメタデータ",
"admin_documentSize": "ドキュメントのサイズ",
@ -1473,5 +1467,33 @@
"home_morestorage": "より多くのストレージ容量が必要な場合:",
"admin_noticeTitle": "トップページでの通知",
"admin_noticeHint": "トップページに表示するメッセージ(オプション)",
"error_evalPermitted": "evalが許可されないため、中止します。\n\nこのエラーはContent-Security-Policyのヘッダーに関係しています。理由は、ヘッダーをサポートしない旧バージョンのブラウザー、適切な動作を防ぐブラウザーの拡張機能のため、もしくは、このCryptPadのインスタンスが適切に設定されていないことが考えられます。"
"error_evalPermitted": "evalが許可されないため、中止します。\n\nこのエラーはContent-Security-Policyのヘッダーに関係しています。理由は、ヘッダーをサポートしない旧バージョンのブラウザー、適切な動作を防ぐブラウザーの拡張機能のため、もしくは、このCryptPadのインスタンスが適切に設定されていないことが考えられます。",
"admin_pinLogAvailable": "ピンのログは利用可能です",
"admin_pinLogArchived": "ピンのログはアーカイブされています",
"admin_blockMetadataHint": "ログインブロックは、CryptPadにログインするためのユーザー名とパスワードの組み合わせのことです",
"admin_blockMetadataTitle": "ログインブロックに関する情報",
"admin_accountMetadataHint": "ユーザーの公開鍵を入力すると、ユーザーのアカウントに関するデータを取得できます。",
"admin_reportContent": "内容を報告",
"admin_getRawMetadata": "メタデータの履歴",
"admin_restoreArchivedPins": "アーカイブ済のピンログを復元",
"admin_archivePinLog": "このアカウントのピンログをアーカイブ",
"admin_getPinList": "現在のピンリスト",
"admin_note": "プランのメモ",
"og_encryptedAppType": "暗号化された {0}",
"og_features": "{0} 機能",
"og_pricing": "{0} 料金",
"og_contact": "{0} 連絡先",
"ui_jsRequired": "ブラウザーで暗号化を行うにはJavaScriptが有効になっている必要があります",
"og_register": "{0}でアカウントを登録",
"og_login": "{0}にログイン",
"og_default": "CryptPadエンドツーエンド暗号化コラボレーションスイート",
"og_teamDrive": "チームドライブ",
"admin_restoreBlock": "アーカイブ済のブロックを復元",
"admin_archiveBlock": "ブロックをアーカイブ",
"admin_blockArchived": "ブロックはアーカイブされています",
"admin_blockAvailable": "ブロックは利用可能です",
"admin_blockKey": "ブロックの公開鍵",
"admin_blockMetadataPlaceholder": "ブロックの絶対または相対URL",
"admin_restoreReason": "復元の理由を指定し、確認して続行してください",
"admin_archiveReason": "アーカイブの理由を指定し、確認して続行してください"
}

View File

@ -865,7 +865,7 @@
"settings_cat_security": "Confidentiality",
"settings_safeLinksTitle": "Safe Links",
"settings_safeLinksCheckbox": "Enable safe links",
"safeLinks_error": "This link was copied from the browser's address bar and does not provide access to the document. Please use the <b>Share</b> menu to share directly with contacts or copy the link. <a> Read more about the Safe Links feature</a>.",
"safeLinks_error": "This link was copied from the browser's address bar and does not provide access to the document. Please use the <i></i> <b>Share</b> menu to share directly with contacts or copy the link. <a> Read more about the Safe Links feature</a>.",
"dontShowAgain": "Don't show again",
"profile_login": "You need to log in to add this user to your contacts",
"settings_safeLinksHint": "CryptPad includes the keys to decrypt your documents in their links. Anyone with access to your browsing history can potentially read your data. This includes intrusive browser extensions and browsers that sync your history across devices. Enabling \"safe links\" prevents the keys from entering your browsing history or being displayed in your address bar whenever possible. We strongly recommend that you enable this feature and use the {0} Share menu to generate shareable links.",
@ -1039,15 +1039,12 @@
"documentID": "Document identifier",
"unableToDisplay": "Unable to display the document. Please press Esc to reload the page. If the problem persists, please contact support.",
"errorPopupBlocked": "CryptPad needs to be able to open new tabs to operate. Please allow popup windows in your browser's address bar. These windows will never be used to show you advertising.",
"admin_archiveTitle": "Archive documents",
"admin_archiveHint": "Make a document unavailable without deleting it permanently. It will be placed in an 'archive' directory and deleted after a few days (configurable in the server configuration file).",
"admin_archiveButton": "Archive",
"admin_unarchiveTitle": "Restore documents",
"admin_unarchiveHint": "Restore a document that had previously been archived",
"admin_unarchiveButton": "Restore",
"admin_archiveInput": "Document URL",
"admin_archiveInput2": "Document password",
"admin_archiveInval": "Invalid document",
"restoredFromServer": "Document restored",
"archivedFromServer": "Document archived",
"allowNotifications": "Allow notifications",
@ -1099,9 +1096,6 @@
"settings_colortheme_default": "System default ({0})",
"settings_colorthemeHint": "Change the overall colors of CryptPad on this device.",
"settings_colorthemeTitle": "Color theme",
"admin_getquotaTitle": "Check account storage",
"admin_getquotaHint": "Check the total size of items counted against a user or team's quota given their public key.",
"admin_getquotaButton": "Check",
"pad_settings_title": "Document Settings",
"pad_settings_info": "Default settings for this document. These will be applied when new users visit this document.",
"pad_settings_width_small": "Page mode",
@ -1459,15 +1453,15 @@
"admin_accountMetadataTitle": "Account information",
"admin_accountMetadataHint": "Enter a user's public key to fetch data about their account.",
"admin_documentMetadataTitle": "Document information",
"admin_documentMetadataHint": "Query a channel or file via its id or URL",
"admin_documentMetadataHint": "Query a document or file via its id or URL",
"admin_documentType": "Document type",
"admin_documentSize": "Document size",
"admin_documentMetadata": "Current metadata",
"admin_documentCreationTime": "Created",
"admin_documentModifiedTime": "Last modified",
"admin_currentlyOpen": "Currently open",
"admin_channelAvailable": "Channel is available",
"admin_channelArchived": "Channel is archived",
"admin_channelAvailable": "Available",
"admin_channelArchived": "Archived",
"admin_documentMetadataPlaceholder": "Document URL or id",
"admin_blockMetadataTitle": "Login-block information",
"admin_blockMetadataHint": "The login block is what allows an account to log in to CryptPad with the combination of username + password",
@ -1479,7 +1473,7 @@
"admin_planName": "Plan name",
"admin_note": "Plan note",
"admin_storageUsage": "Data stored",
"admin_channelCount": "Number of channels",
"admin_channelCount": "Number of documents",
"admin_fileCount": "Number of files",
"admin_pinLogAvailable": "Pin log is available",
"admin_pinLogArchived": "Pin log is archived",
@ -1495,5 +1489,14 @@
"admin_restoreDocument": "Restore document",
"admin_planlimit": "Storage limit",
"admin_reportContent": "Report content",
"admin_getRawMetadata": "Metadata history"
"admin_getRawMetadata": "Metadata history",
"og_teamDrive": "Team drive",
"og_default": "CryptPad: end-to-end encrypted collaboration suite",
"og_login": "Log in to {0}",
"og_register": "Register an account on {0}",
"og_contact": "{0} Contact",
"og_pricing": "{0} Pricing",
"og_features": "{0} Features",
"ui_jsRequired": "JavaScript must be enabled to perform encryption in your browser",
"og_encryptedAppType": "Encrypted {0}"
}

View File

@ -196,5 +196,8 @@
"poll_userPlaceholder": "Vardas",
"poll_optionPlaceholder": "Pasirinkimai",
"poll_commit": "Pateikti",
"poll_create_option": "Pridėti naują parinktį"
"poll_create_option": "Pridėti naują parinktį",
"error_unhelpfulScriptError": "Scenarijaus klaida: daugiau informacijos rasite naršyklės konsolėje",
"tag_edit": "Pakeisti",
"tag_add": "Pridėti"
}

View File

@ -435,7 +435,6 @@
"pad_settings_hide": "Skjul",
"pad_settings_width_large": "Full bredde",
"pad_settings_title": "Dokumentinnstillinger",
"admin_getquotaButton": "Sjekk",
"settings_colorthemeTitle": "Fargedrakt",
"settings_colortheme_light": "Lys",
"settings_colortheme_dark": "Mørk",
@ -463,7 +462,6 @@
"allowNotifications": "Tillat merknader",
"archivedFromServer": "Dokument arkivert",
"restoredFromServer": "Dokument gjenopprettet",
"admin_archiveInval": "Ugyldig dokument",
"admin_archiveInput2": "Dokumentpassord",
"admin_unarchiveButton": "Gjenopprett",
"admin_archiveInput": "Dokument-nettadresse",
@ -631,7 +629,6 @@
"creation_helperText": "Åpne i dokumentasjon",
"creation_expiresIn": "Utløper om",
"mediatag_loadButton": "Last inn vedlegg",
"admin_unarchiveTitle": "Gjenopprett dokumenter",
"documentID": "Dokumentidentifikator",
"loading_state_5": "Rekonstruer dokument",
"loading_state_4": "Last inn lag",
@ -789,4 +786,4 @@
"ui_restore": "Gjenopprett",
"ui_undefined": "ukjent",
"admin_documentType": "Type"
}
}

View File

@ -966,9 +966,6 @@
"pad_settings_width_small": "Tryb strony",
"pad_settings_info": "Domyślne ustawienia dla tego dokumentu. Zostaną one zastosowane, gdy nowi użytkownicy będą odwiedzać ten dokument.",
"pad_settings_title": "Ustawienia dokumentu",
"admin_getquotaButton": "Sprawdź",
"admin_getquotaHint": "Sprawdzanie całkowitego rozmiaru elementów wliczanych do limitu użytkownika lub zespołu na podstawie jego klucza publicznego.",
"admin_getquotaTitle": "Sprawdź miejsce do przechowywania danych na koncie",
"settings_colorthemeTitle": "Motyw kolorystyczny",
"settings_colorthemeHint": "Zmień kolory CryptPada na tym urządzeniu.",
"settings_colortheme_default": "Domyślne ustawienie systemowe ({0})",
@ -1022,15 +1019,12 @@
"allowNotifications": "Zezwól na powiadomienia",
"archivedFromServer": "Zarchiwizowany dokument",
"restoredFromServer": "Przywrócony dokument",
"admin_archiveInval": "Nieprawidłowy dokument",
"admin_archiveInput2": "Hasło do dokumentu",
"admin_archiveInput": "Adres URL dokumentu",
"admin_unarchiveButton": "Przywróc",
"admin_unarchiveHint": "Przywróć dokument, który został wcześniej zarchiwizowany",
"admin_unarchiveTitle": "Przywróć dokumenty",
"admin_archiveButton": "Archiwizuj",
"admin_archiveHint": "Oznacz dokument jako niedostępny bez usuwania go na stałe. Zostanie on umieszczony w katalogu 'archiwum' i usunięty po kilku dniach (można tę opcję zmienić w pliku konfiguracyjnym serwera).",
"admin_archiveTitle": "Archiwizuj dokumenty",
"errorPopupBlocked": "CryptPad musi mieć możliwość otwierania nowych kart, aby mógł działać. Proszę pozwolić na otwieranie wyskakujących okienek w pasku adresu Twojej przeglądarki. Te okna nigdy nie będą używane do pokazywania Ci reklam.",
"unableToDisplay": "Nie można wyświetlić dokumentu. Naciśnij Esc, aby ponownie załadować stronę. Jeśli problem będzie się powtarzał, skontaktuj się z działem pomocy technicznej.",
"documentID": "Identyfikator dokumentu",

View File

@ -1144,15 +1144,12 @@
"allowNotifications": "Permitir notificações",
"archivedFromServer": "Documento arquivado",
"restoredFromServer": "Documento restaurado",
"admin_archiveInval": "Documento inválido",
"admin_archiveInput2": "Senha do documento",
"admin_archiveInput": "URL do documento",
"admin_unarchiveButton": "Restaurar",
"admin_unarchiveHint": "Restaurar um documento arquivado",
"admin_unarchiveTitle": "Restaurar documentos",
"admin_archiveButton": "Arquivar",
"admin_archiveHint": "Tornar um documento indisponível sem apagá-lo permanentemente. Ele será colocado em um diretório de 'arquivo' e excluído após alguns dias (configurável no arquivo de configuração do servidor).",
"admin_archiveTitle": "Arquivar documentos",
"errorPopupBlocked": "O CryptPad precisa ser capaz de abrir novas abas para operar. Por favor, permita janelas popup na barra de endereços do seu navegador. Estas janelas nunca serão usadas para mostrar publicidade.",
"unableToDisplay": "Incapaz de exibir o documento. Por favor, pressione Esc para recarregar a página. Se o problema persistir, favor contatar o suporte.",
"documentID": "Identificador do documento",
@ -1201,7 +1198,6 @@
"form_pollYourAnswers": "Suas respostas",
"form_pollTotal": "Total",
"userlist_visitProfile": "Visitar perfil",
"admin_getquotaButton": "Checar",
"settings_colortheme_light": "Claro",
"settings_colortheme_dark": "Escuro",
"settings_cat_style": "Aparência",
@ -1336,8 +1332,6 @@
"admin_surveyTitle": "Pesquisa",
"toolbar_degraded": "Mais de {0} editores estão atualmente presentes neste documento. A lista de usuários e o chat estão desativados para melhorar o desempenho.",
"pad_settings_title": "Configurações do documento",
"admin_getquotaHint": "Verifique o tamanho total dos itens contados em relação à cota de um usuário ou equipe, dada sua chave pública.",
"admin_getquotaTitle": "Verificar o armazenamento da conta",
"settings_colorthemeTitle": "Tema da cor",
"settings_colorthemeHint": "Mude as cores gerais do CryptPad neste dispositivo.",
"settings_colortheme_default": "Padrão do sistema ({0})",
@ -1386,4 +1380,4 @@
"ui_archive": "Arquivar",
"ui_undefined": "desconhecido",
"admin_documentType": "Tipo"
}
}

View File

@ -1144,15 +1144,12 @@
"allowNotifications": "Permitir notificações",
"archivedFromServer": "Documento arquivado",
"restoredFromServer": "Documento restaurado",
"admin_archiveInval": "Documento inválido",
"admin_archiveInput2": "Senha do documento",
"admin_archiveInput": "URL do documento",
"admin_unarchiveButton": "Restaurar",
"admin_unarchiveHint": "Restaurar um documento arquivado",
"admin_unarchiveTitle": "Restaurar documentos",
"admin_archiveButton": "Arquivar",
"admin_archiveHint": "Tornar um documento indisponível sem apagá-lo permanentemente. Ele será colocado em um diretório de 'arquivo' e excluído após alguns dias (configurável no arquivo de configuração do servidor).",
"admin_archiveTitle": "Arquivar documentos",
"errorPopupBlocked": "O CryptPad precisa ser capaz de abrir novas abas para operar. Por favor, permita janelas popup na barra de endereços do seu navegador. Estas janelas nunca serão usadas para mostrar publicidade.",
"unableToDisplay": "Incapaz de exibir o documento. Por favor, pressione Esc para recarregar a página. Se o problema persistir, favor contatar o suporte.",
"documentID": "Identificador do documento",
@ -1201,7 +1198,6 @@
"form_pollYourAnswers": "Suas respostas",
"form_pollTotal": "Total",
"userlist_visitProfile": "Visitar perfil",
"admin_getquotaButton": "Checar",
"settings_colortheme_light": "Claro",
"settings_colortheme_dark": "Escuro",
"settings_cat_style": "Aparência",
@ -1336,8 +1332,6 @@
"admin_surveyTitle": "Pesquisa",
"toolbar_degraded": "Mais de {0} editores estão atualmente presentes neste documento. A lista de usuários e o chat estão desativados para melhorar o desempenho.",
"pad_settings_title": "Configurações do documento",
"admin_getquotaHint": "Verifique o tamanho total dos itens contados em relação à cota de um usuário ou equipe, dada sua chave pública.",
"admin_getquotaTitle": "Verificar o armazenamento da conta",
"settings_colorthemeTitle": "Tema da cor",
"settings_colorthemeHint": "Mude as cores gerais do CryptPad neste dispositivo.",
"settings_colortheme_default": "Padrão do sistema ({0})",
@ -1389,4 +1383,4 @@
"ui_archive": "Arquivar",
"ui_undefined": "desconhecido",
"admin_documentType": "Tipo"
}
}

View File

@ -543,13 +543,10 @@
"loading_state_3": "Загрузка общих папок",
"documentID": "Идентификатор документа",
"unableToDisplay": "Не могу открыть документ. Пожалуйста, нажмите Esc для обновления страницы. Если проблема сохранится, пожалуйста, обратитесь в поддержку.",
"admin_archiveTitle": "Архивирование документов",
"admin_archiveButton": "Архивировать",
"admin_unarchiveTitle": "Восстановить документы",
"admin_unarchiveHint": "Восстановить ранее архивированный документ",
"admin_unarchiveButton": "Восстановить",
"admin_archiveInput": "URL документа",
"admin_archiveInval": "Неверный документ",
"admin_archiveInput2": "Пароль документа",
"restoredFromServer": "Документ восстановлен",
"archivedFromServer": "Документ архивирован",
@ -1098,9 +1095,6 @@
"pad_settings_width_small": "По ширине страницы",
"pad_settings_info": "Настройки по умолчанию для этого документа. Они будут применяться, когда новые пользователи посетят этот документ.",
"pad_settings_title": "Параметры документа",
"admin_getquotaButton": "Проверить",
"admin_getquotaHint": "Проверьте общий размер элементов, посчитанных по квоте пользователя или команды с учетом их открытого ключа.",
"admin_getquotaTitle": "Проверить хранилище аккаунта",
"settings_colorthemeTitle": "Цветовая тема",
"settings_colorthemeHint": "Измените общие цвета CryptPad на этом устройстве.",
"settings_colortheme_default": "Системное значение по умолчанию ({0})",
@ -1394,4 +1388,4 @@
"ui_archive": "Архивировать",
"ui_undefined": "неизвестный",
"admin_documentType": "Тип"
}
}

View File

@ -1126,20 +1126,14 @@
"admin_openFilesHint": "Кількість файлових дескрипторів, відкритих зараз на вашому сервері.",
"admin_openFilesTitle": "Відкриті файли",
"admin_setlimitButton": "Застосувати межу",
"admin_getquotaButton": "Перевірити",
"admin_getquotaHint": "Звірити сумарну вагу файлів користувачки, користувача чи команди з квотою за їхнім відкритим ключем.",
"admin_getquotaTitle": "Перевірити квоту облікового запису",
"archivedFromServer": "Документ архівовано",
"restoredFromServer": "Документ відновлено",
"admin_archiveInval": "Хибний документ",
"admin_archiveInput2": "Пароль документа",
"admin_archiveInput": "URL-адреса документа",
"admin_unarchiveButton": "Відновити",
"admin_unarchiveHint": "Відновити документ, архівований раніше",
"admin_unarchiveTitle": "Відновити документи",
"admin_archiveButton": "Архівувати",
"admin_archiveHint": "Зробити документ недоступним, не видаляючи його назовсім. Його буде посунуто до каталогу «archive» і видалено за кілька днів (налаштовується файлом конфігурації сервера).",
"admin_archiveTitle": "Архівувати документи",
"admin_limitSetNote": "Примітка",
"admin_limitMB": "Межа (в МБ)",
"admin_limitUser": "Користувацький відкритий ключ",
@ -1166,4 +1160,4 @@
"ui_restore": "Відновити",
"ui_archive": "Архівувати",
"admin_documentType": "Тип"
}
}

View File

@ -1304,9 +1304,6 @@
"pad_settings_width_small": "页面模式",
"pad_settings_info": "本文档的默认设置。 这些将在新用户访问此文档时应用。",
"pad_settings_title": "文档设置",
"admin_getquotaButton": "检查",
"admin_getquotaHint": "根据用户或团队给定的公钥,检查项目的总大小。",
"admin_getquotaTitle": "检查帐户存储",
"settings_colorthemeTitle": "颜色主题",
"settings_colorthemeHint": "更改此设备上 CryptPad 的整体颜色。",
"settings_colortheme_default": "系统默认值 ({0})",
@ -1357,15 +1354,12 @@
"allowNotifications": "允许通知",
"archivedFromServer": "文档已归档",
"restoredFromServer": "文档已恢复",
"admin_archiveInval": "无效文档",
"admin_archiveInput2": "文档密码",
"admin_archiveInput": "文档网址",
"admin_unarchiveButton": "恢复",
"admin_unarchiveHint": "恢复以前存档的文档",
"admin_archiveButton": "归档",
"admin_unarchiveTitle": "恢复文档",
"admin_archiveHint": "在不永久删除文档的情况下使文档不可用。 它将被放置在“存档”目录中,并在几天后删除(可在服务器配置文档中配置)。",
"admin_archiveTitle": "归档文档",
"errorPopupBlocked": "CryptPad 需要能够打开新标签才能操作。 请允许在浏览器的地址栏中弹出窗口。 这些窗口永远不会用于向您展示广告。",
"unableToDisplay": "无法显示文档。 请按 Esc 重新加载页面。 如果问题仍然存在,请联系支持人员。",
"documentID": "文档标识符",
@ -1444,4 +1438,4 @@
"ui_archive": "归档",
"ui_undefined": "未知",
"admin_documentType": "類型"
}
}

View File

@ -0,0 +1,51 @@
var fs = require("fs");
//var en = require("./messages.json");
var others = fs.readdirSync('.').filter(name => {
return /^messages\..+\.json$/.test(name);
});
var suggestions = {
'ui_restore': [
'admin_unarchiveButton',
'fc_restore',
'snapshots_restore',
'settings_restore',
],
ui_archive: [
'admin_archiveButton',
],
ui_undefined: [
'owner_unknownUser',
],
admin_documentType: [
'fm_type',
],
};
others.forEach(n => {
console.log(n);
var path = `./${n}`;
var content = require(path);
Object.keys(suggestions).forEach(k => {
if (content[k]) { return; }
console.log(`${k} is not defined`);
var suggestion;
suggestions[k].some(option => {
if (typeof(content[option]) !== 'string') { return; }
console.log(`\t${option} (${content[option]}) seems like a viable candidate`);
suggestion = option;
return true;
});
if (!suggestion) { return; }
content[k] = content[suggestion];
fs.writeFileSync(path, JSON.stringify(content, null, 4));
});
console.log();
});

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/contacts/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,7 +5,7 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/convert/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -12,9 +12,5 @@
<body class="cp-app-convert">
<div id="cp-toolbar" class="cp-toolbar-container"></div>
<div id="cp-sidebarlayout-container"></div>
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</body>

View File

@ -5,7 +5,7 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.3" rel="stylesheet" type="text/css">

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/debug/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/onlyoffice/main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/onlyoffice/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/drive/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/file/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/form/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -14,9 +14,5 @@
<div id="cp-app-form-editor">
<div id="cp-app-form-container"></div>
</div>
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</body>

View File

@ -1,19 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>CryptPad</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/sframe-app-outer.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>
</iframe>
</body>
</html>

View File

@ -3,7 +3,7 @@
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/kanban/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -8,7 +8,8 @@ This file is intended to be used as a log of what third-party source we have ven
* [jscolor v2.0.5](https://jscolor.com/) for providing a consistent color picker across all browsers
* [jquery.ui 1.12.1](https://jqueryui.com/) for its 'autocomplete' extension which is used for our tag picker
* [pdfjs](https://mozilla.github.io/pdf.js/) with some minor modifications to prevent CSP errors
* [mermaid 9.0.0](https://github.com/mermaid-js/mermaid/releases/tag/8.13.4) extends our markdown integration to support a variety of diagram types
* [mermaid 9.1.6](https://github.com/mermaid-js/mermaid/releases/tag/8.13.4) extends our markdown integration to support a variety of diagram types
* [Fabricjs 4.6.0](https://github.com/fabricjs/fabric.js) and [Fabric-history](https://github.com/lyzerk/fabric-history) for the whiteboard app
* [Requirejs optional module plugin](https://stackoverflow.com/a/27422370)
* [asciidoc.js 2.0.0](https://github.com/asciidoctor/codemirror-asciidoc/releases/tag/2.0.0) with slight changes to match the format of other codemirror modes

View File

@ -0,0 +1,25 @@
Copyright (c) 2010, Ajax.org B.V.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Ajax.org B.V. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,666 @@
// Parts from Ace; see <https://raw.githubusercontent.com/ajaxorg/ace/master/LICENSE>
// Ace highlight rules function imported below.
(function(mod) {
"use strict";
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("cm/lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["cm/lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("asciidoc", function() {
var HighlightRules = function () {
var identifierRe = "[a-zA-Z\u00a1-\uffff]+\\b";
this.$rules = {
"start": [
{token: "empty", regex: /$/},
{token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"},
{token: "literal", regex: /^-{4,}\s*$/, next: "literalBlock"},
{token: "literal", regex: /^\+{4,}\s*$/, next: "passthroughBlock"},
{token: "keyword", regex: /^={4,}\s*$/},
{token: "text", regex: /^\s*$/},
// immediately return to the start mode without matching anything
{token: "empty", regex: "", next: "dissallowDelimitedBlock"}
],
"dissallowDelimitedBlock": [
{include: "paragraphEnd"},
{token: "comment", regex: '^//.+$'},
{token: "keyword", regex: "^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s"},
{include: "listStart"},
{token: "literal", regex: /^\s+.+$/, next: "indentedBlock"},
{token: "empty", regex: "", next: "text"}
],
"paragraphEnd": [
{token: "doc.comment", regex: /^\/{4,}\s*$/, next: "commentBlock"},
{token: "tableBlock", regex: /^\s*[|!]=+\s*$/, next: "tableBlock"},
// open block, ruler
{token: "keyword", regex: /^(?:--|''')\s*$/, next: "start"},
{token: "option", regex: /^\[.*\]\s*$/, next: "start"},
{token: "pageBreak", regex: /^>{3,}$/, next: "start"},
{token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"},
{token: "titleUnderline", regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: "start"},
{token: "singleLineTitle", regex: /^={1,6}\s+\S.*$/, next: "start"},
{token: "otherBlock", regex: /^(?:\*{2,}|_{2,})\s*$/, next: "start"},
// .optional title
{token: "optionalTitle", regex: /^\.[^.\s].+$/, next: "start"}
],
"listStart": [
{
token: "keyword",
regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/,
next: "listText"
},
{token: "meta.tag", regex: /^.+(?::{2,4}|;;)(?: |$)/, next: "listText"},
// continuation
{token: "keyword", regex: /^\+\s*$/, next: "start"}
],
"text": [
{
token: ["link", "link"],
regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/
},
{token: ["link", "link"], regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/},
{token: "link", regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/},
{include: "macros"},
{include: "paragraphEnd"},
{token: "literal", regex: /\+{3,}/, next: "smallPassthrough"},
{
token: "escape",
regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/
},
{token: "escape", regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/},
{token: "keyword", regex: /\s\+$/},
// any word
{token: "text", regex: identifierRe},
{
token: ["keyword", "string", "keyword"],
regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/
},
{token: "keyword", regex: /<<[\w\d\-$]+,?|>>/},
{token: "constant.character", regex: /\({2,3}.*?\){2,3}/},
// List of callouts
{token: "support.function.list.callout", regex: /^(?:<\d+>|\d+>|>) /, next: "text"},
// Anchor
{token: "keyword", regex: /\[\[.+?\]\]/},
// bibliography
{token: "support", regex: /^\[{3}[\w\d =\-]+\]{3}/},
{include: "quotes"},
// text block end
{token: "empty", regex: /^\s*$/, next: "start"}
],
"listText": [
{include: "listStart"},
{include: "text"}
],
"indentedBlock": [
{token: "literal", regex: /^[\s\w].+$/, next: "indentedBlock"},
{token: "literal", regex: "", next: "start"}
],
"listingBlock": [
{token: "literal", regex: /^\.{4,}\s*$/, next: "dissallowDelimitedBlock"},
{token: "constant.numeric", regex: '<\\d+>'},
{token: "literal", regex: '[^<]+'},
{token: "literal", regex: '<'}
],
"literalBlock": [
{token: "literal", regex: /^-{4,}\s*$/, next: "dissallowDelimitedBlock"},
{token: "constant.numeric", regex: '<\\d+>'},
{token: "literal", regex: '[^<]+'},
{token: "literal", regex: '<'}
],
"passthroughBlock": [
{token: "literal", regex: /^\+{4,}\s*$/, next: "dissallowDelimitedBlock"},
{token: "literal", regex: identifierRe + "|\\d+"},
{include: "macros"},
{token: "literal", regex: "."}
],
"smallPassthrough": [
{token: "literal", regex: /[+]{3,}/, next: "dissallowDelimitedBlock"},
{token: "literal", regex: /^\s*$/, next: "dissallowDelimitedBlock"},
{token: "literal", regex: identifierRe + "|\\d+"},
{include: "macros"}
],
"commentBlock": [
{token: "doc.comment", regex: /^\/{4,}\s*$/, next: "dissallowDelimitedBlock"},
{token: "doc.comment", regex: '^.*$'}
],
"tableBlock": [
{token: "tableBlock", regex: /^\s*\|={3,}\s*$/, next: "dissallowDelimitedBlock"},
{token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "innerTableBlock"},
{token: "tableBlock", regex: /\|/},
{include: "text", noEscape: true}
],
"innerTableBlock": [
{token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "tableBlock"},
{token: "tableBlock", regex: /^\s*|={3,}\s*$/, next: "dissallowDelimitedBlock"},
{token: "tableBlock", regex: /\!/}
],
"macros": [
{token: "macro", regex: /{[\w\-$]+}/},
{
token: ["text", "string", "text", "constant.character", "text"],
regex: /({)([\w\-$]+)(:)?(.+)?(})/
},
{
token: ["text", "markup.list.macro", "keyword", "string"],
regex: /(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/
},
{
token: ["markup.list.macro", "keyword", "string"],
regex: /([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/
},
{token: ["markup.list.macro", "keyword"], regex: /([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/},
{token: "keyword", regex: /^:.+?:(?= |$)/}
],
"quotes": [
{token: "string.italic", regex: /__[^_\s].*?__/},
{token: "string.italic", regex: quoteRule("_")},
{token: "keyword.bold", regex: /\*\*[^*\s].*?\*\*/},
{token: "keyword.bold", regex: quoteRule("\\*")},
{token: "literal", regex: /\+\+[^+\s].*?\+\+/},
{token: "literal", regex: quoteRule("\\+")},
{token: "literal", regex: /\$\$.+?\$\$/},
{token: "literal", regex: quoteRule("\\$")},
{token: "literal", regex: /``[^`\s].*?``/},
{token: "literal", regex: quoteRule("`")},
{token: "keyword", regex: /\^[^\^].*?\^/},
{token: "keyword", regex: quoteRule("\\^")},
{token: "keyword", regex: /~[^~].*?~/},
{token: "keyword", regex: quoteRule("~")},
{token: "keyword", regex: /##?/},
{token: "keyword", regex: /(?:\B|^)``|\b''/}
]
};
function quoteRule(ch) {
var prefix = /\w/.test(ch) ? "\\b" : "(?:\\B|^)";
return prefix + ch + "[^" + ch + "].*?" + ch + "(?![\\w*])";
}
//addQuoteBlock("text")
var tokenMap = {
macro: "constant.character",
tableBlock: "doc.comment",
titleUnderline: "markup.heading",
singleLineTitle: "markup.heading",
pageBreak: "string",
option: "string.regexp",
otherBlock: "markup.list",
literal: "support.function",
optionalTitle: "constant.numeric",
escape: "constant.language.escape",
link: "markup.underline.list"
};
for (var state in this.$rules) {
var stateRules = this.$rules[state];
for (var i = stateRules.length; i--;) {
var rule = stateRules[i];
if (rule.include || typeof rule == "string") {
var args = [i, 1].concat(this.$rules[rule.include || rule]);
if (rule.noEscape) {
args = args.filter(function (x) {
return !x.next;
});
}
stateRules.splice.apply(stateRules, args);
} else if (rule.token in tokenMap) {
rule.token = tokenMap[rule.token];
}
}
}
};
// Ace's Syntax Tokenizer.
// tokenizing lines longer than this makes editor very slow
var MAX_TOKEN_COUNT = 1000;
var Tokenizer = function (rules) {
this.states = rules;
this.regExps = {};
this.matchMappings = {};
for (var key in this.states) {
var state = this.states[key];
var ruleRegExps = [];
var matchTotal = 0;
var mapping = this.matchMappings[key] = {defaultToken: "text"};
var flag = "g";
var splitterRurles = [];
for (var i = 0; i < state.length; i++) {
var rule = state[i];
if (rule.defaultToken)
mapping.defaultToken = rule.defaultToken;
if (rule.caseInsensitive)
flag = "gi";
if (rule.regex == null)
continue;
if (rule.regex instanceof RegExp)
rule.regex = rule.regex.toString().slice(1, -1);
// Count number of matching groups. 2 extra groups from the full match
// And the catch-all on the end (used to force a match);
var adjustedregex = rule.regex;
var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2;
if (Array.isArray(rule.token)) {
if (rule.token.length == 1 || matchcount == 1) {
rule.token = rule.token[0];
} else if (matchcount - 1 != rule.token.length) {
throw new Error("number of classes and regexp groups in '" +
rule.token + "'\n'" + rule.regex + "' doesn't match\n"
+ (matchcount - 1) + "!=" + rule.token.length);
} else {
rule.tokenArray = rule.token;
rule.token = null;
rule.onMatch = this.$arrayTokens;
}
} else if (typeof rule.token == "function" && !rule.onMatch) {
if (matchcount > 1)
rule.onMatch = this.$applyToken;
else
rule.onMatch = rule.token;
}
if (matchcount > 1) {
if (/\\\d/.test(rule.regex)) {
// Replace any backreferences and offset appropriately.
adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
return "\\" + (parseInt(digit, 10) + matchTotal + 1);
});
} else {
matchcount = 1;
adjustedregex = this.removeCapturingGroups(rule.regex);
}
if (!rule.splitRegex && typeof rule.token != "string")
splitterRurles.push(rule); // flag will be known only at the very end
}
mapping[matchTotal] = i;
matchTotal += matchcount;
ruleRegExps.push(adjustedregex);
// makes property access faster
if (!rule.onMatch)
rule.onMatch = null;
}
splitterRurles.forEach(function (rule) {
rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
}, this);
this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag);
}
};
(function () {
this.$setMaxTokenCount = function (m) {
MAX_TOKEN_COUNT = m | 0;
};
this.$applyToken = function (str) {
var values = this.splitRegex.exec(str).slice(1);
var types = this.token.apply(this, values);
// required for compatibility with old modes
if (typeof types === "string")
return [{type: types, value: str}];
var tokens = [];
for (var i = 0, l = types.length; i < l; i++) {
if (values[i])
tokens[tokens.length] = {
type: types[i],
value: values[i]
};
}
return tokens;
},
this.$arrayTokens = function (str) {
if (!str)
return [];
var values = this.splitRegex.exec(str);
if (!values)
return "text";
var tokens = [];
var types = this.tokenArray;
for (var i = 0, l = types.length; i < l; i++) {
if (values[i + 1])
tokens[tokens.length] = {
type: types[i],
value: values[i + 1]
};
}
return tokens;
};
this.removeCapturingGroups = function (src) {
var r = src.replace(
/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g,
function (x, y) {
return y ? "(?:" : x;
}
);
return r;
};
this.createSplitterRegexp = function (src, flag) {
if (src.indexOf("(?=") != -1) {
var stack = 0;
var inChClass = false;
var lastCapture = {};
src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function (m, esc, parenOpen, parenClose, square, index) {
if (inChClass) {
inChClass = square != "]";
} else if (square) {
inChClass = true;
} else if (parenClose) {
if (stack == lastCapture.stack) {
lastCapture.end = index + 1;
lastCapture.stack = -1;
}
stack--;
} else if (parenOpen) {
stack++;
if (parenOpen.length != 1) {
lastCapture.stack = stack
lastCapture.start = index;
}
}
return m;
});
if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
}
return new RegExp(src, (flag || "").replace("g", ""));
};
/**
* Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
* @returns {Object}
**/
this.getLineTokens = function (line, startState) {
if (startState && typeof startState != "string") {
var stack = startState.slice(0);
startState = stack[0];
} else
var stack = [];
var currentState = startState || "start";
var state = this.states[currentState];
if (!state) {
currentState = "start";
state = this.states[currentState];
}
var mapping = this.matchMappings[currentState];
var re = this.regExps[currentState];
re.lastIndex = 0;
var match, tokens = [];
var lastIndex = 0;
var token = {type: null, value: ""};
while (match = re.exec(line)) {
var type = mapping.defaultToken;
var rule = null;
var value = match[0];
var index = re.lastIndex;
if (index - value.length > lastIndex) {
var skipped = line.substring(lastIndex, index - value.length);
if (token.type == type) {
token.value += skipped;
} else {
if (token.type)
tokens.push(token);
token = {type: type, value: skipped};
}
}
for (var i = 0; i < match.length - 2; i++) {
if (match[i + 1] === undefined)
continue;
rule = state[mapping[i]];
if (rule.onMatch)
type = rule.onMatch(value, currentState, stack);
else
type = rule.token;
if (rule.next) {
if (typeof rule.next == "string")
currentState = rule.next;
else
currentState = rule.next(currentState, stack);
state = this.states[currentState];
if (!state) {
window.console && console.error && console.error(currentState, "doesn't exist");
currentState = "start";
state = this.states[currentState];
}
mapping = this.matchMappings[currentState];
lastIndex = index;
re = this.regExps[currentState];
re.lastIndex = index;
}
break;
}
if (value) {
if (typeof type == "string") {
if ((!rule || rule.merge !== false) && token.type === type) {
token.value += value;
} else {
if (token.type)
tokens.push(token);
token = {type: type, value: value};
}
} else if (type) {
if (token.type)
tokens.push(token);
token = {type: null, value: ""};
for (var i = 0; i < type.length; i++)
tokens.push(type[i]);
}
}
if (lastIndex == line.length)
break;
lastIndex = index;
if (tokens.length > MAX_TOKEN_COUNT) {
// chrome doens't show contents of text nodes with very long text
while (lastIndex < line.length) {
if (token.type)
tokens.push(token);
token = {
value: line.substring(lastIndex, lastIndex += 2000),
type: "overflow"
};
}
currentState = "start";
stack = [];
break;
}
}
if (token.type)
tokens.push(token);
if (stack.length > 1) {
if (stack[0] !== currentState)
stack.unshift(currentState);
}
return {
tokens: tokens,
state: stack.length ? stack : currentState
};
};
}).call(Tokenizer.prototype);
// Token conversion.
// See <https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#common-tokens>
// This is not an exact match nor the best match that can be made.
var tokenFromAceToken = {
empty: null,
text: null,
// Keyword
keyword: 'keyword',
control: 'keyword',
operator: 'operator',
// Constants
constant: 'atom',
numeric: 'number',
character: 'atom',
escape: 'atom',
// Variables
variable: 'variable',
parameter: 'variable-3',
language: 'variable-2', // Python's `self` uses that.
// Comments
comment: 'comment',
line: 'comment',
'double-slash': 'comment',
'double-dash': 'comment',
'number-sign': 'comment',
percentage: 'comment',
block: 'comment',
doc: 'comment',
// String
string: 'string',
quoted: 'string',
single: 'string',
double: 'string',
triple: 'string',
unquoted: 'string',
interpolated: 'string',
regexp: 'string-2',
meta: 'keyword',
literal: 'qualifier',
support: 'builtin',
// Markup
markup: 'tag',
underline: 'link',
link: 'link',
strong: 'strong',
heading: 'header',
em: 'em',
list: 'variable-2',
numbered: 'variable-2',
unnumbered: 'variable-2',
quote: 'quote',
raw: 'variable-2', // Markdown's raw block uses that.
// Invalid
invalid: 'error',
illegal: 'invalidchar',
deprecated: 'error'
};
// Takes a list of Ace tokens, returns a (string) CodeMirror token.
var cmTokenFromAceTokens = function (tokens) {
var token = null;
for (var i = 0; i < tokens.length; i++) {
// Find the most specific token.
if (tokenFromAceToken[tokens[i]] !== undefined) {
token = tokenFromAceToken[tokens[i]];
}
}
return token;
};
// Consume a token from plannedTokens.
var consumeToken = function (stream, state) {
var plannedToken = state.plannedTokens.shift();
if (plannedToken === undefined) {
return null;
}
stream.match(plannedToken.value);
var tokens = plannedToken.type.split('.');
return cmTokenFromAceTokens(tokens);
};
var matchToken = function (stream, state) {
// Anormal start: we already have planned tokens to consume.
if (state.plannedTokens.length > 0) {
return consumeToken(stream, state);
}
// Normal start.
var currentState = state.current;
var currentLine = stream.match(/.*$/, false)[0];
var tokenized = tokenizer.getLineTokens(currentLine, currentState);
// We got a {tokens, state} object.
// Each token is a {value, type} object.
state.plannedTokens = tokenized.tokens;
state.current = tokenized.state;
// Consume a token.
return consumeToken(stream, state);
}
// Initialize all state.
var aceHighlightRules = new HighlightRules();
var tokenizer = new Tokenizer(aceHighlightRules.$rules);
var asciidoc = {
startState: function () {
return {
current: 'start',
// List of {value, type}, with type being an Ace token string.
plannedTokens: []
};
},
blankLine: function (state) {
matchToken('', state);
},
token: matchToken
};
return asciidoc;
});
CodeMirror.defineMIME('text/asciidoc', 'asciidoc');
});

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,15 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</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/favicon/main-favicon.png" id="favicon"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/customize/template.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/notifications/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -12,9 +12,5 @@
<body class="cp-app-notifications">
<div id="cp-toolbar" class="cp-toolbar-container"></div>
<div id="cp-sidebarlayout-container"></div>
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</body>

View File

@ -5,11 +5,12 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/sframe-app-outer.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll cp-app-print">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/pad/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -3,7 +3,7 @@
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/poll/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/onlyoffice/main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/common/onlyoffice/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>

View File

@ -5,10 +5,11 @@
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="referrer" content="no-referrer" />
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<link href="/customize/src/outer.css?ver=1.3.2" rel="stylesheet" type="text/css">
</head>
<body>
<noscript></noscript>
<iframe-placeholder>

View File

@ -2,7 +2,7 @@
<html class="cp-app-noscroll">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/profile/inner.js" data-main="/common/sframe-boot.js?ver=1.11" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style>
@ -12,9 +12,5 @@
<body class="cp-app-profile">
<div id="cp-toolbar" class="cp-toolbar-container"></div>
<div id="cp-sidebarlayout-container"></div>
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</body>

View File

@ -1,18 +1,15 @@
<!DOCTYPE html>
<html class="cp">
<html>
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</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/favicon/main-favicon.png" id="favicon"/>
<script src="/customize/pre-loading.js?ver=1.0"></script>
<script src="/customize/pre-loading.js?ver=1.1"></script>
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
<script async data-bootload="/customize/template.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>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>
<noscript></noscript>

Some files were not shown because too many files have changed in this diff Show More