From 51c5b7d3e44ec1ca22799741eb0cdcdcbd670bc6 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 15 Jun 2021 14:48:58 +0200 Subject: [PATCH 001/117] Kanban import from Trello --- www/kanban/export.js | 67 ++++++++++++++++++++++++++++++++++++++++++++ www/kanban/inner.js | 9 +++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/www/kanban/export.js b/www/kanban/export.js index 9ee770ac7..694724cf4 100644 --- a/www/kanban/export.js +++ b/www/kanban/export.js @@ -13,6 +13,73 @@ define([ })); }; + module.import = function (content) { + // Import from Trello + + var c = { + data: {}, + items: {}, + list: [] + }; + + var colorMap = { + red: 'color1', + orange: 'color2', + yellow: 'color3', + lime: 'color4', + green: 'color5', + sky: 'color6', + blue: 'color7', + purple: 'color8', + pink: 'color9', + black: 'nocolor' + }; + content.cards.forEach(function (obj, i) { + var tags; + var color; + if (Array.isArray(obj.labels)) { + obj.labels.forEach(function (l) { + if (!color) { + color = colorMap[l.color] || ''; + } + if (l.name) { + tags = tags || []; + var n = l.name.toLowerCase().trim(); + if (tags.indexOf(n) === -1) { tags.push(n); } + } + }); + } + c.items[(i+1)] = { + id: (i+1), + title: obj.name, + body: obj.desc, + color: color, + tags: tags + }; + }); + + var id = 1; + content.lists.forEach(function (obj) { + var _id = obj.id; + var cards = []; + content.cards.forEach(function (card, i) { + if (card.idList === _id) { + cards.push(i+1); + } + }); + c.data[id] = { + id: id, + title: obj.name, + item: cards + }; + c.list.push(id); + + id++; + }); + + return c; + }; + return module; }); diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 76a9fe1cc..8eb090ffc 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -18,6 +18,7 @@ define([ '/bower_components/marked/marked.min.js', 'cm/lib/codemirror', '/kanban/jkanban_cp.js', + '/kanban/export.js', 'cm/mode/gfm/gfm', 'cm/addon/edit/closebrackets', @@ -50,7 +51,8 @@ define([ ChainPad, Marked, CodeMirror, - jKanban) + jKanban, + Export) { var verbose = function (x) { console.log(x); }; @@ -1060,6 +1062,11 @@ define([ var parsed; try { parsed = JSON.parse(content); } catch (e) { return void console.error(e); } + + if (parsed && parsed.id && parsed.lists && parsed.cards) { + return { content: Export.import(parsed) }; + } + return { content: parsed }; }); From 6f9127221763d517f0d87ed216f8bb2429945d85 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 16 Jun 2021 11:17:00 +0200 Subject: [PATCH 002/117] Add default form templates --- www/form/templates.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 www/form/templates.js diff --git a/www/form/templates.js b/www/form/templates.js new file mode 100644 index 000000000..6ff3249b8 --- /dev/null +++ b/www/form/templates.js @@ -0,0 +1,20 @@ +define([ + '/customize/messages.js' +], function (Messages) { + return [{ + id: 'a', + used: 1, + name: Messages.form_type_poll, + content: { + form: { + "1": { + type: 'md' + }, + "2": { + type: 'poll' + } + }, + order: ["1", "2"] + } + }]; +}); From 3f5e3a14afa16c6b820714367caaf636118ff5d9 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 17 Jun 2021 18:05:25 +0200 Subject: [PATCH 003/117] Fix allDay events on Safari --- www/calendar/inner.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 58ad22ac1..21cb12789 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -17,6 +17,7 @@ define([ '/customize/application_config.js', '/lib/calendar/tui-calendar.min.js', '/calendar/export.js', + '/lib/datepicker/flatpickr.js', '/common/inner/share.js', '/common/inner/access.js', @@ -46,6 +47,7 @@ define([ AppConfig, Calendar, Export, + Flatpickr, Share, Access, Properties ) { @@ -169,9 +171,9 @@ define([ var obj = data.content[uid]; obj.title = obj.title || ""; obj.location = obj.location || ""; - if (obj.isAllDay && obj.startDay) { obj.start = +new Date(obj.startDay); } + if (obj.isAllDay && obj.startDay) { obj.start = +Flatpickr.parseDate((obj.startDay)); } if (obj.isAllDay && obj.endDay) { - var endDate = new Date(obj.endDay); + var endDate = Flatpickr.parseDate(obj.endDay); endDate.setHours(23); endDate.setMinutes(59); endDate.setSeconds(59); From a482d6255328c5e1639ed5a4016747e600000a7e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 17 Jun 2021 18:12:21 +0200 Subject: [PATCH 004/117] Fix allDay event reminders on Safari --- www/common/notifications.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/notifications.js b/www/common/notifications.js index e6cad99e2..20738e237 100644 --- a/www/common/notifications.js +++ b/www/common/notifications.js @@ -8,7 +8,8 @@ define([ '/common/common-constants.js', '/customize/messages.js', '/customize/pages.js', -], function($, h, Hash, UI, UIElements, Util, Constants, Messages, Pages) { + '/lib/datepicker/flatpickr.js', +], function($, h, Hash, UI, UIElements, Util, Constants, Messages, Pages, Flatpickr) { var handlers = {}; @@ -477,7 +478,7 @@ define([ var nowDateStr = new Date().toLocaleDateString(); var startDate = new Date(start); if (msg.isAllDay && msg.startDay) { - startDate = new Date(msg.startDay); + startDate = Flatpickr.parseDate(msg.startDay); } // Missed events From a4bd4e27845986c082c0e8176aca031864024f78 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Jun 2021 12:04:56 +0200 Subject: [PATCH 005/117] Support Markdown import/export in Rich text pads --- www/common/diffMarked.js | 12 +- www/lib/turndown.browser.umd.js | 959 ++++++++++++++++++++++++++++++++ www/pad/export.js | 25 +- www/pad/inner.js | 9 +- 4 files changed, 1000 insertions(+), 5 deletions(-) create mode 100644 www/lib/turndown.browser.umd.js diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index cb95f37aa..4bc5c7c5f 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -172,12 +172,16 @@ define([ return h('div.cp-md-toc', content).outerHTML; }; - DiffMd.render = function (md, sanitize, restrictedMd) { + var noHeadingId = false; + DiffMd.render = function (md, sanitize, restrictedMd, noId) { Marked.setOptions({ renderer: restrictedMd ? restrictedRenderer : renderer, }); + noHeadingId = noId; var r = Marked(md, { - sanitize: sanitize + sanitize: sanitize, + headerIds: !noId, + gfm: true, }); // Add Table of Content @@ -207,7 +211,11 @@ define([ }; restrictedRenderer.code = renderer.code; + var _heading = renderer.heading; renderer.heading = function (text, level) { + if (noHeadingId) { + return _heading.apply(this, arguments); + } var i = 0; var safeText = text.toLowerCase().replace(/[^\w]+/g, '-'); var getId = function () { diff --git a/www/lib/turndown.browser.umd.js b/www/lib/turndown.browser.umd.js new file mode 100644 index 000000000..9b8c40d13 --- /dev/null +++ b/www/lib/turndown.browser.umd.js @@ -0,0 +1,959 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.TurndownService = factory()); +}(this, (function () { 'use strict'; + + function extend (destination) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (source.hasOwnProperty(key)) destination[key] = source[key]; + } + } + return destination + } + + function repeat (character, count) { + return Array(count + 1).join(character) + } + + var blockElements = [ + 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', + 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', + 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', + 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES', + 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD', + 'TFOOT', 'TH', 'THEAD', 'TR', 'UL' + ]; + + function isBlock (node) { + return is(node, blockElements) + } + + var voidElements = [ + 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', + 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR' + ]; + + function isVoid (node) { + return is(node, voidElements) + } + + function hasVoid (node) { + return has(node, voidElements) + } + + var meaningfulWhenBlankElements = [ + 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT', + 'AUDIO', 'VIDEO' + ]; + + function isMeaningfulWhenBlank (node) { + return is(node, meaningfulWhenBlankElements) + } + + function hasMeaningfulWhenBlank (node) { + return has(node, meaningfulWhenBlankElements) + } + + function is (node, tagNames) { + return tagNames.indexOf(node.nodeName) >= 0 + } + + function has (node, tagNames) { + return ( + node.getElementsByTagName && + tagNames.some(function (tagName) { + return node.getElementsByTagName(tagName).length + }) + ) + } + + var rules = {}; + + rules.paragraph = { + filter: 'p', + + replacement: function (content) { + return '\n\n' + content + '\n\n' + } + }; + + rules.lineBreak = { + filter: 'br', + + replacement: function (content, node, options) { + return options.br + '\n' + } + }; + + rules.heading = { + filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + + replacement: function (content, node, options) { + var hLevel = Number(node.nodeName.charAt(1)); + + if (options.headingStyle === 'setext' && hLevel < 3) { + var underline = repeat((hLevel === 1 ? '=' : '-'), content.length); + return ( + '\n\n' + content + '\n' + underline + '\n\n' + ) + } else { + return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n' + } + } + }; + + rules.blockquote = { + filter: 'blockquote', + + replacement: function (content) { + content = content.replace(/^\n+|\n+$/g, ''); + content = content.replace(/^/gm, '> '); + return '\n\n' + content + '\n\n' + } + }; + + rules.list = { + filter: ['ul', 'ol'], + + replacement: function (content, node) { + var parent = node.parentNode; + if (parent.nodeName === 'LI' && parent.lastElementChild === node) { + return '\n' + content + } else { + return '\n\n' + content + '\n\n' + } + } + }; + + rules.listItem = { + filter: 'li', + + replacement: function (content, node, options) { + content = content + .replace(/^\n+/, '') // remove leading newlines + .replace(/\n+$/, '\n') // replace trailing newlines with just a single one + .replace(/\n/gm, '\n '); // indent + var prefix = options.bulletListMarker + ' '; + var parent = node.parentNode; + if (parent.nodeName === 'OL') { + var start = parent.getAttribute('start'); + var index = Array.prototype.indexOf.call(parent.children, node); + prefix = (start ? Number(start) + index : index + 1) + '. '; + } + return ( + prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '') + ) + } + }; + + rules.indentedCodeBlock = { + filter: function (node, options) { + return ( + options.codeBlockStyle === 'indented' && + node.nodeName === 'PRE' && + node.firstChild && + node.firstChild.nodeName === 'CODE' + ) + }, + + replacement: function (content, node, options) { + return ( + '\n\n ' + + node.firstChild.textContent.replace(/\n/g, '\n ') + + '\n\n' + ) + } + }; + + rules.fencedCodeBlock = { + filter: function (node, options) { + return ( + options.codeBlockStyle === 'fenced' && + node.nodeName === 'PRE' && + node.firstChild && + node.firstChild.nodeName === 'CODE' + ) + }, + + replacement: function (content, node, options) { + var className = node.firstChild.getAttribute('class') || ''; + var language = (className.match(/language-(\S+)/) || [null, ''])[1]; + var code = node.firstChild.textContent; + + var fenceChar = options.fence.charAt(0); + var fenceSize = 3; + var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm'); + + var match; + while ((match = fenceInCodeRegex.exec(code))) { + if (match[0].length >= fenceSize) { + fenceSize = match[0].length + 1; + } + } + + var fence = repeat(fenceChar, fenceSize); + + return ( + '\n\n' + fence + language + '\n' + + code.replace(/\n$/, '') + + '\n' + fence + '\n\n' + ) + } + }; + + rules.horizontalRule = { + filter: 'hr', + + replacement: function (content, node, options) { + return '\n\n' + options.hr + '\n\n' + } + }; + + rules.inlineLink = { + filter: function (node, options) { + return ( + options.linkStyle === 'inlined' && + node.nodeName === 'A' && + node.getAttribute('href') + ) + }, + + replacement: function (content, node) { + var href = node.getAttribute('href'); + var title = cleanAttribute(node.getAttribute('title')); + if (title) title = ' "' + title + '"'; + return '[' + content + '](' + href + title + ')' + } + }; + + rules.referenceLink = { + filter: function (node, options) { + return ( + options.linkStyle === 'referenced' && + node.nodeName === 'A' && + node.getAttribute('href') + ) + }, + + replacement: function (content, node, options) { + var href = node.getAttribute('href'); + var title = cleanAttribute(node.getAttribute('title')); + if (title) title = ' "' + title + '"'; + var replacement; + var reference; + + switch (options.linkReferenceStyle) { + case 'collapsed': + replacement = '[' + content + '][]'; + reference = '[' + content + ']: ' + href + title; + break + case 'shortcut': + replacement = '[' + content + ']'; + reference = '[' + content + ']: ' + href + title; + break + default: + var id = this.references.length + 1; + replacement = '[' + content + '][' + id + ']'; + reference = '[' + id + ']: ' + href + title; + } + + this.references.push(reference); + return replacement + }, + + references: [], + + append: function (options) { + var references = ''; + if (this.references.length) { + references = '\n\n' + this.references.join('\n') + '\n\n'; + this.references = []; // Reset references + } + return references + } + }; + + rules.emphasis = { + filter: ['em', 'i'], + + replacement: function (content, node, options) { + if (!content.trim()) return '' + return options.emDelimiter + content + options.emDelimiter + } + }; + + rules.strong = { + filter: ['strong', 'b'], + + replacement: function (content, node, options) { + if (!content.trim()) return '' + return options.strongDelimiter + content + options.strongDelimiter + } + }; + + rules.code = { + filter: function (node) { + var hasSiblings = node.previousSibling || node.nextSibling; + var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings; + + return node.nodeName === 'CODE' && !isCodeBlock + }, + + replacement: function (content) { + if (!content.trim()) return '' + + var delimiter = '`'; + var leadingSpace = ''; + var trailingSpace = ''; + var matches = content.match(/`+/gm); + if (matches) { + if (/^`/.test(content)) leadingSpace = ' '; + if (/`$/.test(content)) trailingSpace = ' '; + while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; + } + + return delimiter + leadingSpace + content + trailingSpace + delimiter + } + }; + + rules.image = { + filter: 'img', + + replacement: function (content, node) { + var alt = cleanAttribute(node.getAttribute('alt')); + var src = node.getAttribute('src') || ''; + var title = cleanAttribute(node.getAttribute('title')); + var titlePart = title ? ' "' + title + '"' : ''; + return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '' + } + }; + + function cleanAttribute (attribute) { + return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : '' + } + + /** + * Manages a collection of rules used to convert HTML to Markdown + */ + + function Rules (options) { + this.options = options; + this._keep = []; + this._remove = []; + + this.blankRule = { + replacement: options.blankReplacement + }; + + this.keepReplacement = options.keepReplacement; + + this.defaultRule = { + replacement: options.defaultReplacement + }; + + this.array = []; + for (var key in options.rules) this.array.push(options.rules[key]); + } + + Rules.prototype = { + add: function (key, rule) { + this.array.unshift(rule); + }, + + keep: function (filter) { + this._keep.unshift({ + filter: filter, + replacement: this.keepReplacement + }); + }, + + remove: function (filter) { + this._remove.unshift({ + filter: filter, + replacement: function () { + return '' + } + }); + }, + + forNode: function (node) { + if (node.isBlank) return this.blankRule + var rule; + + if ((rule = findRule(this.array, node, this.options))) return rule + if ((rule = findRule(this._keep, node, this.options))) return rule + if ((rule = findRule(this._remove, node, this.options))) return rule + + return this.defaultRule + }, + + forEach: function (fn) { + for (var i = 0; i < this.array.length; i++) fn(this.array[i], i); + } + }; + + function findRule (rules, node, options) { + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if (filterValue(rule, node, options)) return rule + } + return void 0 + } + + function filterValue (rule, node, options) { + var filter = rule.filter; + if (typeof filter === 'string') { + if (filter === node.nodeName.toLowerCase()) return true + } else if (Array.isArray(filter)) { + if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true + } else if (typeof filter === 'function') { + if (filter.call(rule, node, options)) return true + } else { + throw new TypeError('`filter` needs to be a string, array, or function') + } + } + + /** + * The collapseWhitespace function is adapted from collapse-whitespace + * by Luc Thevenard. + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Luc Thevenard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + /** + * collapseWhitespace(options) removes extraneous whitespace from an the given element. + * + * @param {Object} options + */ + function collapseWhitespace (options) { + var element = options.element; + var isBlock = options.isBlock; + var isVoid = options.isVoid; + var isPre = options.isPre || function (node) { + return node.nodeName === 'PRE' + }; + + if (!element.firstChild || isPre(element)) return + + var prevText = null; + var prevVoid = false; + + var prev = null; + var node = next(prev, element, isPre); + + while (node !== element) { + if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE + var text = node.data.replace(/[ \r\n\t]+/g, ' '); + + if ((!prevText || / $/.test(prevText.data)) && + !prevVoid && text[0] === ' ') { + text = text.substr(1); + } + + // `text` might be empty at this point. + if (!text) { + node = remove(node); + continue + } + + node.data = text; + + prevText = node; + } else if (node.nodeType === 1) { // Node.ELEMENT_NODE + if (isBlock(node) || node.nodeName === 'BR') { + if (prevText) { + prevText.data = prevText.data.replace(/ $/, ''); + } + + prevText = null; + prevVoid = false; + } else if (isVoid(node)) { + // Avoid trimming space around non-block, non-BR void elements. + prevText = null; + prevVoid = true; + } + } else { + node = remove(node); + continue + } + + var nextNode = next(prev, node, isPre); + prev = node; + node = nextNode; + } + + if (prevText) { + prevText.data = prevText.data.replace(/ $/, ''); + if (!prevText.data) { + remove(prevText); + } + } + } + + /** + * remove(node) removes the given node from the DOM and returns the + * next node in the sequence. + * + * @param {Node} node + * @return {Node} node + */ + function remove (node) { + var next = node.nextSibling || node.parentNode; + + node.parentNode.removeChild(node); + + return next + } + + /** + * next(prev, current, isPre) returns the next node in the sequence, given the + * current and previous nodes. + * + * @param {Node} prev + * @param {Node} current + * @param {Function} isPre + * @return {Node} + */ + function next (prev, current, isPre) { + if ((prev && prev.parentNode === current) || isPre(current)) { + return current.nextSibling || current.parentNode + } + + return current.firstChild || current.nextSibling || current.parentNode + } + + /* + * Set up window for Node.js + */ + + var root = (typeof window !== 'undefined' ? window : {}); + + /* + * Parsing HTML strings + */ + + function canParseHTMLNatively () { + var Parser = root.DOMParser; + var canParse = false; + + // Adapted from https://gist.github.com/1129031 + // Firefox/Opera/IE throw errors on unsupported types + try { + // WebKit returns null on unsupported types + if (new Parser().parseFromString('', 'text/html')) { + canParse = true; + } + } catch (e) {} + + return canParse + } + + function createHTMLParser () { + var Parser = function () {}; + + { + if (shouldUseActiveX()) { + Parser.prototype.parseFromString = function (string) { + var doc = new window.ActiveXObject('htmlfile'); + doc.designMode = 'on'; // disable on-page scripts + doc.open(); + doc.write(string); + doc.close(); + return doc + }; + } else { + Parser.prototype.parseFromString = function (string) { + var doc = document.implementation.createHTMLDocument(''); + doc.open(); + doc.write(string); + doc.close(); + return doc + }; + } + } + return Parser + } + + function shouldUseActiveX () { + var useActiveX = false; + try { + document.implementation.createHTMLDocument('').open(); + } catch (e) { + if (window.ActiveXObject) useActiveX = true; + } + return useActiveX + } + + var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser(); + + function RootNode (input) { + var root; + if (typeof input === 'string') { + var doc = htmlParser().parseFromString( + // DOM parsers arrange elements in the and . + // Wrapping in a custom element ensures elements are reliably arranged in + // a single element. + '' + input + '', + 'text/html' + ); + root = doc.getElementById('turndown-root'); + } else { + root = input.cloneNode(true); + } + collapseWhitespace({ + element: root, + isBlock: isBlock, + isVoid: isVoid + }); + + return root + } + + var _htmlParser; + function htmlParser () { + _htmlParser = _htmlParser || new HTMLParser(); + return _htmlParser + } + + function Node (node) { + node.isBlock = isBlock(node); + node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; + node.isBlank = isBlank(node); + node.flankingWhitespace = flankingWhitespace(node); + return node + } + + function isBlank (node) { + return ( + !isVoid(node) && + !isMeaningfulWhenBlank(node) && + /^\s*$/i.test(node.textContent) && + !hasVoid(node) && + !hasMeaningfulWhenBlank(node) + ) + } + + function flankingWhitespace (node) { + var leading = ''; + var trailing = ''; + + if (!node.isBlock) { + var hasLeading = /^\s/.test(node.textContent); + var hasTrailing = /\s$/.test(node.textContent); + var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; + + if (hasLeading && !isFlankedByWhitespace('left', node)) { + leading = ' '; + } + + if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { + trailing = ' '; + } + } + + return { leading: leading, trailing: trailing } + } + + function isFlankedByWhitespace (side, node) { + var sibling; + var regExp; + var isFlanked; + + if (side === 'left') { + sibling = node.previousSibling; + regExp = / $/; + } else { + sibling = node.nextSibling; + regExp = /^ /; + } + + if (sibling) { + if (sibling.nodeType === 3) { + isFlanked = regExp.test(sibling.nodeValue); + } else if (sibling.nodeType === 1 && !isBlock(sibling)) { + isFlanked = regExp.test(sibling.textContent); + } + } + return isFlanked + } + + var reduce = Array.prototype.reduce; + var leadingNewLinesRegExp = /^\n*/; + var trailingNewLinesRegExp = /\n*$/; + var escapes = [ + [/\\/g, '\\\\'], + [/\*/g, '\\*'], + [/^-/g, '\\-'], + [/^\+ /g, '\\+ '], + [/^(=+)/g, '\\$1'], + [/^(#{1,6}) /g, '\\$1 '], + [/`/g, '\\`'], + [/^~~~/g, '\\~~~'], + [/\[/g, '\\['], + [/\]/g, '\\]'], + [/^>/g, '\\>'], + [/_/g, '\\_'], + [/^(\d+)\. /g, '$1\\. '] + ]; + + function TurndownService (options) { + if (!(this instanceof TurndownService)) return new TurndownService(options) + + var defaults = { + rules: rules, + headingStyle: 'setext', + hr: '* * *', + bulletListMarker: '*', + codeBlockStyle: 'indented', + fence: '```', + emDelimiter: '_', + strongDelimiter: '**', + linkStyle: 'inlined', + linkReferenceStyle: 'full', + br: ' ', + blankReplacement: function (content, node) { + return node.isBlock ? '\n\n' : '' + }, + keepReplacement: function (content, node) { + return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML + }, + defaultReplacement: function (content, node) { + return node.isBlock ? '\n\n' + content + '\n\n' : content + } + }; + this.options = extend({}, defaults, options); + this.rules = new Rules(this.options); + } + + TurndownService.prototype = { + /** + * The entry point for converting a string or DOM node to Markdown + * @public + * @param {String|HTMLElement} input The string or DOM node to convert + * @returns A Markdown representation of the input + * @type String + */ + + turndown: function (input) { + if (!canConvert(input)) { + throw new TypeError( + input + ' is not a string, or an element/document/fragment node.' + ) + } + + if (input === '') return '' + + var output = process.call(this, new RootNode(input)); + return postProcess.call(this, output) + }, + + /** + * Add one or more plugins + * @public + * @param {Function|Array} plugin The plugin or array of plugins to add + * @returns The Turndown instance for chaining + * @type Object + */ + + use: function (plugin) { + if (Array.isArray(plugin)) { + for (var i = 0; i < plugin.length; i++) this.use(plugin[i]); + } else if (typeof plugin === 'function') { + plugin(this); + } else { + throw new TypeError('plugin must be a Function or an Array of Functions') + } + return this + }, + + /** + * Adds a rule + * @public + * @param {String} key The unique key of the rule + * @param {Object} rule The rule + * @returns The Turndown instance for chaining + * @type Object + */ + + addRule: function (key, rule) { + this.rules.add(key, rule); + return this + }, + + /** + * Keep a node (as HTML) that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + keep: function (filter) { + this.rules.keep(filter); + return this + }, + + /** + * Remove a node that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + remove: function (filter) { + this.rules.remove(filter); + return this + }, + + /** + * Escapes Markdown syntax + * @public + * @param {String} string The string to escape + * @returns A string with Markdown syntax escaped + * @type String + */ + + escape: function (string) { + return escapes.reduce(function (accumulator, escape) { + return accumulator.replace(escape[0], escape[1]) + }, string) + } + }; + + /** + * Reduces a DOM node down to its Markdown string equivalent + * @private + * @param {HTMLElement} parentNode The node to convert + * @returns A Markdown representation of the node + * @type String + */ + + function process (parentNode) { + var self = this; + return reduce.call(parentNode.childNodes, function (output, node) { + node = new Node(node); + + var replacement = ''; + if (node.nodeType === 3) { + replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue); + } else if (node.nodeType === 1) { + replacement = replacementForNode.call(self, node); + } + + return join(output, replacement) + }, '') + } + + /** + * Appends strings as each rule requires and trims the output + * @private + * @param {String} output The conversion output + * @returns A trimmed version of the ouput + * @type String + */ + + function postProcess (output) { + var self = this; + this.rules.forEach(function (rule) { + if (typeof rule.append === 'function') { + output = join(output, rule.append(self.options)); + } + }); + + return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '') + } + + /** + * Converts an element node to its Markdown equivalent + * @private + * @param {HTMLElement} node The node to convert + * @returns A Markdown representation of the node + * @type String + */ + + function replacementForNode (node) { + var rule = this.rules.forNode(node); + var content = process.call(this, node); + var whitespace = node.flankingWhitespace; + if (whitespace.leading || whitespace.trailing) content = content.trim(); + return ( + whitespace.leading + + rule.replacement(content, node, this.options) + + whitespace.trailing + ) + } + + /** + * Determines the new lines between the current output and the replacement + * @private + * @param {String} output The current conversion output + * @param {String} replacement The string to append to the output + * @returns The whitespace to separate the current output and the replacement + * @type String + */ + + function separatingNewlines (output, replacement) { + var newlines = [ + output.match(trailingNewLinesRegExp)[0], + replacement.match(leadingNewLinesRegExp)[0] + ].sort(); + var maxNewlines = newlines[newlines.length - 1]; + return maxNewlines.length < 2 ? maxNewlines : '\n\n' + } + + function join (string1, string2) { + var separator = separatingNewlines(string1, string2); + + // Remove trailing/leading newlines and replace with separator + string1 = string1.replace(trailingNewLinesRegExp, ''); + string2 = string2.replace(leadingNewLinesRegExp, ''); + + return string1 + separator + string2 + } + + /** + * Determines whether an input can be converted + * @private + * @param {String|HTMLElement} input Describe this parameter + * @returns Describe what it returns + * @type String|Object|Array|Boolean|Number + */ + + function canConvert (input) { + return ( + input != null && ( + typeof input === 'string' || + (input.nodeType && ( + input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11 + )) + ) + ) + } + + return TurndownService; + +}))); diff --git a/www/pad/export.js b/www/pad/export.js index f1e3497c9..db9f5ac37 100644 --- a/www/pad/export.js +++ b/www/pad/export.js @@ -1,12 +1,24 @@ define([ 'jquery', '/common/common-util.js', + '/common/diffMarked.js', + '/common/hyperscript.js', '/bower_components/hyperjson/hyperjson.js', '/bower_components/nthen/index.js', -], function ($, Util, Hyperjson, nThen) { + '/lib/turndown.browser.umd.js' +], function ($, Util, DiffMd, h, Hyperjson, nThen, Turndown) { var module = { ext: '.html', // default - exts: ['.html', '.doc'] + exts: ['.html', '.md', '.doc'] + }; + + module.importMd = function (md, common) { + var html = DiffMd.render(md, true, false, true); + var div = h('div#cp-temp'); + DiffMd.apply(html, $(div), common); + var body = h('body'); + body.innerHTML = div.innerHTML; + return body; }; var exportMediaTags = function (inner, cb) { @@ -77,6 +89,15 @@ define([ }); return void cb(blob); } + if (ext === ".md") { + var md = Turndown({ + headingStyle: 'atx' + }).turndown(toExport); + var blob = new Blob([md], { + type: 'text/markdown;charset=utf-8' + }); + return void cb(blob); + } var html = module.getHTML(toExport); cb(new Blob([ html ], { type: "text/html;charset=utf-8" })); }); diff --git a/www/pad/inner.js b/www/pad/inner.js index 47ab5dbe3..47bd7f7f7 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -1169,7 +1169,14 @@ define([ }); cb($dom[0]); }; - framework.setFileImporter({ accept: 'text/html' }, function(content, f, cb) { + framework.setFileImporter({ accept: ['.md', 'text/html'] }, function(content, f, cb) { + if (!f) { return; } + if (/\.md$/.test(f.name)) { + var mdDom = Exporter.importMd(content, framework._.sfCommon); + return importMediaTags(mdDom, function(dom) { + cb(Hyperjson.fromDOM(dom)); + }); + } importMediaTags(domFromHTML(content).body, function(dom) { cb(Hyperjson.fromDOM(dom)); }); From 544e5bcbfe580a6a22289f3821a9c5b792b40acc Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Jun 2021 12:08:03 +0200 Subject: [PATCH 006/117] Add converter app --- www/common/application_config_internal.js | 2 +- www/convert/app-convert.less | 16 ++ www/convert/file-crypto.js | 209 +++++++++++++++++ www/convert/index.html | 12 + www/convert/inner.html | 18 ++ www/convert/inner.js | 259 ++++++++++++++++++++++ www/convert/main.js | 28 +++ 7 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 www/convert/app-convert.less create mode 100644 www/convert/file-crypto.js create mode 100644 www/convert/index.html create mode 100644 www/convert/inner.html create mode 100644 www/convert/inner.js create mode 100644 www/convert/main.js diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index ad5f726f8..68ba4ed06 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -12,7 +12,7 @@ define(function() { * You should never remove the drive from this list. */ AppConfig.availablePadTypes = ['drive', 'teams', 'pad', 'sheet', 'code', 'slide', 'poll', 'kanban', 'whiteboard', - /*'doc', 'presentation',*/ 'file', /*'todo',*/ 'contacts', 'form']; + /*'doc', 'presentation',*/ 'file', /*'todo',*/ 'contacts', 'form', 'convert']; /* The registered only types are apps restricted to registered users. * You should never remove apps from this list unless you know what you're doing. The apps * listed here by default can't work without a user account. diff --git a/www/convert/app-convert.less b/www/convert/app-convert.less new file mode 100644 index 000000000..c5813641a --- /dev/null +++ b/www/convert/app-convert.less @@ -0,0 +1,16 @@ +@import (reference) '../../customize/src/less2/include/framework.less'; +@import (reference) '../../customize/src/less2/include/sidebar-layout.less'; + +&.cp-app-convert { + + .framework_min_main( + @bg-color: @colortheme_apps[default], + ); + .sidebar-layout_main(); + + // body + display: flex; + flex-flow: column; + background-color: @cp_app-bg; + +} diff --git a/www/convert/file-crypto.js b/www/convert/file-crypto.js new file mode 100644 index 000000000..6a0c08816 --- /dev/null +++ b/www/convert/file-crypto.js @@ -0,0 +1,209 @@ +define([ + '/bower_components/tweetnacl/nacl-fast.min.js', +], function () { + var Nacl = window.nacl; + //var PARANOIA = true; + + var plainChunkLength = 128 * 1024; + var cypherChunkLength = 131088; + + var computeEncryptedSize = function (bytes, meta) { + var metasize = Nacl.util.decodeUTF8(JSON.stringify(meta)).length; + var chunks = Math.ceil(bytes / plainChunkLength); + return metasize + 18 + (chunks * 16) + bytes; + }; + + var encodePrefix = function (p) { + return [ + 65280, // 255 << 8 + 255, + ].map(function (n, i) { + return (p & n) >> ((1 - i) * 8); + }); + }; + var decodePrefix = function (A) { + return (A[0] << 8) | A[1]; + }; + + var slice = function (A) { + return Array.prototype.slice.call(A); + }; + + var createNonce = function () { + return new Uint8Array(new Array(24).fill(0)); + }; + + var increment = function (N) { + var l = N.length; + while (l-- > 1) { + /* our linter suspects this is unsafe because we lack types + but as long as this is only used on nonces, it should be safe */ + if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line + if (l === 0) { throw new Error('E_NONCE_TOO_LARGE'); } + N[l] = 0; + } + }; + + var joinChunks = function (chunks) { + return new Blob(chunks); + }; + + var decrypt = function (u8, key, done, progress) { + var MAX = u8.length; + var _progress = function (offset) { + if (typeof(progress) !== 'function') { return; } + progress(Math.min(1, offset / MAX)); + }; + + var nonce = createNonce(); + var i = 0; + + var prefix = u8.subarray(0, 2); + var metadataLength = decodePrefix(prefix); + + var res = { + metadata: undefined, + }; + + var cancelled = false; + var cancel = function () { + cancelled = true; + }; + + var metaBox = new Uint8Array(u8.subarray(2, 2 + metadataLength)); + + var metaChunk = Nacl.secretbox.open(metaBox, nonce, key); + increment(nonce); + + try { + res.metadata = JSON.parse(Nacl.util.encodeUTF8(metaChunk)); + } catch (e) { + return window.setTimeout(function () { + done('E_METADATA_DECRYPTION'); + }); + } + + if (!res.metadata) { + return void setTimeout(function () { + done('NO_METADATA'); + }); + } + + var takeChunk = function (cb) { + setTimeout(function () { + var start = i * cypherChunkLength + 2 + metadataLength; + var end = start + cypherChunkLength; + i++; + var box = new Uint8Array(u8.subarray(start, end)); + + // decrypt the chunk + var plaintext = Nacl.secretbox.open(box, nonce, key); + increment(nonce); + + if (!plaintext) { return cb('DECRYPTION_ERROR'); } + + _progress(end); + cb(void 0, plaintext); + }); + }; + + var chunks = []; + + var again = function () { + if (cancelled) { return; } + takeChunk(function (e, plaintext) { + if (e) { + return setTimeout(function () { + done(e); + }); + } + if (plaintext) { + if ((2 + metadataLength + i * cypherChunkLength) < u8.length) { // not done + chunks.push(plaintext); + return setTimeout(again); + } + chunks.push(plaintext); + res.content = joinChunks(chunks); + return done(void 0, res); + } + done('UNEXPECTED_ENDING'); + }); + }; + + again(); + + return { + cancel: cancel + }; + }; + + // metadata + /* { filename: 'raccoon.jpg', type: 'image/jpeg' } */ + var encrypt = function (u8, metadata, key) { + var nonce = createNonce(); + + // encode metadata + var plaintext = Nacl.util.decodeUTF8(JSON.stringify(metadata)); + + // if metadata is too large, drop the thumbnail. + if (plaintext.length > 65535) { + var temp = JSON.parse(JSON.stringify(metadata)); + delete metadata.thumbnail; + plaintext = Nacl.util.decodeUTF8(JSON.stringify(temp)); + } + + var i = 0; + + var state = 0; + var next = function (cb) { + if (state === 2) { return void setTimeout(cb); } + + var start; + var end; + var part; + var box; + + if (state === 0) { // metadata... + part = new Uint8Array(plaintext); + box = Nacl.secretbox(part, nonce, key); + increment(nonce); + + if (box.length > 65535) { + return void cb('METADATA_TOO_LARGE'); + } + var prefixed = new Uint8Array(encodePrefix(box.length) + .concat(slice(box))); + state++; + + return void setTimeout(function () { + cb(void 0, prefixed); + }); + } + + // encrypt the rest of the file... + start = i * plainChunkLength; + end = start + plainChunkLength; + + part = u8.subarray(start, end); + box = Nacl.secretbox(part, nonce, key); + increment(nonce); + i++; + + // regular data is done + if (i * plainChunkLength >= u8.length) { state = 2; } + + setTimeout(function () { + cb(void 0, box); + }); + }; + + return next; + }; + + return { + decrypt: decrypt, + encrypt: encrypt, + joinChunks: joinChunks, + computeEncryptedSize: computeEncryptedSize, + }; +}); diff --git a/www/convert/index.html b/www/convert/index.html new file mode 100644 index 000000000..96a3cce86 --- /dev/null +++ b/www/convert/index.html @@ -0,0 +1,12 @@ + + + + CryptPad + + + + + + + + diff --git a/www/convert/inner.html b/www/convert/inner.html new file mode 100644 index 000000000..206b85722 --- /dev/null +++ b/www/convert/inner.html @@ -0,0 +1,18 @@ + + + + + + + + +
+
+ + + diff --git a/www/convert/inner.js b/www/convert/inner.js new file mode 100644 index 000000000..d8eca9af2 --- /dev/null +++ b/www/convert/inner.js @@ -0,0 +1,259 @@ +define([ + 'jquery', + '/api/config', + '/bower_components/chainpad-crypto/crypto.js', + '/common/toolbar.js', + '/bower_components/nthen/index.js', + '/common/sframe-common.js', + '/common/hyperscript.js', + '/customize/messages.js', + '/common/common-interface.js', + '/common/common-util.js', + + '/bower_components/file-saver/FileSaver.min.js', + 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', + 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', + 'less!/convert/app-convert.less', +], function ( + $, + ApiConfig, + Crypto, + Toolbar, + nThen, + SFCommon, + h, + Messages, + UI, + Util + ) +{ + var APP = {}; + + var common; + var sFrameChan; + + var debug = console.debug; + + var x2tReady = Util.mkEvent(true); + var x2tInitialized = false; + var x2tInit = function(x2t) { + debug("x2t mount"); + // x2t.FS.mount(x2t.MEMFS, {} , '/'); + x2t.FS.mkdir('/working'); + x2t.FS.mkdir('/working/media'); + x2t.FS.mkdir('/working/fonts'); + x2tInitialized = true; + x2tReady.fire(); + //fetchFonts(x2t); + debug("x2t mount done"); + }; + var getX2t = function (cb) { + // XXX require http headers on firefox... + require(['/common/onlyoffice/x2t/x2t.js'], function() { // FIXME why does this fail without an access-control-allow-origin header? + var x2t = window.Module; + x2t.run(); + if (x2tInitialized) { + debug("x2t runtime already initialized"); + return void x2tReady.reg(function () { + cb(x2t); + }); + } + + x2t.onRuntimeInitialized = function() { + debug("x2t in runtime initialized"); + // Init x2t js module + x2tInit(x2t); + x2tReady.reg(function () { + cb(x2t); + }); + }; + }); + }; + /* + Converting Data + + This function converts a data in a specific format to the outputformat + The filename extension needs to represent the input format + Example: fileName=cryptpad.bin outputFormat=xlsx + */ + var getFormatId = function (ext) { + // Sheets + if (ext === 'xlsx') { return 257; } + if (ext === 'xls') { return 258; } + if (ext === 'ods') { return 259; } + if (ext === 'csv') { return 260; } + if (ext === 'pdf') { return 513; } + // Docs + if (ext === 'docx') { return 65; } + if (ext === 'doc') { return 66; } + if (ext === 'odt') { return 67; } + if (ext === 'txt') { return 69; } + if (ext === 'html') { return 70; } + + // Slides + if (ext === 'pptx') { return 129; } + if (ext === 'ppt') { return 130; } + if (ext === 'odp') { return 131; } + + return; + }; + var getFromId = function (ext) { + var id = getFormatId(ext); + if (!id) { return ''; } + return ''+id+''; + }; + var getToId = function (ext) { + var id = getFormatId(ext); + if (!id) { return ''; } + return ''+id+''; + }; + var x2tConvertDataInternal = function(x2t, data, fileName, outputFormat) { + debug("Converting Data for " + fileName + " to " + outputFormat); + + var inputFormat = fileName.split('.').pop(); + + x2t.FS.writeFile('/working/' + fileName, data); + var params = "" + + "" + + "/working/" + fileName + "" + + "/working/" + fileName + "." + outputFormat + "" + + getFromId(inputFormat) + + getToId(outputFormat) + + "false" + + ""; + // writing params file to mounted working disk (in memory) + x2t.FS.writeFile('/working/params.xml', params); + // running conversion + x2t.ccall("runX2T", ["number"], ["string"], ["/working/params.xml"]); + // reading output file from working disk (in memory) + var result; + try { + result = x2t.FS.readFile('/working/' + fileName + "." + outputFormat); + } catch (e) { + console.error(e, x2t.FS); + debug("Failed reading converted file"); + UI.warn(Messages.error); + return ""; + } + return result; + }; + var x2tConverter = function (typeSrc, typeTarget) { + return function (data, name, cb) { + getX2t(function (x2t) { + if (typeSrc === 'ods') { + data = x2tConvertDataInternal(x2t, data, name, 'xlsx'); + name += '.xlsx'; + } + if (typeSrc === 'odt') { + data = x2tConvertDataInternal(x2t, data, name, 'docx'); + name += '.docx'; + } + if (typeSrc === 'odp') { + data = x2tConvertDataInternal(x2t, data, name, 'pptx'); + name += '.pptx'; + } + cb(x2tConvertDataInternal(x2t, data, name, typeTarget)); + }); + }; + }; + + var CONVERTERS = { + xlsx: { + //pdf: x2tConverter('xlsx', 'pdf'), + ods: x2tConverter('xlsx', 'ods'), + bin: x2tConverter('xlsx', 'bin'), + }, + ods: { + //pdf: x2tConverter('ods', 'pdf'), + xlsx: x2tConverter('ods', 'xlsx'), + bin: x2tConverter('ods', 'bin'), + }, + odt: { + docx: x2tConverter('odt', 'docx'), + txt: x2tConverter('odt', 'txt'), + bin: x2tConverter('odt', 'bin'), + }, + docx: { + odt: x2tConverter('docx', 'odt'), + txt: x2tConverter('docx', 'txt'), + bin: x2tConverter('docx', 'bin'), + }, + txt: { + odt: x2tConverter('txt', 'odt'), + docx: x2tConverter('txt', 'docx'), + bin: x2tConverter('txt', 'bin'), + }, + odp: { + pptx: x2tConverter('odp', 'pptx'), + bin: x2tConverter('odp', 'bin'), + }, + pptx: { + odp: x2tConverter('pptx', 'odp'), + bin: x2tConverter('pptx', 'bin'), + }, + }; + + Messages.convertPage = "Convert"; // XXX + Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; + + var createToolbar = function () { + var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle', 'notifications']; + var configTb = { + displayed: displayed, + sfCommon: common, + $container: APP.$toolbar, + pageTitle: Messages.convertPage, + metadataMgr: common.getMetadataMgr(), + }; + APP.toolbar = Toolbar.create(configTb); + APP.toolbar.$rightside.hide(); + }; + + nThen(function (waitFor) { + $(waitFor(UI.addLoadingScreen)); + SFCommon.create(waitFor(function (c) { APP.common = common = c; })); + }).nThen(function (waitFor) { + APP.$container = $('#cp-sidebarlayout-container'); + APP.$toolbar = $('#cp-toolbar'); + APP.$leftside = $('
', {id: 'cp-sidebarlayout-leftside'}).appendTo(APP.$container); + APP.$rightside = $('
', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container); + sFrameChan = common.getSframeChannel(); + sFrameChan.onReady(waitFor()); + }).nThen(function (/*waitFor*/) { + createToolbar(); + + var hint = h('p.cp-convert-hint', Messages.convert_hint); + + var picker = h('input', { + type: 'file' + }); + APP.$rightside.append([hint, picker]); + + $(picker).on('change', function () { + var file = picker.files[0]; + var name = file && file.name; + var reader = new FileReader(); + var parsed = file && file.name && /.+\.([^.]+)$/.exec(file.name); + var ext = parsed && parsed[1]; + reader.onload = function (e) { + if (CONVERTERS[ext]) { + Object.keys(CONVERTERS[ext]).forEach(function (to) { + var button = h('button.btn', to); + $(button).click(function () { + CONVERTERS[ext][to](new Uint8Array(e.target.result), name, function (a) { + var n = name.slice(0, -ext.length) + to; + var blob = new Blob([a], {type: "application/bin;charset=utf-8"}); + window.saveAs(blob, n); + }); + + }).appendTo(APP.$rightside); + }); + } + }; + reader.readAsArrayBuffer(file, 'application/octet-stream'); + }); + + UI.removeLoadingScreen(); + + }); +}); diff --git a/www/convert/main.js b/www/convert/main.js new file mode 100644 index 000000000..236290b13 --- /dev/null +++ b/www/convert/main.js @@ -0,0 +1,28 @@ +// Load #1, load as little as possible because we are in a race to get the loading screen up. +define([ + '/bower_components/nthen/index.js', + '/api/config', + '/common/dom-ready.js', + '/common/sframe-common-outer.js' +], function (nThen, ApiConfig, DomReady, SFCommonO) { + + // Loaded in load #2 + nThen(function (waitFor) { + DomReady.onReady(waitFor()); + }).nThen(function (waitFor) { + SFCommonO.initIframe(waitFor, true); + }).nThen(function (/*waitFor*/) { + var category; + if (window.location.hash) { + category = window.location.hash.slice(1); + window.location.hash = ''; + } + var addData = function (obj) { + if (category) { obj.category = category; } + }; + SFCommonO.start({ + noRealtime: true, + addData: addData + }); + }); +}); From 04fc838ef37537cc77b00282986f7b5b505e1813 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Jun 2021 12:08:10 +0200 Subject: [PATCH 007/117] lint compliance --- www/pad/export.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/pad/export.js b/www/pad/export.js index db9f5ac37..01ac27d7e 100644 --- a/www/pad/export.js +++ b/www/pad/export.js @@ -93,10 +93,10 @@ define([ var md = Turndown({ headingStyle: 'atx' }).turndown(toExport); - var blob = new Blob([md], { + var mdBlob = new Blob([md], { type: 'text/markdown;charset=utf-8' }); - return void cb(blob); + return void cb(mdBlob); } var html = module.getHTML(toExport); cb(new Blob([ html ], { type: "text/html;charset=utf-8" })); From 5d156dd346d6b5ce644a81953f7bc1ebcb4c4b80 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 22 Jun 2021 12:24:41 +0200 Subject: [PATCH 008/117] Fix base64 image detection in pads --- www/pad/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/pad/inner.js b/www/pad/inner.js index 47bd7f7f7..ae22af23c 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -1115,7 +1115,7 @@ define([ framework._.sfCommon.isPadStored(function(err, val) { if (!val) { return; } - var b64images = $inner.find('img[src^="data:image"]:not(.cke_reset)'); + var b64images = $inner.find('img[src^="data:image"]:not(.cke_reset), img[src^="data:application/octet-stream"]:not(.cke_reset)'); if (b64images.length && framework._.sfCommon.isLoggedIn()) { var no = h('button.cp-corner-cancel', Messages.cancel); var yes = h('button.cp-corner-primary', Messages.ok); From f5e91ef3ef4c34c97178825c06fec2e81808d741 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 22 Jun 2021 16:16:32 +0530 Subject: [PATCH 009/117] provide installMethod detail in server telemetry --- config/config.example.js | 9 +++++++++ lib/env.js | 1 + lib/stats.js | 1 + 3 files changed, 11 insertions(+) diff --git a/config/config.example.js b/config/config.example.js index 69f0b1e91..96914fa92 100644 --- a/config/config.example.js +++ b/config/config.example.js @@ -276,4 +276,13 @@ module.exports = { * (false by default) */ verbose: false, + + /* Surplus information: + * + * 'installMethod' is included in server telemetry to voluntarily + * indicate how many instances are using unofficial installation methods + * such as Docker. + * + */ + installMethod: 'unspecified', }; diff --git a/lib/env.js b/lib/env.js index 6f1717c09..6b033fa16 100644 --- a/lib/env.js +++ b/lib/env.js @@ -20,6 +20,7 @@ var canonicalizeOrigin = function (s) { module.exports.create = function (config) { const Env = { version: Package.version, + installMethod: config.installMethod || undefined, httpUnsafeOrigin: canonicalizeOrigin(config.httpUnsafeOrigin), httpSafeOrigin: canonicalizeOrigin(config.httpSafeOrigin), diff --git a/lib/stats.js b/lib/stats.js index d1da0e202..da820f7b8 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -4,6 +4,7 @@ const Stats = module.exports; Stats.instanceData = function (Env) { var data = { version: Env.version, + installMethod: Env.installMethod, domain: Env.myDomain, subdomain: Env.mySubdomain, From 881dbcd2ad234cf3e4e95d2c2ab55e6937e6825a Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 22 Jun 2021 16:02:50 +0200 Subject: [PATCH 010/117] Translated using Weblate (Finnish) Currently translated at 81.9% (1110 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fi/ --- www/common/translations/messages.fi.json | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/www/common/translations/messages.fi.json b/www/common/translations/messages.fi.json index d1c5b9bb3..3d6172c14 100644 --- a/www/common/translations/messages.fi.json +++ b/www/common/translations/messages.fi.json @@ -12,7 +12,8 @@ "todo": "Tehtävälista", "contacts": "Yhteystiedot", "sheet": "Taulukko", - "teams": "Teams" + "teams": "Teams", + "form": "Lomake" }, "button_newpad": "Uusi Teksti-padi", "button_newcode": "Uusi Koodi-padi", @@ -28,12 +29,12 @@ "padNotPinnedVariable": "Tämä padi vanhenee {4} päivän käyttämättömyyden jälkeen, {0}kirjaudu sisään{1} tai {2}rekisteröidy{3} säilyttääksesi sen.", "anonymousStoreDisabled": "Tämän CryptPad-instanssin ylläpitäjä on estänyt anonyymien käyttäjien pääsyn tallennustilaan. Kirjaudu sisään käyttääksesi CryptDrivea.", "expiredError": "Tämä padi on vanhentunut, eikä se ole enää saatavilla.", - "deletedError": "Tämä padi on poistettu omistajansa toimesta, eikä se ole enää saatavilla.", + "deletedError": "Tämä padi on poistettu, eikä se ole enää saatavilla.", "inactiveError": "Tämä padi on poistettu käyttämättömyyden vuoksi. Paina Esc-näppäintä luodaksesi uuden padin.", "chainpadError": "Sisältöä päivitettäessä tapahtui vakava virhe. Tämä sivu on vain luku-tilassa, jotta tekemäsi muutokset eivät katoaisi.
Paina Esc-näppäintä jatkaaksesi padin katselua vain luku-tilassa, tai lataa sivu uudelleen yrittääksesi muokkaamista.", "invalidHashError": "Pyytämäsi asiakirjan URL-osoite on virheellinen.", "main_title": "CryptPad: Reaaliaikaista, kollaboratiivista editointia nollatietoperiaatteella", - "errorCopy": " Pääset yhä käyttämään asiakirjan sisältöä painamalla Esc-näppäintä.
Suljettuasi tämän ikkunan sisältö katoaa, etkä voi enää käyttää sitä.", + "errorCopy": " Voit yhä käyttää nykyistä versiota vain luku-tilassa painamalla Esc-näppäintä.", "errorRedirectToHome": "PainaEsc-näppäintä ohjautuaksesi CryptDriveen.", "newVersionError": "Uusi versio CryptPadista on saatavilla.
Lataa sivu uudelleen siirtyäksesi uuteen versioon, tai paina Esc-näppäintä käyttääksesi sisältöäsi offline-tilassa.", "loading": "Ladataan...", @@ -255,7 +256,7 @@ "fm_sharedFolderName": "Jaettu kansio", "fm_searchPlaceholder": "Hae...", "fm_newButton": "Uusi", - "fm_newButtonTitle": "Luo uusi padi tai kansio, tuo tiedosto nykyiseen kansioon", + "fm_newButtonTitle": "Luo uusi asiakirja tai kansio, tuo tiedosto nykyiseen kansioon.", "fm_newFolder": "Uusi kansio", "fm_newFile": "Uusi padi", "fm_morePads": "Lisää", @@ -503,7 +504,7 @@ "mdToolbar_code": "Koodi", "mdToolbar_toc": "Sisällysluettelo", "home_host": "Tämä on itsenäinen yhteisön ylläpitämä Cryptpad-instanssi.", - "main_catch_phrase": "Avoimen lähdekoodin salattu kollaboraatioalusta", + "main_catch_phrase": "Kollaboraatioalusta
päästä päähän -salattu ja avoin lähdekoodi", "footer_aboutUs": "Tietoa meistä", "about": "Tietoa meistä", "privacy": "Yksityisyys", @@ -963,9 +964,9 @@ "properties_addPassword": "Lisää salasana", "password_submit": "Lähetä", "password_placeholder": "Kirjoita salasana tähän...", - "password_error": "Padia ei löytynyt!
Tämä virhe voi johtua kahdesta syystä: joko salasana on virheellinen tai padi on poistettu palvelimelta.", - "password_info": "Padia, jota yrität avata ei ole enää olemassa tai se on suojattu salasanalla. Syötä oikea salasana käyttääksesi padin sisältöä.", - "creation_newPadModalDescription": "Napsauta padityyppiä luodaksesi sellainen. Voit myös painaa Tab-näppäintä valitaksesi tyypin ja Enter vahvistaaksesi valinnan.", + "password_error": "Asiakirjaa ei löytynyt
Tämä virhe voi johtua kahdesta syystä: joko salasana on virheellinen tai asiakirja on poistettu palvelimelta.", + "password_info": "Asiakirja, jota yrität avata ei ole enää olemassa tai se on suojattu uudella salasanalla. Syötä oikea salasana käyttääksesi asiakirjan sisältöä.", + "creation_newPadModalDescription": "Napsauta haluamaasi asiakirjatyyppiä luodaksesi sellaisen. Voit myös painaa Tab-näppäintä valitaksesi tyypin ja Enter-näppäintä vahvistaaksesi valinnan.", "creation_passwordValue": "Salasana", "creation_expiration": "Vanhenemispäivämäärä", "creation_noOwner": "Ei omistajaa", @@ -984,7 +985,7 @@ "creation_404": "Tätä padia ei ole enää olemassa. Käytä seuraavaa lomaketta uuden padin luontiin.", "feedback_optout": "Jos haluat jättäytyä pois tästä toiminnallisuudesta, voit tehdä sen Käyttäjäasetukset-sivulta löytyvän käyttäjäpalautevalintaruudun avulla.", "feedback_privacy": "Välitämme yksityisyydestäsi, ja haluamme samalla tehdä CryptPadista mahdollisimman helppokäyttöisen. Käytämme tätä tiedostoa selvittääksemme, mitkä käyttöliittymätoiminnot ovat tärkeitä käyttäjillemme, pyytämällä sitä tehdyn toiminnon kertovan parametrin yhteydessä.", - "feedback_about": "Jos luet tätä, haluat todennäköisesti tietää, miksi CryptPad lähettää pyyntöjä web-sivuille tiettyjen toimintojen yhteydessä", + "feedback_about": "Jos luet tätä, haluat todennäköisesti tietää, miksi CryptPad lähettää pyyntöjä web-sivuille tiettyjen toimintojen yhteydessä.", "settings_cat_kanban": "Kanban", "kanban_body": "Sisältö", "logoutEverywhere": "Kirjaudu ulos kaikkialta", @@ -1102,5 +1103,12 @@ "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" + "documentID": "Asiakirjan tunniste", + "whatis_collaboration_info": "

CryptPad on rakennettu yhteistyötä varten. Se synkronoi asiakirjoihin tehdyt muutokset reaaliajassa. Kaikki data on salattua, eivätkä palvelu ja sen ylläpitäjät pääse tarkkailemaan asiakirjojen muokkausta tai niihin tallennettua sisältöä.

", + "register_warning_note": "CryptPadin salausrakenteesta johtuen palvelun ylläpitäjät eivät voi palauttaa tietojasi, jos unohdat käyttäjätunnuksesi ja/tai salasanasi. Säilytäthän ne turvallisessa paikassa.", + "register_notes": "
  • Salasanasi on avain, joka salaa kaikki asiakirjasti.Jos kadotat salasanasi, emme voi palauttaa tietojasi.
  • Jos käytät jaettua tietokonetta,muista kirjautua ulos lopettaessasi. Pelkkä selainikkunan sulkeminen jättää käyttäjätunnuksesi haavoittuvaiseksi.
  • Säilyttääksesi kirjautumattomana tekemäsi tai tallentamasi asiakirjat, valitse \"Tuo asiakirjat anonyymistä istunnosta\".
", + "home_support": "

Kehitystiimi ei hyödy käyttäjädatasta millään tavalla. Tämä kuuluu näkemykseemme yksityisyyttä kunnioittavista verkkopalveluista. Toisin kuin itseään \"ilmaisina\" mainostavat verkkoalustat, jotka monetisoivat käyttäjädataa, haluamme rakentaa kestävän käyttäjien omaan tahtoon perustuvan rahoitusmallin.

Voit tukea projektia kertaluonteisella tai jatkuvalla lahjoituksella Open Collective -palvelussamme. Budjettimme on läpinäkyvä ja päivityksiä siihen julkaistaan säännöllisesti. Voit osallistua myös muilla kuin rahallisilla tavoilla.

", + "settings_padOpenLinkLabel": "Ota käyttöön suora linkkien avaus", + "settings_padOpenLinkHint": "Tämä asetus avaa upotetut linkit suoraan napsauttamalla ilman esikatseluikkunaa", + "settings_padOpenLinkTitle": "Avaa linkit ensimmäisellä napsautuksella" } From 433470cf401cf0f54d24c91a9adc85eb5d21fc2b Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 23 Jun 2021 07:54:28 +0530 Subject: [PATCH 011/117] check that server responses don't contain 'Server' headers if they do, check that the server is NGINX. --- www/checkup/main.js | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/www/checkup/main.js b/www/checkup/main.js index 925cd4b7b..2639ff156 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -732,6 +732,54 @@ define([ cb(isHTTPS(trimmedUnsafe) && isHTTPS(trimmedSafe)); }); + assert(function (cb, msg) { + setWarningClass(msg); + $.ajax(cacheBuster('/'), { + dataType: 'text', + complete: function (xhr) { + var serverToken = xhr.getResponseHeader('server'); + if (serverToken === null) { return void cb(true); } + + var lowered = (serverToken || '').toLowerCase(); + var family; + + ['Apache', 'Caddy', 'NGINX'].some(function (pattern) { + if (lowered.indexOf(pattern.toLowerCase()) !== -1) { + family = pattern; + return true; + } + }); + + var text = [ + "This instance is set to respond with an HTTP ", + code("server"), + " header. This information can make it easier for attackers to find and exploit known vulnerabilities. ", + ]; + + + if (family === 'NGINX') { + msg.appendChild(h('span', text.concat([ + "This can be addressed by setting ", + code("server_tokens off"), + " in your global NGINX config." + ]))); + return void cb(serverToken); + } + + // handle other + msg.appendChild(h('span', text.concat([ + "In this case, it appears that the host server is running ", + code(serverToken), + " instead of ", + code("NGINX"), + " as recommended. As such, you may not benefit from the latest security enhancements that are tested and maintained by the CryptPad development team.", + ]))); + + cb(serverToken); + } + }); + }); + if (false) { assert(function (cb, msg) { msg.innerText = 'fake test to simulate failure'; From 6ddcbb948ef7e7f8eb9ad35f936e00ce4f2df3d0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 23 Jun 2021 09:32:58 +0530 Subject: [PATCH 012/117] guard against markdown images with double-quotes in their href --- www/common/diffMarked.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index cb95f37aa..6be2f0e7c 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -267,7 +267,7 @@ define([ }; renderer.image = function (href, title, text) { - if (href.slice(0,6) === '/file/') { + if (href.slice(0,6) === '/file/') { // XXX this has been deprecated for about 3 years... use the same inline image handler as below? // DEPRECATED // Mediatag using markdown syntax should not be used anymore so they don't support // password-protected files @@ -283,12 +283,14 @@ define([ mt += ''; return mt; } - var out = '' + text + '' : '>'; - return out; + + var img = h('img.cp-inline-img', { + src: href || '', + title: title || '', + alt: text || '', + }); + + return img.outerHTML; }; restrictedRenderer.image = renderer.image; From 94abd631a25af7f252379df91444d7434b48059e Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 23 Jun 2021 09:33:39 +0530 Subject: [PATCH 013/117] prototype suppression of markdown images --- .../src/less2/include/markdown.less | 9 ++++++ www/common/diffMarked.js | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index 3943f128d..43d9debaf 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -154,6 +154,15 @@ color: @cp_markdown-block-fg; text-align: left; } + + span.cp-inline-img-warning { + display: inline-block; + border: 1px solid red; + a, br, strong { + border: none; + } + } + //.cp-inline-img { } } .markdown_cryptpad() { diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 6be2f0e7c..770f4daad 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -723,6 +723,35 @@ define([ if (target) { target.scrollIntoView(); } }); + // replace remote images with links to those images + $content.find('img.cp-inline-img').each(function (index, el) { + var link = h('a', { + href: el.src, //common.getBounceURL(el.src), // XXX + target: '_blank', + rel: 'noopener noreferrer', + title: el.src, + }, [ + 'open image at ', + h('strong', el.src), + ]); + + link.onclick = function (ev) { + ev.preventDefault(); + ev.stopPropagation(); + common.openURL(el.src); + }; + + var warning = h('span.cp-inline-img-warning', [ + "CryptPad disallows unencrypted images", + h('br'), + h('br'), + link, + ]); + + var parent = el.parentElement; + parent.replaceChild(warning, el); + }); + // loop over plugin elements in the rendered content $content.find('pre[data-plugin]').each(function (index, el) { var plugin = plugins[el.getAttribute('data-plugin')]; From 761e27cac7582502ab2cb36465beb9b0f5d999f5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 23 Jun 2021 16:19:48 +0530 Subject: [PATCH 014/117] WIP: transform inline css into less and scope it to the preview pane --- www/common/diffMarked.js | 75 +++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index cb95f37aa..9312924ea 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -8,11 +8,12 @@ define([ '/common/inner/common-mediatag.js', '/common/media-tag.js', '/customize/messages.js', + '/common/less.min.js', '/common/highlight/highlight.pack.js', '/lib/diff-dom/diffDOM.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/common/highlight/styles/'+ (window.CryptPad_theme === 'dark' ? 'dark.css' : 'github.css') -],function ($, ApiConfig, Marked, Hash, Util, h, MT, MediaTag, Messages) { +],function ($, ApiConfig, Marked, Hash, Util, h, MT, MediaTag, Messages, Less) { var DiffMd = {}; var Highlight = window.hljs; @@ -473,6 +474,43 @@ define([ } }; + var rendered_less = {}; // XXX this never gets evicted, so it's a memory leak + + var applyCSS = function (el, css) { + var style = h('style'); + style.appendChild(document.createTextNode(css)); + el.innerText = ''; + el.appendChild(style); + }; + + var canonicalizeLess = function (source) { + return source.replace(/\/\/[^\n]*/g, '').replace(/^[ \t]*$/g, '').replace(/\n+/g, ''); + }; + + plugins.less = { // XXX + name: 'less', + attr: 'less-src', + render: function renderLess ($el, opt) { + var src = canonicalizeLess(($el.text() || '').trim()); + + console.log(src); + if (!src) { return; } + var el = $el[0]; + if (rendered_less[src]) { // XXX janky cache instead of using the same methodology as other plugins... + return void applyCSS(el, rendered_less[src]); + } + + var scope = opt.scope.attr('id') || 'cp-app-code-preview-content'; + var scoped_src = '#' + scope + ' { ' + src + '}'; + console.error("RENDERING LESS", opt.cache); + Less.render(scoped_src, {}, function (err, result) { + if (err) { return void console.error(err); } + var css = rendered_less[src] = result.css; + applyCSS(el, css); + }); + }, + }; + var getAvailableCachedElement = function ($content, cache, src) { var cached = cache[src]; if (!Array.isArray(cached)) { return; } @@ -485,7 +523,8 @@ define([ } }; - var cacheRenderedElement = function (cache, src, el) { + var cacheRenderedElement = function (cache, src, el) { // XXX + console.log("CACHING", cache, src, el); if (Array.isArray(cache[src])) { cache[src].push(el); } else { @@ -546,7 +585,9 @@ define([ // caching their source as you go $(newDomFixed).find('pre[data-plugin]').each(function (index, el) { if (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3) { - var plugin = plugins[el.getAttribute('data-plugin')]; + var type = el.getAttribute('data-plugin'); + var plugin = plugins[type]; + console.log(type); if (!plugin) { return; } var src = canonicalizeMermaidSource(el.childNodes[0].wholeText); el.setAttribute(plugin.attr, src); @@ -559,7 +600,8 @@ define([ var scrollTop = $parent.scrollTop(); // iterate over rendered mermaid charts $content.find('pre[data-plugin]:not([processed="true"])').each(function (index, el) { - var plugin = plugins[el.getAttribute('data-plugin')]; + var type = el.getAttribute('data-plugin'); + var plugin = plugins[type]; if (!plugin) { return; } // retrieve the attached source code which it was drawn @@ -721,9 +763,21 @@ define([ if (target) { target.scrollIntoView(); } }); + $content.find('style').each(function (index, el) { // XXX + var parent = el.parentElement; + var pre = h('pre', { + 'data-plugin': 'less', + 'less-src': el.innerText, + style: 'display: none', + }, el.innerText); + parent.replaceChild(pre, el); + }); + // loop over plugin elements in the rendered content - $content.find('pre[data-plugin]').each(function (index, el) { - var plugin = plugins[el.getAttribute('data-plugin')]; + $content.find('pre[data-plugin]').each(function (index, el) { // XXX + var type = el.getAttribute('data-plugin'); + var plugin = plugins[type]; + if (!plugin) { return; } var $el = $(el); $el.off('contextmenu').on('contextmenu', function (e) { @@ -742,13 +796,18 @@ define([ // you can assume that the index of your rendered charts matches that // of those in the markdown source. var src = plugin.source[index]; - el.setAttribute(plugin.attr, src); + if (src) { + el.setAttribute(plugin.attr, src); + } var cached = getAvailableCachedElement($content, plugin.cache, src); // check if you had cached a pre-rendered instance of the supplied source if (typeof(cached) !== 'object') { try { - plugin.render($el); + plugin.render($el, { + scope: $content, // XXX + cache: plugin.cache, + }); } catch (e) { console.error(e); } return; } From c2023fe68011685507b6a0d88f38f257703b3a8f Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 10:03:58 +0530 Subject: [PATCH 015/117] add Thai translation file --- www/common/translations/messages.th.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 www/common/translations/messages.th.json diff --git a/www/common/translations/messages.th.json b/www/common/translations/messages.th.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/www/common/translations/messages.th.json @@ -0,0 +1 @@ +{} From 3f66b91912c7ee7c4e68ef6e1df7e5b83af3f08e Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 10:07:16 +0530 Subject: [PATCH 016/117] archive Arabic, Bengali, and Ukrainian translation files due to inactivity --- www/common/translations/{ => archive}/messages.ar.json | 0 www/common/translations/{ => archive}/messages.bn_BD.json | 0 www/common/translations/{ => archive}/messages.uk.json | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename www/common/translations/{ => archive}/messages.ar.json (100%) rename www/common/translations/{ => archive}/messages.bn_BD.json (100%) rename www/common/translations/{ => archive}/messages.uk.json (100%) diff --git a/www/common/translations/messages.ar.json b/www/common/translations/archive/messages.ar.json similarity index 100% rename from www/common/translations/messages.ar.json rename to www/common/translations/archive/messages.ar.json diff --git a/www/common/translations/messages.bn_BD.json b/www/common/translations/archive/messages.bn_BD.json similarity index 100% rename from www/common/translations/messages.bn_BD.json rename to www/common/translations/archive/messages.bn_BD.json diff --git a/www/common/translations/messages.uk.json b/www/common/translations/archive/messages.uk.json similarity index 100% rename from www/common/translations/messages.uk.json rename to www/common/translations/archive/messages.uk.json From c2ac534f6ae191b25122da7a649463619cfae711 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 10:10:34 +0530 Subject: [PATCH 017/117] archive Hindi and Telugu translations due to inactivity as well --- www/common/translations/{ => archive}/messages.hi.json | 0 www/common/translations/{ => archive}/messages.te.json | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename www/common/translations/{ => archive}/messages.hi.json (100%) rename www/common/translations/{ => archive}/messages.te.json (100%) diff --git a/www/common/translations/messages.hi.json b/www/common/translations/archive/messages.hi.json similarity index 100% rename from www/common/translations/messages.hi.json rename to www/common/translations/archive/messages.hi.json diff --git a/www/common/translations/messages.te.json b/www/common/translations/archive/messages.te.json similarity index 100% rename from www/common/translations/messages.te.json rename to www/common/translations/archive/messages.te.json From c4aeddeee5ac1cfbbf907cf6a428b38fadff2e2e Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 11:48:55 +0530 Subject: [PATCH 018/117] bugfixes for the less cache --- www/common/diffMarked.js | 72 +++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 9312924ea..d2877adbd 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -474,8 +474,6 @@ define([ } }; - var rendered_less = {}; // XXX this never gets evicted, so it's a memory leak - var applyCSS = function (el, css) { var style = h('style'); style.appendChild(document.createTextNode(css)); @@ -483,28 +481,62 @@ define([ el.appendChild(style); }; + // trim non-functional text from less input so that + // the compiler is only triggered when there has been a functional change var canonicalizeLess = function (source) { - return source.replace(/\/\/[^\n]*/g, '').replace(/^[ \t]*$/g, '').replace(/\n+/g, ''); - }; + return (source || '') + // leading and trailing spaces are irrelevant + .trim() + // line comments are easy to disregard + .replace(/\/\/[^\n]*/g, '') + // lines with nothing but spaces and tabs can be ignored + .replace(/^[ \t]*$/g, '') + // consecutive newlines make no difference + .replace(/\n+/g, ''); + }; + + var rendered_less = {}; + var getRenderedLess = (function () { + var timeouts = {}; + return function (src) { + if (!rendered_less[src]) { return; } + if (timeouts[src]) { + clearTimeout(timeouts[src]); + } + // avoid memory leaks by deleting cached content + // 15s after it was last accessed + timeouts[src] = setTimeout(function () { + delete rendered_less[src]; + delete timeouts[src]; + }, 15000); + return rendered_less[src]; + }; + }()); - plugins.less = { // XXX + plugins.less = { name: 'less', attr: 'less-src', render: function renderLess ($el, opt) { - var src = canonicalizeLess(($el.text() || '').trim()); - - console.log(src); + var src = canonicalizeLess($el.text()); if (!src) { return; } var el = $el[0]; - if (rendered_less[src]) { // XXX janky cache instead of using the same methodology as other plugins... - return void applyCSS(el, rendered_less[src]); - } + var rendered = getRenderedLess(src); + if (rendered) { return void applyCSS(el, rendered); } var scope = opt.scope.attr('id') || 'cp-app-code-preview-content'; var scoped_src = '#' + scope + ' { ' + src + '}'; - console.error("RENDERING LESS", opt.cache); + //console.error("RENDERING LESS"); Less.render(scoped_src, {}, function (err, result) { - if (err) { return void console.error(err); } + // the console is the only feedback for users to know that they did something wrong + // but less rendering isn't intended so much as a feature but a useful tool to avoid + // leaking styles from the preview into the rest of the DOM. This is an improvement. + if (err) { + // we assume the compiler is deterministic. Something that returns an error once + // will do it again, so avoid successive calls by caching a truthy + // but non-functional string to block them. + rendered_less[src] = ' '; + return void console.error(err); + } var css = rendered_less[src] = result.css; applyCSS(el, css); }); @@ -523,8 +555,7 @@ define([ } }; - var cacheRenderedElement = function (cache, src, el) { // XXX - console.log("CACHING", cache, src, el); + var cacheRenderedElement = function (cache, src, el) { if (Array.isArray(cache[src])) { cache[src].push(el); } else { @@ -763,18 +794,20 @@ define([ if (target) { target.scrollIntoView(); } }); - $content.find('style').each(function (index, el) { // XXX + // transform style tags into pre tags with the same content + // to be handled by the less rendering plugin + $content.find('style').each(function (index, el) { var parent = el.parentElement; var pre = h('pre', { 'data-plugin': 'less', - 'less-src': el.innerText, + 'less-src': canonicalizeLess(el.innerText), style: 'display: none', }, el.innerText); parent.replaceChild(pre, el); }); // loop over plugin elements in the rendered content - $content.find('pre[data-plugin]').each(function (index, el) { // XXX + $content.find('pre[data-plugin]').each(function (index, el) { var type = el.getAttribute('data-plugin'); var plugin = plugins[type]; @@ -805,8 +838,7 @@ define([ if (typeof(cached) !== 'object') { try { plugin.render($el, { - scope: $content, // XXX - cache: plugin.cache, + scope: $content, }); } catch (e) { console.error(e); } return; From 0cc0118bc2469ebc07b530628cf9ae542ee93cc8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 12:51:52 +0530 Subject: [PATCH 019/117] replace two empty translation files whose removal triggered errors --- www/common/translations/{archive => }/messages.ar.json | 0 www/common/translations/{archive => }/messages.hi.json | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename www/common/translations/{archive => }/messages.ar.json (100%) rename www/common/translations/{archive => }/messages.hi.json (100%) diff --git a/www/common/translations/archive/messages.ar.json b/www/common/translations/messages.ar.json similarity index 100% rename from www/common/translations/archive/messages.ar.json rename to www/common/translations/messages.ar.json diff --git a/www/common/translations/archive/messages.hi.json b/www/common/translations/messages.hi.json similarity index 100% rename from www/common/translations/archive/messages.hi.json rename to www/common/translations/messages.hi.json From e5c8b6fd756675a3430697d221599bc4b71e6506 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 15:08:09 +0530 Subject: [PATCH 020/117] WIP block remote images --- .../src/less2/include/markdown.less | 5 +- www/common/diffMarked.js | 89 ++++++++++++------- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index 43d9debaf..364b3790c 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -155,13 +155,14 @@ text-align: left; } +/* span.cp-inline-img-warning { - display: inline-block; + //display: inline-block; border: 1px solid red; a, br, strong { border: none; } - } + } */ //.cp-inline-img { } } diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 61277bec2..4977cbbac 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -267,7 +267,21 @@ define([ return '
  • ' + text + '
  • \n'; }; - renderer.image = function (href, title, text) { + + var qualifiedHref = function (href) { + if (typeof(window.URL) === 'undefined') { return href; } + try { + var url = new URL(href, ApiConfig.httpUnsafeOrigin); + return url.href; + } catch (err) { + console.error(err); + return href; + } + }; + + var urlArgs = Util.find(ApiConfig, ['requireConf', 'urlArgs']) || ''; + + renderer.image = function (href, title, text) { // XXX if (href.slice(0,6) === '/file/') { // XXX this has been deprecated for about 3 years... use the same inline image handler as below? // DEPRECATED // Mediatag using markdown syntax should not be used anymore so they don't support @@ -285,13 +299,25 @@ define([ return mt; } - var img = h('img.cp-inline-img', { - src: href || '', - title: title || '', - alt: text || '', - }); - - return img.outerHTML; + var warning = h('span.cp-inline-img-warning', [ + h('img', { + src: '/images/broken.png?ver=' + ApiConfig.requireConf.urlArgs, + }), + h('br'), + h('span', { + //title: text, + }, "CryptPad blocked a remote image."), + h('br'), + h('a', { + href: qualifiedHref(href), + }, "Open its source in a new tab"), + h('br'), + h('a', { + href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', + }, 'learn why it was blocked'), + ]); + + return warning.outerHTML; }; restrictedRenderer.image = renderer.image; @@ -741,7 +767,11 @@ define([ if (typeof(patch) === 'string') { throw new Error(patch); } else { - DD.apply($content[0], patch); + try { + DD.apply($content[0], patch); + } catch (err) { + console.error(err); + } var $mts = $content.find('media-tag'); $mts.each(function (i, el) { var $mt = $(el).contextmenu(function (e) { @@ -797,32 +827,31 @@ define([ }); // replace remote images with links to those images - $content.find('img.cp-inline-img').each(function (index, el) { - var link = h('a', { - href: el.src, //common.getBounceURL(el.src), // XXX - target: '_blank', - rel: 'noopener noreferrer', - title: el.src, - }, [ - 'open image at ', - h('strong', el.src), - ]); + $content.find('span.cp-inline-img-warning').each(function (index, el) { // XXX +/* + var link = h('a', { + href: href, //el.src, //common.getBounceURL(el.src), // XXX + //target: '_blank', + //rel: 'noopener noreferrer', + //title: title, //el.src, + }, [ + 'open image at ', + h('strong', href), //el.src), + ]); +*/ + + + console.log('INLINE_IMG', index, el); + if (!el) { return; } + + var link = el.querySelector('a'); + if (!link) { return; } link.onclick = function (ev) { ev.preventDefault(); ev.stopPropagation(); - common.openURL(el.src); + common.openURL(link.href); }; - - var warning = h('span.cp-inline-img-warning', [ - "CryptPad disallows unencrypted images", - h('br'), - h('br'), - link, - ]); - - var parent = el.parentElement; - parent.replaceChild(warning, el); }); // transform style tags into pre tags with the same content From 4dcbddd174c13472b38c08801f4a396395a10b76 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 17:33:45 +0530 Subject: [PATCH 021/117] WIP remote image styles --- .../src/less2/include/markdown.less | 26 ++++++++---- www/common/diffMarked.js | 42 ++++++------------- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index 364b3790c..11c8a7eb4 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -155,15 +155,23 @@ text-align: left; } -/* - span.cp-inline-img-warning { - //display: inline-block; - border: 1px solid red; - a, br, strong { - border: none; - } - } */ - //.cp-inline-img { } + div.cp-inline-img-warning { + display: inline-block; + //border: 1px solid red !important; // @cp_markdown-border !important; + padding: 10px; + //color: @cryptpad_color_light_red; // very bad in light mode + //background: @cryptpad_color_red_fader; + + .cp-inline-img { + display: flex; + margin-bottom:10px; + } + .cp-alt-txt { + margin-left: 10px; + font-family: monospace; + font-size: 0.8em; + } + } } .markdown_cryptpad() { diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 4977cbbac..d432b0841 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -279,8 +279,6 @@ define([ } }; - var urlArgs = Util.find(ApiConfig, ['requireConf', 'urlArgs']) || ''; - renderer.image = function (href, title, text) { // XXX if (href.slice(0,6) === '/file/') { // XXX this has been deprecated for about 3 years... use the same inline image handler as below? // DEPRECATED @@ -299,20 +297,22 @@ define([ return mt; } - var warning = h('span.cp-inline-img-warning', [ - h('img', { - src: '/images/broken.png?ver=' + ApiConfig.requireConf.urlArgs, - }), - h('br'), - h('span', { - //title: text, + var warning = h('div.cp-inline-img-warning', [ + h('div.cp-inline-img', [ + h('img.cp-inline-img', { + src: '/images/broken.png', + title: title || '', + }), + h('p.cp-alt-txt', text), + ]), + h('span.cp-img-block-notice', { }, "CryptPad blocked a remote image."), h('br'), - h('a', { + h('a.cp-remote-img', { href: qualifiedHref(href), }, "Open its source in a new tab"), h('br'), - h('a', { + h('a.cp-learn-more', { href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', }, 'learn why it was blocked'), ]); @@ -827,26 +827,10 @@ define([ }); // replace remote images with links to those images - $content.find('span.cp-inline-img-warning').each(function (index, el) { // XXX -/* - var link = h('a', { - href: href, //el.src, //common.getBounceURL(el.src), // XXX - //target: '_blank', - //rel: 'noopener noreferrer', - //title: title, //el.src, - }, [ - 'open image at ', - h('strong', href), //el.src), - ]); -*/ - - - console.log('INLINE_IMG', index, el); + $content.find('div.cp-inline-img-warning').each(function (index, el) { if (!el) { return; } - - var link = el.querySelector('a'); + var link = el.querySelector('a.cp-remote-img'); if (!link) { return; } - link.onclick = function (ev) { ev.preventDefault(); ev.stopPropagation(); From a86422266e08bfea731eb0b717ca5eae2e64a57a Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 24 Jun 2021 17:56:58 +0530 Subject: [PATCH 022/117] good contrast for most of the remote image warning --- customize.dist/src/less2/include/markdown.less | 7 ++++--- www/common/diffMarked.js | 16 ++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index 11c8a7eb4..3e1837f96 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -157,10 +157,11 @@ div.cp-inline-img-warning { display: inline-block; - //border: 1px solid red !important; // @cp_markdown-border !important; padding: 10px; - //color: @cryptpad_color_light_red; // very bad in light mode - //background: @cryptpad_color_red_fader; + + color: @cryptpad_text_col; + background-color: @cryptpad_color_red_fader; + border: 1px solid @cryptpad_color_red; .cp-inline-img { display: flex; diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index d432b0841..f14b9aab6 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -279,8 +279,12 @@ define([ } }; - renderer.image = function (href, title, text) { // XXX - if (href.slice(0,6) === '/file/') { // XXX this has been deprecated for about 3 years... use the same inline image handler as below? + Messages.resources_imageBlocked = "CryptPad blocked a remote image"; // XXX + Messages.resources_openInNewTab = "Open its source in a new tab"; // XXX + Messages.resources_learnWhy = "Learn why it was blocked"; // XXX + + renderer.image = function (href, title, text) { + if (href.slice(0,6) === '/file/') { // XXX this has been deprecated for about 3 years. Maybe we should display a warning? // DEPRECATED // Mediatag using markdown syntax should not be used anymore so they don't support // password-protected files @@ -301,20 +305,20 @@ define([ h('div.cp-inline-img', [ h('img.cp-inline-img', { src: '/images/broken.png', - title: title || '', + //title: title || '', }), h('p.cp-alt-txt', text), ]), h('span.cp-img-block-notice', { - }, "CryptPad blocked a remote image."), + }, Messages.resources_imageBlocked), h('br'), h('a.cp-remote-img', { href: qualifiedHref(href), - }, "Open its source in a new tab"), + }, Messages.resources_openInNewTab), h('br'), h('a.cp-learn-more', { href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', - }, 'learn why it was blocked'), + }, Messages.resources_learnWhy), ]); return warning.outerHTML; From ec556ed261e3b56e7a160301e2d918835bd4b595 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 24 Jun 2021 15:59:38 +0200 Subject: [PATCH 023/117] Export forms --- www/form/export.js | 60 ++++++++++++++++++++++++++++++++++++++++++++++ www/form/inner.js | 29 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 www/form/export.js diff --git a/www/form/export.js b/www/form/export.js new file mode 100644 index 000000000..e29c6dd87 --- /dev/null +++ b/www/form/export.js @@ -0,0 +1,60 @@ +define([ + '/common/common-util.js', + '/customize/messages.js' +], function (Util, Messages) { + var Export = {}; + + var escapeCSV = function (v) { + if (!/("|,)/.test(v)) { + return v || ''; + } + var value = ''; + var vv = (v || '').replaceAll('"', '""'); + value += '"' + vv + '"'; + return value; + }; + Export.results = function (content, answers, TYPES) { + console.log(content, answers, TYPES); + if (!content || !content.form) { return; } + var csv = ""; + var form = content.form; + + var questions = Object.keys(form).map(function (key) { + var obj = form[key]; + if (!obj) { return; } + return obj.q || Messages.form_default; + }).filter(Boolean); + questions.unshift(Messages.form_poll_time); // "Time" + questions.unshift(Messages.share_formView); // "Participant" + + questions.forEach(function (v, i) { + if (i) { csv += ','; } + csv += escapeCSV(v); + }); + + Object.keys(answers || {}).forEach(function (key) { + var obj = answers[key]; + csv += '\n'; + var time = new Date(obj.time).toISOString(); + var msg = obj.msg || {}; + var user = msg._userdata; + csv += escapeCSV(time); + csv += ',' + escapeCSV(user.name || Messages.anonymous); + Object.keys(form).forEach(function (key) { + csv += ',' + escapeCSV(String(msg[key])); + }); + }); + console.log(csv); + return csv; + }; + + Export.main = function (content, cb) { + var json = Util.clone(content || {}); + delete json.answers; + cb(new Blob([JSON.stringify(json, 0, 2)], { + type: 'application/json;charset=utf-8' + })); + }; + + return Export; +}); diff --git a/www/form/inner.js b/www/form/inner.js index 80c50a0d6..123e86d5b 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -4,6 +4,7 @@ define([ '/bower_components/chainpad-crypto/crypto.js', '/common/sframe-app-framework.js', '/common/toolbar.js', + '/form/export.js', '/bower_components/nthen/index.js', '/common/sframe-common.js', '/common/common-util.js', @@ -30,6 +31,8 @@ define([ 'cm/mode/gfm/gfm', 'css!cm/lib/codemirror.css', + '/bower_components/file-saver/FileSaver.min.js', + 'css!/bower_components/codemirror/lib/codemirror.css', 'css!/bower_components/codemirror/addon/dialog/dialog.css', 'css!/bower_components/codemirror/addon/fold/foldgutter.css', @@ -42,6 +45,7 @@ define([ Crypto, Framework, Toolbar, + Exporter, nThen, SFCommon, Util, @@ -1656,9 +1660,22 @@ define([ var controls = h('div.cp-form-creator-results-controls'); var $controls = $(controls).appendTo($container); + Messages.form_exportCSV = "Export results as CSV"; + var exportButton = h('button.btn.btn-secondary', Messages.form_exportCSV); + var exportCSV = h('div.cp-form-creator-results-export', exportButton); + $(exportCSV).appendTo($container); var results = h('div.cp-form-creator-results-content'); var $results = $(results).appendTo($container); + $(exportButton).click(function () { + var csv = Exporter.results(content, answers, TYPES); + if (!csv) { return void UI.warn(Messages.error); } + var suggestion = APP.framework._.title.suggestTitle('cryptpad-document'); + var title = Util.fixFileName(suggestion) + '.csv'; + window.saveAs(new Blob([csv], { + type: 'text/csv' + }), title); + }); var summary = true; var form = content.form; @@ -2315,6 +2332,7 @@ define([ var andThen = function (framework) { framework.start(); + APP.framework = framework; var evOnChange = Util.mkEvent(); var content = {}; @@ -2739,6 +2757,17 @@ define([ return content; }); + framework.setFileImporter({ accept: ['.json'] }, function (newContent) { + var parsed = JSON.parse(newContent || {}); + parsed.answers = content.answers; + return parsed; + }); + + framework.setFileExporter(['.json'], function(cb, ext) { + Exporter.main(content, cb, ext); + }, true); + + }; Framework.create({ From ef885eed5c20b60810d1cdfbd16e85e26dfa0f5b Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 11:51:18 +0530 Subject: [PATCH 024/117] leave notes for finalizing remote image warning --- www/common/diffMarked.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index f14b9aab6..9e40ad3db 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -305,7 +305,7 @@ define([ h('div.cp-inline-img', [ h('img.cp-inline-img', { src: '/images/broken.png', - //title: title || '', + //title: title || '', // XXX sort out tippy issues (double-title) }), h('p.cp-alt-txt', text), ]), @@ -317,7 +317,7 @@ define([ }, Messages.resources_openInNewTab), h('br'), h('a.cp-learn-more', { - href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', + href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', // XXX point to an actual page }, Messages.resources_learnWhy), ]); From 4a147815f6b7cdd13bd5b74ad90108f5bf315878 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 11:52:24 +0530 Subject: [PATCH 025/117] disable server_tokens test until an easy solution is in place --- www/checkup/main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 2639ff156..732197a2d 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -732,6 +732,7 @@ define([ cb(isHTTPS(trimmedUnsafe) && isHTTPS(trimmedSafe)); }); +/* assert(function (cb, msg) { setWarningClass(msg); $.ajax(cacheBuster('/'), { @@ -756,8 +757,7 @@ define([ " header. This information can make it easier for attackers to find and exploit known vulnerabilities. ", ]; - - if (family === 'NGINX') { + if (family === 'NGINX') { // XXX incorrect instructions for HTTP2. needs a recompile? msg.appendChild(h('span', text.concat([ "This can be addressed by setting ", code("server_tokens off"), @@ -779,6 +779,7 @@ define([ } }); }); +*/ if (false) { assert(function (cb, msg) { From 9104441eb2a6d8c88ad236ce3e8c68b6ec908f45 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 11:58:05 +0530 Subject: [PATCH 026/117] prototype instance purpose radio selection --- www/admin/app-admin.less | 11 ++++++++ www/admin/inner.js | 55 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/www/admin/app-admin.less b/www/admin/app-admin.less index 17450361c..227792540 100644 --- a/www/admin/app-admin.less +++ b/www/admin/app-admin.less @@ -203,6 +203,17 @@ } } + .cp-admin-radio-container { + display: flex; + align-items: left; //center; + flex-wrap: wrap; + flex-direction: column; + label { + margin-right: 40px; + margin-top: 5px; + } + } + .cp-admin-broadcast-form { input.flatpickr-input { width: 307.875px !important; // same width as flatpickr calendar diff --git a/www/admin/inner.js b/www/admin/inner.js index f8bcad681..883db0f84 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -94,6 +94,7 @@ define([ 'cp-admin-list-my-instance', 'cp-admin-consent-to-contact', 'cp-admin-remove-donate-button', + 'cp-admin-instance-purpose', // XXX ], }; @@ -1853,6 +1854,60 @@ define([ }, }); + Messages.admin_instancePurposeTitle = "Instance purpose"; // XXX + Messages.admin_instancePurposeHint = "Why do you run this instance? Your answer will be shared with the developers unless you have disabled telemetry"; // XXX + + Messages.admin_purpose_noanswer = "I prefer not to answer"; // XXX + Messages.admin_purpose_experiment = "To test the CryptPad platform"; // XXX + Messages.admin_purpose_development = "To develop new features for CryptPad"; // XXX + + Messages.admin_purpose_personal = "For myself, family, and friends"; // XXX + + Messages.admin_purpose_business = "For my business's external use"; // XXX + Messages.admin_purpose_intranet = "For my business's internal use"; // XXX + + Messages.admin_purpose_school = "For my school, college, or university"; // XXX + Messages.admin_purpose_org = "For a non-profit organization or advocacy group"; // XXX + + Messages.admin_purpose_commercial = "To provide a commercial service"; // XXX + Messages.admin_purpose_public = "To provide a free service"; // XXX + + create['instance-purpose'] = function () { + var key = 'instance-purpose'; + var $div = makeBlock(key); + + var values = [ + 'noanswer', + 'development', + 'experiment', + 'personal', + 'business', // as a public resource for my business clients + 'intranet', // for my business's _internal use_ + 'school', + 'org', + 'commercial', + 'public', // to provide a free service (for the public) + ]; + + var defaultPurpose = 'noanswer'; + var purpose = defaultPurpose; + + var opts = h('div.cp-admin-radio-container', [ + values.map(function (key) { + var full_key = 'admin_purpose_' + key; + return UI.createRadio('cp-instance-purpose-radio', 'cp-instance-purpose-radio-'+key, + Messages[full_key] || Messages._getKey(full_key, [defaultPurpose]), + key === purpose, { + input: { value: key }, + label: { class: 'noTitle' } + }); + }) + ]); + + $div.append(opts); + return $div; + }; + var hideCategories = function () { APP.$rightside.find('> div').hide(); }; From 0b8239241b5bd09a02eb3a8af0c55d7d233b5892 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 12:23:46 +0530 Subject: [PATCH 027/117] integrate styles for remote images --- .../src/less2/include/markdown.less | 22 ++++++++++++++++--- www/common/diffMarked.js | 10 +++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index 3e1837f96..f52b2666f 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -156,21 +156,37 @@ } div.cp-inline-img-warning { + @cryptpad_test_red_fader: fade(@cryptpad_color_red, 15%); // XXX display: inline-block; padding: 10px; - color: @cryptpad_text_col; - background-color: @cryptpad_color_red_fader; + color: @cryptpad_text_col; // XXX + background-color: @cryptpad_test_red_fader; // XXX @cryptpad_color_red_fader; border: 1px solid @cryptpad_color_red; .cp-inline-img { display: flex; - margin-bottom:10px; + margin-bottom: 10px; } .cp-alt-txt { margin-left: 10px; font-family: monospace; font-size: 0.8em; + color: fade(@cryptpad_text_col, 90%); + } + a { + color: @cryptpad_text_col; + font-size: 0.8em; + &.cp-remote-img::before { + font-family: FontAwesome; + //content: "\f08e\00a0"; + content: "\f08e\00a0\00a0"; + } + &.cp-learn-more::before { + font-family: FontAwesome; + content: "\f059\00a0"; + //content: "\f059\00a0\00a0"; + } } } } diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 9e40ad3db..1f4fadefb 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -314,11 +314,17 @@ define([ h('br'), h('a.cp-remote-img', { href: qualifiedHref(href), - }, Messages.resources_openInNewTab), + }, [ + //h('i.fa.fa-external-link'), // XXX + Messages.resources_openInNewTab + ]), h('br'), h('a.cp-learn-more', { href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', // XXX point to an actual page - }, Messages.resources_learnWhy), + }, [ + //h('i.fa.fa-question-circle'), // XXX + Messages.resources_learnWhy + ]), ]); return warning.outerHTML; From 9027409ce5f53de323b41ee669cfd1d89323dbe9 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 12:29:13 +0530 Subject: [PATCH 028/117] serverside components of instancePurpose flag --- lib/decrees.js | 3 +++ lib/stats.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/lib/decrees.js b/lib/decrees.js index 960ece1ef..5f599705e 100644 --- a/lib/decrees.js +++ b/lib/decrees.js @@ -173,6 +173,9 @@ commands.SET_SUPPORT_MAILBOX = makeGenericSetter('supportMailbox', function (arg return args_isString(args) && Core.isValidPublicKey(args[0]); }); +// CryptPad_AsyncStore.rpc.send('ADMIN', [ 'ADMIN_DECREE', ['SET_INSTANCE_PURPOSE', ["development"]]], console.log) +commands.SET_INSTANCE_PURPOSE = makeGenericSetter('instancePurpose', args_isString); + // Maintenance: Empty string or an object with a start and end time var isNumber = function (value) { return typeof(value) === "number" && !isNaN(value); diff --git a/lib/stats.js b/lib/stats.js index da820f7b8..2a513da44 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -14,6 +14,8 @@ Stats.instanceData = function (Env) { adminEmail: Env.adminEmail, consentToContact: Boolean(Env.consentToContact), + + instancePurpose: Env.instancePurpose, // XXX }; /* We reserve the right to choose not to include instances From ad493e5049c14f403553be2106056a61380e0306 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 12:29:54 +0530 Subject: [PATCH 029/117] add WIP features to changelog --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d33d0e25c..b41b1d9b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# WIP + +* WIP file conversion utilities +* server + * `installMethod: 'unspecified'` in the default config to distinguish docker installs + * `instancePurpose` on admin panel +* display warnings when remote resources are blocked + * in code preview +* restrict style tags to a scope when rendering them in markdown preview by compiling their content as scoped less +* iPhone/Safari calendar and notification fixes (data parsing errors) +* checkup + * display actual FLoC header in checkup test + * WIP check for `server_tokens` settings (needs work for HTTP2) + * nicer output in error/warning tables +* form templates +* guard against a type error in `getAccessKeys` +* guard against invalid or malicious input when constructing media-tags for embedding in markdown + # 4.7.0 ## Goals From 3cbf4c9d6f5a7fa5b7b8991173fe79e5ca088181 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 13:04:29 +0530 Subject: [PATCH 030/117] save instancePurpose choice to server from admin panel --- lib/commands/admin-rpc.js | 1 + www/admin/inner.js | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/commands/admin-rpc.js b/lib/commands/admin-rpc.js index ab48a1086..59750571e 100644 --- a/lib/commands/admin-rpc.js +++ b/lib/commands/admin-rpc.js @@ -326,6 +326,7 @@ var instanceStatus = function (Env, Server, cb) { blockDailyCheck: Env.blockDailyCheck, updateAvailable: Env.updateAvailable, + instancePurpose: Env.instancePurpose, }); }; diff --git a/www/admin/inner.js b/www/admin/inner.js index 883db0f84..592c77a5f 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -1861,7 +1861,7 @@ define([ Messages.admin_purpose_experiment = "To test the CryptPad platform"; // XXX Messages.admin_purpose_development = "To develop new features for CryptPad"; // XXX - Messages.admin_purpose_personal = "For myself, family, and friends"; // XXX + Messages.admin_purpose_personal = "For myself, family, or friends"; // XXX Messages.admin_purpose_business = "For my business's external use"; // XXX Messages.admin_purpose_intranet = "For my business's internal use"; // XXX @@ -1872,6 +1872,13 @@ define([ Messages.admin_purpose_commercial = "To provide a commercial service"; // XXX Messages.admin_purpose_public = "To provide a free service"; // XXX + var sendDecree = function (data, cb) { + sFrameChan.query('Q_ADMIN_RPC', { + cmd: 'ADMIN_DECREE', + data: data, + }, cb); + }; + create['instance-purpose'] = function () { var key = 'instance-purpose'; var $div = makeBlock(key); @@ -1890,7 +1897,7 @@ define([ ]; var defaultPurpose = 'noanswer'; - var purpose = defaultPurpose; + var purpose = APP.instanceStatus.instancePurpose || defaultPurpose; var opts = h('div.cp-admin-radio-container', [ values.map(function (key) { @@ -1904,7 +1911,35 @@ define([ }) ]); + var $opts = $(opts); + //var $br = $(h('br',)); + //$div.append($br); + $div.append(opts); + + var setPurpose = function (value, cb) { + sendDecree([ + 'SET_INSTANCE_PURPOSE', + [ value] + ], cb); + }; + //var spinner = UI.makeSpinner($br); // XXX + + $opts.on('change', function () { + var val = $opts.find('input:radio:checked').val(); + console.log(val); + //spinner.spin(); + setPurpose(val, function (e, response) { + if (e || response.error) { + UI.warn(Messages.error); + //spinner.hide(); + return; + } + //spinner.done(); + UI.log(Messages.saved); + }); + }); + return $div; }; From caece0123e9b0c13228a88513d9843557fb593b8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 20:22:16 +0530 Subject: [PATCH 031/117] archive pin logs instead of removing them outright --- lib/commands/pin-rpc.js | 4 ++-- lib/historyKeeper.js | 2 ++ lib/storage/file.js | 9 ++++++--- lib/workers/db-worker.js | 3 +++ scripts/evict-archived.js | 2 ++ scripts/evict-inactive.js | 2 ++ scripts/lint-translations.js | 8 ++++++++ 7 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 scripts/lint-translations.js diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index 93d922620..ff6bfdbac 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -115,8 +115,8 @@ Pinning.getTotalSize = function (Env, safeKey, cb) { */ Pinning.removePins = function (Env, safeKey, cb) { // FIXME respect the queue - Env.pinStore.removeChannel(safeKey, function (err) { - Env.Log.info('DELETION_PIN_BY_OWNER_RPC', { + Env.pinStore.archiveChannel(safeKey, function (err) { + Env.Log.info('ARCHIVAL_PIN_BY_OWNER_RPC', { safeKey: safeKey, status: err? String(err): 'SUCCESS', }); diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index daa041b5f..44afe0ae0 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -123,6 +123,8 @@ module.exports.create = function (Env, cb) { Store.create({ filePath: pinPath, archivePath: Env.paths.archive, + // indicate that archives should be put in a 'pins' archvie folder + volumeId: 'pins', }, w(function (err, s) { if (err) { throw err; } Env.pinStore = s; diff --git a/lib/storage/file.js b/lib/storage/file.js index 825f14066..30e6c7644 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -51,7 +51,7 @@ var mkPath = function (env, channelId) { }; var mkArchivePath = function (env, channelId) { - return Path.join(env.archiveRoot, 'datastore', channelId.slice(0, 2), channelId) + '.ndjson'; + return Path.join(env.archiveRoot, env.volumeId, channelId.slice(0, 2), channelId) + '.ndjson'; }; var mkMetadataPath = function (env, channelId) { @@ -59,7 +59,7 @@ var mkMetadataPath = function (env, channelId) { }; var mkArchiveMetadataPath = function (env, channelId) { - return Path.join(env.archiveRoot, 'datastore', channelId.slice(0, 2), channelId) + '.metadata.ndjson'; + return Path.join(env.archiveRoot, env.volumeId, channelId.slice(0, 2), channelId) + '.metadata.ndjson'; }; var mkTempPath = function (env, channelId) { @@ -1044,6 +1044,9 @@ module.exports.create = function (conf, _cb) { var env = { root: conf.filePath || './datastore', archiveRoot: conf.archivePath || './data/archive', + // supply a volumeId if you want a store to archive channels to and from + // to its own subpath within the archive directory + volumeId: conf.volumeId || 'datastore', channels: { }, batchGetChannel: BatchRead('store_batch_channel'), }; @@ -1076,7 +1079,7 @@ module.exports.create = function (conf, _cb) { } })); // make sure the cold storage directory exists - Fse.mkdirp(env.archiveRoot, PERMISSIVE, w(function (err) { + Fse.mkdirp(Path.join(env.archiveRoot, env.volumeId), PERMISSIVE, w(function (err) { if (err && err.code !== 'EEXIST') { w.abort(); return void cb(err); diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 8585cc3f6..137b756b4 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -66,6 +66,9 @@ const init = function (config, _cb) { Store.create({ filePath: config.pinPath, archivePath: config.archivePath, + // important to initialize the pinstore with its own volume id + // otherwise archived pin logs will get mixed in with channels + volumeId: 'pins', }, w(function (err, _pinStore) { if (err) { w.abort(); diff --git a/scripts/evict-archived.js b/scripts/evict-archived.js index 7f90f9ff5..255246e99 100644 --- a/scripts/evict-archived.js +++ b/scripts/evict-archived.js @@ -56,6 +56,8 @@ var prepareEnv = function (Env, cb) { Store.create({ filePath: config.pinPath, + // archive pin logs to their own subpath + volumeId: 'pins', }, w(function (err, _) { if (err) { w.abort(); diff --git a/scripts/evict-inactive.js b/scripts/evict-inactive.js index bf7e1ca5b..2521e014f 100644 --- a/scripts/evict-inactive.js +++ b/scripts/evict-inactive.js @@ -56,6 +56,8 @@ var prepareEnv = function (Env, cb) { Store.create({ filePath: config.pinPath, + // archive pin logs to their own subpath + volumeId: 'pins', }, w(function (err, _) { if (err) { w.abort(); diff --git a/scripts/lint-translations.js b/scripts/lint-translations.js new file mode 100644 index 000000000..a38cd615a --- /dev/null +++ b/scripts/lint-translations.js @@ -0,0 +1,8 @@ +// TODO unify the following scripts + // unused-translations.js + // find-html-translations + +// more linting + // Search for 'Cryptpad' string (should be 'CryptPad') + // Search English for -ise\s + From 9806d718d5aaffee95c74d346ae12a88e1ed50d4 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 25 Jun 2021 20:53:09 +0530 Subject: [PATCH 032/117] implement block archival --- lib/commands/block.js | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/commands/block.js b/lib/commands/block.js index 8180cb68e..e405ede85 100644 --- a/lib/commands/block.js +++ b/lib/commands/block.js @@ -86,6 +86,20 @@ var createLoginBlockPath = function (Env, publicKey) { // FIXME BLOCKS return Path.join(Env.paths.block, safeKey.slice(0, 2), safeKey); }; +var createLoginBlockArchivePath = function (Env, publicKey) { + // prepare publicKey to be used as a file name + var safeKey = Util.escapeKeyCharacters(publicKey); + + // validate safeKey + if (typeof(safeKey) !== 'string') { + return; + } + + // derive the full path + // /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd + return Path.join(Env.paths.archive, 'block', safeKey.slice(0, 2), safeKey); +}; + Block.validateAncestorProof = function (Env, proof, _cb) { var cb = Util.once(Util.mkAsync(_cb)); /* prove that you own an existing block by signing for its publicKey */ @@ -216,7 +230,7 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS information, we can just sign some constant and use that as proof. */ -Block.removeLoginBlock = function (Env, safeKey, msg, cb) { // FIXME BLOCKS +Block.removeLoginBlock = function (Env, safeKey, msg, cb) { var publicKey = msg[0]; var signature = msg[1]; var block = Nacl.util.decodeUTF8('DELETE_BLOCK'); // clients and the server will have to agree on this constant @@ -230,21 +244,28 @@ Block.removeLoginBlock = function (Env, safeKey, msg, cb) { // FIXME BLOCKS validateLoginBlock(Env, publicKey, signature, block, function (e /*::, validatedBlock */) { if (e) { return void cb(e); } // derive the filepath - var path = createLoginBlockPath(Env, publicKey); + var currentPath = createLoginBlockPath(Env, publicKey); // make sure the path is valid - if (typeof(path) !== 'string') { + if (typeof(currentPath) !== 'string') { return void cb('E_INVALID_BLOCK_PATH'); } - // FIXME COLDSTORAGE - Fs.unlink(path, function (err) { - Env.Log.info('DELETION_BLOCK_BY_OWNER_RPC', { + var archivePath = createLoginBlockArchivePath(Env, publicKey); + // make sure the path is valid + if (typeof(archivePath) !== 'string') { + return void cb('E_INVALID_BLOCK_ARCHIVAL_PATH'); + } + + Fse.move(currentPath, archivePath, { + overwrite: true, + }, function (err) { + Env.Log.info('ARCHIVAL_BLOCK_BY_OWNER_RPC', { publicKey: publicKey, - path: path, + currentPath: currentPath, + archivePath: archivePath, status: err? String(err): 'SUCCESS', }); - if (err) { return void cb(err); } cb(); }); From ba1a7b37e1a603b55dd6c979689ec481c9877d29 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 28 Jun 2021 14:39:26 +0530 Subject: [PATCH 033/117] separate validation and storage methods for blocks --- lib/commands/block.js | 117 ++++++++---------------------------------- lib/storage/block.js | 92 +++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 96 deletions(-) create mode 100644 lib/storage/block.js diff --git a/lib/commands/block.js b/lib/commands/block.js index e405ede85..947740908 100644 --- a/lib/commands/block.js +++ b/lib/commands/block.js @@ -1,14 +1,10 @@ /*jshint esversion: 6 */ /* globals Buffer*/ -var Block = module.exports; - -const Fs = require("fs"); -const Fse = require("fs-extra"); -const Path = require("path"); +const Block = module.exports; const Nacl = require("tweetnacl/nacl-fast"); const nThen = require("nthen"); - const Util = require("../common-util"); +const BlockStore = require("../storage/block"); /* We assume that the server is secured against MitM attacks @@ -31,7 +27,9 @@ const Util = require("../common-util"); author of the block, since we assume that the block will have been encrypted with xsalsa20-poly1305 which is authenticated. */ -var validateLoginBlock = function (Env, publicKey, signature, block, cb) { // FIXME BLOCKS +var validateLoginBlock = function (Env, publicKey, signature, block, _cb) { // FIXME BLOCKS + var cb = Util.once(Util.mkAsync(_cb)); + // convert the public key to a Uint8Array and validate it if (typeof(publicKey) !== 'string') { return void cb('E_INVALID_KEY'); } @@ -72,34 +70,6 @@ var validateLoginBlock = function (Env, publicKey, signature, block, cb) { // FI return void cb(null, u8_block); }; -var createLoginBlockPath = function (Env, publicKey) { // FIXME BLOCKS - // prepare publicKey to be used as a file name - var safeKey = Util.escapeKeyCharacters(publicKey); - - // validate safeKey - if (typeof(safeKey) !== 'string') { - return; - } - - // derive the full path - // /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd - return Path.join(Env.paths.block, safeKey.slice(0, 2), safeKey); -}; - -var createLoginBlockArchivePath = function (Env, publicKey) { - // prepare publicKey to be used as a file name - var safeKey = Util.escapeKeyCharacters(publicKey); - - // validate safeKey - if (typeof(safeKey) !== 'string') { - return; - } - - // derive the full path - // /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd - return Path.join(Env.paths.archive, 'block', safeKey.slice(0, 2), safeKey); -}; - Block.validateAncestorProof = function (Env, proof, _cb) { var cb = Util.once(Util.mkAsync(_cb)); /* prove that you own an existing block by signing for its publicKey */ @@ -117,31 +87,26 @@ Block.validateAncestorProof = function (Env, proof, _cb) { return void cb('E_INVALID_ANCESTOR_PROOF'); } // else fall through to next step - }).nThen(function (w) { - var path = createLoginBlockPath(Env, pub); - Fs.access(path, Fs.constants.F_OK, w(function (err) { - if (!err) { return; } - w.abort(); // else - return void cb("E_MISSING_ANCESTOR"); - })); }).nThen(function () { - cb(void 0, pub); + Block.check(Env, pub, function (err) { + if (err) { return void cb('E_MISSING_ANCESTOR'); } + cb(void 0, pub); + }); }); } catch (err) { return void cb(err); } }; -Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS +Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { var cb = Util.once(Util.mkAsync(_cb)); - //console.log(msg); var publicKey = msg[0]; var signature = msg[1]; var block = msg[2]; var registrationProof = msg[3]; var previousKey; - var validatedBlock, parsed, path; + var validatedBlock, path; nThen(function (w) { if (Util.escapeKeyCharacters(publicKey) !== safeKey) { w.abort(); @@ -181,33 +146,9 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS } validatedBlock = _validatedBlock; - - // derive the filepath - path = createLoginBlockPath(Env, publicKey); - - // make sure the path is valid - if (typeof(path) !== 'string') { - return void cb('E_INVALID_BLOCK_PATH'); - } - - parsed = Path.parse(path); - if (!parsed || typeof(parsed.dir) !== 'string') { - w.abort(); - return void cb("E_INVALID_BLOCK_PATH_2"); - } - })); - }).nThen(function (w) { - // make sure the path to the file exists - Fse.mkdirp(parsed.dir, w(function (e) { - if (e) { - w.abort(); - cb(e); - } })); }).nThen(function () { - // actually write the block - Fs.writeFile(path, Buffer.from(validatedBlock), { encoding: "binary", }, function (err) { - if (err) { return void cb(err); } + BlockStore.write(Env, publicKey, Buffer.from(validatedBlock), function (err) { Env.Log.info('BLOCK_WRITE_BY_OWNER', { safeKey: safeKey, blockId: publicKey, @@ -215,11 +156,13 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS previousKey: previousKey, path: path, }); - cb(); + cb(err); }); }); }; +const DELETE_BLOCK = Nacl.util.decodeUTF8('DELETE_BLOCK'); + /* When users write a block, they upload the block, and provide a signature proving that they deserve to be able to write to @@ -230,10 +173,11 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS information, we can just sign some constant and use that as proof. */ -Block.removeLoginBlock = function (Env, safeKey, msg, cb) { +Block.removeLoginBlock = function (Env, safeKey, msg, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + var publicKey = msg[0]; var signature = msg[1]; - var block = Nacl.util.decodeUTF8('DELETE_BLOCK'); // clients and the server will have to agree on this constant nThen(function (w) { if (Util.escapeKeyCharacters(publicKey) !== safeKey) { @@ -241,33 +185,14 @@ Block.removeLoginBlock = function (Env, safeKey, msg, cb) { return void cb("INCORRECT_KEY"); } }).nThen(function () { - validateLoginBlock(Env, publicKey, signature, block, function (e /*::, validatedBlock */) { + validateLoginBlock(Env, publicKey, signature, DELETE_BLOCK, function (e /*::, validatedBlock */) { if (e) { return void cb(e); } - // derive the filepath - var currentPath = createLoginBlockPath(Env, publicKey); - - // make sure the path is valid - if (typeof(currentPath) !== 'string') { - return void cb('E_INVALID_BLOCK_PATH'); - } - - var archivePath = createLoginBlockArchivePath(Env, publicKey); - // make sure the path is valid - if (typeof(archivePath) !== 'string') { - return void cb('E_INVALID_BLOCK_ARCHIVAL_PATH'); - } - - Fse.move(currentPath, archivePath, { - overwrite: true, - }, function (err) { + BlockStore.archive(Env, publicKey, function (err) { Env.Log.info('ARCHIVAL_BLOCK_BY_OWNER_RPC', { publicKey: publicKey, - currentPath: currentPath, - archivePath: archivePath, status: err? String(err): 'SUCCESS', }); - if (err) { return void cb(err); } - cb(); + cb(err); }); }); }); diff --git a/lib/storage/block.js b/lib/storage/block.js new file mode 100644 index 000000000..5dfc393a5 --- /dev/null +++ b/lib/storage/block.js @@ -0,0 +1,92 @@ +/*jshint esversion: 6 */ +const Block = module.exports; +const Util = require("../common-util"); +const Path = require("path"); +const Fs = require("fs"); +const Fse = require("fs-extra"); +const nThen = require("nthen"); + +Block.mkPath = function (Env, publicKey) { + // prepare publicKey to be used as a file name + var safeKey = Util.escapeKeyCharacters(publicKey); + + // validate safeKey + if (typeof(safeKey) !== 'string') { return; } + + // derive the full path + // /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd + return Path.join(Env.paths.block, safeKey.slice(0, 2), safeKey); +}; + +Block.mkArchivePath = function (Env, publicKey) { + // prepare publicKey to be used as a file name + var safeKey = Util.escapeKeyCharacters(publicKey); + + // validate safeKey + if (typeof(safeKey) !== 'string') { + return; + } + + // derive the full path + // /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd + return Path.join(Env.paths.archive, 'block', safeKey.slice(0, 2), safeKey); +}; + +Block.archive = function (Env, publicKey, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + + // derive the filepath + var currentPath = Block.mkPath(Env, publicKey); + + // make sure the path is valid + if (typeof(currentPath) !== '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'); + } + + Fse.move(currentPath, archivePath, { + overwrite: true, + }, 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); + Fs.access(path, Fs.constants.F_OK, cb); +}; + +Block.write = function (Env, publicKey, buffer, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + var path = Block.mkPath(Env, publicKey); + if (typeof(path) !== 'string') { return void cb('INVALID_PATH'); } + var parsed = Path.parse(path); + + nThen(function (w) { + Fse.mkdirp(parsed.dir, w(function (err) { + if (!err) { return; } + w.abort(); + cb(err); + })); + }).nThen(function () { + // XXX BLOCK check whether this overwrites a block + // XXX archive the old one if so + Fs.writeFile(path, buffer, { encoding: 'binary' }, cb); + }); +}; + +/* +Block.create = function (opt, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); + + var env = { + root: opt.root || '', // XXX + + + }; +}; +*/ From 7c7acbeae68580254d8a953393f751d2a1689a8c Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 28 Jun 2021 15:07:48 +0530 Subject: [PATCH 034/117] delegate block validation to workers --- lib/commands/block.js | 20 +++++++++++++------- lib/workers/db-worker.js | 4 ++++ lib/workers/index.js | 9 +++++++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/commands/block.js b/lib/commands/block.js index 947740908..ea6a19dc2 100644 --- a/lib/commands/block.js +++ b/lib/commands/block.js @@ -27,7 +27,7 @@ const BlockStore = require("../storage/block"); author of the block, since we assume that the block will have been encrypted with xsalsa20-poly1305 which is authenticated. */ -var validateLoginBlock = function (Env, publicKey, signature, block, _cb) { // FIXME BLOCKS +Block.validateLoginBlock = function (Env, publicKey, signature, block, _cb) { var cb = Util.once(Util.mkAsync(_cb)); // convert the public key to a Uint8Array and validate it @@ -67,7 +67,7 @@ var validateLoginBlock = function (Env, publicKey, signature, block, _cb) { // F // call back with (err) if unsuccessful if (!verified) { return void cb("E_COULD_NOT_VERIFY"); } - return void cb(null, u8_block); + return void cb(null, block); }; Block.validateAncestorProof = function (Env, proof, _cb) { @@ -135,20 +135,26 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { previousKey = provenKey; })); }).nThen(function (w) { - validateLoginBlock(Env, publicKey, signature, block, w(function (e, _validatedBlock) { + Env.validateLoginBlock(publicKey, signature, block, w(function (e, _validatedBlock) { if (e) { w.abort(); return void cb(e); } - if (!(_validatedBlock instanceof Uint8Array)) { + if (typeof(_validatedBlock) !== 'string') { w.abort(); - return void cb('E_INVALID_BLOCK'); + return void cb('E_INVALID_BLOCK_RETURNED'); } validatedBlock = _validatedBlock; })); }).nThen(function () { - BlockStore.write(Env, publicKey, Buffer.from(validatedBlock), function (err) { + var buffer; + try { + buffer = Buffer.from(Nacl.util.decodeBase64(validatedBlock)); + } catch (err) { + return void cb('E_BLOCK_DESERIALIZATION'); + } + BlockStore.write(Env, publicKey, buffer, function (err) { Env.Log.info('BLOCK_WRITE_BY_OWNER', { safeKey: safeKey, blockId: publicKey, @@ -185,7 +191,7 @@ Block.removeLoginBlock = function (Env, safeKey, msg, _cb) { return void cb("INCORRECT_KEY"); } }).nThen(function () { - validateLoginBlock(Env, publicKey, signature, DELETE_BLOCK, function (e /*::, validatedBlock */) { + Env.validateLoginBlock(publicKey, signature, DELETE_BLOCK, function (e) { if (e) { return void cb(e); } BlockStore.archive(Env, publicKey, function (err) { Env.Log.info('ARCHIVAL_BLOCK_BY_OWNER_RPC', { diff --git a/lib/workers/db-worker.js b/lib/workers/db-worker.js index 137b756b4..2371240ec 100644 --- a/lib/workers/db-worker.js +++ b/lib/workers/db-worker.js @@ -697,6 +697,10 @@ COMMANDS.VALIDATE_ANCESTOR_PROOF = function (data, cb) { Block.validateAncestorProof(Env, data && data.proof, cb); }; +COMMANDS.VALIDATE_LOGIN_BLOCK = function (data, cb) { + Block.validateLoginBlock(Env, data.publicKey, data.signature, data.block, cb); +}; + process.on('message', function (data) { if (!data || !data.txid || !data.pid) { return void process.send({ diff --git a/lib/workers/index.js b/lib/workers/index.js index 85c66eeb5..c2bfb5740 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -451,6 +451,15 @@ Workers.initialize = function (Env, config, _cb) { }, cb); }; + Env.validateLoginBlock = function (publicKey, signature, block, cb) { + sendCommand({ + command: 'VALIDATE_LOGIN_BLOCK', + publicKey: publicKey, + signature: signature, + block: block, + }, cb); + }; + cb(void 0); }); }; From 83693a18f28472b44cdbf68c3956b0d3659476b9 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 29 Jun 2021 06:02:56 +0200 Subject: [PATCH 035/117] Translated using Weblate (Japanese) Currently translated at 84.3% (1142 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 81.6% (1106 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 76.2% (1033 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 76.2% (1033 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 55.4% (751 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 824 ++++++++++++++++++++++- 1 file changed, 794 insertions(+), 30 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 3751f0cbb..c56daf9c4 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1,5 +1,5 @@ { - "common_connectionLost": "サーバーとの接続が切断しました。\nサーバーと再接続するまで閲覧モードになります。", + "common_connectionLost": "サーバーとの接続が切断しました
    再接続するまで閲覧モードになります。", "button_newsheet": "新規スプレッドシート", "button_newkanban": "新規看板", "button_newwhiteboard": "新規ホワイトボード", @@ -10,17 +10,18 @@ "type": { "teams": "チーム", "contacts": "連絡先", - "todo": "やることリスト", + "todo": "タスクリスト", "media": "メディア", "file": "ファイル", "whiteboard": "ホワイトボード", "drive": "CryptDrive", - "slide": "プレゼン", - "kanban": "看板", + "slide": "プレゼンテーション", + "kanban": "カンバン", "poll": "投票", "code": "コード", "pad": "リッチテキスト", - "sheet": "シート" + "sheet": "シート", + "form": "フォーム" }, "main_title": "CryptPad - 安全にリアルタイム編集可能なコラボレーションツール", "support_formButton": "送信", @@ -122,7 +123,7 @@ "login_hashing": "パスワードをハッシュ化しています、この処理には時間がかかる場合があります。", "login_invalPass": "パスワードを入力してください", "login_invalUser": "ユーザー名を入力してください", - "register_importRecent": "匿名セッション中のパッドをインポート", + "register_importRecent": "未登録のセッション中のドキュメントをインポート", "importButton": "インポート", "main_catch_phrase": "コラボレーションスイート
    暗号化されかつオープンソース", "tos_3rdparties": "私たちは、法律で義務付けられている場合を除き、個別のデータを第三者に提供しません。", @@ -138,9 +139,9 @@ "footer_aboutUs": "私たちについて", "pricing": "料金", "contact": "連絡先", - "privacy": "プライバシー", + "privacy": "プライバシーポリシー", "blog": "ブログ", - "register_header": "CryptPad へようこそ", + "register_header": "登録", "login_confirm": "パスワードの確認", "login_register": "新規登録", "login_username": "ユーザー名", @@ -173,7 +174,7 @@ "teams_table": "権限", "contacts_fetchHistory": "古い履歴を取得する", "contacts_warning": "ここに入力したすべてのものは永続的であり、このパッドの現在および将来のすべてのユーザーが利用できます。機密情報の入力は推奨されません!", - "contacts_typeHere": "メッセージを入力...", + "contacts_typeHere": "ここにメッセージを入力...", "team_cat_drive": "ドライブ", "team_cat_chat": "チャット", "team_cat_members": "メンバー", @@ -247,14 +248,14 @@ "fc_restore": "復元", "fc_delete_owned": "完全削除", "creation_create": "作成", - "creation_password": "パスワードの追加", + "creation_password": "パスワード\n", "creation_expireMonths": "か月", "creation_expireDays": "日", "creation_expireHours": "時間", "creation_expireFalse": "無制限", "pad_wordCount": "単語数: {0}", "teams_table_role": "権限", - "templateSaved": "テンプレートを保存しました", + "templateSaved": "テンプレートを保存しました!", "saveTemplateButton": "テンプレートとして保存", "fm_rootName": "ドキュメント", "team_listTitle": "あなたのチーム", @@ -263,21 +264,21 @@ "features_f_devices": "全てのデバイスであなたのパッドを利用", "features_f_cryptdrive1_note": "フォルダ、共有フォルダ、テンプレート、タグ", "features_f_cryptdrive1": "CryptDrive への完全なアクセス", - "features_f_anon_note": "匿名ユーザーが利用可能な全機能を利用できます", + "features_f_anon_note": "追加機能あり", "features_f_anon": "匿名ユーザーの全機能", - "features_f_storage0_note": "作成されたパッドは、3か月以上使用されないと削除される可能性があります", + "features_f_storage0_note": "ドキュメントは{0}日以上使用されないと削除されます", "features_f_storage0": "一時的な保存", "features_f_cryptdrive0_note": "後で開けるようにブラウザにアクセスしたパッドを保存する機能", "features_f_cryptdrive0": "CryptDrive への限定的なアクセス", - "features_f_file0_note": "他のユーザーが共有したファイルを表示およびダウンロードできます", - "features_f_file0": "ファイルを開く", + "features_f_file0_note": "他のユーザーが共有したドキュメントを表示およびダウンロードできます", + "features_f_file0": "ドキュメントを開く", "features_f_core_note": "編集、インポートとエクスポート、履歴、ユーザーリスト、チャット", - "features_f_core": "アプリケーションの一般的な機能", - "features_f_apps": "主なアプリケーションへのアクセス", - "features_premium": "プレミアムユーザー", - "features_registered": "登録ユーザー", - "features_title": "機能の比較", - "features_anon": "匿名ユーザー", + "features_f_core": "一般的な機能", + "features_f_apps": "全アプリケーションへのアクセス", + "features_premium": "プレミアム", + "features_registered": "登録済", + "features_title": "機能", + "features_anon": "未登録", "register_whyRegister": "登録するとどの様な利点がありますか?", "historyText": "履歴", "help_button": "ヘルプ", @@ -289,8 +290,8 @@ "fm_noResult": "見つかりませんでした", "fm_info_trash": "ごみ箱を空にすると、あなたの CryptDrive の使用可能容量を増やせます。", "features_f_file1": "ファイルのアップロードと共有", - "features_f_social_note": "プロフィールの作成、アバターの使用、連絡先とのチャット", - "features_f_social": "特別なアプリケーション", + "features_f_social_note": "追加した連絡先との安全なコラボレーション、プロフィールの作成、きめ細かいアクセス権のコントロール", + "features_f_social": "ソーシャル機能", "tos_e2ee": "CryptPad のコンテンツは、パッドのフラグメント識別子を推測または取得できる人物なら誰でも閲覧や編集が行えます。エンドツーエンド暗号化(E2EE)を採用したメッセンジャーサービスなどを使用してリンクを共有し、リンク漏洩が発生しないよう対策を行ってください。", "contact_chat": "チャット", "contact_bug": "バグの報告", @@ -310,10 +311,10 @@ "homePage": "ホームページ", "features_noData": "登録に個人情報は必要ありません", "features_f_register": "無料登録", - "features_f_storage1_note": "CryptDrive に保存されたパッドが有効期限切れで削除されることはありません", + "features_f_storage1_note": "CryptDriveに保存したドキュメントは、有効期限切れで削除されることはありません", "features_f_storage1": "永続的ストレージ (50MB)", "oo_sheetMigration_complete": "新しいバージョンが利用可能です。「OK」を押して再読み込みしてください。", - "oo_sheetMigration_loading": "あなたのスプレッドシートを最新バージョンにアップグレードしています", + "oo_sheetMigration_loading": "あなたのスプレッドシートを最新バージョンにアップグレードしています。1分程度お待ちください。", "settings_ownDriveButton": "アカウントをアップグレード", "features_f_file1_note": "連絡先とファイルを共有したり、パッドを埋め込む", "crowdfunding_button": "CryptPad を支援", @@ -321,11 +322,11 @@ "properties_passwordSuccessFile": "パスワードは正常に変更されました。", "drive_sfPasswordError": "誤ったパスワードです", "team_title": "チーム: {0}", - "password_error": "パッドが存在しません!
    このエラーは「誤ったパスワードが入力された」場合、または「パッドがサーバーから削除された」場合に発生します。", + "password_error": "ドキュメントが存在しません!
    このエラーは、誤ったパスワードが入力された場合、またはドキュメントがサーバーから完全削除された場合に発生します。", "password_error_seed": "パッドが存在しません!
    このエラーは「パスワードが追加・変更された」場合、または「パッドがサーバーから削除された」場合に発生します。", "password_submit": "送信", "password_placeholder": "パスワードを入力...", - "password_info": "開こうとしているパッドが存在しないか、パスワードで保護されています。コンテンツにアクセスするには、正しいパスワードを入力してください。", + "password_info": "開こうとしているドキュメントが存在しないか、新しいパスワードで保護されています。コンテンツにアクセスするには、正しいパスワードを入力してください。", "properties_confirmNew": "パスワードを追加すると、このパッドの URL が変更され、履歴が削除されます。パスワードを知らないユーザーは、このパッドへアクセスできなくなります。続行してよろしいですか?", "properties_changePassword": "パスワードの変更", "properties_addPassword": "パスワードの追加", @@ -389,7 +390,770 @@ "home_opensource": "CryptPad は、個人やプロなど誰でもホストすることができます。ソースコードは GitHub で確認できます。", "home_opensource_title": "オープンソース", "home_host_title": "このインスタンスについて", - "home_privacy_text": "CryptPad は、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。すべてのコンテンツは、あなたのブラウザ上で暗号化および復号されます。つまり、ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービス管理者でさえ、あなたの情報にアクセスすることはできません。", - "home_privacy_title": "プライバシーバイデザイン", - "mdToolbar_tutorial": "https://www.markdowntutorial.com/jp/" + "home_privacy_text": "CryptPad は、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。すべてのコンテンツは、あなたのブラウザ上で暗号化および復号化されます。つまり、ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービス管理者でさえ、あなたの情報にアクセスすることはできません。", + "home_privacy_title": "プライバシー・バイ・デザイン", + "mdToolbar_tutorial": "https://www.markdowntutorial.com/jp/", + "languageButtonTitle": "シンタックスハイライトを行う言語を選択してください", + "useTemplate": "テンプレートで始めますか?", + "oo_uploaded": "アップロードが完了しました。OKをクリックしてページを再読み込みするか、キャンセルをクリックして閲覧モードを継続してください。", + "poll_descriptionHint": "投票の詳細を記入してください。入力が終了したら✓(公開)ボタンをクリックしてください。\n詳細はマークダウンの構文で記入できます。CryptDriveのメディアファイルを埋め込むこともできます。\nリンクを知っているひとは誰でも詳細を変更できますが、推奨されません。", + "pad_mediatagBorder": "枠線の幅(ピクセル)", + "openLinkInNewTab": "新しいタブでリンクを開く", + "history_restorePrompt": "ドキュメントの現在のバージョンを、表示しているバージョンと置き換えてよろしいですか?", + "slideOptionsTitle": "スライドをカスタマイズ", + "propertiesButtonTitle": "パッドのプロパティを表示", + "driveOfflineError": "CryptPadへの接続が切れています。このパッドに加えられる変更はCryptDriveに保存されません。CryptPadの全てのタブを閉じて、新しいウィンドウで開いてみてください。 ", + "properties_passwordWarningFile": "パスワードは変更されましたが、新しいデータでCryptDriveを更新することができませんでした。古いバージョンのファイルを手動で削除する必要があるかもしれません。", + "properties_confirmNewFile": "よろしいですか?パスワードを追加するとファイルのURLが変わります。パスワードをもたないユーザーは、このファイルにアクセスできなくなります。", + "properties_confirmChangeFile": "よろしいですか?新しいパスワードをもたないユーザーは、このファイルにアクセスできなくなります。", + "team_quota": "あなたのチームのストレージの容量制限", + "team_pendingOwner": "(保留中)", + "fm_contextMenuError": "そのアイテムのコンテクストメニューを開けません。問題が続くなら、ページを再読み込みしてみてください。", + "fm_selectError": "そのアイテムを選択できません。問題が続くなら、ページを再読み込みしてみてください。", + "fm_unknownFolderError": "選択、あるいは最後に開いたディレクトリは存在しません。親フォルダを開きます…", + "fm_restoreDialog": "{0}を元の場所に復元してよろしいですか?", + "fm_removeSeveralPermanentlyDialog": "ドライブから{0}個のアイテムを削除してよろしいですか?他のユーザーのドライブからは削除されません。", + "fm_removePermanentlyDialog": "ドライブからこのアイテムを削除してよろしいですか?他のユーザーのドライブからは削除されません。", + "fm_noname": "無題のドキュメント", + "fm_openParent": "フォルダに表示", + "fm_newButtonTitle": "新しいドキュメントやフォルダを作成し、ファイルを現在のフォルダにインポートします。", + "contacts_info4": "チャットの参加者のどちらも履歴を削除できます", + "contacts_info2": "連絡先のアイコンをクリックしてチャットを開始", + "contacts_confirmRemove": "{0}をあなたの連絡先から削除してよろしいですか?", + "profile_error": "プロフィールの作成時にエラーが発生しました: {0}", + "profile_uploadSizeError": "エラー: アバターは{0}より小さい必要があります", + "kanban_addBoard": "ボードを追加", + "viewShare": "読み込み専用のリンク", + "mediatag_loadButton": "添付ファイルを読み込む", + "settings_disableThumbnailsAction": "CryptDriveでのサムネイルの作成を無効にする", + "settings_resetError": "入力したテキストが正しくありません。CryptDriveのデータは消去されていません。", + "settings_resetDone": "データが消去されました!", + "settings_resetPrompt": "あなたのドライブから全てのパッドを削除します。
    本当に続けてよろしいですか?
    続けるには「I love CryptPad」と入力してください。", + "settings_reset": "CryptDriveの全てのファイルとフォルダを削除", + "settings_exportErrorOther": "ドキュメントのエクスポート中にエラーが発生しました: {0}", + "drive_activeOld": "以前のパッド", + "settings_codeSpellcheckLabel": "コードエディターでスペルチェックを有効にする", + "cba_writtenBy": "著者: {0}", + "profile_copyKey": "公開鍵をコピー", + "oo_isLocked": "変更を同期しています。お待ちください", + "kanban_editBoard": "このボードを編集", + "kanban_editCard": "このカードを編集", + "kanban_clearFilter": "フィルターを消去", + "kanban_tags": "タグでフィルタリング", + "allow_text": "アクセスリストを使用すると、選択したユーザーと所有者だけがこのドキュメントにアクセスできます。", + "admin_defaultlimitTitle": "ストレージの制限(MB)", + "owner_add": "{0}があなたをパッド {1} の所有者になるよう希望しています。 受け入れますか?", + "owner_removeConfirm": "選択したユーザーの所有権を削除してよろしいですか? ユーザーには通知が送られます。", + "owner_removePendingText": "保留中", + "properties_unknownUser": "{0}人の不明なユーザー", + "requestEdit_viewPad": "パッドを新しいタブで開く", + "requestEdit_button": "編集権限を要求", + "support_notification": "管理人がサポートチケットに返答しました", + "support_showData": "ユーザーデータを表示/隠す", + "upload_mustLogin": "ファイルのアップロードにはログインが必要です", + "upload_choose": "ファイルを選択", + "form_page": "{0}/{1}ページ", + "form_addMultiple": "全て追加", + "admin_consentToContactLabel": "同意", + "admin_updateAvailableButton": "リリースノートを見る", + "admin_updateAvailableHint": "CryptPadの新しいバージョンが利用可能です", + "admin_updateAvailableTitle": "新しいバージョン", + "userlist_addAsFriendTitle": "「{0}」に連絡先のリクエストを送信", + "contacts_remove": "この連絡先を削除", + "profile_register": "プロフィールの作成にはログインが必要です!", + "poll_removeOption": "このオプションを削除してよろしいですか?", + "share_linkTeam": "チームのドライブに追加", + "sharedFolders_create": "共有フォルダを作成", + "share_mediatagCopy": "Mediaタグをクリップボードにコピー", + "header_homeTitle": "CryptPadのホームページを開く", + "header_logoTitle": "CryptDriveに行く", + "settings_cursorShareTitle": "カーソルの位置を共有", + "settings_padWidthLabel": "エディターの幅を減らす", + "settings_codeIndentation": "コードエディターのインデント(空白スペース)", + "settings_export_done": "ダウンロードの準備ができました!", + "fc_openInCode": "コードエディターで開く", + "poll_create_option": "新しいオプションを追加", + "poll_create_user": "新しいユーザーを追加", + "pad_mediatagImport": "CryptDriveに保存", + "admin_listMyInstanceLabel": "このインスタンスをリストに表示", + "admin_checkupTitle": "インスタンスの設定を検証", + "cba_disable": "消去して無効にする", + "upload_pending": "保留中", + "settings_resetTips": "ヒント", + "chrome68": "バージョン68のChromeあるいはChromiumを使用しているようです。このバージョンには、数秒経過した後でページが白紙になったり、クリックにページが反応しなくなったりするバグがあります。この問題を解決するには、別のタブを表示して改めて表示するか、このページでスクロールを試みてください。このバグは次のバージョンで解決される予定となっています。", + "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずにログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • ログインせずに作成したり共有したりしたファイルを保存するには、 「匿名セッションのデータをインポート」にチェックをしてください。
    ", + "poll_commit": "送信", + "admin_removeDonateButtonTitle": "クラウドファンディングに参加", + "mediatag_notReady": "ダウンロードを完了してください", + "pad_mediatagOpen": "ファイルを開く", + "pad_mediatagShare": "ファイルを共有", + "allowNotifications": "通知を許可", + "archivedFromServer": "ドキュメントがアーカイブされました", + "restoredFromServer": "ドキュメントが復元されました", + "admin_archiveInval": "無効なドキュメント", + "admin_archiveInput2": "ドキュメントのパスワード", + "admin_archiveInput": "ドキュメントのURL", + "admin_unarchiveTitle": "ドキュメントを復元", + "admin_archiveTitle": "ドキュメントをアーカイブ", + "fm_deletedFolder": "削除されたフォルダ", + "history_restoreDriveDone": "CryptDriveが復元されました", + "share_bar": "リンクを作成", + "settings_kanbanTagsTitle": "タグのフィルター", + "slide_textCol": "テキストの色", + "slide_backCol": "背景色", + "code_editorTheme": "エディターのテーマ", + "unknownPad": "不明なパッド", + "admin_openFilesTitle": "ファイルを開く", + "kanban_conflicts": "編集中:", + "kanban_noTags": "タグがありません", + "historyTrim_historySize": "履歴: {0}", + "team_links": "招待用リンク", + "team_cat_link": "招待用リンク", + "team_inviteTitle": "チームへの招待", + "team_inviteJoin": "チームに参加", + "team_inviteLinkCopy": "リンクをコピー", + "team_inviteLinkCreate": "リンクを作成", + "contacts_mutedUsers": "ミュートしたアカウント", + "sent": "メッセージが送信されました", + "team_inviteButton": "メンバーを招待", + "requestEdit_sent": "リクエストが送信されました", + "later": "あとで決める", + "admin_supportListTitle": "メールボックスのサポート", + "friendRequest_later": "あとで決める", + "admin_flushCacheButton": "キャッシュを消去", + "admin_registeredTitle": "登録ユーザー", + "crowdfunding_popup_no": "あとで", + "sharedFolders_create_name": "フォルダ名", + "creation_newTemplate": "新しいテンプレート", + "creation_noTemplate": "テンプレートがありません", + "creation_expire": "期限切れのパッド", + "mdToolbar_list": "箇条書き", + "uploadFolder_modal_filesPassword": "ファイルのパスワード", + "upload_title": "ファイルをアップロード", + "settings_cursorShowLabel": "カーソルを表示", + "settings_cursorColorTitle": "カーソルの色", + "settings_ownDriveTitle": "アカウントを更新", + "settings_driveDuplicateLabel": "重複したパッドを隠す", + "settings_export_compressing": "データを圧縮しています…", + "settings_cat_pad": "リッチテキスト", + "fc_collapseAll": "全て折りたたむ", + "fc_expandAll": "全て展開", + "fc_open_ro": "開く(読み取り専用)", + "fc_color": "色を変更", + "fm_passwordProtected": "パスワードで保護", + "poll_userPlaceholder": "あなたの名前", + "kanban_working": "作業中", + "kanban_newBoard": "新しいボード", + "pad_mediatagOptions": "画像のプロパティ", + "pad_mediatagRatio": "比率を維持", + "pad_mediatagHeight": "高さ(ピクセル)", + "pad_mediatagWidth": "幅(ピクセル)", + "pad_mediatagTitle": "Mediaタグの設定", + "admin_cat_network": "ネットワーク", + "form_clear": "消去", + "form_anonymous_on": "許可", + "form_open": "開く", + "form_input_ph_url": "https://example.com", + "form_input_ph_email": "email@example.com", + "form_backButton": "戻る", + "form_viewButton": "表示", + "form_form": "フォーム", + "form_editor": "エディタ", + "form_delete": "削除", + "form_sent": "送信済", + "form_reset": "リセット", + "form_update": "更新", + "form_submit": "送信", + "form_type_md": "説明", + "form_type_poll": "投票", + "form_type_checkbox": "チェックボックス", + "form_type_textarea": "段落", + "form_type_input": "文字", + "form_text_number": "数", + "form_text_email": "Eメール", + "form_text_url": "リンク", + "settings_colortheme_light": "ライト", + "settings_colortheme_dark": "ダーク", + "settings_cat_style": "表示モード", + "admin_performanceKeyHeading": "コマンド", + "admin_performanceProfilingTitle": "性能", + "admin_cat_performance": "性能", + "redo": "やり直す", + "undo": "取り消す", + "settings_cacheTitle": "キャッシュ", + "admin_support_open": "表示", + "mediatag_saveButton": "保存", + "Offline": "オフライン", + "admin_unarchiveButton": "復元", + "admin_archiveButton": "アーカイブ", + "oo_version_latest": "最新", + "settings_cat_kanban": "カンバン", + "settings_kanbanTagsOr": "または", + "settings_kanbanTagsAnd": "かつ", + "pad_tocHide": "アウトライン", + "oo_refresh": "再読み込み", + "toolbar_file": "ファイル", + "drive_treeButton": "ファイル", + "toolbar_insert": "挿入", + "fm_sort": "並び替え", + "comments_comment": "コメント", + "comments_resolve": "解決", + "comments_reply": "返信", + "comments_submit": "送信", + "comments_edited": "編集済", + "cba_enable": "有効にする", + "canvas_select": "選択", + "kanban_body": "内容", + "kanban_title": "タイトル", + "teams": "チーム", + "teams_table_specific": "例外", + "properties_changePasswordButton": "送信", + "terms": "利用規約", + "poll_publish_button": "公開", + "team_viewers": "閲覧者", + "team_pending": "招待済", + "team_cat_create": "新規", + "team_inviteModalButton": "招待", + "owner_unknownUser": "不明", + "admin_cat_support": "サポート", + "supportPage": "サポート", + "share_withFriends": "共有", + "friendRequest_decline": "拒否", + "settings_codeSpellcheckTitle": "スペルチェック", + "contact_email": "Eメール", + "admin_cat_stats": "統計", + "markdown_toc": "コンテンツ", + "autostore_pad": "パッド", + "autostore_sf": "フォルダ", + "autostore_file": "ファイル", + "share_linkCopy": "コピー", + "creation_passwordValue": "パスワード", + "edit": "編集", + "features": "機能", + "mdToolbar_code": "コード", + "mdToolbar_quote": "引用", + "mdToolbar_link": "リンク", + "mdToolbar_strikethrough": "打ち消し線", + "mdToolbar_bold": "太字", + "mdToolbar_italic": "イタリック", + "mdToolbar_help": "ヘルプ", + "todo_title": "CryptTodo", + "download_step2": "復号化中", + "download_dl": "ダウンロード", + "upload_up": "アップロード", + "upload_cancelled": "キャンセル済", + "settings_padSpellcheckTitle": "スペルチェック", + "settings_resetThumbnailsAction": "消去", + "settings_thumbnails": "サムネイル", + "settings_resetTipsAction": "リセット", + "settings_resetButton": "削除", + "settings_cat_code": "コード", + "settings_cat_cursor": "カーソル", + "fc_hashtag": "タグ", + "fc_prop": "プロパティ", + "fc_remove_sharedfolder": "削除", + "contacts_send": "送信", + "contacts_title": "連絡先", + "poll_comment_list": "コメント", + "poll_optionPlaceholder": "オプション", + "kanban_done": "完了", + "kanban_delete": "削除", + "kanban_color": "色", + "calendar_import_temp": "このカレンダーをインポート", + "settings_deleteContinue": "アカウントを削除", + "admin_emailButton": "更新", + "button_newform": "新しいフォーム", + "form_editBlock": "編集", + "fm_deleteOwnedPads": "これらのパッドをサーバーから完全に削除してよろしいですか?", + "fm_deleteOwnedPad": "このパッドをサーバーから完全に削除してよろしいですか?", + "fm_sharedFolder": "共有フォルダ", + "fm_newFile": "新しいパッド", + "fm_newFolder": "新しいフォルダ", + "fm_newButton": "新規", + "fm_sharedFolderName": "共有フォルダ", + "fm_tagsName": "タグ", + "fm_filesDataName": "全ファイル", + "contacts_leaveRoom": "このルームから退出", + "contacts_rooms": "ルーム", + "contacts_removeHistoryServerError": "チャットの履歴を削除する際にエラーが発生しました。後ほど再試行してください", + "contacts_confirmRemoveHistory": "チャットの履歴を削除してよろしいですか?データは復元できません", + "contacts_info3": "アイコンをダブルクリックしてプロフィールを表示", + "history_restoreDone": "ドキュメントが復元されました", + "history_restoreTitle": "選択したバージョンを復元", + "history_closeTitle": "履歴を閉じる", + "history_loadMore": "さらに履歴を読み込む", + "history_prev": "前のバージョン", + "history_next": "次のバージョン", + "historyButton": "ドキュメントの履歴を表示", + "notifyLeft": "{0}が共同セッションから退出しました", + "fileEmbedTag": "そして、ファイルを埋め込みたい任意のページの箇所に、このMedia Tagを配置してください:", + "themeButtonTitle": "コードとスライドのエディタのテーマ色を選択", + "printTransition": "遷移アニメーションを有効にする", + "admin_blockDailyCheckTitle": "サーバーのテレメトリー", + "admin_blockDailyCheckLabel": "サーバーのテレメトリーを無効にする", + "fc_open_formro": "開く(参加者として)", + "poll_unlocked": "編集可", + "poll_locked": "編集不可", + "poll_edit": "編集", + "poll_remove": "削除", + "poll_removeUser": "このユーザーを削除してよろしいですか?", + "oo_importInProgress": "インポート中です", + "register_emailWarning2": "他のサービスと異なり、メールアドレスを使ってパスワードをリセットすることはできません。", + "register_alreadyRegistered": "このユーザーは既に存在します。ログインしますか?", + "register_warning": "注意", + "register_cancel": "キャンセル", + "register_writtenPassword": "ユーザー名とパスワードをメモしました。続行", + "register_mustAcceptTerms": "利用規約に同意する必要があります。", + "register_passwordTooShort": "パスワードは最低{0}文字でなければなりません。", + "register_passwordsDontMatch": "パスワードが一致しません!", + "register_acceptTerms": "利用規約に同意", + "canvas_widthLabel": "幅: {0}", + "canvas_width": "幅", + "canvas_delete": "選択箇所を削除", + "canvas_clear": "消去", + "oo_cantUpload": "他のユーザーが在席中にアップロードすることはできません。", + "poll_comment_placeholder": "あなたのコメント", + "poll_comment_remove": "このコメントを削除", + "poll_comment_submit": "送信", + "poll_comment_add": "コメントを追加", + "imprint": "法定通知", + "oo_exportInProgress": "エクスポート中です", + "notifyJoined": "{0}が共同セッションに参加しました", + "viewEmbedTag": "パッドを埋め込むには、このiframeを任意の箇所に含めてください。CSSまたはHTMLの属性を使って装飾できます。", + "slideOptionsText": "オプション", + "tags_noentry": "削除したパッドにはタグ付けできません!", + "tags_duplicate": "重複タグ: {0}", + "tags_notShared": "タグは他のユーザーと共有されません", + "tags_add": "選択したパッドのタグを更新", + "tags_title": "タグ(あなた用)", + "filePickerButton": "CryptDriveに保存したファイルを埋め込む", + "printBackgroundRemove": "背景画像を削除", + "printBackgroundValue": "現在の背景: {0}", + "printBackgroundButton": "画像を選択", + "printBackground": "背景画像を使用", + "printTitle": "パッドのタイトルを表示", + "printDate": "日付を表示", + "printSlideNumber": "スライドの番号を表示", + "printOptions": "レイアウトのオプション", + "printButtonTitle2": "ドキュメントを印刷するかPDFファイルでエクスポート", + "printButton": "印刷(Enter)", + "printText": "印刷", + "backgroundButtonTitle": "プレゼンテーションの背景色を変更", + "template_empty": "利用できるテンプレートがありません", + "template_import": "テンプレートをインポート", + "useTemplateOK": "テンプレートを選択してください(Enter)", + "selectTemplate": "テンプレートを選択するかESCキーを押してください", + "saveTemplatePrompt": "テンプレートのタイトルを入力してください", + "newButtonTitle": "新しいパッドを作成", + "newButton": "新規", + "userAccountButton": "アカウント", + "userListButton": "ユーザーリスト", + "movedToTrash": "パッドをゴミ箱に移動しました。
    ドライブにアクセス", + "forgetPrompt": "OKをクリックするとパッドをゴミ箱へと移動します。よろしいですか?", + "forgetButton": "削除", + "pinLimitReached": "利用できるストレージの最大容量に達しました", + "disconnected": "接続が切れました", + "saveTitle": "タイトルを保存(Enter)", + "exportButtonTitle": "ローカルファイルにパッドをエクスポート", + "importButtonTitle": "ローカルファイルからパッドをインポート", + "pinLimitDrive": "ストレージの最大容量に達しました。
    新しいパッドは作成できません。", + "pinLimitNotPinned": "ストレージの最大容量に達しました。
    このパッドはCryptDriveに保存されません。", + "pinLimitReachedAlertNoAccounts": "ストレージの最大容量に達しました", + "pinLimitReachedAlert": "使用できるストレージの最大容量に達しました。新しいパッドはCryptDriveに保存されません。
    パッドをCryptDriveから削除するか、プレミアムユーザーになると容量を増やすことができます。", + "userlist_offline": "現在オフラインのため、ユーザーリストは利用できません。", + "readonly": "読み取り専用", + "errorState": "重大なエラー: {0}", + "realtime_unrecoverableError": "回復不可能なエラーが発生しました。OKをクリックしてリロードしてください。", + "disabledApp": "このアプリケーションは無効になっています。詳細については、このCryptPadの管理者にお問い合わせください。", + "deletedFromServer": "パッドは完全削除されました", + "newVersionError": "新しいバージョンのCryptPadがあります。
    リロードすると新しいバージョンを読み込みます。Escキーを押すとオフラインモードでコンテンツにアクセスします。", + "errorRedirectToHome": "Escキーを押すとCryptDriveにリダイレクトします。", + "errorCopy": " Escキーを押すと、閲覧モードで引き続きコンテンツにアクセスできます。", + "invalidHashError": "要求したドキュメントの URL が無効です。", + "chainpadError": "コンテンツを更新する際に重大なエラーが発生しました。コンテンツが失われないよう、閲覧モードで表示されています。
    このパッドを表示し続けるにはEscキーを押し、再度編集を試みるにはリロードをしてください。", + "inactiveError": "このパッドは使用されていなかったため削除されました。Escキーを押して新しいパッドを作成します。", + "deletedError": "このパッドは所有者によって削除されたため、使用できなくなりました。", + "expiredError": "このパッドは使用期限が過ぎてしまったため、使用できなくなりました。", + "anonymousStoreDisabled": "このCryptPadのインスタンスの管理者は、匿名ユーザーの保存を無効にしています。CryptDriveを使用するにはログインする必要があります。", + "padNotPinnedVariable": "このパッドは{4}日使用しないと期限切れになります。{0}ログイン{1}または{2}登録{3}し保存してください。", + "padNotPinned": "このパッドは3ヶ月間使用しないと有効期限が切れます。{0}ログイン{1}するか{2}登録{3}して保存してください。", + "onLogout": "ログアウトしました。{0}ここをクリック{1}するか
    Escapeキーを押すと、閲覧モードでパッドにアクセスできます。", + "typeError": "このパッドは選択したアプリケーションと互換性がありません", + "form_type_page": "ページ分割", + "form_description_default": "ここにテキストを入力", + "team_pcsSelectHelp": "所有するパッドをチームのドライブに作成すると、そのパッドの所有権はチームに与えられます。", + "sharedFolders_create_owned": "所有するフォルダ", + "creation_owned1": "所有されている項目は、所有者が任意で完全削除できます。完全削除すると、他のユーザーのCryptDriveでも利用できなくなります。", + "creation_owned": "所有するパッド", + "uploadFolder_modal_owner": "所有するファイル", + "upload_modal_owner": "所有するファイル", + "settings_driveDuplicateHint": "所有するパッドを共有フォルダに移動すると、あなたのCryptDriveにパッドのコピーが保存され、あなたは引き続きそのパッドをコントロールできます。重複したファイルは隠すことができます。削除しない限り、共有したバージョンだけが表示されます。削除した場合は、以前の場所に元のファイルが表示されます。", + "settings_driveDuplicateTitle": "重複した所有するパッド", + "fm_info_owned": "あなたはここに表示されているパッドの所有者です。所有者は、サーバーからパッドを永久に削除することができます。削除すると、他のユーザーはパッドにアクセスできなくなります。", + "settings_deleteModal": "あなたのデータを削除するため、以下の情報をCryptPadの管理者と共有します。", + "oo_login": "ログインもしくは登録すると、スプレッドシートの性能が改善します。", + "cba_hint": "設定は次の新しいパッドから有効になります。", + "support_disabledHint": "このCryptPadのインスタンスはサポートフォームを利用するように設定されていません。", + "admin_supportInitTitle": "サポートメールボックスの初期化", + "admin_supportAddError": "秘密鍵が無効です", + "admin_supportAddKey": "秘密鍵を追加", + "todo_markAsIncompleteTitle": "このタスクを未完了にする", + "todo_markAsCompleteTitle": "このタスクを完了済にする", + "settings_codeFontSize": "コードエディターのフォントの大きさ", + "settings_anonymous": "ログインしていません。設定はこのブラウザのみで有効です。", + "settings_deleted": "アカウントが削除されました。OKを押すとホームページに移動します。", + "settings_deleteHint": "アカウントの削除は取り消しできません。あなたのCryptDriveとパッドのリストはサーバーから削除されます。誰もCryptDriveに保存していないパッドは、90日で削除されます。", + "settings_resetThumbnailsDone": "サムネイルが消去されました。", + "settings_resetThumbnailsDescription": "ブラウザに保存したサムネイルを削除します。", + "settings_disableThumbnailsDescription": "新しいパッドを開くと、サムネイルが自動で作成され、ブラウザに保存されます。ここでサムネイルの作成を無効にできます。", + "fm_info_root": "ファイルを並べ替えるのに必要な数のネストされたフォルダーをここに作成できます。", + "oo_conversionSupport": "お使いのブラウザはMicrosoft Officeのフォーマットの変換に対応していません。FirefoxもしくはChromeの最新バージョンの使用を推奨します。", + "register_registrationIsClosed": "登録は締め切りました。", + "settings_notifCalendarHint": "今後のカレンダーのイベントのすべての通知を有効もしくは無効にします。", + "reminder_inProgressAllDay": "今日: {0}", + "reminder_inProgress": "{0}が{1}で開始しました", + "reminder_now": "{0}が開始しました", + "reminder_missed": "{0}が{1}で開催されました", + "calendar_dateRange": "{0} - {1}", + "calendar_import": "マイカレンダーに追加", + "calendar_errorNoCalendar": "編集可能なカレンダーが選択されていません", + "calendar_day": "日", + "calendar_new": "新しいカレンダー", + "calendar_default": "マイカレンダー", + "calendar": "カレンダー", + "pad_goToAnchor": "アンカーに移動", + "oo_cantMigrate": "この表はアップロードの最大のサイズを超えているため、移行することができません。", + "footer_roadmap": "ロードマップ", + "settings_deleteSubscription": "サブスクリプションを管理", + "broadcast_translations": "翻訳", + "admin_broadcastCancel": "メッセージを削除", + "admin_broadcastButton": "送信", + "broadcast_surveyURL": "アンケートのリンク", + "admin_surveyActive": "アンケートを開く", + "admin_surveyCancel": "削除", + "admin_surveyButton": "アンケートを保存", + "broadcast_newSurvey": "新しいアンケートがあります。クリックで開きます。", + "admin_surveyTitle": "アンケート", + "admin_maintenanceCancel": "メンテナンスをキャンセル", + "admin_maintenanceButton": "メンテナンスを予定", + "admin_maintenanceTitle": "メンテナンス", + "importError": "インポートできませんでした(誤ったフォーマット)", + "addOptionalPassword": "パスワードを追加(任意)", + "pad_settings_show": "表示", + "pad_settings_hide": "隠す", + "pad_settings_width_small": "ページモード", + "pad_settings_info": "このドキュメントの既定の設定。新しいユーザーがドキュメントを閲覧したときに適用されます。", + "pad_settings_title": "ドキュメントの設定", + "admin_getquotaTitle": "アカウントのストレージを確認", + "settings_colorthemeTitle": "テーマ色", + "admin_getquotaButton": "確認", + "fm_cantUploadHere": "ここにはファイルをアップロードできません", + "settings_resetTipsDone": "全てのヒントが表示されます。", + "settings_resetTipsButton": "利用可能なCryptDriveのヒントをリセット", + "settings_resetNewTitle": "CryptDriveのデータを消去", + "settings_exportErrorMissing": "このドキュメントはサーバーにありません(期限切れ、もしくは所有者により削除されました)", + "settings_exportErrorEmpty": "このドキュメントはエクスポートできません(内容が空もしくは無効です)。", + "settings_exportErrorDescription": "以下のドキュメントをエクスポートに追加できませんでした:", + "settings_exportDescription": "ドキュメントをダウンロードして復号化しております。少々お待ちください。これには数分程度かかることがあります。タブを閉じると作業が中断されます。", + "crowdfunding_popup_text": "

    あなたの援助が必要です!

    CryptPadの開発が継続できるよう、OpenCollectiveのページからご支援いただきますようお願いします。ロードマップ資金調達の目標を同ページにて公開しています。", + "autostore_notAvailable": "この機能を使うにはCryptDriveにパッドを保存する必要があります。", + "autostore_forceSave": "CryptDriveにファイルを保存", + "autostore_saved": "パッドはCryptDriveに保存されました!", + "autostore_settings": "自動保存は設定ページで有効にできます!", + "broadcast_end": "終了", + "broadcast_start": "開始", + "broadcast_preview": "通知をプレビュー", + "team_inviteLinkError": "リンクの作成時にエラーが発生しました。", + "team_inviteLinkSetPassword": "リンクをパスワードで保護(推奨)", + "team_inviteLinkNote": "プライベート・メッセージを追加", + "contacts_muteInfo": "ミュートしたユーザーからは通知を受け取りません。
    ミュートしたことは相手に通知されません。 ", + "contacts_manageMuted": "ミュートを管理", + "notifyRenamed": "{0}は{1}になりました", + "printBackgroundNoValue": "背景画像が選択されていません", + "canvas_saveToDrive": "この画像をファイル形式でCryptDriveに保存", + "canvas_opacityLabel": "透明度: {0}", + "canvas_opacity": "透明度", + "poll_comment_disabled": "✓ボタンを押して投票を公開すると、コメントが有効になります。", + "kanban_item": "項目 {0}", + "fileEmbedScript": "このファイルを埋め込むには、Media Tagのロード用に、このスクリプトをページに一度含めてください。", + "editShare": "編集用リンク", + "colorButtonTitle": "プレゼンテーションモードの文字色を変更", + "presentButtonTitle": "プレゼンテーションモードに変更", + "exportPrompt": "ファイル名は何にしますか?", + "share_formEdit": "著者", + "history_userNext": "次の著者", + "history_userPrev": "以前の著者", + "comments_deleted": "コメントは著者により削除されました", + "cba_title": "著者の色", + "cba_hide": "著者の色を隠す", + "cba_show": "著者の色を表示", + "cba_properties": "著者の色(実験的)", + "restrictedError": "このドキュメントにアクセスする権限がありません", + "restrictedLoginPrompt": "このドキュメントにアクセスする権限がありません。アクセス権がある場合はログイン してください。", + "history_shareTitle": "このバージョンへのリンクを共有", + "admin_listMyInstanceTitle": "インスタンスを公開ディレクトリに表示", + "admin_checkupButton": "診断を行う", + "settings_driveRedirect": "自動で転送", + "mdToolbar_embed": "タイトルを埋め込む", + "copyToClipboard": "クリップボードにコピー", + "form_anonymousBox": "匿名で回答", + "form_anonymous_blocked": "匿名の回答はブロックされています。回答には ログインもしくは登録が必要です。", + "form_add_item": "項目を追加", + "form_type_radio": "選択肢", + "form_makePublicWarning": "回答を公開してよろしいですか?これは取り消せません。", + "form_notAnswered": "{0}個の未回答", + "form_showSummary": "概要を表示", + "form_showIndividual": "個々の回答を表示", + "form_results_empty": "回答がありません", + "form_results": "回答", + "form_answered": "このフォームは回答済みです", + "form_cantFindAnswers": "このフォームの既存の回答を取得できません。", + "form_duplicates": "重複する項目が削除されました", + "form_editType": "オプションの種類", + "share_formView": "参加者", + "admin_supportPrivHint": "他の管理者がサポートチケットを表示するのに必要な秘密鍵を表示します。この秘密鍵を入力するフォームは、管理パネルに表示されます。", + "oo_importBin": "OKをクリックするとCryptPadの内部フォーマット(.bin)をインポートします。", + "settings_notifCalendarTitle": "カレンダーの通知", + "reminder_minutes": "{0}はあと{1}分で開始します", + "upload_success": "ファイル({0})のアップロードが完了しました。", + "uploadFolder_modal_title": "フォルダーアップロードのオプション", + "upload_modal_title": "ファイルアップロードのオプション", + "settings_cursorShowTitle": "他のユーザーのカーソルの位置を表示", + "admin_authError": "このページには管理者のみアクセスできます", + "settings_cursorShareLabel": "位置を共有", + "settings_changePasswordNewPasswordSameAsOld": "新しいパスワードは現在のパスワードと異なるものでなければなりません。", + "login_unhandledError": "予期しないエラーが発生しました :(", + "autostore_error": "予期しないエラー: このパッドを保存できませんでした。再度試してください。", + "settings_changePasswordError": "予期しないエラーが発生しました。ログインしたりパスワードを変更したりすることができない場合は、CryptPadの管理者に連絡してください。", + "convertFolderToSF_confirm": "このフォルダを他の人が閲覧するには、共有フォルダに変更する必要があります。続行してよろしいですか?", + "share_linkPresent": "表示モード", + "share_linkEmbed": "埋め込みモード(ツールバーとユーザー一覧を隠します)", + "properties_passwordSuccess": "パスワードは変更されました。
    OKを押して再読み込みし、アクセス権限を更新してください。", + "properties_passwordWarning": "パスワードは変更されましたが、CryptDriveを更新することができませんでした。古いバージョンのパッドは手動で削除しなければならないかもしれません。
    OKを押して再読み込みし、アクセス権限を更新してください。", + "properties_confirmChange": "パスワードを変更すると履歴が削除されます。パスワードを知らないユーザーは、このパッドへアクセスできなくなります。続行してよろしいですか?", + "creation_newPadModalDescription": "作成するドキュメントの種類をクリックしてください。タブキーで選択し、エンターキーで作成することもできます。", + "creation_noOwner": "所有者がありません", + "properties_passwordError": "パスワードの変更中にエラーが発生しました。再度試してください。", + "properties_passwordSame": "新しいパスワードは現在のパスワードと異なるものでなければなりません。", + "four04_pageNotFound": "お探しのページが見つかりませんでした。", + "about": "私たちについて", + "whatis_apps_info": "

    CryptPadは共同作業に必要なツールを備えた本格的なオフィススイートです。リッチテキスト、スプレッドシート、コード/マークダウン、カンバン、スライド、ホワイトボード、投票機能を有しています。

    それらのアプリケーションには、チャット、連絡先、著者別の色表示(コード/マークダウン)、コメント、メンション(リッチテキスト)などの機能が付属しています。

    ", + "mdToolbar_button": "マークダウンのツールバーを表示もしくは隠す", + "pad_base64": "このパッドはサイズの大きい画像を含んでいます。パッドのサイズが大きいと、読み込みに時間がかかります。サイズを減らすために、画像のフォーマットを変換して、別の画像ファイルとしてCryptDriveに保存することができます。画像を変換してよろしいですか?", + "todo_removeTaskTitle": "このタスクをリストから削除", + "upload_tooLargeBrief": "ファイルが{0}MBの制限を超えています", + "upload_tooLarge": "ファイルがあなたのアカウントでアップロードできるサイズを超えています。", + "upload_notEnoughSpaceBrief": "容量が足りません", + "upload_notEnoughSpace": "CryptDriveの空き容量が不足しています。", + "upload_uploadPending": "アップロード中です。キャンセルして新しいファイルをアップロードしますか?", + "upload_serverError": "サーバーエラー: ファイルをアップロードできませんでした。", + "uploadFolder_modal_forceSave": "ファイルをCryptDriveに保存", + "settings_export_download": "ドキュメントをダウンロードして復号化しています…", + "settings_export_reading": "CryptDriveを読み込んでいます…", + "settings_exportCancel": "エクスポートをキャンセルしてよろしいでしょうか?次のエクスポートでは最初からやりなおす必要があります。", + "fm_error_cantPin": "内部サーバーエラー。ページを再度読み込んでください。", + "fm_info_anonymous": "ログインしていないため、ドキュメントは{0}日後に期限切れになります。また、ブラウザの履歴を消去するとファイルが消えてしまうかもしれません。
    ファイルを永続的に保存するには、登録するか(個人情報の登録は不要です)、ログインしてください。登録アカウントについては、こちらを参照してください(英語)。", + "fm_info_recent": "これらのパッドは、最近、あなたか共同作業者により開かれたか、もしくは編集されました。", + "fm_info_template": "新しいパッドを作成する際に利用できるテンプレートとして保存した全てのパッドを含みます。", + "fm_categoryError": "選択したカテゴリーが開けません。ルートを表示します。", + "fm_morePads": "さらに表示", + "oo_reconnect": "サーバーの接続が回復しました。OKをクリックして再読み込みし、編集を継続してください。", + "changeNamePrompt": "名前を変更(匿名で利用する場合は空欄): ", + "form_text_text": "テキスト", + "form_poll_time": "時", + "form_poll_day": "日", + "form_poll_text": "テキスト", + "form_invalid": "無効なフォーム", + "admin_supportPrivButton": "鍵を表示", + "admin_supportInitGenerate": "サポートの鍵を生成", + "admin_supportPrivTitle": "サポートのメールボックスの秘密鍵", + "admin_emailHint": "あなたのインスタンスの連絡先のメールアドレスを設定してください", + "admin_emailTitle": "管理者の連絡先のメールアドレス", + "mediatag_defaultImageName": "画像", + "calendar_noNotification": "なし", + "genericCopySuccess": "クリップボードにコピーしました", + "toolbar_storeInDrive": "CryptDriveに保存", + "calendar_addNotification": "リマインダーを追加", + "calendar_notifications": "リマインダー", + "settings_notifCalendarCheckbox": "カレンダーの通知を有効にする", + "calendar_days": "日", + "calendar_hours": "時", + "calendar_minutes": "分", + "calendar_allDay": "全日", + "calendar_location": "場所: {0}", + "calendar_loc": "場所", + "calendar_title": "タイトル", + "calendar_update": "更新", + "calendar_deleteOwned": "共有した他のユーザーには表示されたままになります。", + "calendar_deleteConfirm": "このカレンダーをあなたのアカウントから削除してよろしいですか?", + "calendar_today": "今日", + "calendar_month": "月", + "calendar_week": "週", + "calendar_deleteTeamConfirm": "このカレンダーをチームから削除してよろしいですか?", + "calendar_newEvent": "新しいイベント", + "settings_changePasswordPending": "パスワードを変更しています。完了するまでページを閉じたり、再読み込みしたりしないでください。", + "settings_changePasswordConfirm": "パスワードを変更してよろしいですか?全てのデバイスで再ログインする必要があります。", + "settings_ownDrivePending": "アカウントをアップグレードしています。完了するまでページを閉じたり、再読み込みしたりしないでください。", + "settings_ownDriveConfirm": "アカウントのアップグレードには時間がかかるかもしれません。全てのデバイスで再ログインする必要があります。よろしいですか?", + "settings_padOpenLinkLabel": "直接リンクを開く機能を有効にする", + "settings_padOpenLinkHint": "このオプションを有効にすると、プレビューの吹き出しを表示せず、埋め込んだリンクを直接クリックして開くことができます", + "settings_padOpenLinkTitle": "最初のクリックでリンクを開く", + "settings_padSpellcheckLabel": "リッチテキストのパッドでスペルチェックを有効にする", + "settings_padWidth": "エディターの最大幅", + "settings_codeUseTabs": "タブを使ってインデント(空白スペースの代わりに)", + "login_noSuchUser": "無効なユーザー名あるいはパスワードです。再度試すか、サインアップしてください", + "fo_unavailableName": "同じ名前のファイルまたはフォルダが既に存在しています。アイテムの名前を変更して、再度試してください。", + "fo_moveFolderToChildError": "フォルダをサブフォルダに移動することはできません", + "fo_existingNameError": "その名前はディレクトリで既に使用されています。他の名前を選んでください。", + "fo_moveUnsortedError": "フォルダをテンプレートのリストに移動することはできません", + "fm_moveNestedSF": "共有フォルダを他の共有フォルダの中に移動することはできません。フォルダ {0} は移動されませんでした。", + "fm_restoreDrive": "あなたのドライブを以前の状態に戻しています。最良の結果のため、完了するまでドライブに変更を加えるのは控えてください。", + "fm_padIsOwnedOther": "このパッドは他のユーザーにより所有されています", + "fm_burnThisDrive": "ブラウザに保存されているCryptPadの全ての情報を消去してよろしいですか?
    あなたのCryptDriveと履歴はブラウザから消去されますが、パッドは(暗号化されたまま)サーバー上に残ります。", + "fm_burnThisDriveButton": "ブラウザに保存されているCryptPadの全ての情報を消去", + "fm_canBeShared": "このフォルダは共有可能です", + "useTemplateCancel": "新しく開始(Esc)", + "fm_originalPath": "本来のパス", + "contacts_online": "このルームの別のユーザーがオンラインです", + "contacts_request": "{0}があなたを連絡先に追加しようとしています。受け入れますか?", + "contacts_rejected": "連絡先の招待が拒否されました", + "contacts_added": "連絡先の招待が受け入れられました。", + "profile_uploadTypeError": "エラー: あなたのアバターの種類は許可されていません。許可されている種類: {0}", + "canvas_imageEmbed": "コンピューターの画像を埋め込む", + "canvas_currentBrush": "現在のブラシ", + "poll_total": "合計", + "kanban_todo": "タスク", + "slide_invalidLess": "カスタムスタイルは無効です", + "printCSS": "カスタムスタイルルール(CSS):", + "admin_provideAggregateStatisticsHint": "追加の利用状況を開発者に提供することも選択できます。追加の情報には、あなたのインスタンスのおおよその登録ユーザー数や一日あたりのユーザー数などがあります。", + "fm_info_sharedFolder": "これは共有フォルダです。ログインしていないため、閲覧モードでしかアクセスできません。
    登録あるいはログインすると、CryptDriveにインポートして編集できます。", + "team_invitedToTeam": "{0}があなたをチーム「{1}」に招待しました", + "team_inviteFromMsg": "{0}があなたをチーム「{1}」に招待しました", + "team_invitePleaseLogin": "招待を受け入れるには、ログインもしくは登録してください。", + "team_inviteEnterPassword": "招待パスワードを入力してください。", + "team_inviteGetData": "チームのデータを取得中です", + "team_inviteInvalidLinkError": "招待リンクが無効です。", + "admin_getlimitsHint": "インスタンスに適用されている全てのカスタムストレージの制限を一覧表示します。", + "settings_exportWarning": "注意:このツールはベータ版のため、スケーラビリティ上の問題があるかもしれません。よりよいパフォーマンスのために、このタブをフォーカスしたままにすることを推奨します。", + "settings_exportFailed": "1分以上ダウンロードにかかるパッドは、エクスポートしたファイルには含まれません。エクスポートされなかったパッドについては、リンクを表示します。", + "settings_exportTitle": "CryptDriveをエクスポート", + "settings_backup2Confirm": "あなたのCryptDriveの全てのパッドをダウンロードします。続けたい場合は、名前を入力してOKを押してください", + "settings_backup2": "CryptDriveをダウンロード", + "settings_backupHint2": "ドライブの全てのドキュメントをダウンロードします。ドキュメントは、他のアプリケーションで読み込めるフォーマットがあれば、そのフォーマットでダウンロードされます。そうしたフォーマットがなければ、CryptPadで読み込めるフォーマットでダウンロードされます。", + "settings_backupHint": "CryptDriveのコンテンツをバックアップ、あるいは復元します。パッドの内容ではなく、それにアクセスするための鍵だけを含みます。", + "register_emailWarning3": "その点を踏まえてなおユーザー名にメールアドレスを使用する場合は、OKをクリックしてください。", + "register_emailWarning1": "それもできますが、サーバーには送信されません。", + "register_emailWarning0": "ユーザー名にメールアドレスが入力されています。", + "fm_tags_used": "使用数", + "fm_deletedPads": "これらのパッドはサーバーにありません。あなたのCryptDriveから削除されています: {0}", + "fm_renamedPad": "このパッドにカスタム名を設定しました。共有のファイル名は
    {0}", + "fm_ownedPadsName": "所有", + "burnAfterReading_generateLink": "下のボタンをクリックするとリンクを生成します。", + "fm_restricted": "アクセス権がありません", + "admin_performancePercentHeading": "割合", + "settings_cacheButton": "既存のキャッシュを消去", + "settings_cacheCheckbox": "このデバイスでキャッシュを有効にする", + "form_submitWarning": "強制的に送信", + "form_updateWarning": "強制的にアップデート", + "form_answerName": "{0}から{1}について回答", + "form_addMultipleHint": "複数の日時を追加", + "admin_consentToContactTitle": "連絡に同意", + "form_poll_hint": ": はい、: いいえ、: 許容できる", + "admin_provideAggregateStatisticsLabel": "集計済みの統計を提供", + "admin_provideAggregateStatisticsTitle": "統計による集計", + "admin_blockDailyCheckHint": "以後CryptPadのインスタンスは、1日に1回、CryptPadの開発者のサーバーにメッセージを送信します。開発者はそれをもとに、CryptPadのバージョンごとのサーバー数を追跡することができます。以下からこの測定をオプトアプトできます。なお、送信されるメッセージの内容は、確認用として、アプリケーションのサーバーのログに記録されます。", + "admin_listMyInstanceHint": "あなたのインスタンスが誰でも利用できる場合、同意によってウェブディレクトリに表示できます。その際は、サーバーのテレメトリーが有効になっている必要があります。", + "settings_driveRedirectTitle": "ホームページにリダイレクト", + "form_defaultItem": "項目{0}", + "form_defaultOption": "オプション{0}", + "form_answerAnonymous": "{0}についての匿名の回答", + "form_maxLength": "文字数制限: {0}/{1}", + "form_textType": "テキストの種類", + "form_pollYourAnswers": "あなたの回答", + "form_pollTotal": "合計", + "form_editMaxLength": "最大文字数", + "form_add_option": "オプションを追加", + "form_newItem": "新しい項目", + "form_newOption": "新しいオプション", + "form_anonymous": "匿名の回答", + "form_removeEnd": "締切日を削除", + "form_setEnd": "締切日を設定", + "form_isPrivate": "回答は公開されていません", + "form_isPublic": "回答は公開されています", + "form_makePublic": "回答を公開", + "form_invalidQuestion": "質問{0}", + "info_privacyFlavour": "プライバシーポリシーに、データの取り扱い方を記載しています。", + "toolbar_tools": "ツール", + "toolbar_savetodrive": "画像として保存", + "comments_error": "ここにはコメントを追加できません", + "settings_padNotifHint": "あなたのコメントへの返信の通知を無視する", + "mentions_notification": "{0}があなたを{1}でメンションしました", + "access_muteRequests": "このパッドへのアクセスリクエストをミュート", + "access_noContact": "追加する連絡先がありません", + "trimHistory_needMigration": "この機能を有効にするにはCryptDriveをアップデートしてください。", + "trimHistory_error": "履歴を削除している途中でエラーが発生しました", + "trimHistory_getSizeError": "ドライブの履歴のサイズを計算している途中でエラーが発生しました", + "profile_login": "このユーザーを連絡先に追加するにはログインする必要があります", + "dontShowAgain": "二度と表示しない", + "oo_sheetMigration_anonymousEditor": "登録ユーザーが最新のバージョンに更新するまで、このスプレッドシートを未登録ユーザーが編集することはできません。", + "oo_invalidFormat": "このファイルはインポートできません", + "burnAfterReading_warningDeleted": "このパッドは削除されました。ウインドウを閉じた後で再びアクセスすることはできません。", + "burnAfterReading_proceed": "表示して削除", + "team_leaveConfirm": "チームから退出すると、チームのCryptDrive、チャットの履歴などにアクセスできなくなります。よろしいですか?", + "team_leaveButton": "チームから退出", + "team_rosterKick": "チームからキック", + "team_rosterDemote": "降格", + "team_rosterPromote": "昇格", + "team_createLabel": "新しいチームを作成", + "team_kickedFromTeam": "{0}があなたをチーム「{1}」からキックしました", + "admin_diskUsageButton": "レポートを生成", + "admin_diskUsageTitle": "ディスクの使用状況", + "contact_adminHint": "アカウントに関連した問題、ストレージの制限、サービスの運用状況に関して。\n", + "contact_devHint": "機能のリクエスト、ユーザビリティの改善、あるいはお礼を言う場合。", + "contact_dev": "開発者に連絡", + "contact_admin": "管理者に連絡", + "admin_flushCacheDone": "キャッシュを消去しました", + "admin_flushCacheTitle": "HTTPキャッシュを消去", + "admin_updateLimitDone": "アップデートが完了しました", + "admin_updateLimitButton": "クォータを更新", + "admin_registeredHint": "あなたのインスタンスの登録ユーザー数", + "admin_updateLimitTitle": "ユーザーのクォータを更新", + "mdToolbar_defaultText": "ここにテキストを入力", + "upload_modal_filename": "ファイル名(拡張子 {0} を自動で追加)", + "settings_padSpellcheckHint": "リッチテキストパッドでスペルチェックを有効にします。間違ったつづりには赤色の下線が表示されます。右クリックをしながらコントロールキーあるいはメタキーを押すと、正しい選択肢が表示されます。", + "creation_404": "このパッドは存在しません。以下のフォームより新しいパッドを作成してください。", + "help_genericMore": "CryptPadの使用法についてはドキュメントをご覧ください。", + "whatis_drive": "CryptDriveを使用している組織", + "mdToolbar_toc": "目次", + "mdToolbar_check": "タスクリスト", + "mdToolbar_nlist": "番号付きリスト", + "mdToolbar_heading": "見出し", + "settings_cursorShowHint": "共同ドキュメントであなたが他のユーザーのカーソルの位置を見られるかどうかを決められます。", + "settings_cursorShareHint": "共同ドキュメントで他のユーザーがあなたのカーソルの位置を見られるかどうかを決められます。", + "settings_cursorColorHint": "共同ドキュメントのユーザーと関連付けられた色を変更します。", + "settings_padWidthHint": "テキストエディターの幅を制限するページモード(既定)と、スクリーン全体の幅を使用するモードを切り替える。", + "fm_forbidden": "禁止されたアクション", + "team_exportHint": "チームのドライブの全てのドキュメントをダウンロードします。ドキュメントは、他のアプリケーションで読み込めるフォーマットがあれば、そのフォーマットでダウンロードされます。そうしたフォーマットがなければ、CryptPadで読み込めるフォーマットでダウンロードされます。", + "admin_limitUser": "ユーザーの公開鍵", + "fm_shareFolderPassword": "このフォルダをパスワードで保護(任意)", + "team_exportTitle": "チームのドライブをダウンロード", + "admin_invalLimit": "無効な制限値です", + "admin_limitSetNote": "メモ", + "admin_limitMB": "制限(MB)", + "broadcast_newCustom": "管理者からのメッセージ", + "admin_broadcastActive": "アクティブなメッセージ", + "fc_noAction": "利用可能なアクションはありません", + "support_closed": "このチケットは終了しました", + "support_cat_tickets": "既存のチケット", + "support_formHint": "このフォームから、管理者に問題の報告や質問を安全に行うことができます。
    それらに関しては CryptPad ユーザーガイドで回答されているものがあるかもしれません。既にチケットを作成している場合、同じ問題に関して新しいチケットを作成するのはお控えください。その代わりに、既存のチケットに追加の情報を送信してください。", + "support_disabledTitle": "サポートは有効になっていません", + "admin_supportListHint": "ユーザーからサポートのメールボックスに送信されたチケットの一覧です。管理者はメッセージと回答を閲覧できます。終了したチケットは再開することができます。終了したチケットについては削除する(隠す)ことができますが、他の管理者には引き続き表示されます。", + "drive_sfPassword": "共有フォルダ「 {0} 」は利用できません。所有者により削除されたか、新しいパスワードにより保護されています。CryptDriveから削除するか、新しいパスワードを使ってアクセスを回復できます。", + "fm_info_sharedFolderHistory": "これは共有フォルダの履歴です: {0}
    CryptDriveは閲覧モードを継続します。", + "notification_folderShared": "{0}があなたとフォルダを共有しました: {1}", + "convertFolderToSF_SFChildren": "このフォルダは共有フォルダを含んでいるため、共有フォルダに変更できません。続けるには、このフォルダを共有フォルダの外に移動してください。", + "sharedFolders_share": "このリンクを登録ユーザーと共有すると、共有フォルダへのアクセスが可能になります。相手がリンクを開くと、CryptDriveに共有フォルダが追加されます。", + "sharedFolders_duplicate": "移動しようとしているパッドのいくつかは既に移動先のフォルダに存在しています。", + "sharedFolders_forget": "このパッドは共有フォルダにのみ保存されているため、ゴミ箱に移動できません。あなたのCryptDriveから削除することは可能です。", + "settings_ownDriveHint": "技術上の理由で、旧アカウントは最新の機能にアクセスできません。フリーのアップデートで新しい機能が有効になり、今後のアップデートにも対応します。" } From 107c8c82a088c47c3c574736107de97a68b7a5f5 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 29 Jun 2021 13:56:50 +0530 Subject: [PATCH 036/117] add Japanese to the language selector UI --- customize.dist/messages.js | 1 + 1 file changed, 1 insertion(+) diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 977405db1..7d9af710a 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -9,6 +9,7 @@ var map = { 'fr': 'Français', //'hi': 'हिन्दी', 'it': 'Italiano', + 'ja': '日本語', 'nb': 'Norwegian Bokmål', //'pl': 'Polski', 'pt-br': 'Português do Brasil', From 37e9e1d8cede17937b94ec04274aa47ef901345f Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 29 Jun 2021 12:04:21 +0200 Subject: [PATCH 037/117] Translated using Weblate (English) Currently translated at 100.0% (1357 of 1357 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1356 of 1356 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1355 of 1355 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 477c993a1..afee38fea 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1354,5 +1354,8 @@ "admin_provideAggregateStatisticsHint": "You may opt-in to providing additional usage metrics to the developers, such as the approximate number of registered and daily users for your instance.", "admin_provideAggregateStatisticsLabel": "Provide aggregated statistics", "form_poll_hint": ": Yes, : No, : Acceptable", - "fc_open_formro": "Open (as participant)" + "fc_open_formro": "Open (as participant)", + "resources_imageBlocked": "CryptPad blocked a remote image", + "resources_openInNewTab": "Open it in a new tab", + "resources_learnWhy": "Learn why it was blocked" } From 6b8cb9ab676c6ae1a2367eabb1aba3697455433a Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 29 Jun 2021 12:04:21 +0200 Subject: [PATCH 038/117] Translated using Weblate (Japanese) Currently translated at 85.4% (1157 of 1354 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index c56daf9c4..9574b6ef1 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -300,23 +300,23 @@ "features_pricing": "月額 {0}€ ~ {2}€", "features_emailRequired": "メールアドレスが必要です", "features_f_subscribe_note": "まず CryptPad にログインする必要があります", - "features_f_supporter": "プライバシーの支援者になる", + "features_f_supporter": "プライバシーを支援", "features_f_supporter_note": "プライバシーを保護するソフトウェアが標準であることを世界に示すのを手伝うことができます", - "features_f_support_note": "チームプランには電子メールによる高度なサポートが付属します", + "features_f_support_note": "電子メールとチケットシステムで、管理チームが優先対応", "features_f_support": "優先的なサポート", - "features_f_storage2_note": "選択したプランに応じて 5GB から 50GB までの追加ストレージ容量が利用可能です", + "features_f_storage2_note": "プランに応じて 5GB から 50GB までの追加ストレージ容量が利用でき、ファイルのアップロードの最大容量({0}MB)を増加", "features_f_storage2": "追加のストレージ容量", - "features_f_reg_note": "その上で CryptPad の開発者を支援できます", + "features_f_reg_note": "追加のメリット付き", "features_f_reg": "登録ユーザーの全機能", "homePage": "ホームページ", "features_noData": "登録に個人情報は必要ありません", "features_f_register": "無料登録", "features_f_storage1_note": "CryptDriveに保存したドキュメントは、有効期限切れで削除されることはありません", - "features_f_storage1": "永続的ストレージ (50MB)", + "features_f_storage1": "個人用ストレージ({0})", "oo_sheetMigration_complete": "新しいバージョンが利用可能です。「OK」を押して再読み込みしてください。", "oo_sheetMigration_loading": "あなたのスプレッドシートを最新バージョンにアップグレードしています。1分程度お待ちください。", "settings_ownDriveButton": "アカウントをアップグレード", - "features_f_file1_note": "連絡先とファイルを共有したり、パッドを埋め込む", + "features_f_file1_note": "CryptDriveに画像ファイル、PDF、動画などを保存できます。保存したファイルは、連絡先と共有したり、ドキュメントに埋め込んだりできます(最大容量は{0}MB)。", "crowdfunding_button": "CryptPad を支援", "contacts_removeHistoryTitle": "チャット履歴を削除", "properties_passwordSuccessFile": "パスワードは正常に変更されました。", @@ -1155,5 +1155,13 @@ "sharedFolders_share": "このリンクを登録ユーザーと共有すると、共有フォルダへのアクセスが可能になります。相手がリンクを開くと、CryptDriveに共有フォルダが追加されます。", "sharedFolders_duplicate": "移動しようとしているパッドのいくつかは既に移動先のフォルダに存在しています。", "sharedFolders_forget": "このパッドは共有フォルダにのみ保存されているため、ゴミ箱に移動できません。あなたのCryptDriveから削除することは可能です。", - "settings_ownDriveHint": "技術上の理由で、旧アカウントは最新の機能にアクセスできません。フリーのアップデートで新しい機能が有効になり、今後のアップデートにも対応します。" + "settings_ownDriveHint": "技術上の理由で、旧アカウントは最新の機能にアクセスできません。フリーのアップデートで新しい機能が有効になり、今後のアップデートにも対応します。", + "admin_activePadsHint": "閲覧もしくは編集中のドキュメント数", + "admin_activePadsTitle": "アクティブなパッド", + "admin_activeSessionsTitle": "アクティブな接続", + "fm_expirablePad": "期日: {0}", + "survey": "CryptPadのアンケート", + "share_embedCategory": "埋め込む", + "feedback_optout": "オプトアウトを希望の場合は、設定画面のチェックボックスでフィードバックを無効に設定してください。", + "home_host": "これはCryptPadの独立コミュニティーのインスタンスです。" } From fe4b85c98b01d829c0d00d56e9fddffe74768c62 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 29 Jun 2021 15:55:59 +0530 Subject: [PATCH 039/117] remove hardcoded translations for blocked images --- www/common/diffMarked.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 1f4fadefb..f4c5f40cd 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -279,12 +279,8 @@ define([ } }; - Messages.resources_imageBlocked = "CryptPad blocked a remote image"; // XXX - Messages.resources_openInNewTab = "Open its source in a new tab"; // XXX - Messages.resources_learnWhy = "Learn why it was blocked"; // XXX - renderer.image = function (href, title, text) { - if (href.slice(0,6) === '/file/') { // XXX this has been deprecated for about 3 years. Maybe we should display a warning? + if (href.slice(0,6) === '/file/') { // FIXME this has been deprecated for about 3 years. Maybe we should display a warning? // DEPRECATED // Mediatag using markdown syntax should not be used anymore so they don't support // password-protected files @@ -305,7 +301,7 @@ define([ h('div.cp-inline-img', [ h('img.cp-inline-img', { src: '/images/broken.png', - //title: title || '', // XXX sort out tippy issues (double-title) + //title: title || '', // FIXME sort out tippy issues (double-title) }), h('p.cp-alt-txt', text), ]), @@ -315,14 +311,12 @@ define([ h('a.cp-remote-img', { href: qualifiedHref(href), }, [ - //h('i.fa.fa-external-link'), // XXX Messages.resources_openInNewTab ]), h('br'), h('a.cp-learn-more', { - href: 'https://docs.cryptpad.fr/en/user_guide/index.html?placeholder=remote_images', // XXX point to an actual page + href: 'https://docs.cryptpad.fr/user_guide/security.html#remote-content', // XXX make sure this exists }, [ - //h('i.fa.fa-question-circle'), // XXX Messages.resources_learnWhy ]), ]); From ccda547682d2bf94480310a3520b914950d80f97 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 29 Jun 2021 12:44:42 +0200 Subject: [PATCH 040/117] Translated using Weblate (English) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1365 of 1365 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1364 of 1364 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1363 of 1363 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1362 of 1362 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1361 of 1361 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1360 of 1360 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1359 of 1359 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ Translated using Weblate (English) Currently translated at 100.0% (1358 of 1358 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index afee38fea..f61659809 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1357,5 +1357,14 @@ "fc_open_formro": "Open (as participant)", "resources_imageBlocked": "CryptPad blocked a remote image", "resources_openInNewTab": "Open it in a new tab", - "resources_learnWhy": "Learn why it was blocked" + "resources_learnWhy": "Learn why it was blocked", + "admin_instancePurposeTitle": "Instance purpose", + "admin_purpose_noanswer": "I prefer not to say", + "admin_purpose_experiment": "To test the platform or develop new features", + "admin_purpose_personal": "For myself, family, or friends", + "admin_purpose_org": "For a non-profit organization or advocacy group", + "admin_purpose_education": "For a school, college, or university", + "admin_purpose_public": "To provide a free service to the public", + "admin_purpose_business": "For a business or commercial organization", + "admin_instancePurposeHint": "Why do you run this instance? Your answer will be used to inform the development roadmap if your telemetry is enabled." } From 4fc60b86c5162af1975734c6cfb7b07d68668b27 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 29 Jun 2021 16:29:49 +0530 Subject: [PATCH 041/117] remove hardcoded admin panel translations --- www/admin/inner.js | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 592c77a5f..13f96cdf7 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -1854,24 +1854,6 @@ define([ }, }); - Messages.admin_instancePurposeTitle = "Instance purpose"; // XXX - Messages.admin_instancePurposeHint = "Why do you run this instance? Your answer will be shared with the developers unless you have disabled telemetry"; // XXX - - Messages.admin_purpose_noanswer = "I prefer not to answer"; // XXX - Messages.admin_purpose_experiment = "To test the CryptPad platform"; // XXX - Messages.admin_purpose_development = "To develop new features for CryptPad"; // XXX - - Messages.admin_purpose_personal = "For myself, family, or friends"; // XXX - - Messages.admin_purpose_business = "For my business's external use"; // XXX - Messages.admin_purpose_intranet = "For my business's internal use"; // XXX - - Messages.admin_purpose_school = "For my school, college, or university"; // XXX - Messages.admin_purpose_org = "For a non-profit organization or advocacy group"; // XXX - - Messages.admin_purpose_commercial = "To provide a commercial service"; // XXX - Messages.admin_purpose_public = "To provide a free service"; // XXX - var sendDecree = function (data, cb) { sFrameChan.query('Q_ADMIN_RPC', { cmd: 'ADMIN_DECREE', @@ -1881,19 +1863,16 @@ define([ create['instance-purpose'] = function () { var key = 'instance-purpose'; - var $div = makeBlock(key); + var $div = makeBlock(key); // Messages.admin_instancePurposeTitle.admin_instancePurposeHint var values = [ - 'noanswer', - 'development', - 'experiment', - 'personal', - 'business', // as a public resource for my business clients - 'intranet', // for my business's _internal use_ - 'school', - 'org', - 'commercial', - 'public', // to provide a free service (for the public) + 'noanswer', // Messages.admin_purpose_noanswer + 'experiment', // Messages.admin_purpose_experiment + 'personal', // Messages.admin_purpose_personal + 'education', // Messages.admin_purpose_education + 'org', // Messages.admin_purpose_org + 'business', // Messages.admin_purpose_business + 'public', // Messages.admin_purpose_public ]; var defaultPurpose = 'noanswer'; From 3d224446033f478f7629f5a7e63442aa9bbb601c Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 09:21:53 +0200 Subject: [PATCH 042/117] Translated using Weblate (Japanese) Currently translated at 91.6% (1252 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.3% (1248 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 90.1% (1232 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 87.8% (1200 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 119 ++++++++++++++++++++--- 1 file changed, 104 insertions(+), 15 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 9574b6ef1..a2d5e39ae 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -28,7 +28,7 @@ "support_formMessage": "メッセージを入力…", "support_formContentError": "エラー:内容が空です", "support_formTitleError": "エラー:件名が空です", - "support_formTitle": "チケットの件名", + "support_formTitle": "新しいチケット", "support_cat_new": "新しいチケット", "support_answer": "返信", "support_remove": "チケットを削除", @@ -296,12 +296,12 @@ "contact_chat": "チャット", "contact_bug": "バグの報告", "footer_product": "製品", - "features_f_subscribe": "プレミアムプランに登録", + "features_f_subscribe": "定額利用を申し込む", "features_pricing": "月額 {0}€ ~ {2}€", "features_emailRequired": "メールアドレスが必要です", - "features_f_subscribe_note": "まず CryptPad にログインする必要があります", + "features_f_subscribe_note": "定額利用の登録には、アカウントの登録が必要です", "features_f_supporter": "プライバシーを支援", - "features_f_supporter_note": "プライバシーを保護するソフトウェアが標準であることを世界に示すのを手伝うことができます", + "features_f_supporter_note": "CryptPadが財政的に持続可能になること、また、ユーザーが積極的に資金を提供するプライバシー強化ソフトウェアが標準でなければならないことを示す手助けをする", "features_f_support_note": "電子メールとチケットシステムで、管理チームが優先対応", "features_f_support": "優先的なサポート", "features_f_storage2_note": "プランに応じて 5GB から 50GB までの追加ストレージ容量が利用でき、ファイルのアップロードの最大容量({0}MB)を増加", @@ -316,7 +316,7 @@ "oo_sheetMigration_complete": "新しいバージョンが利用可能です。「OK」を押して再読み込みしてください。", "oo_sheetMigration_loading": "あなたのスプレッドシートを最新バージョンにアップグレードしています。1分程度お待ちください。", "settings_ownDriveButton": "アカウントをアップグレード", - "features_f_file1_note": "CryptDriveに画像ファイル、PDF、動画などを保存できます。保存したファイルは、連絡先と共有したり、ドキュメントに埋め込んだりできます(最大容量は{0}MB)。", + "features_f_file1_note": "CryptDriveに画像ファイル、PDF、動画などを保存できます。保存したファイルは、連絡先と共有したり、ドキュメントに埋め込んだりできます。(最大容量は{0}MB)", "crowdfunding_button": "CryptPad を支援", "contacts_removeHistoryTitle": "チャット履歴を削除", "properties_passwordSuccessFile": "パスワードは正常に変更されました。", @@ -338,7 +338,7 @@ "access_allow": "リスト", "makeACopy": "コピーを作成", "trimHistory_noHistory": "削除可能な履歴がありません", - "areYouSure": "クリックして実行", + "areYouSure": "よろしいですか?", "settings_safeLinksCheckbox": "安全なリンクを有効にする", "settings_safeLinksTitle": "安全なリンク", "settings_safeLinksHint": "CryptPad では、あなたのパッドを解読するための鍵がリンクに含まれています。これは、あなたのブラウザの閲覧履歴にアクセスできる人が、潜在的にあなたの CryptPad のデータを解読・閲覧できることを意味します。この「ブラウザの閲覧履歴にアクセスできる人」には、デバイス間で履歴を同期させる侵入的なブラウザ拡張機能やブラウザが含まれます。「安全なリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にした上で共有メニューを使用することを強く推奨します。", @@ -442,7 +442,7 @@ "kanban_tags": "タグでフィルタリング", "allow_text": "アクセスリストを使用すると、選択したユーザーと所有者だけがこのドキュメントにアクセスできます。", "admin_defaultlimitTitle": "ストレージの制限(MB)", - "owner_add": "{0}があなたをパッド {1} の所有者になるよう希望しています。 受け入れますか?", + "owner_add": "{0}があなたをパッド {1} の所有者になるよう希望しています。 承諾しますか?", "owner_removeConfirm": "選択したユーザーの所有権を削除してよろしいですか? ユーザーには通知が送られます。", "owner_removePendingText": "保留中", "properties_unknownUser": "{0}人の不明なユーザー", @@ -930,7 +930,7 @@ "share_linkEmbed": "埋め込みモード(ツールバーとユーザー一覧を隠します)", "properties_passwordSuccess": "パスワードは変更されました。
    OKを押して再読み込みし、アクセス権限を更新してください。", "properties_passwordWarning": "パスワードは変更されましたが、CryptDriveを更新することができませんでした。古いバージョンのパッドは手動で削除しなければならないかもしれません。
    OKを押して再読み込みし、アクセス権限を更新してください。", - "properties_confirmChange": "パスワードを変更すると履歴が削除されます。パスワードを知らないユーザーは、このパッドへアクセスできなくなります。続行してよろしいですか?", + "properties_confirmChange": "パスワードを変更すると履歴が削除されます。パスワードを知らないユーザーは、このパッドにアクセスできなくなります。続行してよろしいですか?", "creation_newPadModalDescription": "作成するドキュメントの種類をクリックしてください。タブキーで選択し、エンターキーで作成することもできます。", "creation_noOwner": "所有者がありません", "properties_passwordError": "パスワードの変更中にエラーが発生しました。再度試してください。", @@ -1015,21 +1015,21 @@ "useTemplateCancel": "新しく開始(Esc)", "fm_originalPath": "本来のパス", "contacts_online": "このルームの別のユーザーがオンラインです", - "contacts_request": "{0}があなたを連絡先に追加しようとしています。受け入れますか?", + "contacts_request": "{0}があなたを連絡先に追加しようとしています。承諾しますか?", "contacts_rejected": "連絡先の招待が拒否されました", - "contacts_added": "連絡先の招待が受け入れられました。", + "contacts_added": "連絡先の招待が承諾されました。", "profile_uploadTypeError": "エラー: あなたのアバターの種類は許可されていません。許可されている種類: {0}", "canvas_imageEmbed": "コンピューターの画像を埋め込む", "canvas_currentBrush": "現在のブラシ", "poll_total": "合計", "kanban_todo": "タスク", - "slide_invalidLess": "カスタムスタイルは無効です", - "printCSS": "カスタムスタイルルール(CSS):", + "slide_invalidLess": "ユーザー定義のスタイルは無効です", + "printCSS": "ユーザー定義のスタイルルール(CSS):", "admin_provideAggregateStatisticsHint": "追加の利用状況を開発者に提供することも選択できます。追加の情報には、あなたのインスタンスのおおよその登録ユーザー数や一日あたりのユーザー数などがあります。", "fm_info_sharedFolder": "これは共有フォルダです。ログインしていないため、閲覧モードでしかアクセスできません。
    登録あるいはログインすると、CryptDriveにインポートして編集できます。", "team_invitedToTeam": "{0}があなたをチーム「{1}」に招待しました", "team_inviteFromMsg": "{0}があなたをチーム「{1}」に招待しました", - "team_invitePleaseLogin": "招待を受け入れるには、ログインもしくは登録してください。", + "team_invitePleaseLogin": "招待を承諾するには、ログインもしくは登録してください。", "team_inviteEnterPassword": "招待パスワードを入力してください。", "team_inviteGetData": "チームのデータを取得中です", "team_inviteInvalidLinkError": "招待リンクが無効です。", @@ -1046,7 +1046,7 @@ "register_emailWarning0": "ユーザー名にメールアドレスが入力されています。", "fm_tags_used": "使用数", "fm_deletedPads": "これらのパッドはサーバーにありません。あなたのCryptDriveから削除されています: {0}", - "fm_renamedPad": "このパッドにカスタム名を設定しました。共有のファイル名は
    {0}", + "fm_renamedPad": "このパッドにユーザー定義の名前を設定しました。共有のファイル名は
    {0}", "fm_ownedPadsName": "所有", "burnAfterReading_generateLink": "下のボタンをクリックするとリンクを生成します。", "fm_restricted": "アクセス権がありません", @@ -1163,5 +1163,94 @@ "survey": "CryptPadのアンケート", "share_embedCategory": "埋め込む", "feedback_optout": "オプトアウトを希望の場合は、設定画面のチェックボックスでフィードバックを無効に設定してください。", - "home_host": "これはCryptPadの独立コミュニティーのインスタンスです。" + "home_host": "これはCryptPadの独立コミュニティーのインスタンスです。", + "team_deleteConfirm": "チーム全体のデータを全て削除しようとしています。削除すると、チームの他のメンバーもデータにアクセスできなくなります。これは取り消せません。削除してよろしいですか?", + "team_kickConfirm": "{0}はチームから削除された旨通知されます。よろしいですか?", + "admin_instancePurposeHint": "インスタンスを運用する目的は何ですか?テレメトリーが有効になっている場合、回答は開発ロードマップに利用されます。", + "admin_purpose_experiment": "プラットフォームのテストあるいは新機能の開発", + "admin_purpose_noanswer": "回答しない", + "admin_instancePurposeTitle": "インスタンスの目的", + "requestEdit_request": "{1}がパッド({0})の編集を希望しています", + "support_from": "送信元: {0}", + "admin_supportInitPrivate": "あなたのCryptPadのインスタンスは、サポートメールボックスを使用するよう設定されていますが、アクセスに必要な秘密鍵がアカウントに登録されていません。以下のフォームから、秘密鍵を登録もしくは更新してください。", + "resources_imageBlocked": "リモート画像をブロックしました", + "team_inviteLinkErrorName": "招待する人の名前を追加してください。名前は後から変更できます。 ", + "snapshots_ooPickVersion": "スナップショットの作成には、対象となるバージョンの選択が必要です", + "notification_folderSharedTeam": "{0}がチーム({2})とフォルダ({1})を共有しました", + "notification_fileSharedTeam": "{0}がチーム({2})とファイル({1})を共有しました", + "notification_padSharedTeam": "{0}がチーム({2})とパッド({1})を共有しました", + "requestEdit_accepted": "{1}があなたにパッド({0})の編集権を付与しました", + "admin_registrationHint": "ユーザーの新規登録を許可しない", + "oo_deletedVersion": "このバージョンは履歴に存在しません。", + "team_pickFriends": "チームに招待する連絡先を選択", + "notification_fileShared": "{0}があなたとファイルを共有しました: {1}", + "resources_openInNewTab": "新しいタブで開く", + "download_zip": "ZIPファイルを作成しています…", + "fileTableHeader": "ダウンロードとアップロード", + "share_copyProfileLink": "プロフィールのリンクをコピー", + "calendar_weekNumber": "{0}週", + "admin_support_closed": "終了したチケット:", + "admin_support_answered": "回答済のチケット:", + "admin_support_normal": "未回答のチケット:", + "admin_limitNote": "メモ: {0}", + "share_linkFriends": "連絡先と共有", + "share_filterFriend": "名前で検索", + "notification_padShared": "{0}があなたとパッドを共有しました: {1}", + "profile_friendRequestSent": "連絡先のリクエストは保留中です…", + "friendRequest_notification": "{0}があなたに連絡先への追加のリクエストを送信しました", + "friendRequest_received": "{0}が連絡先への追加を希望しています", + "friendRequest_declined": "{0}が連絡先のリクエストを拒否しました", + "admin_diskUsageHint": "CryptPadのリソースが消費しているストレージ容量", + "timeoutError": "エラーが発生してサーバーへの接続が切断されました。
    Escキーを押してページをリロードしてください。", + "footer_team": "貢献者", + "admin_updateLimitHint": "ユーザーのストレージ制限の強制アップデートはいつでも可能ですが、エラーが発生したときのみ必須となります", + "admin_cat_general": "全般", + "poll_bookmarked_col": "列をブックマークしました。常に編集可能な仕方で左端に表示されます。", + "poll_bookmark_col": "この列をブックマークすると、常に編集可能な仕方で左端に表示されます", + "settings_colortheme_custom": "ユーザー定義", + "admin_getlimitsTitle": "個別の制限", + "admin_setlimitTitle": "個別の制限を適用", + "admin_setlimitHint": "公開鍵を使用して、ユーザーに個別の制限を設定します。既存のルールは変更または削除できます。", + "form_maxOptions": "{0}個まで回答可", + "form_anonymous_off": "ブロック", + "admin_checkupHint": "CryptPadには、一般的な構成に関する問題を自動で診断し、必要に応じてそれらを修正する方法を提案するページがあります。", + "admin_broadcastTitle": "メッセージを送信", + "admin_broadcastHint": "このインスタンスの全ユーザーにメッセージを送信します。ユーザーはメッセージを通知で受け取ります。「通知をプレビュー」で送信前のメッセージを確認できます。通知のプレビューには赤いアイコンがあり、あなたにだけ表示されます。", + "calendar_before": "以前", + "share_formAuditor": "監査人", + "form_editMax": "選択できるオプションの最大数", + "form_invalidWarning": "回答にエラーがあります:", + "form_isOpen": "このフォームは公開中です", + "form_isClosed": "このフォームは{0}に閉じられました", + "form_willClose": "このフォームは{0}に終了します", + "settings_driveRedirectHint": "ログイン時にホームページからドライブに自動で転送する機能は、デフォルトで有効ではなくなりました。以前の動作は以下で有効にできます。", + "admin_removeDonateButtonLabel": "クラウドファンディングのキャンペーンの宣伝を表示しない", + "admin_purpose_public": "誰でも利用できるフリーのサービスを提供するため", + "owner_team_add": "{0}があなたをチーム({1})の所有者にしようとしています。承諾しますか?", + "friendRequest_accepted": "{0}が連絡先リクエストを承諾しました", + "friendRequest_accept": "承諾(Enter)", + "admin_flushCacheHint": "サーバーから最新のコンテンツをダウンロードするようユーザーに強制(サーバーが「フレッシュ」モードの場合のみ)", + "admin_activeSessionsHint": "アクティブなwebsocketの接続(および接続する一意のIPアドレス)の数", + "convertFolderToSF_SFParent": "このフォルダは別の共有フォルダ内にあるため、共有フォルダに変換できません。続行するには、外部に移動してください。", + "settings_deleteWarning": "注意:現在、プレミアムプランに加入しています(別のユーザーが支払いまたは提供)。アカウントを削除する前に、プランをキャンセルしてください。アカウントを削除すると、サポートに連絡しないとキャンセルできなくなります。", + "owner_request": "{0}はあなたを{1}の所有者にしようとしています", + "owner_addConfirm": "共同所有者は内容を変更したり、あなたを所有者から削除したりすることができます。続行してよろしいですか?", + "download_zip_file": "ファイル {0}/{1}", + "documentID": "ドキュメントの識別子", + "admin_setlimitButton": "制限を設定", + "historyTrim_contentsSize": "内容: {0}", + "team_invitePasswordLoading": "招待状を復号化しています", + "team_pcsSelectLabel": "保存場所", + "admin_cat_broadcast": "お知らせ", + "docs_link": "ドキュメンテーション", + "admin_support_collapse": "折りたたむ", + "team_inviteFrom": "送信元:", + "admin_supportInitHint": "サポートのメールボックスを設定すれば、あなたのCryptPadのインスタンスのユーザーが、アカウントから安全に問い合わせを行うことができるようになります。", + "isNotContact": "{0}はあなたの連絡先ではありません", + "isContact": "{0}はあなたの連絡先です", + "profile_info": "他のユーザーは、ドキュメントのユーザーリストであなたのアバターをクリックして、あなたのプロフィールを確認できます。", + "owner_removeMeConfirm": "所有権を放棄しようとしています。これは取り消せません。よろしいですか?", + "requestEdit_confirm": "{1}がパッド「{0}」の編集権を要求しました。編集権を与えますか?", + "admin_supportInitHelp": "サーバーはサポートメールボックスを使用するように設定されていません。サポートメールボックスを有効にし、ユーザーからメッセージを受け取るためには、サーバーの管理者に連絡し、「./scripts/generate-admin-keys.js」のスクリプトを実行してもらい、生成された公開鍵を「config.js」に保存して、秘密鍵をあなたに送信してもらうよう依頼する必要があります。", + "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求して、ユーザーにとって重要なUI機能を特定するために使用されます。" } From 2c383831471405e902c1835e04258a49399cc9aa Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 09:21:53 +0200 Subject: [PATCH 043/117] Translated using Weblate (German) Currently translated at 99.2% (1356 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index e07cdf090..ee2be161b 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1354,5 +1354,7 @@ "form_open": "Öffnen", "form_viewButton": "Anzeigen", "form_poll_hint": ": Ja, : Nein, : Akzeptabel", - "fc_open_formro": "Öffnen (als Teilnehmer)" + "fc_open_formro": "Öffnen (als Teilnehmer)", + "resources_openInNewTab": "In neuem Tab öffnen", + "resources_imageBlocked": "CryptPad hat ein externes Bild blockiert" } From 12c18fe7a3d6aa347df2749b5e26887d810f716c Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 30 Jun 2021 12:36:16 +0200 Subject: [PATCH 044/117] Remove unused file --- www/convert/file-crypto.js | 209 ------------------------------------- 1 file changed, 209 deletions(-) delete mode 100644 www/convert/file-crypto.js diff --git a/www/convert/file-crypto.js b/www/convert/file-crypto.js deleted file mode 100644 index 6a0c08816..000000000 --- a/www/convert/file-crypto.js +++ /dev/null @@ -1,209 +0,0 @@ -define([ - '/bower_components/tweetnacl/nacl-fast.min.js', -], function () { - var Nacl = window.nacl; - //var PARANOIA = true; - - var plainChunkLength = 128 * 1024; - var cypherChunkLength = 131088; - - var computeEncryptedSize = function (bytes, meta) { - var metasize = Nacl.util.decodeUTF8(JSON.stringify(meta)).length; - var chunks = Math.ceil(bytes / plainChunkLength); - return metasize + 18 + (chunks * 16) + bytes; - }; - - var encodePrefix = function (p) { - return [ - 65280, // 255 << 8 - 255, - ].map(function (n, i) { - return (p & n) >> ((1 - i) * 8); - }); - }; - var decodePrefix = function (A) { - return (A[0] << 8) | A[1]; - }; - - var slice = function (A) { - return Array.prototype.slice.call(A); - }; - - var createNonce = function () { - return new Uint8Array(new Array(24).fill(0)); - }; - - var increment = function (N) { - var l = N.length; - while (l-- > 1) { - /* our linter suspects this is unsafe because we lack types - but as long as this is only used on nonces, it should be safe */ - if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line - if (l === 0) { throw new Error('E_NONCE_TOO_LARGE'); } - N[l] = 0; - } - }; - - var joinChunks = function (chunks) { - return new Blob(chunks); - }; - - var decrypt = function (u8, key, done, progress) { - var MAX = u8.length; - var _progress = function (offset) { - if (typeof(progress) !== 'function') { return; } - progress(Math.min(1, offset / MAX)); - }; - - var nonce = createNonce(); - var i = 0; - - var prefix = u8.subarray(0, 2); - var metadataLength = decodePrefix(prefix); - - var res = { - metadata: undefined, - }; - - var cancelled = false; - var cancel = function () { - cancelled = true; - }; - - var metaBox = new Uint8Array(u8.subarray(2, 2 + metadataLength)); - - var metaChunk = Nacl.secretbox.open(metaBox, nonce, key); - increment(nonce); - - try { - res.metadata = JSON.parse(Nacl.util.encodeUTF8(metaChunk)); - } catch (e) { - return window.setTimeout(function () { - done('E_METADATA_DECRYPTION'); - }); - } - - if (!res.metadata) { - return void setTimeout(function () { - done('NO_METADATA'); - }); - } - - var takeChunk = function (cb) { - setTimeout(function () { - var start = i * cypherChunkLength + 2 + metadataLength; - var end = start + cypherChunkLength; - i++; - var box = new Uint8Array(u8.subarray(start, end)); - - // decrypt the chunk - var plaintext = Nacl.secretbox.open(box, nonce, key); - increment(nonce); - - if (!plaintext) { return cb('DECRYPTION_ERROR'); } - - _progress(end); - cb(void 0, plaintext); - }); - }; - - var chunks = []; - - var again = function () { - if (cancelled) { return; } - takeChunk(function (e, plaintext) { - if (e) { - return setTimeout(function () { - done(e); - }); - } - if (plaintext) { - if ((2 + metadataLength + i * cypherChunkLength) < u8.length) { // not done - chunks.push(plaintext); - return setTimeout(again); - } - chunks.push(plaintext); - res.content = joinChunks(chunks); - return done(void 0, res); - } - done('UNEXPECTED_ENDING'); - }); - }; - - again(); - - return { - cancel: cancel - }; - }; - - // metadata - /* { filename: 'raccoon.jpg', type: 'image/jpeg' } */ - var encrypt = function (u8, metadata, key) { - var nonce = createNonce(); - - // encode metadata - var plaintext = Nacl.util.decodeUTF8(JSON.stringify(metadata)); - - // if metadata is too large, drop the thumbnail. - if (plaintext.length > 65535) { - var temp = JSON.parse(JSON.stringify(metadata)); - delete metadata.thumbnail; - plaintext = Nacl.util.decodeUTF8(JSON.stringify(temp)); - } - - var i = 0; - - var state = 0; - var next = function (cb) { - if (state === 2) { return void setTimeout(cb); } - - var start; - var end; - var part; - var box; - - if (state === 0) { // metadata... - part = new Uint8Array(plaintext); - box = Nacl.secretbox(part, nonce, key); - increment(nonce); - - if (box.length > 65535) { - return void cb('METADATA_TOO_LARGE'); - } - var prefixed = new Uint8Array(encodePrefix(box.length) - .concat(slice(box))); - state++; - - return void setTimeout(function () { - cb(void 0, prefixed); - }); - } - - // encrypt the rest of the file... - start = i * plainChunkLength; - end = start + plainChunkLength; - - part = u8.subarray(start, end); - box = Nacl.secretbox(part, nonce, key); - increment(nonce); - i++; - - // regular data is done - if (i * plainChunkLength >= u8.length) { state = 2; } - - setTimeout(function () { - cb(void 0, box); - }); - }; - - return next; - }; - - return { - decrypt: decrypt, - encrypt: encrypt, - joinChunks: joinChunks, - computeEncryptedSize: computeEncryptedSize, - }; -}); From 87d04ed68a446eee210ae1e73d864a76db8b5487 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 30 Jun 2021 12:36:24 +0200 Subject: [PATCH 045/117] Fix form CSV export --- www/form/export.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/www/form/export.js b/www/form/export.js index e29c6dd87..93f3ff6d3 100644 --- a/www/form/export.js +++ b/www/form/export.js @@ -5,7 +5,7 @@ define([ var Export = {}; var escapeCSV = function (v) { - if (!/("|,)/.test(v)) { + if (!/("|,|\n)/.test(v)) { return v || ''; } var value = ''; @@ -14,7 +14,6 @@ define([ return value; }; Export.results = function (content, answers, TYPES) { - console.log(content, answers, TYPES); if (!content || !content.form) { return; } var csv = ""; var form = content.form; @@ -24,8 +23,8 @@ define([ if (!obj) { return; } return obj.q || Messages.form_default; }).filter(Boolean); - questions.unshift(Messages.form_poll_time); // "Time" questions.unshift(Messages.share_formView); // "Participant" + questions.unshift(Messages.form_poll_time); // "Time" questions.forEach(function (v, i) { if (i) { csv += ','; } @@ -37,14 +36,14 @@ define([ csv += '\n'; var time = new Date(obj.time).toISOString(); var msg = obj.msg || {}; - var user = msg._userdata; + var user = msg._userdata || {}; csv += escapeCSV(time); csv += ',' + escapeCSV(user.name || Messages.anonymous); Object.keys(form).forEach(function (key) { - csv += ',' + escapeCSV(String(msg[key])); + if (msg[key] && typeof(msg[key]) !== "string") { console.warn(key, msg[key]); } + csv += ',' + escapeCSV(String(msg[key] || '')); }); }); - console.log(csv); return csv; }; From c7ac75d137b7a508a6cd4fb7ca43fdbfdc2b83c7 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 30 Jun 2021 12:47:02 +0200 Subject: [PATCH 046/117] Fix CSV export in forms --- www/form/export.js | 8 ++++++-- www/form/inner.js | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/www/form/export.js b/www/form/export.js index 93f3ff6d3..0e78d171a 100644 --- a/www/form/export.js +++ b/www/form/export.js @@ -5,7 +5,7 @@ define([ var Export = {}; var escapeCSV = function (v) { - if (!/("|,|\n)/.test(v)) { + if (!/("|,|\n|;)/.test(v)) { return v || ''; } var value = ''; @@ -40,7 +40,11 @@ define([ csv += escapeCSV(time); csv += ',' + escapeCSV(user.name || Messages.anonymous); Object.keys(form).forEach(function (key) { - if (msg[key] && typeof(msg[key]) !== "string") { console.warn(key, msg[key]); } + var type = form[key].type; + if (TYPES[type] && TYPES[type].exportCSV) { + csv += ',' + escapeCSV(TYPES[type].exportCSV(msg[key])); + return; + } csv += ',' + escapeCSV(String(msg[key] || '')); }); }); diff --git a/www/form/inner.js b/www/form/inner.js index 123e86d5b..8b51e2102 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1646,6 +1646,15 @@ define([ return h('div.cp-form-type-poll', lines); }, + exportCSV: function (answer) { + if (!answer || !answer.values) { return ''; } + var str = ''; + Object.keys(answer.values).sort().forEach(function (k, i) { + if (i !== 0) { str += ';'; } + str += k.replace(';', '').replace(':', '') + ':' + answer.values[k]; + }); + return str; + }, icon: h('i.cptools.cptools-form-poll') }, }; From c9654a789267c01bf4c687c47d1978525cf84996 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 16:51:50 +0530 Subject: [PATCH 047/117] remove XXX notes from forms and comment why they were there --- www/form/inner.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 123e86d5b..23332b944 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -80,8 +80,11 @@ define([ timeFormat = "h:i K"; } - var MAX_OPTIONS = 15; // XXX - var MAX_ITEMS = 10; // XXX + // multi-line radio, checkboxes, and possibly other things have a max number of items + // we'll consider increasing this restriction if people are unhappy with it + // but as a general rule we expect users will appreciate having simpler questions + var MAX_OPTIONS = 15; + var MAX_ITEMS = 10; var saveAndCancelOptions = function (getRes, cb) { // Cancel changes From 8da7cb023f74a5fdb283aa9c8c4cddc7d52699b1 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 13:23:22 +0200 Subject: [PATCH 048/117] Translated using Weblate (Japanese) Currently translated at 92.4% (1263 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.4% (1263 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.4% (1263 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.3% (1262 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.3% (1262 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.3% (1261 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.2% (1260 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.2% (1260 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.1% (1259 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.1% (1259 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.1% (1259 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1258 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1258 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1258 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1258 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1258 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1257 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.0% (1257 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.9% (1256 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.9% (1256 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.8% (1254 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.7% (1253 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.6% (1252 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.6% (1252 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.7% (1253 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.7% (1253 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.6% (1252 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 91.6% (1252 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 61 ++++++++++++++---------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index a2d5e39ae..f8d52b8c6 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1,7 +1,7 @@ { "common_connectionLost": "サーバーとの接続が切断しました
    再接続するまで閲覧モードになります。", "button_newsheet": "新規スプレッドシート", - "button_newkanban": "新規看板", + "button_newkanban": "新規のカンバン", "button_newwhiteboard": "新規ホワイトボード", "button_newslide": "新規プレゼンテーション", "button_newpoll": "新規投票・アンケート", @@ -60,7 +60,7 @@ "fm_folder": "フォルダ", "fm_folderName": "フォルダ名", "fm_fileName": "ファイル名", - "crowdfunding_button2": "CryptPad を助ける", + "crowdfunding_button2": "CryptPadを支援", "fm_padIsOwned": "あなたはこのパッドの所有者です", "creation_expiration": "有効期限", "owner_removeText": "所有者", @@ -101,7 +101,7 @@ "settings_changePasswordNew": "新しいパスワード", "settings_changePasswordCurrent": "現在のパスワード", "settings_changePasswordButton": "パスワードを変更", - "settings_changePasswordHint": "アカウントのパスワードを変更します。「現在のパスワード」と、「新しいパスワード」および「新しいパスワードの確認」を入力してください。
    あなたがパスワードを忘れた場合、パスワードをリセットする方法はありません。細心の注意を払って、パスワードを安全に管理してください。", + "settings_changePasswordHint": "アカウントのパスワードを変更します。「現在のパスワード」と、「新しいパスワード」および「新しいパスワードの確認」を入力してください。
    パスワードを忘れた場合、パスワードをリセットする方法はありません。細心の注意を払って、パスワードを安全に管理してください。", "settings_changePasswordTitle": "パスワードの変更", "languageButton": "言語", "language": "言語", @@ -120,10 +120,10 @@ "profile_addLink": "あなたのウェブサイトへのリンクを追加", "shareSuccess": "リンクをクリップボードにコピーしました", "shareButton": "共有", - "login_hashing": "パスワードをハッシュ化しています、この処理には時間がかかる場合があります。", + "login_hashing": "パスワードをハッシュ化しています。この処理には時間がかかる場合があります。", "login_invalPass": "パスワードを入力してください", "login_invalUser": "ユーザー名を入力してください", - "register_importRecent": "未登録のセッション中のドキュメントをインポート", + "register_importRecent": "匿名セッションのドキュメントをインポート", "importButton": "インポート", "main_catch_phrase": "コラボレーションスイート
    暗号化されかつオープンソース", "tos_3rdparties": "私たちは、法律で義務付けられている場合を除き、個別のデータを第三者に提供しません。", @@ -151,7 +151,7 @@ "login_login": "ログイン", "autostore_hide": "保存しない", "autostore_store": "保存する", - "autostore_notstored": "この {0} は、あなたの CryptDrive に保存されていません。今すぐ保存しますか?", + "autostore_notstored": "この{0}はあなたのCryptDriveに保存されていません。今すぐ保存しますか?", "user_displayName": "表示名", "exportButton": "エクスポート", "user_rename": "表示名を変更", @@ -232,7 +232,7 @@ "settings_autostoreHint": "自動 あなたがアクセスしたすべてのパッドを、あなたの CryptDrive に保存します。
    手動 (常に確認する) まだ保存していないパッドにアクセスした場合に、あなたの CryptDrive に保存するかどうか尋ねます。
    手動 (確認しない) アクセス先のパッドがあなたの CryptDrive に自動的に保存されなくなります。保存オプションは表示されなくなります。", "settings_userFeedback": "ユーザーフィードバックを有効にする", "settings_userFeedbackHint2": "あなたのパッドのコンテンツがサーバーと共有されることはありません。", - "settings_userFeedbackHint1": "CryptPad は、あなたの経験を向上させる方法を知るために、サーバーにいくつかの非常に基本的なフィードバックを提供します。 ", + "settings_userFeedbackHint1": "CryptPad は、ユーザーエクスペリエンスの向上のため、サーバーにいくつかの非常に基本的なフィードバックを提供します。 ", "settings_userFeedbackTitle": "フィードバック", "settings_autostoreYes": "自動", "settings_importConfirm": "このブラウザで最近使用したパッドを、あなたのユーザーアカウントの CryptDrive にインポートしますか?", @@ -279,7 +279,7 @@ "features_registered": "登録済", "features_title": "機能", "features_anon": "未登録", - "register_whyRegister": "登録するとどの様な利点がありますか?", + "register_whyRegister": "登録するメリットをご紹介します", "historyText": "履歴", "help_button": "ヘルプ", "show_help_button": "ヘルプを表示", @@ -339,9 +339,9 @@ "makeACopy": "コピーを作成", "trimHistory_noHistory": "削除可能な履歴がありません", "areYouSure": "よろしいですか?", - "settings_safeLinksCheckbox": "安全なリンクを有効にする", - "settings_safeLinksTitle": "安全なリンク", - "settings_safeLinksHint": "CryptPad では、あなたのパッドを解読するための鍵がリンクに含まれています。これは、あなたのブラウザの閲覧履歴にアクセスできる人が、潜在的にあなたの CryptPad のデータを解読・閲覧できることを意味します。この「ブラウザの閲覧履歴にアクセスできる人」には、デバイス間で履歴を同期させる侵入的なブラウザ拡張機能やブラウザが含まれます。「安全なリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にした上で共有メニューを使用することを強く推奨します。", + "settings_safeLinksCheckbox": "セーフリンクを有効にする", + "settings_safeLinksTitle": "セーフリンク", + "settings_safeLinksHint": "CryptPadでは、リンクの中にパッドを解読するための鍵が含まれています。ブラウザの閲覧履歴にアクセスできる人は、誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューを使用することを強く推奨します。", "settings_autostoreTitle": "CryptDrive へのパッドの保存", "settings_logoutEverywhereConfirm": "すべてのデバイスでログインが取り消されるため、今後利用する際にもう一度ログインするよう求められます。続行しますか?", "settings_logoutEverywhere": "他のすべてのウェブセッションからログアウトします", @@ -416,7 +416,7 @@ "fm_removePermanentlyDialog": "ドライブからこのアイテムを削除してよろしいですか?他のユーザーのドライブからは削除されません。", "fm_noname": "無題のドキュメント", "fm_openParent": "フォルダに表示", - "fm_newButtonTitle": "新しいドキュメントやフォルダを作成し、ファイルを現在のフォルダにインポートします。", + "fm_newButtonTitle": "新しいドキュメントやフォルダを作成して、現在のフォルダにインポートします。", "contacts_info4": "チャットの参加者のどちらも履歴を削除できます", "contacts_info2": "連絡先のアイコンをクリックしてチャットを開始", "contacts_confirmRemove": "{0}をあなたの連絡先から削除してよろしいですか?", @@ -440,7 +440,7 @@ "kanban_editCard": "このカードを編集", "kanban_clearFilter": "フィルターを消去", "kanban_tags": "タグでフィルタリング", - "allow_text": "アクセスリストを使用すると、選択したユーザーと所有者だけがこのドキュメントにアクセスできます。", + "allow_text": "アクセスリストを使用すると、選択したユーザーと所有者だけがドキュメントにアクセスできます。", "admin_defaultlimitTitle": "ストレージの制限(MB)", "owner_add": "{0}があなたをパッド {1} の所有者になるよう希望しています。 承諾しますか?", "owner_removeConfirm": "選択したユーザーの所有権を削除してよろしいですか? ユーザーには通知が送られます。", @@ -481,7 +481,7 @@ "upload_pending": "保留中", "settings_resetTips": "ヒント", "chrome68": "バージョン68のChromeあるいはChromiumを使用しているようです。このバージョンには、数秒経過した後でページが白紙になったり、クリックにページが反応しなくなったりするバグがあります。この問題を解決するには、別のタブを表示して改めて表示するか、このページでスクロールを試みてください。このバグは次のバージョンで解決される予定となっています。", - "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずにログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • ログインせずに作成したり共有したりしたファイルを保存するには、 「匿名セッションのデータをインポート」にチェックをしてください。
    ", + "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずにログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • 未ログインで作成、共有したファイルを保存するには、 「匿名セッションのデータをインポート」にチェックをしてください。
    ", "poll_commit": "送信", "admin_removeDonateButtonTitle": "クラウドファンディングに参加", "mediatag_notReady": "ダウンロードを完了してください", @@ -802,7 +802,7 @@ "settings_codeFontSize": "コードエディターのフォントの大きさ", "settings_anonymous": "ログインしていません。設定はこのブラウザのみで有効です。", "settings_deleted": "アカウントが削除されました。OKを押すとホームページに移動します。", - "settings_deleteHint": "アカウントの削除は取り消しできません。あなたのCryptDriveとパッドのリストはサーバーから削除されます。誰もCryptDriveに保存していないパッドは、90日で削除されます。", + "settings_deleteHint": "アカウントの削除は取り消せません。あなたのCryptDriveとパッドのリストはサーバーから削除されます。誰もCryptDriveに保存していないパッドは、90日で削除されます。", "settings_resetThumbnailsDone": "サムネイルが消去されました。", "settings_resetThumbnailsDescription": "ブラウザに保存したサムネイルを削除します。", "settings_disableThumbnailsDescription": "新しいパッドを開くと、サムネイルが自動で作成され、ブラウザに保存されます。ここでサムネイルの作成を無効にできます。", @@ -858,7 +858,7 @@ "crowdfunding_popup_text": "

    あなたの援助が必要です!

    CryptPadの開発が継続できるよう、OpenCollectiveのページからご支援いただきますようお願いします。ロードマップ資金調達の目標を同ページにて公開しています。", "autostore_notAvailable": "この機能を使うにはCryptDriveにパッドを保存する必要があります。", "autostore_forceSave": "CryptDriveにファイルを保存", - "autostore_saved": "パッドはCryptDriveに保存されました!", + "autostore_saved": "パッドをCryptDriveに保存しました!", "autostore_settings": "自動保存は設定ページで有効にできます!", "broadcast_end": "終了", "broadcast_start": "開始", @@ -937,7 +937,7 @@ "properties_passwordSame": "新しいパスワードは現在のパスワードと異なるものでなければなりません。", "four04_pageNotFound": "お探しのページが見つかりませんでした。", "about": "私たちについて", - "whatis_apps_info": "

    CryptPadは共同作業に必要なツールを備えた本格的なオフィススイートです。リッチテキスト、スプレッドシート、コード/マークダウン、カンバン、スライド、ホワイトボード、投票機能を有しています。

    それらのアプリケーションには、チャット、連絡先、著者別の色表示(コード/マークダウン)、コメント、メンション(リッチテキスト)などの機能が付属しています。

    ", + "whatis_apps_info": "

    CryptPadは共同作業に必要なツールを備えた本格的なオフィススイートです。リッチテキスト、スプレッドシート、コード/マークダウン、カンバン、スライド、ホワイトボード、投票機能があります。

    それらのアプリケーションには、チャット、連絡先、著者別の色表示(コード/マークダウン)、コメント、メンション(リッチテキスト)などの機能が付属しています。

    ", "mdToolbar_button": "マークダウンのツールバーを表示もしくは隠す", "pad_base64": "このパッドはサイズの大きい画像を含んでいます。パッドのサイズが大きいと、読み込みに時間がかかります。サイズを減らすために、画像のフォーマットを変換して、別の画像ファイルとしてCryptDriveに保存することができます。画像を変換してよろしいですか?", "todo_removeTaskTitle": "このタスクをリストから削除", @@ -953,8 +953,8 @@ "settings_exportCancel": "エクスポートをキャンセルしてよろしいでしょうか?次のエクスポートでは最初からやりなおす必要があります。", "fm_error_cantPin": "内部サーバーエラー。ページを再度読み込んでください。", "fm_info_anonymous": "ログインしていないため、ドキュメントは{0}日後に期限切れになります。また、ブラウザの履歴を消去するとファイルが消えてしまうかもしれません。
    ファイルを永続的に保存するには、登録するか(個人情報の登録は不要です)、ログインしてください。登録アカウントについては、こちらを参照してください(英語)。", - "fm_info_recent": "これらのパッドは、最近、あなたか共同作業者により開かれたか、もしくは編集されました。", - "fm_info_template": "新しいパッドを作成する際に利用できるテンプレートとして保存した全てのパッドを含みます。", + "fm_info_recent": "あなたか共同編集者が最近開いた、もしくは編集したパッドの一覧です。", + "fm_info_template": "テンプレートとして保存したパッドの一覧です。以下のテンプレートを使って、新しいパッドを作成することができます。", "fm_categoryError": "選択したカテゴリーが開けません。ルートを表示します。", "fm_morePads": "さらに表示", "oo_reconnect": "サーバーの接続が回復しました。OKをクリックして再読み込みし、編集を継続してください。", @@ -1040,7 +1040,7 @@ "settings_backup2Confirm": "あなたのCryptDriveの全てのパッドをダウンロードします。続けたい場合は、名前を入力してOKを押してください", "settings_backup2": "CryptDriveをダウンロード", "settings_backupHint2": "ドライブの全てのドキュメントをダウンロードします。ドキュメントは、他のアプリケーションで読み込めるフォーマットがあれば、そのフォーマットでダウンロードされます。そうしたフォーマットがなければ、CryptPadで読み込めるフォーマットでダウンロードされます。", - "settings_backupHint": "CryptDriveのコンテンツをバックアップ、あるいは復元します。パッドの内容ではなく、それにアクセスするための鍵だけを含みます。", + "settings_backupHint": "CryptDriveのコンテンツをバックアップもしくは復元します。バックアップには、パッドの内容ではなく、それにアクセスする鍵だけが含まれます。", "register_emailWarning3": "その点を踏まえてなおユーザー名にメールアドレスを使用する場合は、OKをクリックしてください。", "register_emailWarning1": "それもできますが、サーバーには送信されません。", "register_emailWarning0": "ユーザー名にメールアドレスが入力されています。", @@ -1122,15 +1122,15 @@ "upload_modal_filename": "ファイル名(拡張子 {0} を自動で追加)", "settings_padSpellcheckHint": "リッチテキストパッドでスペルチェックを有効にします。間違ったつづりには赤色の下線が表示されます。右クリックをしながらコントロールキーあるいはメタキーを押すと、正しい選択肢が表示されます。", "creation_404": "このパッドは存在しません。以下のフォームより新しいパッドを作成してください。", - "help_genericMore": "CryptPadの使用法についてはドキュメントをご覧ください。", - "whatis_drive": "CryptDriveを使用している組織", + "help_genericMore": "CryptPadの使い方についてはドキュメントをご覧ください。", + "whatis_drive": "CryptDriveでまとめて管理", "mdToolbar_toc": "目次", "mdToolbar_check": "タスクリスト", "mdToolbar_nlist": "番号付きリスト", "mdToolbar_heading": "見出し", "settings_cursorShowHint": "共同ドキュメントであなたが他のユーザーのカーソルの位置を見られるかどうかを決められます。", "settings_cursorShareHint": "共同ドキュメントで他のユーザーがあなたのカーソルの位置を見られるかどうかを決められます。", - "settings_cursorColorHint": "共同ドキュメントのユーザーと関連付けられた色を変更します。", + "settings_cursorColorHint": "共同ドキュメントでの他のユーザーの色を変更できます。", "settings_padWidthHint": "テキストエディターの幅を制限するページモード(既定)と、スクリーン全体の幅を使用するモードを切り替える。", "fm_forbidden": "禁止されたアクション", "team_exportHint": "チームのドライブの全てのドキュメントをダウンロードします。ドキュメントは、他のアプリケーションで読み込めるフォーマットがあれば、そのフォーマットでダウンロードされます。そうしたフォーマットがなければ、CryptPadで読み込めるフォーマットでダウンロードされます。", @@ -1252,5 +1252,18 @@ "owner_removeMeConfirm": "所有権を放棄しようとしています。これは取り消せません。よろしいですか?", "requestEdit_confirm": "{1}がパッド「{0}」の編集権を要求しました。編集権を与えますか?", "admin_supportInitHelp": "サーバーはサポートメールボックスを使用するように設定されていません。サポートメールボックスを有効にし、ユーザーからメッセージを受け取るためには、サーバーの管理者に連絡し、「./scripts/generate-admin-keys.js」のスクリプトを実行してもらい、生成された公開鍵を「config.js」に保存して、秘密鍵をあなたに送信してもらうよう依頼する必要があります。", - "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求して、ユーザーにとって重要なUI機能を特定するために使用されます。" + "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求して、ユーザーにとって重要なUI機能を特定するために使用されます。", + "register_warning_note": "暗号化を行うCryptPadの性質上、サービス管理者は、ユーザー名とパスワードを忘れた場合にデータを回復することができません。ユーザー名とパスワードを安全な場所に保管してください。", + "history_restoreDriveTitle": "選択したバージョンのCryptDriveを復元", + "errorPopupBlocked": "新しいタブを開く許可が必要です。お使いのブラウザのアドレスバーから、ポップアップウィンドウを許可してください。これらのウィンドウが広告の表示に使用されることはありません。", + "settings_colorthemeHint": "このデバイスでのテーマ色を変更できます。", + "settings_colortheme_default": "システムのデフォルト ({0})", + "settings_codeBrackets": "括弧の自動補完", + "creation_helperText": "ドキュメンテーションを開く", + "contacts_info1": "連絡先の一覧です。", + "share_noContactsLoggedIn": "連絡先がありません。プロフィールのリンクを共有して、連絡先のリクエストを送信してください。", + "settings_cat_security": "セキュリティー", + "whatis_collaboration_info": "

    CryptPadはコラボレーションを念頭に作られています。ドキュメントに加えられる変更は、リアルタイムで同期されます。全てのデータは暗号化されているため、サービスとその管理者が、編集され保存されているコンテンツを覗き見ることは不可能です。

    ", + "whatis_apps": "フルスイートアプリケーション", + "whatis_drive_info": "

    ドキュメントをCryptDriveに保存して管理できます。フォルダを作ったり共有したりできるほか、ドキュメントをタグ付けして整理することもできます。PDFファイル、写真、動画、音声などのファイルをアップロードして共有できます。チームのドライブを使うと、メンバーとデータを共有したり、ファイルの管理や、きめ細かいアクセス権のコントロールを行うことができます。

    " } From 8e725f3d7c46f6720a78c081097cecb1181277a0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 17:20:03 +0530 Subject: [PATCH 049/117] stop returning the hash of all user pins after pinning the client doesn't use it and it's CPU-intensive --- lib/commands/pin-rpc.js | 12 +++++------- www/common/outer/async-store.js | 12 ++++++------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index ff6bfdbac..af2c32c64 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -8,7 +8,7 @@ const nThen = require("nthen"); //const escapeKeyCharacters = Util.escapeKeyCharacters; const unescapeKeyCharacters = Util.unescapeKeyCharacters; -var sumChannelSizes = function (sizes) { +var sumChannelSizes = function (sizes) { // FIXME this synchronous code could be done by a worker return Object.keys(sizes).map(function (id) { return sizes[id]; }) .filter(function (x) { // only allow positive numbers @@ -171,7 +171,7 @@ Pinning.pinChannel = function (Env, safeKey, channels, cb) { getMultipleFileSize(Env, toStore, function (e, sizes) { if (typeof(sizes) === 'undefined') { return void cb(e); } - var pinSize = sumChannelSizes(sizes); + var pinSize = sumChannelSizes(sizes); // FIXME don't do this in the main thread... getFreeSpace(Env, safeKey, function (e, free) { if (typeof(free) === 'undefined') { @@ -186,7 +186,7 @@ Pinning.pinChannel = function (Env, safeKey, channels, cb) { toStore.forEach(function (channel) { session.channels[channel] = true; }); - getHash(Env, safeKey, cb); + cb(); }); }); }); @@ -217,7 +217,7 @@ Pinning.unpinChannel = function (Env, safeKey, channels, cb) { toStore.forEach(function (channel) { delete session.channels[channel]; }); - getHash(Env, safeKey, cb); + cb(); }); }); }; @@ -270,9 +270,7 @@ Pinning.resetUserPins = function (Env, safeKey, channelList, cb) { // update in-memory cache IFF the reset was allowed. session.channels = pins; - getHash(Env, safeKey, function (e, hash) { - cb(e, hash); - }); + cb(); }); }); }); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 66e1967cd..9f779a0a8 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -274,9 +274,9 @@ define([ } var pads = data.pads || data; - s.rpc.pin(pads, function (e, hash) { + s.rpc.pin(pads, function (e) { if (e) { return void cb({error: e}); } - cb({hash: hash}); + cb({}); }); }; @@ -289,9 +289,9 @@ define([ if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } var pads = data.pads || data; - s.rpc.unpin(pads, function (e, hash) { + s.rpc.unpin(pads, function (e) { if (e) { return void cb({error: e}); } - cb({hash: hash}); + cb({}); }); }; @@ -394,9 +394,9 @@ define([ if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } var list = getCanonicalChannelList(false); - store.rpc.reset(list, function (e, hash) { + store.rpc.reset(list, function (e) { if (e) { return void cb(e); } - cb(null, hash); + cb(null); }); }; From 76b90d3c8a8220aee0afd829d0eeaea081d248a6 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 17:55:01 +0530 Subject: [PATCH 050/117] correct a few more places where the client expected hashes in pin responses or where the server incorrectly provided them --- lib/commands/pin-rpc.js | 17 ++++++++--------- scripts/tests/test-rpc.js | 22 ++++++++++------------ www/common/pinpad.js | 35 ++++++++++------------------------- 3 files changed, 28 insertions(+), 46 deletions(-) diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index af2c32c64..6fc05c202 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -145,7 +145,7 @@ var getFreeSpace = Pinning.getFreeSpace = function (Env, safeKey, cb) { }); }; -var getHash = Pinning.getHash = function (Env, safeKey, cb) { +Pinning.getHash = function (Env, safeKey, cb) { getChannelList(Env, safeKey, function (channels) { Env.hashChannelList(channels, cb); }); @@ -166,7 +166,7 @@ Pinning.pinChannel = function (Env, safeKey, channels, cb) { }); if (toStore.length === 0) { - return void getHash(Env, safeKey, cb); + return void cb(); } getMultipleFileSize(Env, toStore, function (e, sizes) { @@ -208,7 +208,7 @@ Pinning.unpinChannel = function (Env, safeKey, channels, cb) { }); if (toStore.length === 0) { - return void getHash(Env, safeKey, cb); + return void cb(); } Env.pinStore.message(safeKey, JSON.stringify(['UNPIN', toStore, +new Date()]), @@ -222,15 +222,14 @@ Pinning.unpinChannel = function (Env, safeKey, channels, cb) { }); }; -Pinning.resetUserPins = function (Env, safeKey, channelList, cb) { +Pinning.resetUserPins = function (Env, safeKey, channelList, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); if (!Array.isArray(channelList)) { return void cb('INVALID_PIN_LIST'); } var session = Core.getSession(Env.Sessions, safeKey); - if (!channelList.length) { - return void getHash(Env, safeKey, function (e, hash) { - if (e) { return cb(e); } - cb(void 0, hash); - }); + + if (!channelList.length) { // XXX wut + return void cb(); } var pins = {}; diff --git a/scripts/tests/test-rpc.js b/scripts/tests/test-rpc.js index 0fd0abc37..b92cf6287 100644 --- a/scripts/tests/test-rpc.js +++ b/scripts/tests/test-rpc.js @@ -122,14 +122,11 @@ var createUser = function (config, cb) { }); })); }).nThen(function (w) { - user.rpc.reset([], w(function (err, hash) { + user.rpc.reset([], w(function (err) { if (err) { w.abort(); user.shutdown(); - return console.log("RESET_ERR"); - } - if (!hash || hash !== EMPTY_ARRAY_HASH) { - throw new Error("EXPECTED EMPTY ARRAY HASH"); + return console.log("TEST_RESET_ERR"); } })); }).nThen(function (w) { @@ -214,17 +211,17 @@ var createUser = function (config, cb) { // TODO check your quota usage }).nThen(function (w) { - user.rpc.unpin([user.mailboxChannel], w(function (err, hash) { + user.rpc.unpin([user.mailboxChannel], w(function (err) { if (err) { w.abort(); return void cb(err); } + })); + }).nThen(function (w) { + user.rpc.getServerHash(w(function (err, hash) { + console.log(hash); - if (hash[0] !== EMPTY_ARRAY_HASH) { - //console.log('UNPIN_RESPONSE', hash); - throw new Error("UNPIN_DIDNT_WORK"); - } - user.latestPinHash = hash[0]; + user.latestPinHash = hash; })); }).nThen(function (w) { // clean up the pin list to avoid lots of accounts on the server @@ -304,7 +301,8 @@ nThen(function (w) { }, w(function (err, roster) { if (err) { w.abort(); - return void console.trace(err); + console.error(err); + return void console.error("ROSTER_ERROR"); } oscar.roster = roster; oscar.destroy.reg(function () { diff --git a/www/common/pinpad.js b/www/common/pinpad.js index 7e9cd4ee2..de93f066f 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -26,23 +26,19 @@ var factory = function (Util, Rpc) { exp.send = rpc.send; // you can ask the server to pin a particular channel for you - exp.pin = function (channels, cb) { + exp.pin = function (channels, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); if (!Array.isArray(channels)) { - setTimeout(function () { - cb('[TypeError] pin expects an array'); - }); - return; + return void cb('[TypeError] pin expects an array'); } rpc.send('PIN', channels, cb); }; // you can also ask to unpin a particular channel - exp.unpin = function (channels, cb) { + exp.unpin = function (channels, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); if (!Array.isArray(channels)) { - setTimeout(function () { - cb('[TypeError] pin expects an array'); - }); - return; + return void cb('[TypeError] pin expects an array'); } rpc.send('UNPIN', channels, cb); }; @@ -70,23 +66,12 @@ var factory = function (Util, Rpc) { }; // if local and remote hashes don't match, send a reset - exp.reset = function (channels, cb) { + exp.reset = function (channels, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); if (!Array.isArray(channels)) { - setTimeout(function () { - cb('[TypeError] pin expects an array'); - }); - return; + return void cb('[TypeError] pin expects an array'); } - rpc.send('RESET', channels, function (e, response) { - if (e) { - return void cb(e); - } - if (!response.length) { - console.log(response); - return void cb('INVALID_RESPONSE'); - } - cb(e, response[0]); - }); + rpc.send('RESET', channels, cb); }; // get the combined size of all channels (in bytes) for all the From e57ccf14d70dcbabd15e8d4944c1c6787765e747 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 18:20:57 +0530 Subject: [PATCH 051/117] clean up some pending notes --- www/admin/inner.js | 3 +-- www/convert/inner.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/www/admin/inner.js b/www/admin/inner.js index 13f96cdf7..263f9a9bc 100644 --- a/www/admin/inner.js +++ b/www/admin/inner.js @@ -94,7 +94,7 @@ define([ 'cp-admin-list-my-instance', 'cp-admin-consent-to-contact', 'cp-admin-remove-donate-button', - 'cp-admin-instance-purpose', // XXX + 'cp-admin-instance-purpose', ], }; @@ -1902,7 +1902,6 @@ define([ [ value] ], cb); }; - //var spinner = UI.makeSpinner($br); // XXX $opts.on('change', function () { var val = $opts.find('input:radio:checked').val(); diff --git a/www/convert/inner.js b/www/convert/inner.js index d8eca9af2..4952b2d6e 100644 --- a/www/convert/inner.js +++ b/www/convert/inner.js @@ -194,7 +194,7 @@ define([ }; Messages.convertPage = "Convert"; // XXX - Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; + Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterward."; // XXX var createToolbar = function () { var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle', 'notifications']; From 73a47986a71018831e9b01c47293195640307e26 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 15:26:55 +0200 Subject: [PATCH 052/117] Translated using Weblate (German) Currently translated at 99.9% (1365 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ Translated using Weblate (German) Currently translated at 99.8% (1364 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index ee2be161b..bc4ae8952 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1356,5 +1356,14 @@ "form_poll_hint": ": Ja, : Nein, : Akzeptabel", "fc_open_formro": "Öffnen (als Teilnehmer)", "resources_openInNewTab": "In neuem Tab öffnen", - "resources_imageBlocked": "CryptPad hat ein externes Bild blockiert" + "resources_imageBlocked": "CryptPad hat ein externes Bild blockiert", + "admin_purpose_noanswer": "Möchte ich nicht sagen", + "admin_purpose_business": "Für ein Unternehmen oder eine kommerzielle Organisation", + "admin_purpose_education": "Für eine Schule, Hochschule oder Universität", + "admin_purpose_org": "Für eine gemeinnützige Organisation oder eine Interessengruppe", + "admin_purpose_personal": "Für mich selbst, Familie oder Freunde", + "admin_purpose_experiment": "Zum Testen der Plattform oder zur Entwicklung neuer Funktionen", + "admin_instancePurposeTitle": "Zweck der Instanz", + "admin_instancePurposeHint": "Warum betreibst du diese Instanz? Deine Antwort wird mit den Entwicklern geteilt, sofern die Telemetrie aktiviert ist.", + "admin_purpose_public": "Zur Bereitstellung eines kostenlosen Dienstes für die Allgemeinheit" } From cbbff49f8935386fb9674d3670f48e48d75c4e96 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 15:26:56 +0200 Subject: [PATCH 053/117] Translated using Weblate (Japanese) Currently translated at 93.2% (1274 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.2% (1274 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.2% (1274 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.2% (1274 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.1% (1273 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.1% (1272 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.0% (1271 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.0% (1271 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.0% (1271 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.9% (1270 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.9% (1270 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.9% (1270 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.8% (1269 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.8% (1269 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.8% (1269 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.8% (1268 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.7% (1267 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.7% (1267 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.7% (1267 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.6% (1266 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 92.5% (1264 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 78 +++++++++++++----------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index f8d52b8c6..199ecd76a 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -20,7 +20,7 @@ "poll": "投票", "code": "コード", "pad": "リッチテキスト", - "sheet": "シート", + "sheet": "スプレッドシート", "form": "フォーム" }, "main_title": "CryptPad - 安全にリアルタイム編集可能なコラボレーションツール", @@ -62,7 +62,7 @@ "fm_fileName": "ファイル名", "crowdfunding_button2": "CryptPadを支援", "fm_padIsOwned": "あなたはこのパッドの所有者です", - "creation_expiration": "有効期限", + "creation_expiration": "有効期限を設定", "owner_removeText": "所有者", "creation_owners": "所有者", "download_mt_button": "ダウンロード", @@ -101,7 +101,7 @@ "settings_changePasswordNew": "新しいパスワード", "settings_changePasswordCurrent": "現在のパスワード", "settings_changePasswordButton": "パスワードを変更", - "settings_changePasswordHint": "アカウントのパスワードを変更します。「現在のパスワード」と、「新しいパスワード」および「新しいパスワードの確認」を入力してください。
    パスワードを忘れた場合、パスワードをリセットする方法はありません。細心の注意を払って、パスワードを安全に管理してください。", + "settings_changePasswordHint": "アカウントのパスワードを変更します。「現在のパスワード」と、「新しいパスワード」および「新しいパスワードの確認」を入力してください。
    パスワードを忘れた場合、再設定する方法はありません。細心の注意を払って、パスワードを安全に管理してください。", "settings_changePasswordTitle": "パスワードの変更", "languageButton": "言語", "language": "言語", @@ -131,8 +131,8 @@ "tos_availability": "私たちはこのサービスがあなたの役に立つことを願っていますが、可用性や性能は保証できません。定期的にデータをエクスポートしてください。", "tos_legal": "悪意ある行為、乱用する行為、または何らかの違法な行為を行わないでください。", "tos_title": "CryptPad サービス利用規約", - "whatis_title": "CryptPad とは?", - "topbar_whatIsCryptpad": "CryptPad とは何か", + "whatis_title": "CryptPadとは?", + "topbar_whatIsCryptpad": "CryptPadとは何か", "footer_tos": "利用規約", "footer_donate": "寄付", "footer_legal": "法的情報", @@ -229,16 +229,16 @@ "notifications_dismiss": "確認済みにする", "settings_autostoreMaybe": "手動 (確認しない)", "settings_autostoreNo": "手動 (常に確認する)", - "settings_autostoreHint": "自動 あなたがアクセスしたすべてのパッドを、あなたの CryptDrive に保存します。
    手動 (常に確認する) まだ保存していないパッドにアクセスした場合に、あなたの CryptDrive に保存するかどうか尋ねます。
    手動 (確認しない) アクセス先のパッドがあなたの CryptDrive に自動的に保存されなくなります。保存オプションは表示されなくなります。", + "settings_autostoreHint": "自動 アクセスしたすべてのパッドをCryptDriveに保存します。
    手動(常に確認) 保存していないパッドにアクセスした際、CryptDriveに保存するかどうかを確認します。
    手動(確認しない) アクセス先のパッドはCryptDriveに自動で保存されません。保存オプションは表示されません。", "settings_userFeedback": "ユーザーフィードバックを有効にする", "settings_userFeedbackHint2": "あなたのパッドのコンテンツがサーバーと共有されることはありません。", - "settings_userFeedbackHint1": "CryptPad は、ユーザーエクスペリエンスの向上のため、サーバーにいくつかの非常に基本的なフィードバックを提供します。 ", + "settings_userFeedbackHint1": "CryptPadは、ユーザーエクスペリエンスの向上のため、いくつかの非常に基本的なフィードバックを、サーバーに提供します。 ", "settings_userFeedbackTitle": "フィードバック", "settings_autostoreYes": "自動", - "settings_importConfirm": "このブラウザで最近使用したパッドを、あなたのユーザーアカウントの CryptDrive にインポートしますか?", + "settings_importConfirm": "このブラウザで最近使用したパッドを、あなたのユーザーアカウントのCryptDriveにインポートしますか?", "settings_importDone": "インポートが完了しました", "settings_import": "インポート", - "settings_importTitle": "このブラウザでの最近のパッドをあなたの CryptDrive にインポートします", + "settings_importTitle": "このブラウザでの最近のパッドをあなたのCryptDriveにインポートします", "settings_trimHistoryHint": "ドライブと通知の履歴を削除して、ストレージ容量を節約します。これはパッドの履歴には影響しません。パッドの履歴は、プロパティダイアログから削除できます。", "trimHistory_currentSize": "現在の履歴容量: {0}", "support_cat_other": "その他", @@ -263,13 +263,13 @@ "features_f_devices_note": "ユーザーアカウントでどこからでも CryptDrive にアクセスできます", "features_f_devices": "全てのデバイスであなたのパッドを利用", "features_f_cryptdrive1_note": "フォルダ、共有フォルダ、テンプレート、タグ", - "features_f_cryptdrive1": "CryptDrive への完全なアクセス", + "features_f_cryptdrive1": "CryptDriveの全機能", "features_f_anon_note": "追加機能あり", "features_f_anon": "匿名ユーザーの全機能", "features_f_storage0_note": "ドキュメントは{0}日以上使用されないと削除されます", "features_f_storage0": "一時的な保存", "features_f_cryptdrive0_note": "後で開けるようにブラウザにアクセスしたパッドを保存する機能", - "features_f_cryptdrive0": "CryptDrive への限定的なアクセス", + "features_f_cryptdrive0": "CryptDriveへの限定的なアクセス", "features_f_file0_note": "他のユーザーが共有したドキュメントを表示およびダウンロードできます", "features_f_file0": "ドキュメントを開く", "features_f_core_note": "編集、インポートとエクスポート、履歴、ユーザーリスト、チャット", @@ -288,11 +288,11 @@ "okButton": "OK (enter)", "mustLogin": "このページにアクセスするにはログインする必要があります", "fm_noResult": "見つかりませんでした", - "fm_info_trash": "ごみ箱を空にすると、あなたの CryptDrive の使用可能容量を増やせます。", + "fm_info_trash": "ごみ箱を空にするとCryptDriveの使用可能容量を増やせます。", "features_f_file1": "ファイルのアップロードと共有", "features_f_social_note": "追加した連絡先との安全なコラボレーション、プロフィールの作成、きめ細かいアクセス権のコントロール", "features_f_social": "ソーシャル機能", - "tos_e2ee": "CryptPad のコンテンツは、パッドのフラグメント識別子を推測または取得できる人物なら誰でも閲覧や編集が行えます。エンドツーエンド暗号化(E2EE)を採用したメッセンジャーサービスなどを使用してリンクを共有し、リンク漏洩が発生しないよう対策を行ってください。", + "tos_e2ee": "CryptPadのコンテンツは、パッドのフラグメント識別子を推測または取得できる人物なら誰でも閲覧や編集が行えます。エンドツーエンド暗号化(E2EE)を採用したメッセンジャーサービスなどを使用してリンクを共有し、リンクの漏洩が発生しないよう対策を行ってください。リンクが漏洩した際に、責任を負うことはできません。", "contact_chat": "チャット", "contact_bug": "バグの報告", "footer_product": "製品", @@ -329,7 +329,7 @@ "password_info": "開こうとしているドキュメントが存在しないか、新しいパスワードで保護されています。コンテンツにアクセスするには、正しいパスワードを入力してください。", "properties_confirmNew": "パスワードを追加すると、このパッドの URL が変更され、履歴が削除されます。パスワードを知らないユーザーは、このパッドへアクセスできなくなります。続行してよろしいですか?", "properties_changePassword": "パスワードの変更", - "properties_addPassword": "パスワードの追加", + "properties_addPassword": "パスワードを設定", "history_close": "閉じる", "history_restore": "復元", "fm_emptyTrashOwned": "ごみ箱に、あなたが所有しているドキュメントが入っています。あなたのドライブからのみ削除するか、すべてのユーザーから完全削除するかを選択できます。", @@ -342,7 +342,7 @@ "settings_safeLinksCheckbox": "セーフリンクを有効にする", "settings_safeLinksTitle": "セーフリンク", "settings_safeLinksHint": "CryptPadでは、リンクの中にパッドを解読するための鍵が含まれています。ブラウザの閲覧履歴にアクセスできる人は、誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューを使用することを強く推奨します。", - "settings_autostoreTitle": "CryptDrive へのパッドの保存", + "settings_autostoreTitle": "CryptDriveへのパッドの保存", "settings_logoutEverywhereConfirm": "すべてのデバイスでログインが取り消されるため、今後利用する際にもう一度ログインするよう求められます。続行しますか?", "settings_logoutEverywhere": "他のすべてのウェブセッションからログアウトします", "settings_logoutEverywhereTitle": "リモートセッションを閉じる", @@ -369,8 +369,8 @@ "snapshots_new": "新規スナップショット", "snaphot_title": "スナップショット", "snapshots_button": "スナップショット", - "filePicker_description": "埋め込むファイルを CryptDrive から選択するか、新規にアップロードしてください", - "uploadButtonTitle": "CryptDrive に新規ファイルをアップロード", + "filePicker_description": "埋め込むファイルをCryptDriveから選択するか、新規にアップロードしてください", + "uploadButtonTitle": "CryptDriveに新規ファイルをアップロード", "uploadFolderButton": "フォルダをアップロード", "uploadButton": "ファイルをアップロード", "filePicker_filter": "ファイル名で検索", @@ -387,10 +387,10 @@ "whatis_model": "ビジネスモデル", "whatis_collaboration": "プライベートコラボレーション", "home_support_title": "CryptPad を支援する", - "home_opensource": "CryptPad は、個人やプロなど誰でもホストすることができます。ソースコードは GitHub で確認できます。", + "home_opensource": "誰でもCryptPadを運営し、個人的または専門的な仕方でサービスを提供することができます。ソースコードはGitHubで確認できます。", "home_opensource_title": "オープンソース", "home_host_title": "このインスタンスについて", - "home_privacy_text": "CryptPad は、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。すべてのコンテンツは、あなたのブラウザ上で暗号化および復号化されます。つまり、ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービス管理者でさえ、あなたの情報にアクセスすることはできません。", + "home_privacy_text": "CryptPadは、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。すべてのコンテンツは、あなたのブラウザ上で暗号化および復号化されます。ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービスの管理者でも、あなたの情報にアクセスすることはできません。", "home_privacy_title": "プライバシー・バイ・デザイン", "mdToolbar_tutorial": "https://www.markdowntutorial.com/jp/", "languageButtonTitle": "シンタックスハイライトを行う言語を選択してください", @@ -399,10 +399,10 @@ "poll_descriptionHint": "投票の詳細を記入してください。入力が終了したら✓(公開)ボタンをクリックしてください。\n詳細はマークダウンの構文で記入できます。CryptDriveのメディアファイルを埋め込むこともできます。\nリンクを知っているひとは誰でも詳細を変更できますが、推奨されません。", "pad_mediatagBorder": "枠線の幅(ピクセル)", "openLinkInNewTab": "新しいタブでリンクを開く", - "history_restorePrompt": "ドキュメントの現在のバージョンを、表示しているバージョンと置き換えてよろしいですか?", + "history_restorePrompt": "ドキュメントの現在のバージョンを、表示しているバージョンに置き換えてよろしいですか?", "slideOptionsTitle": "スライドをカスタマイズ", "propertiesButtonTitle": "パッドのプロパティを表示", - "driveOfflineError": "CryptPadへの接続が切れています。このパッドに加えられる変更はCryptDriveに保存されません。CryptPadの全てのタブを閉じて、新しいウィンドウで開いてみてください。 ", + "driveOfflineError": "CryptPadへの接続が切断されています。このパッドに加えられる変更はCryptDriveに保存されません。CryptPadの全てのタブを閉じて、新しいウィンドウで開いてみてください。 ", "properties_passwordWarningFile": "パスワードは変更されましたが、新しいデータでCryptDriveを更新することができませんでした。古いバージョンのファイルを手動で削除する必要があるかもしれません。", "properties_confirmNewFile": "よろしいですか?パスワードを追加するとファイルのURLが変わります。パスワードをもたないユーザーは、このファイルにアクセスできなくなります。", "properties_confirmChangeFile": "よろしいですか?新しいパスワードをもたないユーザーは、このファイルにアクセスできなくなります。", @@ -416,7 +416,7 @@ "fm_removePermanentlyDialog": "ドライブからこのアイテムを削除してよろしいですか?他のユーザーのドライブからは削除されません。", "fm_noname": "無題のドキュメント", "fm_openParent": "フォルダに表示", - "fm_newButtonTitle": "新しいドキュメントやフォルダを作成して、現在のフォルダにインポートします。", + "fm_newButtonTitle": "新しいドキュメントやフォルダを作成したり、ファイルを現在のフォルダにインポートしたりできます。", "contacts_info4": "チャットの参加者のどちらも履歴を削除できます", "contacts_info2": "連絡先のアイコンをクリックしてチャットを開始", "contacts_confirmRemove": "{0}をあなたの連絡先から削除してよろしいですか?", @@ -426,7 +426,7 @@ "viewShare": "読み込み専用のリンク", "mediatag_loadButton": "添付ファイルを読み込む", "settings_disableThumbnailsAction": "CryptDriveでのサムネイルの作成を無効にする", - "settings_resetError": "入力したテキストが正しくありません。CryptDriveのデータは消去されていません。", + "settings_resetError": "入力した確認文が正しくありません。CryptDriveのデータは消去されていません。", "settings_resetDone": "データが消去されました!", "settings_resetPrompt": "あなたのドライブから全てのパッドを削除します。
    本当に続けてよろしいですか?
    続けるには「I love CryptPad」と入力してください。", "settings_reset": "CryptDriveの全てのファイルとフォルダを削除", @@ -719,7 +719,7 @@ "imprint": "法定通知", "oo_exportInProgress": "エクスポート中です", "notifyJoined": "{0}が共同セッションに参加しました", - "viewEmbedTag": "パッドを埋め込むには、このiframeを任意の箇所に含めてください。CSSまたはHTMLの属性を使って装飾できます。", + "viewEmbedTag": "パッドを埋め込むには、以下のiframeを任意の箇所に含めてください。CSSまたはHTMLの属性を使って装飾できます。", "slideOptionsText": "オプション", "tags_noentry": "削除したパッドにはタグ付けできません!", "tags_duplicate": "重複タグ: {0}", @@ -774,7 +774,7 @@ "inactiveError": "このパッドは使用されていなかったため削除されました。Escキーを押して新しいパッドを作成します。", "deletedError": "このパッドは所有者によって削除されたため、使用できなくなりました。", "expiredError": "このパッドは使用期限が過ぎてしまったため、使用できなくなりました。", - "anonymousStoreDisabled": "このCryptPadのインスタンスの管理者は、匿名ユーザーの保存を無効にしています。CryptDriveを使用するにはログインする必要があります。", + "anonymousStoreDisabled": "このCryptPadのインスタンスの管理者は、匿名ユーザーによる保存を無効に設定しています。CryptDriveを使用するにはログインする必要があります。", "padNotPinnedVariable": "このパッドは{4}日使用しないと期限切れになります。{0}ログイン{1}または{2}登録{3}し保存してください。", "padNotPinned": "このパッドは3ヶ月間使用しないと有効期限が切れます。{0}ログイン{1}するか{2}登録{3}して保存してください。", "onLogout": "ログアウトしました。{0}ここをクリック{1}するか
    Escapeキーを押すと、閲覧モードでパッドにアクセスできます。", @@ -782,8 +782,8 @@ "form_type_page": "ページ分割", "form_description_default": "ここにテキストを入力", "team_pcsSelectHelp": "所有するパッドをチームのドライブに作成すると、そのパッドの所有権はチームに与えられます。", - "sharedFolders_create_owned": "所有するフォルダ", - "creation_owned1": "所有されている項目は、所有者が任意で完全削除できます。完全削除すると、他のユーザーのCryptDriveでも利用できなくなります。", + "sharedFolders_create_owned": "フォルダを所有する", + "creation_owned1": "所有している項目は、所有者が望むときにいつでも完全削除できます。完全削除すると、他のユーザーのCryptDriveからも削除されます。", "creation_owned": "所有するパッド", "uploadFolder_modal_owner": "所有するファイル", "upload_modal_owner": "所有するファイル", @@ -806,7 +806,7 @@ "settings_resetThumbnailsDone": "サムネイルが消去されました。", "settings_resetThumbnailsDescription": "ブラウザに保存したサムネイルを削除します。", "settings_disableThumbnailsDescription": "新しいパッドを開くと、サムネイルが自動で作成され、ブラウザに保存されます。ここでサムネイルの作成を無効にできます。", - "fm_info_root": "ファイルを並べ替えるのに必要な数のネストされたフォルダーをここに作成できます。", + "fm_info_root": "フォルダを作成してファイルを整理できます。", "oo_conversionSupport": "お使いのブラウザはMicrosoft Officeのフォーマットの変換に対応していません。FirefoxもしくはChromeの最新バージョンの使用を推奨します。", "register_registrationIsClosed": "登録は締め切りました。", "settings_notifCalendarHint": "今後のカレンダーのイベントのすべての通知を有効もしくは無効にします。", @@ -1109,7 +1109,7 @@ "admin_diskUsageButton": "レポートを生成", "admin_diskUsageTitle": "ディスクの使用状況", "contact_adminHint": "アカウントに関連した問題、ストレージの制限、サービスの運用状況に関して。\n", - "contact_devHint": "機能のリクエスト、ユーザビリティの改善、あるいはお礼を言う場合。", + "contact_devHint": "機能のリクエスト、ユーザビリティの改善、あるいはお礼については、以下よりお願いします。", "contact_dev": "開発者に連絡", "contact_admin": "管理者に連絡", "admin_flushCacheDone": "キャッシュを消去しました", @@ -1122,7 +1122,7 @@ "upload_modal_filename": "ファイル名(拡張子 {0} を自動で追加)", "settings_padSpellcheckHint": "リッチテキストパッドでスペルチェックを有効にします。間違ったつづりには赤色の下線が表示されます。右クリックをしながらコントロールキーあるいはメタキーを押すと、正しい選択肢が表示されます。", "creation_404": "このパッドは存在しません。以下のフォームより新しいパッドを作成してください。", - "help_genericMore": "CryptPadの使い方についてはドキュメントをご覧ください。", + "help_genericMore": "CryptPadの使い方についてはドキュメンテーションをご覧ください。", "whatis_drive": "CryptDriveでまとめて管理", "mdToolbar_toc": "目次", "mdToolbar_check": "タスクリスト", @@ -1145,7 +1145,7 @@ "fc_noAction": "利用可能なアクションはありません", "support_closed": "このチケットは終了しました", "support_cat_tickets": "既存のチケット", - "support_formHint": "このフォームから、管理者に問題の報告や質問を安全に行うことができます。
    それらに関しては CryptPad ユーザーガイドで回答されているものがあるかもしれません。既にチケットを作成している場合、同じ問題に関して新しいチケットを作成するのはお控えください。その代わりに、既存のチケットに追加の情報を送信してください。", + "support_formHint": "このフォームから、管理者に問題の報告や質問を安全に行うことができます。
    それらに関しては CryptPadユーザーガイドで回答されているものがあるかもしれません。既にチケットを作成している場合、同じ問題に関して新しいチケットを作成するのはお控えください。その代わりに、既存のチケットに追加の情報を送信してください。", "support_disabledTitle": "サポートは有効になっていません", "admin_supportListHint": "ユーザーからサポートのメールボックスに送信されたチケットの一覧です。管理者はメッセージと回答を閲覧できます。終了したチケットは再開することができます。終了したチケットについては削除する(隠す)ことができますが、他の管理者には引き続き表示されます。", "drive_sfPassword": "共有フォルダ「 {0} 」は利用できません。所有者により削除されたか、新しいパスワードにより保護されています。CryptDriveから削除するか、新しいパスワードを使ってアクセスを回復できます。", @@ -1155,7 +1155,7 @@ "sharedFolders_share": "このリンクを登録ユーザーと共有すると、共有フォルダへのアクセスが可能になります。相手がリンクを開くと、CryptDriveに共有フォルダが追加されます。", "sharedFolders_duplicate": "移動しようとしているパッドのいくつかは既に移動先のフォルダに存在しています。", "sharedFolders_forget": "このパッドは共有フォルダにのみ保存されているため、ゴミ箱に移動できません。あなたのCryptDriveから削除することは可能です。", - "settings_ownDriveHint": "技術上の理由で、旧アカウントは最新の機能にアクセスできません。フリーのアップデートで新しい機能が有効になり、今後のアップデートにも対応します。", + "settings_ownDriveHint": "技術上の理由で、旧アカウントは最新の機能にアクセスできません。フリーのアップデートで新しい機能が有効になり、CryptDriveの今後のアップデートにも対応します。", "admin_activePadsHint": "閲覧もしくは編集中のドキュメント数", "admin_activePadsTitle": "アクティブなパッド", "admin_activeSessionsTitle": "アクティブな接続", @@ -1252,7 +1252,7 @@ "owner_removeMeConfirm": "所有権を放棄しようとしています。これは取り消せません。よろしいですか?", "requestEdit_confirm": "{1}がパッド「{0}」の編集権を要求しました。編集権を与えますか?", "admin_supportInitHelp": "サーバーはサポートメールボックスを使用するように設定されていません。サポートメールボックスを有効にし、ユーザーからメッセージを受け取るためには、サーバーの管理者に連絡し、「./scripts/generate-admin-keys.js」のスクリプトを実行してもらい、生成された公開鍵を「config.js」に保存して、秘密鍵をあなたに送信してもらうよう依頼する必要があります。", - "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求して、ユーザーにとって重要なUI機能を特定するために使用されます。", + "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求され、ユーザーにとって重要なUI機能を特定するために使用されます。", "register_warning_note": "暗号化を行うCryptPadの性質上、サービス管理者は、ユーザー名とパスワードを忘れた場合にデータを回復することができません。ユーザー名とパスワードを安全な場所に保管してください。", "history_restoreDriveTitle": "選択したバージョンのCryptDriveを復元", "errorPopupBlocked": "新しいタブを開く許可が必要です。お使いのブラウザのアドレスバーから、ポップアップウィンドウを許可してください。これらのウィンドウが広告の表示に使用されることはありません。", @@ -1265,5 +1265,15 @@ "settings_cat_security": "セキュリティー", "whatis_collaboration_info": "

    CryptPadはコラボレーションを念頭に作られています。ドキュメントに加えられる変更は、リアルタイムで同期されます。全てのデータは暗号化されているため、サービスとその管理者が、編集され保存されているコンテンツを覗き見ることは不可能です。

    ", "whatis_apps": "フルスイートアプリケーション", - "whatis_drive_info": "

    ドキュメントをCryptDriveに保存して管理できます。フォルダを作ったり共有したりできるほか、ドキュメントをタグ付けして整理することもできます。PDFファイル、写真、動画、音声などのファイルをアップロードして共有できます。チームのドライブを使うと、メンバーとデータを共有したり、ファイルの管理や、きめ細かいアクセス権のコントロールを行うことができます。

    " + "whatis_drive_info": "

    ドキュメントをCryptDriveに保存して管理できます。フォルダを作ったり共有したりできるほか、ドキュメントをタグ付けして整理することもできます。PDFファイル、写真、動画、音声などのファイルをアップロードして共有できます。チームのドライブを使うと、メンバーとデータを共有したり、ファイルの管理や、きめ細かいアクセス権のコントロールを行うことができます。

    ", + "whatis_model_info": "

    CryptPadは2016年より、寄付金とcryptpad.frの定額利用のほか、BPIフランス、NLNet財団、NGI Trust、Mozillaオープンソースサポートといったフランス、EUの研究助成を受けています。私たちは、公的資金で作られたソフトウェアについては、コードも公的に公開されるべきであると考えているため、サービスは全てオープンソースで提供しています。誰でも自由にこのソフトウェアを使ったり、運営したり、改変したりすることができます。

    CryptPadは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    私たちは、CryptPadのサービスを無料で提供しています。それは、金銭的に余裕のある人々だけでなく、誰もがプライバシーを得るに値すると確信しているからです。もしあなたがこのプロジェクトを支援できる状況にあるなら、機能の開発や、改良、メンテナンスに参加していただきたく考えます。そうすることで、全てのユーザーに利益をもたらされるはずです。

    このプロジェクトが実行可能であることが明らかになったいま、次のゴールは、ユーザーによる支援を通じて、プロジェクトを持続可能なものにすることにあります。CryptPadが、巨大プラットフォームに代わる持続可能なサービスを開発できるよう支援していただけるなら、一度もしくは継続的な寄付へのご協力をお願いいたします。

    ", + "whatis_xwiki_info": "

    CryptPadはフランス、パリに所在する会社であるXWikiにて開発されています。当社はオープンソース・ソフトウェアを15年以上にわたって開発しており、情報管理のための共同作業ソフトウェアの開発に関して豊富な経験をもっています。当社の実績は、私たちがCryptPadの長期的な開発と維持にコミットしていることを示しています。

    ", + "whatis_xwiki": "XWikiにて開発", + "history_restoreDrivePrompt": "CryptDriveの現在のバージョンを、表示されているバージョンに置き換えてよろしいですか?", + "owner_text": "パッドの所有者は、所有者の追加や削除、リストによるアクセス制限のほか、パッドの削除を行うことができます。", + "share_linkWarning": "このリンクは、ドキュメントを暗号化したり復号化したりする鍵を含んでいます。リンクを受け取った相手は、誰でも(ここにはコンピュータープログラムも含まれます)コンテンツにアクセスすることができます。", + "creation_expiresIn": "有効期限", + "settings_mediatagSizeHint": "ドキュメントに埋め込まれたメディア要素(画像、ビデオ、PDF)を自動で読み込む最大のサイズをメガバイト(MB)で指定してください。指定したサイズより大きい要素については、手動で読み込む必要があります。「-1」を設定すると、メディア要素は常に自動的に読み込まれます。", + "settings_mediatagSizeTitle": "自動ダウンロードの制限", + "settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザ上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティ上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去して、デバイスの空き容量を確保することもできます。" } From f2f9ace7c63ae7403a7e79c18a14f65828fd7c72 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 18:53:32 +0530 Subject: [PATCH 054/117] fix rendering issue with markdown media-tag format --- www/common/diffMarked.js | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 1919f0670..d7c476a90 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -287,9 +287,28 @@ define([ } }; + var isLocalURL = function (href) { + // treat all URLs as remote if you are using an ancient browser + if (typeof(window.URL) === 'undefined') { return false; } + try { + var url = new URL(href, ApiConfig.httpUnsafeOrigin); + var localURL = new URL(ApiConfig.httpUnsafeOrigin); + return url.host === localURL.host; + } catch (err) { + return true; + } + }; + renderer.image = function (href, title, text) { - if (href.slice(0,6) === '/file/') { // FIXME this has been deprecated for about 3 years. Maybe we should display a warning? - // DEPRECATED + if (isLocalURL(href) && href.slice(0, 6) !== '/file/') { + return h('img', { + src: href, + title: title || '', + alt: text, + }).outerHTML; + } + + if (href.slice(0,6) === '/file/') { // Mediatag using markdown syntax should not be used anymore so they don't support // password-protected files console.log('DEPRECATED: mediatag using markdown syntax!'); @@ -297,12 +316,11 @@ define([ var secret = Hash.getSecrets('file', parsed.hash); var src = (ApiConfig.fileHost || '') +Hash.getBlobPathFromHex(secret.channel); var key = Hash.encodeBase64(secret.keys.cryptKey); - var mt = ''; - if (mediaMap[src]) { - mt += mediaMap[src]; - } - mt += ''; - return mt; + var mt = h('media-tag', { + src: src, + 'data-crypto-key': 'cryptpad:' + key, + }); + return mt.outerHTML; } var warning = h('div.cp-inline-img-warning', [ @@ -323,7 +341,7 @@ define([ ]), h('br'), h('a.cp-learn-more', { - href: 'https://docs.cryptpad.fr/user_guide/security.html#remote-content', // XXX make sure this exists + href: 'https://docs.cryptpad.fr/user_guide/security.html#remote-content', }, [ Messages.resources_learnWhy ]), From d27cbb69dc3686dd17680229d61f198bde7edefd Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 19:05:37 +0530 Subject: [PATCH 055/117] filter email and instance purpose from telemetry unless we have consent --- lib/stats.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/stats.js b/lib/stats.js index 2a513da44..1dbbb2ad9 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -12,10 +12,10 @@ Stats.instanceData = function (Env) { httpUnsafeOrigin: Env.httpUnsafeOrigin, httpSafeOrigin: Env.httpSafeOrigin, - adminEmail: Env.adminEmail, + adminEmail: Env.consentToContact? Env.adminEmail: undefined, consentToContact: Boolean(Env.consentToContact), - instancePurpose: Env.instancePurpose, // XXX + instancePurpose: Env.instancePurpose === 'noanswer'? undefined: Env.instancePurpose, }; /* We reserve the right to choose not to include instances From f7f2146fa53e94be742f607a4a089e1c2874f1e0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 19:09:53 +0530 Subject: [PATCH 056/117] miscellaneous cleanup and notes --- customize.dist/src/less2/include/markdown.less | 4 ++-- lib/commands/pin-rpc.js | 2 +- lib/env.js | 2 +- lib/storage/block.js | 11 ----------- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index f52b2666f..f42a27146 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -177,12 +177,12 @@ a { color: @cryptpad_text_col; font-size: 0.8em; - &.cp-remote-img::before { + &.cp-remote-img::before { // .fa.fa-question-circle font-family: FontAwesome; //content: "\f08e\00a0"; content: "\f08e\00a0\00a0"; } - &.cp-learn-more::before { + &.cp-learn-more::before { // .fa.fa-external-link font-family: FontAwesome; content: "\f059\00a0"; //content: "\f059\00a0\00a0"; diff --git a/lib/commands/pin-rpc.js b/lib/commands/pin-rpc.js index 6fc05c202..89afc4ee8 100644 --- a/lib/commands/pin-rpc.js +++ b/lib/commands/pin-rpc.js @@ -228,7 +228,7 @@ Pinning.resetUserPins = function (Env, safeKey, channelList, _cb) { var session = Core.getSession(Env.Sessions, safeKey); - if (!channelList.length) { // XXX wut + if (!channelList.length) { return void cb(); } diff --git a/lib/env.js b/lib/env.js index 6b033fa16..141e028ae 100644 --- a/lib/env.js +++ b/lib/env.js @@ -123,7 +123,7 @@ module.exports.create = function (config) { maxWorkers: config.maxWorkers, disableIntegratedTasks: config.disableIntegratedTasks || false, - disableIntegratedEviction: config.disableIntegratedEviction || false, + disableIntegratedEviction: config.disableIntegratedEviction || true, // XXX false, lastEviction: +new Date(), evictionReport: {}, commandTimers: {}, diff --git a/lib/storage/block.js b/lib/storage/block.js index 5dfc393a5..d3e7a1869 100644 --- a/lib/storage/block.js +++ b/lib/storage/block.js @@ -79,14 +79,3 @@ Block.write = function (Env, publicKey, buffer, _cb) { }); }; -/* -Block.create = function (opt, _cb) { - var cb = Util.once(Util.mkAsync(_cb)); - - var env = { - root: opt.root || '', // XXX - - - }; -}; -*/ From 0c652e71b54cf09f99b1d1ed703f47ad3ef9024f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 15:43:41 +0200 Subject: [PATCH 057/117] Translated using Weblate (Japanese) Currently translated at 93.3% (1275 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.2% (1274 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 199ecd76a..1d7366f6d 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -260,7 +260,7 @@ "fm_rootName": "ドキュメント", "team_listTitle": "あなたのチーム", "team_createName": "チーム名", - "features_f_devices_note": "ユーザーアカウントでどこからでも CryptDrive にアクセスできます", + "features_f_devices_note": "ユーザーアカウントでどこからでもCryptDriveにアクセスできます", "features_f_devices": "全てのデバイスであなたのパッドを利用", "features_f_cryptdrive1_note": "フォルダ、共有フォルダ、テンプレート、タグ", "features_f_cryptdrive1": "CryptDriveの全機能", @@ -466,7 +466,7 @@ "sharedFolders_create": "共有フォルダを作成", "share_mediatagCopy": "Mediaタグをクリップボードにコピー", "header_homeTitle": "CryptPadのホームページを開く", - "header_logoTitle": "CryptDriveに行く", + "header_logoTitle": "CryptDriveを開く", "settings_cursorShareTitle": "カーソルの位置を共有", "settings_padWidthLabel": "エディターの幅を減らす", "settings_codeIndentation": "コードエディターのインデント(空白スペース)", @@ -1275,5 +1275,6 @@ "creation_expiresIn": "有効期限", "settings_mediatagSizeHint": "ドキュメントに埋め込まれたメディア要素(画像、ビデオ、PDF)を自動で読み込む最大のサイズをメガバイト(MB)で指定してください。指定したサイズより大きい要素については、手動で読み込む必要があります。「-1」を設定すると、メディア要素は常に自動的に読み込まれます。", "settings_mediatagSizeTitle": "自動ダウンロードの制限", - "settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザ上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティ上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去して、デバイスの空き容量を確保することもできます。" + "settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザ上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティ上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去して、デバイスの空き容量を確保することもできます。", + "team_infoContent": "それぞれのチームには、チーム所有のCryptDrive、ストレージのクォータ、チャット、メンバーリストが備わっています。チームの所有者はチームを削除することができます。管理者はメンバーを招待したりキックしたりすることができます。メンバーは、チームを退会することができます。" } From 63c852c9aad80cdf342b3b073e68501be632e29d Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 15:43:41 +0200 Subject: [PATCH 058/117] Translated using Weblate (German) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index bc4ae8952..866f7f6ea 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1365,5 +1365,6 @@ "admin_purpose_experiment": "Zum Testen der Plattform oder zur Entwicklung neuer Funktionen", "admin_instancePurposeTitle": "Zweck der Instanz", "admin_instancePurposeHint": "Warum betreibst du diese Instanz? Deine Antwort wird mit den Entwicklern geteilt, sofern die Telemetrie aktiviert ist.", - "admin_purpose_public": "Zur Bereitstellung eines kostenlosen Dienstes für die Allgemeinheit" + "admin_purpose_public": "Zur Bereitstellung eines kostenlosen Dienstes für die Allgemeinheit", + "resources_learnWhy": "Mehr über die Gründe erfahren" } From 0978074c74e479a34b972cfdc01bfd2f6597a254 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 30 Jun 2021 19:31:48 +0530 Subject: [PATCH 059/117] add convert app to example nginx and update changelog --- CHANGELOG.md | 20 ++++++++++++++++++++ docs/example.nginx.conf | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b41b1d9b0..18fd928a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ * server * `installMethod: 'unspecified'` in the default config to distinguish docker installs * `instancePurpose` on admin panel + * add support for archiving pin lists (instead of deleting them) + * blocks + * archive blocks instead of deleting them outright + * implement as storage API + * validate blocks in worker + * don't include adminEmail in telemetry unless we have consentToContact + * don't include instancePurpose in telemetry if it is "noanswer" * display warnings when remote resources are blocked * in code preview * restrict style tags to a scope when rendering them in markdown preview by compiling their content as scoped less @@ -15,6 +22,19 @@ * form templates * guard against a type error in `getAccessKeys` * guard against invalid or malicious input when constructing media-tags for embedding in markdown +* Japanese translation +* conversions + * convert app + * some basic office formats + * rich text => markdown + * handle some pecularities with headings and ids + * forms => .csv + * trello import with some loss +* fix rendering issue for legacy markdown media tag syntax + * guard against domExceptions + * catch errors thrown by the diff applier +* don't bother returning the hash of a pin list to the client, since they don't use it + # 4.7.0 diff --git a/docs/example.nginx.conf b/docs/example.nginx.conf index 85f42dd81..29317ee27 100644 --- a/docs/example.nginx.conf +++ b/docs/example.nginx.conf @@ -214,7 +214,7 @@ server { # The nodejs server has some built-in forwarding rules to prevent # URLs like /pad from resulting in a 404. This simply adds a trailing slash # to a variety of applications. - location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report)$ { + location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report|convert)$ { rewrite ^(.*)$ $1/ redirect; } From 9d23c42e0b6554db18e9536e3b21ef2ff9db116f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 16:10:24 +0200 Subject: [PATCH 060/117] Translated using Weblate (Japanese) Currently translated at 93.4% (1276 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.4% (1276 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.3% (1275 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.3% (1275 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 1d7366f6d..03c32921c 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -784,7 +784,7 @@ "team_pcsSelectHelp": "所有するパッドをチームのドライブに作成すると、そのパッドの所有権はチームに与えられます。", "sharedFolders_create_owned": "フォルダを所有する", "creation_owned1": "所有している項目は、所有者が望むときにいつでも完全削除できます。完全削除すると、他のユーザーのCryptDriveからも削除されます。", - "creation_owned": "所有するパッド", + "creation_owned": "パッドを所有", "uploadFolder_modal_owner": "所有するファイル", "upload_modal_owner": "所有するファイル", "settings_driveDuplicateHint": "所有するパッドを共有フォルダに移動すると、あなたのCryptDriveにパッドのコピーが保存され、あなたは引き続きそのパッドをコントロールできます。重複したファイルは隠すことができます。削除しない限り、共有したバージョンだけが表示されます。削除した場合は、以前の場所に元のファイルが表示されます。", @@ -1273,8 +1273,9 @@ "owner_text": "パッドの所有者は、所有者の追加や削除、リストによるアクセス制限のほか、パッドの削除を行うことができます。", "share_linkWarning": "このリンクは、ドキュメントを暗号化したり復号化したりする鍵を含んでいます。リンクを受け取った相手は、誰でも(ここにはコンピュータープログラムも含まれます)コンテンツにアクセスすることができます。", "creation_expiresIn": "有効期限", - "settings_mediatagSizeHint": "ドキュメントに埋め込まれたメディア要素(画像、ビデオ、PDF)を自動で読み込む最大のサイズをメガバイト(MB)で指定してください。指定したサイズより大きい要素については、手動で読み込む必要があります。「-1」を設定すると、メディア要素は常に自動的に読み込まれます。", + "settings_mediatagSizeHint": "ドキュメントに埋め込まれたメディア要素(画像、ビデオ、PDF)を自動で読み込む最大のサイズをメガバイト(MB)で指定してください。指定したサイズより大きい要素については、手動で読み込む必要があります。「-1」を設定すると、メディア要素は常に自動で読み込みます。", "settings_mediatagSizeTitle": "自動ダウンロードの制限", "settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザ上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティ上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去して、デバイスの空き容量を確保することもできます。", - "team_infoContent": "それぞれのチームには、チーム所有のCryptDrive、ストレージのクォータ、チャット、メンバーリストが備わっています。チームの所有者はチームを削除することができます。管理者はメンバーを招待したりキックしたりすることができます。メンバーは、チームを退会することができます。" + "team_infoContent": "それぞれのチームには、チーム所有のCryptDrive、ストレージのクォータ、チャット、メンバーリストが備わっています。チームの所有者はチームを削除することができます。管理者はメンバーを招待したりキックしたりすることができます。メンバーは、チームを退会することができます。", + "home_support": "

    開発チームは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    Open Collectiveから、一度もしくは継続的な寄付を行い、プロジェクトを支援していただくことができます。予算には透明性があり、更新については定期的に報告を行っています。お金によらずに貢献する方法も数多くあります。

    " } From 41d17a7ee3b51a5123fd51f86b7a2bbe8647248e Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Jun 2021 19:39:00 +0200 Subject: [PATCH 061/117] Translated using Weblate (Japanese) Currently translated at 95.5% (1305 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.5% (1305 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.5% (1305 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.5% (1305 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.4% (1304 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.4% (1304 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.4% (1304 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.1% (1300 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1299 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1299 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1299 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1299 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1299 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1299 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.0% (1298 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.9% (1297 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.9% (1297 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.6% (1293 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.5% (1291 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.4% (1290 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.3% (1289 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.2% (1288 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.1% (1286 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 94.0% (1285 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.9% (1284 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.9% (1284 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.9% (1283 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.9% (1283 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.8% (1282 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.7% (1280 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.6% (1279 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.5% (1278 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.5% (1278 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.5% (1278 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.4% (1277 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 93.4% (1276 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 113 ++++++++++++++--------- 1 file changed, 71 insertions(+), 42 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 03c32921c..5159c5859 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -63,8 +63,8 @@ "crowdfunding_button2": "CryptPadを支援", "fm_padIsOwned": "あなたはこのパッドの所有者です", "creation_expiration": "有効期限を設定", - "owner_removeText": "所有者", - "creation_owners": "所有者", + "owner_removeText": "オーナー", + "creation_owners": "オーナー", "download_mt_button": "ダウンロード", "fc_rename": "名前を変更", "forgotten": "ごみ箱へ移動", @@ -74,7 +74,7 @@ "fm_creation": "作成日時", "fm_lastAccess": "最終アクセス日時", "fm_type": "種類", - "team_inviteLinkLoading": "あなたのリンクを生成中", + "team_inviteLinkLoading": "リンクを生成しています", "download_step1": "ダウンロード中", "loading": "読み込み中...", "fm_searchPlaceholder": "検索...", @@ -159,21 +159,21 @@ "saved": "保存しました", "error": "エラー", "deleted": "削除しました", - "profile_editDescription": "説明を編集", - "profile_addDescription": "説明を追加", + "profile_editDescription": "説明文を編集", + "profile_addDescription": "説明文を追加", "profileButton": "プロフィール", "profile_avatar": "アバター", "profile_upload": " 新しいアバターをアップロード", "teams_table_generic_edit": "編集: フォルダとパッドの作成、変更、削除が可能。", "teams_table_generic_view": "表示: フォルダとパッドへのアクセス(閲覧のみ)。", - "teams_table_generic_own": "チームの管理: チーム名とチームアバターの変更、所有者の追加または削除、チームのサブスクリプションの変更、チームの削除が可能。", + "teams_table_generic_own": "チームの管理: チーム名とチームのアバターの変更、オーナーの追加または削除、チームのサブスクリプションの変更、チームの削除が可能。", "teams_table_owners": "チームの管理", "teams_table_generic_admin": "メンバーの管理: メンバーの招待および取り消し、メンバーに管理者までの権限の付与が可能。", "teams_table_admins": "メンバーの管理", "teams_table_generic": "権限一覧", "teams_table": "権限", "contacts_fetchHistory": "古い履歴を取得する", - "contacts_warning": "ここに入力したすべてのものは永続的であり、このパッドの現在および将来のすべてのユーザーが利用できます。機密情報の入力は推奨されません!", + "contacts_warning": "ここに入力したすべてのメッセージは永続的であり、このパッドの現在および将来のすべてのユーザーが利用できます。機密情報の入力は推奨されません!", "contacts_typeHere": "ここにメッセージを入力...", "team_cat_drive": "ドライブ", "team_cat_chat": "チャット", @@ -184,11 +184,11 @@ "team_deleteHint": "チーム自体とチームが所有しているすべてのドキュメントを削除します。", "team_deleteTitle": "チームの削除", "team_avatarHint": "容量 500KB 以下 (png 、jpg 、jpeg 、gif)", - "team_avatarTitle": "チームアバター", + "team_avatarTitle": "チームのアバター", "team_nameHint": "チームの名前を設定します", "team_nameTitle": "チーム名", "team_members": "メンバー", - "team_owner": "所有者", + "team_owner": "オーナー", "team_admins": "管理者", "viewers": "閲覧者", "contacts_padTitle": "チャット", @@ -268,7 +268,7 @@ "features_f_anon": "匿名ユーザーの全機能", "features_f_storage0_note": "ドキュメントは{0}日以上使用されないと削除されます", "features_f_storage0": "一時的な保存", - "features_f_cryptdrive0_note": "後で開けるようにブラウザにアクセスしたパッドを保存する機能", + "features_f_cryptdrive0_note": "アクセスしたパッドをブラウザに保存して、後で開くことができます", "features_f_cryptdrive0": "CryptDriveへの限定的なアクセス", "features_f_file0_note": "他のユーザーが共有したドキュメントを表示およびダウンロードできます", "features_f_file0": "ドキュメントを開く", @@ -317,7 +317,7 @@ "oo_sheetMigration_loading": "あなたのスプレッドシートを最新バージョンにアップグレードしています。1分程度お待ちください。", "settings_ownDriveButton": "アカウントをアップグレード", "features_f_file1_note": "CryptDriveに画像ファイル、PDF、動画などを保存できます。保存したファイルは、連絡先と共有したり、ドキュメントに埋め込んだりできます。(最大容量は{0}MB)", - "crowdfunding_button": "CryptPad を支援", + "crowdfunding_button": "CryptPadを支援", "contacts_removeHistoryTitle": "チャット履歴を削除", "properties_passwordSuccessFile": "パスワードは正常に変更されました。", "drive_sfPasswordError": "誤ったパスワードです", @@ -344,7 +344,7 @@ "settings_safeLinksHint": "CryptPadでは、リンクの中にパッドを解読するための鍵が含まれています。ブラウザの閲覧履歴にアクセスできる人は、誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューを使用することを強く推奨します。", "settings_autostoreTitle": "CryptDriveへのパッドの保存", "settings_logoutEverywhereConfirm": "すべてのデバイスでログインが取り消されるため、今後利用する際にもう一度ログインするよう求められます。続行しますか?", - "settings_logoutEverywhere": "他のすべてのウェブセッションからログアウトします", + "settings_logoutEverywhere": "他のすべてのウェブセッションからログアウト", "settings_logoutEverywhereTitle": "リモートセッションを閉じる", "loading_state_5": "ドキュメントを再構築", "loading_state_4": "チームを読み込み", @@ -386,8 +386,8 @@ "previewButtonTitle": "マークダウンのプレビューを表示または非表示にします", "whatis_model": "ビジネスモデル", "whatis_collaboration": "プライベートコラボレーション", - "home_support_title": "CryptPad を支援する", - "home_opensource": "誰でもCryptPadを運営し、個人的または専門的な仕方でサービスを提供することができます。ソースコードはGitHubで確認できます。", + "home_support_title": "CryptPadを支援", + "home_opensource": "誰でもCryptPadを運営し、個人的または専門的な規模でサービスを提供することができます。ソースコードはGitHubで確認できます。", "home_opensource_title": "オープンソース", "home_host_title": "このインスタンスについて", "home_privacy_text": "CryptPadは、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。すべてのコンテンツは、あなたのブラウザ上で暗号化および復号化されます。ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービスの管理者でも、あなたの情報にアクセスすることはできません。", @@ -440,10 +440,10 @@ "kanban_editCard": "このカードを編集", "kanban_clearFilter": "フィルターを消去", "kanban_tags": "タグでフィルタリング", - "allow_text": "アクセスリストを使用すると、選択したユーザーと所有者だけがドキュメントにアクセスできます。", + "allow_text": "アクセスリストを使用すると、選択したユーザーとオーナーだけがドキュメントにアクセスできます。", "admin_defaultlimitTitle": "ストレージの制限(MB)", - "owner_add": "{0}があなたをパッド {1} の所有者になるよう希望しています。 承諾しますか?", - "owner_removeConfirm": "選択したユーザーの所有権を削除してよろしいですか? ユーザーには通知が送られます。", + "owner_add": "{0}があなたをパッド「{1}」のオーナーになるよう希望しています。 承諾しますか?", + "owner_removeConfirm": "選択したユーザーのオーナー権を削除してよろしいですか? ユーザーには通知が送られます。", "owner_removePendingText": "保留中", "properties_unknownUser": "{0}人の不明なユーザー", "requestEdit_viewPad": "パッドを新しいタブで開く", @@ -474,14 +474,14 @@ "fc_openInCode": "コードエディターで開く", "poll_create_option": "新しいオプションを追加", "poll_create_user": "新しいユーザーを追加", - "pad_mediatagImport": "CryptDriveに保存", + "pad_mediatagImport": "あなたのCryptDriveに保存", "admin_listMyInstanceLabel": "このインスタンスをリストに表示", "admin_checkupTitle": "インスタンスの設定を検証", "cba_disable": "消去して無効にする", "upload_pending": "保留中", "settings_resetTips": "ヒント", "chrome68": "バージョン68のChromeあるいはChromiumを使用しているようです。このバージョンには、数秒経過した後でページが白紙になったり、クリックにページが反応しなくなったりするバグがあります。この問題を解決するには、別のタブを表示して改めて表示するか、このページでスクロールを試みてください。このバグは次のバージョンで解決される予定となっています。", - "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずにログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • 未ログインで作成、共有したファイルを保存するには、 「匿名セッションのデータをインポート」にチェックをしてください。
    ", + "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • 未ログインで作成、共有したファイルを保存するには、 「匿名セッションのドキュメントをインポート」にチェックをしてください。
    ", "poll_commit": "送信", "admin_removeDonateButtonTitle": "クラウドファンディングに参加", "mediatag_notReady": "ダウンロードを完了してください", @@ -564,7 +564,7 @@ "form_reset": "リセット", "form_update": "更新", "form_submit": "送信", - "form_type_md": "説明", + "form_type_md": "説明文", "form_type_poll": "投票", "form_type_checkbox": "チェックボックス", "form_type_textarea": "段落", @@ -672,7 +672,7 @@ "fm_newButton": "新規", "fm_sharedFolderName": "共有フォルダ", "fm_tagsName": "タグ", - "fm_filesDataName": "全ファイル", + "fm_filesDataName": "全てのファイル", "contacts_leaveRoom": "このルームから退出", "contacts_rooms": "ルーム", "contacts_removeHistoryServerError": "チャットの履歴を削除する際にエラーが発生しました。後ほど再試行してください", @@ -781,9 +781,9 @@ "typeError": "このパッドは選択したアプリケーションと互換性がありません", "form_type_page": "ページ分割", "form_description_default": "ここにテキストを入力", - "team_pcsSelectHelp": "所有するパッドをチームのドライブに作成すると、そのパッドの所有権はチームに与えられます。", + "team_pcsSelectHelp": "所有するパッドをチームのドライブに作成すると、そのパッドのオーナー権はチームに与えられます。", "sharedFolders_create_owned": "フォルダを所有する", - "creation_owned1": "所有している項目は、所有者が望むときにいつでも完全削除できます。完全削除すると、他のユーザーのCryptDriveからも削除されます。", + "creation_owned1": "所有している項目は、オーナーの望むときにいつでも完全削除できます。完全削除すると、他のユーザーのCryptDriveからも削除されます。", "creation_owned": "パッドを所有", "uploadFolder_modal_owner": "所有するファイル", "upload_modal_owner": "所有するファイル", @@ -851,7 +851,7 @@ "settings_resetTipsDone": "全てのヒントが表示されます。", "settings_resetTipsButton": "利用可能なCryptDriveのヒントをリセット", "settings_resetNewTitle": "CryptDriveのデータを消去", - "settings_exportErrorMissing": "このドキュメントはサーバーにありません(期限切れ、もしくは所有者により削除されました)", + "settings_exportErrorMissing": "このドキュメントはサーバーにありません(期限切れ、もしくはオーナーにより削除されました)", "settings_exportErrorEmpty": "このドキュメントはエクスポートできません(内容が空もしくは無効です)。", "settings_exportErrorDescription": "以下のドキュメントをエクスポートに追加できませんでした:", "settings_exportDescription": "ドキュメントをダウンロードして復号化しております。少々お待ちください。これには数分程度かかることがあります。タブを閉じると作業が中断されます。", @@ -880,7 +880,7 @@ "colorButtonTitle": "プレゼンテーションモードの文字色を変更", "presentButtonTitle": "プレゼンテーションモードに変更", "exportPrompt": "ファイル名は何にしますか?", - "share_formEdit": "著者", + "share_formEdit": "作者", "history_userNext": "次の著者", "history_userPrev": "以前の著者", "comments_deleted": "コメントは著者により削除されました", @@ -932,7 +932,7 @@ "properties_passwordWarning": "パスワードは変更されましたが、CryptDriveを更新することができませんでした。古いバージョンのパッドは手動で削除しなければならないかもしれません。
    OKを押して再読み込みし、アクセス権限を更新してください。", "properties_confirmChange": "パスワードを変更すると履歴が削除されます。パスワードを知らないユーザーは、このパッドにアクセスできなくなります。続行してよろしいですか?", "creation_newPadModalDescription": "作成するドキュメントの種類をクリックしてください。タブキーで選択し、エンターキーで作成することもできます。", - "creation_noOwner": "所有者がありません", + "creation_noOwner": "オーナーがいません", "properties_passwordError": "パスワードの変更中にエラーが発生しました。再度試してください。", "properties_passwordSame": "新しいパスワードは現在のパスワードと異なるものでなければなりません。", "four04_pageNotFound": "お探しのページが見つかりませんでした。", @@ -952,7 +952,7 @@ "settings_export_reading": "CryptDriveを読み込んでいます…", "settings_exportCancel": "エクスポートをキャンセルしてよろしいでしょうか?次のエクスポートでは最初からやりなおす必要があります。", "fm_error_cantPin": "内部サーバーエラー。ページを再度読み込んでください。", - "fm_info_anonymous": "ログインしていないため、ドキュメントは{0}日後に期限切れになります。また、ブラウザの履歴を消去するとファイルが消えてしまうかもしれません。
    ファイルを永続的に保存するには、登録するか(個人情報の登録は不要です)、ログインしてください。登録アカウントについては、こちらを参照してください(英語)。", + "fm_info_anonymous": "ログインしていないため、ドキュメントは{0}日後に期限切れになります。また、ブラウザの履歴を消去するとファイルが削除される恐れがあります。
    ファイルを永続的に保存するには、登録するか(個人情報の登録は不要です)ログインしてください。登録アカウントについては、こちらを参照してください。", "fm_info_recent": "あなたか共同編集者が最近開いた、もしくは編集したパッドの一覧です。", "fm_info_template": "テンプレートとして保存したパッドの一覧です。以下のテンプレートを使って、新しいパッドを作成することができます。", "fm_categoryError": "選択したカテゴリーが開けません。ルートを表示します。", @@ -1030,7 +1030,7 @@ "team_invitedToTeam": "{0}があなたをチーム「{1}」に招待しました", "team_inviteFromMsg": "{0}があなたをチーム「{1}」に招待しました", "team_invitePleaseLogin": "招待を承諾するには、ログインもしくは登録してください。", - "team_inviteEnterPassword": "招待パスワードを入力してください。", + "team_inviteEnterPassword": "招待のパスワードを入力してください。", "team_inviteGetData": "チームのデータを取得中です", "team_inviteInvalidLinkError": "招待リンクが無効です。", "admin_getlimitsHint": "インスタンスに適用されている全てのカスタムストレージの制限を一覧表示します。", @@ -1058,7 +1058,7 @@ "form_answerName": "{0}から{1}について回答", "form_addMultipleHint": "複数の日時を追加", "admin_consentToContactTitle": "連絡に同意", - "form_poll_hint": ": はい、: いいえ、: 許容できる", + "form_poll_hint": ": はい、: いいえ、: 可", "admin_provideAggregateStatisticsLabel": "集計済みの統計を提供", "admin_provideAggregateStatisticsTitle": "統計による集計", "admin_blockDailyCheckHint": "以後CryptPadのインスタンスは、1日に1回、CryptPadの開発者のサーバーにメッセージを送信します。開発者はそれをもとに、CryptPadのバージョンごとのサーバー数を追跡することができます。以下からこの測定をオプトアプトできます。なお、送信されるメッセージの内容は、確認用として、アプリケーションのサーバーのログに記録されます。", @@ -1094,7 +1094,7 @@ "trimHistory_error": "履歴を削除している途中でエラーが発生しました", "trimHistory_getSizeError": "ドライブの履歴のサイズを計算している途中でエラーが発生しました", "profile_login": "このユーザーを連絡先に追加するにはログインする必要があります", - "dontShowAgain": "二度と表示しない", + "dontShowAgain": "再び表示しない", "oo_sheetMigration_anonymousEditor": "登録ユーザーが最新のバージョンに更新するまで、このスプレッドシートを未登録ユーザーが編集することはできません。", "oo_invalidFormat": "このファイルはインポートできません", "burnAfterReading_warningDeleted": "このパッドは削除されました。ウインドウを閉じた後で再びアクセスすることはできません。", @@ -1130,8 +1130,8 @@ "mdToolbar_heading": "見出し", "settings_cursorShowHint": "共同ドキュメントであなたが他のユーザーのカーソルの位置を見られるかどうかを決められます。", "settings_cursorShareHint": "共同ドキュメントで他のユーザーがあなたのカーソルの位置を見られるかどうかを決められます。", - "settings_cursorColorHint": "共同ドキュメントでの他のユーザーの色を変更できます。", - "settings_padWidthHint": "テキストエディターの幅を制限するページモード(既定)と、スクリーン全体の幅を使用するモードを切り替える。", + "settings_cursorColorHint": "共同ドキュメントでの他のユーザーのカーソルの色を変更できます。", + "settings_padWidthHint": "テキストエディターの幅を制限するページモード(既定)と、スクリーン全体の幅を使用するモードを切り替えられます。", "fm_forbidden": "禁止されたアクション", "team_exportHint": "チームのドライブの全てのドキュメントをダウンロードします。ドキュメントは、他のアプリケーションで読み込めるフォーマットがあれば、そのフォーマットでダウンロードされます。そうしたフォーマットがなければ、CryptPadで読み込めるフォーマットでダウンロードされます。", "admin_limitUser": "ユーザーの公開鍵", @@ -1148,7 +1148,7 @@ "support_formHint": "このフォームから、管理者に問題の報告や質問を安全に行うことができます。
    それらに関しては CryptPadユーザーガイドで回答されているものがあるかもしれません。既にチケットを作成している場合、同じ問題に関して新しいチケットを作成するのはお控えください。その代わりに、既存のチケットに追加の情報を送信してください。", "support_disabledTitle": "サポートは有効になっていません", "admin_supportListHint": "ユーザーからサポートのメールボックスに送信されたチケットの一覧です。管理者はメッセージと回答を閲覧できます。終了したチケットは再開することができます。終了したチケットについては削除する(隠す)ことができますが、他の管理者には引き続き表示されます。", - "drive_sfPassword": "共有フォルダ「 {0} 」は利用できません。所有者により削除されたか、新しいパスワードにより保護されています。CryptDriveから削除するか、新しいパスワードを使ってアクセスを回復できます。", + "drive_sfPassword": "共有フォルダ「 {0} 」は利用できません。オーナーにより削除されたか、新しいパスワードで保護されています。CryptDriveから削除するか、新しいパスワードを使ってアクセスを回復できます。", "fm_info_sharedFolderHistory": "これは共有フォルダの履歴です: {0}
    CryptDriveは閲覧モードを継続します。", "notification_folderShared": "{0}があなたとフォルダを共有しました: {1}", "convertFolderToSF_SFChildren": "このフォルダは共有フォルダを含んでいるため、共有フォルダに変更できません。続けるには、このフォルダを共有フォルダの外に移動してください。", @@ -1226,15 +1226,15 @@ "settings_driveRedirectHint": "ログイン時にホームページからドライブに自動で転送する機能は、デフォルトで有効ではなくなりました。以前の動作は以下で有効にできます。", "admin_removeDonateButtonLabel": "クラウドファンディングのキャンペーンの宣伝を表示しない", "admin_purpose_public": "誰でも利用できるフリーのサービスを提供するため", - "owner_team_add": "{0}があなたをチーム({1})の所有者にしようとしています。承諾しますか?", + "owner_team_add": "{0}があなたをチーム({1})のオーナーにしようとしています。承諾しますか?", "friendRequest_accepted": "{0}が連絡先リクエストを承諾しました", "friendRequest_accept": "承諾(Enter)", "admin_flushCacheHint": "サーバーから最新のコンテンツをダウンロードするようユーザーに強制(サーバーが「フレッシュ」モードの場合のみ)", "admin_activeSessionsHint": "アクティブなwebsocketの接続(および接続する一意のIPアドレス)の数", "convertFolderToSF_SFParent": "このフォルダは別の共有フォルダ内にあるため、共有フォルダに変換できません。続行するには、外部に移動してください。", "settings_deleteWarning": "注意:現在、プレミアムプランに加入しています(別のユーザーが支払いまたは提供)。アカウントを削除する前に、プランをキャンセルしてください。アカウントを削除すると、サポートに連絡しないとキャンセルできなくなります。", - "owner_request": "{0}はあなたを{1}の所有者にしようとしています", - "owner_addConfirm": "共同所有者は内容を変更したり、あなたを所有者から削除したりすることができます。続行してよろしいですか?", + "owner_request": "{0}はあなたを{1}のオーナーにしようとしています", + "owner_addConfirm": "共同オーナーは内容を変更したり、あなたをオーナーから削除したりすることができます。続行してよろしいですか?", "download_zip_file": "ファイル {0}/{1}", "documentID": "ドキュメントの識別子", "admin_setlimitButton": "制限を設定", @@ -1249,7 +1249,7 @@ "isNotContact": "{0}はあなたの連絡先ではありません", "isContact": "{0}はあなたの連絡先です", "profile_info": "他のユーザーは、ドキュメントのユーザーリストであなたのアバターをクリックして、あなたのプロフィールを確認できます。", - "owner_removeMeConfirm": "所有権を放棄しようとしています。これは取り消せません。よろしいですか?", + "owner_removeMeConfirm": "オーナー権を放棄しようとしています。これは取り消せません。よろしいですか?", "requestEdit_confirm": "{1}がパッド「{0}」の編集権を要求しました。編集権を与えますか?", "admin_supportInitHelp": "サーバーはサポートメールボックスを使用するように設定されていません。サポートメールボックスを有効にし、ユーザーからメッセージを受け取るためには、サーバーの管理者に連絡し、「./scripts/generate-admin-keys.js」のスクリプトを実行してもらい、生成された公開鍵を「config.js」に保存して、秘密鍵をあなたに送信してもらうよう依頼する必要があります。", "feedback_privacy": "私たちはプライバシーを配慮すると同時に、CryptPadを使いやすくしたいと望んでいます。このファイルは、実行されたアクションを特定するパラメーターと共に要求され、ユーザーにとって重要なUI機能を特定するために使用されます。", @@ -1266,16 +1266,45 @@ "whatis_collaboration_info": "

    CryptPadはコラボレーションを念頭に作られています。ドキュメントに加えられる変更は、リアルタイムで同期されます。全てのデータは暗号化されているため、サービスとその管理者が、編集され保存されているコンテンツを覗き見ることは不可能です。

    ", "whatis_apps": "フルスイートアプリケーション", "whatis_drive_info": "

    ドキュメントをCryptDriveに保存して管理できます。フォルダを作ったり共有したりできるほか、ドキュメントをタグ付けして整理することもできます。PDFファイル、写真、動画、音声などのファイルをアップロードして共有できます。チームのドライブを使うと、メンバーとデータを共有したり、ファイルの管理や、きめ細かいアクセス権のコントロールを行うことができます。

    ", - "whatis_model_info": "

    CryptPadは2016年より、寄付金とcryptpad.frの定額利用のほか、BPIフランス、NLNet財団、NGI Trust、Mozillaオープンソースサポートといったフランス、EUの研究助成を受けています。私たちは、公的資金で作られたソフトウェアについては、コードも公的に公開されるべきであると考えているため、サービスは全てオープンソースで提供しています。誰でも自由にこのソフトウェアを使ったり、運営したり、改変したりすることができます。

    CryptPadは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    私たちは、CryptPadのサービスを無料で提供しています。それは、金銭的に余裕のある人々だけでなく、誰もがプライバシーを得るに値すると確信しているからです。もしあなたがこのプロジェクトを支援できる状況にあるなら、機能の開発や、改良、メンテナンスに参加していただきたく考えます。そうすることで、全てのユーザーに利益をもたらされるはずです。

    このプロジェクトが実行可能であることが明らかになったいま、次のゴールは、ユーザーによる支援を通じて、プロジェクトを持続可能なものにすることにあります。CryptPadが、巨大プラットフォームに代わる持続可能なサービスを開発できるよう支援していただけるなら、一度もしくは継続的な寄付へのご協力をお願いいたします。

    ", + "whatis_model_info": "

    CryptPadは2016年より、寄付金とcryptpad.frの定額利用のほか、BPIフランス、NLNet財団、NGI Trust、Mozillaオープンソースサポートといったフランス、EUの研究助成を受けています。私たちは、公的資金で作られたソフトウェアについては、コードも公的に公開されるべきであると考えているため、サービスは全てオープンソースで提供しています。誰でも自由にこのソフトウェアを使用、運営、改変することができます。

    CryptPadは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    私たちは、CryptPadのサービスを無料で提供しています。それは、金銭的に余裕のある人々だけでなく、誰もがプライバシーを得るに値すると確信しているからです。もしあなたがこのプロジェクトを支援できる状況にあるなら、機能の開発や、改良、メンテナンスに参加していただきたく考えます。そうすることで、全てのユーザーに利益をもたらされるはずです。

    このプロジェクトが実行可能であることが明らかになったいま、次のゴールは、ユーザーによる支援を通じて、プロジェクトを持続可能なものにすることにあります。CryptPadが、巨大プラットフォームに代わる持続可能なサービスを開発できるよう支援していただけるなら、一度もしくは継続的な寄付へのご協力をお願いいたします。

    ", "whatis_xwiki_info": "

    CryptPadはフランス、パリに所在する会社であるXWikiにて開発されています。当社はオープンソース・ソフトウェアを15年以上にわたって開発しており、情報管理のための共同作業ソフトウェアの開発に関して豊富な経験をもっています。当社の実績は、私たちがCryptPadの長期的な開発と維持にコミットしていることを示しています。

    ", "whatis_xwiki": "XWikiにて開発", "history_restoreDrivePrompt": "CryptDriveの現在のバージョンを、表示されているバージョンに置き換えてよろしいですか?", - "owner_text": "パッドの所有者は、所有者の追加や削除、リストによるアクセス制限のほか、パッドの削除を行うことができます。", + "owner_text": "パッドのオーナーは、オーナーの追加や削除、リストによるアクセス制限のほか、パッドの削除を行うことができます。", "share_linkWarning": "このリンクは、ドキュメントを暗号化したり復号化したりする鍵を含んでいます。リンクを受け取った相手は、誰でも(ここにはコンピュータープログラムも含まれます)コンテンツにアクセスすることができます。", "creation_expiresIn": "有効期限", "settings_mediatagSizeHint": "ドキュメントに埋め込まれたメディア要素(画像、ビデオ、PDF)を自動で読み込む最大のサイズをメガバイト(MB)で指定してください。指定したサイズより大きい要素については、手動で読み込む必要があります。「-1」を設定すると、メディア要素は常に自動で読み込みます。", "settings_mediatagSizeTitle": "自動ダウンロードの制限", - "settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザ上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティ上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去して、デバイスの空き容量を確保することもできます。", - "team_infoContent": "それぞれのチームには、チーム所有のCryptDrive、ストレージのクォータ、チャット、メンバーリストが備わっています。チームの所有者はチームを削除することができます。管理者はメンバーを招待したりキックしたりすることができます。メンバーは、チームを退会することができます。", - "home_support": "

    開発チームは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    Open Collectiveから、一度もしくは継続的な寄付を行い、プロジェクトを支援していただくことができます。予算には透明性があり、更新については定期的に報告を行っています。お金によらずに貢献する方法も数多くあります。

    " + "settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザ上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティー上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去して、デバイスの空き容量を確保することもできます。", + "team_infoContent": "それぞれのチームには、チーム所有のCryptDrive、ストレージのクォータ、チャット、メンバーリストが備わっています。チームのオーナーはチームを削除することができます。管理者はメンバーを招待したりキックしたりすることができます。メンバーは、チームを退会することができます。", + "home_support": "

    開発チームは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    Open Collectiveから、一度もしくは継続的な寄付を行い、プロジェクトを支援していただくことができます。予算には透明性があり、更新については定期的に報告を行っています。お金によらずに貢献する方法も数多くあります。

    ", + "form_default": "ここに質問を入力", + "form_poll_switch": "行と列を入れ替える", + "settings_kanbanTagsHint": "複数のタグを選択したときにタグフィルターがどのように機能するかについて、「かつ」もしくは「または」から選択できます。「かつ」を選択すると、選択したタグを全て含むカードのみを表示し、「または」を選択すると、選択したタグのいずれかを含むカードを表示します。", + "notifications_cat_pads": "共有に関する通知", + "form_type_multicheck": "チェックボックス式グリッド", + "form_type_multiradio": "選択式グリッド", + "form_type_sort": "番号付きリスト", + "safeLinks_error": "このリンクはブラウザーのアドレスバーからコピーされており、ドキュメントにアクセスすることはできません。 共有メニューを使って、連絡先と直接ドキュメントを共有するか、リンクをコピーしてください。セーフリンク機能についてはこちらよりご確認ください。", + "team_cat_general": "チームについて", + "team_ownerConfirm": "共同オーナーはチームを変更もしくは削除したり、あなたをオーナーから削除したりすることができます。続行してよろしいですか?", + "owner_request_accepted": "{0}はあなたのリクエストを承諾し、「{1}」のオーナーになりました", + "team_acceptInvitation": "{0}がチーム「{1}」への招待を承諾しました", + "team_declineInvitation": "{0}がチーム「{1}」への招待を拒否しました", + "team_inviteLinkWarning": "このリンクにアクセスする最初の人は、このチームに参加して、コンテンツを閲覧することができます。リンクは慎重に共有してください。", + "team_inviteLinkTitle": "このチームへの招待状を好みに合わせて作成", + "team_inviteLinkTempName": "一時的な名前(招待の保留中リストに表示)", + "team_inviteLinkNoteMsg": "このメッセージは、チームに参加するかどうかを決める前に表示されます。", + "owner_removedPending": "{0}は「{1}」に関するオーナー権の申し出をキャンセルしました", + "team_pendingOwnerTitle": "この管理者はオーナー権の申し出を受諾していません。", + "team_rosterPromoteOwner": "オーナー権を提供", + "owner_removed": "{0}は「{1}」に関するあなたのオーナー権を削除しました", + "owner_request_declined": "{0}は「{1}」のオーナーになる依頼を拒否しました", + "team_demoteMeConfirm": "オーナー権を放棄しようとしています。これは取り消せません。よろしいですか?", + "share_noContactsNotLoggedIn": "ログインもしくは新規登録して、連絡先を確認するか新たに追加してください。", + "passwordFaqLink": "パスワードについて確認", + "share_embedPasswordAlert": "この項目はパスワードで保護されています。このパッドを埋め込む際、閲覧にはパスワードの入力が必要となります。", + "share_contactPasswordAlert": "この項目はパスワードで保護されています。CryptPadの連絡先と共有するため、相手がパスワードを入力する必要はありません。", + "share_linkPasswordAlert": "この項目はパスワードで保護されています。リンクを受け取った相手はパスワードを入力する必要があります。", + "register_notes_title": "重要な注意事項" } From 0bb4f0fc3dd1a7c932e363efa31d8799a01364a7 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 11:46:56 +0530 Subject: [PATCH 062/117] set a generic documentation link in translations to be properly set and localized in the code --- www/common/drive-ui.js | 9 ++++++++- www/common/translations/messages.de.json | 2 +- www/common/translations/messages.es.json | 2 +- www/common/translations/messages.fi.json | 2 +- www/common/translations/messages.fr.json | 2 +- www/common/translations/messages.ja.json | 2 +- www/common/translations/messages.json | 2 +- www/common/translations/messages.nl.json | 2 +- www/common/translations/messages.pt-br.json | 2 +- www/common/translations/messages.zh.json | 2 +- 10 files changed, 17 insertions(+), 10 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index a145ab23b..4a75459a5 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2401,7 +2401,14 @@ define([ } if (!APP.loggedIn) { msg = APP.newSharedFolder ? Messages.fm_info_sharedFolder : Messages._getKey('fm_info_anonymous', [ApiConfig.inactiveTime || 90]); - return $(common.fixLinks($box.html(msg))); + var docsLink = 'https://docs.cryptpad.fr/en/user_guide/user_account.html#account-types'; + $box.html(msg).find('a[href="#docs"]').each(function () { + $(this).attr({ + href: Pages.localizeDocsLink(docsLink), + target: '_blank', + }); + }); + return $(common.fixLinks($box)); } if (!msg || APP.store['hide-info-' + path[0]] === '1') { $box.hide(); diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 866f7f6ea..6c2e6695c 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -279,7 +279,7 @@ "fm_info_template": "Hier sind alle Dokumente enthalten, die als Vorlage gespeichert wurden und die du wiederverwenden kannst, um ein neues Pad zu erstellen.", "fm_info_recent": "Diese Pads wurden kürzlich von dir oder von Personen, mit denen du zusammenarbeitest, geöffnet oder geändert.", "fm_info_trash": "Leere den Papierkorb, um mehr freien Platz in deinem CryptDrive zu erhalten.", - "fm_info_anonymous": "Du bist nicht eingeloggt, daher laufen deine Dokumente nach {0} Tagen aus. Sie könnten durch Löschen des Browserverlaufs verloren gehen.
    Registriere dich (keine persönlichen Informationen benötigt) oder logge dich ein, um sie dauerhaft in deinem Drive zu speichern. Mehr zu registrierten Accounts.", + "fm_info_anonymous": "Du bist nicht eingeloggt, daher laufen deine Dokumente nach {0} Tagen aus. Sie könnten durch Löschen des Browserverlaufs verloren gehen.
    Registriere dich (keine persönlichen Informationen benötigt) oder logge dich ein, um sie dauerhaft in deinem Drive zu speichern. Mehr zu registrierten Accounts.", "fm_info_sharedFolder": "Dieser Ordner ist geteilt. Da du aber nicht eingeloggt bist, hast du nur einen schreibgeschützen Zugriff.
    Registriere oder logge ich ein, damit du diesen Ordner in dein CryptDrive importieren und bearbeiten kannst.", "fm_info_owned": "Diese Pads sind deine eigenen. Das heißt, dass du sie jederzeit vom Server entfernen kannst. Wenn du das machst, sind sie auch für andere Nutzer nicht mehr zugänglich.", "fm_error_cantPin": "Interner Serverfehler. Bitte lade die Seite neu und versuche es erneut.", diff --git a/www/common/translations/messages.es.json b/www/common/translations/messages.es.json index 59b0b16db..34b53ef47 100644 --- a/www/common/translations/messages.es.json +++ b/www/common/translations/messages.es.json @@ -216,7 +216,7 @@ "upload_success": "Tu archivo ({0}) ha sido subido con éxito y fue añadido a tu drive.", "pinLimitReachedAlertNoAccounts": "Has llegado a tu límite de espacio", "previewButtonTitle": "Mostrar/esconder la vista previa Markdown", - "fm_info_anonymous": "No has iniciado sesión, por lo que tus documentos expirarán después de {0} días. Borrar el historial de tu navegador puede hacer que desaparezcan.
    Inscríbete (no se requieren datos personales) o Ingresa para almacenarlos en tu disco de forma indefinida. Más información sobre las cuentas registradas.", + "fm_info_anonymous": "No has iniciado sesión, por lo que tus documentos expirarán después de {0} días. Borrar el historial de tu navegador puede hacer que desaparezcan.
    Inscríbete (no se requieren datos personales) o Ingresa para almacenarlos en tu disco de forma indefinida. Más información sobre las cuentas registradas.", "fm_error_cantPin": "Error del servidor. Por favor, recarga la página e inténtalo de nuevo.", "upload_notEnoughSpace": "No tienes suficiente espacio para este archivo en tu CryptDrive", "upload_tooLarge": "Este archivo supera el límite de carga permitido por tu cuenta.", diff --git a/www/common/translations/messages.fi.json b/www/common/translations/messages.fi.json index 3d6172c14..960853bc8 100644 --- a/www/common/translations/messages.fi.json +++ b/www/common/translations/messages.fi.json @@ -287,7 +287,7 @@ "fm_info_template": "Sisältää kaikki mallipohjiksi tallennetut padit, joita voit käyttää uudelleen luodessasi uuden padin.", "fm_info_recent": "Tässä näytetään sinun tai yhteistyökumppaniesi äskettäin avaamat tai muokkaamat padit.", "fm_info_trash": "Tyhjennä roskakorisi vapauttaaksesi CryptDrive-tallennustilaa.", - "fm_info_anonymous": "Et ole kirjautunut sisään, joten luomasi asiakirjat vanhenevat {0} päivän päästä. Selaushistorian tyhjentäminen saattaa myös hävittää ne.
    Rekisteröidy (henkilötietoja ei tarvita) tai kirjaudu sisään säilyttääksesi luomasi asiakirjat pysyvästi CryptDrivessa. Lue lisää rekisteröitymisestä ja käyttäjätileistä.", + "fm_info_anonymous": "Et ole kirjautunut sisään, joten luomasi asiakirjat vanhenevat {0} päivän päästä. Selaushistorian tyhjentäminen saattaa myös hävittää ne.
    Rekisteröidy (henkilötietoja ei tarvita) tai kirjaudu sisään säilyttääksesi luomasi asiakirjat pysyvästi CryptDrivessa. Lue lisää rekisteröitymisestä ja käyttäjätileistä.", "fm_info_sharedFolder": "Tämä on jaettu kansio. Et ole kirjautunut sisään, joten voit käyttää sitä ainoastaan vain luku-tilassa.
    Rekisteröidy tai kirjaudu sisään tuodaksesi kansion omaan CryptDriveesi ja muokataksesi sen sisältöä.", "fm_info_owned": "Omistat tässä näytetyt padit. Se tarkoittaa, että voit halutessasi poistaa ne palvelimelta. Jos teet niin, muut käyttäjät eivät voi enää käyttää niitä.", "fm_error_cantPin": "Sisäinen palvelinvirhe. Ole hyvä ja lataa sivu uudelleen.", diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 2193de407..563b89ade 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -283,7 +283,7 @@ "fm_info_template": "Contient tous les fichiers que vous avez sauvés en tant que modèle afin de les réutiliser lors de la création d'un nouveau pad.", "fm_info_recent": "Ces pads ont été récemment ouverts ou modifiés par vous ou vos collaborateurs.", "fm_info_trash": "Vider la corbeille permet de libérer de l'espace dans votre CryptDrive.", - "fm_info_anonymous": "Vous n'êtes pas connecté, ces documents seront donc supprimés après {0} jours. Nettoyer l'historique de votre navigateur peut les faire disparaître.
    Enregistrez vous (aucune information personelle requise) ou Connectez vous pour les stocker de manière permanente dans votre drive. En lire plus sur les comptes utilisateurs.", + "fm_info_anonymous": "Vous n'êtes pas connecté, ces documents seront donc supprimés après {0} jours. Nettoyer l'historique de votre navigateur peut les faire disparaître.
    Enregistrez vous (aucune information personelle requise) ou Connectez vous pour les stocker de manière permanente dans votre drive. En lire plus sur les comptes utilisateurs.", "fm_info_sharedFolder": "Voici le contenu d'un dossier partagé. Il n'est accessible qu'en lecture seule car vous n'êtes pas connecté.
    Inscrivez-vous ou connectez-vous pour pouvoir l'importer dans votre CryptDrive et le modifier.", "fm_info_owned": "Vous êtes propriétaire des pads affichés dans cette catégorie. Cela signifie que vous pouvez choisir de les supprimer définitivement du serveur à n'importe quel moment. Ils seront alors inaccessibles pour tous les autres utilisateurs.", "fm_error_cantPin": "Erreur interne du serveur. Veuillez recharger la page et essayer de nouveau.", diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 5159c5859..3343d8873 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -952,7 +952,7 @@ "settings_export_reading": "CryptDriveを読み込んでいます…", "settings_exportCancel": "エクスポートをキャンセルしてよろしいでしょうか?次のエクスポートでは最初からやりなおす必要があります。", "fm_error_cantPin": "内部サーバーエラー。ページを再度読み込んでください。", - "fm_info_anonymous": "ログインしていないため、ドキュメントは{0}日後に期限切れになります。また、ブラウザの履歴を消去するとファイルが削除される恐れがあります。
    ファイルを永続的に保存するには、登録するか(個人情報の登録は不要です)ログインしてください。登録アカウントについては、こちらを参照してください。", + "fm_info_anonymous": "ログインしていないため、ドキュメントは{0}日後に期限切れになります。また、ブラウザの履歴を消去するとファイルが削除される恐れがあります。
    ファイルを永続的に保存するには、登録するか(個人情報の登録は不要です)ログインしてください。登録アカウントについては、こちらを参照してください。", "fm_info_recent": "あなたか共同編集者が最近開いた、もしくは編集したパッドの一覧です。", "fm_info_template": "テンプレートとして保存したパッドの一覧です。以下のテンプレートを使って、新しいパッドを作成することができます。", "fm_categoryError": "選択したカテゴリーが開けません。ルートを表示します。", diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index f61659809..4573aa665 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -287,7 +287,7 @@ "fm_info_template": "Contains all the pads stored as templates and that you can re-use when you create a new pad.", "fm_info_recent": "These pads have recently been opened or modified by you or people you collaborate with.", "fm_info_trash": "Empty your trash to free space in your CryptDrive.", - "fm_info_anonymous": "You are not logged in so your documents will expire after {0} days. Clearing your browser's history may make them disappear.
    Sign up (no personal information required) or Log in to store them in your drive indefinitely. Read more about registered accounts.", + "fm_info_anonymous": "You are not logged in so your documents will expire after {0} days. Clearing your browser's history may make them disappear.
    Sign up (no personal information required) or Log in to store them in your drive indefinitely. Read more about registered accounts.", "fm_info_sharedFolder": "This is a shared folder. You're not logged in so you can only access it in read-only mode.
    Sign up or Log in to be able to import it to your CryptDrive and to modify it.", "fm_info_owned": "You are the owner of the pads displayed here. This means you can remove them permanently from the server whenever you want. If you do so, other users won't be able to access them anymore.", "fm_error_cantPin": "Internal server error. Please reload the page and try again.", diff --git a/www/common/translations/messages.nl.json b/www/common/translations/messages.nl.json index d9933fef6..393b91a05 100644 --- a/www/common/translations/messages.nl.json +++ b/www/common/translations/messages.nl.json @@ -414,7 +414,7 @@ "fm_viewListButton": "Lijstweergave", "fm_info_owned": "U bent de eigenaar van de werkomgevingen die hier zijn weergegeven. Dit betekent dat u ze voorgoed van de server kunt verwijderen. Als u dat doet, zijn ze niet meer toegankelijk voor andere gebruikers.", "fm_info_sharedFolder": "Dit is een gedeelde map. U bent niet ingelogd, dus u kunt de inhoud alleen lezen. U kunt zich
    registreren of inloggen om het in uw CryptDrive te importeren en het te wijzigen.", - "fm_info_anonymous": "U bent niet ingelogd, dus uw documenten zullen verlopen na {0} dagen. Ze kunnen ook verdwijnen als uw browsergeschiedenis gewist wordt.
    Registreren (geen persoonlijke gegevens vereist) of Inloggen om ze voor altijd in uw drive op te slaan. Lees meer over geregistreerde accounts.", + "fm_info_anonymous": "U bent niet ingelogd, dus uw documenten zullen verlopen na {0} dagen. Ze kunnen ook verdwijnen als uw browsergeschiedenis gewist wordt.
    Registreren (geen persoonlijke gegevens vereist) of Inloggen om ze voor altijd in uw drive op te slaan. Lees meer over geregistreerde accounts.", "fm_info_trash": "Leeg uw prullenbak om opslagruimte vrij te maken in uw CryptDrive.", "fm_info_recent": "Deze werkomgevingen zijn onlangs geopend of gewijzigd door u of door mensen met wie u samenwerkt.", "fm_info_template": "Dit bevat alle werkomgevingen die zijn opgeslagen als sjablonen en die je kunt gebruiken voor een nieuwe werkomgeving.", diff --git a/www/common/translations/messages.pt-br.json b/www/common/translations/messages.pt-br.json index 2a2f3dcd8..971bf959a 100644 --- a/www/common/translations/messages.pt-br.json +++ b/www/common/translations/messages.pt-br.json @@ -138,7 +138,7 @@ "fm_categoryError": "Incapaz de abrir a categoria selecionada, Exibindo diretório raiz", "fm_info_root": "Crie quantos diretórios aninhados aqui desejar para organizar seus arquivos..", "fm_info_trash": "Empty your trash to free space in your CryptDrive.", - "fm_info_anonymous": "Você não está logado, então estes documentos vão expirar em {0} dias. Limpar o histórico do seu navegador pode fazê-los desaparecer.
    Registre-se (nenhuma informação pessoal será requerida) ou Faça login para guarda-lo no seu disco. Leia mais sobre contas registradas.", + "fm_info_anonymous": "Você não está logado, então estes documentos vão expirar em {0} dias. Limpar o histórico do seu navegador pode fazê-los desaparecer.
    Registre-se (nenhuma informação pessoal será requerida) ou Faça login para guarda-lo no seu disco. Leia mais sobre contas registradas.", "fm_error_cantPin": "Erro interno do servidor. Por favor recarregue a página e tente novamente.", "fc_newfolder": "Nova pasta", "fc_rename": "Renomear", diff --git a/www/common/translations/messages.zh.json b/www/common/translations/messages.zh.json index 814d92cb3..49331f9a5 100644 --- a/www/common/translations/messages.zh.json +++ b/www/common/translations/messages.zh.json @@ -139,7 +139,7 @@ "fm_info_root": "在此建立任何巢狀目錄夾以便於整理分類你的檔案。", "fm_info_template": "包含所有工作檔案已存成模版,便於讓你在建立新工作檔案時套用。", "fm_info_trash": "清空垃圾筒好讓 CryptDrive 多出一些空間", - "fm_info_anonymous": "您没有登录,所以您的文档将在{0}天后过期。清除你的浏览器历史记录可能会使它们消失。
    注册 (无需个人信息) 或登录以无限期地把它们储存在你的硬盘里。 阅读更多关于注册帐户。", + "fm_info_anonymous": "您没有登录,所以您的文档将在{0}天后过期。清除你的浏览器历史记录可能会使它们消失。
    注册 (无需个人信息) 或登录以无限期地把它们储存在你的硬盘里。 阅读更多关于注册帐户。", "fm_error_cantPin": "內部伺服器出錯,請重新載入本頁並再試一次。", "fc_newfolder": "新資料夾", "fc_rename": "重新命名", From 17adbc27bf124e5170425bd76755bcf107929dbd Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 12:46:43 +0530 Subject: [PATCH 063/117] remove blog link from out-of-date translations --- www/common/translations/messages.ca.json | 2 +- www/common/translations/messages.el.json | 2 +- www/common/translations/messages.it.json | 2 +- www/common/translations/messages.ro.json | 2 +- www/common/translations/messages.ru.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/www/common/translations/messages.ca.json b/www/common/translations/messages.ca.json index ad8254798..0132646a2 100644 --- a/www/common/translations/messages.ca.json +++ b/www/common/translations/messages.ca.json @@ -282,7 +282,7 @@ "fm_info_template": "Conté tots els documents desats com plantilles i que podeu reutilitzar quan vulgueu crear un nou document.", "fm_info_recent": "Aquests documents s'han modificat o obert darrerament, per vós o per alguna persona col·laboradora.", "fm_info_trash": "Buideu la paperera per alliberar espai al vostre CryptDrive.", - "fm_info_anonymous": "No heu iniciat la sessió, per tant, els vostres documents caducaran d'aquí a 3 mesos (saber-ne més). Es desen al vostre navegador, per tant, si netegeu el vostre historial podríeu perdre'ls.
    Registreu-vos o Inicieu la sessió per mantenir-los accessibles.
    ", + "fm_info_anonymous": "No heu iniciat la sessió, per tant, els vostres documents caducaran d'aquí a 3 mesos. Es desen al vostre navegador, per tant, si netegeu el vostre historial podríeu perdre'ls.
    Registreu-vos o Inicieu la sessió per mantenir-los accessibles.
    ", "fm_info_sharedFolder": "Aquesta és una carpeta compartida. No heu iniciat cap sessió, pel que només podeu accedir en mode només de lectura.
    Registreu-vos o Inicieu la sessió per poder importar-ho al vostre CryptDrive i modificar-ho.", "fm_info_owned": "Es documents que es mostren són de la vostra propietat. Això vol dir que podeu eliminar-los permanentment del servidor quan vulgueu. Si ho feu, la resta de persones no podran accedir-hi mai més.", "fm_error_cantPin": "Error intern del servidor. Si us plau, torneu a garregar la pàgina i torneu a provar-ho.", diff --git a/www/common/translations/messages.el.json b/www/common/translations/messages.el.json index 67c2e30a8..7bbcaf861 100644 --- a/www/common/translations/messages.el.json +++ b/www/common/translations/messages.el.json @@ -224,7 +224,7 @@ "fm_info_template": "Περιέχει όλα τα pads που έχουν αποθηκευτεί ως πρότυπα και μπορείτε να ξαναχρησιμοποιήσετε όταν δημιουργείτε ένα νέο pad.", "fm_info_recent": "Λίστα των πρόσφατα τροποποιημένων ή ανοιγμένων pads.", "fm_info_trash": "Αδειάστε τον κάδο σας για να απελευθερώσετε χώρο στο CryptDrive σας.", - "fm_info_anonymous": "Δεν έχετε συνδεθεί, οπότε τα pads σας θα διαγραφούν μετά από 3 μήνες (μάθετε περισσότερα). Εγγραφείτε ή Συνδεθείτε για να τα κρατήσετε επ' αόριστον.", + "fm_info_anonymous": "Δεν έχετε συνδεθεί, οπότε τα pads σας θα διαγραφούν μετά από 3 μήνες. Εγγραφείτε ή Συνδεθείτε για να τα κρατήσετε επ' αόριστον.", "fm_error_cantPin": "Εσωτερικό σφάλμα διακομιστή. Παρακαλούμε επαναφορτώστε τη σελίδα και προσπαθήστε ξανά.", "fm_viewListButton": "Προβολή λίστας", "fm_viewGridButton": "Προβολή πλέγματος", diff --git a/www/common/translations/messages.it.json b/www/common/translations/messages.it.json index 2910e0ce2..5cade40ab 100644 --- a/www/common/translations/messages.it.json +++ b/www/common/translations/messages.it.json @@ -282,7 +282,7 @@ "fm_info_template": "Contiene tutti i pad salvati come modelli e che puoi riutilizzare per creare nuovi pad.", "fm_info_recent": "Questi pad sono stati recentemente aperti o modificati da te o da persone con le quali tu collabori.", "fm_info_trash": "Svuota il tuo cestino per liberare spazio nel tuo CryptDrive.", - "fm_info_anonymous": "Non hai effettuato l'accesso, quindi i tuoi pad scadranno fra tre mesi (scopri di più). Sono conservati nel tuo browser, quindi cancellando la cronologia potresti farli scomparire.
    Registrati o Accedi per conservarli permanentemente.
    ", + "fm_info_anonymous": "Non hai effettuato l'accesso, quindi i tuoi pad scadranno fra tre mesi. Sono conservati nel tuo browser, quindi cancellando la cronologia potresti farli scomparire.
    Registrati o Accedi per conservarli permanentemente.
    ", "fm_info_sharedFolder": "Questa è una cartella condivisa. Non hai effettuato l'accesso, quindi puoi visualizzarla solo in modalità di sola lettura.
    Registrati o Accedi per poterla importare nel tuo CryptDrive e per modificarla.", "fm_info_owned": "Sei il proprietario dei pad mostrati qui. Questo significa che puoi rimuoverli permanentemente dal server quando lo desideri. Se lo fai, gli altri utenti non potranno più accedervi.", "fm_error_cantPin": "Errore interno del server. Ricarica la pagina e prova di nuovo.", diff --git a/www/common/translations/messages.ro.json b/www/common/translations/messages.ro.json index 0125606ae..0c0fe1f0e 100644 --- a/www/common/translations/messages.ro.json +++ b/www/common/translations/messages.ro.json @@ -118,7 +118,7 @@ "fm_info_root": "Crează câte foldere tip cuib ai nevoie pentru a-ți sorta fișierele.", "fm_info_template": "Conține toate pad-urile stocate ca șabloane și pe care le poți refolosi atunci când creezi un nou pad.", "fm_info_trash": "Fișierele șterse din gunoi vor fi șterse și din \"Toate fișierele\", făcând imposibilă recuperarea fișierelor din managerul de fișiere.", - "fm_info_anonymous": "Nu ești logat cu un cont valid așa că aceste pad-uri vor fi șterse (află de ce). Înscrie-te sau Loghează-te pentru a le salva.", + "fm_info_anonymous": "Nu ești logat cu un cont valid așa că aceste pad-uri vor fi șterse. Înscrie-te sau Loghează-te pentru a le salva.", "fc_newfolder": "Folder nou", "fc_rename": "Redenumește", "fc_open": "Deschide", diff --git a/www/common/translations/messages.ru.json b/www/common/translations/messages.ru.json index 8f08c3f0d..a46232761 100644 --- a/www/common/translations/messages.ru.json +++ b/www/common/translations/messages.ru.json @@ -299,7 +299,7 @@ "printCSS": "Пользовательские настройки вида (CSS):", "viewEmbedTag": "Чтобы встроить данный документ, вставьте iframe в нужную страницу. Вы можете настроить внешний вид используя CSS и HTML атрибуты.", "fm_ownedPadsName": "Собственный", - "fm_info_anonymous": "Вы не вошли в учетную запись, поэтому срок действия ваших пэдов истечет через 3 месяца (find out more). Они хранятся в вашем браузере, поэтому очистка истории может привести к их исчезновению..
    Sign up or Log in to keep them alive.
    ", + "fm_info_anonymous": "Вы не вошли в учетную запись, поэтому срок действия ваших пэдов истечет через 3 месяца. Они хранятся в вашем браузере, поэтому очистка истории может привести к их исчезновению..
    Sign up or Log in to keep them alive.", "fm_burnThisDriveButton": "Удалить всю информацию, хранящуюся от CryptPad в браузере", "fm_tags_used": "Количество использований", "fm_restoreDrive": "Восстановление прежнего состояния диска. Для достижения наилучших результатов не вносите изменения в диск, пока этот процесс не будет завершен.", From 575269e5a1fbcc7d5b96e47f7ca50ad77905326e Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 13:08:35 +0530 Subject: [PATCH 064/117] use a standard function for creating basic media-tags --- www/code/inner.js | 2 +- www/common/common-interface.js | 9 +++++++++ www/common/diffMarked.js | 1 - www/common/inner/common-mediatag.js | 5 ++--- www/common/sframe-app-framework.js | 4 ++-- www/common/sframe-common.js | 3 +-- www/kanban/inner.js | 2 +- www/poll/inner.js | 4 ++-- www/slide/inner.js | 2 +- 9 files changed, 19 insertions(+), 13 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index d74513035..785e82788 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -507,7 +507,7 @@ define([ var fileHost = privateData.fileHost || privateData.origin; var src = fileHost + Hash.getBlobPathFromHex(secret.channel); var key = Hash.encodeBase64(secret.keys.cryptKey); - var mt = ''; + var mt = UI.mediaTag(src, key).outerHTML; editor.replaceSelection(mt); } }; diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 9bdf9ec7a..4d3520426 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -41,6 +41,15 @@ define([ return e; }; + // FIXME almost everywhere this is used would also be + // a good candidate for sframe-common's getMediatagFromHref + UI.mediaTag = function (src, key) { + return h('media-tag', { + src: src, + 'data-crypto-key': 'cryptpad:' + key, + }); + }; + var findCancelButton = UI.findCancelButton = function (root) { if (root) { return $(root).find('button.cancel').last(); diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index d7c476a90..52a8cf0a1 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -676,7 +676,6 @@ define([ if (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3) { var type = el.getAttribute('data-plugin'); var plugin = plugins[type]; - console.log(type); if (!plugin) { return; } var src = canonicalizeMermaidSource(el.childNodes[0].wholeText); el.setAttribute(plugin.attr, src); diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 966724fa1..b8550fcac 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -127,9 +127,8 @@ define([ if (e || !data) { return void displayDefault(); } if (typeof data !== "number") { return void displayDefault(); } if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); } - var $img = $('').appendTo($container); - $img.attr('src', src); - $img.attr('data-crypto-key', 'cryptpad:' + cryptKey); + var mt = UI.mediaTag(src, cryptKey); + var $img = $(mt).appendTo($container); MT.displayMediatagImage(common, $img, function (err, $image) { if (err) { return void console.error(err); } centerImage($img, $image); diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 796640f6d..0fd250f80 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -748,8 +748,8 @@ define([ var privateDat = cpNfInner.metadataMgr.getPrivateData(); var origin = privateDat.fileHost || privateDat.origin; var src = data.src = data.src.slice(0,1) === '/' ? origin + data.src : data.src; - mediaTagEmbedder($(''), data); + var mt = UI.mediaTag(src, data.key); + mediaTagEmbedder($(mt), data); }); }).appendTo(toolbar.$bottomL).hide(); }; diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 3fd4869d1..5d3738cbb 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -145,8 +145,7 @@ define([ var hexFileName = secret.channel; var origin = data.fileHost || data.origin; var src = origin + Hash.getBlobPathFromHex(hexFileName); - return '' + - ''; + return UI.mediaTag(src, key).outerHTML; } return; }; diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 8eb090ffc..4832adcca 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -289,7 +289,7 @@ define([ var fileHost = privateData.fileHost || privateData.origin; var src = fileHost + Hash.getBlobPathFromHex(secret.channel); var key = Hash.encodeBase64(secret.keys.cryptKey); - var mt = ''; + var mt = UI.mediaTag(src, key).outerHTML; editor.replaceSelection(mt); } }; diff --git a/www/poll/inner.js b/www/poll/inner.js index 6d4e0590e..53faea7e9 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -955,7 +955,7 @@ define([ var fileHost = privateData.fileHost || privateData.origin; var src = fileHost + Hash.getBlobPathFromHex(secret.channel); var key = Hash.encodeBase64(secret.keys.cryptKey); - var mt = ''; + var mt = UI.mediaTag(src, key).outerHTML; APP.editor.replaceSelection(mt); } }; @@ -1235,7 +1235,7 @@ define([ common.openFilePicker(pickerCfg, function (data) { if (data.type === 'file' && APP.editor) { common.setPadAttribute('atime', +new Date(), null, data.href); - var mt = ''; + var mt = UI.mediaTag(data.src, data.key).outerHTML; APP.editor.replaceSelection(mt); return; } diff --git a/www/slide/inner.js b/www/slide/inner.js index 3eb1435ed..e40bd6d79 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -556,7 +556,7 @@ define([ var fileHost = privateData.fileHost || privateData.origin; var src = fileHost + Hash.getBlobPathFromHex(secret.channel); var key = Hash.encodeBase64(secret.keys.cryptKey); - var mt = ''; + var mt = UI.mediaTag(src, key).outerHTML; editor.replaceSelection(mt); } }; From 7d634ab54b90a0e1efe28edb48dd13d17ee6038b Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 13:58:17 +0530 Subject: [PATCH 065/117] suppress 'convert' from new pad modal and make it easy to configure what's displayed via a list in appconfig --- www/common/application_config_internal.js | 6 ++++++ www/common/common-ui-elements.js | 10 ++-------- www/common/drive-ui.js | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 68ba4ed06..971da32ee 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -22,6 +22,12 @@ define(function() { */ AppConfig.registeredOnlyTypes = ['file', 'contacts', 'notifications', 'support']; + // XXX to prevent apps that aren't officially supported from showing up + // in the document creation modal + AppConfig.hiddenTypes = ['drive', 'teams', 'contacts', 'todo', 'file', 'accounts', 'calendar', 'poll', 'convert', + //'doc', 'presentation' + ]; + /* CryptPad is available is multiple languages, but only English and French are maintained * by the developers. The other languages may be outdated, and any missing string for a langauge * will use the english version instead. You can customize the langauges you want to be available diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 3e27b4ee7..a7ef39de6 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2075,15 +2075,9 @@ define([ var $container = $('
    '); var i = 0; + var types = AppConfig.availablePadTypes.filter(function (p) { - if (p === 'drive') { return; } - if (p === 'teams') { return; } - if (p === 'contacts') { return; } - if (p === 'todo') { return; } - if (p === 'file') { return; } - if (p === 'accounts') { return; } - if (p === 'calendar') { return; } - if (p === 'poll') { return; } // Replaced by forms + if (AppConfig.hiddenTypes.indexOf(p) !== -1) { return; } if (!common.isLoggedIn() && AppConfig.registeredOnlyTypes && AppConfig.registeredOnlyTypes.indexOf(p) !== -1) { return; } return true; diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 4a75459a5..0db7018eb 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -3082,6 +3082,7 @@ define([ } // Pads getNewPadTypes().forEach(function (type) { + if (AppConfig.hiddenTypes.indexOf(type) !== -1) { return; } var $element = $('
  • ', { 'class': 'cp-app-drive-new-doc cp-app-drive-element-row ' + 'cp-app-drive-element-grid' From 899eef1ee87d7ddb013efba8f849c36ba9a1b0a8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 14:01:43 +0530 Subject: [PATCH 066/117] filter hidden types from a more sensible place in the drive --- www/common/drive-ui.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index 0db7018eb..e079ad2b9 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -2571,14 +2571,7 @@ define([ var getNewPadTypes = function () { var arr = []; AppConfig.availablePadTypes.forEach(function (type) { - if (type === 'drive') { return; } - if (type === 'teams') { return; } - if (type === 'contacts') { return; } - if (type === 'todo') { return; } - if (type === 'file') { return; } - if (type === 'accounts') { return; } - if (type === 'calendar') { return; } - if (type === 'poll') { return; } // replaced by forms + if (AppConfig.hiddenTypes.indexOf(type) !== -1) { return; } if (!APP.loggedIn && AppConfig.registeredOnlyTypes && AppConfig.registeredOnlyTypes.indexOf(type) !== -1) { return; @@ -3082,7 +3075,6 @@ define([ } // Pads getNewPadTypes().forEach(function (type) { - if (AppConfig.hiddenTypes.indexOf(type) !== -1) { return; } var $element = $('
  • ', { 'class': 'cp-app-drive-new-doc cp-app-drive-element-row ' + 'cp-app-drive-element-grid' From 3b44c09bc4b0bfe4c9b7933142fd0f5c660cfeaf Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 16:42:09 +0530 Subject: [PATCH 067/117] check COOP headers for multiple endpoints and improve some error reporting in the checkup RPC --- docs/example.nginx.conf | 2 +- server.js | 2 +- www/checkup/main.js | 30 ++++++++++++++++++++++++++++++ www/checkup/sandbox/main.js | 12 +++++++++--- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/docs/example.nginx.conf b/docs/example.nginx.conf index 29317ee27..8bc47d9f8 100644 --- a/docs/example.nginx.conf +++ b/docs/example.nginx.conf @@ -64,7 +64,7 @@ server { add_header Permissions-Policy interest-cohort=(); set $coop ''; - if ($uri ~ ^\/(sheet|presentation|doc)\/.*$) { set $coop 'same-origin'; } + if ($uri ~ ^\/(sheet|presentation|doc|convert)\/.*$) { set $coop 'same-origin'; } # Enable SharedArrayBuffer in Firefox (for .xlsx export) add_header Cross-Origin-Resource-Policy cross-origin; diff --git a/server.js b/server.js index 848167a98..3cea171c6 100644 --- a/server.js +++ b/server.js @@ -90,7 +90,7 @@ var setHeaders = (function () { return function (req, res) { // apply a bunch of cross-origin headers for XLSX export in FF and printing elsewhere applyHeaderMap(res, { - "Cross-Origin-Opener-Policy": /^\/sheet\//.test(req.url)? 'same-origin': '', + "Cross-Origin-Opener-Policy": /^\/(sheet|presentation|doc|convert)\//.test(req.url)? 'same-origin': '', }); if (Env.NO_SANDBOX) { // handles correct configuration for local development diff --git a/www/checkup/main.js b/www/checkup/main.js index 732197a2d..143d1709b 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -732,6 +732,36 @@ define([ cb(isHTTPS(trimmedUnsafe) && isHTTPS(trimmedSafe)); }); + + [ + 'sheet', + 'presentation', + 'doc', + 'convert', + ].forEach(function (url) { + assert(function (cb, msg) { + var header = 'cross-origin-opener-policy'; + var expected = 'same-origin'; + deferredPostMessage({ + command: 'GET_HEADER', + content: { + url: '/' + url + '/', + header: header, + } + }, function (content) { + msg.appendChild(h('span', [ + code(url), + ' was served without the correct ', + code(header), + ' HTTP header value (', + code(expected), + '). This will interfere with your ability to convert between office file formats.' + ])); + cb(content === expected); + }); + }); + }); + /* assert(function (cb, msg) { setWarningClass(msg); diff --git a/www/checkup/sandbox/main.js b/www/checkup/sandbox/main.js index 7ddfb07f8..e11aa1d52 100644 --- a/www/checkup/sandbox/main.js +++ b/www/checkup/sandbox/main.js @@ -27,12 +27,14 @@ define([ }; window.addEventListener("message", function (event) { + var txid, command; if (event && event.data) { try { //console.log(JSON.parse(event.data)); var msg = JSON.parse(event.data); - var command = msg.command; - var txid = msg.txid; + command = msg.command; + txid = msg.txid; + if (!txid) { return; } COMMANDS[command](msg.content, function (response) { // postMessage with same txid postMessage({ @@ -41,7 +43,11 @@ define([ }); }); } catch (err) { - console.error(err); + postMessage({ + txid: txid, + content: err, + }); + console.error(err, command); } } else { console.error(event); From 1c1dc421a324fd6c5b60a0aee8af97e8761fdbdd Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 16:44:40 +0530 Subject: [PATCH 068/117] fix broken block archival --- lib/commands/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/commands/block.js b/lib/commands/block.js index ea6a19dc2..195e0c494 100644 --- a/lib/commands/block.js +++ b/lib/commands/block.js @@ -167,7 +167,7 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { }); }; -const DELETE_BLOCK = Nacl.util.decodeUTF8('DELETE_BLOCK'); +const DELETE_BLOCK = Nacl.util.encodeBase64(Nacl.util.decodeUTF8('DELETE_BLOCK')); /* When users write a block, they upload the block, and provide From 279db28e86e0c2cab14ab0e2a14153cc7774efa2 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 18:44:35 +0530 Subject: [PATCH 069/117] start tracking the versions of our vendored software --- www/lib/changelog.md | 4 + www/lib/turndown.browser.umd.js | 135 ++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 59 deletions(-) create mode 100644 www/lib/changelog.md diff --git a/www/lib/changelog.md b/www/lib/changelog.md new file mode 100644 index 000000000..86ef6ec22 --- /dev/null +++ b/www/lib/changelog.md @@ -0,0 +1,4 @@ +This file is intended to be used as a log of what third-party source we have vendored, where we got it, and what modifications we have made to it (if any). + +* [turndown v7.1.1](https://github.com/mixmark-io/turndown/releases/tag/v7.1.1) built from unmodified source as per its build scripts. + diff --git a/www/lib/turndown.browser.umd.js b/www/lib/turndown.browser.umd.js index 9b8c40d13..a812101ae 100644 --- a/www/lib/turndown.browser.umd.js +++ b/www/lib/turndown.browser.umd.js @@ -1,7 +1,7 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global.TurndownService = factory()); + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.TurndownService = factory()); }(this, (function () { 'use strict'; function extend (destination) { @@ -18,6 +18,17 @@ return Array(count + 1).join(character) } + function trimLeadingNewlines (string) { + return string.replace(/^\n*/, '') + } + + function trimTrailingNewlines (string) { + // avoid match-at-end regexp bottleneck, see #370 + var indexEnd = string.length; + while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; + return string.substring(0, indexEnd) + } + var blockElements = [ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', @@ -303,19 +314,15 @@ }, replacement: function (content) { - if (!content.trim()) return '' + if (!content) return '' + content = content.replace(/\r?\n|\r/g, ' '); + var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; var delimiter = '`'; - var leadingSpace = ''; - var trailingSpace = ''; - var matches = content.match(/`+/gm); - if (matches) { - if (/^`/.test(content)) leadingSpace = ' '; - if (/`$/.test(content)) trailingSpace = ' '; - while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; - } + var matches = content.match(/`+/gm) || []; + while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; - return delimiter + leadingSpace + content + trailingSpace + delimiter + return delimiter + extraSpace + content + extraSpace + delimiter } }; @@ -459,7 +466,7 @@ if (!element.firstChild || isPre(element)) return var prevText = null; - var prevVoid = false; + var keepLeadingWs = false; var prev = null; var node = next(prev, element, isPre); @@ -469,7 +476,7 @@ var text = node.data.replace(/[ \r\n\t]+/g, ' '); if ((!prevText || / $/.test(prevText.data)) && - !prevVoid && text[0] === ' ') { + !keepLeadingWs && text[0] === ' ') { text = text.substr(1); } @@ -489,11 +496,14 @@ } prevText = null; - prevVoid = false; - } else if (isVoid(node)) { - // Avoid trimming space around non-block, non-BR void elements. + keepLeadingWs = false; + } else if (isVoid(node) || isPre(node)) { + // Avoid trimming space around non-block, non-BR void elements and inline PRE. prevText = null; - prevVoid = true; + keepLeadingWs = true; + } else if (prevText) { + // Drop protection if set previously. + keepLeadingWs = false; } } else { node = remove(node); @@ -609,7 +619,7 @@ var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser(); - function RootNode (input) { + function RootNode (input, options) { var root; if (typeof input === 'string') { var doc = htmlParser().parseFromString( @@ -626,7 +636,8 @@ collapseWhitespace({ element: root, isBlock: isBlock, - isVoid: isVoid + isVoid: isVoid, + isPre: options.preformattedCode ? isPreOrCode : null }); return root @@ -638,11 +649,15 @@ return _htmlParser } - function Node (node) { + function isPreOrCode (node) { + return node.nodeName === 'PRE' || node.nodeName === 'CODE' + } + + function Node (node, options) { node.isBlock = isBlock(node); - node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode; + node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; node.isBlank = isBlank(node); - node.flankingWhitespace = flankingWhitespace(node); + node.flankingWhitespace = flankingWhitespace(node, options); return node } @@ -656,28 +671,39 @@ ) } - function flankingWhitespace (node) { - var leading = ''; - var trailing = ''; + function flankingWhitespace (node, options) { + if (node.isBlock || (options.preformattedCode && node.isCode)) { + return { leading: '', trailing: '' } + } - if (!node.isBlock) { - var hasLeading = /^\s/.test(node.textContent); - var hasTrailing = /\s$/.test(node.textContent); - var blankWithSpaces = node.isBlank && hasLeading && hasTrailing; + var edges = edgeWhitespace(node.textContent); - if (hasLeading && !isFlankedByWhitespace('left', node)) { - leading = ' '; - } + // abandon leading ASCII WS if left-flanked by ASCII WS + if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { + edges.leading = edges.leadingNonAscii; + } - if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) { - trailing = ' '; - } + // abandon trailing ASCII WS if right-flanked by ASCII WS + if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { + edges.trailing = edges.trailingNonAscii; } - return { leading: leading, trailing: trailing } + return { leading: edges.leading, trailing: edges.trailing } } - function isFlankedByWhitespace (side, node) { + function edgeWhitespace (string) { + var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); + return { + leading: m[1], // whole string for whitespace-only strings + leadingAscii: m[2], + leadingNonAscii: m[3], + trailing: m[4], // empty for whitespace-only strings + trailingNonAscii: m[5], + trailingAscii: m[6] + } + } + + function isFlankedByWhitespace (side, node, options) { var sibling; var regExp; var isFlanked; @@ -693,6 +719,8 @@ if (sibling) { if (sibling.nodeType === 3) { isFlanked = regExp.test(sibling.nodeValue); + } else if (options.preformattedCode && sibling.nodeName === 'CODE') { + isFlanked = false; } else if (sibling.nodeType === 1 && !isBlock(sibling)) { isFlanked = regExp.test(sibling.textContent); } @@ -701,8 +729,6 @@ } var reduce = Array.prototype.reduce; - var leadingNewLinesRegExp = /^\n*/; - var trailingNewLinesRegExp = /\n*$/; var escapes = [ [/\\/g, '\\\\'], [/\*/g, '\\*'], @@ -734,6 +760,7 @@ linkStyle: 'inlined', linkReferenceStyle: 'full', br: ' ', + preformattedCode: false, blankReplacement: function (content, node) { return node.isBlock ? '\n\n' : '' }, @@ -766,7 +793,7 @@ if (input === '') return '' - var output = process.call(this, new RootNode(input)); + var output = process.call(this, new RootNode(input, this.options)); return postProcess.call(this, output) }, @@ -855,7 +882,7 @@ function process (parentNode) { var self = this; return reduce.call(parentNode.childNodes, function (output, node) { - node = new Node(node); + node = new Node(node, self.options); var replacement = ''; if (node.nodeType === 3) { @@ -908,31 +935,21 @@ } /** - * Determines the new lines between the current output and the replacement + * Joins replacement to the current output with appropriate number of new lines * @private * @param {String} output The current conversion output * @param {String} replacement The string to append to the output - * @returns The whitespace to separate the current output and the replacement + * @returns Joined output * @type String */ - function separatingNewlines (output, replacement) { - var newlines = [ - output.match(trailingNewLinesRegExp)[0], - replacement.match(leadingNewLinesRegExp)[0] - ].sort(); - var maxNewlines = newlines[newlines.length - 1]; - return maxNewlines.length < 2 ? maxNewlines : '\n\n' - } - - function join (string1, string2) { - var separator = separatingNewlines(string1, string2); - - // Remove trailing/leading newlines and replace with separator - string1 = string1.replace(trailingNewLinesRegExp, ''); - string2 = string2.replace(leadingNewLinesRegExp, ''); + function join (output, replacement) { + var s1 = trimTrailingNewlines(output); + var s2 = trimLeadingNewlines(replacement); + var nls = Math.max(output.length - s1.length, replacement.length - s2.length); + var separator = '\n\n'.substring(0, nls); - return string1 + separator + string2 + return s1 + separator + s2 } /** From eaf80b731728e33d511686421481988bf759ac6d Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 1 Jul 2021 18:44:50 +0530 Subject: [PATCH 070/117] update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18fd928a0..d74a37dc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * display actual FLoC header in checkup test * WIP check for `server_tokens` settings (needs work for HTTP2) * nicer output in error/warning tables + * more tests for Cross-Origin-Opener-Policy headers * form templates * guard against a type error in `getAccessKeys` * guard against invalid or malicious input when constructing media-tags for embedding in markdown @@ -26,7 +27,7 @@ * conversions * convert app * some basic office formats - * rich text => markdown + * rich text => markdown (via turndown.js v7.1.1) * handle some pecularities with headings and ids * forms => .csv * trello import with some loss @@ -35,7 +36,6 @@ * catch errors thrown by the diff applier * don't bother returning the hash of a pin list to the client, since they don't use it - # 4.7.0 ## Goals From 68e489a2a3acb17dac55631e147cf9e575169299 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 2 Jul 2021 07:34:59 +0200 Subject: [PATCH 071/117] Translated using Weblate (Japanese) Currently translated at 95.6% (1307 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.6% (1307 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.6% (1307 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 3343d8873..749a5c184 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -503,7 +503,7 @@ "slide_backCol": "背景色", "code_editorTheme": "エディターのテーマ", "unknownPad": "不明なパッド", - "admin_openFilesTitle": "ファイルを開く", + "admin_openFilesTitle": "開かれているファイル", "kanban_conflicts": "編集中:", "kanban_noTags": "タグがありません", "historyTrim_historySize": "履歴: {0}", @@ -1022,7 +1022,7 @@ "canvas_imageEmbed": "コンピューターの画像を埋め込む", "canvas_currentBrush": "現在のブラシ", "poll_total": "合計", - "kanban_todo": "タスク", + "kanban_todo": "未着手", "slide_invalidLess": "ユーザー定義のスタイルは無効です", "printCSS": "ユーザー定義のスタイルルール(CSS):", "admin_provideAggregateStatisticsHint": "追加の利用状況を開発者に提供することも選択できます。追加の情報には、あなたのインスタンスのおおよその登録ユーザー数や一日あたりのユーザー数などがあります。", @@ -1306,5 +1306,7 @@ "share_embedPasswordAlert": "この項目はパスワードで保護されています。このパッドを埋め込む際、閲覧にはパスワードの入力が必要となります。", "share_contactPasswordAlert": "この項目はパスワードで保護されています。CryptPadの連絡先と共有するため、相手がパスワードを入力する必要はありません。", "share_linkPasswordAlert": "この項目はパスワードで保護されています。リンクを受け取った相手はパスワードを入力する必要があります。", - "register_notes_title": "重要な注意事項" + "register_notes_title": "重要な注意事項", + "teams_table_specificHint": "以前のバージョンの共有フォルダでは、閲覧者は既存のパッドを変更することができます。 これらのフォルダで作成またはコピーしたパッドには、標準の権限が与えられます。", + "broadcast_maintenance": "{0}から{1}の間でメンテナンスを予定しています。その間CryptPadは使用できません。" } From edc1e95ffe659a5812eccf77a2bbe504c85426cb Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 2 Jul 2021 08:42:03 +0200 Subject: [PATCH 072/117] Translated using Weblate (Japanese) Currently translated at 95.8% (1309 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.7% (1308 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.6% (1307 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.6% (1307 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 749a5c184..977211485 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -1061,7 +1061,7 @@ "form_poll_hint": ": はい、: いいえ、: 可", "admin_provideAggregateStatisticsLabel": "集計済みの統計を提供", "admin_provideAggregateStatisticsTitle": "統計による集計", - "admin_blockDailyCheckHint": "以後CryptPadのインスタンスは、1日に1回、CryptPadの開発者のサーバーにメッセージを送信します。開発者はそれをもとに、CryptPadのバージョンごとのサーバー数を追跡することができます。以下からこの測定をオプトアプトできます。なお、送信されるメッセージの内容は、確認用として、アプリケーションのサーバーのログに記録されます。", + "admin_blockDailyCheckHint": "CryptPadのインスタンスは、1日に1度、開発者のサーバーにメッセージを送信するよう設定されています。開発者はそれをもとに、CryptPadのバージョンごとのサーバー数を追跡しています。以下からこの測定をオプトアプトできます。なお、送信されるメッセージの内容は、確認用として、アプリケーションのサーバーのログに記録されます。", "admin_listMyInstanceHint": "あなたのインスタンスが誰でも利用できる場合、同意によってウェブディレクトリに表示できます。その際は、サーバーのテレメトリーが有効になっている必要があります。", "settings_driveRedirectTitle": "ホームページにリダイレクト", "form_defaultItem": "項目{0}", @@ -1203,7 +1203,7 @@ "admin_diskUsageHint": "CryptPadのリソースが消費しているストレージ容量", "timeoutError": "エラーが発生してサーバーへの接続が切断されました。
    Escキーを押してページをリロードしてください。", "footer_team": "貢献者", - "admin_updateLimitHint": "ユーザーのストレージ制限の強制アップデートはいつでも可能ですが、エラーが発生したときのみ必須となります", + "admin_updateLimitHint": "ユーザーのストレージ制限の強制アップデートはいつでも可能です。エラーが発生したときは必須となります", "admin_cat_general": "全般", "poll_bookmarked_col": "列をブックマークしました。常に編集可能な仕方で左端に表示されます。", "poll_bookmark_col": "この列をブックマークすると、常に編集可能な仕方で左端に表示されます", @@ -1229,7 +1229,7 @@ "owner_team_add": "{0}があなたをチーム({1})のオーナーにしようとしています。承諾しますか?", "friendRequest_accepted": "{0}が連絡先リクエストを承諾しました", "friendRequest_accept": "承諾(Enter)", - "admin_flushCacheHint": "サーバーから最新のコンテンツをダウンロードするようユーザーに強制(サーバーが「フレッシュ」モードの場合のみ)", + "admin_flushCacheHint": "サーバーから最新のコンテンツをダウンロードするようユーザーに強制(サーバーがフレッシュモードの場合のみ)", "admin_activeSessionsHint": "アクティブなwebsocketの接続(および接続する一意のIPアドレス)の数", "convertFolderToSF_SFParent": "このフォルダは別の共有フォルダ内にあるため、共有フォルダに変換できません。続行するには、外部に移動してください。", "settings_deleteWarning": "注意:現在、プレミアムプランに加入しています(別のユーザーが支払いまたは提供)。アカウントを削除する前に、プランをキャンセルしてください。アカウントを削除すると、サポートに連絡しないとキャンセルできなくなります。", @@ -1308,5 +1308,7 @@ "share_linkPasswordAlert": "この項目はパスワードで保護されています。リンクを受け取った相手はパスワードを入力する必要があります。", "register_notes_title": "重要な注意事項", "teams_table_specificHint": "以前のバージョンの共有フォルダでは、閲覧者は既存のパッドを変更することができます。 これらのフォルダで作成またはコピーしたパッドには、標準の権限が与えられます。", - "broadcast_maintenance": "{0}から{1}の間でメンテナンスを予定しています。その間CryptPadは使用できません。" + "broadcast_maintenance": "{0}から{1}の間でメンテナンスを予定しています。その間CryptPadは使用できません。", + "admin_archiveHint": "ドキュメントを完全削除することなく、利用できないよう設定できます。「アーカイブ」フォルダに移動し、数日後に削除します(期間については設定ファイルより設定できます)。", + "admin_unarchiveHint": "アーカイブされたドキュメントを復元できます" } From 29d2fb38efc9b7a29cac0820616a08c8d30ab391 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 2 Jul 2021 12:41:34 +0530 Subject: [PATCH 073/117] trim leading and trailing whitespace from usernames when registering --- www/register/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/register/main.js b/www/register/main.js index 4c63e4482..4d9274253 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -47,7 +47,11 @@ define([ var I_REALLY_WANT_TO_USE_MY_EMAIL_FOR_MY_USERNAME = false; var registerClick = function () { - var uname = $uname.val(); + var uname = $uname.val().trim(); + // trim whitespace surrounding the username since it is otherwise included in key derivation + // most people won't realize that its presence is significant + $uname.val(uname); + var passwd = $passwd.val(); var confirmPassword = $confirm.val(); From 568ced1b7f5909a9a1f063cb2c61b3feff51ca09 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 2 Jul 2021 11:17:00 +0200 Subject: [PATCH 074/117] Translated using Weblate (Japanese) Currently translated at 97.5% (1332 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 97.4% (1331 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 97.2% (1329 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.9% (1324 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.9% (1324 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.8% (1323 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.7% (1322 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.7% (1321 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.6% (1320 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.5% (1319 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.5% (1319 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.5% (1319 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.4% (1318 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.4% (1317 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.4% (1317 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.3% (1316 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.2% (1315 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.1% (1314 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.1% (1314 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.1% (1313 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 96.0% (1312 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.9% (1311 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 95.9% (1310 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 45 ++++++++++++++++++------ 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 977211485..4d02d98c6 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -173,7 +173,7 @@ "teams_table_generic": "権限一覧", "teams_table": "権限", "contacts_fetchHistory": "古い履歴を取得する", - "contacts_warning": "ここに入力したすべてのメッセージは永続的であり、このパッドの現在および将来のすべてのユーザーが利用できます。機密情報の入力は推奨されません!", + "contacts_warning": "ここに入力したすべてのメッセージは永続的であり、このパッドの現在および将来のすべてのユーザーが確認できます。機密情報の入力には注意してください!", "contacts_typeHere": "ここにメッセージを入力...", "team_cat_drive": "ドライブ", "team_cat_chat": "チャット", @@ -454,7 +454,7 @@ "upload_choose": "ファイルを選択", "form_page": "{0}/{1}ページ", "form_addMultiple": "全て追加", - "admin_consentToContactLabel": "同意", + "admin_consentToContactLabel": "同意する", "admin_updateAvailableButton": "リリースノートを見る", "admin_updateAvailableHint": "CryptPadの新しいバージョンが利用可能です", "admin_updateAvailableTitle": "新しいバージョン", @@ -475,7 +475,7 @@ "poll_create_option": "新しいオプションを追加", "poll_create_user": "新しいユーザーを追加", "pad_mediatagImport": "あなたのCryptDriveに保存", - "admin_listMyInstanceLabel": "このインスタンスをリストに表示", + "admin_listMyInstanceLabel": "このインスタンスをリストに表示する", "admin_checkupTitle": "インスタンスの設定を検証", "cba_disable": "消去して無効にする", "upload_pending": "保留中", @@ -483,7 +483,7 @@ "chrome68": "バージョン68のChromeあるいはChromiumを使用しているようです。このバージョンには、数秒経過した後でページが白紙になったり、クリックにページが反応しなくなったりするバグがあります。この問題を解決するには、別のタブを表示して改めて表示するか、このページでスクロールを試みてください。このバグは次のバージョンで解決される予定となっています。", "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • 未ログインで作成、共有したファイルを保存するには、 「匿名セッションのドキュメントをインポート」にチェックをしてください。
    ", "poll_commit": "送信", - "admin_removeDonateButtonTitle": "クラウドファンディングに参加", + "admin_removeDonateButtonTitle": "クラウドファンディングへの参加", "mediatag_notReady": "ダウンロードを完了してください", "pad_mediatagOpen": "ファイルを開く", "pad_mediatagShare": "ファイルを共有", @@ -560,7 +560,7 @@ "form_form": "フォーム", "form_editor": "エディタ", "form_delete": "削除", - "form_sent": "送信済", + "form_sent": "送信しました", "form_reset": "リセット", "form_update": "更新", "form_submit": "送信", @@ -1046,7 +1046,7 @@ "register_emailWarning0": "ユーザー名にメールアドレスが入力されています。", "fm_tags_used": "使用数", "fm_deletedPads": "これらのパッドはサーバーにありません。あなたのCryptDriveから削除されています: {0}", - "fm_renamedPad": "このパッドにユーザー定義の名前を設定しました。共有のファイル名は
    {0}", + "fm_renamedPad": "このパッドにユーザー定義の名前を設定しました。共有のファイル名は「{0}」です", "fm_ownedPadsName": "所有", "burnAfterReading_generateLink": "下のボタンをクリックするとリンクを生成します。", "fm_restricted": "アクセス権がありません", @@ -1062,11 +1062,11 @@ "admin_provideAggregateStatisticsLabel": "集計済みの統計を提供", "admin_provideAggregateStatisticsTitle": "統計による集計", "admin_blockDailyCheckHint": "CryptPadのインスタンスは、1日に1度、開発者のサーバーにメッセージを送信するよう設定されています。開発者はそれをもとに、CryptPadのバージョンごとのサーバー数を追跡しています。以下からこの測定をオプトアプトできます。なお、送信されるメッセージの内容は、確認用として、アプリケーションのサーバーのログに記録されます。", - "admin_listMyInstanceHint": "あなたのインスタンスが誰でも利用できる場合、同意によってウェブディレクトリに表示できます。その際は、サーバーのテレメトリーが有効になっている必要があります。", + "admin_listMyInstanceHint": "あなたのインスタンスが誰でも利用できる場合、同意によってウェブディレクトリに表示できます。表示には、サーバーのテレメトリーが有効になっている必要があります。", "settings_driveRedirectTitle": "ホームページにリダイレクト", "form_defaultItem": "項目{0}", "form_defaultOption": "オプション{0}", - "form_answerAnonymous": "{0}についての匿名の回答", + "form_answerAnonymous": "{0}に匿名の回答", "form_maxLength": "文字数制限: {0}/{1}", "form_textType": "テキストの種類", "form_pollYourAnswers": "あなたの回答", @@ -1215,7 +1215,7 @@ "form_anonymous_off": "ブロック", "admin_checkupHint": "CryptPadには、一般的な構成に関する問題を自動で診断し、必要に応じてそれらを修正する方法を提案するページがあります。", "admin_broadcastTitle": "メッセージを送信", - "admin_broadcastHint": "このインスタンスの全ユーザーにメッセージを送信します。ユーザーはメッセージを通知で受け取ります。「通知をプレビュー」で送信前のメッセージを確認できます。通知のプレビューには赤いアイコンがあり、あなたにだけ表示されます。", + "admin_broadcastHint": "このインスタンスの全ユーザーにメッセージを送信します。ユーザーはメッセージを通知で受け取ります。送信前のメッセージは「通知をプレビュー」から確認できます。プレビューには赤いアイコンが付いており、プレビューはあなたの通知画面にのみ表示されます。", "calendar_before": "以前", "share_formAuditor": "監査人", "form_editMax": "選択できるオプションの最大数", @@ -1245,7 +1245,7 @@ "docs_link": "ドキュメンテーション", "admin_support_collapse": "折りたたむ", "team_inviteFrom": "送信元:", - "admin_supportInitHint": "サポートのメールボックスを設定すれば、あなたのCryptPadのインスタンスのユーザーが、アカウントから安全に問い合わせを行うことができるようになります。", + "admin_supportInitHint": "サポートのメールボックスを設定すると、あなたのCryptPadのインスタンスのユーザーが、アカウントから安全に問い合わせを行うことができるようになります。", "isNotContact": "{0}はあなたの連絡先ではありません", "isContact": "{0}はあなたの連絡先です", "profile_info": "他のユーザーは、ドキュメントのユーザーリストであなたのアバターをクリックして、あなたのプロフィールを確認できます。", @@ -1310,5 +1310,28 @@ "teams_table_specificHint": "以前のバージョンの共有フォルダでは、閲覧者は既存のパッドを変更することができます。 これらのフォルダで作成またはコピーしたパッドには、標準の権限が与えられます。", "broadcast_maintenance": "{0}から{1}の間でメンテナンスを予定しています。その間CryptPadは使用できません。", "admin_archiveHint": "ドキュメントを完全削除することなく、利用できないよう設定できます。「アーカイブ」フォルダに移動し、数日後に削除します(期間については設定ファイルより設定できます)。", - "admin_unarchiveHint": "アーカイブされたドキュメントを復元できます" + "admin_unarchiveHint": "アーカイブされたドキュメントを復元できます", + "admin_registrationTitle": "登録を締め切る", + "admin_defaultlimitHint": "ユーザー定義のルールが適用されていない際の最大のストレージ容量(ユーザーとチームについて)を設定できます", + "admin_limit": "現在の制限: {0}", + "admin_getquotaHint": "ユーザーもしくはチームの公開鍵を入力して、設定されているクォータに対するストレージの使用量を確認できます。", + "admin_openFilesHint": "サーバー上で現在開いているファイル記述子の数", + "admin_support_premium": "プレミアムチケット:", + "admin_maintenanceHint": "このインスタンスのメンテナンスの日程を設定し、ユーザーに通知を送ることができます。メンテナンスの日程を複数設定することはできません。", + "admin_surveyHint": "外部サイトで行うアンケートのリンクを追加、更新、削除できます。ユーザーには通知が送信され、アンケートはユーザーのメニューから開くことができます。", + "broadcast_defaultLanguage": "この言語にフォールバック", + "admin_performanceProfilingHint": "サーバー側でコマンドを実行する際に掛かった合計時間の一覧です", + "admin_consentToContactHint": "サーバーのテレメトリーには、ソフトウェアや設定に関する重大な問題が発生した際に開発者が連絡できるよう、管理者の連絡先のメールアドレスが含まれます。メールアドレスが共有、売却、マーケティングの目的で使用されることはありません。サーバーに重大な問題が発生した際に連絡を希望する場合は、「同意する」にチェックをつけてください。", + "admin_removeDonateButtonHint": "CryptPadの開発の一部は、公的な助成金と寄付金によってまかなわれています。クラウドファンディングに関する宣伝をあなたのインスタンスで行うことで、開発者が万人のためにプラットフォームを改良することへの支援につながります。ただし、もし宣伝が不適切な場合は、宣伝を無効にすることもできます。", + "admin_performanceTimeHeading": "時間(秒)", + "team_maxTeams": "それぞれのユーザーアカウントがメンバーになることができるのは、最大{0}チームまでです。", + "team_listSlot": "利用可能なチームのスロット", + "resources_learnWhy": "ブロックした理由について", + "admin_purpose_business": "ビジネス・営利団体での使用", + "admin_purpose_education": "教育機関での使用", + "admin_purpose_org": "非営利団体・支援団体での使用", + "admin_purpose_personal": "個人利用、家族、友人との利用", + "burnAfterReading_linkBurnAfterReading": "一度だけ表示した後に自動で削除", + "feedback_about": "これを読んでいるのは、特定のアクションの実行時にCryptPadがウェブページのリクエストを送信している理由が気になるからだと思います。", + "burnAfterReading_warningLink": "パッドを自動削除に設定しました。リンクを受け取った相手がリンクを開くと、パッドは一度だけ表示され、その後削除されます。" } From 09cbeefd99c913043b4de0a2bf7a69931082cc12 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 2 Jul 2021 14:48:24 +0530 Subject: [PATCH 075/117] double-check that blocks have been written even if 'write' calls back with no error also update the changelog --- CHANGELOG.md | 3 +++ customize.dist/login.js | 15 ++++++++++++--- www/common/cryptpad-common.js | 11 +++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d74a37dc4..92a38bfb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ * guard against domExceptions * catch errors thrown by the diff applier * don't bother returning the hash of a pin list to the client, since they don't use it +* accounts + * trim leading and trailing whitespace from usernames when registering + * double-check that login blocks can be loaded after they have been written without error # 4.7.0 diff --git a/customize.dist/login.js b/customize.dist/login.js index 74e5e86f6..3309190c0 100644 --- a/customize.dist/login.js +++ b/customize.dist/login.js @@ -153,7 +153,7 @@ define([ register: isRegister, }; - var RT, blockKeys, blockHash, Pinpad, rpc, userHash; + var RT, blockKeys, blockHash, blockUrl, Pinpad, rpc, userHash; nThen(function (waitFor) { // derive a predefined number of bytes from the user's inputs, @@ -171,7 +171,7 @@ define([ // the rest of their data // determine where a block for your set of keys would be stored - var blockUrl = Block.getBlockUrl(res.opt.blockKeys); + blockUrl = Block.getBlockUrl(res.opt.blockKeys); // Check whether there is a block at that location Util.fetch(blockUrl, waitFor(function (err, block) { @@ -412,12 +412,21 @@ define([ toPublish.edPublic = RT.proxy.edPublic; var blockRequest = Block.serialize(JSON.stringify(toPublish), res.opt.blockKeys); - rpc.writeLoginBlock(blockRequest, waitFor(function (e) { if (e) { console.error(e); + waitFor.abort(); return void cb(e); } + })); + }).nThen(function (waitFor) { + // confirm that the block was actually written before considering registration successful + Util.fetch(blockUrl, waitFor(function (err /*, block */) { + if (err) { + console.error(err); + waitFor.abort(); + return void cb(err); + } console.log("blockInfo available at:", blockHash); LocalStore.setBlockHash(blockHash); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 9eb5398e7..15234c35e 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -1937,6 +1937,17 @@ define([ waitFor.abort(); return void cb(obj); } + })); + }).nThen(function (waitFor) { + var blockUrl = Block.getBlockUrl(blockKeys); + Util.fetch(blockUrl, waitFor(function (err /* block */) { + if (err) { + console.error(err); + waitFor.abort(); + return cb({ + error: err, + }); + } console.log("new login block written"); var newBlockHash = Block.getBlockHash(blockKeys); LocalStore.setBlockHash(newBlockHash); From ed438d7b3be7a0fe82ce6ef40a5a391c7265d373 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 2 Jul 2021 13:17:35 +0200 Subject: [PATCH 076/117] Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.9% (1365 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.9% (1365 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.7% (1362 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.7% (1362 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 99.6% (1361 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 98.6% (1348 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 98.1% (1341 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 97.7% (1335 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 97.7% (1335 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 97.6% (1334 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 97.5% (1333 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 61 ++++++++++++++++++------ 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 4d02d98c6..25122b243 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -313,7 +313,7 @@ "features_f_register": "無料登録", "features_f_storage1_note": "CryptDriveに保存したドキュメントは、有効期限切れで削除されることはありません", "features_f_storage1": "個人用ストレージ({0})", - "oo_sheetMigration_complete": "新しいバージョンが利用可能です。「OK」を押して再読み込みしてください。", + "oo_sheetMigration_complete": "新しいバージョンが利用可能です。OKを押して再読み込みしてください。", "oo_sheetMigration_loading": "あなたのスプレッドシートを最新バージョンにアップグレードしています。1分程度お待ちください。", "settings_ownDriveButton": "アカウントをアップグレード", "features_f_file1_note": "CryptDriveに画像ファイル、PDF、動画などを保存できます。保存したファイルは、連絡先と共有したり、ドキュメントに埋め込んだりできます。(最大容量は{0}MB)", @@ -763,7 +763,7 @@ "userlist_offline": "現在オフラインのため、ユーザーリストは利用できません。", "readonly": "読み取り専用", "errorState": "重大なエラー: {0}", - "realtime_unrecoverableError": "回復不可能なエラーが発生しました。OKをクリックしてリロードしてください。", + "realtime_unrecoverableError": "回復不可能なエラーが発生しました。OKをクリックして再読み込みを行ってください。", "disabledApp": "このアプリケーションは無効になっています。詳細については、このCryptPadの管理者にお問い合わせください。", "deletedFromServer": "パッドは完全削除されました", "newVersionError": "新しいバージョンのCryptPadがあります。
    リロードすると新しいバージョンを読み込みます。Escキーを押すとオフラインモードでコンテンツにアクセスします。", @@ -811,7 +811,7 @@ "register_registrationIsClosed": "登録は締め切りました。", "settings_notifCalendarHint": "今後のカレンダーのイベントのすべての通知を有効もしくは無効にします。", "reminder_inProgressAllDay": "今日: {0}", - "reminder_inProgress": "{0}が{1}で開始しました", + "reminder_inProgress": "{0}が{1}に開始しました", "reminder_now": "{0}が開始しました", "reminder_missed": "{0}が{1}で開催されました", "calendar_dateRange": "{0} - {1}", @@ -842,7 +842,7 @@ "pad_settings_show": "表示", "pad_settings_hide": "隠す", "pad_settings_width_small": "ページモード", - "pad_settings_info": "このドキュメントの既定の設定。新しいユーザーがドキュメントを閲覧したときに適用されます。", + "pad_settings_info": "このドキュメントの既定の設定です。新しいユーザーがドキュメントを閲覧したときに適用されます。", "pad_settings_title": "ドキュメントの設定", "admin_getquotaTitle": "アカウントのストレージを確認", "settings_colorthemeTitle": "テーマ色", @@ -871,8 +871,8 @@ "notifyRenamed": "{0}は{1}になりました", "printBackgroundNoValue": "背景画像が選択されていません", "canvas_saveToDrive": "この画像をファイル形式でCryptDriveに保存", - "canvas_opacityLabel": "透明度: {0}", - "canvas_opacity": "透明度", + "canvas_opacityLabel": "不透明度: {0}", + "canvas_opacity": "不透明度", "poll_comment_disabled": "✓ボタンを押して投票を公開すると、コメントが有効になります。", "kanban_item": "項目 {0}", "fileEmbedScript": "このファイルを埋め込むには、Media Tagのロード用に、このスクリプトをページに一度含めてください。", @@ -930,7 +930,7 @@ "share_linkEmbed": "埋め込みモード(ツールバーとユーザー一覧を隠します)", "properties_passwordSuccess": "パスワードは変更されました。
    OKを押して再読み込みし、アクセス権限を更新してください。", "properties_passwordWarning": "パスワードは変更されましたが、CryptDriveを更新することができませんでした。古いバージョンのパッドは手動で削除しなければならないかもしれません。
    OKを押して再読み込みし、アクセス権限を更新してください。", - "properties_confirmChange": "パスワードを変更すると履歴が削除されます。パスワードを知らないユーザーは、このパッドにアクセスできなくなります。続行してよろしいですか?", + "properties_confirmChange": "続行してよろしいですか?パスワードを変更すると履歴が削除されます。パスワードを知らないユーザーは、このパッドにアクセスできなくなります。", "creation_newPadModalDescription": "作成するドキュメントの種類をクリックしてください。タブキーで選択し、エンターキーで作成することもできます。", "creation_noOwner": "オーナーがいません", "properties_passwordError": "パスワードの変更中にエラーが発生しました。再度試してください。", @@ -957,7 +957,7 @@ "fm_info_template": "テンプレートとして保存したパッドの一覧です。以下のテンプレートを使って、新しいパッドを作成することができます。", "fm_categoryError": "選択したカテゴリーが開けません。ルートを表示します。", "fm_morePads": "さらに表示", - "oo_reconnect": "サーバーの接続が回復しました。OKをクリックして再読み込みし、編集を継続してください。", + "oo_reconnect": "サーバーの接続が回復しました。OKをクリックして再読み込みを行い、編集を継続してください。", "changeNamePrompt": "名前を変更(匿名で利用する場合は空欄): ", "form_text_text": "テキスト", "form_poll_time": "時", @@ -977,7 +977,7 @@ "calendar_notifications": "リマインダー", "settings_notifCalendarCheckbox": "カレンダーの通知を有効にする", "calendar_days": "日", - "calendar_hours": "時", + "calendar_hours": "時間", "calendar_minutes": "分", "calendar_allDay": "全日", "calendar_location": "場所: {0}", @@ -1055,7 +1055,7 @@ "settings_cacheCheckbox": "このデバイスでキャッシュを有効にする", "form_submitWarning": "強制的に送信", "form_updateWarning": "強制的にアップデート", - "form_answerName": "{0}から{1}について回答", + "form_answerName": "{0}が{1}に回答", "form_addMultipleHint": "複数の日時を追加", "admin_consentToContactTitle": "連絡に同意", "form_poll_hint": ": はい、: いいえ、: 可", @@ -1201,7 +1201,7 @@ "friendRequest_received": "{0}が連絡先への追加を希望しています", "friendRequest_declined": "{0}が連絡先のリクエストを拒否しました", "admin_diskUsageHint": "CryptPadのリソースが消費しているストレージ容量", - "timeoutError": "エラーが発生してサーバーへの接続が切断されました。
    Escキーを押してページをリロードしてください。", + "timeoutError": "エラーが発生してサーバーへの接続が切断されました。
    Escキーを押してページを再読み込みしてください。", "footer_team": "貢献者", "admin_updateLimitHint": "ユーザーのストレージ制限の強制アップデートはいつでも可能です。エラーが発生したときは必須となります", "admin_cat_general": "全般", @@ -1216,7 +1216,7 @@ "admin_checkupHint": "CryptPadには、一般的な構成に関する問題を自動で診断し、必要に応じてそれらを修正する方法を提案するページがあります。", "admin_broadcastTitle": "メッセージを送信", "admin_broadcastHint": "このインスタンスの全ユーザーにメッセージを送信します。ユーザーはメッセージを通知で受け取ります。送信前のメッセージは「通知をプレビュー」から確認できます。プレビューには赤いアイコンが付いており、プレビューはあなたの通知画面にのみ表示されます。", - "calendar_before": "以前", + "calendar_before": "前", "share_formAuditor": "監査人", "form_editMax": "選択できるオプションの最大数", "form_invalidWarning": "回答にエラーがあります:", @@ -1260,7 +1260,7 @@ "settings_colortheme_default": "システムのデフォルト ({0})", "settings_codeBrackets": "括弧の自動補完", "creation_helperText": "ドキュメンテーションを開く", - "contacts_info1": "連絡先の一覧です。", + "contacts_info1": "連絡先の一覧が表示されます。ここでは以下を行うことができます:", "share_noContactsLoggedIn": "連絡先がありません。プロフィールのリンクを共有して、連絡先のリクエストを送信してください。", "settings_cat_security": "セキュリティー", "whatis_collaboration_info": "

    CryptPadはコラボレーションを念頭に作られています。ドキュメントに加えられる変更は、リアルタイムで同期されます。全てのデータは暗号化されているため、サービスとその管理者が、編集され保存されているコンテンツを覗き見ることは不可能です。

    ", @@ -1333,5 +1333,38 @@ "admin_purpose_personal": "個人利用、家族、友人との利用", "burnAfterReading_linkBurnAfterReading": "一度だけ表示した後に自動で削除", "feedback_about": "これを読んでいるのは、特定のアクションの実行時にCryptPadがウェブページのリクエストを送信している理由が気になるからだと思います。", - "burnAfterReading_warningLink": "パッドを自動削除に設定しました。リンクを受け取った相手がリンクを開くと、パッドは一度だけ表示され、その後削除されます。" + "burnAfterReading_warningLink": "パッドを自動削除に設定しました。リンクを受け取った相手がリンクを開くと、パッドは一度だけ表示され、その後削除されます。", + "burnAfterReading_warningAccess": "このドキュメントは自動的に削除されます。下のボタンをクリックするとコンテンツが自動的に表示され、その後で削除されます。ドキュメントを表示した後でウィンドウを閉じると、二度とドキュメントにアクセスすることはできません。準備が出来ていない場合は、ドキュメントを表示する前にこのウィンドウを閉じて、後ほどアクセスしてください。", + "form_sort_hint": "項目を優先順位(1が最も高く{0}が最も低い)に従って並べてください。", + "canvas_brush": "ペン", + "share_versionHash": "ドキュメントの選択したバージョンを閲覧モードで共有します。それにより、このドキュメントの全てのバージョンへの読み取り専用アクセスも可能になります。", + "history_cantRestore": "復元に失敗しました。接続が切れています。", + "todo_move": "タスクリストはCryptDriveのカンバン「{0}」に移動しました。", + "info_imprintFlavour": "このインスタンスの管理者に関する法的情報。", + "settings_safeLinkDefault": "セーフリンクは既定で有効になっています。ブラウザーのアドレスバーではなく、 共有メニューを使ってリンクをコピーしてください。", + "comments_notification": "{1}でのあなたのコメント「{0}」に対する返信", + "infobar_versionHash": "このドキュメントの過去のバージョンを閲覧しています({0})。", + "history_fastNext": "次の編集セッション", + "history_fastPrev": "以前の編集セッション", + "unableToDisplay": "ドキュメントを表示できません。Escキーを押してページの再読み込みを行ってください。問題が継続する場合は、サポートに連絡してください。", + "snapshots_cantMake": "スナップショットを作成できませんでした。接続が切れています。", + "snapshots_notFound": "ドキュメントの履歴が削除されたため、スナップショットは存在しません。", + "snapshot_error_exists": "このバージョンのスナップショットは既に存在します", + "calendar_dateTimeRange": "{0} {1} - {2}", + "toolbar_degraded": "現在{0}人以上がこのドキュメントを編集しています。パフォーマンスの改善のため、ユーザーリストとチャットを無効に設定しました。", + "oo_lostEdits": "新しいデータと同期したため、保存されていない編集箇所を復元することができませんでした。", + "pad_settings_comments": "コメントを既定で表示するか隠すかを選択してください。", + "pad_settings_outline": "目次を既定で表示するか隠すかを選択してください。", + "pad_settings_width_large": "最大幅", + "offlineError": "データを同期できないため、このページは現在表示できません。サービスへの接続が復旧すると読み込みを継続します。", + "share_noContactsOffline": "現在オフラインです。連絡先にアクセスすることはできません。", + "access_offline": "現在オフラインです。管理画面にアクセスすることはできません。", + "admin_support_last": "アップデートした日時: ", + "admin_support_first": "作成日時: ", + "contacts_confirmCancel": "{0}との連絡先リクエストをキャンセルしてよろしいですか?", + "history_trimPrompt": "このドキュメントは{0}の履歴があり、読み込みを遅くしている恐れがあります。必要でない場合は、履歴の削除を検討してください。", + "reminder_date": "{0}が{1}にあります", + "calendar_more": "あと{0}個", + "reminder_time": "{0}が今日の{1}にあります", + "form_answerWarning": "本人であることが確認されていません" } From 9ad74aeba106c01b8c9baabab5ef9b0e599b4b88 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 2 Jul 2021 13:48:25 +0200 Subject: [PATCH 077/117] Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 25122b243..e3982bca6 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -173,7 +173,7 @@ "teams_table_generic": "権限一覧", "teams_table": "権限", "contacts_fetchHistory": "古い履歴を取得する", - "contacts_warning": "ここに入力したすべてのメッセージは永続的であり、このパッドの現在および将来のすべてのユーザーが確認できます。機密情報の入力には注意してください!", + "contacts_warning": "ここに入力した全てのメッセージは永続的であり、このパッドの現在および将来の全てのユーザーが確認できます。機密情報の入力には注意してください!", "contacts_typeHere": "ここにメッセージを入力...", "team_cat_drive": "ドライブ", "team_cat_chat": "チャット", @@ -181,7 +181,7 @@ "team_cat_admin": "管理", "adminPage": "管理", "team_deleteButton": "削除", - "team_deleteHint": "チーム自体とチームが所有しているすべてのドキュメントを削除します。", + "team_deleteHint": "チームと、チームが所有している全てのドキュメントを削除します。", "team_deleteTitle": "チームの削除", "team_avatarHint": "容量 500KB 以下 (png 、jpg 、jpeg 、gif)", "team_avatarTitle": "チームのアバター", @@ -221,7 +221,7 @@ "support_languagesPreamble": "サポートチームは次の言語に対応可能です:", "support_listHint": "管理者に送信されたチケットとその回答のリストは以下の通りです。閉じたチケットを再開することはできませんが、新しいチケットを作成することはできます。閉じたチケットは非表示にできます。", "support_listTitle": "サポートチケット", - "settings_padNotifCheckbox": "コメント通知を無効化", + "settings_padNotifCheckbox": "コメント通知を無効にする", "settings_padNotifTitle": "コメント通知", "notifications_dismissAll": "全て確認済みにする", "notifications_cat_archived": "履歴", @@ -229,7 +229,7 @@ "notifications_dismiss": "確認済みにする", "settings_autostoreMaybe": "手動 (確認しない)", "settings_autostoreNo": "手動 (常に確認する)", - "settings_autostoreHint": "自動 アクセスしたすべてのパッドをCryptDriveに保存します。
    手動(常に確認) 保存していないパッドにアクセスした際、CryptDriveに保存するかどうかを確認します。
    手動(確認しない) アクセス先のパッドはCryptDriveに自動で保存されません。保存オプションは表示されません。", + "settings_autostoreHint": "自動 アクセスした全てのパッドをCryptDriveに保存します。
    手動(常に確認) 保存していないパッドにアクセスした際、CryptDriveに保存するかどうかを確認します。
    手動(確認しない) アクセス先のパッドはCryptDriveに自動で保存されません。保存オプションは表示されません。", "settings_userFeedback": "ユーザーフィードバックを有効にする", "settings_userFeedbackHint2": "あなたのパッドのコンテンツがサーバーと共有されることはありません。", "settings_userFeedbackHint1": "CryptPadは、ユーザーエクスペリエンスの向上のため、いくつかの非常に基本的なフィードバックを、サーバーに提供します。 ", @@ -332,7 +332,7 @@ "properties_addPassword": "パスワードを設定", "history_close": "閉じる", "history_restore": "復元", - "fm_emptyTrashOwned": "ごみ箱に、あなたが所有しているドキュメントが入っています。あなたのドライブからのみ削除するか、すべてのユーザーから完全削除するかを選択できます。", + "fm_emptyTrashOwned": "ごみ箱に、あなたが所有しているドキュメントが入っています。あなたのドライブからのみ削除するか、全てのユーザーから完全削除するかを選択できます。", "access_destroyPad": "このドキュメントまたはフォルダを完全に削除する", "accessButton": "アクセス", "access_allow": "リスト", @@ -343,8 +343,8 @@ "settings_safeLinksTitle": "セーフリンク", "settings_safeLinksHint": "CryptPadでは、リンクの中にパッドを解読するための鍵が含まれています。ブラウザの閲覧履歴にアクセスできる人は、誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューを使用することを強く推奨します。", "settings_autostoreTitle": "CryptDriveへのパッドの保存", - "settings_logoutEverywhereConfirm": "すべてのデバイスでログインが取り消されるため、今後利用する際にもう一度ログインするよう求められます。続行しますか?", - "settings_logoutEverywhere": "他のすべてのウェブセッションからログアウト", + "settings_logoutEverywhereConfirm": "全てのデバイスでログインが取り消されるため、今後利用する際にもう一度ログインするよう求められます。続行しますか?", + "settings_logoutEverywhere": "他の全てのウェブセッションからログアウト", "settings_logoutEverywhereTitle": "リモートセッションを閉じる", "loading_state_5": "ドキュメントを再構築", "loading_state_4": "チームを読み込み", @@ -390,7 +390,7 @@ "home_opensource": "誰でもCryptPadを運営し、個人的または専門的な規模でサービスを提供することができます。ソースコードはGitHubで確認できます。", "home_opensource_title": "オープンソース", "home_host_title": "このインスタンスについて", - "home_privacy_text": "CryptPadは、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。すべてのコンテンツは、あなたのブラウザ上で暗号化および復号化されます。ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービスの管理者でも、あなたの情報にアクセスすることはできません。", + "home_privacy_text": "CryptPadは、データをプライベートに保護しながらコラボレーションを可能にするように構築されています。のコンテンツは、あなたのブラウザ上で暗号化および復号化されます。ドキュメント、チャット、およびファイルは、あなたがログインしているセッション以外では読み取れません。サービスの管理者でも、あなたの情報にアクセスすることはできません。", "home_privacy_title": "プライバシー・バイ・デザイン", "mdToolbar_tutorial": "https://www.markdowntutorial.com/jp/", "languageButtonTitle": "シンタックスハイライトを行う言語を選択してください", @@ -402,7 +402,7 @@ "history_restorePrompt": "ドキュメントの現在のバージョンを、表示しているバージョンに置き換えてよろしいですか?", "slideOptionsTitle": "スライドをカスタマイズ", "propertiesButtonTitle": "パッドのプロパティを表示", - "driveOfflineError": "CryptPadへの接続が切断されています。このパッドに加えられる変更はCryptDriveに保存されません。CryptPadの全てのタブを閉じて、新しいウィンドウで開いてみてください。 ", + "driveOfflineError": "CryptPadへの接続が切断されています。このパッドに加えられる変更はCryptDriveに保存されません。CryptPadののタブを閉じて、新しいウィンドウで開いてみてください。 ", "properties_passwordWarningFile": "パスワードは変更されましたが、新しいデータでCryptDriveを更新することができませんでした。古いバージョンのファイルを手動で削除する必要があるかもしれません。", "properties_confirmNewFile": "よろしいですか?パスワードを追加するとファイルのURLが変わります。パスワードをもたないユーザーは、このファイルにアクセスできなくなります。", "properties_confirmChangeFile": "よろしいですか?新しいパスワードをもたないユーザーは、このファイルにアクセスできなくなります。", @@ -410,7 +410,7 @@ "team_pendingOwner": "(保留中)", "fm_contextMenuError": "そのアイテムのコンテクストメニューを開けません。問題が続くなら、ページを再読み込みしてみてください。", "fm_selectError": "そのアイテムを選択できません。問題が続くなら、ページを再読み込みしてみてください。", - "fm_unknownFolderError": "選択、あるいは最後に開いたディレクトリは存在しません。親フォルダを開きます…", + "fm_unknownFolderError": "選択、もしくは最後に開いたディレクトリは存在しません。親フォルダを開きます…", "fm_restoreDialog": "{0}を元の場所に復元してよろしいですか?", "fm_removeSeveralPermanentlyDialog": "ドライブから{0}個のアイテムを削除してよろしいですか?他のユーザーのドライブからは削除されません。", "fm_removePermanentlyDialog": "ドライブからこのアイテムを削除してよろしいですか?他のユーザーのドライブからは削除されません。", @@ -428,7 +428,7 @@ "settings_disableThumbnailsAction": "CryptDriveでのサムネイルの作成を無効にする", "settings_resetError": "入力した確認文が正しくありません。CryptDriveのデータは消去されていません。", "settings_resetDone": "データが消去されました!", - "settings_resetPrompt": "あなたのドライブから全てのパッドを削除します。
    本当に続けてよろしいですか?
    続けるには「I love CryptPad」と入力してください。", + "settings_resetPrompt": "あなたのドライブからのパッドを削除します。
    本当に続けてよろしいですか?
    続けるには「I love CryptPad」と入力してください。", "settings_reset": "CryptDriveの全てのファイルとフォルダを削除", "settings_exportErrorOther": "ドキュメントのエクスポート中にエラーが発生しました: {0}", "drive_activeOld": "以前のパッド", @@ -480,7 +480,7 @@ "cba_disable": "消去して無効にする", "upload_pending": "保留中", "settings_resetTips": "ヒント", - "chrome68": "バージョン68のChromeあるいはChromiumを使用しているようです。このバージョンには、数秒経過した後でページが白紙になったり、クリックにページが反応しなくなったりするバグがあります。この問題を解決するには、別のタブを表示して改めて表示するか、このページでスクロールを試みてください。このバグは次のバージョンで解決される予定となっています。", + "chrome68": "バージョン68のChromeもしくはChromiumを使用しているようです。このバージョンには、数秒経過した後でページが白紙になったり、クリックにページが反応しなくなったりするバグがあります。この問題を解決するには、別のタブを表示して改めて表示するか、このページでスクロールを試みてください。このバグは次のバージョンで解決される予定となっています。", "register_notes": "
    • ドキュメントは、パスワードによって暗号化されます。パスワードを紛失すると、データを復元することはできません。
    • 共有のコンピュータを使用している場合は、作業完了時に忘れずログアウトしてください。 ブラウザーのウインドウを閉じても、アカウントからはログアウトされません。
    • 未ログインで作成、共有したファイルを保存するには、 「匿名セッションのドキュメントをインポート」にチェックをしてください。
    ", "poll_commit": "送信", "admin_removeDonateButtonTitle": "クラウドファンディングへの参加", @@ -686,7 +686,7 @@ "history_next": "次のバージョン", "historyButton": "ドキュメントの履歴を表示", "notifyLeft": "{0}が共同セッションから退出しました", - "fileEmbedTag": "そして、ファイルを埋め込みたい任意のページの箇所に、このMedia Tagを配置してください:", + "fileEmbedTag": "その後、ファイルを埋め込みたい任意のページの箇所に、このMedia Tagを配置してください:", "themeButtonTitle": "コードとスライドのエディタのテーマ色を選択", "printTransition": "遷移アニメーションを有効にする", "admin_blockDailyCheckTitle": "サーバーのテレメトリー", @@ -809,7 +809,7 @@ "fm_info_root": "フォルダを作成してファイルを整理できます。", "oo_conversionSupport": "お使いのブラウザはMicrosoft Officeのフォーマットの変換に対応していません。FirefoxもしくはChromeの最新バージョンの使用を推奨します。", "register_registrationIsClosed": "登録は締め切りました。", - "settings_notifCalendarHint": "今後のカレンダーのイベントのすべての通知を有効もしくは無効にします。", + "settings_notifCalendarHint": "今後のカレンダーのイベントの全ての通知を有効もしくは無効にします。", "reminder_inProgressAllDay": "今日: {0}", "reminder_inProgress": "{0}が{1}に開始しました", "reminder_now": "{0}が開始しました", @@ -1001,7 +1001,7 @@ "settings_padSpellcheckLabel": "リッチテキストのパッドでスペルチェックを有効にする", "settings_padWidth": "エディターの最大幅", "settings_codeUseTabs": "タブを使ってインデント(空白スペースの代わりに)", - "login_noSuchUser": "無効なユーザー名あるいはパスワードです。再度試すか、サインアップしてください", + "login_noSuchUser": "無効なユーザー名もしくはパスワードです。再度試すか、サインアップしてください", "fo_unavailableName": "同じ名前のファイルまたはフォルダが既に存在しています。アイテムの名前を変更して、再度試してください。", "fo_moveFolderToChildError": "フォルダをサブフォルダに移動することはできません", "fo_existingNameError": "その名前はディレクトリで既に使用されています。他の名前を選んでください。", @@ -1026,7 +1026,7 @@ "slide_invalidLess": "ユーザー定義のスタイルは無効です", "printCSS": "ユーザー定義のスタイルルール(CSS):", "admin_provideAggregateStatisticsHint": "追加の利用状況を開発者に提供することも選択できます。追加の情報には、あなたのインスタンスのおおよその登録ユーザー数や一日あたりのユーザー数などがあります。", - "fm_info_sharedFolder": "これは共有フォルダです。ログインしていないため、閲覧モードでしかアクセスできません。
    登録あるいはログインすると、CryptDriveにインポートして編集できます。", + "fm_info_sharedFolder": "これは共有フォルダです。ログインしていないため、閲覧モードでしかアクセスできません。
    登録もしくはログインすると、CryptDriveにインポートして編集できます。", "team_invitedToTeam": "{0}があなたをチーム「{1}」に招待しました", "team_inviteFromMsg": "{0}があなたをチーム「{1}」に招待しました", "team_invitePleaseLogin": "招待を承諾するには、ログインもしくは登録してください。", @@ -1109,7 +1109,7 @@ "admin_diskUsageButton": "レポートを生成", "admin_diskUsageTitle": "ディスクの使用状況", "contact_adminHint": "アカウントに関連した問題、ストレージの制限、サービスの運用状況に関して。\n", - "contact_devHint": "機能のリクエスト、ユーザビリティの改善、あるいはお礼については、以下よりお願いします。", + "contact_devHint": "機能のリクエスト、ユーザビリティの改善、もしくはお礼については、以下よりお願いします。", "contact_dev": "開発者に連絡", "contact_admin": "管理者に連絡", "admin_flushCacheDone": "キャッシュを消去しました", @@ -1120,7 +1120,7 @@ "admin_updateLimitTitle": "ユーザーのクォータを更新", "mdToolbar_defaultText": "ここにテキストを入力", "upload_modal_filename": "ファイル名(拡張子 {0} を自動で追加)", - "settings_padSpellcheckHint": "リッチテキストパッドでスペルチェックを有効にします。間違ったつづりには赤色の下線が表示されます。右クリックをしながらコントロールキーあるいはメタキーを押すと、正しい選択肢が表示されます。", + "settings_padSpellcheckHint": "リッチテキストパッドでスペルチェックを有効にします。間違ったつづりには赤色の下線が表示されます。右クリックをしながらコントロールキーもしくはメタキーを押すと、正しい選択肢が表示されます。", "creation_404": "このパッドは存在しません。以下のフォームより新しいパッドを作成してください。", "help_genericMore": "CryptPadの使い方についてはドキュメンテーションをご覧ください。", "whatis_drive": "CryptDriveでまとめて管理", @@ -1167,7 +1167,7 @@ "team_deleteConfirm": "チーム全体のデータを全て削除しようとしています。削除すると、チームの他のメンバーもデータにアクセスできなくなります。これは取り消せません。削除してよろしいですか?", "team_kickConfirm": "{0}はチームから削除された旨通知されます。よろしいですか?", "admin_instancePurposeHint": "インスタンスを運用する目的は何ですか?テレメトリーが有効になっている場合、回答は開発ロードマップに利用されます。", - "admin_purpose_experiment": "プラットフォームのテストあるいは新機能の開発", + "admin_purpose_experiment": "プラットフォームのテストもしくは新機能の開発", "admin_purpose_noanswer": "回答しない", "admin_instancePurposeTitle": "インスタンスの目的", "requestEdit_request": "{1}がパッド({0})の編集を希望しています", From 27f3223490ba132cd5ed995e310790d88be5ad2c Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 2 Jul 2021 17:55:15 +0530 Subject: [PATCH 078/117] provide the language we detect to CKEditor --- www/pad/inner.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/pad/inner.js b/www/pad/inner.js index ae22af23c..304e9abe4 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -1327,6 +1327,7 @@ define([ $(waitFor()); }).nThen(function(waitFor) { Ckeditor.config.toolbarCanCollapse = true; + Ckeditor.config.language = Messages._getLanguage(); if (screen.height < 800) { Ckeditor.config.toolbarStartupExpanded = false; $('meta[name=viewport]').attr('content', From eb9eb9e7829f2470cbb44350414402f3b8b5d28c Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 2 Jul 2021 14:31:46 +0200 Subject: [PATCH 079/117] Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index e3982bca6..348814824 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -23,7 +23,7 @@ "sheet": "スプレッドシート", "form": "フォーム" }, - "main_title": "CryptPad - 安全にリアルタイム編集可能なコラボレーションツール", + "main_title": "CryptPad - 安全にリアルタイムで編集可能なコラボレーションツール", "support_formButton": "送信", "support_formMessage": "メッセージを入力…", "support_formContentError": "エラー:内容が空です", @@ -126,11 +126,11 @@ "register_importRecent": "匿名セッションのドキュメントをインポート", "importButton": "インポート", "main_catch_phrase": "コラボレーションスイート
    暗号化されかつオープンソース", - "tos_3rdparties": "私たちは、法律で義務付けられている場合を除き、個別のデータを第三者に提供しません。", + "tos_3rdparties": "私たちは、法令に基づく場合を除き、個人情報を第三者に提供しません。", "tos_logs": "あなたのブラウザからサーバーに送信されたメタデータは、サービスを維持するために記録される場合があります。", "tos_availability": "私たちはこのサービスがあなたの役に立つことを願っていますが、可用性や性能は保証できません。定期的にデータをエクスポートしてください。", "tos_legal": "悪意ある行為、乱用する行為、または何らかの違法な行為を行わないでください。", - "tos_title": "CryptPad サービス利用規約", + "tos_title": "CryptPadサービス利用規約", "whatis_title": "CryptPadとは?", "topbar_whatIsCryptpad": "CryptPadとは何か", "footer_tos": "利用規約", @@ -242,7 +242,7 @@ "settings_trimHistoryHint": "ドライブと通知の履歴を削除して、ストレージ容量を節約します。これはパッドの履歴には影響しません。パッドの履歴は、プロパティダイアログから削除できます。", "trimHistory_currentSize": "現在の履歴容量: {0}", "support_cat_other": "その他", - "user_about": "CryptPad について", + "user_about": "CryptPadについて", "fc_delete": "ごみ箱へ移動", "fc_remove": "削除", "fc_restore": "復元", @@ -568,7 +568,7 @@ "form_type_poll": "投票", "form_type_checkbox": "チェックボックス", "form_type_textarea": "段落", - "form_type_input": "文字", + "form_type_input": "文", "form_text_number": "数", "form_text_email": "Eメール", "form_text_url": "リンク", @@ -763,7 +763,7 @@ "userlist_offline": "現在オフラインのため、ユーザーリストは利用できません。", "readonly": "読み取り専用", "errorState": "重大なエラー: {0}", - "realtime_unrecoverableError": "回復不可能なエラーが発生しました。OKをクリックして再読み込みを行ってください。", + "realtime_unrecoverableError": "回復不能なエラーが発生しました。OKをクリックして再読み込みを行ってください。", "disabledApp": "このアプリケーションは無効になっています。詳細については、このCryptPadの管理者にお問い合わせください。", "deletedFromServer": "パッドは完全削除されました", "newVersionError": "新しいバージョンのCryptPadがあります。
    リロードすると新しいバージョンを読み込みます。Escキーを押すとオフラインモードでコンテンツにアクセスします。", @@ -854,7 +854,7 @@ "settings_exportErrorMissing": "このドキュメントはサーバーにありません(期限切れ、もしくはオーナーにより削除されました)", "settings_exportErrorEmpty": "このドキュメントはエクスポートできません(内容が空もしくは無効です)。", "settings_exportErrorDescription": "以下のドキュメントをエクスポートに追加できませんでした:", - "settings_exportDescription": "ドキュメントをダウンロードして復号化しております。少々お待ちください。これには数分程度かかることがあります。タブを閉じると作業が中断されます。", + "settings_exportDescription": "ドキュメントをダウンロードして復号化しています。これには数分程度かかることがあります。タブを閉じると作業が中断されます。", "crowdfunding_popup_text": "

    あなたの援助が必要です!

    CryptPadの開発が継続できるよう、OpenCollectiveのページからご支援いただきますようお願いします。ロードマップ資金調達の目標を同ページにて公開しています。", "autostore_notAvailable": "この機能を使うにはCryptDriveにパッドを保存する必要があります。", "autostore_forceSave": "CryptDriveにファイルを保存", @@ -1263,7 +1263,7 @@ "contacts_info1": "連絡先の一覧が表示されます。ここでは以下を行うことができます:", "share_noContactsLoggedIn": "連絡先がありません。プロフィールのリンクを共有して、連絡先のリクエストを送信してください。", "settings_cat_security": "セキュリティー", - "whatis_collaboration_info": "

    CryptPadはコラボレーションを念頭に作られています。ドキュメントに加えられる変更は、リアルタイムで同期されます。全てのデータは暗号化されているため、サービスとその管理者が、編集され保存されているコンテンツを覗き見ることは不可能です。

    ", + "whatis_collaboration_info": "

    CryptPadはコラボレーションを念頭に作られています。ドキュメントに加えられる変更は、リアルタイムで同期されます。全てのデータは暗号化されているため、サービスとその管理者が、編集され保存されているコンテンツを覗き見ることはできません。

    ", "whatis_apps": "フルスイートアプリケーション", "whatis_drive_info": "

    ドキュメントをCryptDriveに保存して管理できます。フォルダを作ったり共有したりできるほか、ドキュメントをタグ付けして整理することもできます。PDFファイル、写真、動画、音声などのファイルをアップロードして共有できます。チームのドライブを使うと、メンバーとデータを共有したり、ファイルの管理や、きめ細かいアクセス権のコントロールを行うことができます。

    ", "whatis_model_info": "

    CryptPadは2016年より、寄付金とcryptpad.frの定額利用のほか、BPIフランス、NLNet財団、NGI Trust、Mozillaオープンソースサポートといったフランス、EUの研究助成を受けています。私たちは、公的資金で作られたソフトウェアについては、コードも公的に公開されるべきであると考えているため、サービスは全てオープンソースで提供しています。誰でも自由にこのソフトウェアを使用、運営、改変することができます。

    CryptPadは、ユーザーのデータを使って金銭上の利益を得ることはありません。これはプライバシーを尊重するオンラインサービスの展望の一部をなすものです。個人情報を使って金銭上の利益をあげながら「無料」を装う巨大プラットフォームとは違って、CryptPadは、ユーザーが自発的に支援を行うサービスのモデルを作ることを目指しています。

    私たちは、CryptPadのサービスを無料で提供しています。それは、金銭的に余裕のある人々だけでなく、誰もがプライバシーを得るに値すると確信しているからです。もしあなたがこのプロジェクトを支援できる状況にあるなら、機能の開発や、改良、メンテナンスに参加していただきたく考えます。そうすることで、全てのユーザーに利益をもたらされるはずです。

    このプロジェクトが実行可能であることが明らかになったいま、次のゴールは、ユーザーによる支援を通じて、プロジェクトを持続可能なものにすることにあります。CryptPadが、巨大プラットフォームに代わる持続可能なサービスを開発できるよう支援していただけるなら、一度もしくは継続的な寄付へのご協力をお願いいたします。

    ", @@ -1321,7 +1321,7 @@ "admin_surveyHint": "外部サイトで行うアンケートのリンクを追加、更新、削除できます。ユーザーには通知が送信され、アンケートはユーザーのメニューから開くことができます。", "broadcast_defaultLanguage": "この言語にフォールバック", "admin_performanceProfilingHint": "サーバー側でコマンドを実行する際に掛かった合計時間の一覧です", - "admin_consentToContactHint": "サーバーのテレメトリーには、ソフトウェアや設定に関する重大な問題が発生した際に開発者が連絡できるよう、管理者の連絡先のメールアドレスが含まれます。メールアドレスが共有、売却、マーケティングの目的で使用されることはありません。サーバーに重大な問題が発生した際に連絡を希望する場合は、「同意する」にチェックをつけてください。", + "admin_consentToContactHint": "サーバーのテレメトリーには、ソフトウェアや設定に関する重大な問題が発生した際に開発者が連絡できるよう、管理者の連絡先のメールアドレスが含まれます。メールアドレスが共有、売却、マーケティングの目的で使用されることはありません。サーバーに重大な問題が発生した際に連絡を希望する場合は、「同意する」にチェックを付けてください。", "admin_removeDonateButtonHint": "CryptPadの開発の一部は、公的な助成金と寄付金によってまかなわれています。クラウドファンディングに関する宣伝をあなたのインスタンスで行うことで、開発者が万人のためにプラットフォームを改良することへの支援につながります。ただし、もし宣伝が不適切な場合は、宣伝を無効にすることもできます。", "admin_performanceTimeHeading": "時間(秒)", "team_maxTeams": "それぞれのユーザーアカウントがメンバーになることができるのは、最大{0}チームまでです。", @@ -1334,7 +1334,7 @@ "burnAfterReading_linkBurnAfterReading": "一度だけ表示した後に自動で削除", "feedback_about": "これを読んでいるのは、特定のアクションの実行時にCryptPadがウェブページのリクエストを送信している理由が気になるからだと思います。", "burnAfterReading_warningLink": "パッドを自動削除に設定しました。リンクを受け取った相手がリンクを開くと、パッドは一度だけ表示され、その後削除されます。", - "burnAfterReading_warningAccess": "このドキュメントは自動的に削除されます。下のボタンをクリックするとコンテンツが自動的に表示され、その後で削除されます。ドキュメントを表示した後でウィンドウを閉じると、二度とドキュメントにアクセスすることはできません。準備が出来ていない場合は、ドキュメントを表示する前にこのウィンドウを閉じて、後ほどアクセスしてください。", + "burnAfterReading_warningAccess": "このドキュメントは自動的に削除されます。下のボタンをクリックするとコンテンツが自動的に表示され、その後で削除されます。ドキュメントを表示した後でウィンドウを閉じると、二度とドキュメントにアクセスすることはできません。準備ができていない場合は、ドキュメントを表示する前にこのウィンドウを閉じて、後ほどアクセスしてください。", "form_sort_hint": "項目を優先順位(1が最も高く{0}が最も低い)に従って並べてください。", "canvas_brush": "ペン", "share_versionHash": "ドキュメントの選択したバージョンを閲覧モードで共有します。それにより、このドキュメントの全てのバージョンへの読み取り専用アクセスも可能になります。", From ca1016ad3a674b760bbf54767d7b2ad0add6fe97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Fri, 2 Jul 2021 13:45:20 +0100 Subject: [PATCH 080/117] Add spacing to Form results --- www/form/app-form.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/form/app-form.less b/www/form/app-form.less index 433316448..95802e18b 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -470,7 +470,11 @@ //padding: 10px; } + .cp-form-creator-results-export { + margin-bottom: 20px; + } .cp-form-creator-results-content { + padding-bottom: 100px; .cp-form-block { background: @cp_form-bg1; padding: 10px; From bca1c086534cac6fcbbd2e187fa94b3be9253a5c Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 2 Jul 2021 18:46:03 +0200 Subject: [PATCH 081/117] Fix team pending owner issues --- www/common/outer/team.js | 162 +++++++++++++++++++++++---------------- www/teams/inner.js | 32 ++++---- 2 files changed, 113 insertions(+), 81 deletions(-) diff --git a/www/common/outer/team.js b/www/common/outer/team.js index 0ec224984..3dc39c6f3 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -986,47 +986,60 @@ define([ var state = team.roster.getState() || {}; var members = state.members || {}; - // Get pending owners - var md = team.listmap.metadata || {}; - if (Array.isArray(md.pending_owners)) { - // Get the members associated to the pending_owners' edPublic and mark them as such - md.pending_owners.forEach(function (ed) { - var member; - Object.keys(members).some(function (curve) { - if (members[curve].edPublic === ed) { - member = members[curve]; - return true; - } - }); - if (!member && teamData.owner) { - var removeOwnership = function (chan) { - ctx.Store.setPadMetadata(null, { - channel: chan, - command: 'RM_PENDING_OWNERS', - value: [ed], - }, function () {}); - }; - removeOwnership(teamData.channel); - removeOwnership(Util.find(teamData, ['keys', 'roster', 'channel'])); - removeOwnership(Util.find(teamData, ['keys', 'chat', 'channel'])); + var md; + nThen(function (waitFor) { + // Get pending owners + ctx.Store.getPadMetadata(null, { + channel: teamData.channel + }, waitFor(function (obj) { + if (obj && obj.error) { + md = team.listmap.metadata || {}; return; } - member.pendingOwner = true; - }); - } + md = obj; + })); + }).nThen(function () { + ctx.pending_owners = md.pending_owners; + if (Array.isArray(md.pending_owners)) { + // Get the members associated to the pending_owners' edPublic and mark them as such + md.pending_owners.forEach(function (ed) { + var member; + Object.keys(members).some(function (curve) { + if (members[curve].edPublic === ed) { + member = members[curve]; + return true; + } + }); + if (!member && teamData.owner) { + var removeOwnership = function (chan) { + ctx.Store.setPadMetadata(null, { + channel: chan, + command: 'RM_PENDING_OWNERS', + value: [ed], + }, function () {}); + }; + removeOwnership(teamData.channel); + removeOwnership(Util.find(teamData, ['keys', 'roster', 'channel'])); + removeOwnership(Util.find(teamData, ['keys', 'chat', 'channel'])); + return; + } + member.pendingOwner = true; + }); + } - // Add online status (using messenger data) - if (ctx.store.messenger) { - var chatData = team.getChatData(); - var online = ctx.store.messenger.getOnlineList(chatData.channel) || []; - online.forEach(function (curve) { - if (members[curve]) { - members[curve].online = true; - } - }); - } + // Add online status (using messenger data) + if (ctx.store.messenger) { + var chatData = team.getChatData(); + var online = ctx.store.messenger.getOnlineList(chatData.channel) || []; + online.forEach(function (curve) { + if (members[curve]) { + members[curve].online = true; + } + }); + } - cb(members); + cb(members); + }); }; // Return folders with edit rights available to everybody (decrypted pad href) @@ -1144,8 +1157,7 @@ define([ if (!teamData) { return void cb ({error: 'ENOENT'}); } var team = ctx.teams[teamId]; if (!team) { return void cb ({error: 'ENOENT'}); } - var md = team.listmap.metadata || {}; - var isPendingOwner = (md.pending_owners || []).indexOf(user.edPublic) !== -1; + var isPendingOwner = user.pendingOwner; nThen(function (waitFor) { var cmd = isPendingOwner ? 'RM_PENDING_OWNERS' : 'RM_OWNERS'; @@ -1364,42 +1376,60 @@ define([ var describeUser = function (ctx, data, cId, cb) { var teamId = data.teamId; if (!teamId) { return void cb({error: 'EINVAL'}); } + var teamData = Util.find(ctx, ['store', 'proxy', 'teams', teamId]); var team = ctx.teams[teamId]; - if (!team) { return void cb ({error: 'ENOENT'}); } + if (!teamData || !team) { return void cb ({error: 'ENOENT'}); } if (!team.roster) { return void cb({error: 'NO_ROSTER'}); } if (!data.curvePublic || !data.data) { return void cb({error: 'MISSING_DATA'}); } var state = team.roster.getState(); var user = state.members[data.curvePublic]; - // It it is an ownership revocation, we have to set it in pad metadata first - if (user.role === "OWNER" && data.data.role !== "OWNER") { - revokeOwnership(ctx, teamId, user, function (err) { - if (!err) { return void cb(); } - console.error(err); - return void cb({error: err}); - }); - return; - } + var md; + nThen(function (waitFor) { + // Get pending owners + ctx.Store.getPadMetadata(null, { + channel: teamData.channel + }, waitFor(function (obj) { + if (obj && obj.error) { + md = team.listmap.metadata || {}; + return; + } + md = obj; + })); + }).nThen(function () { + user.pendingOwner = Array.isArray(md.pending_owners) && + md.pending_owners.indexOf(user.edPublic) !== -1; - // Viewer to editor - if (user.role === "VIEWER" && data.data.role !== "VIEWER") { - changeEditRights(ctx, teamId, user, true, function (obj) { - return void cb(obj); - }); - } + // It it is an ownership revocation, we have to set it in pad metadata first + if (user.role === "OWNER" && data.data.role !== "OWNER") { + revokeOwnership(ctx, teamId, user, function (err) { + if (!err) { return void cb(); } + console.error(err); + return void cb({error: err}); + }); + return; + } - // Editor to viewer - if (user.role !== "VIEWER" && data.data.role === "VIEWER") { - changeEditRights(ctx, teamId, user, false, function (obj) { - return void cb(obj); - }); - } + // Viewer to editor + if (user.role === "VIEWER" && data.data.role !== "VIEWER") { + changeEditRights(ctx, teamId, user, true, function (obj) { + return void cb(obj); + }); + } - var obj = {}; - obj[data.curvePublic] = data.data; - team.roster.describe(obj, function (err) { - if (err) { return void cb({error: err}); } - cb(); + // Editor to viewer + if (user.role !== "VIEWER" && data.data.role === "VIEWER") { + changeEditRights(ctx, teamId, user, false, function (obj) { + return void cb(obj); + }); + } + + var obj = {}; + obj[data.curvePublic] = data.data; + team.roster.describe(obj, function (err) { + if (err) { return void cb({error: err}); } + cb(); + }); }); }; diff --git a/www/teams/inner.js b/www/teams/inner.js index 4b0532628..7a7cf9116 100644 --- a/www/teams/inner.js +++ b/www/teams/inner.js @@ -768,7 +768,7 @@ define([ $(demote).hide(); describeUser(common, data.curvePublic, { role: role - }, promote); + }, demote); }; if (isMe) { return void UI.confirm(Messages.team_demoteMeConfirm, function (yes) { @@ -901,22 +901,24 @@ define([ $header.append(invite); } - if (me && (me.role !== 'OWNER')) { - var leave = h('button.cp-online.btn.btn-danger', Messages.team_leaveButton); - $(leave).click(function () { - UI.confirm(Messages.team_leaveConfirm, function (yes) { - if (!yes) { return; } - APP.module.execCommand('LEAVE_TEAM', { - teamId: APP.team - }, function (obj) { - if (obj && obj.error) { - return void UI.warn(Messages.error); - } - }); + var leave = h('button.cp-online.btn.btn-danger', Messages.team_leaveButton); + $(leave).click(function () { + if (me && me.role === 'OWNER') { + Messages.team_leaveOwner = "Owners can't leave the team. You can demote yourself if there is at least one other owner."; // XXX + return void UI.alert(Messages.team_leaveOwner); + } + UI.confirm(Messages.team_leaveConfirm, function (yes) { + if (!yes) { return; } + APP.module.execCommand('LEAVE_TEAM', { + teamId: APP.team + }, function (obj) { + if (obj && obj.error) { + return void UI.warn(Messages.error); + } }); }); - $header.append(leave); - } + }); + $header.append(leave); var table = h('button.btn.btn-primary', Messages.teams_table); $(table).click(function (e) { From ffad850434fdd31ee38ffd01be2df05097160b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Benqu=C3=A9?= Date: Mon, 5 Jul 2021 10:12:51 +0100 Subject: [PATCH 082/117] Use more faded red for danger alert backgrounds --- customize.dist/src/less2/include/colortheme-dark.less | 2 +- customize.dist/src/less2/include/colortheme.less | 2 +- customize.dist/src/less2/include/markdown.less | 7 ++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/customize.dist/src/less2/include/colortheme-dark.less b/customize.dist/src/less2/include/colortheme-dark.less index f8ea0c92b..5c1649850 100644 --- a/customize.dist/src/less2/include/colortheme-dark.less +++ b/customize.dist/src/less2/include/colortheme-dark.less @@ -53,7 +53,7 @@ @cryptpad_color_light_blue: #00b7d8; @cryptpad_color_red: #ff1100; @cryptpad_color_red_fade: fade(@cryptpad_color_red, 50%); -@cryptpad_color_red_fader: fade(@cryptpad_color_red, 25%); +@cryptpad_color_red_fader: fade(@cryptpad_color_red, 15%); @cryptpad_color_warn_red: @cryptpad_color_red_fade; @cryptpad_color_dark_red: #9e0000; @cryptpad_color_light_red: #FFD4D4; diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less index a7b103797..18dcb1c0a 100644 --- a/customize.dist/src/less2/include/colortheme.less +++ b/customize.dist/src/less2/include/colortheme.less @@ -53,7 +53,7 @@ @cryptpad_color_light_blue: #00b7d8; @cryptpad_color_red: #ff1100; @cryptpad_color_red_fade: fade(@cryptpad_color_red, 50%); -@cryptpad_color_red_fader: fade(@cryptpad_color_red, 25%); +@cryptpad_color_red_fader: fade(@cryptpad_color_red, 15%); @cryptpad_color_warn_red: @cryptpad_color_red_fade; @cryptpad_color_dark_red: #9e0000; @cryptpad_color_light_red: #FFD4D4; diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index f42a27146..43732187a 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -156,14 +156,11 @@ } div.cp-inline-img-warning { - @cryptpad_test_red_fader: fade(@cryptpad_color_red, 15%); // XXX display: inline-block; padding: 10px; - - color: @cryptpad_text_col; // XXX - background-color: @cryptpad_test_red_fader; // XXX @cryptpad_color_red_fader; + color: @cryptpad_text_col; + background-color: @cryptpad_color_red_fader; border: 1px solid @cryptpad_color_red; - .cp-inline-img { display: flex; margin-bottom: 10px; From 512e6eea6b135581c40b05cddf3eb3080c5d7c2f Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 5 Jul 2021 12:54:36 +0200 Subject: [PATCH 083/117] Translated using Weblate (French) Currently translated at 99.8% (1364 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 563b89ade..ade45bb3a 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1354,5 +1354,15 @@ "button_newform": "Nouveau formulaire", "share_formView": "Participant", "share_formAuditor": "Auditeur", - "share_formEdit": "Auteur" + "share_formEdit": "Auteur", + "admin_purpose_noanswer": "Je préfère ne pas répondre", + "admin_purpose_experiment": "Pour tester la plateforme ou développer de nouvelles fonctionnalités", + "resources_imageBlocked": "CryptPad a bloqué une image distante", + "resources_openInNewTab": "Ouvrir dans un nouvel onglet", + "resources_learnWhy": "En savoir plus sur les images bloquées", + "admin_instancePurposeTitle": "Usage de l'instance", + "admin_purpose_personal": "Usage personnel, famille ou amis", + "admin_purpose_org": "Usage associatif", + "admin_purpose_education": "Usage en entreprise", + "admin_purpose_public": "Service gratuit ouvert au public" } From f0635afdf8cf5812e54d53894cff5d48795692b9 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 5 Jul 2021 12:54:36 +0200 Subject: [PATCH 084/117] Translated using Weblate (Portuguese (Brazil)) Currently translated at 69.9% (955 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/pt_BR/ --- www/common/translations/messages.pt-br.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/www/common/translations/messages.pt-br.json b/www/common/translations/messages.pt-br.json index 971bf959a..81237753d 100644 --- a/www/common/translations/messages.pt-br.json +++ b/www/common/translations/messages.pt-br.json @@ -9,7 +9,7 @@ "whiteboard": "Whiteboard", "file": "File", "media": "Media", - "kanban": "Kanban", + "kanban": "Placa de Assinatura", "todo": "A Fazer", "contacts": "Contactos", "sheet": "Planilha (Beta)", @@ -221,7 +221,7 @@ "header_logoTitle": "Go to the main page", "edit": "edit", "view": "view", - "feedback_about": "If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions", + "feedback_about": "Se você está lendo isso, provavelmente está curioso para saber por que o CryptPad está solicitando páginas da web quando você executa certas ações.", "feedback_privacy": "We care about your privacy, and at the same time we want CryptPad to be very easy to use. We use this file to figure out which UI features matter to our users, by requesting it along with a parameter specifying which action was taken.", "feedback_optout": "If you would like to opt out, visit your user settings page, where you'll find a checkbox to enable or disable user feedback.", "button_newkanban": "Novo Kanban", @@ -842,7 +842,7 @@ "admin_flushCacheTitle": "Limpar cache HTTP", "settings_padNotifTitle": "Notificações de comentários", "comments_comment": "Comentário", - "comments_resolve": "Resolve", + "comments_resolve": "Resolver", "comments_reply": "Responder", "comments_submit": "Enviar", "comments_edited": "Editado", @@ -952,5 +952,9 @@ "contacts_unmute": "Com som", "contacts_mute": "Mudo", "share_noContactsNotLoggedIn": "Faça login ou registre-se para ver seus contatos existentes e adicionar novos.", - "share_copyProfileLink": "Copiar link do perfil" + "share_copyProfileLink": "Copiar link do perfil", + "settings_padOpenLinkTitle": "Forma", + "settings_padOpenLinkHint": "Com esta opção, você pode abrir links incorporados com um clique, sem o pop-up de visualização", + "settings_padOpenLinkLabel": "Habilitar abertura de link direto", + "settings_padNotifHint": "Ignorar notificações quando alguém responder a um de seus comentários" } From 91c7accf9ca1752f3cf53fca44f28afd0e0580e2 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 5 Jul 2021 12:54:37 +0200 Subject: [PATCH 085/117] Translated using Weblate (Japanese) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index 348814824..fded593cf 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -343,7 +343,7 @@ "settings_safeLinksTitle": "セーフリンク", "settings_safeLinksHint": "CryptPadでは、リンクの中にパッドを解読するための鍵が含まれています。ブラウザの閲覧履歴にアクセスできる人は、誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューを使用することを強く推奨します。", "settings_autostoreTitle": "CryptDriveへのパッドの保存", - "settings_logoutEverywhereConfirm": "全てのデバイスでログインが取り消されるため、今後利用する際にもう一度ログインするよう求められます。続行しますか?", + "settings_logoutEverywhereConfirm": "全てのデバイスで改めてログインしなければならなくなります。よろしいですか?", "settings_logoutEverywhere": "他の全てのウェブセッションからログアウト", "settings_logoutEverywhereTitle": "リモートセッションを閉じる", "loading_state_5": "ドキュメントを再構築", From 70219e376c5c62257dc000694f10469a26b50599 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 5 Jul 2021 12:54:54 +0200 Subject: [PATCH 086/117] Translated using Weblate (French) Currently translated at 99.8% (1364 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index ade45bb3a..0ce9e2d6f 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1363,6 +1363,6 @@ "admin_instancePurposeTitle": "Usage de l'instance", "admin_purpose_personal": "Usage personnel, famille ou amis", "admin_purpose_org": "Usage associatif", - "admin_purpose_education": "Usage en entreprise", + "admin_purpose_education": "Usage éducatif, école ou université", "admin_purpose_public": "Service gratuit ouvert au public" } From 132bc43e839b194000ae1fc41ddaec640a721830 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 5 Jul 2021 12:55:54 +0200 Subject: [PATCH 087/117] Translated using Weblate (French) Currently translated at 100.0% (1366 of 1366 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 0ce9e2d6f..101ca1c0d 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1364,5 +1364,7 @@ "admin_purpose_personal": "Usage personnel, famille ou amis", "admin_purpose_org": "Usage associatif", "admin_purpose_education": "Usage éducatif, école ou université", - "admin_purpose_public": "Service gratuit ouvert au public" + "admin_purpose_public": "Service gratuit ouvert au public", + "admin_purpose_business": "Usage en entreprise", + "admin_instancePurposeHint": "À quel usage cette instance est-elle destinée ? Votre réponse sera utilisée pour définir la planification de nouvelles fonctionnalités (si votre télémétrie est activée)." } From 15fc16fca33d84362aaebaec0d0f5d6766e953bf Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 5 Jul 2021 18:49:54 +0530 Subject: [PATCH 088/117] update changelog and version strings for 4.8.0 --- CHANGELOG.md | 94 +++++++++++++++++++++++------------------ customize.dist/pages.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a38bfb1..01bb874c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,43 +1,57 @@ -# WIP - -* WIP file conversion utilities -* server - * `installMethod: 'unspecified'` in the default config to distinguish docker installs - * `instancePurpose` on admin panel - * add support for archiving pin lists (instead of deleting them) - * blocks - * archive blocks instead of deleting them outright - * implement as storage API - * validate blocks in worker - * don't include adminEmail in telemetry unless we have consentToContact - * don't include instancePurpose in telemetry if it is "noanswer" -* display warnings when remote resources are blocked - * in code preview -* restrict style tags to a scope when rendering them in markdown preview by compiling their content as scoped less -* iPhone/Safari calendar and notification fixes (data parsing errors) -* checkup - * display actual FLoC header in checkup test - * WIP check for `server_tokens` settings (needs work for HTTP2) - * nicer output in error/warning tables - * more tests for Cross-Origin-Opener-Policy headers -* form templates -* guard against a type error in `getAccessKeys` -* guard against invalid or malicious input when constructing media-tags for embedding in markdown -* Japanese translation -* conversions - * convert app - * some basic office formats - * rich text => markdown (via turndown.js v7.1.1) - * handle some pecularities with headings and ids - * forms => .csv - * trello import with some loss -* fix rendering issue for legacy markdown media tag syntax - * guard against domExceptions - * catch errors thrown by the diff applier -* don't bother returning the hash of a pin list to the client, since they don't use it -* accounts - * trim leading and trailing whitespace from usernames when registering - * double-check that login blocks can be loaded after they have been written without error +# 4.8.0 + +## Goals + +This release cycle we decided to give people a chance to try our forms app and provide feedback before we begin developing its second round of major features and improvements. In the meantime we planned to work mostly on the activities of our [NGI DAPSI](https://dapsi.ngi.eu/) project which concerns client-side file format conversions. Otherwise, we dedicated some of our independently funded time towards some internal code review and security best-practices as a follow-up to the recent quick-scan performed by [Radically Open Security](https://radicallyopensecurity.com/) that was funded by [NLnet](https://nlnet.nl) as a part of our now-closing _CryptPad for Communities_ project. + +## Update notes + +We are still accepting feedback concerning our Form application via [a form hosted on CryptPad.fr](https://cryptpad.fr/form/#/2/form/view/gYs4QS7DetInCXy0z2CQoUW6CwN6kaR2utGsftDzp58/). We will accept feedback here until July 12th, 2021, so if you'd like your opinions to be represented in the app's second round of development act quickly! + +Following our last release we sent out an email to the admins of each outdated instance that had included their addresses in the server's daily telemetry. This appears to have been successful, as more than half of the 700+ instances that provide this telemetry are now running **4.7.0**. Previously, only 15% of instances were running the latest version. It's worth noting that of those admins that are hosting the latest version, less than 10% have opted into future emails warning them of security issues. In case you missed it, this can be done on the admin panel's _Network_ tab. Unlike most companies, we consider excess data collection a liability rather than an asset. As such, adminstrator emails are no longer included in server telemetry unless the admin has consented to be contacted. + +The same HTTP request that communicates server telemetry will soon begin responding with the URL of our latest release notes if it is detected that the remote instance is running an older version. The admin panel's _Network_ tab for instances running 4.7.0 or later will begin prompting admins to view the release notes and update once 4.8.0 is available. + +The Network tab now includes a multiple choice form as well. If you have not disabled your instance's telemetry you can use this field to answer _why you run your instance_ (for a business, an academic institution, personal use, etc.). We intend to use this data to inform our development roadmap, though as always, the fastest way to get us to prioritize your needs is to contact us for a support contract (sales@cryptpad.fr). + +Server telemetry will also include an `installMethod` property. By default this is `"unspecified"`, but we are planning to work with packagers of alternate install methods to modify this property in their installation scripts. This will help us assess what proportion of instances are installed via the steps included in our installation guide vs other methods such as the various docker images. We hope that it will also allow us to determine the source of some common misconfigurations so we can propose some improvements to the root cause. + +Getting off the topic of telemetry: two types of data that were previously deleted outright (pin logs and login blocks) are now archived when the client sends a _remove_ command. This provides for the ability to restore old user credentials in cases where users claim that their new credentials do not work following a password change. Some discretion is required in such cases as a user might have intentionally invalidated their old credentials due to shoulder-surfing or the breach of another service's database where they'd reused credentials. Neither of these types of data are currently included in the scripts which evict old data as they are not likely to consume a significant amount of storage space. In any case, CryptPad's data is stored on the filesystem, so it's always possible to remove outdated files by removing them from `cryptpad/data/archive/*` or whatever path you've configured for your archives. + +This release introduces some minor changes to the provided NGINX configuration file to enable support for WebAssembly where it is required for client-side file format conversions. We've added some new tests on the /checkup/ page that determine whether these changes have been applied. This page can be found via a button on the admin panel. + +To update from 4.7.0 to 4.8.0: + +1. Apply the documented NGINX configuration +2. Stop your server +3. Get the latest code with git +4. Install the latest dependencies with `bower update` and `npm i` +5. Restart your server +6. Confirm that your instance is passing all the tests included on the `/checkup/` page + +## Features + +* Those who prefer using tools localized in Japanese can thank [@Suguru](https://mstdn.progressiv.dev/@suguru) for completing the Japanese translation of the platform's text! CryptPad is a fairly big platform with a lot of text to translate, so we really appreciate how much effort went into this. + * While we're on the topic, CryptPad's _Deutsch_ translation is kept up to date largely by a single member of the German Pirate Party (Piratenpartei Deutschland). This is a huge job and we appreciate your work too! + * Anyone else who wishes to give back to the project by doing the same can contribute translations on an ongoing basis through [our Weblate instance](https://weblate.cryptpad.fr/projects/cryptpad/app/). +* We've implemented a new app for file format conversions as a part of our _INTEROFFICE_ project. At this point this page is largely a test-case for the conversion engine that we hope to integrate more tightly into the rest of the platform. It allows users to load a variety of file formats into their browser and convert to any other format that has a defined conversion process from the original format. What's special about this is that files are converted entirely in your browser, unlike other platforms which do so in the cloud and expose their contents in the process. Currently we support conversion between the following formats in every browser that supports modern web standards (ie. not safari): + * XLSX and ODS + * DOCX and ODT and TXT + * PPTX and ODP +* In addition to the /convert/ page which supports office file formats, we also put some time into improving interoperability for our existing apps. We're introducing the ability to export rich text documents as Markdown (via the [turndown](https://github.com/mixmark-io/turndown) library), to import trello's JSON format into our Kanban app (with some loss of attributes because we don't support all the same features), and to export form summaries as CSV files. +* We've added another extension to our customized markdown renderer which replaces markdown images with a warning that CryptPad blocks remote content to prevent malicious users from tracking visitors to certain pages. Such images should already be blocked by our strict use of Content-Security-Policy headers, but this will provide a better indication why images are failing to load on isnstances that are correctly configured and a modest improvement to users' privacy on instances that aren't. +* Up until now it was possible to include style tags in markdown documents, which some of our more advanced users used in order to customize the appearance of their rendered documents. Unfortunately, these styles were not applied strictly to the markdown preview window, but to the page as a whole, making it possible to break the platform's interface (for that pad) through the use of overly broad and powerful style rules. As of this release style tags are now treated as special elements, such that their contents are compiled as [LESS](https://lesscss.org/) within a scope that is only applied to the preview pane. This was intended as a bug fix, but it's included here as a _feature_ because advanced users might see it as such and use it to do neat things. We have no funding for further work in this direction, however, and presently have no intent of providing documentation about this behaviour. +* The checkup page uses some slightly nicer methods of displaying values returned by tests when the expected value of `true` is not returned. Some tests have been revised to return the problematic value instead of `false` when the test fails, since there were some cases where it was not clear why the test was failing, such as when a header was present but duplicated. +* We've made some server requests related to _pinning files_ moderately faster by skipping an expensive calculation and omitting the value it returned. This value was meant to be used as a checksum to ensure that all of a user's documents were included in the list which should be associated with their account, however, clients used a separate command to fetch this checksum. The value provided in response to the other commands was never used by the client. +* We've implemented a system on the client for defining default templates for particular types of documents across an entire instance in addition to the use of documents in the _templates_ section of the users drive (or that of their teams). This is intended more as a generic system for us to reuse throughout the platform's source than an API for instance admins to use. If there is sufficient interest (and funding) from other admins we'll implement this as an instance configuration point. We now provide a _poll_ template to replicate the features of our old poll app which has been deprecated in favour of forms. + +## Bug fixes + +* It was brought to our attention that the registration page was not trimming leading and trailing whitespace from usernames as intended. We've updated the page to do so, however, accounts created with such characters in their username field must enter their credentials exactly as they were at registration time in order to log in. We have no means of detecting such accounts on the server, as usernames are not visible to server admins. We'll consider this behaviour in the future if we introduce an option to change usernames as we do with passwords. +* We now double-check that login blocks (account credentials encrypted with a key derived from a username and password) can be accessed by the client when registering or changing passwords. It should be sufficient to rely on the server to report whether the encrypted credentials were stored successfully when uploading them, but in instances where these resources don't load due to a misbehaving browser extension it's better that we detect it at registration time rather than after the user creates content that will be difficult to access without assistance determining which extension or browser customization is to blame. +* We learned that the Javascript engine used on iOS has trouble parsing an alternative representation of data strings that every other platform seems to handle. This caused calendars to display incorrect data. Because Apple prevents third-party browsers from including their own JavaScript engines this means that users were affected by this Safari bug regardless of whether they used browsers branded as Safari, Firefox, Chrome, or otherwise. +* After some internal review we now guard against a variety of cases where user-crafted input could trigger a DOMException error and prevent a whole page worth of markdown content to fail to render. While there is no impact for users' privacy or security in this bug, a malicious user could exploit it to be annoying. +* Shortly after our last release a user reported being unable to access their account due to a typeError which we were able to [guard against](https://github.com/xwiki-labs/cryptpad/commit/abc9466abe71a76d1d31ef6a3c2c9bba4d2233e4). # 4.7.0 diff --git a/customize.dist/pages.js b/customize.dist/pages.js index b0fd2f20a..18632f6ea 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -105,7 +105,7 @@ define([ var imprintUrl = AppConfig.imprint && (typeof(AppConfig.imprint) === "boolean" ? '/imprint.html' : AppConfig.imprint); - Pages.versionString = "v4.7.0"; + Pages.versionString = "v4.8.0"; // used for the about menu diff --git a/package-lock.json b/package-lock.json index ab294ec92..4d7992f82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "cryptpad", - "version": "4.7.0", + "version": "4.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f9dfc2c14..9e18f05f0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "4.7.0", + "version": "4.8.0", "license": "AGPL-3.0+", "repository": { "type": "git", From 19eddb1af61c68d098bd49e88f50202c42287ef3 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 5 Jul 2021 18:57:32 +0530 Subject: [PATCH 089/117] grep the changelog for 'the the ' --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01bb874c5..721fa7ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -543,7 +543,7 @@ To upgrade from 3.24.0 to 3.25.0: ## Features * This release makes a lot of changes to how content is loaded over the network. - * Most notably, CryptPad now employs a client-side cache based on the the _indexedDB API_. Browsers that support this functionality will opportunistically store messages in a local cache for the next time they need them. This should make a considerable difference in how quickly you're able to load a pad, particularly if you accessing the server over a low-bandwidth network. + * Most notably, CryptPad now employs a client-side cache based on the _indexedDB API_. Browsers that support this functionality will opportunistically store messages in a local cache for the next time they need them. This should make a considerable difference in how quickly you're able to load a pad, particularly if you accessing the server over a low-bandwidth network. * Uploaded files (images, PDFs, etc.) are also cached in a similar way. Once you'd loaded an asset, your client will prefer to load its local copy instead of the server. * We've updated the code for our _full drive backup_ functionality so that it uses the local cache to load files more quickly. In addition to this, backing up the contents of your drive will also populate the cache as though you had loaded your documents in the normal fashion. This cache will persist until it is invalidated (due to the authoritative document having been deleted or had its history trimmed) or until you have logged out. * We've added the ability to configure the maximum size for automatically downloaded files. Any encrypted files that are above this size will instead require manual interaction to begin downloading. Files that are larger than this limit which are already loaded in your cache will still be automatically displayed. @@ -2063,7 +2063,7 @@ Finally, we prioritized the ability to archive files for a period instead of del * Users with existing friends on the platform will run a migration to allow them to share pads with friends directly instead of sending them a link. * they'll receive a notification indicating the title of the pad and who shared it * if you've already added friends on the platform, you can send them pads from the usual "sharing menu" -* Our code editor already offered the ability to set their color theme and highlighting mode, but now those values will be previewed when mousing over the the option in the dropdown. +* Our code editor already offered the ability to set their color theme and highlighting mode, but now those values will be previewed when mousing over the option in the dropdown. * Our slide editor now offers the same theme selection as the code editor * It's now possible to view the history of a shared folder by clicking the history button while viewing the shared folder's contents. From 30955260669d5124b50c064acf4f7f93c988da0d Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 5 Jul 2021 18:59:33 +0530 Subject: [PATCH 090/117] remove some notes that have been addressed --- www/checkup/main.js | 3 +-- www/convert/inner.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 143d1709b..f4a40d11e 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -732,7 +732,6 @@ define([ cb(isHTTPS(trimmedUnsafe) && isHTTPS(trimmedSafe)); }); - [ 'sheet', 'presentation', @@ -787,7 +786,7 @@ define([ " header. This information can make it easier for attackers to find and exploit known vulnerabilities. ", ]; - if (family === 'NGINX') { // XXX incorrect instructions for HTTP2. needs a recompile? + if (family === 'NGINX') { // FIXME incorrect instructions for HTTP2. needs a recompile? msg.appendChild(h('span', text.concat([ "This can be addressed by setting ", code("server_tokens off"), diff --git a/www/convert/inner.js b/www/convert/inner.js index 4952b2d6e..cdcf745ca 100644 --- a/www/convert/inner.js +++ b/www/convert/inner.js @@ -48,7 +48,6 @@ define([ debug("x2t mount done"); }; var getX2t = function (cb) { - // XXX require http headers on firefox... require(['/common/onlyoffice/x2t/x2t.js'], function() { // FIXME why does this fail without an access-control-allow-origin header? var x2t = window.Module; x2t.run(); From 5070a751cd4830a5edf94b0c9a8c5a9a7c11b8ba Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 5 Jul 2021 19:21:22 +0530 Subject: [PATCH 091/117] style remote image warnings in slides --- www/slide/app-slide.less | 1 + 1 file changed, 1 insertion(+) diff --git a/www/slide/app-slide.less b/www/slide/app-slide.less index 7e518a1c7..ce12b1de3 100644 --- a/www/slide/app-slide.less +++ b/www/slide/app-slide.less @@ -356,6 +356,7 @@ } .markdown_main(); + .markdown_cryptpad(); .markdown_preformatted-code; .markdown_gfm-table(); From aaa18a3feb320ed39051b32b2c59adc873479a67 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 13:23:41 +0530 Subject: [PATCH 092/117] fix stretched images in 'lightbox' preview modal --- customize.dist/src/less2/include/modals-ui-elements.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/customize.dist/src/less2/include/modals-ui-elements.less b/customize.dist/src/less2/include/modals-ui-elements.less index 92fef68d0..7ec19a699 100644 --- a/customize.dist/src/less2/include/modals-ui-elements.less +++ b/customize.dist/src/less2/include/modals-ui-elements.less @@ -221,6 +221,9 @@ button { line-height: 1.5; } + img { + align-self: center; + } & > iframe { width: 100%; height: 100%; From f652d11ace5cd53f72c245affc31e28f03280cbe Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 14:02:29 +0530 Subject: [PATCH 093/117] don't show the 'remote image warning' for data URLs in markdown --- www/common/diffMarked.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 52a8cf0a1..99031b336 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -292,6 +292,9 @@ define([ if (typeof(window.URL) === 'undefined') { return false; } try { var url = new URL(href, ApiConfig.httpUnsafeOrigin); + // FIXME data URLs can be quite large, but that should be addressed + // in the source markdown's, not the renderer + if (url.protocol === 'data:') { return true; } var localURL = new URL(ApiConfig.httpUnsafeOrigin); return url.host === localURL.host; } catch (err) { From 1b50efe7acd97f122ec67a7c0478ad9772f507a2 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 6 Jul 2021 11:13:42 +0200 Subject: [PATCH 094/117] Add more debugging metadata to support tickets --- www/common/outer/team.js | 7 +++++++ www/support/inner.js | 14 +++++++++++--- www/support/ui.js | 14 ++++++++------ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/www/common/outer/team.js b/www/common/outer/team.js index 3dc39c6f3..4184b8482 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -2040,9 +2040,16 @@ define([ if (['drive', 'teams', 'settings'].indexOf(app) !== -1) { safe = true; } Object.keys(teams).forEach(function (id) { if (!ctx.teams[id]) { return; } + var proxy = ctx.teams[id].proxy || {}; + var nPads = proxy.drive && Object.keys(proxy.drive.filesData || {}).length; + var nSf = proxy.drive && Object.keys(proxy.drive.sharedFolders || {}).length; t[id] = { owner: teams[id].owner, name: teams[id].metadata.name, + channel: teams[id].channel, + numberPads: nPads, + numberSf: nSf, + roster: Util.find(teams[id], ['keys', 'roster', 'channel']), edPublic: Util.find(teams[id], ['keys', 'drive', 'edPublic']), avatar: Util.find(teams[id], ['metadata', 'avatar']), viewer: !Util.find(teams[id], ['keys', 'drive', 'edPrivate']), diff --git a/www/support/inner.js b/www/support/inner.js index f466e7693..6d9e5eae8 100644 --- a/www/support/inner.js +++ b/www/support/inner.js @@ -272,19 +272,27 @@ define([ APP.$rightside = $('
    ', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container); var sFrameChan = common.getSframeChannel(); sFrameChan.onReady(waitFor()); + }).nThen(function (waitFor) { + metadataMgr = common.getMetadataMgr(); + privateData = metadataMgr.getPrivateData(); common.getPinUsage(null, waitFor(function (err, data) { if (err) { return void console.error(err); } APP.pinUsage = data; })); + APP.teamsUsage = {}; + Object.keys(privateData.teams).forEach(function (teamId) { + common.getPinUsage(teamId, waitFor(function (err, data) { + if (err) { return void console.error(err); } + APP.teamsUsage[teamId] = data; + })); + }); }).nThen(function (/*waitFor*/) { createToolbar(); - metadataMgr = common.getMetadataMgr(); - privateData = metadataMgr.getPrivateData(); common.setTabTitle(Messages.supportPage); APP.origin = privateData.origin; APP.readOnly = privateData.readOnly; - APP.support = Support.create(common, false, APP.pinUsage); + APP.support = Support.create(common, false, APP.pinUsage, APP.teamsUsage); // Content var $rightside = APP.$rightside; diff --git a/www/support/ui.js b/www/support/ui.js index 679776c59..90fd43fa5 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -31,9 +31,7 @@ define([ if (typeof(ctx.pinUsage) === 'object') { // pass pin.usage, pin.limit, and pin.plan if supplied - Object.keys(ctx.pinUsage).forEach(function (k) { - data.sender[k] = ctx.pinUsage[k]; - }); + data.sender.quota = ctx.pinUsage; } data.id = id; @@ -45,11 +43,14 @@ define([ data.sender.blockLocation = privateData.blockLocation || ''; data.sender.teams = Object.keys(teams).map(function (key) { var team = teams[key]; - if (!teams) { return; } + if (!team) { return; } var ret = {}; - ['edPublic', 'owner', 'viewer', 'hasSecondaryKey', 'validKeys'].forEach(function (k) { + ['channel', 'roster', 'numberPads', 'numberSf', 'edPublic', 'curvePublic', 'owner', 'viewer', 'hasSecondaryKey', 'validKeys'].forEach(function (k) { ret[k] = team[k]; }); + if (ctx.teamsUsage && ctx.teamsUsage[key]) { + ret.quota = ctx.teamsUsage[key]; + } return ret; }).filter(Boolean); @@ -430,12 +431,13 @@ define([ ]); }; - var create = function (common, isAdmin, pinUsage) { + var create = function (common, isAdmin, pinUsage, teamsUsage) { var ui = {}; var ctx = { common: common, isAdmin: isAdmin, pinUsage: pinUsage || false, + teamsUsage: teamsUsage || false, adminKeys: Array.isArray(ApiConfig.adminKeys)? ApiConfig.adminKeys.slice(): [], }; From c1b3ac89605e8c721a5e182c754a2dfe00b2dfa6 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 6 Jul 2021 11:29:19 +0200 Subject: [PATCH 095/117] Translated using Weblate (English) Currently translated at 100.0% (1367 of 1367 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 4573aa665..45e9afecf 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1366,5 +1366,6 @@ "admin_purpose_education": "For a school, college, or university", "admin_purpose_public": "To provide a free service to the public", "admin_purpose_business": "For a business or commercial organization", - "admin_instancePurposeHint": "Why do you run this instance? Your answer will be used to inform the development roadmap if your telemetry is enabled." + "admin_instancePurposeHint": "Why do you run this instance? Your answer will be used to inform the development roadmap if your telemetry is enabled.", + "team_leaveOwner": "Please demote yourself from the owner role before leaving the team. Note that teams must have at least one owner, please add one before proceeding if you are currently the only owner." } From bceff56d0245a341de120c0107152c5ae654d33e Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 15:00:54 +0530 Subject: [PATCH 096/117] remove hardcoded translation --- www/teams/inner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/teams/inner.js b/www/teams/inner.js index 7a7cf9116..373a27998 100644 --- a/www/teams/inner.js +++ b/www/teams/inner.js @@ -904,7 +904,6 @@ define([ var leave = h('button.cp-online.btn.btn-danger', Messages.team_leaveButton); $(leave).click(function () { if (me && me.role === 'OWNER') { - Messages.team_leaveOwner = "Owners can't leave the team. You can demote yourself if there is at least one other owner."; // XXX return void UI.alert(Messages.team_leaveOwner); } UI.confirm(Messages.team_leaveConfirm, function (yes) { From 517f9797455b060c444a2bdba86f04a7a2f8447c Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 6 Jul 2021 11:44:16 +0200 Subject: [PATCH 097/117] Translated using Weblate (Japanese) Currently translated at 100.0% (1367 of 1367 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ Translated using Weblate (Japanese) Currently translated at 100.0% (1367 of 1367 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/ja/ --- www/common/translations/messages.ja.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/translations/messages.ja.json b/www/common/translations/messages.ja.json index fded593cf..714cb4c00 100644 --- a/www/common/translations/messages.ja.json +++ b/www/common/translations/messages.ja.json @@ -428,7 +428,7 @@ "settings_disableThumbnailsAction": "CryptDriveでのサムネイルの作成を無効にする", "settings_resetError": "入力した確認文が正しくありません。CryptDriveのデータは消去されていません。", "settings_resetDone": "データが消去されました!", - "settings_resetPrompt": "あなたのドライブからのパッドを削除します。
    本当に続けてよろしいですか?
    続けるには「I love CryptPad」と入力してください。", + "settings_resetPrompt": "あなたのドライブからのパッドを削除します。
    本当に続けてよろしいですか?
    続けるには「I love CryptPad」と入力してください。", "settings_reset": "CryptDriveの全てのファイルとフォルダを削除", "settings_exportErrorOther": "ドキュメントのエクスポート中にエラーが発生しました: {0}", "drive_activeOld": "以前のパッド", @@ -1366,5 +1366,6 @@ "reminder_date": "{0}が{1}にあります", "calendar_more": "あと{0}個", "reminder_time": "{0}が今日の{1}にあります", - "form_answerWarning": "本人であることが確認されていません" + "form_answerWarning": "本人であることが確認されていません", + "team_leaveOwner": "チームから退出する前に、オーナーの役割から降格してください。チームには最低1人以上のオーナーが必要です。あなたが唯一のオーナーの場合は、別のオーナーを追加してください。" } From 05043b96c5279fed40bac90fafab641a2b34a892 Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 6 Jul 2021 12:10:58 +0200 Subject: [PATCH 098/117] Translated using Weblate (German) Currently translated at 100.0% (1367 of 1367 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 6c2e6695c..195fcc8af 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1366,5 +1366,6 @@ "admin_instancePurposeTitle": "Zweck der Instanz", "admin_instancePurposeHint": "Warum betreibst du diese Instanz? Deine Antwort wird mit den Entwicklern geteilt, sofern die Telemetrie aktiviert ist.", "admin_purpose_public": "Zur Bereitstellung eines kostenlosen Dienstes für die Allgemeinheit", - "resources_learnWhy": "Mehr über die Gründe erfahren" + "resources_learnWhy": "Mehr über die Gründe erfahren", + "team_leaveOwner": "Bitte entferne dich von der Rolle des Eigentümers, bevor du das Teams verlässt. Beachte, dass Teams mindestens einen Eigentümer haben müssen. Bitte füge daher zunächst einen weiteren Eigentümer hinzu, sofern du derzeit der alleinige Eigentümer bist." } From 7bdabb5cbc3853090b3b133587e820e48495b75d Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 15:42:37 +0530 Subject: [PATCH 099/117] archive blocks before overwriting them --- lib/storage/block.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/storage/block.js b/lib/storage/block.js index d3e7a1869..1078f6d2e 100644 --- a/lib/storage/block.js +++ b/lib/storage/block.js @@ -72,9 +72,16 @@ Block.write = function (Env, publicKey, buffer, _cb) { w.abort(); cb(err); })); + }).nThen(function (w) { + Block.archive(Env, publicKey, w(function (/* err */) { + /* + we proceed even if there are errors. + it might be ENOENT (there is no file to archive) + or EACCES (bad filesystem permissions for the existing archived block?) + or lots of other things, none of which justify preventing the write + */ + })); }).nThen(function () { - // XXX BLOCK check whether this overwrites a block - // XXX archive the old one if so Fs.writeFile(path, buffer, { encoding: 'binary' }, cb); }); }; From b2ed8f4fb0ff94626b253bdd7d1e91a2dd1ef8d0 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 15:44:10 +0530 Subject: [PATCH 100/117] handle missing languages and other errors ...when checking translations for HTML --- scripts/find-html-translations.js | 15 ++++++++++----- scripts/pin-test.js | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 scripts/pin-test.js diff --git a/scripts/find-html-translations.js b/scripts/find-html-translations.js index dabdbac4b..fc1d4a18e 100644 --- a/scripts/find-html-translations.js +++ b/scripts/find-html-translations.js @@ -9,6 +9,7 @@ var simpleTags = [ // FIXME "", + '', '

    ', '

    ', @@ -70,7 +71,7 @@ processLang(EN, 'en', true); [ 'ar', - 'bn_BD', + //'bn_BD', 'ca', 'de', 'es', @@ -86,11 +87,15 @@ processLang(EN, 'en', true); 'ro', 'ru', 'sv', - 'te', + //'te', 'tr', 'zh', ].forEach(function (lang) { - var map = require("../www/common/translations/messages." + lang + ".json"); - if (!Object.keys(map).length) { return; } - processLang(map, lang); + try { + var map = require("../www/common/translations/messages." + lang + ".json"); + if (!Object.keys(map).length) { return; } + processLang(map, lang); + } catch (err) { + console.error(err); + } }); diff --git a/scripts/pin-test.js b/scripts/pin-test.js new file mode 100644 index 000000000..fe313c45b --- /dev/null +++ b/scripts/pin-test.js @@ -0,0 +1,19 @@ +var Pins = require("../lib/pins"); +var Fs = require("fs"); + +var content = Fs.readFileSync('./data/pins/Bp/BpL3pEyX2IlfsvxQELB9uz5qh+40re0gD6J6LOobBm8=.ndjson', 'utf8'); + +//var lines = content.split("\n"); + +//console.log(content); + +var result; + +for (var i = 0; i < 10000; i++) { + result = Pins.calculateFromLog(content, function (label, data) { + console.log([label, data]); + }); +} + +//console.log(result, result.length); + From 15dc966f50aefa8c2f968a8b31ec724779fdba41 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 15:47:34 +0530 Subject: [PATCH 101/117] remove local benchmarking test with hardcoded values --- scripts/pin-test.js | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 scripts/pin-test.js diff --git a/scripts/pin-test.js b/scripts/pin-test.js deleted file mode 100644 index fe313c45b..000000000 --- a/scripts/pin-test.js +++ /dev/null @@ -1,19 +0,0 @@ -var Pins = require("../lib/pins"); -var Fs = require("fs"); - -var content = Fs.readFileSync('./data/pins/Bp/BpL3pEyX2IlfsvxQELB9uz5qh+40re0gD6J6LOobBm8=.ndjson', 'utf8'); - -//var lines = content.split("\n"); - -//console.log(content); - -var result; - -for (var i = 0; i < 10000; i++) { - result = Pins.calculateFromLog(content, function (label, data) { - console.log([label, data]); - }); -} - -//console.log(result, result.length); - From 706166bc60913a01f94bc55ed0d411458a36d665 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 16:05:57 +0530 Subject: [PATCH 102/117] add last-minute fixes to the changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 721fa7ff5..5c05ce5ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ To update from 4.7.0 to 4.8.0: * The checkup page uses some slightly nicer methods of displaying values returned by tests when the expected value of `true` is not returned. Some tests have been revised to return the problematic value instead of `false` when the test fails, since there were some cases where it was not clear why the test was failing, such as when a header was present but duplicated. * We've made some server requests related to _pinning files_ moderately faster by skipping an expensive calculation and omitting the value it returned. This value was meant to be used as a checksum to ensure that all of a user's documents were included in the list which should be associated with their account, however, clients used a separate command to fetch this checksum. The value provided in response to the other commands was never used by the client. * We've implemented a system on the client for defining default templates for particular types of documents across an entire instance in addition to the use of documents in the _templates_ section of the users drive (or that of their teams). This is intended more as a generic system for us to reuse throughout the platform's source than an API for instance admins to use. If there is sufficient interest (and funding) from other admins we'll implement this as an instance configuration point. We now provide a _poll_ template to replicate the features of our old poll app which has been deprecated in favour of forms. +* We've included some more non-sensitive information about users' teams to the debugging data to which is automatically submitted along with support tickets, such as the id of the team's drive, roster, and how large the drive's contents are. ## Bug fixes @@ -52,6 +53,8 @@ To update from 4.7.0 to 4.8.0: * We learned that the Javascript engine used on iOS has trouble parsing an alternative representation of data strings that every other platform seems to handle. This caused calendars to display incorrect data. Because Apple prevents third-party browsers from including their own JavaScript engines this means that users were affected by this Safari bug regardless of whether they used browsers branded as Safari, Firefox, Chrome, or otherwise. * After some internal review we now guard against a variety of cases where user-crafted input could trigger a DOMException error and prevent a whole page worth of markdown content to fail to render. While there is no impact for users' privacy or security in this bug, a malicious user could exploit it to be annoying. * Shortly after our last release a user reported being unable to access their account due to a typeError which we were able to [guard against](https://github.com/xwiki-labs/cryptpad/commit/abc9466abe71a76d1d31ef6a3c2c9bba4d2233e4). +* Images appearing in the 'lightbox' preview modal no longer appear stretched. +* Before applying actions that modify the team's membership we now confirm that server-enforced permissions match our local state. # 4.7.0 From f13b82bdf6fecc39d514aee41f94a68069ec9d5d Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 16:14:40 +0530 Subject: [PATCH 103/117] disable integrated eviction by default we'll implement an admin panel checkbox to enable it later --- lib/env.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/env.js b/lib/env.js index 141e028ae..3d58f11f7 100644 --- a/lib/env.js +++ b/lib/env.js @@ -123,7 +123,7 @@ module.exports.create = function (config) { maxWorkers: config.maxWorkers, disableIntegratedTasks: config.disableIntegratedTasks || false, - disableIntegratedEviction: config.disableIntegratedEviction || true, // XXX false, + disableIntegratedEviction: typeof(config.disableIntegratedEviction) === 'undefined'? true: config.disableIntegratedEviction, // XXX false, lastEviction: +new Date(), evictionReport: {}, commandTimers: {}, From 7049396bd958f06c5ab1111e665e2fa465560d54 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 16:14:52 +0530 Subject: [PATCH 104/117] remove unneeded XXX note --- www/common/application_config_internal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 971da32ee..15e5b5e34 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -22,7 +22,7 @@ define(function() { */ AppConfig.registeredOnlyTypes = ['file', 'contacts', 'notifications', 'support']; - // XXX to prevent apps that aren't officially supported from showing up + // to prevent apps that aren't officially supported from showing up // in the document creation modal AppConfig.hiddenTypes = ['drive', 'teams', 'contacts', 'todo', 'file', 'accounts', 'calendar', 'poll', 'convert', //'doc', 'presentation' From 59f24344a60b1415ccdf48dcf4eebd7919ed8149 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 17:16:22 +0530 Subject: [PATCH 105/117] add a note to the changelog about imperfect form result CSV export --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c05ce5ac..f69b0d723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ To update from 4.7.0 to 4.8.0: * DOCX and ODT and TXT * PPTX and ODP * In addition to the /convert/ page which supports office file formats, we also put some time into improving interoperability for our existing apps. We're introducing the ability to export rich text documents as Markdown (via the [turndown](https://github.com/mixmark-io/turndown) library), to import trello's JSON format into our Kanban app (with some loss of attributes because we don't support all the same features), and to export form summaries as CSV files. + * note: the currently merged implementation does not preserve all information for complex question/answer types such as polls, multi-line radios, or multi-line checkboxes. More improvements will be included in our next release. * We've added another extension to our customized markdown renderer which replaces markdown images with a warning that CryptPad blocks remote content to prevent malicious users from tracking visitors to certain pages. Such images should already be blocked by our strict use of Content-Security-Policy headers, but this will provide a better indication why images are failing to load on isnstances that are correctly configured and a modest improvement to users' privacy on instances that aren't. * Up until now it was possible to include style tags in markdown documents, which some of our more advanced users used in order to customize the appearance of their rendered documents. Unfortunately, these styles were not applied strictly to the markdown preview window, but to the page as a whole, making it possible to break the platform's interface (for that pad) through the use of overly broad and powerful style rules. As of this release style tags are now treated as special elements, such that their contents are compiled as [LESS](https://lesscss.org/) within a scope that is only applied to the preview pane. This was intended as a bug fix, but it's included here as a _feature_ because advanced users might see it as such and use it to do neat things. We have no funding for further work in this direction, however, and presently have no intent of providing documentation about this behaviour. * The checkup page uses some slightly nicer methods of displaying values returned by tests when the expected value of `true` is not returned. Some tests have been revised to return the problematic value instead of `false` when the test fails, since there were some cases where it was not clear why the test was failing, such as when a header was present but duplicated. From 663f0d87717a5b348ba559d1fb6fe65981ec281a Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 17:47:13 +0530 Subject: [PATCH 106/117] Display confirmation on "Log out everywhere" in the upper right menu addresses #765 --- www/common/common-ui-elements.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index a7ef39de6..0ab010cb5 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1886,8 +1886,11 @@ define([ }, content: h('span', Messages.logoutEverywhere), action: function () { - Common.getSframeChannel().query('Q_LOGOUT_EVERYWHERE', null, function () { - Common.gotoURL(origin + '/'); + UI.confirm(Messages.settings_logoutEverywhereConfirm, function (yes) { + if (!yes) { return; } + Common.getSframeChannel().query('Q_LOGOUT_EVERYWHERE', null, function () { + Common.gotoURL(origin + '/'); + }); }); }, }); From 230425c3dea752a902e855a3bb52551baa656a97 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 17:54:18 +0530 Subject: [PATCH 107/117] update changelog again --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f69b0d723..a7987f731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ To update from 4.7.0 to 4.8.0: * We've made some server requests related to _pinning files_ moderately faster by skipping an expensive calculation and omitting the value it returned. This value was meant to be used as a checksum to ensure that all of a user's documents were included in the list which should be associated with their account, however, clients used a separate command to fetch this checksum. The value provided in response to the other commands was never used by the client. * We've implemented a system on the client for defining default templates for particular types of documents across an entire instance in addition to the use of documents in the _templates_ section of the users drive (or that of their teams). This is intended more as a generic system for us to reuse throughout the platform's source than an API for instance admins to use. If there is sufficient interest (and funding) from other admins we'll implement this as an instance configuration point. We now provide a _poll_ template to replicate the features of our old poll app which has been deprecated in favour of forms. * We've included some more non-sensitive information about users' teams to the debugging data to which is automatically submitted along with support tickets, such as the id of the team's drive, roster, and how large the drive's contents are. +* The _Log out everywhere_ option that is displayed in the user admin menu in the top-right corner of the page for logged-in users now displays a confirmation before terminating all remote sessions. ## Bug fixes From 9bb884cac6379663c0dc66ba478d80325e5108ec Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 6 Jul 2021 18:21:47 +0530 Subject: [PATCH 108/117] fix a type error caused by (my) invalid API use --- lib/commands/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/commands/block.js b/lib/commands/block.js index 195e0c494..4af32af70 100644 --- a/lib/commands/block.js +++ b/lib/commands/block.js @@ -88,7 +88,7 @@ Block.validateAncestorProof = function (Env, proof, _cb) { } // else fall through to next step }).nThen(function () { - Block.check(Env, pub, function (err) { + BlockStore.check(Env, pub, function (err) { if (err) { return void cb('E_MISSING_ANCESTOR'); } cb(void 0, pub); }); From 0560a9a403f20e43efeb1b7026620f61451d2a25 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 6 Jul 2021 16:09:30 +0200 Subject: [PATCH 109/117] Fix forms CSV export --- www/form/export.js | 25 +++++++++++++++++-------- www/form/inner.js | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/www/form/export.js b/www/form/export.js index 0e78d171a..4afc4170a 100644 --- a/www/form/export.js +++ b/www/form/export.js @@ -18,13 +18,18 @@ define([ var csv = ""; var form = content.form; - var questions = Object.keys(form).map(function (key) { + var questions = [Messages.form_poll_time, Messages.share_formView]; + + content.order.forEach(function (key) { var obj = form[key]; if (!obj) { return; } - return obj.q || Messages.form_default; - }).filter(Boolean); - questions.unshift(Messages.share_formView); // "Participant" - questions.unshift(Messages.form_poll_time); // "Time" + var type = obj.type; + if (!TYPES[type]) { return; } // Ignore static types + var c; + if (TYPES[type] && TYPES[type].exportCSV) { c = TYPES[type].exportCSV(false, obj); } + if (!c) { c = [obj.q || Messages.form_default]; } + Array.prototype.push.apply(questions, c); + }); questions.forEach(function (v, i) { if (i) { csv += ','; } @@ -39,10 +44,14 @@ define([ var user = msg._userdata || {}; csv += escapeCSV(time); csv += ',' + escapeCSV(user.name || Messages.anonymous); - Object.keys(form).forEach(function (key) { + content.order.forEach(function (key) { var type = form[key].type; - if (TYPES[type] && TYPES[type].exportCSV) { - csv += ',' + escapeCSV(TYPES[type].exportCSV(msg[key])); + if (!TYPES[type]) { return; } // Ignore static types + if (TYPES[type].exportCSV) { + var res = TYPES[type].exportCSV(msg[key], form[key]).map(function (str) { + return escapeCSV(str); + }).join(','); + csv += ',' + res; return; } csv += ',' + escapeCSV(String(msg[key] || '')); diff --git a/www/form/inner.js b/www/form/inner.js index 8e6b30d47..3fe71873d 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1215,6 +1215,20 @@ define([ return h('div.cp-form-results-type-radio', results); }, + exportCSV: function (answer, form) { + var opts = form.opts; + var q = form.q || Messages.form_default; + if (answer === false) { + return (opts.items || []).map(function (obj) { + return q + ' | ' + obj.v; + }); + } + if (!answer) { return ['']; } + return (opts.items || []).map(function (obj) { + var uid = obj.uid; + return String(answer[uid] || ''); + }); + }, icon: h('i.cptools.cptools-form-grid-radio') }, checkbox: { @@ -1429,6 +1443,20 @@ define([ return h('div.cp-form-results-type-radio', results); }, + exportCSV: function (answer, form) { + var opts = form.opts; + var q = form.q || Messages.form_default; + if (answer === false) { + return (opts.items || []).map(function (obj) { + return q + ' | ' + obj.v; + }); + } + if (!answer) { return ['']; } + return (opts.items || []).map(function (obj) { + var uid = obj.uid; + return String(answer[uid] || ''); + }); + }, icon: h('i.cptools.cptools-form-grid-check') }, sort: { @@ -1650,13 +1678,14 @@ define([ return h('div.cp-form-type-poll', lines); }, exportCSV: function (answer) { - if (!answer || !answer.values) { return ''; } + if (answer === false) { return; } + if (!answer || !answer.values) { return ['']; } var str = ''; Object.keys(answer.values).sort().forEach(function (k, i) { if (i !== 0) { str += ';'; } str += k.replace(';', '').replace(':', '') + ':' + answer.values[k]; }); - return str; + return [str]; }, icon: h('i.cptools.cptools-form-poll') }, From fceab00a6bb0ac813cd4132ab41709fd3a3ebbbc Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Jul 2021 13:06:07 +0530 Subject: [PATCH 110/117] guard against type errors when exporting results as CSV and label a hardcoded string --- www/form/inner.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/form/inner.js b/www/form/inner.js index 3fe71873d..07cd07ce5 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1216,7 +1216,7 @@ define([ return h('div.cp-form-results-type-radio', results); }, exportCSV: function (answer, form) { - var opts = form.opts; + var opts = form.opts || {}; var q = form.q || Messages.form_default; if (answer === false) { return (opts.items || []).map(function (obj) { @@ -1444,7 +1444,7 @@ define([ return h('div.cp-form-results-type-radio', results); }, exportCSV: function (answer, form) { - var opts = form.opts; + var opts = form.opts || {}; var q = form.q || Messages.form_default; if (answer === false) { return (opts.items || []).map(function (obj) { @@ -1701,7 +1701,7 @@ define([ var controls = h('div.cp-form-creator-results-controls'); var $controls = $(controls).appendTo($container); - Messages.form_exportCSV = "Export results as CSV"; + Messages.form_exportCSV = "Export results as CSV"; // XXX var exportButton = h('button.btn.btn-secondary', Messages.form_exportCSV); var exportCSV = h('div.cp-form-creator-results-export', exportButton); $(exportCSV).appendTo($container); From e7654112d2281901b45e60b4edc2de9e2e2303c1 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Jul 2021 13:10:07 +0530 Subject: [PATCH 111/117] remove note from changelog about incomplete CSV export --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7987f731..55d0e2534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,6 @@ To update from 4.7.0 to 4.8.0: * DOCX and ODT and TXT * PPTX and ODP * In addition to the /convert/ page which supports office file formats, we also put some time into improving interoperability for our existing apps. We're introducing the ability to export rich text documents as Markdown (via the [turndown](https://github.com/mixmark-io/turndown) library), to import trello's JSON format into our Kanban app (with some loss of attributes because we don't support all the same features), and to export form summaries as CSV files. - * note: the currently merged implementation does not preserve all information for complex question/answer types such as polls, multi-line radios, or multi-line checkboxes. More improvements will be included in our next release. * We've added another extension to our customized markdown renderer which replaces markdown images with a warning that CryptPad blocks remote content to prevent malicious users from tracking visitors to certain pages. Such images should already be blocked by our strict use of Content-Security-Policy headers, but this will provide a better indication why images are failing to load on isnstances that are correctly configured and a modest improvement to users' privacy on instances that aren't. * Up until now it was possible to include style tags in markdown documents, which some of our more advanced users used in order to customize the appearance of their rendered documents. Unfortunately, these styles were not applied strictly to the markdown preview window, but to the page as a whole, making it possible to break the platform's interface (for that pad) through the use of overly broad and powerful style rules. As of this release style tags are now treated as special elements, such that their contents are compiled as [LESS](https://lesscss.org/) within a scope that is only applied to the preview pane. This was intended as a bug fix, but it's included here as a _feature_ because advanced users might see it as such and use it to do neat things. We have no funding for further work in this direction, however, and presently have no intent of providing documentation about this behaviour. * The checkup page uses some slightly nicer methods of displaying values returned by tests when the expected value of `true` is not returned. Some tests have been revised to return the problematic value instead of `false` when the test fails, since there were some cases where it was not clear why the test was failing, such as when a header was present but duplicated. From 96eb5f614e316d5ba65410149e89061248118ee6 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Jul 2021 14:03:54 +0530 Subject: [PATCH 112/117] fix docs link for remote content and localize it --- www/common/diffMarked.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index 99031b336..0fe8aed0a 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -9,11 +9,13 @@ define([ '/common/media-tag.js', '/customize/messages.js', '/common/less.min.js', + '/customize/pages.js', + '/common/highlight/highlight.pack.js', '/lib/diff-dom/diffDOM.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/common/highlight/styles/'+ (window.CryptPad_theme === 'dark' ? 'dark.css' : 'github.css') -],function ($, ApiConfig, Marked, Hash, Util, h, MT, MediaTag, Messages, Less) { +],function ($, ApiConfig, Marked, Hash, Util, h, MT, MediaTag, Messages, Less, Pages) { var DiffMd = {}; var Highlight = window.hljs; @@ -344,7 +346,7 @@ define([ ]), h('br'), h('a.cp-learn-more', { - href: 'https://docs.cryptpad.fr/user_guide/security.html#remote-content', + href: Pages.localizeDocsLink('https://docs.cryptpad.fr/en/user_guide/security.html#remote-content'), }, [ Messages.resources_learnWhy ]), From 5b5c98f929b5a46fde04a68975dc695117b6987a Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jul 2021 10:41:33 +0200 Subject: [PATCH 113/117] Translated using Weblate (French) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/fr/ --- www/common/translations/messages.fr.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.fr.json b/www/common/translations/messages.fr.json index 101ca1c0d..1ea01009b 100644 --- a/www/common/translations/messages.fr.json +++ b/www/common/translations/messages.fr.json @@ -1366,5 +1366,7 @@ "admin_purpose_education": "Usage éducatif, école ou université", "admin_purpose_public": "Service gratuit ouvert au public", "admin_purpose_business": "Usage en entreprise", - "admin_instancePurposeHint": "À quel usage cette instance est-elle destinée ? Votre réponse sera utilisée pour définir la planification de nouvelles fonctionnalités (si votre télémétrie est activée)." + "admin_instancePurposeHint": "À quel usage cette instance est-elle destinée ? Votre réponse sera utilisée pour définir la planification de nouvelles fonctionnalités (si votre télémétrie est activée).", + "team_leaveOwner": "Veuillez vous rétrograder de votre rôle de propriétaire avant de quitter l'équipe. Notez que les équipes doivent avoir au moins un propriétaire, veuillez en ajouter un autre avant de poursuivre si vous êtes actuellement le seul propriétaire.", + "form_exportCSV": "Exporter en CSV" } From 1c95c262b3268b827d256cd58ba2cf60cabde9cb Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jul 2021 10:41:34 +0200 Subject: [PATCH 114/117] Translated using Weblate (German) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/de/ --- www/common/translations/messages.de.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.de.json b/www/common/translations/messages.de.json index 195fcc8af..226e57c7c 100644 --- a/www/common/translations/messages.de.json +++ b/www/common/translations/messages.de.json @@ -1367,5 +1367,6 @@ "admin_instancePurposeHint": "Warum betreibst du diese Instanz? Deine Antwort wird mit den Entwicklern geteilt, sofern die Telemetrie aktiviert ist.", "admin_purpose_public": "Zur Bereitstellung eines kostenlosen Dienstes für die Allgemeinheit", "resources_learnWhy": "Mehr über die Gründe erfahren", - "team_leaveOwner": "Bitte entferne dich von der Rolle des Eigentümers, bevor du das Teams verlässt. Beachte, dass Teams mindestens einen Eigentümer haben müssen. Bitte füge daher zunächst einen weiteren Eigentümer hinzu, sofern du derzeit der alleinige Eigentümer bist." + "team_leaveOwner": "Bitte entferne dich von der Rolle des Eigentümers, bevor du das Teams verlässt. Beachte, dass Teams mindestens einen Eigentümer haben müssen. Bitte füge daher zunächst einen weiteren Eigentümer hinzu, sofern du derzeit der alleinige Eigentümer bist.", + "form_exportCSV": "Als CSV exportieren" } From 78f2cb1d631e995d36a7fa03ef8c84dc66c65e6f Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 7 Jul 2021 10:41:34 +0200 Subject: [PATCH 115/117] Translated using Weblate (English) Currently translated at 100.0% (1368 of 1368 strings) Translation: CryptPad/App Translate-URL: http://weblate.cryptpad.fr/projects/cryptpad/app/en/ --- www/common/translations/messages.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/translations/messages.json b/www/common/translations/messages.json index 45e9afecf..29f415755 100644 --- a/www/common/translations/messages.json +++ b/www/common/translations/messages.json @@ -1367,5 +1367,6 @@ "admin_purpose_public": "To provide a free service to the public", "admin_purpose_business": "For a business or commercial organization", "admin_instancePurposeHint": "Why do you run this instance? Your answer will be used to inform the development roadmap if your telemetry is enabled.", - "team_leaveOwner": "Please demote yourself from the owner role before leaving the team. Note that teams must have at least one owner, please add one before proceeding if you are currently the only owner." + "team_leaveOwner": "Please demote yourself from the owner role before leaving the team. Note that teams must have at least one owner, please add one before proceeding if you are currently the only owner.", + "form_exportCSV": "Export to CSV" } From ccddcefc1d2e2ee0f41b05d12c430a346662b573 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Jul 2021 14:16:43 +0530 Subject: [PATCH 116/117] remove hardcoded translation --- www/form/inner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/form/inner.js b/www/form/inner.js index 07cd07ce5..b2e303f9c 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1701,7 +1701,6 @@ define([ var controls = h('div.cp-form-creator-results-controls'); var $controls = $(controls).appendTo($container); - Messages.form_exportCSV = "Export results as CSV"; // XXX var exportButton = h('button.btn.btn-secondary', Messages.form_exportCSV); var exportCSV = h('div.cp-form-creator-results-export', exportButton); $(exportCSV).appendTo($container); From a398af12134c6dd6b6f8525d5d241f321b021d80 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Jul 2021 14:18:48 +0530 Subject: [PATCH 117/117] use existing translation until next release --- www/form/inner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/form/inner.js b/www/form/inner.js index b2e303f9c..2a1501ecb 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -1701,7 +1701,7 @@ define([ var controls = h('div.cp-form-creator-results-controls'); var $controls = $(controls).appendTo($container); - var exportButton = h('button.btn.btn-secondary', Messages.form_exportCSV); + var exportButton = h('button.btn.btn-secondary', Messages.exportButton); // XXX form_exportCSV; var exportCSV = h('div.cp-form-creator-results-export', exportButton); $(exportCSV).appendTo($container); var results = h('div.cp-form-creator-results-content');