Merge branch 'develop' into feature/appearance-mobile-layout

This commit is contained in:
Ilya Oleshko 2023-09-07 10:22:25 +03:00
commit 1f8c40bcf9
107 changed files with 1646 additions and 543 deletions

View File

@ -63,10 +63,12 @@ jobs:
wget https://packages.microsoft.com/config/$(lsb_release -is | \
tr [:upper:] [:lower:])/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/nodesource.gpg --import
chmod 644 /usr/share/keyrings/nodesource.gpg
apt-get -y update
echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | \
sudo tee /etc/apt/sources.list.d/nodesource.list
wget -O - https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | \
sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/nodesource.gpg --import
sudo chmod 644 /usr/share/keyrings/nodesource.gpg
sudo apt-get -y update
sudo apt install -y dotnet-sdk-7.0 yarn nodejs dh-make rename dpkg-sig lintian
sudo npm install -g json
echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_OUTPUT
@ -136,10 +138,12 @@ jobs:
wget https://packages.microsoft.com/config/$(lsb_release -is | \
tr [:upper:] [:lower:])/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/nodesource.gpg --import
chmod 644 /usr/share/keyrings/nodesource.gpg
apt-get -y update
echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | \
sudo tee /etc/apt/sources.list.d/nodesource.list
wget -O - https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | \
sudo gpg --no-default-keyring --keyring gnupg-ring:/usr/share/keyrings/nodesource.gpg --import
sudo chmod 644 /usr/share/keyrings/nodesource.gpg
sudo apt-get -y update
sudo apt install -y dotnet-sdk-7.0 yarn nodejs dh-make rename python3-pip python3-rpm
sudo npm install -g json
sudo pip install rpmlint

View File

@ -13,7 +13,7 @@ $LocalIp = (Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where
$Doceditor = ($LocalIp + ":5013")
$Login = ($LocalIp + ":5011")
$Client = ($LocalIp + ":5001")
$PortalUrl = ("http://" + $LocalIp + ":8092")
$PortalUrl = ("http://" + $LocalIp)
$ProxyVersion="v1.0.0"
# Stop all backend services"
@ -38,6 +38,10 @@ if (-not $ExistsNetwork) {
Write-Host "Run MySQL" -ForegroundColor Green
docker compose -f "$DockerDir\db.yml" up -d
Write-Host "Run local dns server" -ForegroundColor Green
$Env:ROOT_DIR=$RootDir
docker compose -f "$DockerDir\dnsmasq.yml" up -d
Write-Host "Build backend services (to `publish/` folder)" -ForegroundColor Green
& "$PSScriptRoot\install\common\build-services.ps1"
@ -75,7 +79,7 @@ if (!$ExistsNode -or $Force) {
if (!$ExistsProxy -or $Force) {
Write-Host "Build proxy base image from source (apply new nginx config)" -ForegroundColor Green
docker build -t "onlyoffice/4testing-docspace-proxy-runtime:$ProxyVersion" -f "$DockerDir\Dockerfile.runtime" --target proxy .
docker build -t "onlyoffice/4testing-docspace-proxy-runtime:$ProxyVersion" -f "$DockerDir\Dockerfile.runtime" --target router .
} else {
Write-Host "SKIP build proxy base image (already exists)" -ForegroundColor Blue
}

View File

@ -16,7 +16,7 @@ echo "LOCAL IP: $local_ip"
doceditor=${local_ip}:5013
login=${local_ip}:5011
client=${local_ip}:5001
portal_url="http://$local_ip:8092"
portal_url="http://$local_ip"
echo "SERVICE_DOCEDITOR: $doceditor"
echo "SERVICE_LOGIN: $login"
@ -56,6 +56,10 @@ else
exit 1
fi
echo "Run local dns server"
ROOT_DIR=$dir \
docker compose -f $dockerDir/dnsmasq.yml up -d
echo "Clear publish folder"
rm -rf $dir/publish
@ -99,7 +103,7 @@ exists=$(docker images | egrep "onlyoffice/4testing-docspace-proxy-runtime" | eg
if [ "${exists}" = "" ] || [ "$force" = true ]; then
echo "Build proxy base image from source (apply new nginx config)"
docker build -t onlyoffice/4testing-docspace-proxy-runtime:$proxy_version -f ./build/install/docker/Dockerfile.runtime --target proxy .
docker build -t onlyoffice/4testing-docspace-proxy-runtime:$proxy_version -f ./build/install/docker/Dockerfile.runtime --target router .
else
echo "SKIP build proxy base image (already exists)"
fi

View File

@ -31,7 +31,7 @@ if [ "$UPDATE" = "true" ] && [ "$DOCUMENT_SERVER_INSTALLED" = "true" ]; then
RECONFIGURE_PRODUCT="true"
else
systemctl is-active openresty | grep -q "^active" && systemctl stop openresty
systemctl list-units --type=service | grep -q openresty && systemctl stop openresty
apt-get install -y --only-upgrade ${ds_pkg_name};
fi
fi
@ -62,7 +62,7 @@ if [ "$DOCUMENT_SERVER_INSTALLED" = "false" ]; then
echo ${package_sysname}-documentserver $DS_COMMON_NAME/jwt-secret select ${DS_JWT_SECRET} | sudo debconf-set-selections
echo ${package_sysname}-documentserver $DS_COMMON_NAME/jwt-header select ${DS_JWT_HEADER} | sudo debconf-set-selections
systemctl is-active openresty | grep -q "^active" && systemctl stop openresty
systemctl list-units --type=service | grep -q openresty && systemctl stop openresty
if [ "$INSTALLATION_TYPE" = "COMMUNITY" ]; then
apt-get install -yq ${package_sysname}-documentserver

View File

@ -105,7 +105,7 @@ echo "deb [signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/pac
chmod 644 /usr/share/keyrings/openresty.gpg
#Temporary fix for missing openresty repository for debian bookworm
[ "$DISTRIB_CODENAME" = "bookworm" ] && sed -i "s/$DISTRIB_CODENAME/bullseye/g" /etc/apt/sources.list.d/openresty.list
systemctl is-active nginx | grep -q "^active" && systemctl stop nginx
systemctl list-units --type=service | grep -q nginx && systemctl stop nginx && systemctl disable nginx
# setup msttcorefonts
echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections

View File

@ -35,6 +35,7 @@ PACKAGE_SYSNAME="onlyoffice"
PRODUCT_NAME="DocSpace"
PRODUCT=$(tr '[:upper:]' '[:lower:]' <<< ${PRODUCT_NAME})
BASE_DIR="/app/$PACKAGE_SYSNAME";
PROXY_YML="${BASE_DIR}/proxy.yml"
STATUS=""
DOCKER_TAG=""
GIT_BRANCH="master"
@ -100,6 +101,8 @@ DOCUMENT_SERVER_URL_EXTERNAL=""
APP_CORE_BASE_DOMAIN=""
APP_CORE_MACHINEKEY=""
ENV_EXTENSION=""
LETS_ENCRYPT_DOMAIN=""
LETS_ENCRYPT_MAIL=""
HELP_TARGET="install-Docker.sh";
@ -433,6 +436,34 @@ while [ "$1" != "" ]; do
fi
;;
-led | --letsencryptdomain )
if [ "$2" != "" ]; then
LETS_ENCRYPT_DOMAIN=$2
shift
fi
;;
-lem | --letsencryptmail )
if [ "$2" != "" ]; then
LETS_ENCRYPT_MAIL=$2
shift
fi
;;
-cf | --certfile )
if [ "$2" != "" ]; then
CERTIFICATE_PATH=$2
shift
fi
;;
-ckf | --certkeyfile )
if [ "$2" != "" ]; then
CERTIFICATE_KEY_PATH=$2
shift
fi
;;
-? | -h | --help )
echo " Usage: bash $HELP_TARGET [PARAMETER] [[PARAMETER], ...]"
echo
@ -477,6 +508,10 @@ while [ "$1" != "" ]; do
echo " -mysqlp, --mysqlpassword $PRODUCT database password"
echo " -mysqlh, --mysqlhost mysql server host"
echo " -mysqlport, --mysqlport mysql server port number (default value 3306)"
echo " -led, --letsencryptdomain defines the domain for Let's Encrypt certificate"
echo " -lem, --letsencryptmail defines the domain administator mail address for Let's Encrypt certificate"
echo " -cf, --certfile path to the certificate file for the domain"
echo " -ckf, --certkeyfile path to the private key file for the certificate"
echo " -dbm, --databasemigration database migration (true|false)"
echo " -ms, --makeswap make swap file (true|false)"
echo " -?, -h, --help this help"
@ -1145,6 +1180,7 @@ set_docspace_params() {
ENV_EXTENSION=${ENV_EXTENSION:-$(get_container_env_parameter "${CONTAINER_NAME}" "ENV_EXTENSION")};
APP_CORE_BASE_DOMAIN=${APP_CORE_BASE_DOMAIN:-$(get_container_env_parameter "${CONTAINER_NAME}" "APP_CORE_BASE_DOMAIN")};
APP_URL_PORTAL=${APP_URL_PORTAL:-$(get_container_env_parameter "${CONTAINER_NAME}" "APP_URL_PORTAL")};
EXTERNAL_PORT=${EXTERNAL_PORT:-$(get_container_env_parameter "${CONTAINER_NAME}" "EXTERNAL_PORT")};
ELK_SHEME=${ELK_SHEME:-$(get_container_env_parameter "${CONTAINER_NAME}" "ELK_SHEME")};
ELK_HOST=${ELK_HOST:-$(get_container_env_parameter "${CONTAINER_NAME}" "ELK_HOST")};
@ -1161,7 +1197,9 @@ set_docspace_params() {
RABBIT_PASSWORD=${RABBIT_PASSWORD:-$(get_container_env_parameter "${CONTAINER_NAME}" "RABBIT_PASSWORD")};
RABBIT_VIRTUAL_HOST=${RABBIT_VIRTUAL_HOST:-$(get_container_env_parameter "${CONTAINER_NAME}" "RABBIT_VIRTUAL_HOST")};
[ -f ${BASE_DIR}/${PRODUCT}.yml ] && EXTERNAL_PORT=$(grep -oP '(?<=- ).*?(?=:8092)' ${BASE_DIR}/${PRODUCT}.yml)
CERTIFICATE_PATH=${CERTIFICATE_PATH:-$(get_container_env_parameter "${CONTAINER_NAME}" "CERTIFICATE_PATH")};
CERTIFICATE_KEY_PATH=${CERTIFICATE_KEY_PATH:-$(get_container_env_parameter "${CONTAINER_NAME}" "CERTIFICATE_KEY_PATH")};
DHPARAM_PATH=${DHPARAM_PATH:-$(get_container_env_parameter "${CONTAINER_NAME}" "DHPARAM_PATH")};
}
set_installation_type_data () {
@ -1288,19 +1326,27 @@ install_product () {
if [ "${UPDATE}" = "true" ] && [ "${LOCAL_CONTAINER_TAG}" != "${DOCKER_TAG}" ]; then
docker-compose -f $BASE_DIR/build.yml pull
docker-compose -f $BASE_DIR/migration-runner.yml -f $BASE_DIR/notify.yml -f $BASE_DIR/healthchecks.yml down
docker-compose -f $BASE_DIR/migration-runner.yml -f $BASE_DIR/notify.yml -f $BASE_DIR/healthchecks.yml -f ${PROXY_YML} down
docker-compose -f $BASE_DIR/${PRODUCT}.yml down --volumes
fi
reconfigure ENV_EXTENSION ${ENV_EXTENSION}
reconfigure APP_CORE_MACHINEKEY ${APP_CORE_MACHINEKEY}
reconfigure APP_CORE_BASE_DOMAIN ${APP_CORE_BASE_DOMAIN}
reconfigure APP_URL_PORTAL "${APP_URL_PORTAL:-"http://${PACKAGE_SYSNAME}-proxy:8092"}"
reconfigure APP_URL_PORTAL "${APP_URL_PORTAL:-"http://${PACKAGE_SYSNAME}-router:8092"}"
reconfigure EXTERNAL_PORT ${EXTERNAL_PORT}
[[ -n $EXTERNAL_PORT ]] && sed -i "s/8092:8092/${EXTERNAL_PORT}:8092/g" $BASE_DIR/${PRODUCT}.yml
if [ ! -z "${CERTIFICATE_PATH}" ] && [ ! -z "${CERTIFICATE_KEY_PATH}" ]; then
bash $BASE_DIR/config/${PRODUCT}-ssl-setup -f "${CERTIFICATE_PATH}" "${CERTIFICATE_KEY_PATH}"
PROXY_YML="${BASE_DIR}/proxy-ssl.yml"
elif [ ! -z "${LETS_ENCRYPT_DOMAIN}" ] && [ ! -z "${LETS_ENCRYPT_MAIL}" ]; then
bash $BASE_DIR/config/${PRODUCT}-ssl-setup "${LETS_ENCRYPT_MAIL}" "${LETS_ENCRYPT_DOMAIN}"
PROXY_YML="${BASE_DIR}/proxy-ssl.yml"
fi
docker-compose -f $BASE_DIR/migration-runner.yml up -d
docker-compose -f $BASE_DIR/${PRODUCT}.yml up -d
docker-compose -f ${PROXY_YML} up -d
docker-compose -f $BASE_DIR/notify.yml up -d
docker-compose -f $BASE_DIR/healthchecks.yml up -d
}

View File

@ -62,7 +62,7 @@ if [ "${MYSQL_FIRST_TIME_INSTALL}" = "true" ]; then
MYSQL="mysql --connect-expired-password -u$MYSQL_SERVER_USER -D mysql";
else
MYSQL="mysql --connect-expired-password -u$MYSQL_SERVER_USER -p${MYSQL_TEMPORARY_ROOT_PASS} -D mysql";
MYSQL_ROOT_PASS=$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 12);
MYSQL_ROOT_PASS=$(echo $MYSQL_TEMPORARY_ROOT_PASS | sed -e 's/;/%/g' -e 's/=/%/g');
fi
MYSQL_AUTHENTICATION_PLUGIN=$($MYSQL -e "SHOW VARIABLES LIKE 'default_authentication_plugin';" -s | awk '{print $2}')

View File

@ -59,8 +59,13 @@ curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/sc
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | os=centos dist=$REV bash
#add nodejs repo
[ "$REV" = "7" ] && NODE_VERSION="16" || NODE_VERSION="18"
yum install -y https://rpm.nodesource.com/pub_${NODE_VERSION}.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm
if [ "$REV" != "8" ]; then
[ "$REV" = "7" ] && NODE_VERSION="16" || NODE_VERSION="18"
yum install -y https://rpm.nodesource.com/pub_${NODE_VERSION}.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm
else
curl -sL https://rpm.nodesource.com/setup_18.x | bash - || true
rpm --import http://rpm.nodesource.com/pub/el/NODESOURCE-GPG-SIGNING-KEY-EL
fi
#add dotnet repo
if [ $REV = "7" ] || [[ $DIST != "redhat" && $REV = "8" ]]; then
@ -94,7 +99,7 @@ END
rpm --import https://openresty.org/package/pubkey.gpg
OPENRESTY_REPO_FILE=$( [[ "$REV" -ge 9 ]] && echo "openresty2.repo" || echo "openresty.repo" )
curl -o /etc/yum.repos.d/openresty.repo "https://openresty.org/package/centos/${OPENRESTY_REPO_FILE}"
systemctl is-active nginx | grep -q "^active" && systemctl stop nginx
systemctl list-units --type=service | grep -q nginx && systemctl stop nginx && systemctl disable nginx
${package_manager} -y install epel-release \
python3 \

View File

@ -459,8 +459,8 @@ change_mysql_config(){
setup_openresty(){
echo -n "Configuring openresty... "
if systemctl is-active nginx | grep -q "active"; then
systemctl disable nginx && systemctl stop nginx
if systemctl list-units --type=service | grep -q nginx; then
systemctl stop nginx && systemctl disable nginx
fi
cp -rf ${APP_DIR}/nginx/nginx.conf.template /usr/local/openresty/nginx/conf/nginx.conf
@ -468,10 +468,28 @@ setup_openresty(){
# Remove default nginx website
rm -f ${NGINX_DIR}/conf.d/default.conf ${NGINX_DIR}/sites-enabled/default
sed -i "s_\(listen\).*;_\1 $APP_PORT;_" ${NGINX_DIR}/conf.d/${PACKAGE_SYSNAME}.conf
sed 's/\(listen .*:\)\([0-9]\{2,5\}\b\)\( default_server\)\?\(;\)/\1'${APP_PORT}'\3\4/' -i ${NGINX_DIR}/conf.d/${PACKAGE_SYSNAME}-proxy.conf
sed "s!\(^worker_processes\).*;!\1 ${NGINX_WORKER_PROCESSES:-$(grep processor /proc/cpuinfo | wc -l)};!" -i ${NGINX_CONF}
sed "s!\(worker_connections\).*;!\1 ${NGINX_WORKER_CONNECTIONS:-$(ulimit -n)};!" -i ${NGINX_CONF}
# Check for old configuration files
if [ -f "${NGINX_DIR}/conf.d/onlyoffice-proxy.conf.dpkg-old" ]; then
PROXY_CONF="${NGINX_DIR}/conf.d/onlyoffice-proxy.conf.dpkg-old"
elif [ -f "${NGINX_DIR}/conf.d/onlyoffice-proxy.conf.rpmsave" ]; then
PROXY_CONF="${NGINX_DIR}/conf.d/onlyoffice-proxy.conf.rpmsave"
fi
# If the configuration file is found, extract the paths to the certificate and key
if [ ! -z "${PROXY_CONF}" ]; then
CERTIFICATE_PATH=$(grep -oP 'ssl_certificate\s+\K\S+' "${PROXY_CONF}" | tr -d ';')
CERTIFICATE_KEY_PATH=$(grep -oP 'ssl_certificate_key\s+\K\S+' "${PROXY_CONF}" | tr -d ';')
# If both values are found, start SSL configuration
if [ ! -z "${CERTIFICATE_PATH}" ] && [ ! -z "${CERTIFICATE_KEY_PATH}" ]; then
/usr/bin/${PRODUCT}-ssl-setup -f "${CERTIFICATE_PATH}" "${CERTIFICATE_KEY_PATH}"
fi
fi
if [ "$DIST" = "RedHat" ]; then
shopt -s nocasematch
PORTS=()
@ -663,8 +681,14 @@ setup_redis() {
sed -i "s~\(redis_port =\).*~\1 $REDIS_PORT~" "${NGINX_DIR}/conf.d/${PACKAGE_SYSNAME}.conf"
if [ $1 == "LOCAL_REDIS_SERVER" ]; then
sed "s_\(^bind\).*_\1 ${REDIS_HOST}_" -i /etc/redis/redis.conf
sed -r "/^save\s[0-9]+/d" -i /etc/redis/redis.conf
if [ -f "/etc/redis/redis.conf" ]; then
REDIS_CONF="/etc/redis/redis.conf"
elif [ -f "/etc/redis.conf" ]; then
REDIS_CONF="/etc/redis.conf"
fi
sed "s_\(^bind\).*_\1 ${REDIS_HOST}_" -i ${REDIS_CONF}
sed -r "/^save\s[0-9]+/d" -i ${REDIS_CONF}
systemctl enable $REDIS_PACKAGE >/dev/null 2>&1
systemctl restart $REDIS_PACKAGE

View File

@ -0,0 +1,96 @@
#!/bin/bash
set -e
PRODUCT="docspace"
DIR="/usr/bin"
LETSENCRYPT="/etc/letsencrypt/live";
NGINX="/etc/nginx/conf.d"
DHPARAM_FILE="/etc/ssl/certs/dhparam.pem"
if [ "$#" -ge "2" ]; then
if [ "$1" != "-f" ]; then
MAIL=$1
DOMAIN=$2
LETSENCRYPT_ENABLE="true"
# Install certbot if not already installed
if ! type "certbot" &> /dev/null; then
if type "apt-get" &> /dev/null; then
apt-get -y update -qq
apt-get -y -q install certbot
elif type "yum" &> /dev/null; then
yum -y install certbot
fi
fi
echo "Generating Let's Encrypt SSL Certificates..."
# Request and generate Let's Encrypt SSL certificate
echo certbot certonly --expand --webroot --noninteractive --agree-tos --email ${MAIL} -d ${DOMAIN} > /var/log/le-start.log
certbot certonly --expand --webroot --noninteractive --agree-tos --email ${MAIL} -d ${DOMAIN} > /var/log/le-new.log
else
echo "Using specified files to configure SSL..."
CERTIFICATE_FILE=$2
PRIVATEKEY_FILE=$3
fi
[[ ! -f "${DHPARAM_FILE}" ]] && openssl dhparam -out ${DHPARAM_FILE} 4096
CERTIFICATE_FILE="${CERTIFICATE_FILE:-"${LETSENCRYPT}/${DOMAIN}/fullchain.pem"}"
PRIVATEKEY_FILE="${PRIVATEKEY_FILE:-"${LETSENCRYPT}/${DOMAIN}/privkey.pem"}"
if [ -f "${CERTIFICATE_FILE}" -a -f ${PRIVATEKEY_FILE} ]; then
if [ -f "${NGINX}/onlyoffice-proxy-ssl.conf.template" ]; then
cp -f ${NGINX}/onlyoffice-proxy-ssl.conf.template ${NGINX}/onlyoffice-proxy.conf
ENVIRONMENT=$(grep -oP 'ENVIRONMENT=\K.*' /usr/lib/systemd/system/${PRODUCT}-api.service)
sed -i "s/\(\"portal\":\).*/\1 \"https:\/\/${DOMAIN:-$(hostname --fqdn)}\"/" /etc/onlyoffice/docspace/appsettings.$ENVIRONMENT.json
sed -i "s~\(ssl_certificate \).*;~\1${CERTIFICATE_FILE};~g" ${NGINX}/onlyoffice-proxy.conf
sed -i "s~\(ssl_certificate_key \).*;~\1${PRIVATEKEY_FILE};~g" ${NGINX}/onlyoffice-proxy.conf
sed -i "s~\(ssl_dhparam \).*;~\1${DHPARAM_FILE};~g" ${NGINX}/onlyoffice-proxy.conf
if [[ "${LETSENCRYPT_ENABLE}" = "true" ]]; then
# Create and set permissions for ${PRODUCT}-renew-letsencrypt
echo '#!/bin/bash' > ${DIR}/${PRODUCT}-renew-letsencrypt
echo "certbot renew >> /var/log/le-renew.log" >> ${DIR}/${PRODUCT}-renew-letsencrypt
if [ $(pgrep -x ""systemd"" | wc -l) -gt 0 ]; then
echo 'systemctl reload openresty' >> ${DIR}/${PRODUCT}-renew-letsencrypt
else
echo 'service openresty reload' >> ${DIR}/${PRODUCT}-renew-letsencrypt
fi
chmod a+x ${DIR}/${PRODUCT}-renew-letsencrypt
# Add cron job if /etc/cron.d directory exists
if [ -d /etc/cron.d ]; then
echo -e "@weekly root ${DIR}/${PRODUCT}-renew-letsencrypt" | tee /etc/cron.d/${PRODUCT}-letsencrypt
fi
fi
[ $(pgrep -x ""systemd"" | wc -l) -gt 0 ] && systemctl reload openresty || service openresty reload
echo "OK"
else
echo "Error: proxy configuration file not found." && exit 1
fi
else
echo "Error: certificate or private key file not found." && exit 1
fi
else
echo ""
echo "This script provided to automatically setup SSL Certificates for DocSpace"
echo "Automatically get Let's Encrypt SSL Certificates:"
echo " docspace-ssl-setup EMAIL DOMAIN"
echo " EMAIL Email used for registration and recovery contact."
echo " Use comma to register multiple emails, ex:"
echo " u1@example.com,u2@example.com."
echo " DOMAIN Domain name to apply"
echo ""
echo "Using your own certificates via the -f parameter:"
echo " docspace-ssl-setup -f CERTIFICATE PRIVATEKEY"
echo " CERTIFICATE Path to the certificate file for the domain."
echo " PRIVATEKEY Path to the private key file for the certificate."
echo ""
fi

View File

@ -1,5 +1,7 @@
## COPY PUBLIC ##
../../../build/install/common/{{product}}-ssl-setup usr/bin
../../../build/install/docker/config/nginx/templates/*.template etc/onlyoffice/{{product}}/nginx
../../../build/install/docker/config/nginx/onlyoffice* etc/nginx/conf.d
../../../config/nginx/onlyoffice*.conf etc/nginx/conf.d
../../../config/nginx/includes/onlyoffice*.conf etc/nginx/includes
../../../build/deploy/public/* var/www/{{product}}/public

View File

@ -50,7 +50,9 @@ override_dh_auto_build:
sed 's_\(minlevel=\)".*"_\1"Warn"_g' -i ${SRC_PATH}/config/nlog.config
sed 's/teamlab.info/onlyoffice.com/g' -i ${SRC_PATH}/config/autofac.consumers.json
sed -e '/.pid/d' -e '/MAP_HASH_BUCKET_SIZE/d' -e '/temp_path/d' -i ${SRC_PATH}/build/install/docker/config/nginx/templates/nginx.conf.template
sed -e 's/$$router_host/127.0.0.1/g' -e '/proxy_set_header/d' -i ${SRC_PATH}/build/install/docker/config/nginx/onlyoffice-proxy*.conf
sed -e '/.pid/d' -e '/temp_path/d' -i ${SRC_PATH}/build/install/docker/config/nginx/templates/nginx.conf.template
mv -f ${SRC_PATH}/build/install/docker/config/nginx/onlyoffice-proxy-ssl.conf ${SRC_PATH}/build/install/docker/config/nginx/onlyoffice-proxy-ssl.conf.template
for i in ${PRODUCT} $$(ls ${CURRENT_PATH}/debian/*.install | grep -oP 'debian/\K.*' | grep -o '^[^.]*'); do \
cp ${CURRENT_PATH}/debian/source/lintian-overrides ${CURRENT_PATH}/debian/$$i.lintian-overrides; \

View File

@ -13,6 +13,7 @@
DOCUMENT_SERVER_IMAGE_NAME=onlyoffice/4testing-documentserver-ee:latest
DOCKERFILE=Dockerfile.app
APP_DOTNET_ENV=""
EXTERNAL_PORT="80"
# zookeeper #
ZOO_PORT=2181
@ -47,6 +48,10 @@
APP_KNOWN_NETWORKS=""
APP_CORE_MACHINEKEY=your_core_machinekey
CERTIFICATE_PATH=""
CERTIFICATE_KEY_PATH=""
DHPARAM_PATH=""
# docs #
DOCUMENT_CONTAINER_NAME=${CONTAINER_PREFIX}document-server
DOCUMENT_SERVER_URL_EXTERNAL=""
@ -96,11 +101,12 @@
SSOAUTH_HOST=${CONTAINER_PREFIX}ssoauth
MIGRATION_RUNNER_HOST=${CONTAINER_PREFIX}migration-runner
PROXY_HOST=${CONTAINER_PREFIX}proxy
ROUTER_HOST=${CONTAINER_PREFIX}router
DOCEDITOR_HOST=${CONTAINER_PREFIX}doceditor
LOGIN_HOST=${CONTAINER_PREFIX}login
HELTHCHECKS_HOST=${CONTAINER_PREFIX}healthchecks
# proxy upstream environment #
# router upstream environment #
SERVICE_API_SYSTEM=${API_SYSTEM_HOST}:${SERVICE_PORT}
SERVICE_BACKUP=${BACKUP_HOST}:${SERVICE_PORT}
SERVICE_BACKUP_BACKGRUOND_TASKS=${BACKUP_BACKGRUOND_TASKS_HOST}:${SERVICE_PORT}

View File

@ -140,7 +140,7 @@ EXPOSE 5050
ENTRYPOINT ["python3", "docker-entrypoint.py"]
## Nginx image ##
FROM nginx AS proxy
FROM nginx AS router
ARG SRC_PATH
ARG BUILD_PATH
ARG COUNT_WORKER_CONNECTIONS=1024
@ -160,7 +160,7 @@ COPY --from=base ${SRC_PATH}/build/deploy/client ${BUILD_PATH}/client
COPY --from=base ${SRC_PATH}/build/deploy/public ${BUILD_PATH}/public
COPY --from=base ${SRC_PATH}/build/install/docker/config/nginx/templates/upstream.conf.template /etc/nginx/templates/upstream.conf.template
COPY --from=base ${SRC_PATH}/build/install/docker/config/nginx/templates/nginx.conf.template /etc/nginx/nginx.conf.template
COPY --from=base ${SRC_PATH}/build/install/docker/prepare-nginx-proxy.sh /docker-entrypoint.d/prepare-nginx-proxy.sh
COPY --from=base ${SRC_PATH}/build/install/docker/prepare-nginx-router.sh /docker-entrypoint.d/prepare-nginx-router.sh
# add defualt user and group for no-root run
RUN chown nginx:nginx /etc/nginx/* -R && \
@ -179,7 +179,9 @@ RUN chown nginx:nginx /etc/nginx/* -R && \
if [[ -z "${SERVICE_CLIENT}" ]] ; then sed -i 's/127.0.0.1:5001/$service_client/' /etc/nginx/conf.d/onlyoffice.conf; fi && \
sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf
sed -i 's/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i '/client_body_temp_path/ i \ \ \ \ $MAP_HASH_BUCKET_SIZE' /etc/nginx/nginx.conf.template && \
sed -i 's/\(worker_connections\).*;/\1 $COUNT_WORKER_CONNECTIONS;/' /etc/nginx/nginx.conf.template
## Doceditor ##
FROM noderun as doceditor

View File

@ -126,7 +126,7 @@ EXPOSE 5050
ENTRYPOINT ["python3", "docker-entrypoint.py"]
## Nginx image ##
FROM openresty/openresty:focal AS proxy
FROM openresty/openresty:focal AS router
ARG SRC_PATH
ARG BUILD_PATH
ARG COUNT_WORKER_CONNECTIONS=1024
@ -150,7 +150,7 @@ COPY /config/nginx/docker-entrypoint.sh /docker-entrypoint.sh
COPY /config/nginx/docker-entrypoint.d /docker-entrypoint.d
COPY /config/nginx/templates/upstream.conf.template /etc/nginx/templates/upstream.conf.template
COPY /config/nginx/templates/nginx.conf.template /etc/nginx/nginx.conf.template
COPY prepare-nginx-proxy.sh /docker-entrypoint.d/prepare-nginx-proxy.sh
COPY prepare-nginx-router.sh /docker-entrypoint.d/prepare-nginx-router.sh
# changes for upstream configure
RUN sed -i 's/127.0.0.1:5010/$service_api_system/' /etc/nginx/conf.d/onlyoffice.conf && \
@ -165,7 +165,9 @@ RUN sed -i 's/127.0.0.1:5010/$service_api_system/' /etc/nginx/conf.d/onlyoffice.
sed -i 's/127.0.0.1:5011/$service_login/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/http:\/\/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf
sed -i 's/http:\/\/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i '/client_body_temp_path/ i \ \ \ \ $MAP_HASH_BUCKET_SIZE' /etc/nginx/nginx.conf.template && \
sed -i 's/\(worker_connections\).*;/\1 $COUNT_WORKER_CONNECTIONS;/' /etc/nginx/nginx.conf.template
ENTRYPOINT [ "/docker-entrypoint.sh" ]

View File

@ -75,7 +75,7 @@ COPY --from=base --chown=onlyoffice:onlyoffice /app/onlyoffice/config/* /app/onl
EXPOSE 5050
ENTRYPOINT ["python3", "docker-entrypoint.py"]
FROM openresty/openresty:focal AS proxy
FROM openresty/openresty:focal AS router
ARG SRC_PATH
ARG BUILD_PATH
ARG COUNT_WORKER_CONNECTIONS=1024
@ -98,7 +98,7 @@ COPY /build/install/docker/config/nginx/docker-entrypoint.d /docker-entrypoint.d
COPY /build/install/docker/config/nginx/templates/upstream.conf.template /etc/nginx/templates/upstream.conf.template
COPY /build/install/docker/config/nginx/templates/nginx.conf.template /etc/nginx/nginx.conf.template
COPY /build/install/docker/prepare-nginx-proxy.sh /docker-entrypoint.d/prepare-nginx-proxy.sh
COPY /build/install/docker/prepare-nginx-router.sh /docker-entrypoint.d/prepare-nginx-router.sh
RUN dos2unix /docker-entrypoint.d/* && \
dos2unix /docker-entrypoint.sh && \
@ -124,7 +124,9 @@ RUN chown onlyoffice:onlyoffice /etc/nginx/* -R && \
sed -i 's/127.0.0.1:5033/$service_healthchecks/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/$public_root/\/var\/www\/public\//' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/http:\/\/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i 's/local redis_host = "127.0.0.1"/local redis_host = "onlyoffice-redis"/' /etc/nginx/conf.d/onlyoffice.conf
sed -i 's/local redis_host = "127.0.0.1"/local redis_host = "onlyoffice-redis"/' /etc/nginx/conf.d/onlyoffice.conf && \
sed -i '/client_body_temp_path/ i \ \ \ \ $MAP_HASH_BUCKET_SIZE' /etc/nginx/nginx.conf.template && \
sed -i 's/\(worker_connections\).*;/\1 $COUNT_WORKER_CONNECTIONS;/' /etc/nginx/nginx.conf.template
ENTRYPOINT [ "/docker-entrypoint.sh" ]

View File

@ -120,12 +120,12 @@ services:
target: login
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-login:${DOCKER_TAG}"
onlyoffice-proxy:
onlyoffice-router:
build:
context: ./
dockerfile: "${DOCKERFILE}"
target: proxy
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-proxy:${DOCKER_TAG}"
target: router
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-router:${DOCKER_TAG}"
onlyoffice-migration-runner:
build:

View File

@ -0,0 +1,95 @@
#!/bin/bash
set -e
PRODUCT="docspace"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DOCKERCOMPOSE=$(dirname "$DIR")
LETSENCRYPT="/etc/letsencrypt/live";
DHPARAM_FILE="/etc/ssl/certs/dhparam.pem"
if [ "$#" -ge "2" ]; then
if [ "$1" != "-f" ]; then
MAIL=$1
DOMAIN=$2
LETSENCRYPT_ENABLE="true"
if [ -f "${DOCKERCOMPOSE}/proxy.yml" ]; then
docker-compose -f ${DOCKERCOMPOSE}/proxy.yml down
elif [ -f "/app/onlyoffice/proxy.yml" ]; then
DOCKERCOMPOSE="/app/onlyoffice"
DIR="/app/onlyoffice/config"
else
echo "Error: proxy configuration file not found." && exit 1
fi
echo "Generating Let's Encrypt SSL Certificates..."
# Request and generate Let's Encrypt SSL certificate
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot/certbot certonly \
--webroot --non-interactive --agree-tos --email ${MAIL} -d ${DOMAIN}
else
echo "Using specified files to configure SSL..."
CERTIFICATE_FILE=$2
PRIVATEKEY_FILE=$3
fi
[[ ! -f "${DHPARAM_FILE}" ]] && openssl dhparam -out ${DHPARAM_FILE} 4096
CERTIFICATE_FILE="${CERTIFICATE_FILE:-"${LETSENCRYPT}/${DOMAIN}/fullchain.pem"}"
PRIVATEKEY_FILE="${PRIVATEKEY_FILE:-"${LETSENCRYPT}/${DOMAIN}/privkey.pem"}"
if [ -f "${CERTIFICATE_FILE}" -a -f ${PRIVATEKEY_FILE} ]; then
if [ -f ${DOCKERCOMPOSE}/.env -a -f ${DOCKERCOMPOSE}/proxy-ssl.yml ]; then
sed -i "s~\(APP_URL_PORTAL=\).*~\1\"https://${DOMAIN:-$(hostname --fqdn)}\"~g" ${DOCKERCOMPOSE}/.env
sed -i "s~\(CERTIFICATE_PATH=\).*~\1\"${CERTIFICATE_FILE}\"~g" ${DOCKERCOMPOSE}/.env
sed -i "s~\(CERTIFICATE_KEY_PATH=\).*~\1\"${PRIVATEKEY_FILE}\"~g" ${DOCKERCOMPOSE}/.env
sed -i "s~\(DHPARAM_PATH=\).*~\1\"${DHPARAM_FILE}\"~g" ${DOCKERCOMPOSE}/.env
if [[ "${LETSENCRYPT_ENABLE}" = "true" ]]; then
# Create and set permissions for docspace-renew-letsencrypt
echo '#!/bin/bash' > ${DIR}/${PRODUCT}-renew-letsencrypt
echo "docker-compose -f ${DOCKERCOMPOSE}/proxy-ssl.yml down" >> ${DIR}/${PRODUCT}-renew-letsencrypt
echo 'docker run -it --rm \' >> ${DIR}/${PRODUCT}-renew-letsencrypt
echo ' -v /etc/letsencrypt:/etc/letsencrypt \' >> ${DIR}/${PRODUCT}-renew-letsencrypt
echo ' -v /var/lib/letsencrypt:/var/lib/letsencrypt \' >> ${DIR}/${PRODUCT}-renew-letsencrypt
echo ' certbot/certbot renew' >> ${DIR}/${PRODUCT}-renew-letsencrypt
echo "docker-compose -f ${DOCKERCOMPOSE}/proxy-ssl.yml up -d" >> ${DIR}/${PRODUCT}-renew-letsencrypt
chmod a+x ${DIR}/${PRODUCT}-renew-letsencrypt
# Add cron job if /etc/cron.d directory exists
if [ -d /etc/cron.d ]; then
echo -e "@weekly root ${DIR}/${PRODUCT}-renew-letsencrypt" | tee /etc/cron.d/${PRODUCT}-letsencrypt
fi
fi
docker-compose -f ${DOCKERCOMPOSE}/proxy-ssl.yml up -d
echo "OK"
else
echo "Error: proxy configuration file not found." && exit 1
fi
else
echo "Error: certificate or private key file not found." && exit 1
fi
else
echo ""
echo "This script provided to automatically setup SSL Certificates for DocSpace"
echo "Automatically get Let's Encrypt SSL Certificates:"
echo " docspace-ssl-setup EMAIL DOMAIN"
echo " EMAIL Email used for registration and recovery contact."
echo " Use comma to register multiple emails, ex:"
echo " u1@example.com,u2@example.com."
echo " DOMAIN Domain name to apply"
echo ""
echo "Using your own certificates via the -f parameter:"
echo " docspace-ssl-setup -f CERTIFICATE PRIVATEKEY"
echo " CERTIFICATE Path to the certificate file for the domain."
echo " PRIVATEKEY Path to the private key file for the certificate."
echo ""
fi

View File

@ -0,0 +1,61 @@
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header Host $the_host;
proxy_set_header X-Forwarded-Host $the_host;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
## HTTP host
server {
listen 0.0.0.0:80;
listen [::]:80 default_server;
server_name _;
## Redirects all traffic to the HTTPS host
root /nowhere; ## root doesn't have to be a valid path since we are redirecting
rewrite ^ https://$host$request_uri? permanent;
}
## HTTPS host
server {
listen 0.0.0.0:443 ssl;
listen [::]:443 ssl default_server;
root /usr/share/nginx/html;
## Strong SSL Security
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_certificate /usr/local/share/ca-certificates/tls.crt;
ssl_certificate_key /etc/ssl/private/tls.key;
# Uncomment string below and specify the path to the file with the password if you use encrypted certificate key
# ssl_password_file $ssl_password_path;
ssl_verify_client off;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_protocols TLSv1.2;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security max-age=31536000;
# add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL.
## Replace with your ssl_trusted_certificate. For more info see:
## - https://medium.com/devops-programming/4445f4862461
## - https://www.ruby-forum.com/topic/4419319
## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
# ssl_stapling on;
# ssl_stapling_verify on;
# ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
# resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
# resolver_timeout 10s;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
location / {
proxy_pass http://$router_host:8092;
}
}

View File

@ -0,0 +1,15 @@
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header Host $the_host;
proxy_set_header X-Forwarded-Host $the_host;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
server {
listen 0.0.0.0:80;
listen [::]:80 default_server;
location / {
proxy_pass http://$router_host:8092;
}
}

View File

@ -6,12 +6,11 @@ pid /tmp/nginx.pid;
events {
worker_connections $COUNT_WORKER_CONNECTIONS;
worker_connections 1024;
}
http {
$MAP_HASH_BUCKET_SIZE
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;

View File

@ -0,0 +1,32 @@
resolver 127.0.0.11 valid=30s;
map $http_host $this_host {
"" $host;
default $http_host;
}
map $http_x_forwarded_proto $the_scheme {
default $http_x_forwarded_proto;
"" $scheme;
}
map $http_x_forwarded_host $the_host {
default $http_x_forwarded_host;
"" $host;
}
map $http_x_forwarded_port $proxy_x_forwarded_port {
default $http_x_forwarded_port;
'' $server_port;
}
map $http_upgrade $proxy_connection {
default upgrade;
"" close;
}
map $ROUTER_HOST $router_host {
volatile;
default onlyoffice-router;
~^(.*)$ $1;
}

View File

@ -0,0 +1,19 @@
version: "3.8"
services:
onlyoffice-dns:
image: jpillora/dnsmasq
container_name: onlyoffice-dns
restart: always
expose:
- "5380"
- "53"
ports:
- 53:53/udp
- 5380:8080
environment:
- HTTP_USER=foo
- HTTP_PASS=bar
volumes:
- ${ROOT_DIR}/config/dnsmasq.conf:/etc/dnsmasq.conf
cap_add:
- NET_ADMIN

View File

@ -11,12 +11,12 @@ jsonValue = None
PRODUCT = os.environ["PRODUCT"] if environ.get("PRODUCT") else "onlyoffice"
BASE_DIR = os.environ["BASE_DIR"] if environ.get("BASE_DIR") else "/app/" + PRODUCT
ENV_EXTENSION = os.environ["ENV_EXTENSION"] if environ.get("ENV_EXTENSION") else "none"
PROXY_HOST = os.environ["PROXY_HOST"] if environ.get("PROXY_HOST") else "proxy"
PROXY_HOST = os.environ["PROXY_HOST"] if environ.get("PROXY_HOST") else "onlyoffice-proxy"
SERVICE_PORT = os.environ["SERVICE_PORT"] if environ.get("SERVICE_PORT") else "5050"
URLS = os.environ["URLS"] if environ.get("URLS") else "http://0.0.0.0:"
PATH_TO_CONF = os.environ["PATH_TO_CONF"] if environ.get("PATH_TO_CONF") else "/app/" + PRODUCT + "/config"
LOG_DIR = os.environ["LOG_DIR"] if environ.get("LOG_DIR") else "/var/log/" + PRODUCT
ROUTER_HOST = os.environ["ROUTER_HOST"] if environ.get("ROUTER_HOST") else "localhost"
ROUTER_HOST = os.environ["ROUTER_HOST"] if environ.get("ROUTER_HOST") else "onlyoffice-router"
SOCKET_HOST = os.environ["SOCKET_HOST"] if environ.get("SOCKET_HOST") else "onlyoffice-socket"
MYSQL_CONTAINER_NAME = os.environ["MYSQL_CONTAINER_NAME"] if environ.get("MYSQL_CONTAINER_NAME") else "onlyoffice-mysql-server"

View File

@ -26,7 +26,7 @@ echo "Executing -- ${NAME_SERVICE}"
PRODUCT=${PRODUCT:-"onlyoffice"}
ENV_EXTENSION=${ENV_EXTENSION:-"test"}
PROXY_HOST=${PROXY_HOST:-"proxy"}
ROUTER_HOST=${ROUTER_HOST:-"onlyoffice-router"}
SHEME=${SHEME:-"http"}
SERVICE_PORT=${SERVICE_PORT:-"5050"}
@ -41,7 +41,7 @@ MYSQL_USER=${MYSQL_USER:-"${PRODUCT}_user"}
MYSQL_PASSWORD=${MYSQL_PASSWORD:-"${PRODUCT}_pass"}
APP_CORE_BASE_DOMAIN=${APP_CORE_BASE_DOMAIN:-"localhost"}
APP_URL_PORTAL=${APP_URL_PORTAL:-"${SHEME}://${PROXY_HOST}:8092"}
APP_URL_PORTAL=${APP_URL_PORTAL:-"${SHEME}://${ROUTER_HOST}:8092"}
APP_CORE_MACHINEKEY=${APP_CORE_MACHINEKEY:-"your_core_machinekey"}
DOCUMENT_SERVER_JWT_SECRET=${DOCUMENT_SERVER_JWT_SECRET:-"your_jwt_secret"}

View File

@ -165,7 +165,7 @@ services:
volumes:
- ${SRC_PATH}/ASC.Migration.Runner/service:${BUILD_PATH}/services/ASC.Migration.Runner/
onlyoffice-proxy:
onlyoffice-router:
<<: *x-profiles-local
image: ${Baseimage_Proxy_Run}
environment:

View File

@ -56,7 +56,7 @@ x-service: &x-service-base
RABBIT_VIRTUAL_HOST: ${RABBIT_VIRTUAL_HOST}
RABBIT_USER_NAME: ${RABBIT_USER_NAME}
RABBIT_PASSWORD: ${RABBIT_PASSWORD}
PROXY_HOST: ${PROXY_HOST}
ROUTER_HOST: ${ROUTER_HOST}
volumes:
- ${ROOT_DIR}/Data:/app/onlyoffice/data
- files_data:/var/www/products/ASC.Files/server/
@ -239,10 +239,10 @@ services:
expose:
- "5011"
onlyoffice-proxy:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-proxy:${DOCKER_TAG}"
onlyoffice-router:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-router:${DOCKER_TAG}"
profiles: ["prod", "backend", frontend]
container_name: ${PROXY_HOST}
container_name: ${ROUTER_HOST}
restart: always
healthcheck:
<<: *x-healthcheck
@ -252,7 +252,7 @@ services:
- "8099"
- "8092"
ports:
- 8092:8092
- 80:8092
environment:
- SERVICE_BACKUP=${SERVICE_BACKUP}
- SERVICE_FILES=${SERVICE_FILES}
@ -276,7 +276,7 @@ services:
- REDIS_PORT=${REDIS_PORT}
- SERVICE_PORT=${SERVICE_PORT}
volumes:
- proxy_log:/var/log/nginx
- router_log:/var/log/nginx
onlyoffice-migration-runner:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-migration-runner:${DOCKER_TAG}"
@ -297,7 +297,7 @@ networks:
volumes:
es_data:
proxy_log:
router_log:
app_data:
files_data:
people_data:

View File

@ -49,7 +49,7 @@ x-service: &x-service-base
RABBIT_VIRTUAL_HOST: ${RABBIT_VIRTUAL_HOST}
RABBIT_USER_NAME: ${RABBIT_USER_NAME}
RABBIT_PASSWORD: ${RABBIT_PASSWORD}
PROXY_HOST: ${PROXY_HOST}
ROUTER_HOST: ${ROUTER_HOST}
LOG_LEVEL: ${LOG_LEVEL}
DEBUG_INFO: ${DEBUG_INFO}
volumes:
@ -174,9 +174,9 @@ services:
<<: *x-healthcheck
test: curl --fail http://${SERVICE_LOGIN}/health || exit 1
onlyoffice-proxy:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-proxy:${DOCKER_TAG}"
container_name: ${PROXY_HOST}
onlyoffice-router:
image: "${REPO}/${DOCKER_IMAGE_PREFIX}-router:${DOCKER_TAG}"
container_name: ${ROUTER_HOST}
restart: always
healthcheck:
<<: *x-healthcheck
@ -185,8 +185,6 @@ services:
- "8081"
- "8099"
- "8092"
ports:
- 8092:8092
depends_on:
- onlyoffice-backup-background-tasks
- onlyoffice-backup
@ -225,7 +223,7 @@ services:
- REDIS_PORT=${REDIS_PORT}
- SERVICE_PORT=${SERVICE_PORT}
volumes:
- proxy_log:/var/log/nginx
- router_log:/var/log/nginx
networks:
default:
@ -233,7 +231,7 @@ networks:
external: true
volumes:
proxy_log:
router_log:
app_data:
files_data:
people_data:

View File

@ -50,7 +50,7 @@ x-service:
RABBIT_VIRTUAL_HOST: ${RABBIT_VIRTUAL_HOST}
RABBIT_USER_NAME: ${RABBIT_USER_NAME}
RABBIT_PASSWORD: ${RABBIT_PASSWORD}
PROXY_HOST: ${PROXY_HOST}
ROUTER_HOST: ${ROUTER_HOST}
LOG_LEVEL: ${LOG_LEVEL}
DEBUG_INFO: ${DEBUG_INFO}
volumes:

View File

@ -0,0 +1,38 @@
version: "3.8"
x-healthcheck:
&x-healthcheck
test: curl --fail http://127.0.0.1 || exit 1
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
services:
onlyoffice-proxy:
image: nginx
container_name: ${PROXY_HOST}
restart: always
healthcheck:
<<: *x-healthcheck
test: nginx -t || exit 1
ports:
- 80:80
- 443:443
environment:
- ROUTER_HOST=${ROUTER_HOST}
volumes:
- proxy_log:/var/log/nginx
- ./config/nginx/templates/nginx.conf.template:/etc/nginx/nginx.conf
- ./config/nginx/templates/proxy.upstream.conf.template:/etc/nginx/templates/proxy.upstream.conf.template:ro
- ./config/nginx/onlyoffice-proxy-ssl.conf:/etc/nginx/conf.d/default.conf
- ${CERTIFICATE_PATH}:/usr/local/share/ca-certificates/tls.crt
- ${CERTIFICATE_KEY_PATH}:/etc/ssl/private/tls.key
- ${DHPARAM_PATH}:/etc/ssl/certs/dhparam.pem
networks:
default:
name: ${NETWORK_NAME}
external: true
volumes:
proxy_log:

View File

@ -0,0 +1,34 @@
version: "3.8"
x-healthcheck:
&x-healthcheck
test: curl --fail http://127.0.0.1 || exit 1
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
services:
onlyoffice-proxy:
image: nginx
container_name: ${PROXY_HOST}
restart: always
healthcheck:
<<: *x-healthcheck
test: nginx -t || exit 1
ports:
- ${EXTERNAL_PORT}:80
environment:
- ROUTER_HOST=${ROUTER_HOST}
volumes:
- proxy_log:/var/log/nginx
- ./config/nginx/templates/nginx.conf.template:/etc/nginx/nginx.conf
- ./config/nginx/templates/proxy.upstream.conf.template:/etc/nginx/templates/proxy.upstream.conf.template:ro
- ./config/nginx/onlyoffice-proxy.conf:/etc/nginx/conf.d/default.conf
networks:
default:
name: ${NETWORK_NAME}
external: true
volumes:
proxy_log:

View File

@ -21,7 +21,8 @@ json -I -f %{_builddir}/%{sourcename}/config/apisystem.json -e "this.core.notify
sed 's_\(minlevel=\)".*"_\1"Warn"_g' -i %{_builddir}/%{sourcename}/config/nlog.config
sed 's/teamlab.info/onlyoffice.com/g' -i %{_builddir}/%{sourcename}/config/autofac.consumers.json
sed -e '/.pid/d' -e '/MAP_HASH_BUCKET_SIZE/d' -e '/temp_path/d' -i %{_builddir}/%{sourcename}/build/install/docker/config/nginx/templates/nginx.conf.template
sed -e 's/$router_host/127.0.0.1/g' -e '/proxy_set_header/d' -i %{_builddir}/%{sourcename}/build/install/docker/config/nginx/onlyoffice-proxy*.conf
sed -e '/.pid/d' -e '/temp_path/d' -i %{_builddir}/%{sourcename}/build/install/docker/config/nginx/templates/nginx.conf.template
find %{_builddir}/%{sourcename}/publish/ \
%{_builddir}/%{sourcename}/ASC.Migration.Runner \

View File

@ -1,5 +1,5 @@
%files
%attr(744, root, root) %{_bindir}/*
%attr(744, root, root) %{_bindir}/%{product}-configuration
%files api
%defattr(-, onlyoffice, onlyoffice, -)
@ -75,6 +75,7 @@
%defattr(-, onlyoffice, onlyoffice, -)
%config %{_sysconfdir}/nginx/includes/*
%config %{_sysconfdir}/nginx/conf.d/*
%attr(744, root, root) %{_bindir}/%{product}-ssl-setup
%config %{_sysconfdir}/onlyoffice/%{product}/nginx/nginx.conf.template
%dir %{_sysconfdir}/onlyoffice/
%dir %{_sysconfdir}/onlyoffice/%{product}/

View File

@ -39,7 +39,7 @@ cp -rf %{_builddir}/%{sourcename}/build/deploy/public/* "%{buildroot}%{buildpath
cp -rf %{_builddir}/%{sourcename}/build/deploy/client/* "%{buildroot}%{buildpath}/client/"
cp -rf %{_builddir}/%{sourcename}/build/deploy/login/* "%{buildroot}%{buildpath}/products/ASC.Login/login/"
cp -rf %{_builddir}/%{sourcename}/build/install/RadicalePlugins/* "%{buildroot}%{buildpath}/Tools/radicale/plugins/"
cp -rf %{_builddir}/%{sourcename}/build/install/common/%{product}-configuration "%{buildroot}%{_bindir}/"
cp -rf %{_builddir}/%{sourcename}/build/install/common/%{product}-configuration "%{buildroot}%{_bindir}/%{product}-configuration"
cp -rf %{_builddir}/%{sourcename}/build/install/common/systemd/modules/* "%{buildroot}/usr/lib/systemd/system/"
cp -rf %{_builddir}/%{sourcename}/build/install/common/logrotate/product-common "%{buildroot}%{_sysconfdir}/logrotate.d/%{product}-common"
cp -rf %{_builddir}/%{sourcename}/config/* "%{buildroot}%{_sysconfdir}/onlyoffice/%{product}/"
@ -60,4 +60,7 @@ cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Studio.Notify/service/* "
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Web.Api/service/* "%{buildroot}%{buildpath}/studio/ASC.Web.Api/"
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Web.HealthChecks.UI/service/* "%{buildroot}%{buildpath}/services/ASC.Web.HealthChecks.UI/"
cp -rf %{_builddir}/%{sourcename}/publish/services/ASC.Web.Studio/service/* "%{buildroot}%{buildpath}/studio/ASC.Web.Studio/"
cp -rf %{_builddir}/%{sourcename}/build/install/docker/config/nginx/onlyoffice-proxy.conf "%{buildroot}%{_sysconfdir}/nginx/conf.d/onlyoffice-proxy.conf"
cp -rf %{_builddir}/%{sourcename}/build/install/docker/config/nginx/onlyoffice-proxy-ssl.conf "%{buildroot}%{_sysconfdir}/nginx/conf.d/onlyoffice-proxy-ssl.conf.template"
cp -rf %{_builddir}/%{sourcename}/build/install/docker/config/nginx/templates/nginx.conf.template "%{buildroot}%{_sysconfdir}/onlyoffice/%{product}/nginx/nginx.conf.template"
cp -rf %{_builddir}/%{sourcename}/build/install/common/%{product}-ssl-setup "%{buildroot}%{_bindir}/%{product}-ssl-setup"

View File

@ -0,0 +1,40 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Core.Common.Security;
public class CspSettings : ISettings<CspSettings>
{
[JsonIgnore]
public Guid ID => new Guid("27504162-16FF-405F-8530-1537B0F2B89D");
public IEnumerable<string> Domains { get; set; }
public bool SetDefaultIfEmpty { get; set; }
public CspSettings GetDefault()
{
return new CspSettings();
}
}

View File

@ -1276,7 +1276,7 @@ public class S3Storage : BaseStorage
var metadataResponse = await client.GetObjectMetadataAsync(metadataRequest);
var objectSize = metadataResponse.ContentLength;
if (objectSize >= 100 * 1024 * 1024L) //100 megabytes
if (objectSize >= 1000 * 1024 * 1024L) //1000 megabytes
{
var copyResponses = new List<CopyPartResponse>();
@ -1304,7 +1304,7 @@ public class S3Storage : BaseStorage
var uploadId = initResponse.UploadId;
var partSize = GetChunkSize();
var partSize = 500 * 1024 * 1024L;//500 megabytes
var uploadTasks = new List<Task<CopyPartResponse>>();
@ -1547,18 +1547,6 @@ public class S3Storage : BaseStorage
return el.ETag;
}
private long GetChunkSize()
{
var configSetting = _configuration["files:uploader:chunk-size"];
if (!string.IsNullOrEmpty(configSetting))
{
configSetting = configSetting.Trim();
return long.Parse(configSetting);
}
long defaultValue = 10 * 1024 * 1024;
return defaultValue;
}
private enum EncryptionMethod
{
None,

View File

@ -50,7 +50,8 @@ public class ProviderManager
ProviderConstants.Yandex,
ProviderConstants.GosUslugi,
ProviderConstants.AppleId,
ProviderConstants.Microsoft
ProviderConstants.Microsoft,
ProviderConstants.Zoom
};
public static List<string> InviteExceptProviders = new List<string>

View File

@ -0,0 +1,263 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using AutoMapper;
using static System.Formats.Asn1.AsnWriter;
namespace ASC.FederatedLogin.LoginProviders;
[Scope]
public class ZoomLoginProvider : BaseLoginProvider<ZoomLoginProvider>
{
public override string AccessTokenUrl => "https://zoom.us/oauth/token";
public override string RedirectUri => this["zoomRedirectUrl"];
public override string ClientID => this["zoomClientId"];
public override string ClientSecret => this["zoomClientSecret"];
public override string CodeUrl => "https://zoom.us/oauth/authorize";
public override string Scopes => "";
public string ApiRedirectUri => this["zoomApiRedirectUrl"];
public const string ApiUrl = "https://api.zoom.us/v2";
private const string UserProfileUrl = $"{ApiUrl}/users/me";
public ZoomLoginProvider() { }
private readonly RequestHelper _requestHelper;
public ZoomLoginProvider(
OAuth20TokenHelper oAuth20TokenHelper,
TenantManager tenantManager,
CoreBaseSettings coreBaseSettings,
CoreSettings coreSettings,
IConfiguration configuration,
ICacheNotify<ConsumerCacheItem> cache,
ConsumerFactory consumerFactory,
Signature signature,
InstanceCrypto instanceCrypto,
RequestHelper requestHelper,
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
: base(oAuth20TokenHelper, tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, signature, instanceCrypto, name, order, props, additional)
{
_requestHelper = requestHelper;
}
public override LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params, IDictionary<string, string> additionalStateArgs)
{
try
{
var error = context.Request.Query["error"];
if (!string.IsNullOrEmpty(error))
{
if (error == "access_denied")
{
error = "Canceled at provider";
}
throw new Exception(error);
}
var code = context.Request.Query["code"];
if (string.IsNullOrEmpty(code))
{
context.Response.Redirect(_oAuth20TokenHelper.RequestCode<ZoomLoginProvider>(Scopes, @params, additionalStateArgs));
return null;
}
var token = GetAccessToken(code);
return GetLoginProfile(token);
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception ex)
{
return LoginProfile.FromError(Signature, InstanceCrypto, ex);
}
}
public OAuth20Token GetAccessToken(string code, string redirectUri = null, string codeVerifier = null)
{
var clientPair = $"{ClientID}:{ClientSecret}";
var b64clientPair = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientPair));
var body = new Dictionary<string, string>()
{
{ "code", code },
{ "grant_type", "authorization_code" },
{ "redirect_uri", redirectUri ?? RedirectUri }
};
if (codeVerifier != null)
{
body.Add("code_verifier", codeVerifier);
}
var json = _requestHelper.PerformRequest(AccessTokenUrl, "application/x-www-form-urlencoded", "POST",
body: string.Join("&", body.Select(kv => $"{HttpUtility.UrlEncode(kv.Key)}={HttpUtility.UrlEncode(kv.Value)}" )),
headers: new Dictionary<string, string> { { "Authorization", $"Basic {b64clientPair}" } }
);
return OAuth20Token.FromJson(json);
}
public override LoginProfile GetLoginProfile(string accessToken)
{
if (string.IsNullOrEmpty(accessToken))
{
throw new Exception("Login failed");
}
var (loginProfile, _) = RequestProfile(accessToken);
return loginProfile;
}
public (LoginProfile, ZoomProfile) GetLoginProfileAndRaw(string accessToken)
{
if (string.IsNullOrEmpty(accessToken))
{
throw new Exception("Login failed");
}
var (loginProfile, raw) = RequestProfile(accessToken);
return (loginProfile, raw);
}
public LoginProfile GetMinimalProfile(string uid)
{
return new LoginProfile(Signature, InstanceCrypto)
{
Id = uid,
Provider = ProviderConstants.Zoom
};
}
private (LoginProfile, ZoomProfile) ProfileFromZoom(string zoomProfile)
{
var jsonProfile = JsonConvert.DeserializeObject<ZoomProfile>(zoomProfile);
var profile = new LoginProfile(Signature, InstanceCrypto)
{
Id = jsonProfile.Id,
Avatar = jsonProfile.PicUrl?.ToString(),
EMail = jsonProfile.Email,
FirstName = jsonProfile.FirstName,
LastName = jsonProfile.LastName,
Locale = jsonProfile.Language,
TimeZone = jsonProfile.Timezone,
DisplayName = jsonProfile.DisplayName,
Provider = ProviderConstants.Zoom,
};
return (profile, jsonProfile);
}
private (LoginProfile, ZoomProfile) RequestProfile(string accessToken)
{
var json = _requestHelper.PerformRequest(UserProfileUrl, headers: new Dictionary<string, string> { { "Authorization", "Bearer " + accessToken } });
var (loginProfile, jsonProfile) = ProfileFromZoom(json);
return (loginProfile, jsonProfile);
}
public class ZoomProfile
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
[JsonProperty("display_name")]
public string DisplayName { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
[JsonProperty("role_name")]
public string RoleName { get; set; }
[JsonProperty("pmi")]
public long Pmi { get; set; }
[JsonProperty("use_pmi")]
public bool UsePmi { get; set; }
[JsonProperty("personal_meeting_url")]
public Uri PersonalMeetingUrl { get; set; }
[JsonProperty("timezone")]
public string Timezone { get; set; }
[JsonProperty("created_at")]
public DateTimeOffset CreatedAt { get; set; }
[JsonProperty("last_login_time")]
public DateTimeOffset LastLoginTime { get; set; }
[JsonProperty("pic_url")]
public Uri PicUrl { get; set; }
[JsonProperty("jid")]
public string Jid { get; set; }
[JsonProperty("account_id")]
public string AccountId { get; set; }
[JsonProperty("language")]
public string Language { get; set; }
[JsonProperty("phone_country")]
public string PhoneCountry { get; set; }
[JsonProperty("phone_number")]
public string PhoneNumber { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("job_title")]
public string JobTitle { get; set; }
[JsonProperty("location")]
public string Location { get; set; }
[JsonProperty("account_number")]
public long AccountNumber { get; set; }
[JsonProperty("cluster")]
public string Cluster { get; set; }
[JsonProperty("user_created_at")]
public DateTimeOffset UserCreatedAt { get; set; }
}
}

View File

@ -40,4 +40,5 @@ public static class ProviderConstants
public const string Encryption = "e2e";
public const string AppleId = "appleid";
public const string Microsoft = "microsoft";
public const string Zoom = "zoom";
}

View File

@ -533,6 +533,37 @@
"private_container" : ""
}
}
}
},
{
"type": "ASC.FederatedLogin.LoginProviders.ZoomLoginProvider, ASC.FederatedLogin",
"services": [
{
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
},
{
"type": "ASC.FederatedLogin.LoginProviders.ZoomLoginProvider, ASC.FederatedLogin"
},
{
"key": "zoom",
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
},
{
"key": "zoom",
"type": "ASC.FederatedLogin.LoginProviders.ZoomLoginProvider, ASC.FederatedLogin"
}
],
"instanceScope": "perlifetimescope",
"parameters": {
"name": "zoom",
"order": "24",
"props": {
"zoomClientId": "",
"zoomClientSecret": ""
},
"additional": {
"zoomRedirectUrl": "https://service.teamlab.info/oauth2.aspx"
}
}
}
]
}

View File

@ -16,7 +16,7 @@
{
"Period":"00:15:00"
},
"ChunkSize": 20971520,
"ChunkSize": 524288000,
"MaxLocalSize": 1048576000
}
}

14
config/dnsmasq.conf Normal file
View File

@ -0,0 +1,14 @@
#dnsmasq config, for a complete example, see:
# http://oss.segetech.com/intra/srv/dnsmasq.conf
#log all dns queries
log-queries
#dont use hosts nameservers
no-resolv
#use cloudflare as default nameservers, prefer 1^4
server=8.8.4.4
server=8.8.8.8
strict-order
#serve all .company queries using a specific nameserver
server=/site/127.0.0.1
#explicitly define host-ip mappings
address=/docspace.site/127.0.0.1

View File

@ -90,29 +90,7 @@ server {
proxy_set_header Connection $proxy_connection;
proxy_set_header Proxy "";
location ~* ^/ds-vpath/ {
rewrite /ds-vpath/(.*) /$1 break;
proxy_pass http://172.18.0.4:80;
proxy_redirect off;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host/ds-vpath;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
}
location / {
set $csp "";
set $csp "";
access_by_lua '
if ngx.req.get_method() == "GET" then
local key = string.format("csp:%s",ngx.var.host)
@ -137,6 +115,28 @@ server {
end
end
';
location ~* ^/ds-vpath/ {
rewrite /ds-vpath/(.*) /$1 break;
proxy_pass http://172.18.0.4:80;
proxy_redirect off;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host/ds-vpath;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
}
location / {
proxy_pass http://127.0.0.1:5001;
location ~* /(manifest.json|sw.js|appIcon(.)*\.png|icon.svg|bg-error.png|favicon.ico|debuginfo.md) {
try_files /$basename /index.html =404;

View File

@ -1,6 +1,6 @@
{
"name": "docspace",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"workspaces": {
"packages": [

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/client",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"homepage": "",
"scripts": {

View File

@ -83,6 +83,15 @@
window.DocSpaceConfig = {
...config,
};
if (window.navigator.userAgent.includes("ZoomWebKit") || window.navigator.userAgent.includes("ZoomApps")) {
window.DocSpaceConfig.editor = {
openOnNewPage: false,
requestClose: true
};
}
//console.log({ DocSpaceConfig: window.DocSpaceConfig });
})
.catch((e) => {
console.error(e);

View File

@ -111,7 +111,10 @@ const CreateEvent = ({
}
let tab =
!isDesktop && extension && open
!isDesktop &&
window.DocSpaceConfig?.editor?.openOnNewPage &&
extension &&
open
? window.open(
combineUrl(
window.DocSpaceConfig?.proxy?.url,

View File

@ -55,7 +55,10 @@ const ConvertPasswordDialogComponent = (props) => {
if (hasError) return;
tab =
!isDesktop && formCreationInfo.fileInfo.fileExst && formCreationInfo.open
!isDesktop &&
window.DocSpaceConfig?.editor?.openOnNewPage &&
formCreationInfo.fileInfo.fileExst &&
formCreationInfo.open
? window.open(
combineUrl(
window.DocSpaceConfig?.proxy?.url,

View File

@ -11,9 +11,6 @@ import RoomTypeList from "./sub-components/RoomTypeList";
import DialogHeader from "./sub-components/DialogHeader";
const StyledModalDialog = styled(ModalDialog)`
#modal-dialog {
margin-bottom: -64px !important;
}
.header-with-button {
display: flex;
align-items: center;

View File

@ -185,7 +185,7 @@ class NewFilesPanel extends React.Component {
config.homepage,
`/doceditor?fileId=${id}`
),
"_blank"
window.DocSpaceConfig?.editor?.openOnNewPage ? "_blank" : "_self"
)
);
}

View File

@ -444,7 +444,10 @@ export default inject(
const fileIcon = getIconSrc(ext, 32);
const downloadInCurrentTab = isArchive(ext) || !canViewedDocs(ext);
const downloadInCurrentTab =
window.DocSpaceConfig?.editor?.openOnNewPage === false ||
isArchive(ext) ||
!canViewedDocs(ext);
return {
isPersonal: personal,

View File

@ -141,7 +141,10 @@ export const openDocEditor = async (
tab.close();
}
} else {
window.open(url, "_blank");
window.open(
url,
window.DocSpaceConfig?.editor?.openOnNewPage ? "_blank" : "_self"
);
}
return Promise.resolve();

View File

@ -95,7 +95,11 @@ const VersionRow = (props) => {
setCommentValue(info.comment);
setShowEditPanel(!showEditPanel);
};
const onOpenFile = () => window.open(info.webUrl);
const onOpenFile = () =>
window.open(
info.webUrl,
window.DocSpaceConfig?.editor?.openOnNewPage ? "_blank" : "_self"
);
const onRestoreClick = () => {
onSetRestoreProcess(true);

View File

@ -336,7 +336,9 @@ class ContextOptionsStore {
: null;
let tab =
!isDesktopClient && fileExst
!isDesktopClient &&
window.DocSpaceConfig?.editor?.openOnNewPage &&
fileExst
? window.open(
combineUrl(
window.DocSpaceConfig?.proxy?.url,

View File

@ -2099,7 +2099,9 @@ class FilesActionStore {
if (canWebEdit || canViewedDocs) {
let tab =
!this.authStore.settingsStore.isDesktopClient && !isFolder
!this.authStore.settingsStore.isDesktopClient &&
window.DocSpaceConfig?.editor?.openOnNewPage &&
!isFolder
? window.open(
combineUrl(
window.DocSpaceConfig?.proxy?.url,

View File

@ -515,7 +515,9 @@ class UploadDataStore {
if (!error && isOpen && data && data[0]) {
let tab =
!this.authStore.settingsStore.isDesktopClient && fileInfo.fileExst
!this.authStore.settingsStore.isDesktopClient &&
window.DocSpaceConfig?.editor?.openOnNewPage &&
fileInfo.fileExst
? window.open(
combineUrl(
window.DocSpaceConfig?.proxy?.url,

View File

@ -3,6 +3,7 @@ import ShareFacebookReactSvgUrl from "PUBLIC_DIR/images/share.facebook.react.svg
import ShareTwitterReactSvgUrl from "PUBLIC_DIR/images/share.twitter.react.svg?url";
import ShareLinkedinReactSvgUrl from "PUBLIC_DIR/images/share.linkedin.react.svg?url";
import ShareMicrosoftReactSvgUrl from "PUBLIC_DIR/images/share.microsoft.react.svg?url";
import ShareZoomReactSvgUrl from "PUBLIC_DIR/images/share.zoom.react.svg?url";
export const LANGUAGE = "asc_language";
export const COOKIE_EXPIRATION_YEAR = 31536000000;
@ -271,6 +272,10 @@ export const providersData = Object.freeze({
label: "microsoft",
icon: ShareMicrosoftReactSvgUrl,
},
zoom: {
label: "zoom",
icon: ShareZoomReactSvgUrl,
},
});
export const LoaderStyle = {
title: "",

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/common",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"scripts": {
"build": "echo 'skip it'",

View File

@ -57,6 +57,7 @@ import VkSvgUrl from "PUBLIC_DIR/images/thirdparties/vk.svg?url";
import WordpressSvgUrl from "PUBLIC_DIR/images/thirdparties/wordpress.svg?url";
import YahooSvgUrl from "PUBLIC_DIR/images/thirdparties/yahoo.svg?url";
import YandexSvgUrl from "PUBLIC_DIR/images/thirdparties/yandex.svg?url";
import ZoomSvgUrl from "PUBLIC_DIR/images/thirdparties/zoom.svg?url";
import AviSvg24Url from "PUBLIC_DIR/images/icons/24/avi.svg?url";
import CsvSvg24Url from "PUBLIC_DIR/images/icons/24/csv.svg?url";
@ -592,6 +593,7 @@ export const thirdpartiesLogo = new Map([
["wordpress.svg", WordpressSvgUrl],
["yahoo.svg", YahooSvgUrl],
["yandex.svg", YandexSvgUrl],
["zoom.svg", ZoomSvgUrl],
]);
export const flagsIcons = new Map([

View File

@ -197,8 +197,8 @@ export function getCookie(name) {
let matches = document.cookie.match(
new RegExp(
"(?:^|; )" +
name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1") +
"=([^;]*)"
name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1") +
"=([^;]*)"
)
);
return matches ? decodeURIComponent(matches[1]) : undefined;
@ -287,6 +287,8 @@ export function getProviderTranslation(provider, t, linked = false) {
return t("Common:SignInWithMicrosoft");
case "sso":
return t("Common:SignInWithSso");
case "zoom":
return t("Common:SignInWithZoom");
}
}
@ -399,7 +401,7 @@ export function isElementInViewport(el) {
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <=
(window.innerHeight || document.documentElement.clientHeight) &&
(window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
@ -597,8 +599,11 @@ export const getFileExtension = (fileTitle: string) => {
export const getSystemTheme = () => {
const isDesktopClient = window["AscDesktopEditor"] !== undefined;
const desktopClientTheme = window?.RendererProcessVariable?.theme;
const isDark = desktopClientTheme?.id === "theme-dark" || desktopClientTheme?.id === "theme-contrast-dark" ||
(desktopClientTheme?.id === "theme-system" && desktopClientTheme?.system === "dark");
const isDark =
desktopClientTheme?.id === "theme-dark" ||
desktopClientTheme?.id === "theme-contrast-dark" ||
(desktopClientTheme?.id === "theme-system" &&
desktopClientTheme?.system === "dark");
return isDesktopClient
? isDark
@ -606,6 +611,6 @@ export const getSystemTheme = () => {
: ThemeKeys.BaseStr
: window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? ThemeKeys.DarkStr
: ThemeKeys.BaseStr;
? ThemeKeys.DarkStr
: ThemeKeys.BaseStr;
};

View File

@ -83,7 +83,7 @@ const Content = styled.div.attrs((props) => ({
@media ${smallTablet} {
transform: translateY(${(props) => (props.visible ? "0" : "100%")});
height: 100%;
height: calc(100% - 64px);
width: 100%;
left: 0;
top: ${(props) => (props.embedded ? "0" : "auto")};

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/components",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"scripts": {
"build": "echo 'skip it'",

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/editor",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"homepage": "/doceditor",
"scripts": {

View File

@ -22,7 +22,7 @@ import {
import { EditorWrapper } from "../components/StyledEditor";
import { useTranslation } from "react-i18next";
import withDialogs from "../helpers/withDialogs";
import { assign } from "@docspace/common/utils";
import { assign, frameCallEvent } from "@docspace/common/utils";
import toastr from "@docspace/components/toast/toastr";
import { DocumentEditor } from "@onlyoffice/document-editor-react";
import ErrorContainer from "@docspace/common/components/ErrorContainer";
@ -346,7 +346,10 @@ function Editor({
config.homepage,
`/doceditor?fileId=${encodeURIComponent(newFile.id)}`
);
window.open(newUrl, "_blank");
window.open(
newUrl,
window.DocSpaceConfig?.editor?.openOnNewPage ? "_blank" : "_self"
);
})
.catch((e) => {
toastr.error(e);
@ -646,6 +649,42 @@ function Editor({
}
};
const onSDKRequestClose = () => {
const search = window.location.search;
const editorGoBack = new URLSearchParams(search).get("editorGoBack");
if (editorGoBack === "event") {
frameCallEvent({ event: "onEditorCloseCallback" });
} else {
const backUrl = getBackUrl();
window.location.replace(backUrl);
}
};
const getBackUrl = () => {
if (!fileInfo) return;
const search = window.location.search;
const shareIndex = search.indexOf("share=");
const key = search.substring(shareIndex + 6);
let backUrl = "";
if (fileInfo.rootFolderType === FolderType.Rooms) {
if (key) {
backUrl = `/rooms/share?key=${key}`;
} else {
backUrl = `/rooms/shared/${fileInfo.folderId}/filter?folder=${fileInfo.folderId}`;
}
} else {
backUrl = `/rooms/personal/filter?folder=${fileInfo.folderId}`;
}
const url = window.location.href;
const origin = url.substring(0, url.indexOf("/doceditor"));
return `${combineUrl(origin, backUrl)}`;
};
const init = () => {
try {
if (isMobile) {
@ -653,37 +692,28 @@ function Editor({
}
let goBack;
const url = window.location.href;
const search = window.location.search;
const shareIndex = search.indexOf("share=");
const key = search.substring(shareIndex + 6);
if (fileInfo) {
let backUrl = "";
if (fileInfo.rootFolderType === FolderType.Rooms) {
if (key) {
backUrl = `/rooms/share?key=${key}`;
} else {
backUrl = `/rooms/shared/${fileInfo.folderId}/filter?folder=${fileInfo.folderId}`;
}
} else {
backUrl = `/rooms/personal/filter?folder=${fileInfo.folderId}`;
}
const origin = url.substring(0, url.indexOf("/doceditor"));
const search = window.location.search;
const editorGoBack = new URLSearchParams(search).get("editorGoBack");
goBack =
editorGoBack === "false"
? {}
: {
blank: true,
requestClose: false,
text: t("FileLocation"),
url: `${combineUrl(origin, backUrl)}`,
};
if (editorGoBack === "false") {
goBack = {};
} else if (editorGoBack === "event") {
goBack = {
requestClose: true,
text: t("FileLocation"),
};
} else {
goBack = {
requestClose: window.DocSpaceConfig?.editor?.requestClose ?? false,
text: t("FileLocation"),
};
if (!window.DocSpaceConfig?.editor?.requestClose) {
goBack.blank = window.DocSpaceConfig?.editor?.openOnNewPage ?? true;
goBack.url = getBackUrl();
}
}
}
config.editorConfig.customization = {
@ -700,6 +730,8 @@ function Editor({
// config.document.info.favorite = null;
// }
const url = window.location.href;
if (url.indexOf("anchor") !== -1) {
const splitUrl = url.split("anchor=");
const decodeURI = decodeURIComponent(splitUrl[1]);
@ -721,10 +753,14 @@ function Editor({
onRequestReferenceData,
onRequestUsers,
onRequestSendNotify,
onRequestCreateNew;
onRequestCreateNew,
onRequestClose;
if (successAuth && !user.isVisitor) {
if (isDesktopEditor) {
if (
isDesktopEditor ||
window.DocSpaceConfig?.editor?.openOnNewPage === false
) {
onRequestCreateNew = onSDKRequestCreateNew;
} else {
//FireFox security issue fix (onRequestCreateNew will be blocked)
@ -781,6 +817,10 @@ function Editor({
onRequestSendNotify = onSDKRequestSendNotify;
}
if (window.DocSpaceConfig?.editor?.requestClose) {
onRequestClose = onSDKRequestClose;
}
const events = {
events: {
onRequestReferenceData,
@ -806,6 +846,7 @@ function Editor({
onRequestUsers,
onRequestSendNotify,
onRequestCreateNew,
onRequestClose,
},
};

View File

@ -66,6 +66,13 @@ export default function template(
window.DocSpaceConfig = {
...config,
};
if (window.navigator.userAgent.includes("ZoomWebKit") || window.navigator.userAgent.includes("ZoomApps")) {
window.DocSpaceConfig.editor = {
openOnNewPage: false,
requestClose: true
};
}
})
.catch((e) => {
console.error(e);

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/login",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"homepage": "/login",
"scripts": {

View File

@ -79,6 +79,13 @@ const template: Template = (
window.DocSpaceConfig = {
...config,
};
if (window.navigator.userAgent.includes("ZoomWebKit") || window.navigator.userAgent.includes("ZoomApps")) {
window.DocSpaceConfig.editor = {
openOnNewPage: false,
requestClose: true
};
}
})
.catch((e) => {
console.error(e);

View File

@ -109,22 +109,11 @@ public class InvitationLinkService
return new InvitationLinkData { Result = EmailValidationKeyProvider.ValidationResult.Invalid };
}
if (userId != default)
{
var account = await _authManager.GetAccountByIDAsync(tenant.Id, userId);
if (!await _permissionContext.CheckPermissionsAsync(account, new UserSecurityProvider(employeeType), Constants.Action_AddRemoveUser))
{
return linkData;
}
}
var validationResult = await _invitationLinkHelper.ValidateAsync(key, email, employeeType);
linkData.Result = validationResult.Result;
linkData.LinkType = validationResult.LinkType;
linkData.EmployeeType = employeeType;
if (validationResult.LinkId == default)
{
if (!await CheckQuota(linkData.LinkType, employeeType))

View File

@ -559,6 +559,11 @@ public class FileSharing
if (isRoom && r.IsLink)
{
if (!canEditAccess)
{
continue;
}
w.Link = r.SubjectType == SubjectType.InvitationLink ?
_invitationLinkService.GetInvitationLink(r.Subject, _authContext.CurrentAccount.ID) :
await _externalShare.GetLinkAsync(r.Subject);
@ -579,7 +584,7 @@ public class FileSharing
result.Add(w);
}
if (isRoom && !withoutTemplates)
if (isRoom && canEditAccess&& !withoutTemplates)
{
var invitationId = Guid.NewGuid();

View File

@ -351,9 +351,12 @@ public class UserController : PeopleControllerBase
[HttpPost("invite")]
public async Task<List<EmployeeDto>> InviteUsersAsync(InviteUsersRequestDto inDto)
{
var currentUser = await _userManager.GetUsersAsync(_authContext.CurrentAccount.ID);
foreach (var invite in inDto.Invitations)
{
if (!await _permissionContext.CheckPermissionsAsync(new UserSecurityProvider(Guid.Empty, invite.Type), Constants.Action_AddRemoveUser))
if ((invite.Type == EmployeeType.DocSpaceAdmin && !currentUser.IsOwner(await _tenantManager.GetCurrentTenantAsync())) ||
!await _permissionContext.CheckPermissionsAsync(new UserSecurityProvider(Guid.Empty, invite.Type), Constants.Action_AddRemoveUser))
{
continue;
}
@ -1440,17 +1443,17 @@ public class UserController : PeopleControllerBase
var isUser = inDto.IsUser.Value;
if (isUser && !await _userManager.IsUserAsync(user) && canBeGuestFlag)
{
await _countUserChecker.CheckAppend();
await _userManager.AddUserIntoGroupAsync(user.Id, Constants.GroupUser.ID);
_webItemSecurityCache.ClearCache(Tenant.Id);
}
await _countUserChecker.CheckAppend();
await _userManager.AddUserIntoGroupAsync(user.Id, Constants.GroupUser.ID);
_webItemSecurityCache.ClearCache(Tenant.Id);
}
if (!self && !isUser && await _userManager.IsUserAsync(user))
{
await _countPaidUserChecker.CheckAppend();
await _userManager.RemoveUserFromGroupAsync(user.Id, Constants.GroupUser.ID);
_webItemSecurityCache.ClearCache(Tenant.Id);
}
{
await _countPaidUserChecker.CheckAppend();
await _userManager.RemoveUserFromGroupAsync(user.Id, Constants.GroupUser.ID);
_webItemSecurityCache.ClearCache(Tenant.Id);
}
}
await _userManager.UpdateUserInfoWithSyncCardDavAsync(user);

View File

@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_468_3079)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10ZM5 7H9.02446H11.5077C12.3318 7 13 7.64261 13 8.4353V13H6.49235C5.66814 13 5 12.3574 5 11.5647V7ZM13.5 9L16 7V13L13.5 11V10V9Z" fill="#008CFF"/>
</g>
<defs>
<clipPath id="clip0_468_3079">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 553 B

View File

@ -0,0 +1,10 @@
<svg width="79" height="40" viewBox="0 0 79 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8445_1359)">
<path d="M16.5673 28.7192H2.51991C2.06053 28.7257 1.60812 28.6065 1.21161 28.3745C0.815099 28.1425 0.489576 27.8066 0.27024 27.4031C0.0330939 26.9422 -0.051619 26.4179 0.0282935 25.9057C0.108206 25.3936 0.348623 24.92 0.714942 24.5531L10.4635 14.7739H3.48779C2.56275 14.7739 1.6756 14.4066 1.0215 13.7528C0.367401 13.099 -6.90971e-05 12.2123 -6.90971e-05 11.2876H12.9486C13.408 11.2812 13.8604 11.4004 14.2569 11.6323C14.6534 11.8643 14.9789 12.2002 15.1983 12.6037C15.4354 13.0647 15.5201 13.589 15.4402 14.1011C15.3603 14.6133 15.1199 15.0869 14.7536 15.4538L4.97013 25.2329H13.0794C14.0044 25.2329 14.8916 25.6002 15.5457 26.254C16.1998 26.9078 16.5673 27.7946 16.5673 28.7192ZM72.2073 11C71.2496 11.0027 70.3033 11.2074 69.4303 11.601C68.5573 11.9945 67.7772 12.5678 67.1412 13.2835C66.5052 12.5678 65.7252 11.9945 64.8521 11.601C63.9791 11.2074 63.0328 11.0027 62.0751 11C60.2569 11.0477 58.5293 11.8034 57.2605 13.1058C55.9916 14.4083 55.2819 16.1547 55.2825 17.9726V28.7192C55.7405 28.7192 56.1941 28.629 56.6172 28.4538C57.0404 28.2786 57.4249 28.0218 57.7488 27.6981C58.0727 27.3744 58.3296 26.99 58.5049 26.5671C58.6801 26.1441 58.7704 25.6907 58.7704 25.2329V17.9029C58.7577 17.0331 59.0818 16.192 59.6748 15.5553C60.2679 14.9187 61.0841 14.5357 61.953 14.4863C62.4023 14.4639 62.8515 14.5329 63.2733 14.6892C63.6951 14.8454 64.0807 15.0857 64.4069 15.3954C64.733 15.7051 64.9928 16.0777 65.1705 16.4908C65.3483 16.9039 65.4403 17.3487 65.4409 17.7983V25.2068C65.4409 26.1314 65.8083 27.0181 66.4625 27.672C67.1166 28.3258 68.0037 28.6931 68.9287 28.6931V17.9029C68.9155 17.0402 69.2335 16.2051 69.8174 15.5696C70.4013 14.9341 71.2067 14.5464 72.0678 14.4863C72.5135 14.4699 72.958 14.5434 73.3746 14.7024C73.7913 14.8614 74.1717 15.1026 74.4931 15.4117C74.8146 15.7208 75.0704 16.0914 75.2455 16.5014C75.4205 16.9114 75.5112 17.3525 75.5121 17.7983V25.2068C75.5121 26.1314 75.8795 27.0181 76.5336 27.672C77.1878 28.3258 78.0749 28.6931 78.9999 28.6931V17.9726C79.0006 16.1547 78.2908 14.4083 77.0219 13.1058C75.7531 11.8034 74.0255 11.0477 72.2073 11ZM34.181 20.0034C34.1758 21.7778 33.6446 23.5109 32.6546 24.9838C31.6646 26.4566 30.2602 27.6032 28.6186 28.2787C26.977 28.9541 25.172 29.1282 23.4316 28.7788C21.6911 28.4295 20.0933 27.5725 18.8398 26.3159C17.5864 25.0594 16.7336 23.4598 16.3892 21.7191C16.0448 19.9784 16.2241 18.1747 16.9047 16.5358C17.5852 14.8969 18.7364 13.4964 20.2127 12.5111C21.6891 11.5259 23.4245 11 25.1997 11C26.381 11.0011 27.5505 11.235 28.6414 11.6882C29.7322 12.1414 30.723 12.805 31.5571 13.6412C32.3912 14.4773 33.0523 15.4696 33.5025 16.5613C33.9527 17.653 34.1832 18.8226 34.181 20.0034ZM30.6931 20.0034C30.6931 18.9174 30.3709 17.8558 29.7673 16.9528C29.1637 16.0498 28.3057 15.346 27.3019 14.9304C26.2982 14.5148 25.1936 14.4061 24.128 14.618C23.0624 14.8298 22.0836 15.3528 21.3153 16.1207C20.547 16.8887 20.0239 17.867 19.8119 18.9322C19.5999 19.9973 19.7087 21.1014 20.1245 22.1047C20.5403 23.1081 21.2444 23.9656 22.1478 24.569C23.0511 25.1723 24.1132 25.4944 25.1997 25.4944C26.6559 25.4921 28.0519 24.9128 29.0816 23.8836C30.1113 22.8543 30.6908 21.459 30.6931 20.0034ZM53.5386 20.0034C53.5334 21.7778 53.0023 23.5109 52.0123 24.9838C51.0222 26.4566 49.6178 27.6032 47.9762 28.2787C46.3347 28.9541 44.5297 29.1282 42.7892 28.7788C41.0487 28.4295 39.4509 27.5725 38.1974 26.3159C36.944 25.0594 36.0912 23.4598 35.7468 21.7191C35.4024 19.9784 35.5817 18.1747 36.2623 16.5358C36.9428 14.8969 38.094 13.4964 39.5704 12.5111C41.0467 11.5259 42.7821 11 44.5573 11C45.7386 11.0011 46.9081 11.235 47.999 11.6882C49.0898 12.1414 50.0806 12.805 50.9147 13.6412C51.7488 14.4773 52.4099 15.4696 52.8601 16.5613C53.3103 17.653 53.5409 18.8226 53.5386 20.0034ZM50.0507 20.0034C50.0507 18.9174 49.7285 17.8558 49.1249 16.9528C48.5213 16.0498 47.6633 15.346 46.6596 14.9304C45.6558 14.5148 44.5512 14.4061 43.4856 14.618C42.42 14.8298 41.4412 15.3528 40.6729 16.1207C39.9047 16.8887 39.3815 17.867 39.1695 18.9322C38.9575 19.9973 39.0663 21.1014 39.4821 22.1047C39.8979 23.1081 40.602 23.9656 41.5054 24.569C42.4088 25.1723 43.4708 25.4944 44.5573 25.4944C46.0136 25.4921 47.4095 24.9128 48.4392 23.8836C49.4689 22.8543 50.0484 21.459 50.0507 20.0034Z" fill="#0B5CFF"/>
</g>
<defs>
<clipPath id="clip0_8445_1359">
<rect width="79" height="40" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Microsoft ilə giriş edin",
"SignInWithSso": "SSO ilə daxil olun",
"SignInWithTwitter": "Twitter ilə giriş edin",
"SignInWithZoom": "Zoom ilə giriş edin",
"Size": "Ölçü",
"SizeImageLarge": "Şəklin ölçüsü çox böyükdür, lütfən, başqa şəkil seçin.",
"SomethingWentWrong": "Xəta baş Verdi.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Влез с Microsoft",
"SignInWithSso": "Вход със SSO",
"SignInWithTwitter": "Влез с Twitter",
"SignInWithZoom": "Влез с Zoom",
"Size": "Размер",
"SizeImageLarge": "Размерът на изображението е твърде голям, моля изберете друго изображение.",
"SomethingWentWrong": "Нещо се обърка.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Přihlásit se pomocí Microsoft",
"SignInWithSso": "Přihlásit se pomocí SSO",
"SignInWithTwitter": "Přihlásit se pomocí Twitteru",
"SignInWithZoom": "Přihlásit se pomocí Zoom",
"Size": "Velikost",
"SizeImageLarge": "Velikost obrázku je příliš velká, vyberte prosím jiný obrázek.",
"SomethingWentWrong": "Něco se pokazilo.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Login über Microsoft",
"SignInWithSso": "Mit SSO anmelden",
"SignInWithTwitter": "Login über Twitter",
"SignInWithZoom": "Login über Zoom",
"Size": "Größe",
"SizeImageLarge": "Das Bild ist zu groß, bitte wählen Sie ein anderes Bild.",
"SomethingWentWrong": "Ein Fehler ist aufgetreten.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Συνδεθείτε με το Microsoft",
"SignInWithSso": "Σύνδεση με SSO",
"SignInWithTwitter": "Συνδεθείτε με το Twitter",
"SignInWithZoom": "Συνδεθείτε με την Zoom",
"Size": "Μέγεθος",
"SizeImageLarge": "Το μέγεθος της εικόνας είναι πολύ μεγάλο, επιλέξτε άλλη εικόνα.",
"SomethingWentWrong": "Κάτι πήγε στραβά.",

View File

@ -249,6 +249,7 @@
"SignInWithMicrosoft": "Sign in with Microsoft",
"SignInWithSso": "Sign in with SSO",
"SignInWithTwitter": "Sign in with Twitter",
"SignInWithZoom": "Sign in with Zoom",
"Size": "Size",
"SizeImageLarge": "The image size is too large, please select another image.",
"SomethingWentWrong": "Something went wrong.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Iniciar sesión con Microsoft",
"SignInWithSso": "Iniciar sesión con SSO",
"SignInWithTwitter": "Iniciar sesión con Twitter",
"SignInWithZoom": "Iniciar sesión con Zoom",
"Size": "Tamaño",
"SizeImageLarge": "El tamaño de la imagen es demasiado grande. Por favor, seleccione otra imagen.",
"SomethingWentWrong": "Se ha producido un error.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Kirjaudu sisään Microsoftilla",
"SignInWithSso": "Kirjaudu sisään kertakirjautumisella",
"SignInWithTwitter": "Kirjaudu sisään Twitterillä",
"SignInWithZoom": "Kirjaudu sisään Zoomillä",
"Size": "Koko",
"SizeImageLarge": "Kuva on liian suuri, ole hyvä ja valitse toinen kuva.",
"SomethingWentWrong": "Jokin meni pieleen.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Se connecter avec Microsoft",
"SignInWithSso": "Se connecter avec SSO",
"SignInWithTwitter": "Se connecter avec Twitter",
"SignInWithZoom": "Se connecter avec Zoom",
"Size": "Taille",
"SizeImageLarge": "La taille de limage est trop grande, veuillez sélectionner une autre image.",
"SomethingWentWrong": "Un problème est survenu.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Մուտք գործեք Microsoft-ով",
"SignInWithSso": "Մուտք գործեք SSO-ով",
"SignInWithTwitter": "Մուտք գործեք Twitter-ով",
"SignInWithZoom": "Մուտք գործեք Zoom-ով",
"Size": "Չափ",
"SizeImageLarge": "Պատկերի չափը չափազանց մեծ է, խնդրում ենք ընտրել մեկ այլ պատկեր:",
"SomethingWentWrong": "Ինչ որ բան այնպես չգնաց.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Accedere con Microsoft",
"SignInWithSso": "Accedere con SSO",
"SignInWithTwitter": "Accedere con Twitter",
"SignInWithZoom": "Accedere con Zoom",
"Size": "Dimensione",
"SizeImageLarge": "La dimensione dell&apos;immagine è troppo grande, seleziona un'altra immagine.",
"SomethingWentWrong": "Qualcosa è andato storto.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Microsoftでサインイン",
"SignInWithSso": "SSOでサインイン",
"SignInWithTwitter": "Twitterでサインイン",
"SignInWithZoom": "Zoomでサインイン",
"Size": "サイズ",
"SizeImageLarge": "画像サイズが大きすぎるため、別の画像を選択してください。",
"SomethingWentWrong": "何かが間違っていた.",

View File

@ -243,6 +243,7 @@
"SignInWithMicrosoft": "Microsoft으로 로그인",
"SignInWithSso": "SSO로 로그인",
"SignInWithTwitter": "Twitter로 로그인",
"SignInWithZoom": "Zoom로 로그인",
"Size": "크기",
"SizeImageLarge": "이미지 크기가 너무 큽니다. 다른 이미지를 선택해주세요.",
"SomethingWentWrong": "무언가 잘못됐습니다.",

View File

@ -243,6 +243,7 @@
"SignInWithMicrosoft": "ເຂົ້າລະບົບດ້ວຍ Microsoft",
"SignInWithSso": "ເຂົ້າສູ່ລະບົບດ້ວຍ SSO",
"SignInWithTwitter": "ເຂົ້າລະບົບດ້ວຍ Twitter",
"SignInWithZoom": "ເຂົ້າລະບົບດ້ວຍ Zoom",
"Size": "ຂະໜາດ",
"SizeImageLarge": "ຂະໜາດຮູບໃຫຍ່ເກີນໄປ, ກະລຸນາເລືອກຮູບອື່ນ.",
"SomethingWentWrong": "ມີບາງຢ່າງຜິດພາດ",

View File

@ -243,6 +243,7 @@
"SignInWithMicrosoft": "Pierakstīties ar Microsoft",
"SignInWithSso": "Pierakstīties, izmantojot SSO",
"SignInWithTwitter": "Pierakstīties ar Twitter",
"SignInWithZoom": "Pierakstīties ar Zoom",
"Size": "Izmērs",
"SizeImageLarge": "Attēls ir pārāk liels. Lūdzu, atlasiet citu attēlu.",
"SomethingWentWrong": "Radās problēma.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Aanmelden met Microsoft",
"SignInWithSso": "Aanmelden met SSO",
"SignInWithTwitter": "Aanmelden met Twitter",
"SignInWithZoom": "Aanmelden met Zoom",
"Size": "Formaat",
"SizeImageLarge": "De afbeelding is te groot, kies een andere afbeelding.",
"SomethingWentWrong": "Er is iets fout gegaan.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Zaloguj się przez Microsoft",
"SignInWithSso": "Zaloguj się za pomocą logowania jednokrotnego",
"SignInWithTwitter": "Zaloguj się przez Twitter",
"SignInWithZoom": "Zaloguj się przez Zoom",
"Size": "Rozmiar",
"SizeImageLarge": "Rozmiar obrazu jest zbyt duży, wybierz inny obraz.",
"SomethingWentWrong": "Coś poszło nie tak.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Entrar com Microsoft",
"SignInWithSso": "Fazer login com SSO",
"SignInWithTwitter": "Entrar com Twitter",
"SignInWithZoom": "Entrar com Zoom",
"Size": "Tamanho",
"SizeImageLarge": "O tamanho da imagem é muito grande, selecione outra imagem.",
"SomethingWentWrong": "Algo deu errado.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Iniciar sessão com a Microsoft",
"SignInWithSso": "Entrar com SSO",
"SignInWithTwitter": "Iniciar sessão com o Twitter",
"SignInWithZoom": "Iniciar sessão com o Zoom",
"Size": "Tamanho",
"SizeImageLarge": "A imagem é demasiado grande, por favor selecione outra imagem.",
"SomethingWentWrong": "Ocorreu um erro.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Conectare cu Microsoft",
"SignInWithSso": "Conectare cu SSO",
"SignInWithTwitter": "Conectare cu Twitter",
"SignInWithZoom": "Conectare cu Zoom",
"Size": "Dimensiune",
"SizeImageLarge": "Dimensiunea imaginii este prea mare, selectaţi o altă imagine.",
"SomethingWentWrong": "Ceva nu a mers bine.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Вход через Microsoft",
"SignInWithSso": "Вход через SSO",
"SignInWithTwitter": "Вход через Twitter",
"SignInWithZoom": "Вход через Zoom",
"Size": "Размер",
"SizeImageLarge": "Размер изображения слишком большой, пожалуйста, выберите другое изображение.",
"SomethingWentWrong": "Что-то пошло не так.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Prihlásiť sa pomocou Microsoft",
"SignInWithSso": "Prihlásiť sa pomocou SSO",
"SignInWithTwitter": "Prihlásiť sa pomocou Twitteru",
"SignInWithZoom": "Prihlásiť sa pomocou Zoom",
"Size": "Veľkosť",
"SizeImageLarge": "Obrázok je príliš veľký, vyberte iný obrázok.",
"SomethingWentWrong": "Niečo sa pokazilo.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Prijavi se z Microsoft",
"SignInWithSso": "Vpiši se s SSO",
"SignInWithTwitter": "Prijavi se s Twitter",
"SignInWithZoom": "Prijavi se s Zoom",
"Size": "Velikost",
"SizeImageLarge": "Velikost slike je prevelika, izberite drugo sliko.",
"SomethingWentWrong": "Nekaj je šlo narobe.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Microsoft hesabınız ile giriş yapın",
"SignInWithSso": "SSO ile giriş yap",
"SignInWithTwitter": "Twitter hesabınız ile giriş yapın",
"SignInWithZoom": "Zoom hesabınız ile giriş yapın",
"Size": "Boyut",
"SizeImageLarge": "Resim boyutu çok büyük, lütfen başka bir resim seçin.",
"SomethingWentWrong": "Bir şeyler ters gitti.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Увійти за допомогою Microsoft",
"SignInWithSso": "Увійти за допомогою єдиного входу",
"SignInWithTwitter": "Увійти за допомогою Twitter",
"SignInWithZoom": "Увійти за допомогою Zoom",
"Size": "Розмір",
"SizeImageLarge": "Розмір зображення завеликий, виберіть інше зображення.",
"SomethingWentWrong": "Сталася помилка.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "Đăng nhập bằng Microsoft",
"SignInWithSso": "Đăng nhập bằng SSO",
"SignInWithTwitter": "Đăng nhập bằng Twitter",
"SignInWithZoom": "Đăng nhập bằng Zoom",
"Size": "Kích cỡ",
"SizeImageLarge": "Kích thước hình ảnh quá lớn, xin vui lòng chọn một hình ảnh khác.",
"SomethingWentWrong": "Đã xảy ra lỗi.",

View File

@ -244,6 +244,7 @@
"SignInWithMicrosoft": "使用Microsoft登录",
"SignInWithSso": "用SSO登录",
"SignInWithTwitter": "使用Twitter登录",
"SignInWithZoom": "使用Zoom登录",
"Size": "大小",
"SizeImageLarge": "图像尺寸过大,请选择另一张图像。",
"SomethingWentWrong": "出了点问题。",

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