Merge branch 'ooapi' into ooapi-dl

This commit is contained in:
yflory 2024-09-26 18:40:08 +02:00
commit 38f5a56c09
86 changed files with 2944 additions and 592 deletions

11
.gitignore vendored
View File

@ -17,12 +17,11 @@ customize
messages.log
www/scratch
data
pins/
blob/
block/
blobstage/
block/
logs/
pins
blob
block
blobstage
logs
privileged.conf
config/config.js
config/sso.js

View File

@ -29,6 +29,10 @@ Files: .stylelintrc.js
Copyright: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
License: AGPL-3.0-or-later
Files: scripts/tests/test-data/*
Copyright: 2024 XWiki CryptPad Team <contact@cryptpad.org> and contributors
License: AGPL-3.0-or-later
## Dependencies
Files: www/common/theme/*

View File

@ -59,7 +59,7 @@ This release introduces a new onboarding flow to guide administrators through th
- Onboarding screens & app configuration [#1513](https://github.com/cryptpad/cryptpad/pull/1513)
- Bahasa Indonesia is a new available language [fe78b6a](https://github.com/cryptpad/cryptpad/commit/fe78b6ab1dc76ce9eb8d5361c309db8e92117fa8)
- Thanks to our [Weblate](https://weblate.cryptpad.org) contributors who made that happen!
- Thanks to our [Weblate](https://weblate.cryptpad.org) contributors who made that happen!
## Improvements
@ -92,7 +92,7 @@ This release introduces a new onboarding flow to guide administrators through th
- Switch to new `http2` Nginx option [#1516](https://github.com/cryptpad/cryptpad/pull/1516)
- Server fixes and aggregated stats [#1509](https://github.com/cryptpad/cryptpad/pull/1509)
- Create the block folder at boot [#911](https://github.com/cryptpad/cryptpad/pull/911)
- Remove obsolete `version` from `docker-compose.yml` [2e716eb](https://github.com/cryptpad/cryptpad/commit/2e716eb4e39fb835f95a1fa1a340e01142d11b1c)
- Remove obsolete `version` from `docker-compose.yml` [2e716eb](https://github.com/cryptpad/cryptpad/commit/2e716eb4e39fb835f95a1fa1a340e01142d11b1c)
- Other
- Unsharp the corners when hovering the dismiss button on notification drop-down menu [#1466](https://github.com/cryptpad/cryptpad/pull/1466)
- Fix contextual menu `Open` on anonymous drive [#1464](https://github.com/cryptpad/cryptpad/pull/1464)

View File

@ -14,7 +14,7 @@ COPY . /cryptpad
RUN sed -i "s@//httpAddress: 'localhost'@httpAddress: '0.0.0.0'@" /cryptpad/config/config.example.js
RUN sed -i "s@installMethod: 'unspecified'@installMethod: 'docker'@" /cryptpad/config/config.example.js
# Install dependencies
RUN npm install --production \
&& npm run install:components

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner>.
Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View File

@ -35,7 +35,7 @@ Mozilla Public License Version 2.0
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"

View File

@ -38,11 +38,10 @@ var getStoredLanguage = function () { return localStorage && localStorage.getIte
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage || ''; };
var getLanguage = Messages._getLanguage = function () {
if (window.cryptpadLanguage) { return window.cryptpadLanguage; }
try {
if (getStoredLanguage()) { return getStoredLanguage(); }
} catch (e) { console.log(e); }
var l = getBrowserLanguage();
// Edge returns 'fr-FR' --> transform it to 'fr' and check again
try {
l = getStoredLanguage() || getBrowserLanguage();
} catch (e) { console.log(e); }
return map[l] ? l :
(map[l.split('-')[0]] ? l.split('-')[0] :
(map[l.split('_')[0]] ? l.split('_')[0] : 'en'));
@ -135,8 +134,7 @@ define(req, function(AppConfig, Default, Language) {
return text;
}
};
Messages.admin_mfa_confirm_enable = "Are you sure you want to enable Multi-Factor Authentication?"; // XXX
Messages.admin_mfa_confirm_disable = "Are you sure you want to disable Multi-Factor Authentication?"; // XXX
return Messages;
});

View File

@ -28,8 +28,9 @@ define([
var premiumButton = h('a', {
href: accounts.upgradeURL,
target: '_blank',
rel: 'noopener noreferrer'
}, h('button.cp-features-register-button', Msg.features_f_subscribe));
rel: 'noopener noreferrer',
class: 'cp-features-register-button',
}, Msg.features_f_subscribe);
var groupItemTemplate = function (title, content) {
return h('li.list-group-item', [
@ -119,14 +120,15 @@ define([
h('div.card-body',[
h('div.cp-features-register#cp-features-register', [
h('a', {
href: '/register/'
}, h('button.cp-features-register-button', Msg.features_f_register))
href: '/register/',
class: 'cp-features-register-button',
}, Msg.features_f_register)
]),
]),
]),
]);
var premiumFeatures =
h('div.col-12.col-sm-4.cp-anon-user',[
h('div.col-12.col-sm-4.cp-premium-user',[
h('div.card',[
h('div.title-card',[
h('h3.text-center',Msg.features_premium)

View File

@ -153,10 +153,10 @@ define([
if (Pages.areSubscriptionsAllowed() && !LocalStore.getPremium()) {
var sub = h('div.cp-sub-prompt', [
h('span', Msg.home_morestorage),
h('a', {href:"/accounts/"}, h('button', [
h('a', {href:"/accounts/", class:'subscribe-btn'}, [
h('i.fa.fa-ticket'),
Msg.features_f_subscribe
]))
])
]);
return sub;
} else {

View File

@ -200,8 +200,8 @@
}
.cp-usergrid-user, textarea, a, .fa-times {
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
}
@ -244,8 +244,8 @@
}
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
span.alertify-tabs-active {
@ -275,7 +275,7 @@
.tools_placeholder-color();
outline: none;
&:focus-visible {
outline: @cryptpad_color_brand solid 2px;
outline: @variables_focus_style;
}
}

View File

@ -129,8 +129,8 @@
box-sizing: border-box;
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
@ -217,8 +217,8 @@
height: var(--checkmark-dim1);
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}

View File

@ -30,6 +30,11 @@
.cp-unselectable {
.tools_unselectable();
}
.btn-primary{
&:focus-visible {
outline: @variables_focus_style;
}
}
/* local mixins */
@drive_icon-margin: 10px;
@ -329,11 +334,10 @@
overflow: hidden;
text-overflow: ellipsis;
.leftside-menu-category_main();
margin: 0;
display: flex;
align-items: center;
cursor: pointer;
margin-left: -5px;
margin: 0 0 2px -5px;
padding-left: 5px;
.fa, .cptools {
display: inline-block;
@ -348,6 +352,9 @@
overflow: hidden;
text-overflow: ellipsis;
}
&:focus-visible {
outline: @variables_focus_style;
}
}
}
}
@ -373,6 +380,9 @@
padding-left: 20px;
.leftside-menu-category_main();
margin: 0;
&:focus-visible {
outline: @variables_focus_style;
}
}
}
}
@ -399,6 +409,10 @@
position: relative;
top: -1px;
}
&:focus-visible {
outline: @variables_focus_style;
border-radius: @variables_radius_S;
}
}
.cp-app-drive-tree-docs {
box-shadow: @cryptpad_ui_shadow;

View File

@ -28,6 +28,9 @@
}
&.tui-full-calendar-content {
font-size: @colortheme_app-font-size;
&:focus-visible {
outline: @variables_focus_style;
}
}
&[readonly] {
//margin-top:1rem;
@ -138,8 +141,8 @@
color: @cryptpad_text_col;
}
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
}
@ -148,8 +151,8 @@
background-color: @cp_buttons-cancel;
box-sizing: border-box;
align-items: center;
padding: 0 6px;
line-height: 36px;
line-height: 20px;
padding: 8px 6px;
white-space: nowrap;
text-align: center;
text-transform: uppercase;
@ -257,8 +260,8 @@
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
&::-moz-focus-inner {
border: 0;

View File

@ -6,6 +6,7 @@
@import (reference) "./colortheme-all.less";
@import (reference) "./font.less";
@import (reference) "./variables.less";
@infopages-radius: 5px;
@infopages-radius-L: 10px;
@ -46,6 +47,10 @@ body.html {
a:hover {
opacity: 1;
}
a:focus-visible {
outline: @variables_focus_style;
border-radius: @variables_radius;
}
border: 0;
padding: 0;
margin: 0;
@ -231,6 +236,9 @@ body.html {
border: 0px;
border-radius: @infopages-radius;
padding: 0.5em 0.7em;
&:focus-visible {
outline: @variables_focus_style;
}
}
}
.cp-footer-version {
@ -293,6 +301,9 @@ body.html {
&:hover {
color: @cryptpad_text_col;
}
&:focus-visible {
outline: @variables_focus_style;
}
i {
margin-right: 5px;
}

View File

@ -47,6 +47,9 @@
align-items: center;
.leftside-menu-category_main();
box-shadow: @cryptpad_ui_shadow;
&:focus-visible {
outline: @variables_focus_style;
}
}
}
&.cp-leftside-narrow {

View File

@ -81,8 +81,8 @@
padding-left: 4px;
vertical-align: middle;
outline: none;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
.close {

View File

@ -29,35 +29,6 @@
font: @colortheme_app-font;
}
@media screen and (max-width: 870px) {
flex-flow: column;
.cp-toolbar-history-actions {
width: 100%;
.cp-history-actions-first {
margin-right: 0 !important;
}
}
.cp-toolbar-history-timeline {
width: ~"calc(100% - 20px)";
margin-right: 10px !important;
}
}
@media screen and (max-height: 500px) {
padding-top: 0px;
.cp-history-timeline-line {
display: none !important;
}
.cp-toolbar-history-timeline {
width: 100% !important;
margin: 0 !important;
}
.cp-history-timeline-actions {
margin-left: 0 !important;
}
}
&.cp-history-init {
padding: 0;
height: 32px;
@ -102,8 +73,8 @@
text-transform: uppercase;
display: inline-flex;
align-items: center;
.fa:not(:last-child) {
margin-right: 5px;
i:not(:last-child) {
margin-right: 0.5rem;
}
&:hover {
background-color: fade(@cp_toolbar-fg, 30%);
@ -293,6 +264,39 @@
left: ~"calc(50% - 6px)";
}
}
@media screen and (max-width: 870px) {
flex-flow: column;
.cp-toolbar-history-actions {
width: 100%;
margin: 0.6rem 0;
height: auto;
.cp-history-actions-first {
margin-right: 0 !important;
}
button {
margin: 0.1rem;
}
}
.cp-toolbar-history-timeline {
width: ~"calc(100% - 20px)";
margin-right: 10px !important;
}
}
@media screen and (max-height: 500px) {
padding-top: 0px;
.cp-history-timeline-line {
display: none !important;
}
.cp-toolbar-history-timeline {
width: 100% !important;
margin: 0 !important;
}
.cp-history-timeline-actions {
margin-left: 0 !important;
}
}
}
}

View File

@ -77,8 +77,8 @@
&:hover {
background-color: contrast(@cp_toolbar-bg, darken(@cp_toolbar-bg, 5%), lighten(@cp_toolbar-bg, 5%));
}
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
button:nth-of-type(1) {
@ -373,7 +373,7 @@
* {
outline-style: none;
&:focus-visible {
outline: @cryptpad_color_brand solid 2px;
outline: @variables_focus_style;
}
}
@ -676,6 +676,10 @@
overflow: hidden;
text-overflow: ellipsis;
border-collapse: collapse;
&:focus {
margin: 2px;
border-radius: @variables_radius;
}
}
input {
color: @cryptpad_text_col;
@ -983,11 +987,8 @@
height: @toolbar_line-height;
display: inline-flex;
align-items: center;
.fa, .cptools {
margin-right: 5px;
}
.cp-dropdown-button-title .cp-icon {
margin-left: 5px;
i ~ span {
margin-left: 0.5rem;
}
&:hover {
background-color: fade(@cp_toolbar-bottom-bg, 70%);
@ -1109,15 +1110,6 @@
}
}
.cp-toolbar-bottom-left {
.cp-toolbar-appmenu, .cp-toolbar-file {
button {
&::before, .fa {
min-width: 20px;
text-align: center;
margin-right: 0;
}
}
}
.cp-toolbar-file {
order: 1;
}

View File

@ -18,6 +18,8 @@
@variables_shadow: 0 8px 32px 0 @cp_shadow-color;
// Rounded corners
@variables_radius_S: 3px;
@variables_radius: 5px;
@variables_radius_L: 10px;
@variables_focus_style: @cryptpad_color_brand solid 2px;

View File

@ -15,12 +15,19 @@
padding: 20px;
}
.cp-features-register-button {
text-decoration: none;
text-align: center;
background-color: @cp_buttons-primary;
color: @cryptpad_text_col;
font-size: 20px;
color: @cryptpad_color_white;
background: @cryptpad_color_brand;
border-radius: 0;
&:hover {
cursor: pointer;
margin: 10px 0;
border-radius: @infopages-radius;
padding: 10px 20px;
&:hover, &:focus {
background-color: contrast(@cp_buttons-primary-text, darken(@cp_buttons-primary, 10%), lighten(@cp_buttons-primary, 10%));
}
&:visited {
color: @cryptpad_text_col;
}
}
.cp-features-web {
@ -114,5 +121,10 @@
margin-top: 3em;
}
}
.cp-premium-user {
@media (max-width:575px) {
margin-top: 3em;
}
}
}

View File

@ -255,9 +255,10 @@
* {
display: block;
}
button {
background-color: @cryptpad_color_link;
color: @cryptpad_text_col_inv;
.subscribe-btn {
text-align: center;
background-color: @cp_buttons-primary;
color: @cryptpad_text_col;
font-size: 1.4rem;
margin: 10px 0;
border-radius: @infopages-radius-L;
@ -267,8 +268,7 @@
margin-right: 10px;
}
&:hover, &:focus {
background-color: @cp_static-card-bg;
color: @cryptpad_text_col;
background-color: contrast(@cp_buttons-primary-text, darken(@cp_buttons-primary, 10%), lighten(@cp_buttons-primary, 10%));
}
}
}

View File

@ -43,13 +43,10 @@
nav {
display: flex;
align-items: center;
justify-content: flex-end;
}
@media screen and (max-width: 600px) {
nav .btn-danger {
line-height: inherit;
align-items: flex-end;
.btn-confirm {
white-space: normal;
}
}

View File

@ -68,13 +68,10 @@
nav {
display: flex;
align-items: center;
justify-content: flex-end;
}
@media screen and (max-width: 600px) {
nav .btn-danger {
line-height: inherit;
align-items: flex-end;
.btn-confirm {
white-space: normal;
}
}

View File

@ -22,9 +22,9 @@ if [ ! -f "$CPAD_CONF" ]; then
eg: docker run -v /path/to/config.js:/cryptpad/config/config.js \n\
#################################################################### \n"
cp "$CPAD_HOME"/config/config.example.js "$CPAD_CONF"
cp "$CPAD_HOME"/config/config.example.js "$CPAD_CONF"
sed -i -e "s@\(httpUnsafeOrigin:\).*[^,]@\1 '$CPAD_MAIN_DOMAIN'@" \
sed -i -e "s@\(httpUnsafeOrigin:\).*[^,]@\1 '$CPAD_MAIN_DOMAIN'@" \
-e "s@\(^ *\).*\(httpSafeOrigin:\).*[^,]@\1\2 '$CPAD_SANDBOX_DOMAIN'@" "$CPAD_CONF"
fi

10
docs/community/README.md Normal file
View File

@ -0,0 +1,10 @@
<!--
SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-->
# Community configuration files
This folder is listing community-contributed configuration files. They **aren't** supported and are provided as-is, without any warranty.
If you are using CryptPad in production and require professional support please contact sales@cryptpad.org

View File

@ -0,0 +1,245 @@
# SPDX-FileCopyrightText: 2024 XWiki CryptPad Team <contact@cryptpad.org> and contributors
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# This file is included strictly as an example of how Caddy can be configured
# to work with CryptPad. This example WILL NOT WORK AS IS. For best results,
# compare the sections of this configuration file against a working CryptPad
# installation (http server by the Nodejs process). If you are using CryptPad
# in production and require professional support please contact sales@cryptpad.org
(trustedProxies) {
# Force Caddy to accept `X-Forwarded-For` and other origin headers.
# Modify the line below if you want to restrict the scope of direct downstream sending these headers.
trusted_proxies 0.0.0.0/0 ::/0
}
# Caddy does not have variables for server names, so domains need to be hardcoded.
# You can bulk replace "your-main-domain.com" and "your-sandbox-domain.com" safely.
your-main-domain.com:443,
your-sandbox-domain.com:443 {
# Define your certificates below.
# No need to adjust TLS configurations, as the defaults in Caddy are already secure.
tls /path/to/fullchain/publicKey.pem /path/to/certificate/privateKey.pem
# Enable HSTS.
# Do not enable this line when configuring over mixnet, e.g. Tor.
header Strict-Transport-Security "max-age=63072000; includeSubDomains"
# Security headers
header X-XSS-Protection "1; mode=block"
header X-Content-Type-Options "nosniff"
header Access-Control-Allow-Credentials "true"
#header X-Frame-Options "SAMEORIGIN"
# OnlyOffice fonts may be loaded from both domains.
@onlyOfficeFonts {
path_regexp "^\\/common\\/onlyoffice\\/.*\\/fonts\\/.*$"
}
header Access-Control-Allow-Origin "*"
# By default CryptPad forbids remote domains from embedding CryptPad documents in iframes.
# The sandbox domain must always be permitted in order for the platform to function.
# If you wish to enable remote embedding you may change the value below to "*"
# as per the commented value.
header ?Access-Control-Allow-Origin "https://your-sandbox-domain.com"
#header ?Access-Control-Allow-Origin "*"
# Opt out of Google's FLoC Network
header Permissions-Policy "interest-cohort=()"
# Enable SharedArrayBuffer in Firefox (for .xlsx export)
header ?Cross-Origin-Resource-Policy "cross-origin"
header ?Cross-Origin-Embedder-Policy "require-corp"
# Specify the relative path to root of your custom error page.
# This error page won't only be served for 404 errors.
handle_errors {
rewrite * /error.htm
header Cache-Control "no-cache, no-store"
file_server
templates
}
# Insert the path to your CryptPad repository root here
root /home/cryptpad/cryptpad
# Any static assets loaded with "vers=" in their URL will be cached for a year
@staticAssets {
query "ver=*"
}
header @staticAssets Cache-Control "max-age=31536000"
vars {
# CSS can be dynamically set inline, loaded from the same domain, or from your main domain.
styleSrc "'unsafe-inline' 'self' https://your-main-domain.com"
# connect-src restricts URLs which can be loaded using script interfaces.
# If you have configured your instance to use a dedicated file delivery domain or API domain,
# you will need to add them below.
connectSrc "'self' https://your-main-domain.com blob: wss://api.your-main-domain.com https://your-sandbox-domain.com"
# Fonts can be loaded from data-URLs or the main domain.
fontSrc "'self' data: https://your-main-domain.com"
# Images can be loaded from anywhere, though we'd like to deprecate this as it allows
# the use of images for tracking.
imgSrc "'self' data: blob: https://your-main-domain.com"
# frame-src specifies valid sources for nested browsing contexts.
# This prevents loading any iframes from anywhere other than the sandbox domain.
frameSrc "'self' https://your-sandbox-domain.com blob:"
# media-src specifies valid sources for loading media using video or audio.
mediaSrc "blob:"
# child-src defines valid sources for webworkers and nested browser contexts.
# It is deprecated in favour of worker-src and frame-src.
childSrc "https://your-main-domain.com"
# worker-src valid sources for Worker, Shared Worker, or Service Worker scripts.
# Supercedes child-src, but is unfortunately not yet universally supported.
workerSrc "'self'"
# script-src specifies valid sources for JavaScript, including inline handlers.
scriptSrc "'self' resource: https://your-main-domain.com"
# frame-ancestors specifies which origins can embed your CryptPad instance.
# This must include 'self' and your main domain (over HTTPS) in order for CryptPad to work,
# if you have enabled remote embedding via the admin panel, then this must be more permissive.
# Note: cryptpad.fr permits web pages served via https: and vector: (element desktop app)
frameAncestors "'self' https://your-main-domain.com"
#frameAncestors "'self' https: vector:"
# A few assets are loaded via the sandbox domain.
# They unfortunately still require exceptions to the sandboxing to work correctly.
# Everything except the sandbox domain is a privileged scope, as they might be used to handle keys.
# Unsafe iframes are exceptions. Office file formats are converted outside of the sandboxed scope,
# because of bugs in Chromium-based browsers that incorrectly ignore headers supposed to enable
# the use of some modern APIs, that are required when JavaScript is run in a cross-origin context.
# We've applied other sandboxing techniques to mitigate the risk of running WebAssembly
# in this privileged scope.
# Privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied.
scriptSrcUnsafe "'self' 'unsafe-eval' 'unsafe-inline' resource: https://your-main-domain.com"
}
# Finally, set all the security rules you have composed above.
@privilegedScope1 {
host "your-sandbox-domain.com"
path_regexp "^\\/(sheet|doc|presentation)\\/inner.html.*$"
}
@privilegedScope2 {
host "your-sandbox-domain.com"
path_regexp "^\\/common\\/onlyoffice\\/.*\\/.*\\.html.*$"
}
@privilegedScope3 {
host "your-sandbox-domain.com"
path_regexp "^\\/unsafeiframe\\/inner\\.html.*$"
}
header @privilegedScope1 Content-Security-Policy "default-src 'none'; child-src {vars.childSrc}; worker-src {vars.workerSrc}; media-src {vars.mediaSrc}; style-src {vars.styleSrc}; script-src {vars.scriptSrcUnsafe}; connect-src {vars.connectSrc}; font-src {vars.fontSrc}; img-src {vars.imgSrc}; frame-src {vars.frameSrc}; frame-ancestors {vars.frameAncestors}"
header @privilegedScope2 Content-Security-Policy "default-src 'none'; child-src {vars.childSrc}; worker-src {vars.workerSrc}; media-src {vars.mediaSrc}; style-src {vars.styleSrc}; script-src {vars.scriptSrcUnsafe}; connect-src {vars.connectSrc}; font-src {vars.fontSrc}; img-src {vars.imgSrc}; frame-src {vars.frameSrc}; frame-ancestors {vars.frameAncestors}"
header @privilegedScope3 Content-Security-Policy "default-src 'none'; child-src {vars.childSrc}; worker-src {vars.workerSrc}; media-src {vars.mediaSrc}; style-src {vars.styleSrc}; script-src {vars.scriptSrcUnsafe}; connect-src {vars.connectSrc}; font-src {vars.fontSrc}; img-src {vars.imgSrc}; frame-src {vars.frameSrc}; frame-ancestors {vars.frameAncestors}"
header ?Content-Security-Policy "default-src 'none'; child-src {vars.childSrc}; worker-src {vars.workerSrc}; media-src {vars.mediaSrc}; style-src {vars.styleSrc}; script-src {vars.scriptSrc}; connect-src {vars.connectSrc}; font-src {vars.fontSrc}; img-src {vars.imgSrc}; frame-src {vars.frameSrc}; frame-ancestors {vars.frameAncestors}"
# Add support for .mjs files used by pdfjs
@fileModuleJS {
path "*.mjs"
}
header @fileModuleJS Content-Type "application/javascript"
# The Node.js process can handle all traffic, whether accessed over websocket or as static assets.
# We prefer to serve static content from Caddy directly, and to leave the API server to handle the
# the dynamic content that only it can manage. This is primarily for optimization.
handle /cryptpad_websocket/* {
reverse_proxy * {
to 127.0.0.1:3003
header_up Host "{host}"
header_up X-Real-IP "{remote_host}"
# Caddy supports WebSockets directly. No additional headers are needed.
import trustedProxies
}
}
handle_path /customize.dist/* {
# This is needed in order to prevent infinite recursion between /customize/ and the root.
}
# Try to load customizeable content via /customize/ and fall back to the default content located
# at /customize.dist/ .
# This is what allows you to override behaviour.
handle_path /customize/* {
try_files /customize/{path} /customize.dist/{path}
file_server {
index index.html index.htm default.html default.htm
}
}
# /api/config is loaded once per page load, and is used to retrieve the caching variable,
# which is applied to every other resource loaded during that session.
@sharedReverseProxy {
path /api/*
path /extensions.js
}
handle @sharedReverseProxy {
reverse_proxy * {
to 127.0.0.1:3000
header_up Host "{host}"
header_up X-Real-IP "{remote_host}"
# These settings prevent both Caddy and the API server from setting duplicate headers.
header_down Cross-Origin-Resource-Policy cross-origin
header_down Cross-Origin-Embedder-Policy require-corp
import trustedProxies
}
}
# Requests for blobs and blocks are now proxied to the API server.
# This simplifies Caddy path configuration, in the event they are being hosted in a non-standard location
# or with odd unexpected permissions. Serving blobs in this manner also means that it will be possible to
# enforce access control for them, though this is not yet implemented.
# Access control (via TOTP 2FA) has been added to blocks, so they can be handled with the same directives.
@blobsAndBlocks {
path /blob/*
path /block/*
}
handle @blobsAndBlocks {
@corsPreflight {
method OPTIONS
}
handle @corsPreflight {
header Access-Control-Allow-Origin "https://your-sandbox-domain.com"
header Access-Control-Allow-Credentials "true"
header Access-Control-Allow-Methods "GET, POST, OPTIONS"
header Access-Control-Allow-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range"
header Access-Control-Max-Age "1728000"
header Content-Type "application/octet-stream; charset=utf-8"
header Content-Length "0"
respond 204
}
reverse_proxy * {
to 127.0.0.1:3000
# Preventing these headers from getting duplicated, since we are proxying to the API server.
header_down -X-Content-Type-Options
header_down -Access-Control-Allow-Origin
header_down -Permissions-Policy
header_down -X-XSS-Protection
header_down -Cross-Origin-Resource-Policy
header_down -Cross-Origin-Embedder-Policy
}
}
# The Node.JS server has some built-in forwarding rulesets to prevent URLs not suffixed with a slash
# from resulting in a 404 error. This simply adds a trailing slash to a variety of applications.
@preventNotFound {
path_regexp "^/(register|login|recovery|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|checkup|diagram)$"
}
redir @preventNotFound "{path}/"
# Enable file serving
file_server {
index index.html index.htm default.html default.htm
}
}

View File

@ -0,0 +1,64 @@
# SPDX-FileCopyrightText: 2024 XWiki CryptPad Team <contact@cryptpad.org> and contributors
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# This file is included strictly as an example of how Caddy can be configured
# to work with CryptPad. This example WILL NOT WORK AS IS. For best results,
# compare the sections of this configuration file against a working CryptPad
# installation (http server by the Nodejs process). If you are using CryptPad
# in production and require professional support please contact sales@cryptpad.org
(trustedProxies) {
# Force Caddy to accept `X-Forwarded-For` and other origin headers.
# Modify the line below if you want to restrict the scope of direct downstream sending these headers.
trusted_proxies 0.0.0.0/0 ::/0
}
# Caddy does not have variables for server names, so domains need to be hardcoded.
# You can bulk replace "your-main-domain.com" and "your-sandbox-domain.com" safely.
your-main-domain.com:443,
your-sandbox-domain.com:443 {
# Define your certificates below.
# No need to adjust TLS configurations, as the defaults in Caddy are already secure.
tls /path/to/fullchain/publicKey.pem /path/to/certificate/privateKey.pem
# Enable HSTS.
# Do not enable this line when configuring over mixnet, e.g. Tor.
header Strict-Transport-Security "max-age=63072000; includeSubDomains"
# Specify the relative path to root of your custom error page.
# This error page won't only be served for 404 errors.
handle_errors {
rewrite * /error.htm
header Cache-Control "no-cache, no-store"
file_server
templates
}
# The Node.js process can handle all traffic, whether accessed over websocket or as static assets.
reverse_proxy /cryptpad_websocket/* {
to 127.0.0.1:3003
header_up Host "{host}"
header_up X-Real-IP "{remote_host}"
# Caddy supports WebSockets directly. No additional headers are needed.
import trustedProxies
}
reverse_proxy * {
to 127.0.0.1:3000
header_up Host "{host}"
header_up X-Real-IP "{remote_host}"
# These settings prevent both Caddy and the API server from setting duplicate headers.
header_down Cross-Origin-Resource-Policy cross-origin
header_down Cross-Origin-Embedder-Policy require-corp
import trustedProxies
}
# Enable file serving
file_server {
index index.html index.htm default.html default.htm
}
}

View File

@ -4,7 +4,7 @@
# This file is included strictly as an example of how Apache httpd can be
# configured to work with CryptPad. If you are using CryptPad in production
# and require professional support please contact sales@cryptpad.fr
# and require professional support please contact sales@cryptpad.org
# This configuration requires mod_ssl, mod_socache_shmcb, mod_proxy,
# mod_proxy_http and mod_headers

View File

@ -8,6 +8,21 @@
# installation (http server by the Nodejs process). If you are using CryptPad
# in production and require professional support please contact sales@cryptpad.fr
server {
listen 80;
listen [::]:80;
server_name your-main-domain.com your-sandbox-domain.com;
access_log /dev/null;
error_log /dev/null emerg;
# Let's Encrypt webroot
include letsencrypt-webroot;
# Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;

View File

@ -8,6 +8,21 @@
# installation (http server by the Nodejs process). If you are using CryptPad
# in production and require professional support please contact sales@cryptpad.fr
server {
listen 80;
listen [::]:80;
server_name your-main-domain.com your-sandbox-domain.com;
access_log /dev/null;
error_log /dev/null emerg;
# Let's Encrypt webroot
include letsencrypt-webroot;
# Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;

View File

@ -190,6 +190,9 @@ nThen(function (w) {
removed++;
}
});
if (Env.store) {
Env.store.closeInactiveChannels(active);
}
if (removed) {
Env.Log.info("CLEANED_ACTIVE_CHANNELS_MAP", {removed});
}

View File

@ -146,6 +146,7 @@ const dropChannel = HK.dropChannel = function (Env, chanName) {
expireChannel(Env, chanName);
}, TEMPORARY_CHANNEL_LIFETIME);
}
if (Env.store) { Env.store.closeChannel(chanName, function () {}); }
};
/* checkExpired

View File

@ -286,6 +286,16 @@ var closeChannel = function (env, channelName, cb) {
}
};
var closeInactiveChannels = function (env, schedule, active) {
Object.keys(env.channels).forEach(channelName => {
if (!active.includes(channelName)) {
schedule.ordered(channelName, function (next) {
closeChannel(env, channelName, next);
});
}
});
};
var clearOffset = function (env, channelId, cb) {
var path = mkOffsetPath(env, channelId);
// we should always be able to recover from invalid offsets, so failure to delete them
@ -429,7 +439,27 @@ How to proceed
*/
let requiresChannel = true;
let all = [];
nThen(function (w) {
let first = true;
getDedicatedMetadata(env, channelId, (err, line) => {
if (first && !err) {
if (!Array.isArray(line)) {
requiresChannel = false;
}
first = false;
}
all.push({err, line});
}, w(function (err) {
if (err) {
// stream errors?
w.abort();
return void cb(err);
}
}));
}).nThen(function (w) {
if (!requiresChannel) { return; }
// returns the first line of a channel, parsed...
getChannelMetadata(env, channelId, w(function (err, data) {
if (err) {
@ -445,13 +475,10 @@ How to proceed
handler(null, data);
}));
}).nThen(function () {
getDedicatedMetadata(env, channelId, handler, function (err) {
if (err) {
// stream errors?
return void cb(err);
}
cb();
all.forEach(({err, line}) => {
handler(err, line);
});
cb();
});
};
@ -1445,6 +1472,9 @@ module.exports.create = function (conf, _cb) {
closeChannel(env, channelName, Util.both(cb, next));
});
},
closeInactiveChannels: function (active) {
closeInactiveChannels(env, schedule, active);
},
// write to a log file
log: function (channelName, content, cb) {
// you probably want the events in your log to be in the correct order.

236
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "cryptpad",
"version": "2024.6.1",
"version": "2024.9.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cryptpad",
"version": "2024.6.1",
"version": "2024.9.0",
"license": "AGPL-3.0+",
"dependencies": {
"@mcrowe/minibloom": "^0.2.0",
@ -19,7 +19,7 @@
"chainpad-crypto": "^0.2.5",
"chainpad-listmap": "^1.1.0",
"chainpad-netflux": "^1.2.0",
"chainpad-server": "^5.2.0",
"chainpad-server": "^5.2.2",
"ckeditor": "npm:ckeditor4@~4.22.1",
"codemirror": "^5.19.0",
"components-font-awesome": "^4.6.3",
@ -27,7 +27,7 @@
"croppie": "^2.5.0",
"dragula": "3.7.2",
"drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5",
"express": "~4.19.2",
"express": "~4.20.0",
"file-saver": "1.3.1",
"fs-extra": "^7.0.0",
"get-folder-size": "^2.0.1",
@ -41,7 +41,7 @@
"localforage": "^1.5.2",
"marked": "^4.3.0",
"mathjax": "3.0.5",
"netflux-websocket": "^1.2.0",
"netflux-websocket": "^1.2.1",
"notp": "^2.0.3",
"nthen": "0.1.8",
"open-sans-fontface": "^1.4.0",
@ -1203,9 +1203,9 @@
}
},
"node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
@ -1215,7 +1215,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@ -1225,6 +1225,20 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/bootstrap": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
@ -1326,22 +1340,27 @@
}
},
"node_modules/call-bind": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
"integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.1",
"set-function-length": "^1.1.1"
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001591",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz",
"integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==",
"version": "1.0.30001660",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz",
"integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==",
"dev": true,
"funding": [
{
@ -1396,9 +1415,9 @@
}
},
"node_modules/chainpad-server": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.1.tgz",
"integrity": "sha512-r6kNMCbMuwUMxsFIZJgyXtdGxwoXm+gFVIUBxKLOzhvbeMm0RSBYa6BJ5qgzYIwUhYgqyUxmm9tXzYecmPUHIA==",
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/chainpad-server/-/chainpad-server-5.2.2.tgz",
"integrity": "sha512-fUCffhnd8PlO92A6cYH5lSIiiI6bpJymP0yC3O2KI+4NPyxFK7I2iuadMrC7RzK3eAI1w72Y1nbMN8rQImppoQ==",
"dependencies": {
"nthen": "0.1.8",
"pull-stream": "^3.6.9",
@ -1684,16 +1703,19 @@
"dev": true
},
"node_modules/define-data-property": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz",
"integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dependencies": {
"get-intrinsic": "^1.2.1",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.0"
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-property": {
@ -1825,6 +1847,25 @@
"node": ">=0.10.0"
}
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escalade": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
@ -2144,36 +2185,36 @@
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"node_modules/express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"version": "4.20.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz",
"integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"send": "0.19.0",
"serve-static": "1.16.0",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@ -2184,6 +2225,14 @@
"node": ">= 0.10.0"
}
},
"node_modules/express/node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@ -2416,15 +2465,19 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
"integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -2588,20 +2641,20 @@
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
"integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dependencies": {
"get-intrinsic": "^1.2.2"
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"engines": {
"node": ">= 0.4"
},
@ -3326,9 +3379,12 @@
}
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge2": {
"version": "1.4.1",
@ -3520,9 +3576,9 @@
}
},
"node_modules/netflux-websocket": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-1.2.0.tgz",
"integrity": "sha512-CNQF1wd/UOCmnfaWDATi5vTMfIpMm0Zghy1Fkvr5p7Q70wJdT85RdtnQvsqfLU5AXMUKwjeP1GgxMyAAdRUeJA=="
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-1.2.1.tgz",
"integrity": "sha512-8oQOyEyh0MCnifNIfyvkNXpEELlVRzDleRivRgsDGh+5ZDG109axweVZ0RIOIpkQmTZk4/xVsBk/oLXpMSWEOw=="
},
"node_modules/node-releases": {
"version": "2.0.14",
@ -3791,9 +3847,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
},
"node_modules/picocolors": {
"version": "1.0.1",
@ -4401,9 +4457,9 @@
}
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
@ -4429,9 +4485,9 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serve-static": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz",
"integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==",
"dependencies": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
@ -4442,15 +4498,45 @@
"node": ">= 0.8.0"
}
},
"node_modules/set-function-length": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
"integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
"node_modules/serve-static/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serve-static/node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dependencies": {
"define-data-property": "^1.1.1",
"get-intrinsic": "^1.2.1",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.0"
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@ -4512,13 +4598,17 @@
}
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4",
"object-inspect": "^1.13.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"

View File

@ -1,7 +1,7 @@
{
"name": "cryptpad",
"description": "a collaborative office suite that is end-to-end encrypted and open-source",
"version": "2024.6.1",
"version": "2024.9.0",
"license": "AGPL-3.0+",
"repository": {
"type": "git",
@ -22,7 +22,7 @@
"chainpad-crypto": "^0.2.5",
"chainpad-listmap": "^1.1.0",
"chainpad-netflux": "^1.2.0",
"chainpad-server": "^5.2.0",
"chainpad-server": "^5.2.2",
"ckeditor": "npm:ckeditor4@~4.22.1",
"codemirror": "^5.19.0",
"components-font-awesome": "^4.6.3",
@ -30,7 +30,7 @@
"croppie": "^2.5.0",
"dragula": "3.7.2",
"drawio": "github:cryptpad/drawio-npm#npm-21.8.2+5",
"express": "~4.19.2",
"express": "~4.20.0",
"file-saver": "1.3.1",
"fs-extra": "^7.0.0",
"get-folder-size": "^2.0.1",
@ -44,7 +44,7 @@
"localforage": "^1.5.2",
"marked": "^4.3.0",
"mathjax": "3.0.5",
"netflux-websocket": "^1.2.0",
"netflux-websocket": "^1.2.1",
"notp": "^2.0.3",
"nthen": "0.1.8",
"open-sans-fontface": "^1.4.0",

View File

@ -28,7 +28,7 @@ The most recent version and all past release notes can be found on the [releases
## Setup using Docker
You can find `Dockerfile`, `docker-compose.yml` and `docker-entrypoint.sh` files at the root of this repository. We also publish every release on [Docker Hub](https://hub.docker.com/r/cryptpad/cryptpad) as AMD64 & ARM64 official images.
You can find `Dockerfile`, `docker-compose.yml` and `docker-entrypoint.sh` files at the root of this repository. We also publish every release on [Docker Hub](https://hub.docker.com/r/cryptpad/cryptpad) as AMD64 & ARM64 official images.
Previously, Docker images were community maintained, had their own repository and weren't official supported. We changed that with v5.4.0 during July 2023. Thanks to @promasu for all the work on the community images.

View File

@ -5,6 +5,6 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
for f in ../customize.dist/favicon/*.png; do
base="$(basename $f ".png")"
magick convert $f -define icon:auto-resize=16,24,32,48,64,72,96,128,256 "$base.ico"
base="$(basename $f ".png")"
magick convert $f -define icon:auto-resize=16,24,32,48,64,72,96,128,256 "$base.ico"
done

View File

@ -0,0 +1,7 @@
{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462}
[0,"test","MSG","test",1721035117969]
[0,"test","MSG","test2",1721035117969]
[0,"test","MSG","test3",1721035117969]
[0,"test","MSG","test4",1721035117969]
[0,"test","MSG","test5",1721035117969]
[0,"test","MSG","test6",1721035117969]

View File

@ -0,0 +1,5 @@
["RESTRICT_ACCESS",[true],1721035145090]
["ADD_ALLOWED",["NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl"],1721035148115]
["ADD_PENDING_OWNERS",["PendingOwner"],1721035151295]
["RESTRICT_ACCESS",[false],1721035155836]
["RESTRICT_ACCESS",[true],1721035156728]

View File

@ -0,0 +1,7 @@
{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462}
[0,"test","MSG","test",1721035117969]
[0,"test","MSG","test2",1721035117969]
[0,"test","MSG","test3",1721035117969]
[0,"test","MSG","test4",1721035117969]
[0,"test","MSG","test5",1721035117969]
[0,"test","MSG","test6",1721035117969]

View File

@ -0,0 +1 @@
{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462}

View File

@ -0,0 +1,6 @@
[0,"test","MSG","test",1721035117969]
[0,"test","MSG","test2",1721035117969]
[0,"test","MSG","test3",1721035117969]
[0,"test","MSG","test4",1721035117969]
[0,"test","MSG","test5",1721035117969]
[0,"test","MSG","test6",1721035117969]

View File

@ -0,0 +1,6 @@
{"owners":["TestOwner"],"validateKey":"TestKey","channel":"0","created":1721035117462}
["RESTRICT_ACCESS",[true],1721035145090]
["ADD_ALLOWED",["NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl"],1721035148115]
["ADD_PENDING_OWNERS",["PendingOwner"],1721035151295]
["RESTRICT_ACCESS",[false],1721035155836]
["RESTRICT_ACCESS",[true],1721035156728]

View File

@ -0,0 +1,6 @@
[0,"test","MSG","test",1721035117969]
[0,"test","MSG","test2",1721035117969]
[0,"test","MSG","test3",1721035117969]
[0,"test","MSG","test4",1721035117969]
[0,"test","MSG","test5",1721035117969]
[0,"test","MSG","test6",1721035117969]

View File

@ -0,0 +1,6 @@
[0,"test","MSG","test",1721035117969]
[0,"test","MSG","test2",1721035117969]
[0,"test","MSG","test3",1721035117969]
[0,"test","MSG","test4",1721035117969]
[0,"test","MSG","test5",1721035117969]
[0,"test","MSG","test6",1721035117969]

View File

@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
const Store = require("../../lib/storage/file");
const Meta = require("../../lib/metadata");
const nThen = require('nthen');
let chanOld = '00000000000000000000000000000000';
let chanOldUpdated = '00000000000000000000000000000001';
let chanNew = '00000000000000000000000000000002';
let chanNewUpdated = '00000000000000000000000000000003';
let chanNoMeta = '00000000000000000000000000000004';
Store.create({
filePath: './test-data/'
}, (err, store) => {
if (err) { return void console.error(err); }
const readMetadata = (channel, cb) => {
const ref = {};
const h = Meta.createLineHandler(ref, console.error);
store.readChannelMetadata(channel, h, () => {
cb(ref && ref.meta);
});
};
nThen(w => {
readMetadata(chanOld, w(meta => {
if (!meta || meta.validateKey !== "TestKey") {
console.log('OldChanNoUpdate', meta);
throw new Error("Error with old channel without metadata update");
}
}));
readMetadata(chanOldUpdated, w(meta => {
if (!meta || meta.validateKey !== "TestKey" || !meta.restricted || !meta.allowed.includes('NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl')) {
console.log('OldChanUpdate', meta);
throw new Error("Error with old channel with metadata updates");
}
}));
readMetadata(chanNew, w(meta => {
if (!meta || meta.validateKey !== "TestKey") {
console.log('NewChanNoUpdate', meta);
throw new Error("Error with new channel without metadata update");
}
}));
readMetadata(chanNewUpdated, w(meta => {
if (!meta || meta.validateKey !== "TestKey" || !meta.restricted || !meta.allowed.includes('NewAllowedKeyNewAllowedKeyNewAllowedKeyNewAl')) {
console.log('NewChanUpdate', meta);
throw new Error("Error with new channel with metadata updates");
}
}));
readMetadata(chanNoMeta, w(meta => {
if (meta && Object.keys(meta).length) {
console.log('NoMetadataChan', meta);
throw new Error("Error with channel without metadata");
}
}));
}).nThen(() => {
console.log('Success');
process.exit(1);
});
});

View File

@ -22,6 +22,11 @@
flex-flow: column;
font: @colortheme_app-font;
input, textarea, .cp-appblock {
&:focus-visible {
outline: @variables_focus_style;
}
}
.cp-admin-customize-logo {
padding: 1em;
img {

View File

@ -39,7 +39,7 @@
.tui-full-calendar-confirm {
span, i {
padding: 0.5rem;
padding: 0 0.5rem;
}
span {
padding-left: 0;
@ -133,6 +133,13 @@
width: 540px;
max-width: 100%;
max-height: 100%;
border-radius: @variables_radius_L;
@media screen and (max-width : @browser_media-medium-screen){
position: fixed;
top: 5.5rem;
overflow-y: auto;
max-height: calc(100% - 6rem);
}
}
}
#tui-full-calendar-popup-arrow {
@ -153,9 +160,6 @@
border-color: @cp_calendar-border !important;
}
.tui-full-calendar-popup {
border-radius: @variables_radius_L;
}
.tui-full-calendar-popup-container {
.tui-full-calendar-section-allday{
&:focus {
@ -420,10 +424,7 @@
// margin-bottom: 20px;
input {
width: 80px;
margin-right: 0.3rem;
}
.fa-plus{
margin-left:0.3rem;
margin-right: 0.5rem;
}
}
}
@ -646,6 +647,9 @@
color: @cp_sidebar-left-active-fg;
border: 0px;
}
&:focus-visible {
outline: @variables_focus_style;
}
i {
margin-left: 5px;
}

View File

@ -780,7 +780,6 @@ define([
UI.confirm = function (msg, cb, opt, force) {
cb = cb || function () {};
opt = opt || {};
var message;
if (typeof(msg) === 'string') {
if (!force) { msg = Util.fixHTML(msg); }

View File

@ -623,13 +623,22 @@ define([
var appType = (common.getMetadataMgr().getMetadata().type || 'pad').toUpperCase();
data = data || {};
if (!callback && data.callback) { callback = data.callback; }
let makeButton = function(iconClasses, buttonClasses, title, text) {
const ariaLabel = title || text || '';
return $(h('button', {
class: buttonClasses,
title: title,
'aria-label': ariaLabel
}, [
iconClasses ? h('i', { class: iconClasses }) : null,
text ? h('span', { class: 'cp-toolbar-drawer-element' }, text) : null
]));
};
switch (type) {
case 'export':
button = $('<button>', {
'class': 'fa fa-download cp-toolbar-icon-export',
title: Messages.exportButtonTitle,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.exportButton));
button = makeButton('fa fa-download', 'cp-toolbar-icon-export', Messages.exportButtonTitle, Messages.exportButton);
button
.click(common.prepareFeedback(type))
.click(UI.clearTooltipsDelay);
@ -638,34 +647,28 @@ define([
}
break;
case 'import':
button = $('<button>', {
'class': 'fa fa-upload cp-toolbar-icon-import',
title: Messages.importButtonTitle,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton));
var importer = importContent((data && data.binary) ? 'application/octet-stream' : 'text/plain', callback, {
accept: data ? data.accept : undefined,
binary: data ? data.binary : undefined
});
button = makeButton('fa fa-upload', 'cp-toolbar-icon-import', Messages.importButtonTitle, Messages.importButton);
var importer = importContent((data && data.binary) ? 'application/octet-stream' : 'text/plain', callback, {
accept: data ? data.accept : undefined,
binary: data ? data.binary : undefined
});
var handler = data.first? function () {
data.first(function () {
importer(); // Make sure we don't pass arguments to importer
});
}: importer; //importContent;
button
.click(common.prepareFeedback(type))
.click(function () {
handler();
UI.clearTooltipsDelay();
var handler = data.first? function () {
data.first(function () {
importer(); // Make sure we don't pass arguments to importer
});
}: importer; //importContent;
button
.click(common.prepareFeedback(type))
.click(function () {
handler();
UI.clearTooltipsDelay();
});
//}
break;
case 'upload':
button = $('<button>', {
'class': 'btn btn-primary new',
title: Messages.uploadButtonTitle,
}).append($('<span>', {'class':'fa fa-upload'})).append(' '+Messages.uploadButton);
button = makeButton('fa fa-upload', 'btn btn-primary new', Messages.uploadButtonTitle, Messages.uploadButton);
if (!data.FM) { return; }
var $input = $('<input>', {
'type': 'file',
@ -697,9 +700,7 @@ define([
});
break;
case 'copy':
button = $('<button>', {
'class': 'fa fa-files-o cp-toolbar-icon-import',
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.makeACopy));
button = makeButton('fa fa-files-o', 'cp-toolbar-icon-import', '', Messages.makeACopy);
button
.click(common.prepareFeedback(type))
.click(function () {
@ -710,9 +711,7 @@ define([
case 'importtemplate':
if (!AppConfig.enableTemplates) { return; }
if (!common.isLoggedIn()) { return; }
button = $('<button>', {
'class': 'fa fa-upload cp-toolbar-icon-import',
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.template_import));
button = makeButton('fa fa-upload', 'cp-toolbar-icon-import', '', Messages.template_import);
button
.click(common.prepareFeedback(type))
.click(function () {
@ -724,9 +723,7 @@ define([
case 'template':
if (!AppConfig.enableTemplates) { return; }
if (!common.isLoggedIn()) { return; }
button = $('<button>', {
'class': 'cptools cptools-new-template cp-toolbar-icon-template',
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.saveTemplateButton));
button = makeButton('cptools cptools-new-template', 'cp-toolbar-icon-template', '', Messages.saveTemplateButton);
if (data.rt || data.callback) {
button
.click(function () {
@ -774,9 +771,7 @@ define([
}
break;
case 'forget':
button = $('<button>', {
'class': "fa fa-trash cp-toolbar-icon-forget"
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.fc_delete));
button = makeButton('fa fa-trash', 'cp-toolbar-icon-forget', '', Messages.fc_delete);
callback = typeof callback === "function" ? callback : function () {};
button
.click(common.prepareFeedback(type))
@ -837,25 +832,16 @@ define([
])).click(common.prepareFeedback(type));
break;
case 'print':
button = $('<button>', {
title: Messages.printButtonTitle2,
'class': "fa fa-print cp-toolbar-icon-print",
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.printText));
button = makeButton('fa fa-print', 'cp-toolbar-icon-print', Messages.printButtonTitle2, Messages.printText);
break;
case 'history':
if (!AppConfig.enableHistory) {
button = $('<span>');
break;
}
button = $('<button>', {
title: Messages.historyButton,
'aria-label': Messages.historyButton,
'class': "fa fa-history cp-toolbar-icon-history",
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.historyText));
button = makeButton('fa fa-history', 'cp-toolbar-icon-history', Messages.historyButton, Messages.historyText, Messages.historyButton);
if (data.histConfig) {
button
.click(common.prepareFeedback(type))
.on('click', function () {
button.click(common.prepareFeedback(type)).on('click', function () {
common.getHistory(data.histConfig);
UI.clearTooltipsDelay();
});
@ -879,9 +865,10 @@ define([
if (callback) { button.click(callback); }
break;
case 'storeindrive':
button = $(h('button.cp-toolbar-storeindrive.fa.fa-hdd-o', {
button = $(h('button.cp-toolbar-storeindrive', {
style: 'display:none;'
}, [
h('i.fa.fa-hdd-o'),
h('span.cp-toolbar-name.cp-toolbar-drawer-element', Messages.toolbar_storeInDrive)
])).click(common.prepareFeedback(type)).click(function () {
$(button).hide();
@ -902,10 +889,7 @@ define([
});
break;
case 'hashtag':
button = $('<button>', {
'class': 'fa fa-hashtag cp-toolbar-icon-hashtag',
title: Messages.tags_title,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.fc_hashtag));
button = makeButton('fa fa-hashtag', 'cp-toolbar-icon-hashtag', Messages.tags_title, Messages.fc_hashtag);
button.click(common.prepareFeedback(type))
.click(function () {
common.isPadStored(function (err, data) {
@ -950,11 +934,8 @@ define([
//updateIcon(data.element.is(':visible'));
break;
case 'properties':
button = $('<button>', {
'class': 'fa fa-info-circle cp-toolbar-icon-properties',
title: Messages.propertiesButtonTitle,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'})
.text(Messages.propertiesButton))
button = makeButton('fa fa-info-circle', 'cp-toolbar-icon-properties', Messages.propertiesButtonTitle, Messages.propertiesButton);
button
.click(common.prepareFeedback(type))
.click(function () {
var isTop;
@ -970,11 +951,8 @@ define([
});
break;
case 'save': // OnlyOffice save
button = $('<button>', {
'class': 'fa fa-save',
title: Messages.settings_save,
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'})
.text(Messages.settings_save))
button = makeButton('fa fa-save', '', Messages.settings_save, Messages.settings_save);
button
.click(function() {
common.prepareFeedback(type);
UI.clearTooltipsDelay();
@ -982,10 +960,7 @@ define([
if (callback) { button.click(callback); }
break;
case 'newpad':
button = $('<button>', {
title: Messages.newButtonTitle,
'class': 'fa fa-plus cp-toolbar-icon-newpad',
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.newButton));
button = makeButton('fa fa-plus', 'cp-toolbar-icon-newpad', Messages.newButtonTitle, Messages.newButton);
button
.click(common.prepareFeedback(type))
.click(function () {
@ -994,10 +969,7 @@ define([
});
break;
case 'snapshots':
button = $('<button>', {
title: Messages.snapshots_button,
'class': 'fa fa-camera cp-toolbar-icon-snapshots',
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.snapshots_button));
button = makeButton('fa fa-camera', 'cp-toolbar-icon-snapshots', Messages.snapshots_button,Messages.snapshots_button);
button
.click(common.prepareFeedback(type))
.click(function () {
@ -1280,6 +1252,7 @@ define([
kanban: 'kanban',
form: 'form',
whiteboard: 'whiteboard',
diagram: 'diagram',
};
var href = "https://docs.cryptpad.org/en/user_guide/applications.html";
@ -1607,10 +1580,10 @@ define([
]));
if (config.caretDown) {
$button.append(h('i.fa.fa-caret-down'));
$button.prepend(h('i.fa.fa-caret-down'));
}
if (config.angleDown) {
$button.append(h('i.fa.fa-angle-down'));
$button.prepend(h('i.fa.fa-angle-down'));
}
// Menu
@ -2510,10 +2483,21 @@ define([
});
var selected = -1;
var previous = function () {
selected = (selected === 0 ? types.length : selected) - 1;
$container.find('.cp-icons-element-selected').removeClass('cp-icons-element-selected');
let element = $container.find('#cp-newpad-icons-'+selected).addClass('cp-icons-element-selected');
if (element.hasClass('cp-app-disabled')) {
previous();
}
};
var next = function () {
selected = ++selected % types.length;
$container.find('.cp-icons-element-selected').removeClass('cp-icons-element-selected');
$container.find('#cp-newpad-icons-'+selected).addClass('cp-icons-element-selected');
let element = $container.find('#cp-newpad-icons-'+selected).addClass('cp-icons-element-selected');
if (element.hasClass('cp-app-disabled')) {
next();
}
};
$modal.off('keydown');
@ -2521,7 +2505,11 @@ define([
if (e.which === 9) {
e.preventDefault();
e.stopPropagation();
next();
if (e.shiftKey) {
previous();
} else {
next();
}
return;
}
if (e.which === 13) {

View File

@ -3568,7 +3568,8 @@ define([
if (APP.$content.data('readOnlyFolder') || !APP.editable) { return; }
var isInRoot = currentPath[0] === ROOT;
var $element = $('<li>', {
'class': 'cp-app-drive-element-row cp-app-drive-new-ghost'
'class': 'cp-app-drive-element-row cp-app-drive-new-ghost',
'tabindex': 0
}).prepend($addIcon.clone()).appendTo($list);
$element.append($('<span>', {'class': 'cp-app-drive-element-name'})
.text(Messages.fm_newButton));
@ -3587,6 +3588,12 @@ define([
window.setTimeout(function () { modal.show(); });
addNewPadHandlers($modal, isInRoot);
});
$element.keydown(function(){
if (event.which === 13) {
event.stopPropagation();
$element.click();
}
});
};
// Drive content toolbar

View File

@ -123,8 +123,19 @@ define([
if (!seed) { return; }
return ANIMALS[seed % ANIMALS.length] || '';
};
//this regex identifies both discord and unicode emojis (with optional skin tone modifiers) and complex zwj emoji sequences
const emojiWithZWJRegex = /(?:\p{Extended_Pictographic}(?:\p{Emoji_Modifier}|\uFE0F)?(?:\u200D\p{Extended_Pictographic}(?:\p{Emoji_Modifier}|\uFE0F)?)*|\p{Extended_Pictographic})/gu;
var getPrettyInitials = MT.getPrettyInitials = function (name) {
let matches = name.match(emojiWithZWJRegex);
if (matches && name.startsWith(matches[0])) {
return matches[0];
}
else {
//this is for removing all trailing white characters and unnecessary/redundant emojis
name = name.replace(emojiWithZWJRegex, '');
name = name.replace(/\uFE0F/g, '').replace(/\u200D/g, '').replace(/\u2060/g, '');
name = name.trim();
}
var parts = name.split(/\s+/);
var text;
if (parts.length > 1) {

View File

@ -48,7 +48,8 @@ define([
data.password = priv.password;
// Access modal and the pad is not stored: get the hashes from outer
var hashes = priv.hashes || {};
data.href = Hash.hashToHref(hashes.editHash || hashes.fileHash, priv.app);
// For calendars, individual href is passed via opts
data.href = ((priv.app === 'calendar') && opts.href) || Hash.hashToHref(hashes.editHash || hashes.fileHash, priv.app);
if (hashes.viewHash) {
data.roHref = Hash.hashToHref(hashes.viewHash, priv.app);
}

View File

@ -388,6 +388,10 @@ define([
};
var onUploaded = function (ev, data, err) {
if (!ev && err) {
console.error(err);
return void UI.warn(Messages.error);
}
if (ev.newTemplate) {
if (err) {
console.error(err);
@ -545,7 +549,7 @@ define([
var saveToServer = function (blob, title) {
if (APP.cantCheckpoint) { return; } // TOO_LARGE
var text = getContent();
var text = !blob && getContent();
if (!text && !blob) {
setEditable(false, true);
sframeChan.query('Q_CLEAR_CACHE_CHANNELS', [
@ -1681,6 +1685,10 @@ define([
var lang = (window.cryptpadLanguage || navigator.language || navigator.userLanguage || '').slice(0,2);
let username = Util.find(privateData, ['integrationConfig', 'user', 'name'])
|| metadataMgr.getUserData().name
|| Messages.anonymous;
// Config
APP.ooconfig = {
"document": {
@ -1704,8 +1712,8 @@ define([
},
"user": {
"id": String(myOOId), //"c0c3bf82-20d7-4663-bf6d-7fa39c598b1d",
"firstname": metadataMgr.getUserData().name || Messages.anonymous,
"name": metadataMgr.getUserData().name || Messages.anonymous,
"firstname": username,
"name": username
},
"mode": "edit",
"lang": lang
@ -3176,9 +3184,9 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
return void UI.errorLoadingScreen(Messages.error);
}
var blob = new Blob([bin], {type: 'text/plain'});
var file = getFileType();
resetData(blob, file);
//saveToServer(blob, title);
//var file = getFileType();
//resetData(blob, file);
saveToServer(blob, title);
Title.updateTitle(title);
UI.removeLoadingScreen();
});
@ -3227,10 +3235,9 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
cb();
});
});
if (privateData.initialState) {
if (privateData.initialState && (!content || !content.hashes || !Object.keys(content.hashes).length)) {
var blob = privateData.initialState;
let title = `document.${cfg.fileType}`;
console.error(blob, title);
return convertImportBlob(blob, title);
}
}

View File

@ -252,7 +252,7 @@ define([
list.push(userChannel);
if (store.data && store.data.blockId) {
//list.push(`${store.data.blockId}#block`); // NEXT 5.7.0?
list.push(`${store.data.blockId}#block`);
}
list.sort();
@ -467,6 +467,19 @@ define([
});
};
var initTempRpc = (clientId, cb) => {
if (store.rpc) { return void cb(store.rpc); }
var kp = Crypto.Nacl.sign.keyPair();
var keys = {
edPublic: Crypto.Nacl.util.encodeBase64(kp.publicKey),
edPrivate: Crypto.Nacl.util.encodeBase64(kp.secretKey)
};
Pinpad.create(store.network, keys, function (e, call) {
if (e) { return void cb({error: e}); }
store.rpc = call;
cb(call);
});
};
var initRpc = function (clientId, data, cb) {
if (!store.loggedIn) { return cb(); }
if (store.rpc) { return void cb(account); }
@ -3153,7 +3166,7 @@ define([
// If we load CryptPad for the first time from an existing pad, don't create a
// drive automatically.
var onNoDrive = function (clientId, cb) {
var onNoDrive = function (clientId, cb, initRpc) {
var andThen = function () {
// To be able to use all the features inside the pad, we need to
// initialize the chat (messenger) and the cursor modules.
@ -3164,9 +3177,16 @@ define([
store.messenger = store.modules['messenger'];
// And now we're ready
initAnonRpc(null, null, function () {
cb({});
});
let getAnon = () => {
initAnonRpc(null, null, function () {
cb({});
});
};
if (initRpc) {
return initTempRpc(clientId, getAnon);
}
getAnon();
};
// We need an anonymous RPC to be able to check if the pad exists and to get
@ -3249,7 +3269,7 @@ define([
// First tab, no user hash, no anon hash and this app doesn't need a drive
// ==> don't create a drive
// Or "neverDrive" (integration into another platform?)
// ==> don't create a drive
// ==> don't create a drive BUT create temp RPC (we may need to upload)
if (data.neverDrive || (data.noDrive && !data.userHash && !data.anonHash)) {
return void onNoDrive(clientId, function (obj) {
if (obj && obj.error) {
@ -3263,7 +3283,7 @@ define([
}
Feedback.send("NO_DRIVE", true);
callback(obj);
});
}, !!data.neverDrive);
}
initialized = true;

View File

@ -62,6 +62,19 @@ define([
return channels;
};
let getTeamChannels = function (ctx, teamId) {
let team = Util.find(ctx.store, ['proxy', 'teams', teamId]);
if (!team) { return []; }
let channels = [team.channel];
let roster = team.keys.roster;
channels.push({
channel: roster.channel,
lastKnownHash: roster.lastKnownHash
});
return channels;
};
var getEdPublic = function (ctx, teamId) {
if (!teamId) { return Util.find(ctx.store, ['proxy', 'edPublic']); }
@ -155,6 +168,8 @@ define([
// If account trim history, get the correct channels here
if (data.account) {
channels = getAccountChannels(ctx);
} else if (data.team) {
channels = getTeamChannels(ctx, data.team);
}
var size = 0;

View File

@ -694,7 +694,7 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto, Feedback)
// but since multiple users who can and should might be online at once
// and since they'll all trigger this process at the same time...
// we want to stagger attempts at random intervals
setTimeout(function () {
ref.internal.checkpointTimeout = setTimeout(function () {
ref.internal.pendingCheckpointId = roster.checkpoint(function (err) {
if (err) { console.error(err); }
});
@ -730,7 +730,10 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto, Feedback)
//console.log("Sending with id [%s]", id, msg);
//console.log();
response.expect(id, cb, TIMEOUT_INTERVAL);
response.expect(id, function (err, state) {
if (err) { return void cb(err); }
cb(void 0, state, id);
}, TIMEOUT_INTERVAL);
anon_rpc.send('WRITE_PRIVATE_MESSAGE', [
channel,
ciphertext

View File

@ -17,7 +17,9 @@ define([
nThen(function (waitFor) {
DomReady.onReady(waitFor());
}).nThen(function (waitFor) {
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname);
let lang = integration && integration.config && integration.config.editorConfig
&& integration.config.editorConfig.lang;
var obj = SFCommonO.initIframe(waitFor, true, integration.pathname, lang);
href = obj.href;
hash = obj.hash;
if (isIntegration) {

View File

@ -446,5 +446,26 @@
"settings_changePasswordPending": "Вашата парола се обновява. Моля, не затваряйте и не презареждайте тази страница, докато процесът не приключи.",
"settings_cursorColorTitle": "Цвят на курсора",
"settings_changePasswordError": "Възникна неочаквана грешка. Ако не можете да влезете или да промените паролата си, свържете се с администраторите на CryptPad.",
"settings_changePasswordNewPasswordSameAsOld": "Вашата нова парола трябва да е различна от настоящата."
"settings_changePasswordNewPasswordSameAsOld": "Вашата нова парола трябва да е различна от настоящата.",
"settings_cursorShareTitle": "Споделяне на позицията на курсора ми",
"settings_cursorShareLabel": "Споделяне на позицията",
"settings_cursorShowTitle": "Показване на позицията на курсора на другите потребители",
"settings_cursorShowHint": "Можете да изберете дали искате да виждате курсора на другите потребители в документите за съвместната работа.",
"settings_cursorShowLabel": "Показване на курсорите",
"upload_title": "Качване на файла",
"upload_modal_filename": "Име на файла (разширението <em>{0}</em> се добавя автоматично)",
"upload_modal_owner": "Личен файл",
"uploadFolder_modal_filesPassword": "Парола на файловете",
"uploadFolder_modal_owner": "Лични файлове",
"uploadFolder_modal_forceSave": "Съхраняване на файлове във вашия CryptDrive",
"upload_uploadPending": "В момента качвате. Искате ли да го отмените и да качите новия си файл?",
"upload_notEnoughSpace": "Няма достатъчно място за този файл във вашия CryptDrive.",
"upload_notEnoughSpaceBrief": "Няма достатъчно място",
"settings_cursorColorHint": "Променете цвета, свързан с вашия потребител в документите за съвместната работа.",
"settings_cursorShareHint": "Можете да решите дали искате други потребители да виждат позицията на курсора ви в документите за съвместната работа.",
"uploadFolder_modal_title": "Опции за качване на папка",
"upload_modal_title": "Опции за качване на файлове",
"upload_tooLarge": "Този файл надвишава максималния разрешен размер на качване за вашия акаунт.",
"upload_serverError": "Грешка в сървъра: файлът ви не може да бъде качен в момента.",
"upload_success": "Вашият файл ({0}) бе успешно качен и е добавен към устройството ви."
}

View File

@ -1129,7 +1129,7 @@
"admin_updateLimitTitle": "Actualitzar les quotes d'usuari",
"admin_updateLimitButton": "Actualitzar les quotes",
"admin_flushCacheTitle": "Neteja la memòria cau HTTP",
"admin_flushCacheHint": "Força als usuaris a descarregar els últims actius del client (només si el servidor està en mode nou)",
"admin_flushCacheHint": "Força tots els usuaris a baixar els últims actius després d'un canvi en la configuració o la personalització. Evita reiniciar el servidor, però fa que cada usuari actiu restableixi la connexió, utilitzeu-ho amb moderació.",
"admin_flushCacheButton": "Neteja la memòria cau",
"footer_donate": "Donació",
"contact_admin": "Contacteu amb l'administració de: {0}",
@ -1340,7 +1340,7 @@
"snapshots_ooPickVersion": "Heu de seleccionar una versió abans de crear una instantània",
"snapshot_error_exists": "Ja hi ha una instantània d'aquesta versió",
"snapshots_notFound": "Aquesta instantània ja no existeix perquè s'ha suprimit l'historial del document.",
"admin_registrationHint": "No permetis que cap usuari nou es registri",
"admin_registrationHint": "Els visitants de la instància no poden crear comptes. Els administradors poden crear invitacions.",
"admin_registrationTitle": "Tanca el registre",
"admin_defaultlimitHint": "Límit màxim d'emmagatzematge per a CryptDrives (usuaris i equips) quan no s'apliqui cap regla personalitzada",
"admin_setlimitButton": "Estableix el límit",
@ -1717,5 +1717,50 @@
"admin_usersHint": "Llista dels comptes coneguts d'aquesta instància. Seleccioneu a continuació per a afegir comptes automàticament, o introduïu la informació manualment amb el formulari.",
"admin_usersBlock": "URL de blocatge d'inici de sessió de l'usuari (opcional)",
"ssoauth_form_hint_register": "Afegiu una contrasenya CryptPad per a més seguretat, o deixeu-la buida i continueu. Si no afegiu una contrasenya, els administradors de la instància tindran a l'abast les claus que protegeixen les vostres dades.",
"admin_storeInvitedLabel": "Desa automàticament els usuaris convidats"
"admin_storeInvitedLabel": "Desa automàticament els usuaris convidats",
"admin_supportAdd": "Afegiu un contacte a l'equip d'assistència",
"admin_supportConfirm": "N'esteu segur? Això eliminarà tots els tiquets existents i blocarà l'accés a tots els moderadors.",
"support_cat_settings": "Configuració",
"admin_supportDelete": "Desactiva l'assistència",
"admin_supportMembers": "Equip d'assistència",
"admin_supportRotateNotify": "Atenció: les claus noves s'han generat, però un error inesperat ha evitat que el sistema les enviés als moderadors. Elimineu i reafegiu a tots els moderadors de l'equip d'administració",
"support_cat_closed": "Tancats",
"support_cat_search": "Cerca",
"support_cat_open": "Safata d'entrada",
"support_openTicketTitle": "Obre un tiquet amb un usuari",
"admin_supportTeamTitle": "Gestiona l'equip d'assistència",
"support_cat_legacy": "Compatibilitat",
"support_pending": "Tiquets arxivats:",
"support_privacyHint": "Marqueu aquesta opció per a respondre com a «Equip d'assistència» en compte d'amb el vostre nom d'usuari",
"support_pending_tag": "Arxivat",
"support_active_tag": "Safata d'entrada",
"support_closed_tag": "Tancat",
"support_privacyTitle": "Resposta anònima",
"support_notificationsHint": "Marqueu aquesta opció per a desactivar les notificacions de tiquets i respostes nous",
"support_notificationsTitle": "Desactiva les notificacions",
"support_userChannel": "ID del canal de notificacions de l'usuari",
"support_openTicketHint": "Copia les dades de l'usuari destinatari des de la seva pàgina de perfil o des d'un tiquet existent. Rebran una notificació del CryptPad sobre aquest missatge.",
"support_userKey": "Clau pública de l'usuari",
"support_invalChan": "Canal de notificacions no vàlid",
"admin_supportTeamHint": "Afegiu i elimina gent de la instància de l'equip d'assistència",
"support_pasteUserData": "Enganxeu les dades de l'usuari aquí",
"support_legacyButton": "Recupera els tiquets actius",
"support_recordedHint": "Emmagatzema el text comú com a dreceres d'un clic per a inserir-los a missatges d'assistència.",
"support_recordedContent": "Contingut",
"support_legacyTitle": "Mostra les dades d'assistència antigues",
"support_searchLabel": "Cerca (títol o ID del tiquet)",
"support_team": "L'Equip d'assistència",
"support_legacyHint": "Mostra els tiquets del sistema d'assistència antic i els recrea en el sistema nou.",
"support_legacyDump": "Exporta-ho tot",
"support_legacyClear": "Elimina d'aquest compte",
"support_moveActive": "Mou a l'arxiu",
"support_answerAs": "Es respon com a <b>{0}</b>",
"support_movePending": "Mou a l'arxiu",
"admin_supportOpen": "Obre el servei d'assistència",
"moderationPage": "Servei d'assistència",
"support_copyUserData": "Copia les dades d'usuari",
"support_userNotification": "Tiquet d'assistència o resposta nou: {0}",
"install_instance": "Creeu el primer compte d'administrador, després personalitzeu la instància",
"install_header": "Instal·lació",
"install_launch": "Configuració de la instància"
}

View File

@ -1 +1,25 @@
{}
{
"type": {
"slide": "Markdown slides",
"media": "Media",
"pad": "Rich tekst",
"poll": "Afstemning",
"file": "Fil",
"todo": "Todo",
"contacts": "Kontakter",
"code": "Kode",
"drive": "CryptDrive",
"form": "Form",
"teams": "Hold",
"doc": "Dokument",
"presentation": "Præsentation",
"diagram": "Diagram",
"kanban": "Kanban",
"sheet": "Ark",
"whiteboard": "Whiteboard"
},
"typeError": "Dette dokument er ikke kompatibelt med det valgte program",
"main_title": "CryptPad: Zero Knowledge, Collaborative Real Time Editing",
"common_connectionLost": "<b>Serverforbindelse afbrudt</b><br>Du er nu i skrivebeskyttet tilstand, indtil forbindelsen er tilbage.",
"onLogout": "Du er logget ud, {0}klik her{1} for at logge ind<br>eller tryk på Esc for at få adgang til dit dokument i skrivebeskyttet tilstand."
}

View File

@ -1780,5 +1780,8 @@
"admin_onboardingNamePlaceholder": "Name der Instanz",
"admin_onboardingDescPlaceholder": "Beschreibungstext für die Instanz",
"admin_onboardingOptionsHint": "Bitte wähle die geeignete Option für deine Instanz.<br>Diese Einstellungen können später im Administrationsbereich geändert werden.",
"admin_onboardingNameHint": "Bitte wähle einen Namen, eine Beschreibung, eine Akzentfarbe und ein Logo (alle Angaben sind optional)"
"admin_onboardingNameHint": "Bitte wähle einen Namen, eine Beschreibung, eine Akzentfarbe und ein Logo (alle Angaben sind optional)",
"team_autoTrim": "Verlauf des Team-Drives wird gelöscht... Bitte warten.",
"admin_mfa_confirm_enable": "Bist du sicher, dass du die Multi-Faktor-Authentifizierung aktivieren möchtest?",
"admin_mfa_confirm_disable": "Bist du sicher, dass du die Multi-Faktor-Authentifizierung deaktivieren möchtest?"
}

View File

@ -589,8 +589,8 @@
"properties_passwordWarning": "La contraseña ha sido cambiada con éxito pero fue incapaz de actualizar tu CryptDrive con los nuevos datos. Es posible que tenga que eliminar la versión antigua del documento manualmente.<br>Pulse OK para recargar y actualizar sus derechos de acceso.",
"properties_passwordSuccess": "La contraseña ha sido cambiada con éxito.<br>Pulsa OK para recargar y actualizar tus derechos de acceso.",
"admin_updateLimitTitle": "Actualizar cuotas de usuarios",
"admin_registeredHint": "Número de usuarios registrados en tu instancia",
"admin_registeredTitle": "Usuarios registrados",
"admin_registeredHint": "Número de unidades activas en tu instancia",
"admin_registeredTitle": "Unidades de usuario y de equipo",
"admin_activePadsHint": "Número de documentos únicos que se están viendo o editando ahora",
"admin_activePadsTitle": "Documentos activos",
"admin_activeSessionsHint": "Número de conexiones websocket activas (y direcciones IP únicas conectadas)",

File diff suppressed because it is too large Load Diff

View File

@ -594,8 +594,8 @@
"features_f_storage1": "Biltegiratze pertsonala ({0})",
"features_f_file1_note": "Gorde fitxategiak zure CryptDrive-an: irudiak, PDFak, bideoak eta abar. Partekatu itzazu zure kontaktuekin edo txertatu dokumentuetan. (gehienez {0}MB)",
"admin_updateLimitTitle": "Eguneratu erabiltzaileen kuotak",
"admin_registeredHint": "Zure instantzian erregistratutako erabiltzaile kopurua",
"admin_registeredTitle": "Erabiltzaile erregistratuak",
"admin_registeredHint": "Zure instantziako unitate aktibo kopurua",
"admin_registeredTitle": "Erabiltzaile eta taldeko gidak",
"admin_activePadsHint": "Une honetan ikusten edo editatzen ari diren dokumentu bakarrak",
"admin_activePadsTitle": "Dokumentu aktiboak",
"admin_activeSessionsHint": "Websocket konexio aktiboen kopurua (eta konektatutako IP helbide bakarrak)",
@ -1205,7 +1205,7 @@
"admin_defaultlimitTitle": "Biltegiratze muga (MB)",
"admin_defaultlimitHint": "CryptDrive edo unitatearen (erabiltzaileren zein talderen) biltegiratzeko gehienezko muga, arau pertsonalizatua aplikatzen ez denean",
"admin_registrationTitle": "Itxi izena ematea",
"admin_registrationHint": "Ez utzi erabiltzaile berririk izena ematen",
"admin_registrationHint": "Instantziaren bisitariek ezin dute konturik sortu. Gonbidapenak administratzaileek sor ditzakete.",
"snapshots_notFound": "Babeskopia hau jada ez dago dokumentuaren historia ezabatu delako.",
"snapshot_error_exists": "Dagoeneko badago bertsio honen babeskopia bat",
"snapshots_ooPickVersion": "Bertsio bat hautatu behar duzu babeskopia bat sortu aurretik",
@ -1668,7 +1668,7 @@
"calendar_rec_change": "Errepikatzen den gertaera bat beste egutegi batera eramatea.. Aldaketa hau gertaera honetan edo errepikatzen diren gertaera guztietan soilik aplika dezakezu.",
"access_passwordUsed": "Pasahitz hau dagoeneko erabili da dokumentu honetarako. Ezin da berriro erabili.",
"calendar_rec_change_first": "Lehenengo errepikapena beste egutegi batera mugitzea. Errepikatzen diren gertaera guztiak ere mugituko dira.",
"admin_forcemfaHint": "Instantzia honetako erabiltzaile guztiei bi faktoreko autentifikazioa konfiguratzeko eskatuko zaie beren kontuan saioa hasteko.",
"admin_forcemfaHint": "Instantzia honetako erabiltzaile guztiei bi faktoreko autentifikazioa konfiguratzeko eskatuko zaie beren kontuan saioa hasteko. Kontuan izan lehendik dauden erabiltzaileek ezin izango dutela beren kontua erabiltzen jarraitu TOTP aplikazioa konfiguratu gabe.",
"ssoauth_form_hint_login": "Sartu zure CryptPad pasahitza",
"status": "Egoera orria",
"calendar_desc": "Deskribapena",
@ -1763,5 +1763,22 @@
"admin_supportOpen": "Ireki laguntza tresnak",
"support_copyUserData": "Kopiatu erabiltzailearen datuak",
"support_userNotification": "Laguntza-txartel edo erantzun berria: {0}",
"admin_supportTeamHint": "Gehitu eta kendu jendea instantziako laguntza-taldetik"
"admin_supportTeamHint": "Gehitu eta kendu jendea instantziako laguntza-taldetik",
"install_token": "Instalazioaren tokena",
"install_header": "Instalazioa",
"admin_appSelection": "Aplikazioaren konfigurazioa",
"install_instance": "Sortu lehen administratzailearen kontua, eta jarraitu instantzia hau pertsonalizatzen",
"install_launch": "Instantziaren konfigurazioa",
"install_notes": "<ul class=\"cp-notes-list\"><li>Sortu zure lehen administratzaile kontua orrialde honetan. Administratzaileek instantzia-ezarpenak kudeatzen dituzte biltegiratze-kuotak barne, eta moderazio-tresnetarako sarbidea dute.</li><li>Zure pasahitza instantzia honetako dokumentu eta administratzaile-pribilegio guztiak enkriptatzen dituen gako sekretua da. <span class=\"red\">Galtzen baduzu, ezin dugu zure datuak berreskuratu.</span></li><li>Partekatutako ordenagailu bat erabiltzen ari bazara, <span class=\"red\">gogoratu amaitutakoan saioa ixtea</span>. Nabigatzailearen leihoa ixteak bakarrik utziko du zure kontua agerian. </li></ul>",
"admin_appsTitle": "Instantziaren aplikazioak",
"admin_appsHint": "Aukeratu zein aplikazio aktibatu instantzia honetan.",
"admin_cat_apps": "Aplikazioak",
"onboarding_upload": "Hautatu logoa",
"onboarding_save_error": "Aukera batzuk ezin izan dira behar bezala gorde. Mesedez, bisitatu administrazio panelera balioak egiaztatzeko.",
"admin_onboardingNameHint": "Mesedez, aukeratu izenburua, deskribapena, nabarmentzeko kolorea eta logotipoa (guztiak aukerakoak dira)",
"admin_onboardingNameTitle": "Ongi etorri zure CryptPad instantziara",
"admin_onboardingOptionsTitle": "Instantziaren aukerak",
"admin_onboardingNamePlaceholder": "Instantziaren izenburua",
"admin_onboardingDescPlaceholder": "Instantziaren deskribapen testua",
"admin_onboardingOptionsHint": "Mesedez, hautatu aukera egokia zure instantziarako.<br>Ezarpen hauek geroago alda daitezke administrazio panelean."
}

View File

@ -1780,5 +1780,8 @@
"admin_onboardingNamePlaceholder": "Nom de l'instance",
"admin_onboardingOptionsHint": "Veuillez sélectionner les options appropriées pour votre instance.<br>Ces paramètres peuvent être changés plus tard depuis l'espace d'administration.",
"admin_onboardingDescPlaceholder": "Texte de description de l'instance",
"install_notes": "<ul class=\"cp-notes-list\"><li>Créez votre premier compte administrateur·ice sur cette page. Les administrateur·ices peuvent paramétrer l'instance, ceci incluant les quotas de stockage, et ont accès aux outils de modération.</li><li>Votre mot de passe est la clé secrète qui chiffre l'ensemble de vos documents et vos privilèges d'administration sur l'instance. <span class=\"red\">Si vous le perdez il n'est pas possible de récupérer vos données.</span></li><li>Si vous utilisez un ordinateur partagé, <span class=\"red\">n'oubliez pas de vous déconnecter</span> quand vous aurez terminé. Simplement fermer la fenêtre du navigateur web laisse votre compte exposé à des risques de sécurité. </li></ul>"
"install_notes": "<ul class=\"cp-notes-list\"><li>Créez votre premier compte administrateur·ice sur cette page. Les administrateur·ices peuvent paramétrer l'instance, ceci incluant les quotas de stockage, et ont accès aux outils de modération.</li><li>Votre mot de passe est la clé secrète qui chiffre l'ensemble de vos documents et vos privilèges d'administration sur l'instance. <span class=\"red\">Si vous le perdez il n'est pas possible de récupérer vos données.</span></li><li>Si vous utilisez un ordinateur partagé, <span class=\"red\">n'oubliez pas de vous déconnecter</span> quand vous aurez terminé. Simplement fermer la fenêtre du navigateur web laisse votre compte exposé à des risques de sécurité. </li></ul>",
"team_autoTrim": "Suppression de l'historique du drive d'équipe... Veuillez patienter.",
"admin_mfa_confirm_disable": "Êtes-vous sûr de vouloir désactiver l'authentification multi-facteur ?",
"admin_mfa_confirm_enable": "Êtes-vous sûr de vouloir activer l'authentification multi-facteur ?"
}

View File

@ -1741,5 +1741,32 @@
"admin_onboardingNameHint": "Scegli un titolo, una descrizione, un colore principale ed un logo (sono tutti facoltativi)",
"admin_onboardingNameTitle": "Benvenut* nella tua istanza di CryptPad",
"admin_onboardingNamePlaceholder": "Titolo dell'istanza",
"admin_onboardingDescPlaceholder": "Descrizione dell'istanza"
"admin_onboardingDescPlaceholder": "Descrizione dell'istanza",
"admin_planName": "Nome della pianificazione",
"admin_enableembedsTitle": "Abilita l incorporamento remoto",
"error_evalPermitted": "Sto abortendo: eval non dovrebbe essere permesso.\n\nQuesto errore è collegato al Content-Security-Policy header, può essere causato: da un browser obsoleto che non lo supporta, da un estensione che interferisce con il comportamento atteso o da una configurazione errata di questa istanza di CryptPad.",
"admin_blockMetadataTitle": "Informazioni sulla Sezione Login",
"admin_blockMetadataHint": "La sezione di login abilita un account ad identificarsi in CryptPad con la propria combinazione di nome utente + password",
"admin_blockMetadataPlaceholder": "URL assoluto o relativo della sezione",
"admin_restoreBlock": "Ripristina la sezione archiviata",
"admin_blockAvailable": "La sezione è disponibile",
"admin_blockArchived": "La sezione é archiviata",
"admin_archiveBlock": "Archivia la sezione",
"admin_note": "Note della pianificazione",
"support_cat_closed": "Chiuso",
"support_cat_open": "Casella in arrivo",
"support_pending_tag": "Archiviato",
"support_active_tag": "Casella in ingresso",
"support_closed_tag": "Chiuso",
"support_moveActive": "Sposta negli attivi",
"install_header": "Installazione",
"install_token": "Token di installazione",
"admin_appSelection": "Configurazione app",
"install_instance": "Crea il primo profilo da amministratore quindi procedi a configurare questa istanza",
"install_launch": "Configura listanza",
"admin_appsTitle": "Applicazioni dellistanza",
"admin_appsHint": "Scegli le app da abilitare su questa istanza.",
"admin_cat_apps": "ApplicazIoni",
"admin_onboardingOptionsTitle": "Opzioni dellistanza",
"admin_onboardingOptionsHint": "Scegli lopzione appropriata per la tua istanza.<br> Queste configurazioni possono essere cambiate successivamente nel pannello di amministrazione."
}

View File

@ -97,7 +97,7 @@
"settings_changePasswordNew": "新しいパスワード",
"settings_changePasswordCurrent": "現在のパスワード",
"settings_changePasswordButton": "パスワードを変更",
"settings_changePasswordHint": "アカウントのパスワードを変更します。「現在のパスワード」と、「新しいパスワード」および「新しいパスワードの確認」を入力してください。<br><b>パスワードを忘れた場合、再設定する方法はありません。細心の注意を払って、パスワードを安全に管理してください。</b>",
"settings_changePasswordHint": "アカウントのパスワードを変更できます。現在のパスワードを入力し、新しいパスワードを2回入力して承認してください。<br><b>パスワードを忘れた場合、再設定する方法はありません。細心の注意を払って、パスワードを安全に管理してください。</b>",
"settings_changePasswordTitle": "パスワードの変更",
"languageButton": "言語",
"language": "言語",
@ -300,7 +300,7 @@
"settings_ownDriveButton": "アカウントをアップグレード",
"features_f_file1_note": "CryptDriveに画像ファイル、PDF、動画などを保存できます。保存したファイルは、連絡先と共有したり、ドキュメントに埋め込んだりできます。最大容量は{0}MB",
"crowdfunding_button": "CryptPadを支援",
"contacts_removeHistoryTitle": "チャット履歴を削除",
"contacts_removeHistoryTitle": "チャット履歴を消去",
"properties_passwordSuccessFile": "パスワードは正常に変更されました。",
"drive_sfPasswordError": "誤ったパスワードです",
"team_title": "チーム: {0}",
@ -323,7 +323,7 @@
"areYouSure": "よろしいですか?",
"settings_safeLinksCheckbox": "セーフリンクを有効にする",
"settings_safeLinksTitle": "セーフリンク",
"settings_safeLinksHint": "CryptPadでは、リンクの中にドキュメントを解読するための鍵が含まれています。ブラウザーの閲覧履歴にアクセスできる人は、誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザーやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザーの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューから共有用リンクを使用することを強く推奨します。",
"settings_safeLinksHint": "CryptPadでは、リンクの中にドキュメントを復号するための鍵が含まれています。ブラウザーの閲覧履歴にアクセスできる人は、理論上は誰でもCryptPadのデータを閲覧することができます。ここにはデバイス間で履歴を同期するブラウザーやその拡張機能も含まれます。「セーフリンク」を有効にすると、鍵がブラウザーの閲覧履歴に残ったり、アドレスバーに表示されたりするのを可能な限り防ぐことができます。この機能を有効にして{0}の共有メニューから共有用リンクを使用することを強く推奨します。",
"settings_autostoreTitle": "CryptDriveへのドキュメントの保存",
"settings_logoutEverywhereConfirm": "全てのデバイスで改めてログインしなければならなくなります。よろしいですか?",
"settings_logoutEverywhere": "他の全てのウェブセッションからログアウト",
@ -421,7 +421,7 @@
"properties_unknownUser": "{0}人の不明なユーザー",
"requestEdit_viewPad": "ドキュメントを新しいタブで開く",
"requestEdit_button": "編集権限を要求",
"support_notification": "管理がサポートチケットに返答しました",
"support_notification": "管理がサポートチケットに返答しました",
"support_showData": "ユーザーデータを表示/隠す",
"upload_mustLogin": "ファイルのアップロードにはログインが必要です",
"upload_choose": "ファイルを選択",
@ -490,7 +490,7 @@
"admin_supportListTitle": "メールボックスのサポート",
"friendRequest_later": "あとで決める",
"admin_flushCacheButton": "キャッシュを消去",
"admin_registeredTitle": "登録ユーザー",
"admin_registeredTitle": "ユーザーとチームのドライブ",
"crowdfunding_popup_no": "あとで",
"sharedFolders_create_name": "フォルダー名",
"creation_newTemplate": "新しいテンプレート",
@ -713,8 +713,8 @@
"newButton": "新規",
"userAccountButton": "ユーザーメニュー",
"userListButton": "ユーザー一覧",
"movedToTrash": "ドキュメントをゴミ箱に移動しました。<br><a>ドライブにアクセス</a>",
"forgetPrompt": "OKをクリックするとドキュメントをゴミ箱に移動します。よろしいですか?",
"movedToTrash": "ドキュメントをごみ箱に移動しました。<br><a>ドライブにアクセス</a>",
"forgetPrompt": "OKをクリックするとドキュメントをごみ箱に移動します。よろしいですか?",
"forgetButton": "削除",
"pinLimitReached": "利用できるストレージの最大容量に達しました",
"disconnected": "接続が切れました",
@ -769,7 +769,7 @@
"settings_deleted": "アカウントが削除されました。OKを押すとホームページに移動します。",
"settings_deleteHint": "アカウントの削除は取り消せません。あなたのCryptDriveとドキュメントの一覧はサーバーから削除されます。誰もCryptDriveに保存していないドキュメントは、90日で削除されます。",
"settings_resetThumbnailsDone": "全てのサムネイルが消去されました。",
"settings_resetThumbnailsDescription": "ブラウザーに保存したドキュメントのサムネイルを削除します。",
"settings_resetThumbnailsDescription": "ブラウザーに保存したドキュメントのサムネイルを消去します。",
"settings_disableThumbnailsDescription": "新しいドキュメントを開くと、サムネイルが自動で作成され、ブラウザーに保存されます。ここでサムネイルの作成を無効にできます。",
"fm_info_root": "フォルダーを作成してファイルを整理できます。",
"oo_conversionSupport": "お使いのブラウザーは、オフィスソフトウェアのフォーマットの変換に対応していません。FirefoxもしくはChromeの最新バージョンの使用を推奨します。",
@ -828,7 +828,7 @@
"broadcast_preview": "通知をプレビュー",
"team_inviteLinkError": "リンクの作成中にエラーが発生しました。",
"team_inviteLinkSetPassword": "リンクをパスワードで保護(推奨)",
"team_inviteLinkNote": "プライベート・メッセージを追加",
"team_inviteLinkNote": "個人メッセージを追加",
"contacts_muteInfo": "ミュートしたユーザーからは通知を受け取りません。<br>ミュートしたことは相手に通知されません。 ",
"contacts_manageMuted": "ミュートを管理",
"notifyRenamed": "{0}は{1}になりました",
@ -1075,7 +1075,7 @@
"admin_flushCacheTitle": "HTTPキャッシュを消去",
"admin_updateLimitDone": "アップデートが完了しました",
"admin_updateLimitButton": "クォータを更新",
"admin_registeredHint": "あなたのインスタンスの登録ユーザー数",
"admin_registeredHint": "あなたのインスタンスのアクティブなドライブ数",
"admin_updateLimitTitle": "ユーザーのクォータを更新",
"mdToolbar_defaultText": "ここにテキストを入力",
"upload_modal_filename": "ファイル名(拡張子 <em>{0}</em> を自動で追加)",
@ -1087,7 +1087,7 @@
"mdToolbar_nlist": "番号付きリスト",
"mdToolbar_heading": "見出し",
"settings_cursorShowHint": "共同ドキュメントであなたが他のユーザーのカーソルの位置を見られるかどうかを決められます。",
"settings_cursorShareHint": "共同ドキュメントで他のユーザーがあなたのカーソルの位置を見られるかどうかを決められます。",
"settings_cursorShareHint": "共同ドキュメントで他のユーザーがあなたのカーソルの位置を見られるかどうかを設定できます。",
"settings_cursorColorHint": "共同ドキュメントでのユーザーのカーソルの色を変更できます。",
"settings_padWidthHint": "テキストエディターの幅を制限するページモード(既定)と、スクリーン全体の幅を使用するモードを切り替えられます。",
"fm_forbidden": "禁止されたアクション",
@ -1112,7 +1112,7 @@
"convertFolderToSF_SFChildren": "このフォルダーは共有フォルダーを含んでいるため、共有フォルダーに変更できません。続けるには、このフォルダーを共有フォルダーの外に移動してください。",
"sharedFolders_share": "このリンクを登録ユーザーと共有すると、共有フォルダーへのアクセスが可能になります。相手がリンクを開くと、CryptDriveに共有フォルダーが追加されます。",
"sharedFolders_duplicate": "移動しようとしているドキュメントのいくつかは既に移動先のフォルダーに存在しています。",
"sharedFolders_forget": "このドキュメントは共有フォルダーにのみ保存されているため、ゴミ箱に移動できません。あなたのCryptDriveから削除することは可能です。",
"sharedFolders_forget": "このドキュメントは共有フォルダーにのみ保存されているため、ごみ箱に移動できません。あなたのCryptDriveから削除することは可能です。",
"settings_ownDriveHint": "技術上の理由で、旧アカウントは最新の機能にアクセスできません。フリーのアップデートで新しい機能が有効になり、CryptDriveの今後のアップデートにも対応します。",
"admin_activePadsHint": "閲覧もしくは編集中のドキュメント数",
"admin_activePadsTitle": "アクティブなドキュメント",
@ -1138,7 +1138,7 @@
"notification_fileSharedTeam": "{0}がチーム({2})とファイル(<b>{1}</b>)を共有しました",
"notification_padSharedTeam": "{0}がチーム({2})とドキュメント(<b>{1}</b>)を共有しました",
"requestEdit_accepted": "{1}があなたにドキュメント(<b>{0}</b>)の編集権を付与しました",
"admin_registrationHint": "このインスタンスの訪問者にはアカウントの作成が許可されていません。管理は招待を行うことができます。",
"admin_registrationHint": "このインスタンスの訪問者にはアカウントの作成が許可されていません。管理は招待を行うことができます。",
"oo_deletedVersion": "このバージョンは履歴に存在しません。",
"team_pickFriends": "チームに招待する連絡先を選択",
"notification_fileShared": "{0}があなたとファイルを共有しました: <b>{1}</b>",
@ -1180,7 +1180,7 @@
"form_isOpen": "このフォームは公開中です",
"form_isClosed": "このフォームは{0}に回答を締め切りました",
"form_willClose": "このフォームは{0}に回答を締め切ります",
"settings_driveRedirectHint": "ログイン時にホームページからドライブに自動で転送する機能は、デフォルトで有効ではなくなりました。以前の動作は以下で有効にできます。",
"settings_driveRedirectHint": "ログイン時にホームページからドライブに自動で転送する機能は、既定で有効ではなくなりました。以前の動作は以下で有効にできます。",
"admin_removeDonateButtonLabel": "クラウドファンディングのキャンペーンの宣伝を表示しない",
"admin_purpose_public": "誰でも利用できる自由なサービスを提供するため",
"owner_team_add": "{0}があなたをチーム(<b>{1}</b>)のオーナーにしようとしています。承諾しますか?",
@ -1226,7 +1226,7 @@
"creation_expiresIn": "有効期限",
"settings_mediatagSizeHint": "ドキュメントに埋め込まれたメディア要素画像、ビデオ、PDFを自動で読み込む最大のサイズをメガバイトMBで指定してください。指定したサイズより大きい要素については、手動で読み込む必要があります。「-1」を設定すると、メディア要素は常に自動で読み込みます。",
"settings_mediatagSizeTitle": "自動ダウンロードの制限",
"settings_cacheHint": "CryptPadは、帯域の使用量を減らし、読み込み時間を短縮することを目的に、ドキュメントの各部分をブラウザー上のメモリに保存しています。もし空き容量が少なければ、キャッシュを無効にしてください。セキュリティー上の懸念から、キャッシュはログアウト時に毎回消去されますが、手動でキャッシュを消去してデバイスの空き容量を確保することもできます。",
"settings_cacheHint": "CryptPadはネットワークの使用量を節約し、また、読み込み時間を改善するため、ドキュメントの各部分をブラウザーのメモリーに保存します。端末のストレージの空き容量が少ない場合、キャッシュを無効にできます。セキュリティー上の理由から、キャッシュはログアウトすると常に消去されますが、端末で使用しているストレージ容量を減らしたい場合は、手動でこれを消去することもできます。",
"team_infoContent": "それぞれのチームには、チーム所有のCryptDrive、ストレージのクォータ、チャット、メンバーリストが備わっています。チームのオーナーはチームを削除することができます。管理者はメンバーを招待したりキックしたりすることができます。メンバーは、チームを退会することができます。",
"form_default": "ここに質問を入力",
"form_poll_switch": "行と列を入れ替える",
@ -1279,11 +1279,11 @@
"admin_purpose_business": "ビジネス、営利団体での使用",
"admin_purpose_education": "教育機関での使用",
"admin_purpose_org": "非営利団体、支援団体での使用",
"admin_purpose_personal": "個人用、家族、友人との利用",
"admin_purpose_personal": "個人用、家族、友人との利用",
"burnAfterReading_linkBurnAfterReading": "一度だけ表示した後に自動で削除",
"feedback_about": "これを読んでいるのは、特定のアクションの実行時にCryptPadがウェブページのリクエストを送信している理由が気になるからだと思います。",
"burnAfterReading_warningLink": "ドキュメントを自動削除に設定しました。リンクを受け取った相手がリンクを開くと、ドキュメントは一度だけ表示され、その後削除されます。",
"burnAfterReading_warningAccess": "このドキュメントは自動的に削除されます。下のボタンをクリックするとコンテンツが自動的に表示され、その後で削除されます。ドキュメントを表示した後でウィンドウを閉じると、二度とドキュメントにアクセスすることはできません。準備ができていない場合は、ドキュメントを表示する前にこのウィンドウを閉じて、後ほどアクセスしてください。",
"burnAfterReading_warningAccess": "このドキュメントは自動的に破棄(完全に削除されます。下のボタンをクリックするとコンテンツが自動的に表示され、その後で削除されます。ドキュメントを表示した後でウィンドウを閉じると、二度とドキュメントにアクセスすることはできません。準備ができていない場合は、ドキュメントを表示する前にこのウィンドウを閉じて、後ほどアクセスしてください。",
"form_sort_hint": "項目を優先順位1が最も高く{0}が最も低い)に従って並べてください。",
"canvas_brush": "ペン",
"share_versionHash": "ドキュメントの選択したバージョンを閲覧モードで共有します。それにより、このドキュメントの全てのバージョンへの<b>読み取り専用アクセス</b>も可能になります。",
@ -1579,7 +1579,7 @@
"form_showCondorcetWinner": "勝者: ",
"form_showDetails": "詳細",
"form_type_date": "日付",
"settings_mfaHint": "任意の認証用アプリケーションによる追加の認証コードで、アカウントを保護しましょう",
"settings_mfaHint": "任意の認証用アプリケーションによる追加の認証コードで、アカウントを保護できます",
"continue": "続行",
"mfa_setup_label": "二要素認証を有効にするには、初めにアカウントのパスワードを入力してください",
"mfa_setup_button": "二要素認証の設定を開始",
@ -1769,7 +1769,17 @@
"admin_onboardingNameTitle": "あなたのCryptPadのインスタンスにようこそ",
"support_legacyHint": "旧式のサポートシステムのチケットを表示した後、新しいサポートシステムで改めてチケットを作成します。",
"admin_onboardingOptionsTitle": "インスタンスのオプション",
"admin_onboardingOptionsHint": "インスタンスに適切な設定を選択してください。</br>これらの設定は、後から管理者パネルで変更できます。",
"admin_onboardingOptionsHint": "インスタンスに適切な設定を選択してください。<br>これらの設定は、後から管理者パネルで変更できます。",
"admin_onboardingNamePlaceholder": "インスタンスのタイトル",
"admin_onboardingDescPlaceholder": "インスタントの説明文"
"admin_onboardingDescPlaceholder": "インスタントの説明文",
"form_condorcetRanked": "ランク付けペア",
"admin_mfa_confirm_enable": "多要素認証を有効にしてよろしいですか?",
"admin_mfa_confirm_disable": "多要素認証を無効にしてよろしいですか?",
"install_instance": "初めに管理者アカウントを作成して、その後にインスタンスのカスタマイズに移ります",
"support_legacyButton": "アクティブなチケットを入手",
"support_searchLabel": "検索タイトルまたはチケットのID",
"support_legacyClear": "このアカウントで削除",
"support_moveActive": "アクティブに移動",
"support_userNotification": "新しいサポートチケットまたは回答:{0}",
"install_notes": "<ul class=\"cp-notes-list\"><li>このページで最初の管理者アカウントを作成してください。管理者は、ストレージの割合などを含むインスタンスの設定を管理したり、モデレーション用のツールにアクセスしたりできます。</li><li>あなたのパスワードは、あなたの全ドキュメントと、このインスタンスの管理者特権を暗号化する秘密鍵となります。 <span class=\"red\">パスワードを紛失した場合、データを復元することはできません。</span></li><li>コンピューターを共用している場合、作業を完了したら<span class=\"red\">必ずログアウトしてください</span>。ブラウザーのウインドウを閉じるだけでは、第三者によりあなたのアカウントにアクセスされるおそれがあります。 </li></ul>"
}

View File

@ -1780,5 +1780,8 @@
"admin_onboardingOptionsTitle": "Instance options",
"admin_onboardingOptionsHint": "Please select the appropriate option for your instance.<br>These settings can be changed later in the admin panel.",
"admin_onboardingNamePlaceholder": "Instance title",
"admin_onboardingDescPlaceholder": "Instance description text"
"admin_onboardingDescPlaceholder": "Instance description text",
"team_autoTrim": "Trimming team drive history... Please wait.",
"admin_mfa_confirm_enable": "Are you sure you want to enable Multi-Factor Authentication?",
"admin_mfa_confirm_disable": "Are you sure you want to disable Multi-Factor Authentication?"
}

View File

@ -342,7 +342,7 @@
"settings_exportCancel": "Czy na pewno chcesz anulować eksport? Następnym razem będziesz musiał zacząć od początku.",
"settings_exportWarning": "Uwaga: to narzędzie jest wciąż w wersji beta i może mieć problemy ze skalowalnością. Aby uzyskać lepszą wydajność, zaleca się pozostawienie tej zakładki aktywnej.",
"settings_exportFailed": "Jeśli pobranie dokumentu wymaga więcej niż 1 minutę, nie zostanie on wyeksportowany. Zostanie wyświetlony link do każdego dokumentu, który nie został wyeksportowany.",
"settings_exportDescription": "Proszę czekać, aż pobierzemy i odszyfrujemy Twoje dokumenty. Może to potrwać kilka minut. Zamknięcie karty spowoduje przerwanie tego procesu.",
"settings_exportDescription": "Zaczekaj, aż pobierzemy i odszyfrujemy Twoje dokumenty. Może to potrwać kilka minut. Zamknięcie karty spowoduje przerwanie tego procesu.",
"settings_exportTitle": "Eksportuj swój CryptDrive",
"settings_backup2Confirm": "Spowoduje to pobranie wszystkich dokumentów i plików z Twojego CryptDrive. Jeśli chcesz kontynuować, wybierz nazwę i naciśnij OK",
"settings_backup2": "Pobierz mój CryptDrive",
@ -444,7 +444,7 @@
"support_formContentError": "Błąd: treść jest pusta",
"support_formTitleError": "Błąd: tytuł jest pusty",
"support_formButton": "Wyślij",
"support_formHint": "Użyj tego formularza, aby bezpiecznie skontaktować się z administratorami.<br>Proszę zauważyć, że niektóre kwestie/pytania mogą być już poruszone w <a>Podręczniku użytkownika programu CryptPad</a>. Prosimy nie tworzyć nowego zgłoszenia, jeśli masz już otwarte zgłoszenie dotyczące tego samego problemu. Zamiast tego odpowiedz na oryginalną wiadomość, podając dodatkowe informacje.",
"support_formHint": "Użyj tego formularza, aby bezpiecznie skontaktować się z administratorami.<br>Proszę zauważyć, że niektóre kwestie/pytania mogą być już poruszone w <a>Podręczniku Użytkownika CryptPad</a>. Prosimy nie tworzyć nowego zgłoszenia, jeśli masz już otwarte zgłoszenie dotyczące tego samego problemu. Zamiast tego odpowiedz na oryginalną wiadomość, podając dodatkowe informacje.",
"support_formTitle": "Nowe Zgłoszenie",
"support_cat_new": "Nowe zgłoszenie",
"support_disabledHint": "Ta instancja CryptPad nie jest jeszcze skonfigurowana do korzystania z formularza pomocy technicznej.",
@ -509,8 +509,8 @@
"admin_updateLimitButton": "Aktualizuj limity",
"admin_updateLimitHint": "Wymuszenie aktualizacji limitu przestrzeni dostępnej dla użytkownika może być wykonane w dowolnym momencie, ale jest konieczne tylko w przypadku wystąpienia błędu",
"admin_updateLimitTitle": "Aktualizuj limity użytkowników",
"admin_registeredHint": "Liczba użytkowników zarejestrowanych na Twojej instancji",
"admin_registeredTitle": "Użytkownicy zarejestrowani",
"admin_registeredHint": "Liczba aktywnych dysków w Twojej instancji",
"admin_registeredTitle": "Dyski indywidualne i zespołowe",
"admin_activePadsHint": "Liczba unikalnych dokumentów, które są aktualnie przeglądane lub edytowane",
"admin_activePadsTitle": "Aktywne dokumenty",
"admin_activeSessionsHint": "Liczba aktywnych połączeń websocket (i połączonych unikalnych adresów IP)",
@ -641,7 +641,7 @@
"privacy": "Polityka prywatności",
"about": "O stronie",
"main_catch_phrase": "Pakiet do współpracy<br>end-to-end szyfrowany i oparty na otwartym kodzie źródłowym",
"home_host": "To jest niezależna wersja społecznościowa CryptPada.",
"home_host": "Niezależna społecznościowa instancja CryptPada.",
"mdToolbar_toc": "Spis Treści",
"mdToolbar_code": "Kod",
"mdToolbar_check": "Lista zadań",
@ -1057,7 +1057,7 @@
"admin_defaultlimitHint": "Maksymalny limit przechowywania danych w CryptDrive (użytkownicy i zespoły), gdy nie jest stosowana żadna reguła własna",
"admin_defaultlimitTitle": "Maksymalny limit przechowywania danych (MB)",
"admin_registrationTitle": "Zamknij rejestrację",
"admin_registrationHint": "Nie zezwalaj nowym użytkownikom na rejestrację",
"admin_registrationHint": "Goście odwiedzający instancję nie mają możliwości stworzenia konta. Zaproszenia mogą być tworzone przez administratorów.",
"snapshots_cantMake": "Nie można utworzyć obrazu. Jesteś rozłączony.",
"snapshots_notFound": "Ten obraz już nie istnieje, ponieważ historia tego dokumentu została usunięta.",
"snapshot_error_exists": "Istnieje już obraz tej wersji",
@ -1241,7 +1241,7 @@
"imprint": "Informacje prawne",
"oo_sheetMigration_anonymousEditor": "Ten dokument wymaga aktualizacji. Edycja jest zablokowana dla gości do momentu otwarcia go przez zarejestrowanego użytkownika.",
"oo_sheetMigration_complete": "Dostępna jest zaktualizowana wersja, naciśnij OK, aby załadować ponownie.",
"oo_sheetMigration_loading": "Aktualizacja dokumentu do najnowszej wersji. Proszę czekać około 1 minuty.",
"oo_sheetMigration_loading": "Aktualizacja dokumentu do najnowszej wersji. Poczekaj około 1 minutę.",
"oo_exportInProgress": "Eksport w toku",
"oo_importInProgress": "Import w toku",
"oo_invalidFormat": "Ten plik nie może być zaimportowany",
@ -1397,7 +1397,7 @@
"ui_saved": "{0} zapisano",
"admin_nameHint": "Wyświetlana nazwa dla tego urządzenia z listy publicznych instacji na stronie cryptpad.org",
"admin_archiveNote": "Notatka",
"common_connectionLost": "<b>Utracono połączenie z serwerem</b><br>Dopóki połączenie nie wróci, włączony będzie tryb tylko do odczytu.",
"common_connectionLost": "<b>Utracono Połączenie z Serwerem</b><br>Dopóki połączenie nie wróci, włączony będzie tryb tylko do odczytu.",
"admin_infoNotice2": "Więcej informacji można znaleźć w zakładce \"Sieć\".",
"admin_nameTitle": "Nazwa instancji",
"support_warning_abuse": "Prosimy o zgłaszanie treści, które naruszają <a>Warunki korzystania z usługi</a>. Prosimy o podanie linków do obraźliwych dokumentów lub profili użytkowników i opisanie, w jaki sposób naruszają one warunki. Wszelkie dodatkowe informacje na temat kontekstu, w którym odkryłeś treść lub zachowanie, mogą pomóc administratorom w zapobieganiu przyszłym naruszeniom",
@ -1640,7 +1640,7 @@
"settings_removeOwnedButton": "Zniszcz swoje dokumenty",
"admin_totpEnabled": "2FA jest włączone",
"recovery_mfa_error": "Nieznany błąd. Odśwież i spróbuj ponownie.",
"recovery_mfa_disabled": "Uwierzytelnianie dwuetapowe jest już wyłączone dla tego konta.",
"recovery_mfa_disabled": "Uwierzytelnianie wieloetapowe jest już wyłączone dla tego konta.",
"recovery_mfa_secret_ph": "Kod odzyskiwania",
"admin_invitationTitle": "Zaproszenia",
"admin_invitationCreate": "Stwórz zaproszenie",
@ -1664,15 +1664,15 @@
"admin_totpCheck": "Weryfikacja podpisu powiodła się",
"admin_totpDisableButton": "Wyłącz",
"register_nameTooLong": "Nazwa użytkownika musi zawierać poniżej {0} znaków",
"loading_enter_otp": "To konto jest chronione za pomocą uwierzytelniania dwuetapowego. Wprowadź kod weryfikacyjny",
"loading_enter_otp": "To konto jest chronione za pomocą uwierzytelniania dwuskładnikowego. Wprowadź swój kod weryfikacyjny",
"loading_recover": "Nie możesz zdobyć kodu? <a href=\"/recovery/\">Przywróć swoje konto</a>",
"goLeft": "Lewo",
"ssoauth_header": "Hasło CryptPad",
"ssoauth_form_hint_login": "Wprowadź swoje hasło CryptPad",
"kanban_showTags": "Wszystkie tagi",
"kanban_hideTags": "Mniej tagów",
"admin_forcemfaTitle": "Wymagaj Uwierzytelniania Dwuetapowego",
"admin_forcemfaHint": "Wszyscy użytkownicy tej instancji zostaną poproszeni o skonfigurowanie uwierzytelniania dwuetapowego, aby zalogować się do swojego konta.",
"admin_forcemfaTitle": "Wymagaj Uwierzytelniania Dwuskładnikowego",
"admin_forcemfaHint": "Wszyscy użytkownicy tej instancji zostaną poproszeni o skonfigurowanie uwierzytelniania dwuskładnikowego, aby zalogować się do swojego konta. Użytkownicy już istniejący również nie będą mogli korzystać ze swojego konta bez konfiguracji aplikacji TOTP.",
"support_recordedContent": "Treść",
"support_legacyDump": "Wyeksportuj wszystko",
"support_legacyClear": "Usuń to konto",
@ -1683,13 +1683,13 @@
"admin_invitationDeleteConfirm": "Czy na pewno chcesz usunąć to zaproszenie?",
"admin_invitationCopy": "Skopiuj link",
"settings_removeOwnedTitle": "Zniszcz wszystkie swoje dokumenty",
"settings_removeOwnedText": "Niszczenie twoich dokumentów w toku...",
"settings_removeOwnedText": "Proszę czekać, trwa niszczenie Twoich dokumentów...",
"mfa_status_on": "2FA aktywne na tym koncie",
"recovery_header": "Przywracanie 2FA",
"recovery_forgot": "Zapomniany kod odzyskiwania",
"recovery_forgot_text": "Skopiuj następujące informacje i <a href=\"mailto:{0}\">prześlij je</a> administratorom swojej instancji",
"goRight": "Prawo",
"loading_mfa_required": "Uwierzytelnianie dwuetapowe jest wymagane na tej instancji. Uaktualnij swoje kono z użyciem aplikacji uwierzytelniającej i poniższego formularza.",
"loading_mfa_required": "Uwierzytelnianie dwuskłądnikowe jest wymagane na tej instancji. Uaktualnij swoje konto z użyciem aplikacji uwierzytelniającej i poniższego formularza.",
"admin_invitationLink": "Zaproszenie",
"admin_registrationSsoTitle": "Zamknij rejestrację SSO",
"admin_usersAdd": "Dodaj istniejącego użytkownika",
@ -1763,5 +1763,25 @@
"admin_usersHint": "Lista znanych Ci kont na tej instancji. Zaznacz poniżej aby dodać konta automatycznie, lub wprowadź informacje ręcznie za pomocą formularza.",
"admin_supportSetupHint": "Stwórz lub aktualizuj klucze pomocy.",
"admin_supportRotateNotify": "Uwaga: nowe klucze zostały wygenerowane, ale nieoczekiwany błąd nie pozwolił systemowi wysłać ich moderatorom. Usuń i dodaj ponownie członków zespołu",
"support_notificationsHint": "Zaznacz tę opcję, żeby wyłączyć powiadomienia o nowych zgłoszeniach i odpowiedziach"
"support_notificationsHint": "Zaznacz tę opcję, żeby wyłączyć powiadomienia o nowych zgłoszeniach i odpowiedziach",
"admin_appSelection": "Konfiguracja aplikacji",
"admin_appsTitle": "Aplikacje instancji",
"admin_appsHint": "Wybierz, które aplikacje włączyć dla tej instancji.",
"admin_cat_apps": "Aplikacje",
"install_token": "Token instalacyjny",
"install_header": "Instalacja",
"install_instance": "Stwórz pierwsze konto administratora, a następnie dostosuj instancję",
"install_launch": "Konfiguracja instancji",
"install_notes": "<ul class=\"cp-notes-list\"><li>Na tej stronie stworzysz swoje pierwsze konto administratora. Administratorzy zarządzają ustawieniami instancji, w tym przydziałem przestrzeni dyskowej i mają dostęp do narzędzi moderacji.</li><li>Twoje hasło to tajny klucz, szyfrujący wszystkie Twoje dokumenty i przywileje administratora na tej instancji. <span class=\"red\">Jeśli je zgubisz, nie mamy możliwości odzyskania Twoich danych.</span></li><li>Jeśli dzielisz komputer z innymi osobami, <span class=\"red\">pamiętaj, aby się wylogować</span> po zakończeniu pracy. Zamknięcie jedynie okna przeglądarki naraża bezpieczeństwo Twojego konta.</li></ul>",
"onboarding_upload": "Wybierz logo",
"onboarding_save_error": "Niektóre opcje nie zostały prawidłowo zapisane. Odwiedź panel administratora, aby sprawdzić ich wartości.",
"admin_onboardingNameHint": "Wybierz tytuł, opis, kolor wiodący i logo (opcjonalnie)",
"admin_onboardingNameTitle": "Witaj w Twojej instancji CryptPad",
"admin_onboardingOptionsTitle": "Opcje instancji",
"admin_onboardingNamePlaceholder": "Tytuł instancji",
"admin_onboardingDescPlaceholder": "Treść opisu instancji",
"admin_onboardingOptionsHint": "Zaznacz właściwą opcję dla Twojej instancji.<br>To ustawienie może być później zmienione w panelu administratora.",
"team_autoTrim": "Zmniejszanie historii dysku... Proszę czekać.",
"admin_mfa_confirm_enable": "Czy na pewno chcesz włączyć uwierzytelnianie wieloetapowe?",
"admin_mfa_confirm_disable": "Czy na pewno chcesz wyłączyć uwierzytelnianie wieloetapowe?"
}

File diff suppressed because it is too large Load Diff

View File

@ -931,8 +931,8 @@
"admin_updateLimitButton": "Обновить квоты",
"admin_updateLimitHint": "Принудительное обновление лимитов пользовательского хранилища можно выполнить в любое время, но это необходимо только в случае ошибки",
"admin_updateLimitTitle": "Обновить пользовательские квоты",
"admin_registeredHint": "Количество пользователей, зарегистрированных на вашем экземпляре",
"admin_registeredTitle": "Зарегистрированные пользователи",
"admin_registeredHint": "Количество активных дисков на Вашем экземпляре",
"admin_registeredTitle": "Дисков пользователей и команд",
"admin_activePadsHint": "Количество уникальных документов, просматриваемых или редактируемых в данный момент",
"admin_activePadsTitle": "Активные документы",
"admin_activeSessionsHint": "Количество активных подключений к веб-сокетам (и подключенных уникальных IP-адресов)",
@ -1780,5 +1780,7 @@
"admin_onboardingOptionsHint": "Пожалуйста, выберите подходящий вариант для Вашего экземпляра.<br>Эти настройки можно изменить позже в панели администратора.",
"admin_onboardingNamePlaceholder": "Заголовок экземпляра",
"install_instance": "Создайте первую учетную запись администратора, а затем приступайте к настройке этого экземпляра",
"admin_onboardingDescPlaceholder": "Текст описания экземпляра"
"admin_onboardingDescPlaceholder": "Текст описания экземпляра",
"admin_mfa_confirm_disable": "Вы уверены, что хотите выключить многофакторную аутентификацию (MFA)?",
"admin_mfa_confirm_enable": "Вы уверены, что хотите включить многофакторную аутентификацию (MFA)?"
}

View File

@ -119,7 +119,8 @@
url: config.document.url,
document: blob,
ext: config.document.fileType,
autosave: config.autosave || 10
autosave: config.autosave || 10,
editorConfig: config.editorConfig || {}
}, function (obj) {
if (obj && obj.error) { reject(obj.error); return console.error(obj.error); }
resolve({});
@ -194,6 +195,7 @@
chan.on('ON_DOWNLOADAS', blob => {
let url = URL.createObjectURL(blob);
if (!config.events.onDownloadAs) { return; }
config.events.onDownloadAs({
data: {
fileType: config.document && config.document.fileType,
@ -204,6 +206,7 @@
chan.on('SAVE', function (data, cb) {
blob = data;
if (!config.events.onSave) { return void cb(); }
config.events.onSave(data, cb);
});
chan.on('RELOAD', function () {
@ -254,16 +257,22 @@
cryptpadURL = getInstanceURL();
}
config.events = config.events || {};
// OnlyOffice shim
let url = config.document.url;
if (/^http:\/\/localhost\/cache\/files\//.test(url)) {
url = url.replace(/(http:\/\/localhost\/cache\/files\/)/, getInstanceURL() + 'ooapi/');
}
config.document.url = url;
if (config.documentType === "spreadsheet") {
if (config.documentType === "spreadsheet" || config.documentType === "cell") {
config.documentType = "sheet";
}
if (config.documentType === "text") {
if (config.documentType === "slide") {
config.documentType = "presentation";
}
if (config.documentType === "word" || config.documentType === "text") {
config.documentType = "doc";
}
@ -314,8 +323,8 @@
iframe.setAttribute('name', 'frameEditor');
iframe.setAttribute('align', 'top');
iframe.setAttribute("src", url);
iframe.setAttribute("width", config.width);
iframe.setAttribute("height", config.height);
iframe.setAttribute("width", config.width || '100%');
iframe.setAttribute("height", config.height || '100%');
if (config.editorConfig) { // OnlyOffice
container.replaceWith(iframe);
container = iframe;

View File

@ -4,20 +4,24 @@
// This is the initialization loading the CryptPad libraries
define([
'jquery',
'/common/sframe-app-framework.js',
'/customize/messages.js', // translation keys
'/components/pako/dist/pako.min.js',
'/components/x2js/x2js.js',
'/diagram/util.js',
'/common/common-ui-elements.js',
'/components/tweetnacl/nacl-fast.min.js',
'less!/diagram/app-diagram.less',
'css!/diagram/drawio.css',
], function (
$,
Framework,
Messages,
pako,
X2JS,
DiagramUtil
DiagramUtil,
UIElements
) {
const Nacl = window.nacl;
const APP = window.APP = {};
@ -61,6 +65,15 @@ define([
return JSON.stringify(o1) === JSON.stringify(o2);
};
var mkHelpMenu = function (framework) {
var $codeMirrorContainer = $('#cp-app-diagram-container');
var helpMenu = framework._.sfCommon.createHelpMenu(['diagram']);
$codeMirrorContainer.prepend(helpMenu.menu);
var $helpMenuButton = UIElements.getEntryFromButton(helpMenu.button);
framework._.toolbar.$drawer.append($helpMenuButton);
};
// This is the main initialization loop
var onFrameworkReady = function (framework) {
var EMPTY_DRAWIO = "<mxfile type=\"embed\"><diagram id=\"bWoO5ACGZIaXrIiKNTKd\" name=\"Page-1\"><mxGraphModel dx=\"1259\" dy=\"718\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"827\" pageHeight=\"1169\" math=\"0\" shadow=\"0\"><root><mxCell id=\"0\"/><mxCell id=\"1\" parent=\"0\"/></root></mxGraphModel></diagram></mxfile>";
@ -69,6 +82,11 @@ define([
var lastContent = x2js.xml2js(EMPTY_DRAWIO);
var drawIoInitalized = false;
var privateData = framework._.cpNfInner.metadataMgr.getPrivateData();
if (!privateData.isEmbed) {
mkHelpMenu(framework);
}
var postMessageToDrawio = function(msg) {
if (!drawIoInitalized) {
return;

View File

@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
</head>
<body class="cp-app-drive cp-body-drive">
<div id="cp-toolbar" class="cp-toolbar-container"></div>
<div class="cp-app-drive-container" tabindex="0">
<div class="cp-app-drive-container">
<div id="cp-app-drive-tree">
</div>
<div id="cp-app-drive-content-container">

View File

@ -189,7 +189,7 @@ define([
anywhere else then we can deprecate them and make this a
custom modal in common-interface (or here). */
cancelClass: 'btn.btn-cancel.btn-register',
okClass: 'btn.btn-danger.btn-register',
okClass: 'btn.btn-danger.btn-register.btn-confirm',
reverseOrder: true,
done: function ($dialog) {
$dialog.find('> div').addClass('half');

View File

@ -182,6 +182,11 @@ define([
chan.on('START', function (data, cb) {
console.warn('INNER START', data);
var href = Hash.hashToHref(data.key, data.application);
if (data.editorConfig.lang) {
var LS_LANG = "CRYPTPAD_LANG";
localStorage.setItem(LS_LANG, data.editorConfig.lang);
}
console.error(Hash.hrefToHexChannelId(href));
let startApp = function (blob) {
window.CP_integration_outer = {
@ -191,7 +196,8 @@ define([
initialState: blob,
config: {
fileType: data.ext,
autosave: data.autosave
autosave: data.autosave,
user: data.editorConfig.user
},
utils: {
onReady: onReady,

View File

@ -177,8 +177,8 @@
align-self: flex-start;
outline-style: none;
border-radius: @variables_radius;
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
@media (hover: none) {
margin-right: 20px;
@ -413,8 +413,8 @@
.fa {
margin-right: 5px;
}
&:focus{
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}
}
@ -651,8 +651,8 @@
&:hover {
background-color: @cp_kanban-add-hover;
}
&:focus {
outline: @cryptpad_color_brand solid 2px;
&:focus-visible {
outline: @variables_focus_style;
}
}

View File

@ -22,6 +22,7 @@ define([
'cm/lib/codemirror',
'/kanban/jkanban_cp.js',
'/kanban/export.js',
'/common/TypingTests.js',
'cm/mode/gfm/gfm',
'cm/addon/edit/closebrackets',
@ -54,7 +55,8 @@ define([
ChainPad,
CodeMirror,
jKanban,
Export)
Export,
TypingTest)
{
var verbose = function (x) { console.log(x); };
@ -251,6 +253,10 @@ define([
// Body
var cm = SFCodeMirror.create("gfm", CodeMirror, text);
var editor = cm.editor;
window.easyTest = function () {
var test = TypingTest.testCode(editor);
return test;
};
editor.setOption('gutters', []);
editor.setOption('lineNumbers', false);
editor.setOption('readOnly', false);
@ -1210,6 +1216,8 @@ define([
var json = kanban.getBoardJSON(id) || kanban.getItemJSON(id);
var oldVal = json && json.title;
if (id === "new") { $el.remove(); }
return {
id: id,
newBoard: newBoard,

View File

@ -60,6 +60,7 @@ body.cp-app-pad {
cursor: pointer;
height: 28px;
line-height: 28px;
padding: 0px 6px;
.fa { margin: 0 !important; }
}
&.hidden {

View File

@ -175,7 +175,7 @@ define([
anywhere else then we can deprecate them and make this a
custom modal in common-interface (or here). */
cancelClass: 'btn.btn-cancel.btn-register',
okClass: 'btn.btn-danger.btn-register',
okClass: 'btn.btn-danger.btn-register.btn-confirm',
reverseOrder: true,
done: function ($dialog) {
$dialog.find('> div').addClass('half');

View File

@ -20,6 +20,9 @@ define([
'/common/userObject.js',
'/common/clipboard.js',
'/common/outer/login-block.js',
'/common/outer/roster.js',
'/common/rpc.js',
'/common/pinpad.js',
'/components/tweetnacl/nacl-fast.min.js',
@ -27,7 +30,7 @@ define([
'less!/customize/src/less2/pages/page-report.less',
], function ($, ApiConfig, h, Messages,
nThen, Hash, Util, Constants, Crypt, Cryptpad, Cache, UI, CPNetflux,
Crypto, UserObject, Clipboard, Block) {
Crypto, UserObject, Clipboard, Block, Roster, Rpc, Pinpad) {
var $report = $('#cp-report');
var blockHash = localStorage.Block_hash;
if (!blockHash) {
@ -41,6 +44,21 @@ define([
});
}
let report = true;
let fixRoster = false;
let urlHash = window.location.hash.slice(1);
if (urlHash) {
let s = urlHash.split('=');
let key = s[0];
let value = s[1];
if (key === "roster") {
report = false;
fixRoster = value; // teamid
}
}
var addReport = function (str) {
$report.append(h('div', str));
};
@ -153,6 +171,8 @@ define([
addReport('Teams: ' + Object.keys(proxy.teams || {}).join(', '));
addReport('-------------------');
if (!report) { return; }
var n = nThen;
Object.keys(drive.sharedFolders || {}).forEach(function (id) {
n = n(function (w) {
@ -188,16 +208,67 @@ define([
addReport('===================');
var n = nThen;
Object.keys(proxy.teams || {}).forEach(function (id) {
// If we're in "repair" mode, only load the affected team
var obj = proxy.teams[id];
if (!report && fixRoster !== obj.channel) { return; }
n = n(function (w) {
var next = w();
var obj = proxy.teams[id];
var team;
addReport('Load team. ID: ' + id + '. Channel ID: '+ obj.channel);
addReport('Roster channel: ' + obj.keys.roster.channel);
addReport('Roster lkh: ' + obj.keys.roster.lastKnownHash);
if (!obj.hash) { addReport("View only"); }
var teamSecret = Hash.getSecrets('team', obj.hash || obj.roHash, obj.password);
var cryptor = UserObject.createCryptor(teamSecret.keys.secondaryKey);
// Repair roster mode
if (!report) {
let roster = obj.keys.roster;
let rpc, anon_rpc;
if (!obj.owner || !roster.edit) {
return void addReport('Roster error: only owners can repair');
}
n(w => {
Rpc.createAnonymous(network, w(function (e, call) {
anon_rpc = call;
}));
Pinpad.create(network, proxy, w(function (e, call) {
rpc = call;
}));
}).nThen(w => {
if (!anon_rpc || !rpc) {
return void addReport('RPC error');
}
var rosterKeys = Crypto.Team.deriveMemberKeys(roster.edit, {
curvePublic: proxy.curvePublic,
curvePrivate: proxy.curvePrivate
});
let store = { anon_rpc };
Roster.create({
network: network,
channel: roster.channel,
keys: rosterKeys,
store: store,
lastKnownHash: roster.lastKnownHash
}, w(function (err, _roster) {
if (err) { return void addReport('Fix roster error', err); }
_roster.checkpoint(w((err, state, hash) => {
if (err) { addReport('Fix roster error', err); }
rpc.trimHistory({
channel: roster.channel,
hash
}, w(function (err) {
console.error(arguments);
if (err) { addReport('Trim roster error', err); }
}));
}));
}));
}).nThen(next);
return;
}
// Check team drive
nThen(function (ww) {
addReport('Team drive');

View File

@ -38,8 +38,24 @@
margin-left: 0.5rem;
}
.alertify {
nav {
display: flex;
justify-content: flex-end;
align-items: flex-end;
.btn-confirm {
white-space: normal;
}
}
}
#cp-sidebarlayout-container {
#cp-sidebarlayout-rightside {
input, button, span[tabindex="0"] {
&:focus-visible {
outline: @variables_focus_style;
}
}
input[type="checkbox"] {
vertical-align: middle;
margin-right: 5px;
@ -112,6 +128,14 @@
margin-top:0;
margin-left: 10px;
}
.cp-password-reveal {
border-radius:@variables_radius;
}
}
nav {
display: flex;
justify-content: center;
align-items: flex-end;
}
@media (max-width: 840px) {

View File

@ -807,7 +807,7 @@ define([
}, {
ok: Messages.register_writtenPassword,
cancel: Messages.register_cancel,
okClass: 'btn.btn-danger',
okClass: 'btn.btn-danger.btn-confirm',
reverseOrder: true,
done: function($dialog) {
$dialog.find('> div').addClass('half');

View File

@ -62,6 +62,14 @@
div#cp-sidebarlayout-leftside {
background-color: @cp_teams-leftside-bg;
}
#cp-sidebarlayout-rightside{
input, button, textarea {
&:focus-visible {
outline: @variables_focus_style;
}
}
}
div#cp-sidebarlayout-rightside.cp-rightside-drive {
padding: 0;
& > .cp-team-chat {
@ -73,7 +81,11 @@
}
.cp-app-contacts-input {
textarea {
border: 0px;
border: 0;
margin-right: 2px;
}
.fa-paper-plane{
border-radius: @variables_radius;
}
}
}
@ -96,7 +108,7 @@
}
}
.cp-team-cat-header {
justify-content: center;
justify-content: left;
background-color: transparent !important;
box-shadow: none !important;
.avatar_main(30px);
@ -106,6 +118,7 @@
}
media-tag, .cp-avatar-default {
margin-right: 3px;
flex-shrink: 0;
}
media-tag {
order: -1;
@ -113,7 +126,12 @@
cursor: default !important;
font-size: 18px;
span.cp-sidebarlayout-category-name {
max-width: 12rem;
padding-left: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
}
.cp-team-cat-chat {
@ -142,6 +160,9 @@
height: 384px;
padding: 50px;
margin: 5px;
&:focus-visible {
outline: @variables_focus_style;
}
&.create, &:not(.empty) {
cursor: pointer;
&:hover {
@ -292,6 +313,15 @@
margin: 0;
}
}
.cp-team-trim {
display: flex;
align-items: center;
justify-content: center;
.fa {
font-size: 30px;
margin-right: 10px;
}
}
.cp-teams-invite-uses {
input {

View File

@ -191,6 +191,7 @@ define([
'cp-team-avatar',
'cp-team-export',
'cp-team-delete',
'cp-team-history',
],
};
@ -398,6 +399,43 @@ define([
]);
});
let AUTOTRIM_LIMIT = 102400; // 100kB history before auto trim
var trimHistory = function () {
var size;
var channels = [];
nThen(function(waitFor) {
APP.history.execCommand('GET_HISTORY_SIZE', {
team: APP.team,
channels: []
}, waitFor(function(obj) {
if (obj && obj.error) {
waitFor.abort();
console.error(obj.error);
return;
}
channels = obj.channels;
size = Number(obj.size);
}));
}).nThen(function() {
if (!size || size < AUTOTRIM_LIMIT) {
// Nothing to delete
return;
}
var div = h('div.cp-team-trim', [
h('span.fa.fa-spin.fa-spinner'),
h('span', Messages.team_autoTrim)
]);
UI.openCustomModal(UI.dialog.customModal(div, {buttons: []}));
console.log('Trimming team history', APP.team, size);
APP.history.execCommand('TRIM_HISTORY', {
channels: channels
}, function(obj) {
if (obj && obj.error) { console.error(obj.error); }
UI.removeModals();
});
});
};
var openTeam = function (common, id, team) {
var sframeChan = common.getSframeChannel();
APP.module.execCommand('SUBSCRIBE', id, function () {
@ -422,6 +460,7 @@ define([
APP.team = id;
APP.teamEdPublic = Util.find(team, ['keys', 'drive', 'edPublic']);
buildUI(common, true, team.owner);
if (team.owner) { trimHistory(common); }
});
});
};
@ -1556,6 +1595,7 @@ define([
}
};
APP.history = common.makeUniversal('history');
APP.module = common.makeUniversal('team', {
onEvent: onEvent
});