Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
a31b1d878f Bump mdast-util-to-hast from 13.2.0 to 13.2.1 in /frontend
Bumps [mdast-util-to-hast](https://github.com/syntax-tree/mdast-util-to-hast) from 13.2.0 to 13.2.1.
- [Release notes](https://github.com/syntax-tree/mdast-util-to-hast/releases)
- [Commits](https://github.com/syntax-tree/mdast-util-to-hast/compare/13.2.0...13.2.1)

---
updated-dependencies:
- dependency-name: mdast-util-to-hast
  dependency-version: 13.2.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-13 13:39:59 +00:00
126 changed files with 2474 additions and 7831 deletions

104
.github/dependabot.yml vendored
View File

@@ -1,104 +0,0 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/backend"
schedule:
interval: "weekly"
groups:
dev-patch-updates:
dependency-type: "development"
update-types:
- "patch"
dev-minor-updates:
dependency-type: "development"
update-types:
- "minor"
prod-patch-updates:
dependency-type: "production"
update-types:
- "patch"
prod-minor-updates:
dependency-type: "production"
update-types:
- "minor"
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
groups:
dev-patch-updates:
dependency-type: "development"
update-types:
- "patch"
dev-minor-updates:
dependency-type: "development"
update-types:
- "minor"
prod-patch-updates:
dependency-type: "production"
update-types:
- "patch"
prod-minor-updates:
dependency-type: "production"
update-types:
- "minor"
- package-ecosystem: "npm"
directory: "/docs"
schedule:
interval: "weekly"
groups:
dev-patch-updates:
dependency-type: "development"
update-types:
- "patch"
dev-minor-updates:
dependency-type: "development"
update-types:
- "minor"
prod-patch-updates:
dependency-type: "production"
update-types:
- "patch"
prod-minor-updates:
dependency-type: "production"
update-types:
- "minor"
- package-ecosystem: "npm"
directory: "/test"
schedule:
interval: "weekly"
groups:
dev-patch-updates:
dependency-type: "development"
update-types:
- "patch"
dev-minor-updates:
dependency-type: "development"
update-types:
- "minor"
prod-patch-updates:
dependency-type: "production"
update-types:
- "patch"
prod-minor-updates:
dependency-type: "production"
update-types:
- "minor"
- package-ecosystem: "docker"
directory: "/docker"
schedule:
interval: "weekly"
groups:
updates:
update-types:
- "patch"
- "minor"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -8,7 +8,7 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v10 - uses: actions/stale@v9
with: with:
stale-issue-label: 'stale' stale-issue-label: 'stale'
stale-pr-label: 'stale' stale-pr-label: 'stale'

View File

@@ -1 +1 @@
2.14.0 2.13.5

View File

@@ -1,7 +1,7 @@
<p align="center"> <p align="center">
<img src="https://nginxproxymanager.com/github.png"> <img src="https://nginxproxymanager.com/github.png">
<br><br> <br><br>
<img src="https://img.shields.io/badge/version-2.14.0-green.svg?style=for-the-badge"> <img src="https://img.shields.io/badge/version-2.13.5-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager"> <a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge"> <img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a> </a>
@@ -36,10 +36,6 @@ so that the barrier for entry here is low.
- Advanced Nginx configuration available for super users - Advanced Nginx configuration available for super users
- User management, permissions and audit log - User management, permissions and audit log
::: warning
`armv7` is no longer supported in version 2.14+. This is due to Nodejs dropping support for armhf. Please
use the `2.13.7` image tag if this applies to you.
:::
## Hosting your home network ## Hosting your home network
@@ -47,15 +43,16 @@ I won't go in to too much detail here but here are the basics for someone new to
1. Your home router will have a Port Forwarding section somewhere. Log in and find it 1. Your home router will have a Port Forwarding section somewhere. Log in and find it
2. Add port forwarding for port 80 and 443 to the server hosting this project 2. Add port forwarding for port 80 and 443 to the server hosting this project
3. Configure your domain name details to point to your home, either with a static ip or a service like 3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
- DuckDNS
- [Amazon Route53](https://github.com/jc21/route53-ddns)
- [Cloudflare](https://github.com/jc21/cloudflare-ddns)
4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services 4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
## Quick Setup ## Quick Setup
1. [Install Docker](https://docs.docker.com/install/) 1. Install Docker and Docker-Compose
- [Docker Install documentation](https://docs.docker.com/install/)
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
2. Create a docker-compose.yml file similar to this: 2. Create a docker-compose.yml file similar to this:
```yml ```yml

View File

@@ -1,5 +1,5 @@
{ {
"$schema": "https://biomejs.dev/schemas/2.3.14/schema.json", "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json",
"vcs": { "vcs": {
"enabled": true, "enabled": true,
"clientKind": "git", "clientKind": "git",

View File

@@ -23,14 +23,6 @@
"credentials": "dns_aliyun_access_key = 12345678\ndns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef", "credentials": "dns_aliyun_access_key = 12345678\ndns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef",
"full_plugin_name": "dns-aliyun" "full_plugin_name": "dns-aliyun"
}, },
"arvan": {
"name": "ArvanCloud",
"package_name": "certbot-dns-arvan",
"version": ">=0.1.0",
"dependencies": "",
"credentials": "dns_arvan_key = Apikey xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"full_plugin_name": "dns-arvan"
},
"azure": { "azure": {
"name": "Azure", "name": "Azure",
"package_name": "certbot-dns-azure", "package_name": "certbot-dns-azure",
@@ -82,7 +74,7 @@
"cloudns": { "cloudns": {
"name": "ClouDNS", "name": "ClouDNS",
"package_name": "certbot-dns-cloudns", "package_name": "certbot-dns-cloudns",
"version": "~=0.7.0", "version": "~=0.6.0",
"dependencies": "", "dependencies": "",
"credentials": "# Target user ID (see https://www.cloudns.net/api-settings/)\n\tdns_cloudns_auth_id=1234\n\t# Alternatively, one of the following two options can be set:\n\t# dns_cloudns_sub_auth_id=1234\n\t# dns_cloudns_sub_auth_user=foobar\n\n\t# API password\n\tdns_cloudns_auth_password=password1", "credentials": "# Target user ID (see https://www.cloudns.net/api-settings/)\n\tdns_cloudns_auth_id=1234\n\t# Alternatively, one of the following two options can be set:\n\t# dns_cloudns_sub_auth_id=1234\n\t# dns_cloudns_sub_auth_user=foobar\n\n\t# API password\n\tdns_cloudns_auth_password=password1",
"full_plugin_name": "dns-cloudns" "full_plugin_name": "dns-cloudns"

View File

@@ -2,7 +2,7 @@
"database": { "database": {
"engine": "knex-native", "engine": "knex-native",
"knex": { "knex": {
"client": "better-sqlite3", "client": "sqlite3",
"connection": { "connection": {
"filename": "/app/config/mydb.sqlite" "filename": "/app/config/mydb.sqlite"
}, },

View File

@@ -1,9 +1,9 @@
import crypto from "node:crypto";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { createGuardrails, generateSecret, generateURI, verify } from "otplib"; import crypto from "node:crypto";
import errs from "../lib/error.js"; import { authenticator } from "otplib";
import authModel from "../models/auth.js"; import authModel from "../models/auth.js";
import internalUser from "./user.js"; import userModel from "../models/user.js";
import errs from "../lib/error.js";
const APP_NAME = "Nginx Proxy Manager"; const APP_NAME = "Nginx Proxy Manager";
const BACKUP_CODE_COUNT = 8; const BACKUP_CODE_COUNT = 8;
@@ -26,98 +26,134 @@ const generateBackupCodes = async () => {
return { plain, hashed }; return { plain, hashed };
}; };
const internal2fa = { export default {
/**
* Generate a new TOTP secret
* @returns {string}
*/
generateSecret: () => {
return authenticator.generateSecret();
},
/**
* Generate otpauth URL for QR code
* @param {string} email
* @param {string} secret
* @returns {string}
*/
generateOTPAuthURL: (email, secret) => {
return authenticator.keyuri(email, APP_NAME, secret);
},
/**
* Verify a TOTP code
* @param {string} secret
* @param {string} code
* @returns {boolean}
*/
verifyCode: (secret, code) => {
try {
return authenticator.verify({ token: code, secret });
} catch {
return false;
}
},
/** /**
* Check if user has 2FA enabled * Check if user has 2FA enabled
* @param {number} userId * @param {number} userId
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
isEnabled: async (userId) => { isEnabled: async (userId) => {
const auth = await internal2fa.getUserPasswordAuth(userId); const auth = await authModel
return auth?.meta?.totp_enabled === true; .query()
.where("user_id", userId)
.where("type", "password")
.first();
if (!auth || !auth.meta) {
return false;
}
return auth.meta.totp_enabled === true;
}, },
/** /**
* Get 2FA status for user * Get 2FA status for user
* @param {Access} access * @param {number} userId
* @param {number} userId * @returns {Promise<{enabled: boolean, backupCodesRemaining: number}>}
* @returns {Promise<{enabled: boolean, backup_codes_remaining: number}>}
*/ */
getStatus: async (access, userId) => { getStatus: async (userId) => {
await access.can("users:password", userId); const auth = await authModel
await internalUser.get(access, { id: userId }); .query()
const auth = await internal2fa.getUserPasswordAuth(userId); .where("user_id", userId)
const enabled = auth?.meta?.totp_enabled === true; .where("type", "password")
let backup_codes_remaining = 0; .first();
if (enabled) { if (!auth || !auth.meta || !auth.meta.totp_enabled) {
const backupCodes = auth.meta.backup_codes || []; return { enabled: false, backupCodesRemaining: 0 };
backup_codes_remaining = backupCodes.length;
} }
const backupCodes = auth.meta.backup_codes || [];
return { return {
enabled, enabled: true,
backup_codes_remaining, backupCodesRemaining: backupCodes.length,
}; };
}, },
/** /**
* Start 2FA setup - store pending secret * Start 2FA setup - store pending secret
* * @param {number} userId
* @param {Access} access * @returns {Promise<{secret: string, otpauthUrl: string}>}
* @param {number} userId
* @returns {Promise<{secret: string, otpauth_url: string}>}
*/ */
startSetup: async (access, userId) => { startSetup: async (userId) => {
await access.can("users:password", userId); const user = await userModel.query().where("id", userId).first();
const user = await internalUser.get(access, { id: userId }); if (!user) {
const secret = generateSecret(); throw new errs.ItemNotFoundError("User not found");
const otpauth_url = generateURI({ }
issuer: APP_NAME,
label: user.email,
secret: secret,
});
const auth = await internal2fa.getUserPasswordAuth(userId);
// ensure user isn't already setup for 2fa const secret = authenticator.generateSecret();
const enabled = auth?.meta?.totp_enabled === true; const otpauthUrl = authenticator.keyuri(user.email, APP_NAME, secret);
if (enabled) {
throw new errs.ValidationError("2FA is already enabled"); const auth = await authModel
.query()
.where("user_id", userId)
.where("type", "password")
.first();
if (!auth) {
throw new errs.ItemNotFoundError("Auth record not found");
} }
const meta = auth.meta || {}; const meta = auth.meta || {};
meta.totp_pending_secret = secret; meta.totp_pending_secret = secret;
await authModel await authModel.query().where("id", auth.id).patch({ meta });
.query()
.where("id", auth.id)
.andWhere("user_id", userId)
.andWhere("type", "password")
.patch({ meta });
return { secret, otpauth_url }; return { secret, otpauthUrl };
}, },
/** /**
* Enable 2FA after verifying code * Enable 2FA after verifying code
* * @param {number} userId
* @param {Access} access * @param {string} code
* @param {number} userId * @returns {Promise<{backupCodes: string[]}>}
* @param {string} code
* @returns {Promise<{backup_codes: string[]}>}
*/ */
enable: async (access, userId, code) => { enable: async (userId, code) => {
await access.can("users:password", userId); const auth = await authModel
await internalUser.get(access, { id: userId }); .query()
const auth = await internal2fa.getUserPasswordAuth(userId); .where("user_id", userId)
const secret = auth?.meta?.totp_pending_secret || false; .where("type", "password")
.first();
if (!secret) { if (!auth || !auth.meta || !auth.meta.totp_pending_secret) {
throw new errs.ValidationError("No pending 2FA setup found"); throw new errs.ValidationError("No pending 2FA setup found");
} }
const result = await verify({ token: code, secret }); const secret = auth.meta.totp_pending_secret;
if (!result.valid) { const valid = authenticator.verify({ token: code, secret });
if (!valid) {
throw new errs.ValidationError("Invalid verification code"); throw new errs.ValidationError("Invalid verification code");
} }
@@ -132,44 +168,35 @@ const internal2fa = {
}; };
delete meta.totp_pending_secret; delete meta.totp_pending_secret;
await authModel await authModel.query().where("id", auth.id).patch({ meta });
.query()
.where("id", auth.id)
.andWhere("user_id", userId)
.andWhere("type", "password")
.patch({ meta });
return { backup_codes: plain }; return { backupCodes: plain };
}, },
/** /**
* Disable 2FA * Disable 2FA
* * @param {number} userId
* @param {Access} access * @param {string} code
* @param {number} userId
* @param {string} code
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
disable: async (access, userId, code) => { disable: async (userId, code) => {
await access.can("users:password", userId); const auth = await authModel
await internalUser.get(access, { id: userId }); .query()
const auth = await internal2fa.getUserPasswordAuth(userId); .where("user_id", userId)
.where("type", "password")
.first();
const enabled = auth?.meta?.totp_enabled === true; if (!auth || !auth.meta || !auth.meta.totp_enabled) {
if (!enabled) {
throw new errs.ValidationError("2FA is not enabled"); throw new errs.ValidationError("2FA is not enabled");
} }
const result = await verify({ const valid = authenticator.verify({
token: code, token: code,
secret: auth.meta.totp_secret, secret: auth.meta.totp_secret,
guardrails: createGuardrails({ });
MIN_SECRET_BYTES: 10,
}),
});
if (!result.valid) { if (!valid) {
throw new errs.AuthError("Invalid verification code"); throw new errs.ValidationError("Invalid verification code");
} }
const meta = { ...auth.meta }; const meta = { ...auth.meta };
@@ -178,64 +205,46 @@ const internal2fa = {
delete meta.totp_enabled_at; delete meta.totp_enabled_at;
delete meta.backup_codes; delete meta.backup_codes;
await authModel await authModel.query().where("id", auth.id).patch({ meta });
.query()
.where("id", auth.id)
.andWhere("user_id", userId)
.andWhere("type", "password")
.patch({ meta });
}, },
/** /**
* Verify 2FA code for login * Verify 2FA code for login
* * @param {number} userId
* @param {number} userId * @param {string} code
* @param {string} token
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
verifyForLogin: async (userId, token) => { verifyForLogin: async (userId, code) => {
const auth = await internal2fa.getUserPasswordAuth(userId); const auth = await authModel
const secret = auth?.meta?.totp_secret || false; .query()
.where("user_id", userId)
.where("type", "password")
.first();
if (!secret) { if (!auth || !auth.meta || !auth.meta.totp_secret) {
return false; return false;
} }
// Try TOTP code first, if it's 6 chars. it will throw errors if it's not 6 chars // Try TOTP code first
// and the backup codes are 8 chars. const valid = authenticator.verify({
if (token.length === 6) { token: code,
const result = await verify({ secret: auth.meta.totp_secret,
token, });
secret,
// These guardrails lower the minimum length requirement for secrets.
// In v12 of otplib the default minimum length is 10 and in v13 it is 16.
// Since there are 2fa secrets in the wild generated with v12 we need to allow shorter secrets
// so people won't be locked out when upgrading.
guardrails: createGuardrails({
MIN_SECRET_BYTES: 10,
}),
});
if (result.valid) { if (valid) {
return true; return true;
}
} }
// Try backup codes // Try backup codes
const backupCodes = auth?.meta?.backup_codes || []; const backupCodes = auth.meta.backup_codes || [];
for (let i = 0; i < backupCodes.length; i++) { for (let i = 0; i < backupCodes.length; i++) {
const match = await bcrypt.compare(token.toUpperCase(), backupCodes[i]); const match = await bcrypt.compare(code.toUpperCase(), backupCodes[i]);
if (match) { if (match) {
// Remove used backup code // Remove used backup code
const updatedCodes = [...backupCodes]; const updatedCodes = [...backupCodes];
updatedCodes.splice(i, 1); updatedCodes.splice(i, 1);
const meta = { ...auth.meta, backup_codes: updatedCodes }; const meta = { ...auth.meta, backup_codes: updatedCodes };
await authModel await authModel.query().where("id", auth.id).patch({ meta });
.query()
.where("id", auth.id)
.andWhere("user_id", userId)
.andWhere("type", "password")
.patch({ meta });
return true; return true;
} }
} }
@@ -245,61 +254,35 @@ const internal2fa = {
/** /**
* Regenerate backup codes * Regenerate backup codes
* * @param {number} userId
* @param {Access} access * @param {string} code
* @param {number} userId * @returns {Promise<{backupCodes: string[]}>}
* @param {string} token
* @returns {Promise<{backup_codes: string[]}>}
*/ */
regenerateBackupCodes: async (access, userId, token) => { regenerateBackupCodes: async (userId, code) => {
await access.can("users:password", userId); const auth = await authModel
await internalUser.get(access, { id: userId }); .query()
const auth = await internal2fa.getUserPasswordAuth(userId); .where("user_id", userId)
const enabled = auth?.meta?.totp_enabled === true; .where("type", "password")
const secret = auth?.meta?.totp_secret || false; .first();
if (!enabled) { if (!auth || !auth.meta || !auth.meta.totp_enabled) {
throw new errs.ValidationError("2FA is not enabled"); throw new errs.ValidationError("2FA is not enabled");
} }
if (!secret) {
throw new errs.ValidationError("No 2FA secret found");
}
const result = await verify({ const valid = authenticator.verify({
token, token: code,
secret, secret: auth.meta.totp_secret,
}); });
if (!result.valid) { if (!valid) {
throw new errs.ValidationError("Invalid verification code"); throw new errs.ValidationError("Invalid verification code");
} }
const { plain, hashed } = await generateBackupCodes(); const { plain, hashed } = await generateBackupCodes();
const meta = { ...auth.meta, backup_codes: hashed }; const meta = { ...auth.meta, backup_codes: hashed };
await authModel await authModel.query().where("id", auth.id).patch({ meta });
.query()
.where("id", auth.id)
.andWhere("user_id", userId)
.andWhere("type", "password")
.patch({ meta });
return { backup_codes: plain }; return { backupCodes: plain };
},
getUserPasswordAuth: async (userId) => {
const auth = await authModel
.query()
.where("user_id", userId)
.andWhere("type", "password")
.first();
if (!auth) {
throw new errs.ItemNotFoundError("Auth not found");
}
return auth;
}, },
}; };
export default internal2fa;

View File

@@ -630,7 +630,7 @@ const internalCertificate = {
* @param {String} privateKey This is the entire key contents as a string * @param {String} privateKey This is the entire key contents as a string
*/ */
checkPrivateKey: async (privateKey) => { checkPrivateKey: async (privateKey) => {
const filepath = await tempWrite(privateKey); const filepath = await tempWrite(privateKey, "/tmp");
const failTimeout = setTimeout(() => { const failTimeout = setTimeout(() => {
throw new error.ValidationError( throw new error.ValidationError(
"Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.", "Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.",
@@ -660,8 +660,8 @@ const internalCertificate = {
* @param {Boolean} [throwExpired] Throw when the certificate is out of date * @param {Boolean} [throwExpired] Throw when the certificate is out of date
*/ */
getCertificateInfo: async (certificate, throwExpired) => { getCertificateInfo: async (certificate, throwExpired) => {
const filepath = await tempWrite(certificate);
try { try {
const filepath = await tempWrite(certificate, "/tmp");
const certData = await internalCertificate.getCertificateInfoFromFile(filepath, throwExpired); const certData = await internalCertificate.getCertificateInfoFromFile(filepath, throwExpired);
fs.unlinkSync(filepath); fs.unlinkSync(filepath);
return certData; return certData;

View File

@@ -5,7 +5,7 @@ import { global as logger } from "../logger.js";
const keysFile = '/data/keys.json'; const keysFile = '/data/keys.json';
const mysqlEngine = 'mysql2'; const mysqlEngine = 'mysql2';
const postgresEngine = 'pg'; const postgresEngine = 'pg';
const sqliteClientName = 'better-sqlite3'; const sqliteClientName = 'sqlite3';
let instance = null; let instance = null;
@@ -84,7 +84,6 @@ const configure = () => {
} }
const envSqliteFile = process.env.DB_SQLITE_FILE || "/data/database.sqlite"; const envSqliteFile = process.env.DB_SQLITE_FILE || "/data/database.sqlite";
logger.info(`Using Sqlite: ${envSqliteFile}`); logger.info(`Using Sqlite: ${envSqliteFile}`);
instance = { instance = {
database: { database: {

View File

@@ -1,43 +0,0 @@
import { migrate as logger } from "../logger.js";
const migrateName = "trust_forwarded_proto";
/**
* Migrate
*
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
* @returns {Promise}
*/
const up = function (knex) {
logger.info(`[${migrateName}] Migrating Up...`);
return knex.schema
.alterTable('proxy_host', (table) => {
table.tinyint('trust_forwarded_proto').notNullable().defaultTo(0);
})
.then(() => {
logger.info(`[${migrateName}] proxy_host Table altered`);
});
};
/**
* Undo Migrate
*
* @param {Object} knex
* @returns {Promise}
*/
const down = function (knex) {
logger.info(`[${migrateName}] Migrating Down...`);
return knex.schema
.alterTable('proxy_host', (table) => {
table.dropColumn('trust_forwarded_proto');
})
.then(() => {
logger.info(`[${migrateName}] proxy_host Table altered`);
});
};
export { up, down };

View File

@@ -21,7 +21,6 @@ const boolFields = [
"enabled", "enabled",
"hsts_enabled", "hsts_enabled",
"hsts_subdomains", "hsts_subdomains",
"trust_forwarded_proto",
]; ];
class ProxyHost extends Model { class ProxyHost extends Model {

View File

@@ -12,38 +12,37 @@
"validate-schema": "node validate-schema.js" "validate-schema": "node validate-schema.js"
}, },
"dependencies": { "dependencies": {
"@apidevtools/json-schema-ref-parser": "^14.1.1", "@apidevtools/json-schema-ref-parser": "^11.7.0",
"ajv": "^8.18.0", "ajv": "^8.17.1",
"archiver": "^7.0.1", "archiver": "^5.3.0",
"batchflow": "^0.4.0", "batchflow": "^0.4.0",
"bcrypt": "^6.0.0", "bcrypt": "^5.0.0",
"better-sqlite3": "^12.6.2", "body-parser": "^1.20.3",
"body-parser": "^2.2.2",
"compression": "^1.7.4", "compression": "^1.7.4",
"express": "^5.2.1", "express": "^4.22.0",
"express-fileupload": "^1.5.2", "express-fileupload": "^1.5.2",
"gravatar": "^1.8.2", "gravatar": "^1.8.2",
"jsonwebtoken": "^9.0.3", "jsonwebtoken": "^9.0.2",
"knex": "3.1.0", "knex": "2.4.2",
"liquidjs": "10.24.0", "liquidjs": "10.6.1",
"lodash": "^4.17.23", "lodash": "^4.17.21",
"moment": "^2.30.1", "moment": "^2.30.1",
"mysql2": "^3.17.1", "mysql2": "^3.15.3",
"node-rsa": "^1.1.1", "node-rsa": "^1.1.1",
"objection": "3.1.5", "objection": "3.0.1",
"otplib": "^13.3.0", "otplib": "^12.0.1",
"path": "^0.12.7", "path": "^0.12.7",
"pg": "^8.18.0", "pg": "^8.16.3",
"proxy-agent": "^6.5.0", "proxy-agent": "^6.5.0",
"signale": "1.4.0", "signale": "1.4.0",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"temp-write": "^4.0.0" "temp-write": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@apidevtools/swagger-parser": "^12.1.0", "@apidevtools/swagger-parser": "^10.1.0",
"@biomejs/biome": "^2.3.14", "@biomejs/biome": "^2.3.2",
"chalk": "5.6.2", "chalk": "4.1.2",
"nodemon": "^3.1.11" "nodemon": "^2.0.2"
}, },
"signale": { "signale": {
"displayDate": true, "displayDate": true,

View File

@@ -66,7 +66,16 @@ router
*/ */
.post(async (req, res, next) => { .post(async (req, res, next) => {
try { try {
const { challenge_token, code } = await apiValidator(getValidationSchema("/tokens/2fa", "post"), req.body); const { challenge_token, code } = req.body;
if (!challenge_token || !code) {
return res.status(400).json({
error: {
message: "Missing challenge_token or code",
},
});
}
const result = await internalToken.verify2FA(challenge_token, code); const result = await internalToken.verify2FA(challenge_token, code);
res.status(200).send(result); res.status(200).send(result);
} catch (err) { } catch (err) {

View File

@@ -339,21 +339,6 @@ router
.all(jwtdecode()) .all(jwtdecode())
.all(userIdFromMe) .all(userIdFromMe)
/**
* POST /api/users/123/2fa
*
* Start 2FA setup, returns QR code URL
*/
.post(async (req, res, next) => {
try {
const result = await internal2FA.startSetup(res.locals.access, req.params.user_id);
res.status(200).send(result);
} catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
})
/** /**
* GET /api/users/123/2fa * GET /api/users/123/2fa
* *
@@ -361,7 +346,15 @@ router
*/ */
.get(async (req, res, next) => { .get(async (req, res, next) => {
try { try {
const status = await internal2FA.getStatus(res.locals.access, req.params.user_id); const userId = Number.parseInt(req.params.user_id, 10);
const access = res.locals.access;
// Users can only view their own 2FA status
if (access.token.getUserId() !== userId && !access.token.hasScope("admin")) {
throw new errs.PermissionError("Cannot view 2FA status for other users");
}
const status = await internal2FA.getStatus(userId);
res.status(200).send(status); res.status(200).send(status);
} catch (err) { } catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
@@ -370,18 +363,63 @@ router
}) })
/** /**
* DELETE /api/users/123/2fa?code=XXXXXX * DELETE /api/users/123/2fa
* *
* Disable 2FA for a user * Disable 2FA for a user
*/ */
.delete(async (req, res, next) => { .delete(async (req, res, next) => {
try { try {
const code = typeof req.query.code === "string" ? req.query.code : null; const userId = Number.parseInt(req.params.user_id, 10);
if (!code) { const access = res.locals.access;
throw new errs.ValidationError("Missing required parameter: code");
// Users can only disable their own 2FA
if (access.token.getUserId() !== userId && !access.token.hasScope("admin")) {
throw new errs.PermissionError("Cannot disable 2FA for other users");
} }
await internal2FA.disable(res.locals.access, req.params.user_id, code);
res.status(200).send(true); const { code } = req.body;
if (!code) {
throw new errs.ValidationError("Verification code is required");
}
await internal2FA.disable(userId, code);
res.status(200).send({ success: true });
} catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
});
/**
* User 2FA setup
*
* /api/users/123/2fa/setup
*/
router
.route("/:user_id/2fa/setup")
.options((_, res) => {
res.sendStatus(204);
})
.all(jwtdecode())
.all(userIdFromMe)
/**
* POST /api/users/123/2fa/setup
*
* Start 2FA setup, returns QR code URL
*/
.post(async (req, res, next) => {
try {
const userId = Number.parseInt(req.params.user_id, 10);
const access = res.locals.access;
// Users can only setup their own 2FA
if (access.token.getUserId() !== userId) {
throw new errs.PermissionError("Cannot setup 2FA for other users");
}
const result = await internal2FA.startSetup(userId);
res.status(200).send(result);
} catch (err) { } catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err); next(err);
@@ -402,17 +440,26 @@ router
.all(userIdFromMe) .all(userIdFromMe)
/** /**
* POST /api/users/123/2fa/enable * PUT /api/users/123/2fa/enable
* *
* Verify code and enable 2FA * Verify code and enable 2FA
*/ */
.post(async (req, res, next) => { .put(async (req, res, next) => {
try { try {
const { code } = await apiValidator( const userId = Number.parseInt(req.params.user_id, 10);
getValidationSchema("/users/{userID}/2fa/enable", "post"), const access = res.locals.access;
req.body,
); // Users can only enable their own 2FA
const result = await internal2FA.enable(res.locals.access, req.params.user_id, code); if (access.token.getUserId() !== userId) {
throw new errs.PermissionError("Cannot enable 2FA for other users");
}
const { code } = req.body;
if (!code) {
throw new errs.ValidationError("Verification code is required");
}
const result = await internal2FA.enable(userId, code);
res.status(200).send(result); res.status(200).send(result);
} catch (err) { } catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
@@ -440,11 +487,20 @@ router
*/ */
.post(async (req, res, next) => { .post(async (req, res, next) => {
try { try {
const { code } = await apiValidator( const userId = Number.parseInt(req.params.user_id, 10);
getValidationSchema("/users/{userID}/2fa/backup-codes", "post"), const access = res.locals.access;
req.body,
); // Users can only regenerate their own backup codes
const result = await internal2FA.regenerateBackupCodes(res.locals.access, req.params.user_id, code); if (access.token.getUserId() !== userId) {
throw new errs.PermissionError("Cannot regenerate backup codes for other users");
}
const { code } = req.body;
if (!code) {
throw new errs.ValidationError("Verification code is required");
}
const result = await internal2FA.regenerateBackupCodes(userId, code);
res.status(200).send(result); res.status(200).send(result);
} catch (err) { } catch (err) {
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);

View File

@@ -22,8 +22,7 @@
"enabled", "enabled",
"locations", "locations",
"hsts_enabled", "hsts_enabled",
"hsts_subdomains", "hsts_subdomains"
"trust_forwarded_proto"
], ],
"properties": { "properties": {
"id": { "id": {
@@ -142,11 +141,6 @@
"hsts_subdomains": { "hsts_subdomains": {
"$ref": "../common.json#/properties/hsts_subdomains" "$ref": "../common.json#/properties/hsts_subdomains"
}, },
"trust_forwarded_proto":{
"type": "boolean",
"description": "Trust the forwarded headers",
"example": false
},
"certificate": { "certificate": {
"oneOf": [ "oneOf": [
{ {

View File

@@ -1,18 +0,0 @@
{
"type": "object",
"description": "Token object",
"required": ["requires_2fa", "challenge_token"],
"additionalProperties": false,
"properties": {
"requires_2fa": {
"description": "Whether this token request requires two-factor authentication",
"example": true,
"type": "boolean"
},
"challenge_token": {
"description": "Challenge Token used in subsequent 2FA verification",
"example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4",
"type": "string"
}
}
}

View File

@@ -58,8 +58,7 @@
"enabled": true, "enabled": true,
"locations": [], "locations": [],
"hsts_enabled": false, "hsts_enabled": false,
"hsts_subdomains": false, "hsts_subdomains": false
"trust_forwarded_proto": false
} }
] ]
} }

View File

@@ -56,7 +56,6 @@
"locations": [], "locations": [],
"hsts_enabled": false, "hsts_enabled": false,
"hsts_subdomains": false, "hsts_subdomains": false,
"trust_forwarded_proto": false,
"owner": { "owner": {
"id": 1, "id": 1,
"created_on": "2025-10-28T00:50:24.000Z", "created_on": "2025-10-28T00:50:24.000Z",

View File

@@ -56,9 +56,6 @@
"hsts_subdomains": { "hsts_subdomains": {
"$ref": "../../../../components/proxy-host-object.json#/properties/hsts_subdomains" "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_subdomains"
}, },
"trust_forwarded_proto": {
"$ref": "../../../../components/proxy-host-object.json#/properties/trust_forwarded_proto"
},
"http2_support": { "http2_support": {
"$ref": "../../../../components/proxy-host-object.json#/properties/http2_support" "$ref": "../../../../components/proxy-host-object.json#/properties/http2_support"
}, },
@@ -125,7 +122,6 @@
"locations": [], "locations": [],
"hsts_enabled": false, "hsts_enabled": false,
"hsts_subdomains": false, "hsts_subdomains": false,
"trust_forwarded_proto": false,
"owner": { "owner": {
"id": 1, "id": 1,
"created_on": "2025-10-28T00:50:24.000Z", "created_on": "2025-10-28T00:50:24.000Z",

View File

@@ -48,9 +48,6 @@
"hsts_subdomains": { "hsts_subdomains": {
"$ref": "../../../components/proxy-host-object.json#/properties/hsts_subdomains" "$ref": "../../../components/proxy-host-object.json#/properties/hsts_subdomains"
}, },
"trust_forwarded_proto": {
"$ref": "../../../components/proxy-host-object.json#/properties/trust_forwarded_proto"
},
"http2_support": { "http2_support": {
"$ref": "../../../components/proxy-host-object.json#/properties/http2_support" "$ref": "../../../components/proxy-host-object.json#/properties/http2_support"
}, },
@@ -122,7 +119,6 @@
"locations": [], "locations": [],
"hsts_enabled": false, "hsts_enabled": false,
"hsts_subdomains": false, "hsts_subdomains": false,
"trust_forwarded_proto": false,
"certificate": null, "certificate": null,
"owner": { "owner": {
"id": 1, "id": 1,

View File

@@ -1,55 +0,0 @@
{
"operationId": "loginWith2FA",
"summary": "Verify 2FA code and get full token",
"tags": ["tokens"],
"requestBody": {
"description": "2fa Challenge Payload",
"required": true,
"content": {
"application/json": {
"schema": {
"additionalProperties": false,
"properties": {
"challenge_token": {
"minLength": 1,
"type": "string",
"example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
},
"code": {
"minLength": 6,
"maxLength": 8,
"type": "string",
"example": "012345"
}
},
"required": ["challenge_token", "code"],
"type": "object"
},
"example": {
"challenge_token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4",
"code": "012345"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"expires": "2025-02-04T20:40:46.340Z",
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
}
}
},
"schema": {
"$ref": "../../../components/token-object.json"
}
}
},
"description": "200 response"
}
}
}

View File

@@ -50,14 +50,7 @@
} }
}, },
"schema": { "schema": {
"oneOf": [ "$ref": "../../components/token-object.json"
{
"$ref": "../../components/token-object.json"
},
{
"$ref": "../../components/token-challenge.json"
}
]
} }
} }
}, },

View File

@@ -1,92 +0,0 @@
{
"operationId": "regenUser2faCodes",
"summary": "Regenerate 2FA backup codes",
"tags": ["users"],
"parameters": [
{
"in": "path",
"name": "userID",
"schema": {
"type": "integer",
"minimum": 1
},
"required": true,
"description": "User ID",
"example": 2
}
],
"requestBody": {
"description": "Verification Payload",
"required": true,
"content": {
"application/json": {
"schema": {
"additionalProperties": false,
"properties": {
"code": {
"minLength": 6,
"maxLength": 8,
"type": "string",
"example": "123456"
}
},
"required": ["code"],
"type": "object"
},
"example": {
"code": "123456"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"backup_codes": [
"6CD7CB06",
"495302F3",
"D8037852",
"A6FFC956",
"BC1A1851",
"A05E644F",
"A406D2E8",
"0AE3C522"
]
}
}
},
"schema": {
"type": "object",
"required": ["backup_codes"],
"additionalProperties": false,
"properties": {
"backup_codes": {
"description": "Backup codes",
"example": [
"6CD7CB06",
"495302F3",
"D8037852",
"A6FFC956",
"BC1A1851",
"A05E644F",
"A406D2E8",
"0AE3C522"
],
"type": "array",
"items": {
"type": "string",
"example": "6CD7CB06"
}
}
}
}
}
},
"description": "200 response"
}
}
}

View File

@@ -1,48 +0,0 @@
{
"operationId": "disableUser2fa",
"summary": "Disable 2fa for user",
"tags": ["users"],
"parameters": [
{
"in": "path",
"name": "userID",
"schema": {
"type": "integer",
"minimum": 1
},
"required": true,
"description": "User ID",
"example": 2
},
{
"in": "query",
"name": "code",
"schema": {
"type": "string",
"minLength": 6,
"maxLength": 6,
"example": "012345"
},
"required": true,
"description": "2fa Code",
"example": "012345"
}
],
"responses": {
"200": {
"content": {
"application/json": {
"examples": {
"default": {
"value": true
}
},
"schema": {
"type": "boolean"
}
}
},
"description": "200 response"
}
}
}

View File

@@ -1,92 +0,0 @@
{
"operationId": "enableUser2fa",
"summary": "Verify code and enable 2FA",
"tags": ["users"],
"parameters": [
{
"in": "path",
"name": "userID",
"schema": {
"type": "integer",
"minimum": 1
},
"required": true,
"description": "User ID",
"example": 2
}
],
"requestBody": {
"description": "Verification Payload",
"required": true,
"content": {
"application/json": {
"schema": {
"additionalProperties": false,
"properties": {
"code": {
"minLength": 6,
"maxLength": 8,
"type": "string",
"example": "123456"
}
},
"required": ["code"],
"type": "object"
},
"example": {
"code": "123456"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"backup_codes": [
"6CD7CB06",
"495302F3",
"D8037852",
"A6FFC956",
"BC1A1851",
"A05E644F",
"A406D2E8",
"0AE3C522"
]
}
}
},
"schema": {
"type": "object",
"required": ["backup_codes"],
"additionalProperties": false,
"properties": {
"backup_codes": {
"description": "Backup codes",
"example": [
"6CD7CB06",
"495302F3",
"D8037852",
"A6FFC956",
"BC1A1851",
"A05E644F",
"A406D2E8",
"0AE3C522"
],
"type": "array",
"items": {
"type": "string",
"example": "6CD7CB06"
}
}
}
}
}
},
"description": "200 response"
}
}
}

View File

@@ -1,57 +0,0 @@
{
"operationId": "getUser2faStatus",
"summary": "Get user 2fa Status",
"tags": ["users"],
"security": [
{
"bearerAuth": []
}
],
"parameters": [
{
"in": "path",
"name": "userID",
"schema": {
"type": "integer",
"minimum": 1
},
"required": true,
"description": "User ID",
"example": 2
}
],
"responses": {
"200": {
"description": "200 response",
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"enabled": false,
"backup_codes_remaining": 0
}
}
},
"schema": {
"type": "object",
"additionalProperties": false,
"required": ["enabled", "backup_codes_remaining"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Is 2FA enabled for this user",
"example": true
},
"backup_codes_remaining": {
"type": "integer",
"description": "Number of remaining backup codes for this user",
"example": 5
}
}
}
}
}
}
}
}

View File

@@ -1,52 +0,0 @@
{
"operationId": "setupUser2fa",
"summary": "Start 2FA setup, returns QR code URL",
"tags": ["users"],
"parameters": [
{
"in": "path",
"name": "userID",
"schema": {
"type": "integer",
"minimum": 1
},
"required": true,
"description": "User ID",
"example": 2
}
],
"responses": {
"200": {
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"secret": "JZYCEBIEEJYUGPQM",
"otpauth_url": "otpauth://totp/Nginx%20Proxy%20Manager:jc%40jc21.com?secret=JZYCEBIEEJYUGPQM&period=30&digits=6&algorithm=SHA1&issuer=Nginx%20Proxy%20Manager"
}
}
},
"schema": {
"type": "object",
"required": ["secret", "otpauth_url"],
"additionalProperties": false,
"properties": {
"secret": {
"description": "TOTP Secret",
"example": "JZYCEBIEEJYUGPQM",
"type": "string"
},
"otpauth_url": {
"description": "OTP Auth URL for QR Code generation",
"example": "otpauth://totp/Nginx%20Proxy%20Manager:jc%40jc21.com?secret=JZYCEBIEEJYUGPQM&period=30&digits=6&algorithm=SHA1&issuer=Nginx%20Proxy%20Manager",
"type": "string"
}
}
}
}
},
"description": "200 response"
}
}
}

View File

@@ -293,11 +293,6 @@
"$ref": "./paths/tokens/post.json" "$ref": "./paths/tokens/post.json"
} }
}, },
"/tokens/2fa": {
"post": {
"$ref": "./paths/tokens/2fa/post.json"
}
},
"/version/check": { "/version/check": {
"get": { "get": {
"$ref": "./paths/version/check/get.json" "$ref": "./paths/version/check/get.json"
@@ -322,27 +317,6 @@
"$ref": "./paths/users/userID/delete.json" "$ref": "./paths/users/userID/delete.json"
} }
}, },
"/users/{userID}/2fa": {
"post": {
"$ref": "./paths/users/userID/2fa/post.json"
},
"get": {
"$ref": "./paths/users/userID/2fa/get.json"
},
"delete": {
"$ref": "./paths/users/userID/2fa/delete.json"
}
},
"/users/{userID}/2fa/enable": {
"post": {
"$ref": "./paths/users/userID/2fa/enable/post.json"
}
},
"/users/{userID}/2fa/backup-codes": {
"post": {
"$ref": "./paths/users/userID/2fa/backup-codes/post.json"
}
},
"/users/{userID}/auth": { "/users/{userID}/auth": {
"put": { "put": {
"$ref": "./paths/users/userID/auth/put.json" "$ref": "./paths/users/userID/auth/put.json"

View File

@@ -1,11 +1,6 @@
{% if certificate and certificate_id > 0 -%} {% if certificate and certificate_id > 0 -%}
{% if ssl_forced == 1 or ssl_forced == true %} {% if ssl_forced == 1 or ssl_forced == true %}
# Force SSL # Force SSL
{% if trust_forwarded_proto == true %}
set $trust_forwarded_proto "T";
{% else %}
set $trust_forwarded_proto "F";
{% endif %}
include conf.d/include/force-ssl.conf; include conf.d/include/force-ssl.conf;
{% endif %} {% endif %}
{% endif %} {% endif %}

File diff suppressed because it is too large Load Diff

View File

@@ -109,7 +109,7 @@ services:
- "cypress_logs:/test/results" - "cypress_logs:/test/results"
- "./dev/resolv.conf:/etc/resolv.conf:ro" - "./dev/resolv.conf:/etc/resolv.conf:ro"
- "/etc/localtime:/etc/localtime:ro" - "/etc/localtime:/etc/localtime:ro"
command: cypress run --browser chrome --config-file=cypress/config/ci.mjs command: cypress run --browser chrome --config-file=cypress/config/ci.js
networks: networks:
- fulltest - fulltest

View File

@@ -192,7 +192,7 @@ services:
- "../test/results:/results" - "../test/results:/results"
- "./dev/resolv.conf:/etc/resolv.conf:ro" - "./dev/resolv.conf:/etc/resolv.conf:ro"
- "/etc/localtime:/etc/localtime:ro" - "/etc/localtime:/etc/localtime:ro"
command: cypress run --browser chrome --config-file=cypress/config/ci.mjs command: cypress run --browser chrome --config-file=cypress/config/ci.js
networks: networks:
- nginx_proxy_manager - nginx_proxy_manager

View File

@@ -5,28 +5,6 @@ if ($scheme = "http") {
if ($request_uri = /.well-known/acme-challenge/test-challenge) { if ($request_uri = /.well-known/acme-challenge/test-challenge) {
set $test "${test}T"; set $test "${test}T";
} }
# Check if the ssl staff has been handled
set $test_ssl_handled "";
if ($trust_forwarded_proto = "") {
set $trust_forwarded_proto "F";
}
if ($trust_forwarded_proto = "T") {
set $test_ssl_handled "${test_ssl_handled}T";
}
if ($http_x_forwarded_proto = "https") {
set $test_ssl_handled "${test_ssl_handled}S";
}
if ($http_x_forwarded_scheme = "https") {
set $test_ssl_handled "${test_ssl_handled}S";
}
if ($test_ssl_handled = "TSS") {
set $test_ssl_handled "TS";
}
if ($test_ssl_handled = "TS") {
set $test "${test}S";
}
if ($test = H) { if ($test = H) {
return 301 https://$host$request_uri; return 301 https://$host$request_uri;
} }

View File

@@ -1,7 +1,7 @@
add_header X-Served-By $host; add_header X-Served-By $host;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $x_forwarded_scheme; proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_pass $forward_scheme://$server:$port$request_uri; proxy_pass $forward_scheme://$server:$port$request_uri;

View File

@@ -57,18 +57,6 @@ http {
default http; default http;
} }
# Handle upstream X-Forwarded-Proto and X-Forwarded-Scheme header
map $http_x_forwarded_proto $x_forwarded_proto {
"http" "http";
"https" "https";
default $scheme;
}
map $http_x_forwarded_scheme $x_forwarded_scheme {
"http" "http";
"https" "https";
default $scheme;
}
# Real IP Determination # Real IP Determination
# Local subnets: # Local subnets:

View File

@@ -17,6 +17,10 @@ case $TARGETPLATFORM in
S6_ARCH=aarch64 S6_ARCH=aarch64
;; ;;
linux/arm/v7)
S6_ARCH=armhf
;;
*) *)
S6_ARCH=x86_64 S6_ARCH=x86_64
;; ;;

View File

@@ -0,0 +1,176 @@
# Two-Factor Authentication Implementation
> **Note:** This document should be deleted after PR approval. It serves as a reference for reviewers to understand the scope of the contribution.
---
**Acknowledgments**
Thanks to all contributors and authors from the Inte.Team for the great work on Nginx Proxy Manager. It saves us time and effort, and we're happy to contribute back to the project.
---
## Overview
Add TOTP-based two-factor authentication to the login flow. Users can enable 2FA from their profile settings, scan a QR code with any authenticator app (Google Authenticator, Authy, etc.), and will be required to enter a 6-digit code on login.
## Current Authentication Flow
```
POST /tokens {identity, secret}
-> Validate user exists and is not disabled
-> Verify password against auth.secret
-> Return JWT token
```
## Proposed 2FA Flow
```
POST /tokens {identity, secret}
-> Validate user exists and is not disabled
-> Verify password against auth.secret
-> If 2FA enabled:
Return {requires_2fa: true, challenge_token: <short-lived JWT>}
-> Else:
Return {token: <JWT>, expires: <timestamp>}
POST /tokens/2fa {challenge_token, code}
-> Validate challenge_token
-> Verify TOTP code against user's secret
-> Return {token: <JWT>, expires: <timestamp>}
```
## Database Changes
Extend the existing `auth.meta` JSON column to store 2FA data:
```json
{
"totp_secret": "<encrypted-secret>",
"totp_enabled": true,
"totp_enabled_at": "<timestamp>",
"backup_codes": ["<hashed-code-1>", "<hashed-code-2>", ...]
}
```
No new tables required. The `auth.meta` column is already designed for this purpose.
## Backend Changes
### New Files
1. `backend/internal/2fa.js` - Core 2FA logic
- `generateSecret()` - Generate TOTP secret
- `generateQRCodeURL(user, secret)` - Generate otpauth URL
- `verifyCode(secret, code)` - Verify TOTP code
- `generateBackupCodes()` - Generate 8 backup codes
- `verifyBackupCode(user, code)` - Verify and consume backup code
2. `backend/routes/2fa.js` - 2FA management endpoints
- `GET /users/:id/2fa` - Get 2FA status
- `POST /users/:id/2fa/setup` - Start 2FA setup, return QR code
- `PUT /users/:id/2fa/enable` - Verify code and enable 2FA
- `DELETE /users/:id/2fa` - Disable 2FA (requires code)
- `GET /users/:id/2fa/backup-codes` - View remaining backup codes count
- `POST /users/:id/2fa/backup-codes` - Regenerate backup codes
### Modified Files
1. `backend/internal/token.js`
- Update `getTokenFromEmail()` to check for 2FA
- Add `verifyTwoFactorChallenge()` function
- Add `createChallengeToken()` for short-lived 2FA tokens
2. `backend/routes/tokens.js`
- Add `POST /tokens/2fa` endpoint
3. `backend/index.js`
- Register new 2FA routes
### Dependencies
Add to `package.json`:
```json
"otplib": "^12.0.1"
```
## Frontend Changes
### New Files
1. `frontend/src/pages/Login2FA/index.tsx` - 2FA code entry page
2. `frontend/src/modals/TwoFactorSetupModal.tsx` - Setup wizard modal
3. `frontend/src/api/backend/twoFactor.ts` - 2FA API functions
4. `frontend/src/api/backend/verify2FA.ts` - Token verification
### Modified Files
1. `frontend/src/api/backend/responseTypes.ts`
- Add `TwoFactorChallengeResponse` type
- Add `TwoFactorStatusResponse` type
2. `frontend/src/context/AuthContext.tsx`
- Add `twoFactorRequired` state
- Add `challengeToken` state
- Update `login()` to handle 2FA response
- Add `verify2FA()` function
3. `frontend/src/pages/Login/index.tsx`
- Handle 2FA challenge response
- Redirect to 2FA entry when required
4. `frontend/src/pages/Settings/` (or user profile)
- Add 2FA enable/disable section
### Dependencies
Add to `package.json`:
```json
"qrcode.react": "^3.1.0"
```
## API Endpoints Summary
| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | /tokens | No | Login (returns challenge if 2FA) |
| POST | /tokens/2fa | Challenge | Complete 2FA login |
| GET | /users/:id/2fa | JWT | Get 2FA status |
| POST | /users/:id/2fa/setup | JWT | Start setup, get QR code |
| PUT | /users/:id/2fa/enable | JWT | Verify and enable |
| DELETE | /users/:id/2fa | JWT | Disable (requires code) |
| GET | /users/:id/2fa/backup-codes | JWT | Get backup codes count |
| POST | /users/:id/2fa/backup-codes | JWT | Regenerate codes |
## Security Considerations
1. Challenge tokens expire in 5 minutes
2. TOTP secrets encrypted at rest
3. Backup codes hashed with bcrypt
4. Rate limit on 2FA attempts (5 attempts, 15 min lockout)
5. Backup codes single-use only
6. 2FA disable requires valid TOTP code
## Implementation Order
1. Backend: Add `otplib` dependency
2. Backend: Create `internal/2fa.js` module
3. Backend: Update `internal/token.js` for challenge flow
4. Backend: Add `POST /tokens/2fa` route
5. Backend: Create `routes/2fa.js` for management
6. Frontend: Add `qrcode.react` dependency
7. Frontend: Update API types and functions
8. Frontend: Update AuthContext for 2FA state
9. Frontend: Create Login2FA page
10. Frontend: Update Login to handle 2FA
11. Frontend: Add 2FA settings UI
## Testing
1. Enable 2FA for user
2. Login with password only - should get challenge
3. Submit correct TOTP - should get token
4. Submit wrong TOTP - should fail
5. Use backup code - should work once
6. Disable 2FA - should require valid code
7. Login after disable - should work without 2FA

View File

@@ -169,11 +169,7 @@ Custom Postgres schema is not supported, as such `public` will be used.
The docker images support the following architectures: The docker images support the following architectures:
- amd64 - amd64
- arm64 - arm64
- armv7
::: warning
`armv7` is no longer supported in version 2.14+. This is due to Nodejs dropping support for armhf. Please
use the `2.13.7` image tag if this applies to you.
:::
The docker images are a manifest of all the architecture docker builds supported, so this means The docker images are a manifest of all the architecture docker builds supported, so this means
you don't have to worry about doing anything special and you can follow the common instructions above. you don't have to worry about doing anything special and you can follow the common instructions above.

View File

@@ -1,5 +1,5 @@
{ {
"$schema": "https://biomejs.dev/schemas/2.3.14/schema.json", "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json",
"vcs": { "vcs": {
"enabled": true, "enabled": true,
"clientKind": "git", "clientKind": "git",

View File

@@ -7,28 +7,25 @@
// - Also checks the error messages returned by the backend // - Also checks the error messages returned by the backend
const allLocales = [ const allLocales = [
["en", "en-US"], ["en", "en-US"],
["de", "de-DE"], ["de", "de-DE"],
["pt", "pt-PT"], ["es", "es-ES"],
["es", "es-ES"], ["it", "it-IT"],
["fr", "fr-FR"], ["ja", "ja-JP"],
["it", "it-IT"], ["nl", "nl-NL"],
["ja", "ja-JP"], ["pl", "pl-PL"],
["nl", "nl-NL"], ["ru", "ru-RU"],
["pl", "pl-PL"], ["sk", "sk-SK"],
["ru", "ru-RU"], ["vi", "vi-VN"],
["sk", "sk-SK"], ["zh", "zh-CN"],
["cs", "cs-CZ"], ["ko", "ko-KR"],
["vi", "vi-VN"], ["bg", "bg-BG"],
["zh", "zh-CN"], ["id", "id-ID"],
["ko", "ko-KR"],
["bg", "bg-BG"],
["id", "id-ID"],
["tr", "tr-TR"],
["hu", "hu-HU"],
]; ];
const ignoreUnused = [/^.*$/]; const ignoreUnused = [
/^.*$/,
];
const { spawnSync } = require("child_process"); const { spawnSync } = require("child_process");
const fs = require("fs"); const fs = require("fs");
@@ -69,95 +66,105 @@ const allWarnings = [];
const allKeys = []; const allKeys = [];
const checkLangList = (fullCode) => { const checkLangList = (fullCode) => {
const key = "locale-" + fullCode; const key = "locale-" + fullCode;
if (typeof langList[key] === "undefined") { if (typeof langList[key] === "undefined") {
allErrors.push("ERROR: `" + key + "` language does not exist in lang-list.json"); allErrors.push(
} "ERROR: `" + key + "` language does not exist in lang-list.json",
);
}
}; };
const compareLocale = (locale) => { const compareLocale = (locale) => {
const projectLocaleKeys = Object.keys(allLocalesInProject); const projectLocaleKeys = Object.keys(allLocalesInProject);
// Check that locale contains the items used in the codebase // Check that locale contains the items used in the codebase
projectLocaleKeys.map((key) => { projectLocaleKeys.map((key) => {
if (typeof locale.data[key] === "undefined") { if (typeof locale.data[key] === "undefined") {
allErrors.push("ERROR: `" + locale[0] + "` does not contain item: `" + key + "`"); allErrors.push(
} "ERROR: `" + locale[0] + "` does not contain item: `" + key + "`",
return null; );
}); }
// Check that locale contains all error.* items return null;
BACKEND_ERRORS.forEach((key) => { });
if (typeof locale.data[key] === "undefined") { // Check that locale contains all error.* items
allErrors.push("ERROR: `" + locale[0] + "` does not contain item: `" + key + "`"); BACKEND_ERRORS.forEach((key) => {
} if (typeof locale.data[key] === "undefined") {
return null; allErrors.push(
}); "ERROR: `" + locale[0] + "` does not contain item: `" + key + "`",
);
}
return null;
});
// Check that locale does not contain items not used in the codebase // Check that locale does not contain items not used in the codebase
const localeKeys = Object.keys(locale.data); const localeKeys = Object.keys(locale.data);
localeKeys.map((key) => { localeKeys.map((key) => {
let ignored = false; let ignored = false;
ignoreUnused.map((regex) => { ignoreUnused.map((regex) => {
if (key.match(regex)) { if (key.match(regex)) {
ignored = true; ignored = true;
} }
return null; return null;
}); });
if (!ignored && typeof allLocalesInProject[key] === "undefined") { if (!ignored && typeof allLocalesInProject[key] === "undefined") {
// ensure this key doesn't exist in the backend errors either // ensure this key doesn't exist in the backend errors either
if (!BACKEND_ERRORS.includes(key)) { if (!BACKEND_ERRORS.includes(key)) {
allErrors.push("ERROR: `" + locale[0] + "` contains unused item: `" + key + "`"); allErrors.push(
} "ERROR: `" + locale[0] + "` contains unused item: `" + key + "`",
} );
}
}
// Add this key to allKeys // Add this key to allKeys
if (allKeys.indexOf(key) === -1) { if (allKeys.indexOf(key) === -1) {
allKeys.push(key); allKeys.push(key);
} }
return null; return null;
}); });
}; };
// Checks for any keys missing from this locale, that // Checks for any keys missing from this locale, that
// have been defined in any other locales // have been defined in any other locales
const checkForMissing = (locale) => { const checkForMissing = (locale) => {
allKeys.forEach((key) => { allKeys.forEach((key) => {
if (typeof locale.data[key] === "undefined") { if (typeof locale.data[key] === "undefined") {
allWarnings.push("WARN: `" + locale[0] + "` does not contain item: `" + key + "`"); allWarnings.push(
} "WARN: `" + locale[0] + "` does not contain item: `" + key + "`",
return null; );
}); }
return null;
});
}; };
// Local all locale data // Local all locale data
allLocales.map((locale, idx) => { allLocales.map((locale, idx) => {
checkLangList(locale[1]); checkLangList(locale[1]);
allLocales[idx].data = require("./src/locale/src/" + locale[0] + ".json"); allLocales[idx].data = require("./src/locale/src/" + locale[0] + ".json");
return null; return null;
}); });
// Verify all locale data // Verify all locale data
allLocales.map((locale) => { allLocales.map((locale) => {
compareLocale(locale); compareLocale(locale);
checkForMissing(locale); checkForMissing(locale);
return null; return null;
}); });
if (allErrors.length) { if (allErrors.length) {
allErrors.map((err) => { allErrors.map((err) => {
console.log("\x1b[31m%s\x1b[0m", err); console.log("\x1b[31m%s\x1b[0m", err);
return null; return null;
}); });
} }
if (allWarnings.length) { if (allWarnings.length) {
allWarnings.map((err) => { allWarnings.map((err) => {
console.log("\x1b[33m%s\x1b[0m", err); console.log("\x1b[33m%s\x1b[0m", err);
return null; return null;
}); });
} }
if (allErrors.length) { if (allErrors.length) {
process.exit(1); process.exit(1);
} }
console.log("\x1b[32m%s\x1b[0m", "Locale check passed"); console.log("\x1b[32m%s\x1b[0m", "Locale check passed");

View File

@@ -17,50 +17,50 @@
}, },
"dependencies": { "dependencies": {
"@tabler/core": "^1.4.0", "@tabler/core": "^1.4.0",
"@tabler/icons-react": "^3.36.1", "@tabler/icons-react": "^3.35.0",
"@tanstack/react-query": "^5.90.21", "@tanstack/react-query": "^5.90.6",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@uiw/react-textarea-code-editor": "^3.1.1", "@uiw/react-textarea-code-editor": "^3.1.1",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"country-flag-icons": "^1.6.13", "country-flag-icons": "^1.5.21",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"ez-modal-react": "^1.0.5", "ez-modal-react": "^1.0.5",
"formik": "^2.4.9", "formik": "^2.4.6",
"generate-password-browser": "^1.1.0", "generate-password-browser": "^1.1.0",
"humps": "^2.0.1", "humps": "^2.0.1",
"query-string": "^9.3.1", "query-string": "^9.3.1",
"react": "^19.2.4", "react": "^19.2.3",
"react-bootstrap": "^2.10.10", "react-bootstrap": "^2.10.10",
"react-dom": "^19.2.4", "react-dom": "^19.2.3",
"react-intl": "^8.1.3", "react-intl": "^7.1.14",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-router-dom": "^7.13.0", "react-router-dom": "^7.9.5",
"react-select": "^5.10.2", "react-select": "^5.10.2",
"react-toastify": "^11.0.5", "react-toastify": "^11.0.5",
"rooks": "^9.5.0" "rooks": "^9.3.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.4.2", "@biomejs/biome": "^2.3.2",
"@formatjs/cli": "^6.12.2", "@formatjs/cli": "^6.7.4",
"@tanstack/react-query-devtools": "^5.91.3", "@tanstack/react-query-devtools": "^5.90.2",
"@testing-library/dom": "^10.4.1", "@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2", "@testing-library/react": "^16.3.0",
"@types/country-flag-icons": "^1.2.2", "@types/country-flag-icons": "^1.2.2",
"@types/humps": "^2.0.6", "@types/humps": "^2.0.6",
"@types/react": "^19.2.14", "@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/react-table": "^7.7.20", "@types/react-table": "^7.7.20",
"@vitejs/plugin-react": "^5.1.4", "@vitejs/plugin-react": "^5.1.2",
"happy-dom": "^20.6.1", "happy-dom": "^20.0.10",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"postcss-simple-vars": "^7.0.1", "postcss-simple-vars": "^7.0.1",
"sass": "^1.97.3", "sass": "^1.93.3",
"tmp": "^0.2.5", "tmp": "^0.2.5",
"typescript": "5.9.3", "typescript": "5.9.3",
"vite": "^7.3.1", "vite": "^7.1.12",
"vite-plugin-checker": "^0.12.0", "vite-plugin-checker": "^0.11.0",
"vite-tsconfig-paths": "^6.1.1", "vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.18" "vitest": "^4.0.6"
} }
} }

View File

@@ -156,6 +156,7 @@ export async function del({ url, params }: DeleteArgs, abortController?: AbortCo
const method = "DELETE"; const method = "DELETE";
const headers = { const headers = {
...buildAuthHeader(), ...buildAuthHeader(),
[contentTypeHeader]: "application/json",
}; };
const signal = abortController?.signal; const signal = abortController?.signal;
const response = await fetch(apiUrl, { method, headers, signal }); const response = await fetch(apiUrl, { method, headers, signal });

View File

@@ -127,7 +127,6 @@ export interface ProxyHost {
locations?: ProxyLocation[]; locations?: ProxyLocation[];
hstsEnabled: boolean; hstsEnabled: boolean;
hstsSubdomains: boolean; hstsSubdomains: boolean;
trustForwardedProto: boolean;
// Expansions: // Expansions:
owner?: User; owner?: User;
accessList?: AccessList; accessList?: AccessList;

View File

@@ -1,5 +1,11 @@
import { camelizeKeys, decamelizeKeys } from "humps";
import AuthStore from "src/modules/AuthStore";
import type {
TwoFactorEnableResponse,
TwoFactorSetupResponse,
TwoFactorStatusResponse,
} from "./responseTypes";
import * as api from "./base"; import * as api from "./base";
import type { TwoFactorEnableResponse, TwoFactorSetupResponse, TwoFactorStatusResponse } from "./responseTypes";
export async function get2FAStatus(userId: number | "me"): Promise<TwoFactorStatusResponse> { export async function get2FAStatus(userId: number | "me"): Promise<TwoFactorStatusResponse> {
return await api.get({ return await api.get({
@@ -9,27 +15,42 @@ export async function get2FAStatus(userId: number | "me"): Promise<TwoFactorStat
export async function start2FASetup(userId: number | "me"): Promise<TwoFactorSetupResponse> { export async function start2FASetup(userId: number | "me"): Promise<TwoFactorSetupResponse> {
return await api.post({ return await api.post({
url: `/users/${userId}/2fa`, url: `/users/${userId}/2fa/setup`,
}); });
} }
export async function enable2FA(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> { export async function enable2FA(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> {
return await api.post({ return await api.put({
url: `/users/${userId}/2fa/enable`, url: `/users/${userId}/2fa/enable`,
data: { code }, data: { code },
}); });
} }
export async function disable2FA(userId: number | "me", code: string): Promise<boolean> { export async function disable2FA(userId: number | "me", code: string): Promise<{ success: boolean }> {
return await api.del({ const headers: Record<string, string> = {
url: `/users/${userId}/2fa`, "Content-Type": "application/json",
params: { };
code, if (AuthStore.token) {
}, headers.Authorization = `Bearer ${AuthStore.token.token}`;
}
const response = await fetch(`/api/users/${userId}/2fa`, {
method: "DELETE",
headers,
body: JSON.stringify(decamelizeKeys({ code })),
}); });
const payload = await response.json();
if (!response.ok) {
throw new Error(payload.error?.messageI18n || payload.error?.message || "Failed to disable 2FA");
}
return camelizeKeys(payload) as { success: boolean };
} }
export async function regenerateBackupCodes(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> { export async function regenerateBackupCodes(
userId: number | "me",
code: string,
): Promise<TwoFactorEnableResponse> {
return await api.post({ return await api.post({
url: `/users/${userId}/2fa/backup-codes`, url: `/users/${userId}/2fa/backup-codes`,
data: { code }, data: { code },

View File

@@ -5,18 +5,17 @@ import { T } from "src/locale";
interface Props { interface Props {
forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields
forProxyHost?: boolean; // the advanced fields
forceDNSForNew?: boolean; forceDNSForNew?: boolean;
requireDomainNames?: boolean; // used for streams requireDomainNames?: boolean; // used for streams
color?: string; color?: string;
} }
export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDNSForNew, requireDomainNames, color = "bg-cyan" }: Props) { export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomainNames, color = "bg-cyan" }: Props) {
const { values, setFieldValue } = useFormikContext(); const { values, setFieldValue } = useFormikContext();
const v: any = values || {}; const v: any = values || {};
const newCertificate = v?.certificateId === "new"; const newCertificate = v?.certificateId === "new";
const hasCertificate = newCertificate || (v?.certificateId && v?.certificateId > 0); const hasCertificate = newCertificate || (v?.certificateId && v?.certificateId > 0);
const { sslForced, http2Support, hstsEnabled, hstsSubdomains, trustForwardedProto, meta } = v; const { sslForced, http2Support, hstsEnabled, hstsSubdomains, meta } = v;
const { dnsChallenge } = meta || {}; const { dnsChallenge } = meta || {};
if (forceDNSForNew && newCertificate && !dnsChallenge) { if (forceDNSForNew && newCertificate && !dnsChallenge) {
@@ -116,34 +115,6 @@ export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDN
</div> </div>
); );
const getHttpAdvancedOptions = () =>(
<div>
<details>
<summary className="mb-1"><T id="domains.advanced" /></summary>
<div className="row">
<div className="col-12">
<Field name="trustForwardedProto">
{({ field }: any) => (
<label className="form-check form-switch mt-1">
<input
className={trustForwardedProto ? toggleEnabled : toggleClasses}
type="checkbox"
checked={!!trustForwardedProto}
onChange={(e) => handleToggleChange(e, field.name)}
disabled={!hasCertificate || !sslForced}
/>
<span className="form-check-label">
<T id="domains.trust-forwarded-proto" />
</span>
</label>
)}
</Field>
</div>
</div>
</details>
</div>
);
return ( return (
<div> <div>
{forHttp ? getHttpOptions() : null} {forHttp ? getHttpOptions() : null}
@@ -169,7 +140,6 @@ export function SSLOptionsFields({ forHttp = true, forProxyHost = false, forceDN
{dnsChallenge ? <DNSProviderFields showBoundaryBox /> : null} {dnsChallenge ? <DNSProviderFields showBoundaryBox /> : null}
</> </>
) : null} ) : null}
{forProxyHost && forHttp ? getHttpAdvancedOptions() : null}
</div> </div>
); );
} }

View File

@@ -24,7 +24,6 @@ const fetchProxyHost = (id: number | "new") => {
enabled: true, enabled: true,
hstsEnabled: false, hstsEnabled: false,
hstsSubdomains: false, hstsSubdomains: false,
trustForwardedProto: false,
} as ProxyHost); } as ProxyHost);
} }
return getProxyHost(id, ["owner"]); return getProxyHost(id, ["owner"]);

View File

@@ -1,94 +1,81 @@
import { createIntl, createIntlCache } from "react-intl"; import { createIntl, createIntlCache } from "react-intl";
import langBg from "./lang/bg.json";
import langDe from "./lang/de.json"; import langDe from "./lang/de.json";
import langPt from "./lang/pt.json";
import langEn from "./lang/en.json"; import langEn from "./lang/en.json";
import langEs from "./lang/es.json"; import langEs from "./lang/es.json";
import langFr from "./lang/fr.json";
import langGa from "./lang/ga.json";
import langId from "./lang/id.json";
import langIt from "./lang/it.json"; import langIt from "./lang/it.json";
import langJa from "./lang/ja.json"; import langJa from "./lang/ja.json";
import langKo from "./lang/ko.json"; import langList from "./lang/lang-list.json";
import langNl from "./lang/nl.json"; import langNl from "./lang/nl.json";
import langPl from "./lang/pl.json"; import langPl from "./lang/pl.json";
import langRu from "./lang/ru.json"; import langRu from "./lang/ru.json";
import langSk from "./lang/sk.json"; import langSk from "./lang/sk.json";
import langCs from "./lang/cs.json";
import langVi from "./lang/vi.json"; import langVi from "./lang/vi.json";
import langZh from "./lang/zh.json"; import langZh from "./lang/zh.json";
import langTr from "./lang/tr.json"; import langKo from "./lang/ko.json";
import langHu from "./lang/hu.json"; import langBg from "./lang/bg.json";
import langList from "./lang/lang-list.json"; import langId from "./lang/id.json";
// first item of each array should be the language code, // first item of each array should be the language code,
// not the country code // not the country code
// Remember when adding to this list, also update check-locales.js script // Remember when adding to this list, also update check-locales.js script
const localeOptions = [ const localeOptions = [
["en", "en-US", langEn], ["en", "en-US", langEn],
["de", "de-DE", langDe], ["de", "de-DE", langDe],
["es", "es-ES", langEs], ["es", "es-ES", langEs],
["pt", "pt-PT", langPt], ["ja", "ja-JP", langJa],
["fr", "fr-FR", langFr], ["it", "it-IT", langIt],
["ga", "ga-IE", langGa], ["nl", "nl-NL", langNl],
["ja", "ja-JP", langJa], ["pl", "pl-PL", langPl],
["it", "it-IT", langIt], ["ru", "ru-RU", langRu],
["nl", "nl-NL", langNl], ["sk", "sk-SK", langSk],
["pl", "pl-PL", langPl], ["vi", "vi-VN", langVi],
["ru", "ru-RU", langRu], ["zh", "zh-CN", langZh],
["sk", "sk-SK", langSk], ["ko", "ko-KR", langKo],
["cs", "cs-CZ", langCs], ["bg", "bg-BG", langBg],
["vi", "vi-VN", langVi], ["id", "id-ID", langId],
["zh", "zh-CN", langZh],
["ko", "ko-KR", langKo],
["bg", "bg-BG", langBg],
["id", "id-ID", langId],
["tr", "tr-TR", langTr],
["hu", "hu-HU", langHu],
]; ];
const loadMessages = (locale?: string): typeof langList & typeof langEn => { const loadMessages = (locale?: string): typeof langList & typeof langEn => {
const thisLocale = (locale || "en").slice(0, 2); const thisLocale = (locale || "en").slice(0, 2);
// ensure this lang exists in localeOptions above, otherwise fallback to en // ensure this lang exists in localeOptions above, otherwise fallback to en
if (thisLocale === "en" || !localeOptions.some(([code]) => code === thisLocale)) { if (thisLocale === "en" || !localeOptions.some(([code]) => code === thisLocale)) {
return Object.assign({}, langList, langEn); return Object.assign({}, langList, langEn);
} }
return Object.assign({}, langList, langEn, localeOptions.find(([code]) => code === thisLocale)?.[2]); return Object.assign({}, langList, langEn, localeOptions.find(([code]) => code === thisLocale)?.[2]);
}; };
const getFlagCodeForLocale = (locale?: string) => { const getFlagCodeForLocale = (locale?: string) => {
const thisLocale = (locale || "en").slice(0, 2); const thisLocale = (locale || "en").slice(0, 2);
// only add to this if your flag is different from the locale code // only add to this if your flag is different from the locale code
const specialCases: Record<string, string> = { const specialCases: Record<string, string> = {
ja: "jp", // Japan ja: "jp", // Japan
zh: "cn", // China zh: "cn", // China
vi: "vn", // Vietnam vi: "vn", // Vietnam
ko: "kr", // Korea ko: "kr", // Korea
cs: "cz", // Czechia };
};
if (specialCases[thisLocale]) { if (specialCases[thisLocale]) {
return specialCases[thisLocale].toUpperCase(); return specialCases[thisLocale].toUpperCase();
} }
return thisLocale.toUpperCase(); return thisLocale.toUpperCase();
}; };
const getLocale = (short = false) => { const getLocale = (short = false) => {
let loc = window.localStorage.getItem("locale"); let loc = window.localStorage.getItem("locale");
if (!loc) { if (!loc) {
loc = document.documentElement.lang; loc = document.documentElement.lang;
} }
if (short) { if (short) {
return loc.slice(0, 2); return loc.slice(0, 2);
} }
// finally, fallback // finally, fallback
if (!loc) { if (!loc) {
loc = "en"; loc = "en";
} }
return loc; return loc;
}; };
const cache = createIntlCache(); const cache = createIntlCache();
@@ -97,43 +84,43 @@ const initialMessages = loadMessages(getLocale());
let intl = createIntl({ locale: getLocale(), messages: initialMessages }, cache); let intl = createIntl({ locale: getLocale(), messages: initialMessages }, cache);
const changeLocale = (locale: string): void => { const changeLocale = (locale: string): void => {
const messages = loadMessages(locale); const messages = loadMessages(locale);
intl = createIntl({ locale, messages }, cache); intl = createIntl({ locale, messages }, cache);
window.localStorage.setItem("locale", locale); window.localStorage.setItem("locale", locale);
document.documentElement.lang = locale; document.documentElement.lang = locale;
}; };
// This is a translation component that wraps the translation in a span with a data // This is a translation component that wraps the translation in a span with a data
// attribute so devs can inspect the element to see the translation ID // attribute so devs can inspect the element to see the translation ID
const T = ({ const T = ({
id, id,
data, data,
tData, tData,
}: { }: {
id: string; id: string;
data?: Record<string, string | number | undefined>; data?: Record<string, string | number | undefined>;
tData?: Record<string, string>; tData?: Record<string, string>;
}) => { }) => {
const translatedData: Record<string, string> = {}; const translatedData: Record<string, string> = {};
if (tData) { if (tData) {
// iterate over tData and translate each value // iterate over tData and translate each value
Object.entries(tData).forEach(([key, value]) => { Object.entries(tData).forEach(([key, value]) => {
translatedData[key] = intl.formatMessage({ id: value }); translatedData[key] = intl.formatMessage({ id: value });
}); });
} }
return ( return (
<span data-translation-id={id}> <span data-translation-id={id}>
{intl.formatMessage( {intl.formatMessage(
{ id }, { id },
{ {
...data, ...data,
...translatedData, ...translatedData,
}, },
)} )}
</span> </span>
); );
}; };
//console.log("L:", localeOptions); console.log("L:", localeOptions);
export { localeOptions, getFlagCodeForLocale, getLocale, createIntl, changeLocale, intl, T }; export { localeOptions, getFlagCodeForLocale, getLocale, createIntl, changeLocale, intl, T };

View File

@@ -1,69 +0,0 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const DIR = path.resolve(__dirname, "../src");
// Function to sort object keys recursively
function sortKeys(obj) {
if (obj === null || typeof obj !== "object" || obj instanceof Array) {
return obj;
}
const sorted = {};
const keys = Object.keys(obj).sort();
for (const key of keys) {
const value = obj[key];
if (typeof value === "object" && value !== null && !(value instanceof Array)) {
sorted[key] = sortKeys(value);
} else {
sorted[key] = value;
}
}
return sorted;
}
// Get all JSON files in the directory
const files = fs.readdirSync(DIR).filter((file) => {
return file.endsWith(".json") && file !== "lang-list.json";
});
files.forEach((file) => {
const filePath = path.join(DIR, file);
const stats = fs.statSync(filePath);
if (!stats.isFile()) {
return;
}
if (stats.size === 0) {
console.log(`Skipping empty file ${file}`);
return;
}
try {
// Read original content
const originalContent = fs.readFileSync(filePath, "utf8");
const originalJson = JSON.parse(originalContent);
// Sort keys
const sortedJson = sortKeys(originalJson);
// Convert back to string with tabs
const sortedContent = JSON.stringify(sortedJson, null, "\t") + "\n";
// Compare (normalize whitespace)
if (originalContent.trim() === sortedContent.trim()) {
console.log(`${file} is already sorted`);
return;
}
// Write sorted content
fs.writeFileSync(filePath, sortedContent, "utf8");
console.log(`Sorted ${file}`);
} catch (error) {
console.error(`Error processing ${file}:`, error.message);
}
});

View File

@@ -1,7 +0,0 @@
## Co je seznam přístupů?
Seznamy přístupů poskytují blacklist nebo whitelist konkrétních IP adres klientů spolu s ověřením pro proxy hostitele prostřednictvím základního ověřování HTTP.
Můžete nakonfigurovat více pravidel pro klienty, uživatelská jména a hesla pro jeden seznam přístupu a poté ho použít na jednoho nebo více proxy hostitelů.
Toto je nejužitečnější pro přesměrované webové služby, které nemají vestavěné ověřovací mechanismy, nebo pokud se chcete chránit před neznámými klienty.

View File

@@ -1,32 +0,0 @@
## Pomoc s certifikáty
### Certifikát HTTP
Certifikát ověřený prostřednictvím protokolu HTTP znamená, že servery Let's Encrypt se
pokusí připojit k vašim doménám přes protokol HTTP (nikoli HTTPS!) a v případě úspěchu
vydají váš certifikát.
Pro tuto metodu budete muset mít pro své domény vytvořeného _Proxy Host_, který
je přístupný přes HTTP a směruje na tuto instalaci Nginx. Po vydání certifikátu
můžete změnit _Proxy Host_ tak, aby tento certifikát používal i pro HTTPS
připojení. _Proxy Host_ však bude stále potřeba nakonfigurovat pro přístup přes HTTP,
aby se certifikát mohl obnovit.
Tento proces _nepodporuje_ domény se zástupnými znaky.
### Certifikát DNS
Certifikát ověřený DNS vyžaduje použití pluginu DNS Provider. Tento DNS
Provider se použije na vytvoření dočasných záznamů ve vaší doméně a poté Let's
Encrypt ověří tyto záznamy, aby se ujistil, že jste vlastníkem, a pokud bude úspěšný,
vydá váš certifikát.
Před požádáním o tento typ certifikátu není potřeba vytvořit _Proxy Host_.
Není také potřeba mít _Proxy Host_ nakonfigurovaný pro přístup HTTP.
Tento proces _podporuje_ domény se zástupnými znaky.
### Vlastní certifikát
Tuto možnost použijte na nahrání vlastního SSL certifikátu, který vám poskytla vaše
certifikační autorita.

View File

@@ -1,10 +0,0 @@
## Co je to 404 Host?
404 Host je jednoduše nastavení hostitele, které zobrazuje stránku 404.
To může být užitečné, pokud je vaše doména uvedena ve vyhledávačích a chcete
poskytnout hezčí chybovou stránku nebo konkrétně oznámit vyhledávačům, že
stránky domény již neexistují.
Další výhodou tohoto hostitele je sledování protokolů o návštěvách a
zobrazení odkazů.

View File

@@ -1,7 +0,0 @@
## Co je proxy hostitel?
Proxy hostitel je příchozí koncový bod pro webovou službu, kterou chcete přesměrovat.
Poskytuje volitelné ukončení SSL pro vaši službu, která nemusí mít zabudovanou podporu SSL.
Proxy hostitelé jsou nejběžnějším použitím pro Nginx Proxy Manager.

View File

@@ -1,7 +0,0 @@
## Co je přesměrovací hostitel?
Přesměrovací hostitel přesměruje požadavky z příchozí domény a přesměruje
návštěvníka na jinou doménu.
Nejčastějším důvodem pro použití tohoto typu hostitele je situace, kdy vaše webová stránka změní
doménu, ale stále máte odkazy ve vyhledávačích nebo referenční odkazy směřující na starou doménu.

View File

@@ -1,6 +0,0 @@
## Co je stream?
Stream je relativně nová funkce pro Nginx, která slouží na přesměrování TCP/UDP
datového toku přímo do jiného počítače v síti.
Pokud provozujete herní servery, FTP nebo SSH servery, tato funkce se vám může hodit.

View File

@@ -1,6 +0,0 @@
export * as AccessLists from "./AccessLists.md";
export * as Certificates from "./Certificates.md";
export * as DeadHosts from "./DeadHosts.md";
export * as ProxyHosts from "./ProxyHosts.md";
export * as RedirectionHosts from "./RedirectionHosts.md";
export * as Streams from "./Streams.md";

View File

@@ -1,7 +0,0 @@
## Qu'est-ce qu'une liste d'accès ?
Les listes d'accès permettent de définir une liste noire ou une liste blanche d'adresses IP clientes spécifiques, ainsi que l'authentification des Hôtes Proxy via l'authentification HTTP de base.
Vous pouvez configurer plusieurs règles client, noms d'utilisateur et mots de passe pour une même liste d'accès, puis l'appliquer à un ou plusieurs Hôtes Proxy.
Ceci est particulièrement utile pour les services web redirigés qui ne disposent pas de mécanismes d'authentification intégrés ou lorsque vous souhaitez vous protéger contre les clients inconnus.

View File

@@ -1,23 +0,0 @@
## Aide concernant les certificats
### Certificat HTTP
Un certificat HTTP validé signifie que les serveurs de Let's Encrypt testeront d'accéder à vos domaines via HTTP (et non HTTPS !). En cas de succès, ils émettront votre certificat.
Pour cette méthode, vous devrez créer un Hôte Proxy pour votre ou vos domaines. Cet Hôte Proxy devra être accessible via HTTP et pointer vers cette installation Nginx. Une fois le certificat émis, vous pourrez modifier l'Hôte Proxy pour qu'il utilise également ce certificat pour les connexions HTTPS. Cependant, l'Hôte Proxy devra toujours être configuré pour l'accès HTTP afin que le certificat puisse être renouvelé.
Ce processus ne prend pas en charge les domaines génériques.
### Certificat DNS
Un certificat DNS validé nécessite l'utilisation du plugin Fournisseur DNS. Fournisseur DNS créera des enregistrements temporaires sur votre domaine. Let's Encrypt interrogera ensuite ces enregistrements pour vérifier que vous en êtes bien le propriétaire. En cas de succès, votre certificat sera émis.
Il n'est pas nécessaire de créer un Hôte Proxy avant de demander ce type de certificat.
Il n'est pas non plus nécessaire de configurer votre Hôte Proxy pour l'accès HTTP.
Ce processus prend en charge les domaines génériques.
## Certificat personnalisé
Utilisez cette option pour importer votre propre certificat SSL, fourni par votre autorité de certification.

View File

@@ -1,7 +0,0 @@
## Qu'est-ce qu'un serveur 404 ?
Un Hôte 404 est simplement un hôte configuré pour afficher une page 404.
Cela peut s'avérer utile lorsque votre domaine est indexé par les moteurs de recherche et que vous souhaitez fournir une page d'erreur plus conviviale ou, plus précisément, indiquer aux moteurs de recherche que les pages du domaine n'existent plus.
Un autre avantage de cet hôte est la possibilité de suivre les journaux et de consulter les sites référenceurs.

View File

@@ -1,7 +0,0 @@
## Qu'est-ce qu'un hôte proxy ?
Un Hôte Proxy est le point de terminaison entrant d'un service web que vous souhaitez rediriger.
Il assure la terminaison SSL optionnelle pour votre service qui ne prend pas en charge SSL nativement.
Les Hôtes Proxy constituent l'utilisation la plus courante du Nginx Proxy Manager.

View File

@@ -1,5 +0,0 @@
## Qu'est-ce qu'un serveur de redirection ?
Un Hôte de Redirection redirige les requêtes provenant du domaine entrant vers un autre domaine.
On utilise généralement ce type d'hôte lorsque votre site web change de domaine, mais que des liens provenant des moteurs de recherche ou des sites référenceurs pointent toujours vers l'ancien domaine.

View File

@@ -1,5 +0,0 @@
## Qu'est-ce qu'un Stream ?
Fonctionnalité relativement récente de Nginx, un Stream permet de rediriger le trafic TCP/UDP directement vers un autre ordinateur du réseau.
Si vous gérez des serveurs de jeux, FTP ou SSH, cela peut s'avérer très utile.

View File

@@ -1,6 +0,0 @@
export * as AccessLists from "./AccessLists.md";
export * as Certificates from "./Certificates.md";
export * as DeadHosts from "./DeadHosts.md";
export * as ProxyHosts from "./ProxyHosts.md";
export * as RedirectionHosts from "./RedirectionHosts.md";
export * as Streams from "./Streams.md";

View File

@@ -1,7 +0,0 @@
## Cad is Liosta Rochtana ann?
Soláthraíonn Liostaí Rochtana liosta dubh nó liosta bán de sheoltaí IP cliant ar leith mar aon le fíordheimhniú do na hÓstaigh Seachfhreastalaí trí Fhíordheimhniú Bunúsach HTTP.
Is féidir leat rialacha cliant, ainmneacha úsáideora agus pasfhocail iolracha a chumrú le haghaidh Liosta Rochtana aonair agus ansin iad sin a chur i bhfeidhm ar _Óstach Seachfhreastalaí_ amháin nó níos mó.
Tá sé seo an-úsáideach i gcás seirbhísí gréasáin atreoraithe nach bhfuil meicníochtaí fíordheimhnithe ionsuite iontu nó nuair is mian leat cosaint a dhéanamh ar chliaint anaithnide.

View File

@@ -1,21 +0,0 @@
## Cabhair le Deimhnithe
### Teastas HTTP
Ciallaíonn deimhniú bailíochtaithe HTTP go ndéanfaidh freastalaithe Let's Encrypt iarracht teacht ar do fhearainn thar HTTP (ní HTTPS!) agus má éiríonn leo, eiseoidh siad do theastas.
Chun an modh seo a dhéanamh, beidh ort _Óstach Proxy_ a chruthú do do fhearainn(eanna) atá inrochtana le HTTP agus ag pointeáil chuig an suiteáil Nginx seo. Tar éis deimhniú a thabhairt, is féidir leat an _Óstach Proxy_ a mhodhnú chun an deimhniú seo a úsáid le haghaidh naisc HTTPS freisin. Mar sin féin, beidh ort an _Óstach Proxy_ a chumrú fós le haghaidh rochtain HTTP chun go ndéanfar an deimhniú a athnuachan.
_Ní thacaíonn_ an próiseas seo le fearainn fiáine.
### Teastas DNS
Éilíonn deimhniú bailíochtaithe DNS ort breiseán Soláthraí DNS a úsáid. Úsáidfear an Soláthraí DNS seo chun taifid shealadacha a chruthú ar do fhearann agus ansin déanfaidh Let's Encrypt fiosrúchán ar na taifid sin lena chinntiú gurb tusa an t-úinéir agus má éiríonn leo, eiseoidh siad do theastas.
Ní gá duit _Óstach Proxy_ a chruthú sula n-iarrann tú an cineál seo teastais. Ní gá duit do _Óstach Proxy_ a chumrú le haghaidh rochtana HTTP ach an oiread.
_Tacaíonn_ an próiseas seo le fearainn fiáine.
### Teastas Saincheaptha
Úsáid an rogha seo chun do Theastas SSL féin a uaslódáil, mar a sholáthraíonn d'Údarás Deimhnithe féin é.

View File

@@ -1,7 +0,0 @@
## Cad is Óstach 404 ann?
Is socrú óstach a thaispeánann leathanach 404 é Óstach 404.
Is féidir leis seo a bheith úsáideach nuair a bhíonn do fhearann liostaithe in innill chuardaigh agus más mian leat leathanach earráide níos deise a sholáthar nó a chur in iúl do na hinnéacsóirí cuardaigh go sonrach nach bhfuil na leathanaigh fearainn ann a thuilleadh.
Buntáiste eile a bhaineann leis an óstach seo a bheith agat ná go bhfeictear na logaí le haghaidh amas agus go bhfeictear na tagairtí.

View File

@@ -1,7 +0,0 @@
## Cad is Óstach Seachfhreastalaí ann?
Is é Óstach Seachfhreastalaí an críochphointe isteach do sheirbhís ghréasáin ar mhaith leat a atreorú.
Soláthraíonn sé foirceannadh SSL roghnach do do sheirbhís nach bhfuil tacaíocht SSL ionsuite inti b'fhéidir.
Is iad Óstaigh Seachfhreastalaí an úsáid is coitianta a bhaintear as Bainisteoir Seachfhreastalaí Nginx.

View File

@@ -1,5 +0,0 @@
## Cad is Óstach Athsheolta ann?
Déanfaidh Óstach Athsheolta iarratais a atreorú ón bhfearann ag teacht isteach agus an breathnóir a bhrú chuig fearann eile.
Is é an chúis is coitianta le húsáid a bhaint as an gcineál seo óstála ná nuair a athraíonn do shuíomh Gréasáin fearainn ach go bhfuil naisc innill chuardaigh nó atreoraithe agat fós ag tagairt don seanfhearann.

View File

@@ -1,5 +0,0 @@
## Cad is Sruth ann?
Gné réasúnta nua do Nginx is ea Sruth a sheolfaidh trácht TCP/UDP go díreach chuig ríomhaire eile ar an líonra.
Más freastalaithe cluichí, freastalaithe FTP nó SSH atá á rith agat, dfhéadfadh sé seo a bheith úsáideach.

View File

@@ -1,6 +0,0 @@
export * as AccessLists from "./AccessLists.md";
export * as Certificates from "./Certificates.md";
export * as DeadHosts from "./DeadHosts.md";
export * as ProxyHosts from "./ProxyHosts.md";
export * as RedirectionHosts from "./RedirectionHosts.md";
export * as Streams from "./Streams.md";

View File

@@ -1,7 +0,0 @@
## Mi az a hozzáférési lista?
A hozzáférési listák feketelistát vagy fehérlistát biztosítanak meghatározott kliens IP-címekhez, valamint alap HTTP-hitelesítést (Basic HTTP Authentication) a proxy kiszolgálókhoz.
Egyetlen hozzáférési listához több kliensszabályt, felhasználónevet és jelszót is beállíthatsz, majd ezt alkalmazhatod egy vagy több _Proxy Kiszolgáló_-ra.
Ez különösen hasznos olyan továbbított webszolgáltatásoknál, amelyekben nincs beépített hitelesítési mechanizmus, vagy amikor ismeretlen kliensektől szeretnél védeni.

View File

@@ -1,21 +0,0 @@
## Tanúsítványok súgó
### HTTP tanúsítvány
A HTTP érvényes tanúsítvány azt jelenti, hogy a Let's Encrypt szerverek megpróbálják elérni a domaineket HTTP-n keresztül (nem HTTPS-en!), és ha sikerül, kiállítják a tanúsítványt.
Ehhez a módszerhez létre kell hoznod egy _Proxy Kiszolgáló_-t a domain(ek)hez, amely HTTP-n keresztül elérhető és erre az Nginx telepítésre mutat. Miután a tanúsítvány megérkezett, módosíthatod a _Proxy Kiszolgáló_-t, hogy ezt a tanúsítványt használja a HTTPS kapcsolatokhoz is. Azonban a _Proxy Kiszolgáló_-nak továbbra is konfigurálva kell lennie HTTP hozzáféréshez, hogy a tanúsítvány megújulhasson.
Ez a folyamat _nem_ támogatja a helyettesítő karakteres domaineket.
### DNS tanúsítvány
A DNS érvényes tanúsítvány megköveteli, hogy DNS szolgáltató plugint használj. Ez a DNS szolgáltató ideiglenes rekordokat hoz létre a domainen, majd a Let's Encrypt lekérdezi ezeket a rekordokat, hogy megbizonyosodjon a tulajdonjogról, és ha sikeres, kiállítják a tanúsítványt.
Nem szükséges előzetesen _Proxy Kiszolgáló_-t létrehozni az ilyen típusú tanúsítvány igényléséhez. Nem is kell a _Proxy Kiszolgáló_-t HTTP hozzáférésre konfigurálni.
Ez a folyamat _támogatja_ a helyettesítő karakteres domaineket.
### Egyéni tanúsítvány
Ezt az opciót használd a saját SSL tanúsítvány feltöltéséhez, amelyet a saját tanúsítványkibocsátód biztosított.

View File

@@ -1,7 +0,0 @@
## Mi az a 404-es Kiszolgáló?
A 404-es Kiszolgáló egyszerűen egy olyan kiszolgáló beállítás, amely egy 404-es oldalt jelenít meg.
Ez akkor lehet hasznos, ha a domained szerepel a keresőmotorokban, és egy szebb hibaoldalt szeretnél nyújtani, vagy kifejezetten jelezni akarod a keresőrobotoknak, hogy a domain oldalai már nem léteznek.
Ennek a kiszolgálónak egy további előnye, hogy nyomon követheted a rá érkező találatokat a naplókban, és megtekintheted a hivatkozó oldalakat.

View File

@@ -1,7 +0,0 @@
## Mi az a Proxy Kiszolgáló?
A Proxy Kiszolgáló egy bejövő végpont egy olyan webszolgáltatáshoz, amelyet továbbítani szeretnél.
Opcionális SSL lezárást biztosít a szolgáltatásodhoz, amelyben esetleg nincs beépített SSL támogatás.
A Proxy Kiszolgálók az Nginx Proxy Manager leggyakoribb felhasználási módjai.

View File

@@ -1,5 +0,0 @@
## Mi az az Átirányító Kiszolgáló?
Az Átirányító Kiszolgáló a bejövő domainre érkező kéréseket átirányítja, és a látogatót egy másik domainre küldi.
Ennek a kiszolgálótípusnak a leggyakoribb használati oka az, amikor a weboldalad domaint vált, de a keresőkben vagy a hivatkozó oldalakon még mindig a régi domainre mutató linkek vannak.

View File

@@ -1,5 +0,0 @@
## Mi az a Stream?
Az Nginx egy viszonylag új funkciója, a Stream arra szolgál, hogy a TCP/UDP forgalmat közvetlenül továbbítsa a hálózat egy másik számítógépére.
Ha játékszervereket, FTP vagy SSH szervereket futtatsz, ez hasznos lehet.

View File

@@ -1,6 +0,0 @@
export * as AccessLists from "./AccessLists.md";
export * as Certificates from "./Certificates.md";
export * as DeadHosts from "./DeadHosts.md";
export * as ProxyHosts from "./ProxyHosts.md";
export * as RedirectionHosts from "./RedirectionHosts.md";
export * as Streams from "./Streams.md";

View File

@@ -1,38 +1,36 @@
import * as bg from "./bg/index";
import * as de from "./de/index"; import * as de from "./de/index";
import * as pt from "./pt/index";
import * as en from "./en/index"; import * as en from "./en/index";
import * as es from "./es/index";
import * as fr from "./fr/index";
import * as ga from "./ga/index";
import * as id from "./id/index";
import * as it from "./it/index"; import * as it from "./it/index";
import * as ja from "./ja/index"; import * as ja from "./ja/index";
import * as ko from "./ko/index";
import * as nl from "./nl/index"; import * as nl from "./nl/index";
import * as pl from "./pl/index"; import * as pl from "./pl/index";
import * as ru from "./ru/index"; import * as ru from "./ru/index";
import * as sk from "./sk/index"; import * as sk from "./sk/index";
import * as cs from "./cs/index";
import * as vi from "./vi/index"; import * as vi from "./vi/index";
import * as zh from "./zh/index"; import * as zh from "./zh/index";
import * as tr from "./tr/index"; import * as ko from "./ko/index";
import * as hu from "./hu/index"; import * as bg from "./bg/index";
import * as id from "./id/index";
const items: any = { en, de, pt, es, ja, sk, cs, zh, pl, ru, it, vi, nl, bg, ko, ga, id, fr, tr, hu };
const items: any = { en, de, ja, sk, zh, pl, ru, it, vi, nl, bg, ko, id };
const fallbackLang = "en"; const fallbackLang = "en";
export const getHelpFile = (lang: string, section: string): string => { export const getHelpFile = (lang: string, section: string): string => {
if (typeof items[lang] !== "undefined" && typeof items[lang][section] !== "undefined") { if (
return items[lang][section].default; typeof items[lang] !== "undefined" &&
} typeof items[lang][section] !== "undefined"
// Fallback to English ) {
if (typeof items[fallbackLang] !== "undefined" && typeof items[fallbackLang][section] !== "undefined") { return items[lang][section].default;
return items[fallbackLang][section].default; }
} // Fallback to English
throw new Error(`Cannot load help doc for ${lang}-${section}`); if (
typeof items[fallbackLang] !== "undefined" &&
typeof items[fallbackLang][section] !== "undefined"
) {
return items[fallbackLang][section].default;
}
throw new Error(`Cannot load help doc for ${lang}-${section}`);
}; };
export default items; export default items;

View File

@@ -1,11 +0,0 @@
## O que é uma Access List?
As *Access Lists* fornecem uma lista de permissões (whitelist) ou bloqueios (blacklist)
de endereços IP específicos de clientes, juntamente com autenticação para os *Proxy Hosts*
via Autenticação HTTP Básica (*Basic Auth*).
Podes configurar múltiplas regras de cliente, nomes de utilizador e palavras-passe
para uma única *Access List*, e depois aplicá-la a um ou mais *Proxy Hosts*.
Isto é especialmente útil para serviços web encaminhados que não têm mecanismos
de autenticação integrados ou quando pretendes proteger o acesso contra clientes desconhecidos.

View File

@@ -1,31 +0,0 @@
## Ajuda de Certificados
### Certificado HTTP
Um certificado validado por HTTP significa que os servidores do Let's Encrypt irão
tentar aceder aos teus domínios via HTTP (não HTTPS!) e, se a ligação for bem-sucedida,
emitirão o certificado.
Para este método, é necessário ter um *Proxy Host* criado para o(s) teu(s) domínio(s),
acessível via HTTP e a apontar para esta instalação do Nginx. Depois de o certificado ser
emitido, podes modificar o *Proxy Host* para também utilizar esse certificado em ligações HTTPS.
No entanto, o *Proxy Host* deve continuar configurado para acesso HTTP para que a renovação
funcione corretamente.
Este processo **não** suporta domínios wildcard.
### Certificado DNS
Um certificado validado por DNS requer que uses um plugin de fornecedor DNS (*DNS Provider*).
Este fornecedor será usado para criar registos temporários no teu domínio, que serão consultados
pelo Let's Encrypt para confirmar que és o proprietário. Se tudo correr bem, o certificado será emitido.
Não é necessário ter um *Proxy Host* criado antes de pedir este tipo de certificado.
Também não é necessário que o *Proxy Host* tenha acesso HTTP configurado.
Este processo **suporta** domínios wildcard.
### Certificado Personalizado
Usa esta opção para carregar o teu próprio Certificado SSL, fornecido pela
tua Autoridade Certificadora.

View File

@@ -1,9 +0,0 @@
## O que é um 404 Host?
Um *404 Host* é simplesmente um host configurado para apresentar uma página 404.
Isto pode ser útil quando o teu domínio aparece em motores de busca e queres fornecer
uma página de erro mais agradável ou indicar especificamente aos indexadores de pesquisa
que as páginas desse domínio já não existem.
Outra vantagem é permitir consultar os registos de acessos a este host e ver os referenciadores.

View File

@@ -1,7 +0,0 @@
## O que é um Proxy Host?
Um *Proxy Host* é o ponto de entrada para um serviço web que pretendes encaminhar.
Permite, opcionalmente, fazer terminação SSL para um serviço que possa não ter suporte SSL nativo.
Os *Proxy Hosts* são a utilização mais comum do Nginx Proxy Manager.

View File

@@ -1,7 +0,0 @@
## O que é um Redirection Host?
Um *Redirection Host* redireciona pedidos recebidos no domínio de entrada e envia
o utilizador para outro domínio.
A razão mais comum para usar este tipo de host é quando o teu site muda de domínio
mas ainda tens motores de busca ou links de referência a apontar para o domínio antigo.

View File

@@ -1,6 +0,0 @@
## O que é um Stream?
Uma funcionalidade relativamente recente no Nginx, um *Stream* serve para encaminhar
tráfego TCP/UDP diretamente para outro computador na rede.
Se estiveres a executar servidores de jogos, FTP ou SSH, isto pode ser bastante útil.

View File

@@ -1,6 +0,0 @@
export * as AccessLists from "./AccessLists.md";
export * as Certificates from "./Certificates.md";
export * as DeadHosts from "./DeadHosts.md";
export * as ProxyHosts from "./ProxyHosts.md";
export * as RedirectionHosts from "./RedirectionHosts.md";
export * as Streams from "./Streams.md";

View File

@@ -1,8 +0,0 @@
## Erişim Listesi Nedir?
Erişim Listeleri, Temel HTTP Kimlik Doğrulama aracılığıyla Proxy Host'lar için belirli istemci IP adreslerinin kara listesi veya beyaz listesini ve kimlik doğrulamasını sağlar.
Tek bir Erişim Listesi için birden fazla istemci kuralı, kullanıcı adı ve şifre yapılandırabilir ve bunu bir veya daha fazla _Proxy Host_'a uygulayabilirsiniz.
Bu, yerleşik kimlik doğrulama mekanizmaları olmayan veya bilinmeyen istemcilerden korunmak istediğinizde iletilen web hizmetleri için en kullanışlıdır.

View File

@@ -1,29 +0,0 @@
## Sertifika Yardımı
### HTTP Sertifikası
Bir HTTP doğrulanmış sertifika, Let's Encrypt sunucularının
alan adlarınıza HTTP (HTTPS değil!) üzerinden ulaşmaya çalışacağı ve başarılı olursa,
sertifikanızı verecekleri anlamına gelir.
Bu yöntem için, alan adlarınız için HTTP ile erişilebilir ve bu Nginx kurulumuna işaret eden bir _Proxy Host_ oluşturulmuş olmalıdır. Bir sertifika
verildikten sonra, _Proxy Host_'u HTTPS
bağlantıları için de bu sertifikayı kullanacak şekilde değiştirebilirsiniz. Ancak, sertifikanın yenilenmesi için _Proxy Host_'un hala HTTP erişimi için yapılandırılmış olması gerekecektir.
Bu işlem joker karakter alan adlarını _desteklemez_.
### DNS Sertifikası
Bir DNS doğrulanmış sertifika, bir DNS Sağlayıcı eklentisi kullanmanızı gerektirir. Bu DNS
Sağlayıcı, alan adınızda geçici kayıtlar oluşturmak için kullanılacak ve ardından Let's
Encrypt bu kayıtları sorgulayarak sahibi olduğunuzdan emin olacak ve başarılı olursa,
sertifikanızı verecektir.
Bu tür bir sertifika talep etmeden önce bir _Proxy Host_ oluşturulmasına gerek yoktur. Ayrıca _Proxy Host_'unuzun HTTP erişimi için yapılandırılmasına da gerek yoktur.
Bu işlem joker karakter alan adlarını _destekler_.
### Özel Sertifika
Kendi Sertifika Otoriteniz tarafından sağlanan kendi SSL Sertifikanızı yüklemek için bu seçeneği kullanın.

View File

@@ -1,10 +0,0 @@
## 404 Host Nedir?
404 Host, basitçe bir 404 sayfası gösteren bir host kurulumudur.
Bu, alan adınız arama motorlarında listelendiğinde ve daha güzel bir hata sayfası sağlamak veya özellikle arama dizinleyicilerine
alan adı sayfalarının artık mevcut olmadığını söylemek istediğinizde yararlı olabilir.
Bu host'un bir başka faydası da, ona yapılan isteklerin loglarını takip etmek ve
referansları görüntülemektir.

View File

@@ -1,8 +0,0 @@
## Proxy Host Nedir?
Proxy Host, iletilmek istediğiniz bir web hizmeti için gelen uç noktadır.
SSL desteği yerleşik olmayan hizmetiniz için isteğe bağlı SSL sonlandırma sağlar.
Proxy Host'lar, Nginx Proxy Manager'ın en yaygın kullanımıdır.

View File

@@ -1,8 +0,0 @@
## Yönlendirme Host'u Nedir?
Yönlendirme Host'u, gelen alan adından gelen istekleri yönlendirir ve
görüntüleyiciyi başka bir alan adına yönlendirir.
Bu tür bir host kullanmanın en yaygın nedeni, web sitenizin alan adı değiştiğinde
ancak hala eski alan adına işaret eden arama motoru veya referans bağlantılarınız olduğunda ortaya çıkar.

View File

@@ -1,7 +0,0 @@
## Akış Nedir?
Nginx için nispeten yeni bir özellik olan Akış, TCP/UDP
trafiğini doğrudan ağdaki başka bir bilgisayara iletmek için hizmet edecektir.
Oyun sunucuları, FTP veya SSH sunucuları çalıştırıyorsanız bu işinize yarayabilir.

View File

@@ -1,7 +0,0 @@
export * as AccessLists from "./AccessLists.md";
export * as Certificates from "./Certificates.md";
export * as DeadHosts from "./DeadHosts.md";
export * as ProxyHosts from "./ProxyHosts.md";
export * as RedirectionHosts from "./RedirectionHosts.md";
export * as Streams from "./Streams.md";

View File

@@ -1,770 +0,0 @@
{
"2fa.backup-codes-remaining": {
"defaultMessage": "Počet zbývajících záložních kódů: {count}"
},
"2fa.backup-warning": {
"defaultMessage": "Tyto záložní kódy si uložte na bezpečném místě. Každý kód lze použít pouze jednou."
},
"2fa.disable": {
"defaultMessage": "Vypnout dvoufaktorové ověřování"
},
"2fa.disable-confirm": {
"defaultMessage": "Vypnout 2FA"
},
"2fa.disable-warning": {
"defaultMessage": "Vypnutím dvoufaktorového ověřování snížíte bezpečnost svého účtu."
},
"2fa.disabled": {
"defaultMessage": "Vypnuto"
},
"2fa.done": {
"defaultMessage": "Uložil jsem si své záložní kódy."
},
"2fa.enable": {
"defaultMessage": "Zapnout dvoufaktorové ověřování"
},
"2fa.enabled": {
"defaultMessage": "Zapnuto"
},
"2fa.enter-code": {
"defaultMessage": "Zadejte ověřovací kód"
},
"2fa.enter-code-disable": {
"defaultMessage": "Zadejte ověřovací kód pro vypnutí"
},
"2fa.regenerate": {
"defaultMessage": "Znovu vytvořit"
},
"2fa.regenerate-backup": {
"defaultMessage": "Znovu vytvořit záložní kódy"
},
"2fa.regenerate-instructions": {
"defaultMessage": "Zadejte ověřovací kód pro vytvoření nových záložních kódů. Vaše staré kódy budou neplatné."
},
"2fa.secret-key": {
"defaultMessage": "Tajný klíč"
},
"2fa.setup-instructions": {
"defaultMessage": "Naskenujte tento QR kód pomocí své ověřovací aplikace nebo zadejte tajný klíč ručně."
},
"2fa.status": {
"defaultMessage": "Stav"
},
"2fa.title": {
"defaultMessage": "Dvoufaktorové ověření"
},
"2fa.verify-enable": {
"defaultMessage": "Ověřit a zapnout"
},
"access-list": {
"defaultMessage": "seznam přístupů"
},
"access-list.access-count": {
"defaultMessage": "{count} {count, plural, one {pravidlo} few {pravidla} other {pravidel}}"
},
"access-list.auth-count": {
"defaultMessage": "{count} {count, plural, one {uživatel} few {uživatelé} other {uživatelů}}"
},
"access-list.help-rules-last": {
"defaultMessage": "Když existuje alespoň jedno pravidlo, toto pravidlo „zamítnout vše“ bude přidáno jako poslední"
},
"access-list.help.rules-order": {
"defaultMessage": "Upozornění: pravidla povolit a zamítnout budou uplatňována v pořadí, v jakém jsou definována."
},
"access-list.pass-auth": {
"defaultMessage": "Odeslat ověření na Upstream"
},
"access-list.public": {
"defaultMessage": "Veřejně přístupné"
},
"access-list.public.subtitle": {
"defaultMessage": "Není potřeba základní ověření"
},
"access-list.rule-source.placeholder": {
"defaultMessage": "192.168.1.100 nebo 192.168.1.0/24 nebo 2001:0db8::/32"
},
"access-list.satisfy-any": {
"defaultMessage": "Splnit kterékoliv"
},
"access-list.subtitle": {
"defaultMessage": "{users} {users, plural, one {uživatel} few {uživatelé} other {uživatelů}}, {rules} {rules, plural, one {pravidlo} few {pravidla} other {pravidel}} - Vytvořeno: {date}"
},
"access-lists": {
"defaultMessage": "Seznamy přístupů"
},
"action.add": {
"defaultMessage": "Přidat"
},
"action.add-location": {
"defaultMessage": "Přidat umístění"
},
"action.allow": {
"defaultMessage": "Povolit"
},
"action.close": {
"defaultMessage": "Zavřít"
},
"action.delete": {
"defaultMessage": "Smazat"
},
"action.deny": {
"defaultMessage": "Zamítnout"
},
"action.disable": {
"defaultMessage": "Deaktivovat"
},
"action.download": {
"defaultMessage": "Stáhnout"
},
"action.edit": {
"defaultMessage": "Upravit"
},
"action.enable": {
"defaultMessage": "Aktivovat"
},
"action.permissions": {
"defaultMessage": "Oprávnění"
},
"action.renew": {
"defaultMessage": "Obnovit"
},
"action.view-details": {
"defaultMessage": "Zobrazit podrobnosti"
},
"auditlogs": {
"defaultMessage": "Záznamy auditu"
},
"auto": {
"defaultMessage": "Automaticky"
},
"cancel": {
"defaultMessage": "Zrušit"
},
"certificate": {
"defaultMessage": "certifikát"
},
"certificate.custom-certificate": {
"defaultMessage": "Certifikát"
},
"certificate.custom-certificate-key": {
"defaultMessage": "Klíč certifikátu"
},
"certificate.custom-intermediate": {
"defaultMessage": "Zprostředkovatelský certifikát"
},
"certificate.in-use": {
"defaultMessage": "Používá se"
},
"certificate.none.subtitle": {
"defaultMessage": "Není přiřazen žádný certifikát"
},
"certificate.none.subtitle.for-http": {
"defaultMessage": "Tento hostitel nebude používat HTTPS"
},
"certificate.none.title": {
"defaultMessage": "Žádný"
},
"certificate.not-in-use": {
"defaultMessage": "Nepoužívá se"
},
"certificate.renew": {
"defaultMessage": "Obnovit certifikát"
},
"certificates": {
"defaultMessage": "Certifikáty"
},
"certificates.custom": {
"defaultMessage": "Vlastní certifikát"
},
"certificates.custom.warning": {
"defaultMessage": "Soubory klíčů chráněné heslem nejsou podporovány."
},
"certificates.dns.credentials": {
"defaultMessage": "Obsah souboru s přihlašovacími údaji"
},
"certificates.dns.credentials-note": {
"defaultMessage": "Tento doplněk vyžaduje konfigurační soubor obsahující API token nebo jiné přihlašovací údaje vašeho poskytovatele"
},
"certificates.dns.credentials-warning": {
"defaultMessage": "Tyto údaje budou uloženy v databázi a v souboru jako obyčejný text!"
},
"certificates.dns.propagation-seconds": {
"defaultMessage": "Propagace v sekundách"
},
"certificates.dns.propagation-seconds-note": {
"defaultMessage": "Nechte prázdné pro výchozí hodnotu doplňku. Počet sekund, po které se čeká na propagaci DNS."
},
"certificates.dns.provider": {
"defaultMessage": "DNS poskytovatel"
},
"certificates.dns.provider.placeholder": {
"defaultMessage": "Vyberte poskytovatele..."
},
"certificates.dns.warning": {
"defaultMessage": "Tato sekce vyžaduje znalost Certbotu a jeho DNS doplňků. Prosím, podívejte se do dokumentace příslušného doplňku."
},
"certificates.http.reachability-404": {
"defaultMessage": "Na této doméně byl nalezen server, ale nezdá se, že jde o Nginx Proxy Manager. Ujistěte se, že vaše doména směřuje na IP, kde běží vaše instance NPM."
},
"certificates.http.reachability-failed-to-check": {
"defaultMessage": "Nepodařilo se ověřit dostupnost kvůli chybě komunikace se službou site24x7.com."
},
"certificates.http.reachability-not-resolved": {
"defaultMessage": "Na této doméně není dostupný žádný server. Ujistěte se, že doména existuje a směřuje na IP adresu s NPM a pokud je to potřeba, port 80 je přesměrován ve vašem routeru."
},
"certificates.http.reachability-ok": {
"defaultMessage": "Váš server je dostupný a vytvoření certifikátu by mělo být možné."
},
"certificates.http.reachability-other": {
"defaultMessage": "Na této doméně byl nalezen server, ale vrátil neočekávaný stavový kód {code}. Je to NPM server? Ujistěte se prosím, že doména směřuje na IP, kde běží vaše instance NPM."
},
"certificates.http.reachability-wrong-data": {
"defaultMessage": "Na této doméně byl nalezen server, ale vrátil neočekávaná data. Je to NPM server? Ujistěte se, že doména směřuje na IP, kde běží vaše instance NPM."
},
"certificates.http.test-results": {
"defaultMessage": "Výsledky testu"
},
"certificates.http.warning": {
"defaultMessage": "Tyto domény musí být již nakonfigurovány tak, aby směřovaly na tuto instalaci."
},
"certificates.key-type": {
"defaultMessage": "Typ klíče"
},
"certificates.key-type-description": {
"defaultMessage": "RSA je široce kompatibilní, ECDSA je rychlejší a bezpečnější, ale nemusí být podporován staršími systémy"
},
"certificates.key-type-ecdsa": {
"defaultMessage": "ECDSA 256"
},
"certificates.key-type-rsa": {
"defaultMessage": "RSA 2048"
},
"certificates.request.subtitle": {
"defaultMessage": "pomocí Let's Encrypt"
},
"certificates.request.title": {
"defaultMessage": "Vyžádat nový certifikát"
},
"column.access": {
"defaultMessage": "Přístup"
},
"column.authorization": {
"defaultMessage": "Autorizace"
},
"column.authorizations": {
"defaultMessage": "Autorizace"
},
"column.custom-locations": {
"defaultMessage": "Vlastní umístění"
},
"column.destination": {
"defaultMessage": "Cíl"
},
"column.details": {
"defaultMessage": "Podrobnosti"
},
"column.email": {
"defaultMessage": "Email"
},
"column.event": {
"defaultMessage": "Událost"
},
"column.expires": {
"defaultMessage": "Platnost do"
},
"column.http-code": {
"defaultMessage": "Přístup"
},
"column.incoming-port": {
"defaultMessage": "Vstupní port"
},
"column.name": {
"defaultMessage": "Název"
},
"column.protocol": {
"defaultMessage": "Protokol"
},
"column.provider": {
"defaultMessage": "Poskytovatel"
},
"column.roles": {
"defaultMessage": "Role"
},
"column.rules": {
"defaultMessage": "Pravidla"
},
"column.satisfy": {
"defaultMessage": "Splnit"
},
"column.satisfy-all": {
"defaultMessage": "Všechny"
},
"column.satisfy-any": {
"defaultMessage": "Kterékoliv"
},
"column.scheme": {
"defaultMessage": "Schéma"
},
"column.source": {
"defaultMessage": "Zdroj"
},
"column.ssl": {
"defaultMessage": "SSL"
},
"column.status": {
"defaultMessage": "Stav"
},
"created-on": {
"defaultMessage": "Vytvořeno: {date}"
},
"dashboard": {
"defaultMessage": "Panel"
},
"dead-host": {
"defaultMessage": "404 hostitel"
},
"dead-hosts": {
"defaultMessage": "404 Hostitelé"
},
"dead-hosts.count": {
"defaultMessage": "{count} {count, plural, one {404 hostitel} few {404 hostitelé} other {404 hostitelů}}"
},
"disabled": {
"defaultMessage": "Deaktivováno"
},
"domain-names": {
"defaultMessage": "Doménová jména"
},
"domain-names.max": {
"defaultMessage": "Maximálně {count} doménových jmen"
},
"domain-names.placeholder": {
"defaultMessage": "Začněte psát pro přidání domény..."
},
"domain-names.wildcards-not-permitted": {
"defaultMessage": "Wildcards nejsou pro tento typ povoleny"
},
"domain-names.wildcards-not-supported": {
"defaultMessage": "Wildcards nejsou podporovány pro tuto certifikační autoritu"
},
"domains.force-ssl": {
"defaultMessage": "Vynutit SSL"
},
"domains.hsts-enabled": {
"defaultMessage": "HSTS povoleno"
},
"domains.hsts-subdomains": {
"defaultMessage": "HSTS pro subdomény"
},
"domains.http2-support": {
"defaultMessage": "Podpora HTTP/2"
},
"domains.use-dns": {
"defaultMessage": "Použít DNS výzvu"
},
"email-address": {
"defaultMessage": "Emailová adresa"
},
"empty-search": {
"defaultMessage": "Nebyly nalezeny žádné výsledky"
},
"empty-subtitle": {
"defaultMessage": "Proč nevytvoříte nějaký?"
},
"enabled": {
"defaultMessage": "Aktivováno"
},
"error.access.at-least-one": {
"defaultMessage": "Je vyžadována alespoň jedna autorizace nebo jedno přístupové pravidlo"
},
"error.access.duplicate-usernames": {
"defaultMessage": "Uživatelská jména pro autorizaci musí být jedinečná"
},
"error.invalid-auth": {
"defaultMessage": "Neplatný email nebo heslo"
},
"error.invalid-domain": {
"defaultMessage": "Neplatná doména: {domain}"
},
"error.invalid-email": {
"defaultMessage": "Neplatná emailová adresa"
},
"error.max-character-length": {
"defaultMessage": "Maximální délka je {max} znak{max, plural, one {} few {y} other {ů}}"
},
"error.max-domains": {
"defaultMessage": "Příliš mnoho domén, maximum je {max}"
},
"error.maximum": {
"defaultMessage": "Maximum je {max}"
},
"error.min-character-length": {
"defaultMessage": "Minimální délka je {min} znak{min, plural, one {} few {y} other {ů}}"
},
"error.minimum": {
"defaultMessage": "Minimum je {min}"
},
"error.passwords-must-match": {
"defaultMessage": "Hesla se musí shodovat"
},
"error.required": {
"defaultMessage": "Toto pole je povinné"
},
"expires.on": {
"defaultMessage": "Platnost do: {date}"
},
"footer.github-fork": {
"defaultMessage": "Forkněte mě na GitHubu"
},
"host.flags.block-exploits": {
"defaultMessage": "Blokovat běžné exploity"
},
"host.flags.cache-assets": {
"defaultMessage": "Uložit zdroje do mezipaměti"
},
"host.flags.preserve-path": {
"defaultMessage": "Zachovat cestu"
},
"host.flags.protocols": {
"defaultMessage": "Protokoly"
},
"host.flags.websockets-upgrade": {
"defaultMessage": "Podpora WebSockets"
},
"host.forward-port": {
"defaultMessage": "Port přesměrování"
},
"host.forward-scheme": {
"defaultMessage": "Schéma"
},
"hosts": {
"defaultMessage": "Hostitelé"
},
"http-only": {
"defaultMessage": "Pouze HTTP"
},
"lets-encrypt": {
"defaultMessage": "Let's Encrypt"
},
"lets-encrypt-via-dns": {
"defaultMessage": "Let's Encrypt přes DNS"
},
"lets-encrypt-via-http": {
"defaultMessage": "Let's Encrypt přes HTTP"
},
"loading": {
"defaultMessage": "Načítá se…"
},
"login.2fa-code": {
"defaultMessage": "Ověřovací kód"
},
"login.2fa-code-placeholder": {
"defaultMessage": "Vložit kód"
},
"login.2fa-description": {
"defaultMessage": "Vložte kód z vaší ověřovací aplikace"
},
"login.2fa-title": {
"defaultMessage": "Dvoufaktorové ověření"
},
"login.2fa-verify": {
"defaultMessage": "Ověřit"
},
"login.title": {
"defaultMessage": "Přihlaste se ke svému účtu"
},
"nginx-config.label": {
"defaultMessage": "Vlastní Nginx konfigurace"
},
"nginx-config.placeholder": {
"defaultMessage": "# Zadejte vlastní Nginx konfiguraci na vlastní riziko!"
},
"no-permission-error": {
"defaultMessage": "Nemáte oprávnění k zobrazení tohoto obsahu."
},
"notfound.action": {
"defaultMessage": "Zpět na hlavní stránku"
},
"notfound.content": {
"defaultMessage": "Omlouváme se, stránka, kterou hledáte, nebyla nalezena"
},
"notfound.title": {
"defaultMessage": "Ups… Našli jste chybovou stránku"
},
"notification.error": {
"defaultMessage": "Chyba"
},
"notification.object-deleted": {
"defaultMessage": "{object} byl odstraněn"
},
"notification.object-disabled": {
"defaultMessage": "{object} byl deaktivován"
},
"notification.object-enabled": {
"defaultMessage": "{object} byl aktivován"
},
"notification.object-renewed": {
"defaultMessage": "{object} byl obnoven"
},
"notification.object-saved": {
"defaultMessage": "{object} byl uložen"
},
"notification.success": {
"defaultMessage": "Úspěch"
},
"object.actions-title": {
"defaultMessage": "{object} #{id}"
},
"object.add": {
"defaultMessage": "Přidat {object}"
},
"object.delete": {
"defaultMessage": "Smazat {object}"
},
"object.delete.content": {
"defaultMessage": "Opravdu chcete smazat tento {object}?"
},
"object.edit": {
"defaultMessage": "Upravit {object}"
},
"object.empty": {
"defaultMessage": "Nejsou {objects}"
},
"object.event.created": {
"defaultMessage": "Vytvořen {object}"
},
"object.event.deleted": {
"defaultMessage": "Smazán {object}"
},
"object.event.disabled": {
"defaultMessage": "Deaktivován {object}"
},
"object.event.enabled": {
"defaultMessage": "Aktivován {object}"
},
"object.event.renewed": {
"defaultMessage": "Obnoven {object}"
},
"object.event.updated": {
"defaultMessage": "Aktualizován {object}"
},
"offline": {
"defaultMessage": "Offline"
},
"online": {
"defaultMessage": "Online"
},
"options": {
"defaultMessage": "Možnosti"
},
"password": {
"defaultMessage": "Heslo"
},
"password.generate": {
"defaultMessage": "Vygenerovat náhodné heslo"
},
"password.hide": {
"defaultMessage": "Skrýt heslo"
},
"password.show": {
"defaultMessage": "Zobrazit heslo"
},
"permissions.hidden": {
"defaultMessage": "Skryté"
},
"permissions.manage": {
"defaultMessage": "Spravovat"
},
"permissions.view": {
"defaultMessage": "Pouze pro zobrazení"
},
"permissions.visibility.all": {
"defaultMessage": "Všechny položky"
},
"permissions.visibility.title": {
"defaultMessage": "Viditelnost položky"
},
"permissions.visibility.user": {
"defaultMessage": "Pouze vytvořené položky"
},
"proxy-host": {
"defaultMessage": "proxy hostitele"
},
"proxy-host.forward-host": {
"defaultMessage": "Cílový název hostitele / IP"
},
"proxy-hosts": {
"defaultMessage": "Proxy hostitelé"
},
"proxy-hosts.count": {
"defaultMessage": "{count} {count, plural, one {proxy hostitel} few {proxy hostitelé} other {proxy hostitelů}}"
},
"public": {
"defaultMessage": "Veřejné"
},
"redirection-host": {
"defaultMessage": "přesměrovacího hostitele"
},
"redirection-host.forward-domain": {
"defaultMessage": "Cílová doména"
},
"redirection-host.forward-http-code": {
"defaultMessage": "HTTP kód"
},
"redirection-hosts": {
"defaultMessage": "Přesměrovací hostitelé"
},
"redirection-hosts.count": {
"defaultMessage": "{count} {count, plural, one {přesměrovací hostitel} few {přesměrovací hostitelé} other {přesměrovacích hostitelů}}"
},
"redirection-hosts.http-code.300": {
"defaultMessage": "300 Více možností"
},
"redirection-hosts.http-code.301": {
"defaultMessage": "301 Trvale přesunuto"
},
"redirection-hosts.http-code.302": {
"defaultMessage": "302 Dočasně přesunuto"
},
"redirection-hosts.http-code.303": {
"defaultMessage": "303 Podívat se na jiné"
},
"redirection-hosts.http-code.307": {
"defaultMessage": "307 Dočasné přesměrování"
},
"redirection-hosts.http-code.308": {
"defaultMessage": "308 Trvalé přesměrování"
},
"role.admin": {
"defaultMessage": "Administrátor"
},
"role.standard-user": {
"defaultMessage": "Běžný uživatel"
},
"save": {
"defaultMessage": "Uložit"
},
"setting": {
"defaultMessage": "Nastavení"
},
"settings": {
"defaultMessage": "Nastavení"
},
"settings.default-site": {
"defaultMessage": "Výchozí stránka"
},
"settings.default-site.404": {
"defaultMessage": "Stránka 404"
},
"settings.default-site.444": {
"defaultMessage": "Bez odpovědi (444)"
},
"settings.default-site.congratulations": {
"defaultMessage": "Gratulační stránka"
},
"settings.default-site.description": {
"defaultMessage": "Co zobrazit, když Nginx zachytí neznámého hostitele"
},
"settings.default-site.html": {
"defaultMessage": "Vlastní HTML"
},
"settings.default-site.html.placeholder": {
"defaultMessage": "<!-- Sem zadejte vlastní HTML obsah -->"
},
"settings.default-site.redirect": {
"defaultMessage": "Přesměrovat"
},
"setup.preamble": {
"defaultMessage": "Začněte vytvořením administrátorského účtu."
},
"setup.title": {
"defaultMessage": "Vítejte!"
},
"sign-in": {
"defaultMessage": "Přihlásit se"
},
"ssl-certificate": {
"defaultMessage": "SSL certifikát"
},
"stream": {
"defaultMessage": "stream"
},
"stream.forward-host": {
"defaultMessage": "Cílový hostitel"
},
"stream.forward-host.placeholder": {
"defaultMessage": "napriklad.cz nebo 10.0.0.1 nebo 2001:db8:3333:4444:5555:6666:7777:8888"
},
"stream.incoming-port": {
"defaultMessage": "Vstupní port"
},
"streams": {
"defaultMessage": "Streamy"
},
"streams.count": {
"defaultMessage": "{count} {count, plural, one {stream} few {streamy} other {streamů}}"
},
"streams.tcp": {
"defaultMessage": "TCP"
},
"streams.udp": {
"defaultMessage": "UDP"
},
"test": {
"defaultMessage": "Test"
},
"update-available": {
"defaultMessage": "Dostupná aktualizace: {latestVersion}"
},
"user": {
"defaultMessage": "uživatele"
},
"user.change-password": {
"defaultMessage": "Změnit heslo"
},
"user.confirm-password": {
"defaultMessage": "Potvrdit heslo"
},
"user.current-password": {
"defaultMessage": "Aktuální heslo"
},
"user.edit-profile": {
"defaultMessage": "Upravit profil"
},
"user.full-name": {
"defaultMessage": "Celé jméno"
},
"user.login-as": {
"defaultMessage": "Přihlásit se jako {name}"
},
"user.logout": {
"defaultMessage": "Odhlásit se"
},
"user.new-password": {
"defaultMessage": "Nové heslo"
},
"user.nickname": {
"defaultMessage": "Přezdívka"
},
"user.set-password": {
"defaultMessage": "Nastavit heslo"
},
"user.set-permissions": {
"defaultMessage": "Nastavit oprávnění pro {name}"
},
"user.switch-dark": {
"defaultMessage": "Přepnout na tmavý režim"
},
"user.switch-light": {
"defaultMessage": "Přepnout na světlý režim"
},
"user.two-factor": {
"defaultMessage": "Dvoufaktorové ověření"
},
"username": {
"defaultMessage": "Uživatelské jméno"
},
"users": {
"defaultMessage": "Uživatelé"
}
}

View File

@@ -30,13 +30,13 @@
"defaultMessage": "{users} {users, plural, one {User} other {Users}}, {rules} {rules, plural, one {Regel} other {Regeln}} - Erstellt: {date}" "defaultMessage": "{users} {users, plural, one {User} other {Users}}, {rules} {rules, plural, one {Regel} other {Regeln}} - Erstellt: {date}"
}, },
"access-lists": { "access-lists": {
"defaultMessage": "Zugriffslisten" "defaultMessage": "Zugrifflisten"
}, },
"action.add": { "action.add": {
"defaultMessage": "Hinzufügen" "defaultMessage": "Hinzufügen"
}, },
"action.add-location": { "action.add-location": {
"defaultMessage": "Pfad hinzufügen" "defaultMessage": "Pfad Hinzufügen"
}, },
"action.close": { "action.close": {
"defaultMessage": "Schließen" "defaultMessage": "Schließen"
@@ -60,13 +60,13 @@
"defaultMessage": "Berechtigungen" "defaultMessage": "Berechtigungen"
}, },
"action.renew": { "action.renew": {
"defaultMessage": "Erneuern" "defaultMessage": "Erneuert"
}, },
"action.view-details": { "action.view-details": {
"defaultMessage": "Details anzeigen" "defaultMessage": "Details"
}, },
"auditlogs": { "auditlogs": {
"defaultMessage": "Protokolle" "defaultMessage": "Protokoll"
}, },
"cancel": { "cancel": {
"defaultMessage": "Abbrechen" "defaultMessage": "Abbrechen"
@@ -81,7 +81,7 @@
"defaultMessage": "Privater Schlüssel" "defaultMessage": "Privater Schlüssel"
}, },
"certificate.custom-intermediate": { "certificate.custom-intermediate": {
"defaultMessage": "Zwischenzertifikat" "defaultMessage": "Zwischen Zertifikat"
}, },
"certificate.in-use": { "certificate.in-use": {
"defaultMessage": "In Benutzung" "defaultMessage": "In Benutzung"
@@ -120,7 +120,7 @@
"defaultMessage": "Diese Daten werden als Klartext in der Datenbank und in einer Datei gespeichert!" "defaultMessage": "Diese Daten werden als Klartext in der Datenbank und in einer Datei gespeichert!"
}, },
"certificates.dns.propagation-seconds": { "certificates.dns.propagation-seconds": {
"defaultMessage": "Wartezeit in Sekunden" "defaultMessage": "Wartzeit in Sekunden"
}, },
"certificates.dns.propagation-seconds-note": { "certificates.dns.propagation-seconds-note": {
"defaultMessage": "Leer lassen um die Standardwartezeit des Plugins zu nutzen" "defaultMessage": "Leer lassen um die Standardwartezeit des Plugins zu nutzen"
@@ -150,7 +150,7 @@
"defaultMessage": "Unter dieser Domain wurde ein Server gefunden, der jedoch unerwartete Daten zurückgegeben hat. Handelt es sich um den NPM-Server? Bitte stellen Sie sicher, dass Ihre Domain auf die IP-Adresse verweist, unter der Ihre NPM-Instanz ausgeführt wird." "defaultMessage": "Unter dieser Domain wurde ein Server gefunden, der jedoch unerwartete Daten zurückgegeben hat. Handelt es sich um den NPM-Server? Bitte stellen Sie sicher, dass Ihre Domain auf die IP-Adresse verweist, unter der Ihre NPM-Instanz ausgeführt wird."
}, },
"certificates.http.test-results": { "certificates.http.test-results": {
"defaultMessage": "Testergebnisse" "defaultMessage": "Test Ergeniss"
}, },
"certificates.http.warning": { "certificates.http.warning": {
"defaultMessage": "Diese Domänen müssen bereits so konfiguriert sein, dass sie auf diese Installation verweisen." "defaultMessage": "Diese Domänen müssen bereits so konfiguriert sein, dass sie auf diese Installation verweisen."
@@ -183,7 +183,7 @@
"defaultMessage": "Genehmigungen" "defaultMessage": "Genehmigungen"
}, },
"column.custom-locations": { "column.custom-locations": {
"defaultMessage": "Benutzerdefinierte Pfade" "defaultMessage": "Benutzerdefinierte Pfad"
}, },
"column.destination": { "column.destination": {
"defaultMessage": "Ziel" "defaultMessage": "Ziel"
@@ -192,7 +192,7 @@
"defaultMessage": "Details" "defaultMessage": "Details"
}, },
"column.email": { "column.email": {
"defaultMessage": "E-Mail" "defaultMessage": "Email"
}, },
"column.event": { "column.event": {
"defaultMessage": "Ereignis" "defaultMessage": "Ereignis"
@@ -291,7 +291,7 @@
"defaultMessage": "Nutze DNS Challenge" "defaultMessage": "Nutze DNS Challenge"
}, },
"email-address": { "email-address": {
"defaultMessage": "E-Mail-Adresse" "defaultMessage": "Email Addresse"
}, },
"empty-search": { "empty-search": {
"defaultMessage": "Keine Ergebnisse gefunden" "defaultMessage": "Keine Ergebnisse gefunden"
@@ -384,7 +384,7 @@
"defaultMessage": "Laden…" "defaultMessage": "Laden…"
}, },
"login.title": { "login.title": {
"defaultMessage": "Anmelden" "defaultMessage": "Account Login"
}, },
"nginx-config.label": { "nginx-config.label": {
"defaultMessage": "Benutzerdefinierte Nginx Konfiguration" "defaultMessage": "Benutzerdefinierte Nginx Konfiguration"
@@ -399,7 +399,7 @@
"defaultMessage": "Take me home" "defaultMessage": "Take me home"
}, },
"notfound.content": { "notfound.content": {
"defaultMessage": "Es tut uns leid, aber die gesuchte Seite wurde nicht gefunden" "defaultMessage": "We are sorry but the page you are looking for was not found"
}, },
"notfound.title": { "notfound.title": {
"defaultMessage": "Oops… You just found an error page" "defaultMessage": "Oops… You just found an error page"
@@ -495,7 +495,7 @@
"defaultMessage": "Alle Elemente" "defaultMessage": "Alle Elemente"
}, },
"permissions.visibility.title": { "permissions.visibility.title": {
"defaultMessage": "Objektsichtbarkeit" "defaultMessage": "Objekt Sichtbarkeit"
}, },
"permissions.visibility.user": { "permissions.visibility.user": {
"defaultMessage": "Nur erstellte Elemente" "defaultMessage": "Nur erstellte Elemente"
@@ -534,7 +534,7 @@
"defaultMessage": "Administrator" "defaultMessage": "Administrator"
}, },
"role.standard-user": { "role.standard-user": {
"defaultMessage": "Standardbenutzer" "defaultMessage": "Standard User"
}, },
"save": { "save": {
"defaultMessage": "Speichern" "defaultMessage": "Speichern"
@@ -546,7 +546,7 @@
"defaultMessage": "Einstellungen" "defaultMessage": "Einstellungen"
}, },
"settings.default-site": { "settings.default-site": {
"defaultMessage": "Standardseite" "defaultMessage": "Standard Seite"
}, },
"settings.default-site.404": { "settings.default-site.404": {
"defaultMessage": "404 Page" "defaultMessage": "404 Page"
@@ -579,7 +579,7 @@
"defaultMessage": "Login" "defaultMessage": "Login"
}, },
"ssl-certificate": { "ssl-certificate": {
"defaultMessage": "SSL-Zertifikate" "defaultMessage": "SSL Zertifikate"
}, },
"stream": { "stream": {
"defaultMessage": "Stream" "defaultMessage": "Stream"
@@ -645,7 +645,7 @@
"defaultMessage": "Zum Dark Mode wechseln" "defaultMessage": "Zum Dark Mode wechseln"
}, },
"user.switch-light": { "user.switch-light": {
"defaultMessage": "Zum Light Mode wechseln" "defaultMessage": "Zum Light Mode wechslen"
}, },
"username": { "username": {
"defaultMessage": "Benutzername" "defaultMessage": "Benutzername"

View File

@@ -347,9 +347,6 @@
"domain-names.wildcards-not-supported": { "domain-names.wildcards-not-supported": {
"defaultMessage": "Wildcards not supported for this CA" "defaultMessage": "Wildcards not supported for this CA"
}, },
"domains.advanced": {
"defaultMessage": "Advanced"
},
"domains.force-ssl": { "domains.force-ssl": {
"defaultMessage": "Force SSL" "defaultMessage": "Force SSL"
}, },
@@ -362,9 +359,6 @@
"domains.http2-support": { "domains.http2-support": {
"defaultMessage": "HTTP/2 Support" "defaultMessage": "HTTP/2 Support"
}, },
"domains.trust-forwarded-proto": {
"defaultMessage": "Trust Upstream Forwarded Proto Headers"
},
"domains.use-dns": { "domains.use-dns": {
"defaultMessage": "Use DNS Challenge" "defaultMessage": "Use DNS Challenge"
}, },

View File

@@ -1,647 +0,0 @@
{
"access-list": {
"defaultMessage": "Liste d'accès"
},
"access-list.access-count": {
"defaultMessage": "{count} {count, plural, one {Règle} other {Règles}}"
},
"access-list.auth-count": {
"defaultMessage": "{count} {count, plural, one {Utilisateur} other {Utilisateurs}}"
},
"access-list.help-rules-last": {
"defaultMessage": "S'il existe au moins une règle, cette règle de refuser tout sera ajoutée en dernier."
},
"access-list.help.rules-order": {
"defaultMessage": "Notez que les directives autoriser et refuser seront appliquées dans l'ordre où elles sont définies."
},
"access-list.pass-auth": {
"defaultMessage": "Transmettre l'authentification au serveur en amont"
},
"access-list.public": {
"defaultMessage": "Accessible au public"
},
"access-list.public.subtitle": {
"defaultMessage": "Aucune authentification de base requise"
},
"access-list.satisfy-any": {
"defaultMessage": "Valide n'importe quelle règle"
},
"access-list.subtitle": {
"defaultMessage": "{utilisateurs} {utilisateurs, plural, one {Utilisateur} other {Utilisateurs}}, {règles} {règles, plural, one {Règle} other {Règles}} - Crée: {date}"
},
"access-lists": {
"defaultMessage": "Listes d'accès"
},
"action.add": {
"defaultMessage": "Ajouter"
},
"action.add-location": {
"defaultMessage": "Ajouter localisation"
},
"action.close": {
"defaultMessage": "Fermer"
},
"action.delete": {
"defaultMessage": "Supprimer"
},
"action.disable": {
"defaultMessage": "Désactiver"
},
"action.download": {
"defaultMessage": "Télécharger"
},
"action.edit": {
"defaultMessage": "Modifier"
},
"action.enable": {
"defaultMessage": "Activer"
},
"action.permissions": {
"defaultMessage": "Permissions"
},
"action.renew": {
"defaultMessage": "Renouveler"
},
"action.view-details": {
"defaultMessage": "Voir les Détails"
},
"auditlogs": {
"defaultMessage": "Journaux d'audit"
},
"cancel": {
"defaultMessage": "Annuler"
},
"certificate": {
"defaultMessage": "Certificat"
},
"certificate.custom-certificate": {
"defaultMessage": "Certificat"
},
"certificate.custom-certificate-key": {
"defaultMessage": "Clé du Certificat"
},
"certificate.custom-intermediate": {
"defaultMessage": "Certificat intermédiaire"
},
"certificate.in-use": {
"defaultMessage": "Utilisé"
},
"certificate.none.subtitle": {
"defaultMessage": "Aucun certificat assigné"
},
"certificate.none.subtitle.for-http": {
"defaultMessage": "Cet hôte n'utilisera pas le HTTPS"
},
"certificate.none.title": {
"defaultMessage": "Aucun"
},
"certificate.not-in-use": {
"defaultMessage": "Non utilisé"
},
"certificate.renew": {
"defaultMessage": "Renouveler Certificat"
},
"certificates": {
"defaultMessage": "Certificats"
},
"certificates.custom": {
"defaultMessage": "Certificat personnalisé"
},
"certificates.custom.warning": {
"defaultMessage": "Les fichiers de clé protégés par une passphrase ne sont pas acceptés."
},
"certificates.dns.credentials": {
"defaultMessage": "Contenu du fichier d'identifiants"
},
"certificates.dns.credentials-note": {
"defaultMessage": "Ce plugin nécessite un fichier de configuration contenant un jeton d'API ou d'autres informations d'identification pour votre fournisseur."
},
"certificates.dns.credentials-warning": {
"defaultMessage": "Ces données seront stockées en clair dans la base de données et dans un fichier!"
},
"certificates.dns.propagation-seconds": {
"defaultMessage": "Propagation Seconds"
},
"certificates.dns.propagation-seconds-note": {
"defaultMessage": "Laisser vide pour utiliser la valeur par défaut du plugin. Nombre de secondes à attendre pour la propagation DNS."
},
"certificates.dns.provider": {
"defaultMessage": "Fournisseur DNS"
},
"certificates.dns.warning": {
"defaultMessage": "Cette section requiert une certaine connaissance de Certbot et de ses plugins DNS. Veuillez consulter la documentation des plugins correspondants."
},
"certificates.http.reachability-404": {
"defaultMessage": "Un serveur a été trouvé sur ce domaine, mais il ne semble pas s'agir de Nginx Proxy Manager. Veuillez vérifier que votre domaine pointe bien vers l'adresse IP où votre instance NPM est exécutée."
},
"certificates.http.reachability-failed-to-check": {
"defaultMessage": "Impossible de vérifier l'accessibilité en raison d'une erreur de communication avec site24x7.com."
},
"certificates.http.reachability-not-resolved": {
"defaultMessage": "Aucun serveur n'est disponible pour ce domaine. Veuillez vérifier que votre domaine existe et pointe vers l'adresse IP où votre instance NPM est exécutée. Si nécessaire, le port 80 est ouvert dans votre routeur."
},
"certificates.http.reachability-ok": {
"defaultMessage": "Votre serveur est accessible et la création de certificats devrait être possible."
},
"certificates.http.reachability-other": {
"defaultMessage": "Un serveur a été trouvé sur ce domaine, mais il a renvoyé un code d'état inattendu {code}. S'agit-il du serveur NPM ? Veuillez vérifier que votre domaine pointe bien vers l'adresse IP où votre instance NPM est exécutée."
},
"certificates.http.reachability-wrong-data": {
"defaultMessage": "Un serveur a été trouvé sur ce domaine, mais il a renvoyé des données inattendues. S'agit-il du serveur NPM ? Veuillez vérifier que votre domaine pointe bien vers l'adresse IP où votre instance NPM est exécutée."
},
"certificates.http.test-results": {
"defaultMessage": "Résultats du test"
},
"certificates.http.warning": {
"defaultMessage": "Ces domaines doivent déjà être configurés pour pointer vers cette installation."
},
"certificates.request.subtitle": {
"defaultMessage": "avec Let's Encrypt"
},
"certificates.request.title": {
"defaultMessage": "Demander un nouveau certificat"
},
"column.access": {
"defaultMessage": "Accès"
},
"column.authorization": {
"defaultMessage": "Autorisation"
},
"column.authorizations": {
"defaultMessage": "Autorisations"
},
"column.custom-locations": {
"defaultMessage": "Emplacement personnalisé"
},
"column.destination": {
"defaultMessage": "Destination"
},
"column.details": {
"defaultMessage": "Détails"
},
"column.email": {
"defaultMessage": "eMail"
},
"column.event": {
"defaultMessage": "Évènement"
},
"column.expires": {
"defaultMessage": "Expire"
},
"column.http-code": {
"defaultMessage": "Code HTTP"
},
"column.incoming-port": {
"defaultMessage": "Port entrant"
},
"column.name": {
"defaultMessage": "Nom"
},
"column.protocol": {
"defaultMessage": "Protocole"
},
"column.provider": {
"defaultMessage": "Fournisseur"
},
"column.roles": {
"defaultMessage": "Rôles"
},
"column.rules": {
"defaultMessage": "Règles"
},
"column.satisfy": {
"defaultMessage": "Valide"
},
"column.satisfy-all": {
"defaultMessage": "All"
},
"column.satisfy-any": {
"defaultMessage": "Any"
},
"column.scheme": {
"defaultMessage": "Schéma"
},
"column.source": {
"defaultMessage": "Source"
},
"column.ssl": {
"defaultMessage": "SSL"
},
"column.status": {
"defaultMessage": "Statut"
},
"created-on": {
"defaultMessage": "Créé : {date}"
},
"dashboard": {
"defaultMessage": "Tableau de bord"
},
"dead-host": {
"defaultMessage": "Hôte 404"
},
"dead-hosts": {
"defaultMessage": "Hôtes 404"
},
"dead-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Hôte 404} other {Hôtes 404}}"
},
"disabled": {
"defaultMessage": "Désactivé"
},
"domain-names": {
"defaultMessage": "Noms de domaine"
},
"domain-names.max": {
"defaultMessage": "{count} noms de domaine au maximum"
},
"domain-names.placeholder": {
"defaultMessage": "Commencez à écrire pour ajouter un domaine…"
},
"domain-names.wildcards-not-permitted": {
"defaultMessage": "Les Wildcards ne sont pas permises dans ce cas"
},
"domain-names.wildcards-not-supported": {
"defaultMessage": "Les Wildcards ne sont pas prises en charge par cette autorité de certification."
},
"domains.force-ssl": {
"defaultMessage": "Forcer SSL"
},
"domains.hsts-enabled": {
"defaultMessage": "HSTS activé"
},
"domains.hsts-subdomains": {
"defaultMessage": "Sous-domaines HSTS"
},
"domains.http2-support": {
"defaultMessage": "Prise en charge de HTTP/2"
},
"domains.use-dns": {
"defaultMessage": "Utiliser le challenge DNS"
},
"email-address": {
"defaultMessage": "Adresse eMail"
},
"empty-search": {
"defaultMessage": "Aucun résultat trouvé"
},
"empty-subtitle": {
"defaultMessage": "Pourquoi n'en créez-vous pas un ?"
},
"enabled": {
"defaultMessage": "Activé"
},
"error.access.at-least-one": {
"defaultMessage": "Une autorisation ou une règle d'accès est requise."
},
"error.access.duplicate-usernames": {
"defaultMessage": "Les noms d'utilisateurs autorisés doivent être uniques"
},
"error.invalid-auth": {
"defaultMessage": "Adresse eMail ou mot de passe invalide"
},
"error.invalid-domain": {
"defaultMessage": "Domaine invalide: {domain}"
},
"error.invalid-email": {
"defaultMessage": "Adresse eMail invalide"
},
"error.max-character-length": {
"defaultMessage": "La longueur maximale est {max} caractère{max, plural, one {} other {s}}"
},
"error.max-domains": {
"defaultMessage": "Trop de domaines, le maximum est {max}"
},
"error.maximum": {
"defaultMessage": "Le maximum est {max}"
},
"error.min-character-length": {
"defaultMessage": "La longueur minimale est {min} caractère{min, plural, one {} other {s}}"
},
"error.minimum": {
"defaultMessage": "Le minimum est {min}"
},
"error.passwords-must-match": {
"defaultMessage": "Les mots de passe doivent correspondre"
},
"error.required": {
"defaultMessage": "Ceci est obligatoire"
},
"expires.on": {
"defaultMessage": "Expire: {date}"
},
"footer.github-fork": {
"defaultMessage": "Forkez-moi sur Github"
},
"host.flags.block-exploits": {
"defaultMessage": "Bloquer les exploits courants"
},
"host.flags.cache-assets": {
"defaultMessage": "Ressources du cache"
},
"host.flags.preserve-path": {
"defaultMessage": "Préserver le chemin"
},
"host.flags.protocols": {
"defaultMessage": "Protocoles"
},
"host.flags.websockets-upgrade": {
"defaultMessage": "Prise en charge de Websockets"
},
"host.forward-port": {
"defaultMessage": "Port de redirection"
},
"host.forward-scheme": {
"defaultMessage": "Schéma"
},
"hosts": {
"defaultMessage": "Hôtes"
},
"http-only": {
"defaultMessage": "HTTP uniquement"
},
"lets-encrypt": {
"defaultMessage": "Let's Encrypt"
},
"lets-encrypt-via-dns": {
"defaultMessage": "Let's Encrypt via DNS"
},
"lets-encrypt-via-http": {
"defaultMessage": "Let's Encrypt via HTTP"
},
"loading": {
"defaultMessage": "Chargement…"
},
"login.title": {
"defaultMessage": "Connectez-vous à votre compte"
},
"nginx-config.label": {
"defaultMessage": "Configuration Nginx personnalisée"
},
"nginx-config.placeholder": {
"defaultMessage": "# Mettez ici votre configuration Nginx personnalisé à vos risques et périls!"
},
"no-permission-error": {
"defaultMessage": "Vous n'avez pas la permission de voir ce contenu."
},
"notfound.action": {
"defaultMessage": "Ramenez-moi à l'accueil"
},
"notfound.content": {
"defaultMessage": "Nous sommes désolés, mais la page que vous cherchez est introuvable"
},
"notfound.title": {
"defaultMessage": "Oops… Vous avez découvert une page d'erreur"
},
"notification.error": {
"defaultMessage": "Erreur"
},
"notification.object-deleted": {
"defaultMessage": "{object} a été supprimé"
},
"notification.object-disabled": {
"defaultMessage": "{object} a été désactivé"
},
"notification.object-enabled": {
"defaultMessage": "{object} a été activé"
},
"notification.object-renewed": {
"defaultMessage": "{object} a été renouvelé"
},
"notification.object-saved": {
"defaultMessage": "{object} a été enregistré"
},
"notification.success": {
"defaultMessage": "Réussi"
},
"object.actions-title": {
"defaultMessage": "{object} #{id}"
},
"object.add": {
"defaultMessage": "Ajouter {object}"
},
"object.delete": {
"defaultMessage": "Supprimer {object}"
},
"object.delete.content": {
"defaultMessage": "Êtes-vous sûr de vouloir supprimer {object}?"
},
"object.edit": {
"defaultMessage": "Modifier {object}"
},
"object.empty": {
"defaultMessage": "Il n'y a aucun {objects}"
},
"object.event.created": {
"defaultMessage": "{object} créé"
},
"object.event.deleted": {
"defaultMessage": "{object} supprimé"
},
"object.event.disabled": {
"defaultMessage": "{object} désactivé"
},
"object.event.enabled": {
"defaultMessage": "{object} activé"
},
"object.event.renewed": {
"defaultMessage": "{object} renouvelé"
},
"object.event.updated": {
"defaultMessage": "{object} mis à jour"
},
"offline": {
"defaultMessage": "Hors ligne"
},
"online": {
"defaultMessage": "En ligne"
},
"options": {
"defaultMessage": "Options"
},
"password": {
"defaultMessage": "Mot de passe"
},
"password.generate": {
"defaultMessage": "Générer un mot de passe aléatoire"
},
"password.hide": {
"defaultMessage": "Masquer le mot de passe"
},
"password.show": {
"defaultMessage": "Afficher le mot de passe"
},
"permissions.hidden": {
"defaultMessage": "Masquer"
},
"permissions.manage": {
"defaultMessage": "Gérer"
},
"permissions.view": {
"defaultMessage": "Voir uniquement"
},
"permissions.visibility.all": {
"defaultMessage": "Tous les éléments"
},
"permissions.visibility.title": {
"defaultMessage": "Éléments visibles"
},
"permissions.visibility.user": {
"defaultMessage": "Éléments créés uniquement"
},
"proxy-host": {
"defaultMessage": "Hôte proxy"
},
"proxy-host.forward-host": {
"defaultMessage": "Nom d'hôte de redirection / IP"
},
"proxy-hosts": {
"defaultMessage": "Hôtes proxy"
},
"proxy-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Hôte proxy} other {Hôtes proxy}}"
},
"public": {
"defaultMessage": "Publique"
},
"redirection-host": {
"defaultMessage": "Hôte de redirection"
},
"redirection-host.forward-domain": {
"defaultMessage": "Domaine de redirection"
},
"redirection-host.forward-http-code": {
"defaultMessage": "Code HTTP"
},
"redirection-hosts": {
"defaultMessage": "Hôtes de redirection"
},
"redirection-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Hôte de redirection} other {Hôtes de redirection}}"
},
"role.admin": {
"defaultMessage": "Administrateur"
},
"role.standard-user": {
"defaultMessage": "Utilisateur standard"
},
"save": {
"defaultMessage": "Enregistrer"
},
"setting": {
"defaultMessage": "Paramètre"
},
"settings": {
"defaultMessage": "Paramètres"
},
"settings.default-site": {
"defaultMessage": "Site par défaut"
},
"settings.default-site.404": {
"defaultMessage": "Page 404"
},
"settings.default-site.444": {
"defaultMessage": "Aucune réponse (444)"
},
"settings.default-site.congratulations": {
"defaultMessage": "Page de félicitations"
},
"settings.default-site.description": {
"defaultMessage": "ce qu'il faut afficher lorsqu'un hôte inconnu est détecté par Nginx"
},
"settings.default-site.html": {
"defaultMessage": "HTML personnalisé"
},
"settings.default-site.html.placeholder": {
"defaultMessage": "<!-- Mettez votre contenu HTML personnalisé ici -->"
},
"settings.default-site.redirect": {
"defaultMessage": "Redirection"
},
"setup.preamble": {
"defaultMessage": "Commencez par créer votre compte administrateur."
},
"setup.title": {
"defaultMessage": "Bienvenue!"
},
"sign-in": {
"defaultMessage": "Se connecter"
},
"ssl-certificate": {
"defaultMessage": "Certificat SSL"
},
"stream": {
"defaultMessage": "Stream"
},
"stream.forward-host": {
"defaultMessage": "Hôte destinataire"
},
"stream.incoming-port": {
"defaultMessage": "Port d'entrée"
},
"streams": {
"defaultMessage": "Streams"
},
"streams.count": {
"defaultMessage": "{count} {count, plural, one {Stream} other {Streams}}"
},
"streams.tcp": {
"defaultMessage": "TCP"
},
"streams.udp": {
"defaultMessage": "UDP"
},
"test": {
"defaultMessage": "Test"
},
"update-available": {
"defaultMessage": "Mise à jour disponible: {latestVersion}"
},
"user": {
"defaultMessage": "Utilisateur"
},
"user.change-password": {
"defaultMessage": "Modifier le mot de passe"
},
"user.confirm-password": {
"defaultMessage": "Confirmer le mot de passe"
},
"user.current-password": {
"defaultMessage": "Mot de passe actuel"
},
"user.edit-profile": {
"defaultMessage": "Modifier le profil"
},
"user.full-name": {
"defaultMessage": "Nom complet"
},
"user.login-as": {
"defaultMessage": "Se connecter en tant que {name}"
},
"user.logout": {
"defaultMessage": "Déconnexion"
},
"user.new-password": {
"defaultMessage": "Nouveau mot de passe"
},
"user.nickname": {
"defaultMessage": "Pseudonyme"
},
"user.set-password": {
"defaultMessage": "Définir le mot de passe"
},
"user.set-permissions": {
"defaultMessage": "Définir les autorisations pour {name}"
},
"user.switch-dark": {
"defaultMessage": "Passer au mode Sombre"
},
"user.switch-light": {
"defaultMessage": "Passer au mode Lumineux"
},
"username": {
"defaultMessage": "Nom d'utilisateur"
},
"users": {
"defaultMessage": "Utilisateurs"
}
}

View File

@@ -1,683 +0,0 @@
{
"access-list": {
"defaultMessage": "Liosta Rochtana"
},
"access-list.access-count": {
"defaultMessage": "{count} {count, plural, one {Rial} other {Rialacha}}"
},
"access-list.auth-count": {
"defaultMessage": "{count} {count, plural, one {Úsáideoir} other {Úsáideoirí}}"
},
"access-list.help-rules-last": {
"defaultMessage": "Nuair a bhíonn riail amháin ar a laghad ann, cuirfear an riail seo chun gach rud a dhiúltú leis an gceann deireanach."
},
"access-list.help.rules-order": {
"defaultMessage": "Tabhair faoi deara go gcuirfear na treoracha ceadaigh agus diúltaigh i bhfeidhm san ord a shainmhínítear iad."
},
"access-list.pass-auth": {
"defaultMessage": "Tabhair Údarú chuig an Sruth Uachtarach"
},
"access-list.public": {
"defaultMessage": "Inrochtana don Phobal"
},
"access-list.public.subtitle": {
"defaultMessage": "Níl aon údarú bunúsach ag teastáil"
},
"access-list.rule-source.placeholder": {
"defaultMessage": "192.168.1.100 nó 192.168.1.0/24 nó 2001:0db8::/32"
},
"access-list.satisfy-any": {
"defaultMessage": "Sásaigh Aon"
},
"access-list.subtitle": {
"defaultMessage": "{users} {users, plural, one {Úsáideoir} other {Úsáideoirí}}, {rules} {rules, plural, one {Riail} other {Rialacha}} - Cruthaithe: {date}"
},
"access-lists": {
"defaultMessage": "Liostaí Rochtana"
},
"action.add": {
"defaultMessage": "Cuir leis"
},
"action.add-location": {
"defaultMessage": "Cuir Suíomh leis"
},
"action.allow": {
"defaultMessage": "Ceadaigh"
},
"action.close": {
"defaultMessage": "Dún"
},
"action.delete": {
"defaultMessage": "Scrios"
},
"action.deny": {
"defaultMessage": "Diúltaigh"
},
"action.disable": {
"defaultMessage": "Díchumasaigh"
},
"action.download": {
"defaultMessage": "Íoslódáil"
},
"action.edit": {
"defaultMessage": "Cuir in Eagar"
},
"action.enable": {
"defaultMessage": "Cumasaigh"
},
"action.permissions": {
"defaultMessage": "Ceadanna"
},
"action.renew": {
"defaultMessage": "Athnuachan"
},
"action.view-details": {
"defaultMessage": "Féach Sonraí"
},
"auditlogs": {
"defaultMessage": "Logaí Iniúchta"
},
"auto": {
"defaultMessage": "Uath"
},
"cancel": {
"defaultMessage": "Cealaigh"
},
"certificate": {
"defaultMessage": "Teastas"
},
"certificate.custom-certificate": {
"defaultMessage": "Teastas"
},
"certificate.custom-certificate-key": {
"defaultMessage": "Eochair Teastais"
},
"certificate.custom-intermediate": {
"defaultMessage": "Teastas Idirmheánach"
},
"certificate.in-use": {
"defaultMessage": "In Úsáid"
},
"certificate.none.subtitle": {
"defaultMessage": "Níor sannadh aon deimhniú"
},
"certificate.none.subtitle.for-http": {
"defaultMessage": "Ní úsáidfidh an t-óstach seo HTTPS"
},
"certificate.none.title": {
"defaultMessage": "Dada"
},
"certificate.not-in-use": {
"defaultMessage": "Níor Úsáideadh"
},
"certificate.renew": {
"defaultMessage": "Athnuachan an Teastais"
},
"certificates": {
"defaultMessage": "Teastais"
},
"certificates.custom": {
"defaultMessage": "Teastas Saincheaptha"
},
"certificates.custom.warning": {
"defaultMessage": "Ní thacaítear le comhaid eochair atá cosanta le frása faire."
},
"certificates.dns.credentials": {
"defaultMessage": "Ábhar Comhaid Dintiúir"
},
"certificates.dns.credentials-note": {
"defaultMessage": "Éilíonn an breiseán seo comhad cumraíochta ina bhfuil comhartha API nó dintiúir eile do do sholáthraí."
},
"certificates.dns.credentials-warning": {
"defaultMessage": "Stórálfar an fhaisnéis seo mar théacs simplí sa bhunachar sonraí agus i gcomhad!"
},
"certificates.dns.propagation-seconds": {
"defaultMessage": "Soicindí Iolraithe"
},
"certificates.dns.propagation-seconds-note": {
"defaultMessage": "Fág folamh chun luach réamhshocraithe na mbreiseán a úsáid. Líon na soicindí le fanacht le haghaidh iomadú DNS."
},
"certificates.dns.provider": {
"defaultMessage": "Soláthraí DNS"
},
"certificates.dns.provider.placeholder": {
"defaultMessage": "Roghnaigh Soláthraí..."
},
"certificates.dns.warning": {
"defaultMessage": "Éilíonn an chuid seo roinnt eolais faoi Certbot agus a bhreiseáin DNS. Féach ar dhoiciméadacht na mbreiseán faoi seach, le do thoil."
},
"certificates.http.reachability-404": {
"defaultMessage": "Tá freastalaí aimsithe ag an bhfearann seo ach ní cosúil gur Bainisteoir Proxy Nginx atá ann. Déan cinnte go bhfuil do fhearann ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith."
},
"certificates.http.reachability-failed-to-check": {
"defaultMessage": "Theip ar sheiceáil an inrochtaineachta mar gheall ar earráid chumarsáide le site24x7.com."
},
"certificates.http.reachability-not-resolved": {
"defaultMessage": "Níl aon fhreastalaí ar fáil ag an bhfearann seo. Cinntigh le do thoil go bhfuil do fhearann ann agus go bhfuil sé ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith agus más gá, go bhfuil port 80 curtha ar aghaidh i do ródaire."
},
"certificates.http.reachability-ok": {
"defaultMessage": "Tá rochtain ar do fhreastalaí agus ba cheart go mbeadh sé indéanta deimhnithe a chruthú."
},
"certificates.http.reachability-other": {
"defaultMessage": "Tá freastalaí aimsithe ag an bhfearann seo ach thug sé cód stádais gan choinne {code} ar ais. An é an freastalaí NPM atá ann? Déan cinnte go bhfuil do fhearann ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith."
},
"certificates.http.reachability-wrong-data": {
"defaultMessage": "Tá freastalaí aimsithe ag an bhfearann seo ach thug sé sonraí gan choinne ar ais. An é an freastalaí NPM atá ann? Déan cinnte go bhfuil do fhearann ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith."
},
"certificates.http.test-results": {
"defaultMessage": "Torthaí Tástála"
},
"certificates.http.warning": {
"defaultMessage": "Ní mór na fearainn seo a bheith cumraithe cheana féin chun pointeáil chuig an suiteáil seo."
},
"certificates.request.subtitle": {
"defaultMessage": "le Let's Encrypt"
},
"certificates.request.title": {
"defaultMessage": "Iarr Teastas nua"
},
"column.access": {
"defaultMessage": "Rochtain"
},
"column.authorization": {
"defaultMessage": "Údarú"
},
"column.authorizations": {
"defaultMessage": "Údaruithe"
},
"column.custom-locations": {
"defaultMessage": "Suíomhanna Saincheaptha"
},
"column.destination": {
"defaultMessage": "Ceann Scríbe"
},
"column.details": {
"defaultMessage": "Sonraí"
},
"column.email": {
"defaultMessage": "Ríomhphost"
},
"column.event": {
"defaultMessage": "Imeacht"
},
"column.expires": {
"defaultMessage": "Éagaíonn"
},
"column.http-code": {
"defaultMessage": "Cód HTTP"
},
"column.incoming-port": {
"defaultMessage": "Port Isteach"
},
"column.name": {
"defaultMessage": "Ainm"
},
"column.protocol": {
"defaultMessage": "Prótacal"
},
"column.provider": {
"defaultMessage": "Soláthraí"
},
"column.roles": {
"defaultMessage": "Róil"
},
"column.rules": {
"defaultMessage": "Rialacha"
},
"column.satisfy": {
"defaultMessage": "Sásamh"
},
"column.satisfy-all": {
"defaultMessage": "Gach"
},
"column.satisfy-any": {
"defaultMessage": "Aon"
},
"column.scheme": {
"defaultMessage": "Scéim"
},
"column.source": {
"defaultMessage": "Foinse"
},
"column.ssl": {
"defaultMessage": "SSL"
},
"column.status": {
"defaultMessage": "Stádas"
},
"created-on": {
"defaultMessage": "Cruthaithe: {date}"
},
"dashboard": {
"defaultMessage": "Painéal Rialaithe"
},
"dead-host": {
"defaultMessage": "Óstach 404"
},
"dead-hosts": {
"defaultMessage": "404 Óstaigh"
},
"dead-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Óstach 404} other {Óstaigh 404}}"
},
"disabled": {
"defaultMessage": "Míchumasaithe"
},
"domain-names": {
"defaultMessage": "Ainmneacha Fearainn"
},
"domain-names.max": {
"defaultMessage": "Uasmhéid d'ainmneacha fearainn: {count}"
},
"domain-names.placeholder": {
"defaultMessage": "Tosaigh ag clóscríobh chun fearann a chur leis..."
},
"domain-names.wildcards-not-permitted": {
"defaultMessage": "Ní cheadaítear cártaí fiáine don chineál seo"
},
"domain-names.wildcards-not-supported": {
"defaultMessage": "Ní thacaítear le cártaí fiáine don ÚD seo"
},
"domains.force-ssl": {
"defaultMessage": "Fórsáil SSL"
},
"domains.hsts-enabled": {
"defaultMessage": "Cumasaithe HSTS"
},
"domains.hsts-subdomains": {
"defaultMessage": "Fo-fhearainn HSTS"
},
"domains.http2-support": {
"defaultMessage": "Tacaíocht HTTP/2"
},
"domains.use-dns": {
"defaultMessage": "Úsáid Dúshlán DNS"
},
"email-address": {
"defaultMessage": "Seoladh ríomhphoist"
},
"empty-search": {
"defaultMessage": "Níor aimsíodh aon torthaí"
},
"empty-subtitle": {
"defaultMessage": "Cén fáth nach gcruthaíonn tú ceann?"
},
"enabled": {
"defaultMessage": "Cumasaithe"
},
"error.access.at-least-one": {
"defaultMessage": "Tá Údarú amháin nó Riail Rochtana amháin ag teastáil"
},
"error.access.duplicate-usernames": {
"defaultMessage": "Ní mór dainmneacha úsáideora údaraithe a bheith uathúil"
},
"error.invalid-auth": {
"defaultMessage": "Ríomhphost nó pasfhocal neamhbhailí"
},
"error.invalid-domain": {
"defaultMessage": "Fearann neamhbhailí: {domain}"
},
"error.invalid-email": {
"defaultMessage": "Seoladh ríomhphoist neamhbhailí"
},
"error.max-character-length": {
"defaultMessage": "Is é an fad uasta ná {max} carachtar{max, plural, one {} other {anna}}"
},
"error.max-domains": {
"defaultMessage": "An iomarca fearainn, is é {max} an t-uasmhéid"
},
"error.maximum": {
"defaultMessage": "Is é {max} an t-uasmhéid"
},
"error.min-character-length": {
"defaultMessage": "Is é an fad íosta ná {min} carachtar{min, plural, one {} other {anna}}"
},
"error.minimum": {
"defaultMessage": "Is é {min} an t-íosmhéid"
},
"error.passwords-must-match": {
"defaultMessage": "Ní mór pasfhocail a bheith mar a chéile"
},
"error.required": {
"defaultMessage": "Tá sé seo riachtanach"
},
"expires.on": {
"defaultMessage": "Éagaíonn: {date}"
},
"footer.github-fork": {
"defaultMessage": "Forc mé ar Github"
},
"host.flags.block-exploits": {
"defaultMessage": "Blocáil Easnaimh Choitianta"
},
"host.flags.cache-assets": {
"defaultMessage": "Sócmhainní Taisce"
},
"host.flags.preserve-path": {
"defaultMessage": "Cosán a Chaomhnú"
},
"host.flags.protocols": {
"defaultMessage": "Prótacail"
},
"host.flags.websockets-upgrade": {
"defaultMessage": "Tacaíocht Websockets"
},
"host.forward-port": {
"defaultMessage": "Port Ar Aghaidh"
},
"host.forward-scheme": {
"defaultMessage": "Scéim"
},
"hosts": {
"defaultMessage": "Óstaigh"
},
"http-only": {
"defaultMessage": "HTTP Amháin"
},
"lets-encrypt": {
"defaultMessage": "Let's Encrypt"
},
"lets-encrypt-via-dns": {
"defaultMessage": "Let's Encrypt trí DNS"
},
"lets-encrypt-via-http": {
"defaultMessage": "Let's Encrypt trí HTTP"
},
"loading": {
"defaultMessage": "Ag lódáil…"
},
"login.title": {
"defaultMessage": "Logáil isteach i do chuntas"
},
"nginx-config.label": {
"defaultMessage": "Cumraíocht Nginx Saincheaptha"
},
"nginx-config.placeholder": {
"defaultMessage": "# Cuir isteach do chumraíocht saincheaptha Nginx anseo ar do phriacal féin!"
},
"no-permission-error": {
"defaultMessage": "Níl rochtain agat chun seo a fheiceáil."
},
"notfound.action": {
"defaultMessage": "Tabhair abhaile mé"
},
"notfound.content": {
"defaultMessage": "Tá brón orainn ach níor aimsíodh an leathanach atá á lorg agat"
},
"notfound.title": {
"defaultMessage": "Úps… Fuair tú leathanach earráide díreach anois."
},
"notification.error": {
"defaultMessage": "Earráid"
},
"notification.object-deleted": {
"defaultMessage": "Scriosadh {object}"
},
"notification.object-disabled": {
"defaultMessage": "Tá {object} díchumasaithe"
},
"notification.object-enabled": {
"defaultMessage": "Tá {object} cumasaithe"
},
"notification.object-renewed": {
"defaultMessage": "Tá {object} athnuaite"
},
"notification.object-saved": {
"defaultMessage": "Tá {object} sábháilte"
},
"notification.success": {
"defaultMessage": "Rath"
},
"object.actions-title": {
"defaultMessage": "{object} #{id}"
},
"object.add": {
"defaultMessage": "Cuir {object} leis"
},
"object.delete": {
"defaultMessage": "Scrios {object}"
},
"object.delete.content": {
"defaultMessage": "An bhfuil tú cinnte gur mian leat an {object} seo a scriosadh?"
},
"object.edit": {
"defaultMessage": "Cuir in eagar {object}"
},
"object.empty": {
"defaultMessage": "Níl aon {objects} ann"
},
"object.event.created": {
"defaultMessage": "Cruthaithe {object}"
},
"object.event.deleted": {
"defaultMessage": "Scriosadh {object}"
},
"object.event.disabled": {
"defaultMessage": "Díchumasaithe {object}"
},
"object.event.enabled": {
"defaultMessage": "Cumasaithe {object}"
},
"object.event.renewed": {
"defaultMessage": "Athnuaite {object}"
},
"object.event.updated": {
"defaultMessage": "Nuashonraithe {object}"
},
"offline": {
"defaultMessage": "As líne"
},
"online": {
"defaultMessage": "Ar líne"
},
"options": {
"defaultMessage": "Roghanna"
},
"password": {
"defaultMessage": "Pasfhocal"
},
"password.generate": {
"defaultMessage": "Gin pasfhocal randamach"
},
"password.hide": {
"defaultMessage": "Folaigh Pasfhocal"
},
"password.show": {
"defaultMessage": "Taispeáin Pasfhocal"
},
"permissions.hidden": {
"defaultMessage": "I bhfolach"
},
"permissions.manage": {
"defaultMessage": "Bainistigh"
},
"permissions.view": {
"defaultMessage": "Amharc Amháin"
},
"permissions.visibility.all": {
"defaultMessage": "Gach Míreanna"
},
"permissions.visibility.title": {
"defaultMessage": "Infheictheacht Míre"
},
"permissions.visibility.user": {
"defaultMessage": "Míreanna Cruthaithe Amháin"
},
"proxy-host": {
"defaultMessage": "Óstach Seachfhreastalaí"
},
"proxy-host.forward-host": {
"defaultMessage": "Ainm Óstach / IP Ar Aghaidh"
},
"proxy-hosts": {
"defaultMessage": "Óstaigh Seachfhreastalaí"
},
"proxy-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Óstach Seachfhreastalaí} other {Óstaigh Seachfhreastalaí}}"
},
"public": {
"defaultMessage": "Poiblí"
},
"redirection-host": {
"defaultMessage": "Óstach Athsheolta"
},
"redirection-host.forward-domain": {
"defaultMessage": "Fearann Ar Aghaidh"
},
"redirection-host.forward-http-code": {
"defaultMessage": "Cód HTTP"
},
"redirection-hosts": {
"defaultMessage": "Óstaigh Athsheolta"
},
"redirection-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Athsheoladh Óstach} other {Athsheoladh Óstaigh}}"
},
"redirection-hosts.http-code.300": {
"defaultMessage": "300 Rogha Ilghnéitheach"
},
"redirection-hosts.http-code.301": {
"defaultMessage": "301 Bogtha go buan"
},
"redirection-hosts.http-code.302": {
"defaultMessage": "302 Bogtha go sealadach"
},
"redirection-hosts.http-code.303": {
"defaultMessage": "303 Féach eile"
},
"redirection-hosts.http-code.307": {
"defaultMessage": "307 Atreorú sealadach"
},
"redirection-hosts.http-code.308": {
"defaultMessage": "308 Athsheoladh buan"
},
"role.admin": {
"defaultMessage": "Riarthóir"
},
"role.standard-user": {
"defaultMessage": "Úsáideoir Caighdeánach"
},
"save": {
"defaultMessage": "Sábháil"
},
"setting": {
"defaultMessage": "Socrú"
},
"settings": {
"defaultMessage": "Socruithe"
},
"settings.default-site": {
"defaultMessage": "Suíomh Réamhshocraithe"
},
"settings.default-site.404": {
"defaultMessage": "Leathanach 404"
},
"settings.default-site.444": {
"defaultMessage": "Gan Freagra (444)"
},
"settings.default-site.congratulations": {
"defaultMessage": "Leathanach Comhghairdeas"
},
"settings.default-site.description": {
"defaultMessage": "Cad atá le taispeáint nuair a bhuaileann óstach anaithnid Nginx"
},
"settings.default-site.html": {
"defaultMessage": "HTML saincheaptha"
},
"settings.default-site.html.placeholder": {
"defaultMessage": "<!-- Cuir isteach dábhar HTML saincheaptha anseo -->"
},
"settings.default-site.redirect": {
"defaultMessage": "Atreorú"
},
"setup.preamble": {
"defaultMessage": "Tosaigh trí do chuntas riarthóra a chruthú."
},
"setup.title": {
"defaultMessage": "Fáilte!"
},
"sign-in": {
"defaultMessage": "Sínigh isteach"
},
"ssl-certificate": {
"defaultMessage": "Teastas SSL"
},
"stream": {
"defaultMessage": "Sruth"
},
"stream.forward-host": {
"defaultMessage": "Óstach Ar Aghaidh"
},
"stream.forward-host.placeholder": {
"defaultMessage": "example.com nó 10.0.0.1 nó 2001:db8:3333:4444:5555:6666:7777:8888"
},
"stream.incoming-port": {
"defaultMessage": "Port Isteach"
},
"streams": {
"defaultMessage": "Sruthanna"
},
"streams.count": {
"defaultMessage": "{count} {count, plural, one {Sruth} other {Sruthanna}}"
},
"streams.tcp": {
"defaultMessage": "TCP"
},
"streams.udp": {
"defaultMessage": "UDP"
},
"test": {
"defaultMessage": "Tástáil"
},
"update-available": {
"defaultMessage": "Nuashonrú ar Fáil: {latestVersion}"
},
"user": {
"defaultMessage": "Úsáideoir"
},
"user.change-password": {
"defaultMessage": "Athraigh Pasfhocal"
},
"user.confirm-password": {
"defaultMessage": "Deimhnigh Pasfhocal"
},
"user.current-password": {
"defaultMessage": "Pasfhocal Reatha"
},
"user.edit-profile": {
"defaultMessage": "Cuir Próifíl in Eagar"
},
"user.full-name": {
"defaultMessage": "Ainm Iomlán"
},
"user.login-as": {
"defaultMessage": "Sínigh isteach mar {name}"
},
"user.logout": {
"defaultMessage": "Logáil Amach"
},
"user.new-password": {
"defaultMessage": "Pasfhocal Nua"
},
"user.nickname": {
"defaultMessage": "Leasainm"
},
"user.set-password": {
"defaultMessage": "Socraigh Pasfhocal"
},
"user.set-permissions": {
"defaultMessage": "Socraigh Ceadanna do {name}"
},
"user.switch-dark": {
"defaultMessage": "Athraigh go Mód Dorcha"
},
"user.switch-light": {
"defaultMessage": "Athraigh go mód Solais"
},
"username": {
"defaultMessage": "Ainm úsáideora"
},
"users": {
"defaultMessage": "Úsáideoirí"
}
}

View File

@@ -1,770 +0,0 @@
{
"2fa.backup-codes-remaining": {
"defaultMessage": "Hátralévő tartalék kódok: {count}"
},
"2fa.backup-warning": {
"defaultMessage": "Mentse el ezeket a tartalék kódokat biztonságos helyre. Minden kód csak egyszer használható."
},
"2fa.disable": {
"defaultMessage": "Kétfaktoros hitelesítés letiltása"
},
"2fa.disable-confirm": {
"defaultMessage": "2FA letiltása"
},
"2fa.disable-warning": {
"defaultMessage": "A kétfaktoros hitelesítés letiltása kevésbé teszi biztonságossá a fiókját."
},
"2fa.disabled": {
"defaultMessage": "Letiltva"
},
"2fa.done": {
"defaultMessage": "Elmentettem a tartalék kódjaimat"
},
"2fa.enable": {
"defaultMessage": "Kétfaktoros hitelesítés engedélyezése"
},
"2fa.enabled": {
"defaultMessage": "Engedélyezve"
},
"2fa.enter-code": {
"defaultMessage": "Adja meg az ellenőrző kódot"
},
"2fa.enter-code-disable": {
"defaultMessage": "Adja meg az ellenőrző kódot a letiltáshoz"
},
"2fa.regenerate": {
"defaultMessage": "Újragenerálás"
},
"2fa.regenerate-backup": {
"defaultMessage": "Tartalék kódok újragenerálása"
},
"2fa.regenerate-instructions": {
"defaultMessage": "Adjon meg egy ellenőrző kódot az új tartalék kódok generálásához. A régi kódok érvénytelenné válnak."
},
"2fa.secret-key": {
"defaultMessage": "Titkos kulcs"
},
"2fa.setup-instructions": {
"defaultMessage": "Olvassa be ezt a QR kódot a hitelesítő alkalmazásával, vagy adja meg a titkot manuálisan."
},
"2fa.status": {
"defaultMessage": "Állapot"
},
"2fa.title": {
"defaultMessage": "Kétfaktoros hitelesítés"
},
"2fa.verify-enable": {
"defaultMessage": "Ellenőrzés és engedélyezés"
},
"access-list": {
"defaultMessage": "Hozzáférési lista"
},
"access-list.access-count": {
"defaultMessage": "{count} {count, plural, one {szabály} other {szabály}}"
},
"access-list.auth-count": {
"defaultMessage": "{count} {count, plural, one {felhasználó} other {felhasználó}}"
},
"access-list.help-rules-last": {
"defaultMessage": "Ha legalább 1 szabály létezik, ez a mindent tiltó szabály utolsóként lesz hozzáadva"
},
"access-list.help.rules-order": {
"defaultMessage": "Vegye figyelembe, hogy az engedélyező és tiltó direktívák a meghatározásuk sorrendjében lesznek alkalmazva."
},
"access-list.pass-auth": {
"defaultMessage": "Hitelesítés továbbítása az upstream felé"
},
"access-list.public": {
"defaultMessage": "Nyilvánosan elérhető"
},
"access-list.public.subtitle": {
"defaultMessage": "Alapszintű hitelesítés nem szükséges"
},
"access-list.rule-source.placeholder": {
"defaultMessage": "192.168.1.100 vagy 192.168.1.0/24 vagy 2001:0db8::/32"
},
"access-list.satisfy-any": {
"defaultMessage": "Bármely teljesítése"
},
"access-list.subtitle": {
"defaultMessage": "{users} {users, plural, one {felhasználó} other {felhasználó}}, {rules} {rules, plural, one {szabály} other {szabály}} - Létrehozva: {date}"
},
"access-lists": {
"defaultMessage": "Hozzáférési listák"
},
"action.add": {
"defaultMessage": "Hozzáadás"
},
"action.add-location": {
"defaultMessage": "Útvonal hozzáadása"
},
"action.allow": {
"defaultMessage": "Engedélyezés"
},
"action.close": {
"defaultMessage": "Bezárás"
},
"action.delete": {
"defaultMessage": "Törlés"
},
"action.deny": {
"defaultMessage": "Tiltás"
},
"action.disable": {
"defaultMessage": "Letiltás"
},
"action.download": {
"defaultMessage": "Letöltés"
},
"action.edit": {
"defaultMessage": "Szerkesztés"
},
"action.enable": {
"defaultMessage": "Engedélyezés"
},
"action.permissions": {
"defaultMessage": "Engedélyek"
},
"action.renew": {
"defaultMessage": "Megújítás"
},
"action.view-details": {
"defaultMessage": "Részletek megtekintése"
},
"auditlogs": {
"defaultMessage": "Audit naplók"
},
"auto": {
"defaultMessage": "Automatikus"
},
"cancel": {
"defaultMessage": "Mégse"
},
"certificate": {
"defaultMessage": "Tanúsítvány"
},
"certificate.custom-certificate": {
"defaultMessage": "Tanúsítvány"
},
"certificate.custom-certificate-key": {
"defaultMessage": "Tanúsítvány kulcs"
},
"certificate.custom-intermediate": {
"defaultMessage": "Köztes tanúsítvány"
},
"certificate.in-use": {
"defaultMessage": "Használatban"
},
"certificate.none.subtitle": {
"defaultMessage": "Nincs tanúsítvány hozzárendelve"
},
"certificate.none.subtitle.for-http": {
"defaultMessage": "Ez a kiszolgáló nem fog HTTPS-t használni"
},
"certificate.none.title": {
"defaultMessage": "Nincs"
},
"certificate.not-in-use": {
"defaultMessage": "Nincs használatban"
},
"certificate.renew": {
"defaultMessage": "Tanúsítvány megújítása"
},
"certificates": {
"defaultMessage": "Tanúsítványok"
},
"certificates.custom": {
"defaultMessage": "Egyéni tanúsítvány"
},
"certificates.custom.warning": {
"defaultMessage": "Jelszóval védett kulcsfájlok nem támogatottak."
},
"certificates.dns.credentials": {
"defaultMessage": "Hitelesítő fájl tartalma"
},
"certificates.dns.credentials-note": {
"defaultMessage": "Ez a plugin egy konfigurációs fájlt igényel, amely API tokent vagy egyéb hitelesítő adatokat tartalmaz a szolgáltatóhoz"
},
"certificates.dns.credentials-warning": {
"defaultMessage": "Ezek az adatok sima szövegként lesznek tárolva az adatbázisban és egy fájlban!"
},
"certificates.dns.propagation-seconds": {
"defaultMessage": "Propagálási másodpercek"
},
"certificates.dns.propagation-seconds-note": {
"defaultMessage": "Hagyja üresen a plugin alapértelmezett értékének használatához. Másodpercek száma a DNS propagálás megvárásához."
},
"certificates.dns.provider": {
"defaultMessage": "DNS szolgáltató"
},
"certificates.dns.provider.placeholder": {
"defaultMessage": "Válasszon szolgáltatót..."
},
"certificates.dns.warning": {
"defaultMessage": "Ez a szakasz némi ismeretet igényel a Certbot-ról és a DNS plugin-jeiről. Kérjük, olvassa el a megfelelő plugin dokumentációját."
},
"certificates.http.reachability-404": {
"defaultMessage": "Található szerver ezen a domain-en, de nem úgy tűnik, hogy Nginx Proxy Manager lenne. Kérjük, győződjön meg róla, hogy a domain arra az IP címre mutat, ahol az NPM példánya fut."
},
"certificates.http.reachability-failed-to-check": {
"defaultMessage": "Az elérhetőség ellenőrzése sikertelen a site24x7.com kommunikációs hiba miatt."
},
"certificates.http.reachability-not-resolved": {
"defaultMessage": "Nincs elérhető szerver ezen a domain-en. Kérjük, győződjön meg róla, hogy a domain létezik és arra az IP címre mutat, ahol az NPM példánya fut, és szükség esetén a 80-as port továbbítva van a routerében."
},
"certificates.http.reachability-ok": {
"defaultMessage": "A szerver elérhető és a tanúsítványok létrehozása lehetséges lesz."
},
"certificates.http.reachability-other": {
"defaultMessage": "Található szerver ezen a domain-en, de váratlan {code} státuszkódot adott vissza. Ez az NPM szerver? Kérjük, győződjön meg róla, hogy a domain arra az IP címre mutat, ahol az NPM példánya fut."
},
"certificates.http.reachability-wrong-data": {
"defaultMessage": "Található szerver ezen a domain-en, de váratlan adatot adott vissza. Ez az NPM szerver? Kérjük, győződjön meg róla, hogy a domain arra az IP címre mutat, ahol az NPM példánya fut."
},
"certificates.http.test-results": {
"defaultMessage": "Teszt eredmények"
},
"certificates.http.warning": {
"defaultMessage": "Ezeknek a domain-eknek már konfigurálva kell lenniük, hogy erre a telepítésre mutassanak."
},
"certificates.key-type": {
"defaultMessage": "Kulcs típus"
},
"certificates.key-type-description": {
"defaultMessage": "Az RSA széles körben kompatibilis, az ECDSA gyorsabb és biztonságosabb, de nem biztos, hogy régebbi rendszerek támogatják"
},
"certificates.key-type-ecdsa": {
"defaultMessage": "ECDSA 256"
},
"certificates.key-type-rsa": {
"defaultMessage": "RSA 2048"
},
"certificates.request.subtitle": {
"defaultMessage": "Let's Encrypt-tel"
},
"certificates.request.title": {
"defaultMessage": "Új tanúsítvány kérelmezése"
},
"column.access": {
"defaultMessage": "Hozzáférés"
},
"column.authorization": {
"defaultMessage": "Jogosultság"
},
"column.authorizations": {
"defaultMessage": "Jogosultságok"
},
"column.custom-locations": {
"defaultMessage": "Egyéni útvonalak"
},
"column.destination": {
"defaultMessage": "Cél"
},
"column.details": {
"defaultMessage": "Részletek"
},
"column.email": {
"defaultMessage": "E-mail"
},
"column.event": {
"defaultMessage": "Esemény"
},
"column.expires": {
"defaultMessage": "Lejár"
},
"column.http-code": {
"defaultMessage": "HTTP kód"
},
"column.incoming-port": {
"defaultMessage": "Bejövő port"
},
"column.name": {
"defaultMessage": "Név"
},
"column.protocol": {
"defaultMessage": "Protokoll"
},
"column.provider": {
"defaultMessage": "Szolgáltató"
},
"column.roles": {
"defaultMessage": "Szerepkörök"
},
"column.rules": {
"defaultMessage": "Szabályok"
},
"column.satisfy": {
"defaultMessage": "Teljesítés"
},
"column.satisfy-all": {
"defaultMessage": "Összes"
},
"column.satisfy-any": {
"defaultMessage": "Bármely"
},
"column.scheme": {
"defaultMessage": "Séma"
},
"column.source": {
"defaultMessage": "Forrás"
},
"column.ssl": {
"defaultMessage": "SSL"
},
"column.status": {
"defaultMessage": "Állapot"
},
"created-on": {
"defaultMessage": "Létrehozva: {date}"
},
"dashboard": {
"defaultMessage": "Vezérlőpult"
},
"dead-host": {
"defaultMessage": "404-es Kiszolgáló"
},
"dead-hosts": {
"defaultMessage": "404-es Kiszolgálók"
},
"dead-hosts.count": {
"defaultMessage": "{count} {count, plural, one {404-es Kiszolgáló} other {404-es Kiszolgálók}}"
},
"disabled": {
"defaultMessage": "Letiltva"
},
"domain-names": {
"defaultMessage": "Domain nevek"
},
"domain-names.max": {
"defaultMessage": "Maximum {count} domain név"
},
"domain-names.placeholder": {
"defaultMessage": "Kezdjen el gépelni domain hozzáadásához..."
},
"domain-names.wildcards-not-permitted": {
"defaultMessage": "Helyettesítő karakterek nem engedélyezettek ennél a típusnál"
},
"domain-names.wildcards-not-supported": {
"defaultMessage": "Helyettesítő karakterek nem támogatottak ennél a CA-nál"
},
"domains.force-ssl": {
"defaultMessage": "SSL kényszerítése"
},
"domains.hsts-enabled": {
"defaultMessage": "HSTS engedélyezve"
},
"domains.hsts-subdomains": {
"defaultMessage": "HSTS aldomain-ek"
},
"domains.http2-support": {
"defaultMessage": "HTTP/2 támogatás"
},
"domains.use-dns": {
"defaultMessage": "DNS Challenge használata"
},
"email-address": {
"defaultMessage": "E-mail cím"
},
"empty-search": {
"defaultMessage": "Nincs találat"
},
"empty-subtitle": {
"defaultMessage": "Miért nem hoz létre egyet?"
},
"enabled": {
"defaultMessage": "Engedélyezve"
},
"error.access.at-least-one": {
"defaultMessage": "Legalább egy jogosultság vagy egy hozzáférési szabály szükséges"
},
"error.access.duplicate-usernames": {
"defaultMessage": "A jogosultsági felhasználóneveknek egyedieknek kell lenniük"
},
"error.invalid-auth": {
"defaultMessage": "Érvénytelen e-mail vagy jelszó"
},
"error.invalid-domain": {
"defaultMessage": "Érvénytelen domain: {domain}"
},
"error.invalid-email": {
"defaultMessage": "Érvénytelen e-mail cím"
},
"error.max-character-length": {
"defaultMessage": "Maximális hossz {max} karakter"
},
"error.max-domains": {
"defaultMessage": "Túl sok domain, a maximum {max}"
},
"error.maximum": {
"defaultMessage": "A maximum {max}"
},
"error.min-character-length": {
"defaultMessage": "Minimális hossz {min} karakter"
},
"error.minimum": {
"defaultMessage": "A minimum {min}"
},
"error.passwords-must-match": {
"defaultMessage": "A jelszavaknak egyezniük kell"
},
"error.required": {
"defaultMessage": "Ez kötelező"
},
"expires.on": {
"defaultMessage": "Lejár: {date}"
},
"footer.github-fork": {
"defaultMessage": "Fork-olj a GitHub-on"
},
"host.flags.block-exploits": {
"defaultMessage": "Gyakori exploitok blokkolása"
},
"host.flags.cache-assets": {
"defaultMessage": "Erőforrások gyorsítótárazása"
},
"host.flags.preserve-path": {
"defaultMessage": "Útvonal megőrzése"
},
"host.flags.protocols": {
"defaultMessage": "Protokollok"
},
"host.flags.websockets-upgrade": {
"defaultMessage": "Websockets támogatás"
},
"host.forward-port": {
"defaultMessage": "Továbbító port"
},
"host.forward-scheme": {
"defaultMessage": "Séma"
},
"hosts": {
"defaultMessage": "Kiszolgálók"
},
"http-only": {
"defaultMessage": "Csak HTTP"
},
"lets-encrypt": {
"defaultMessage": "Let's Encrypt"
},
"lets-encrypt-via-dns": {
"defaultMessage": "Let's Encrypt DNS-en keresztül"
},
"lets-encrypt-via-http": {
"defaultMessage": "Let's Encrypt HTTP-n keresztül"
},
"loading": {
"defaultMessage": "Betöltés…"
},
"login.2fa-code": {
"defaultMessage": "Ellenőrző kód"
},
"login.2fa-code-placeholder": {
"defaultMessage": "Adja meg a kódot"
},
"login.2fa-description": {
"defaultMessage": "Adja meg a kódot a hitelesítő alkalmazásából"
},
"login.2fa-title": {
"defaultMessage": "Kétfaktoros hitelesítés"
},
"login.2fa-verify": {
"defaultMessage": "Ellenőrzés"
},
"login.title": {
"defaultMessage": "Jelentkezzen be a fiókjába"
},
"nginx-config.label": {
"defaultMessage": "Egyéni Nginx konfiguráció"
},
"nginx-config.placeholder": {
"defaultMessage": "# Adja meg az egyéni Nginx konfigurációját itt, saját felelősségére!"
},
"no-permission-error": {
"defaultMessage": "Nincs jogosultsága ennek megtekintéséhez."
},
"notfound.action": {
"defaultMessage": "Vigyen haza"
},
"notfound.content": {
"defaultMessage": "Sajnáljuk, de a keresett oldal nem található"
},
"notfound.title": {
"defaultMessage": "Hoppá… Hibás oldalra talált"
},
"notification.error": {
"defaultMessage": "Hiba"
},
"notification.object-deleted": {
"defaultMessage": "{object} törölve lett"
},
"notification.object-disabled": {
"defaultMessage": "{object} letiltva lett"
},
"notification.object-enabled": {
"defaultMessage": "{object} engedélyezve lett"
},
"notification.object-renewed": {
"defaultMessage": "{object} megújítva lett"
},
"notification.object-saved": {
"defaultMessage": "{object} mentve lett"
},
"notification.success": {
"defaultMessage": "Sikeres"
},
"object.actions-title": {
"defaultMessage": "{object} #{id}"
},
"object.add": {
"defaultMessage": "{object} hozzáadása"
},
"object.delete": {
"defaultMessage": "{object} törlése"
},
"object.delete.content": {
"defaultMessage": "Biztosan törölni szeretné ezt: {object}?"
},
"object.edit": {
"defaultMessage": "{object} szerkesztése"
},
"object.empty": {
"defaultMessage": "Nincsenek {objects}"
},
"object.event.created": {
"defaultMessage": "{object} létrehozva"
},
"object.event.deleted": {
"defaultMessage": "{object} törölve"
},
"object.event.disabled": {
"defaultMessage": "{object} letiltva"
},
"object.event.enabled": {
"defaultMessage": "{object} engedélyezve"
},
"object.event.renewed": {
"defaultMessage": "{object} megújítva"
},
"object.event.updated": {
"defaultMessage": "{object} frissítve"
},
"offline": {
"defaultMessage": "Offline"
},
"online": {
"defaultMessage": "Online"
},
"options": {
"defaultMessage": "Beállítások"
},
"password": {
"defaultMessage": "Jelszó"
},
"password.generate": {
"defaultMessage": "Véletlenszerű jelszó generálása"
},
"password.hide": {
"defaultMessage": "Jelszó elrejtése"
},
"password.show": {
"defaultMessage": "Jelszó megjelenítése"
},
"permissions.hidden": {
"defaultMessage": "Rejtett"
},
"permissions.manage": {
"defaultMessage": "Kezelés"
},
"permissions.view": {
"defaultMessage": "Csak megtekintés"
},
"permissions.visibility.all": {
"defaultMessage": "Összes elem"
},
"permissions.visibility.title": {
"defaultMessage": "Elemek láthatósága"
},
"permissions.visibility.user": {
"defaultMessage": "Csak létrehozott elemek"
},
"proxy-host": {
"defaultMessage": "Proxy Kiszolgáló"
},
"proxy-host.forward-host": {
"defaultMessage": "Továbbító hostnév / IP"
},
"proxy-hosts": {
"defaultMessage": "Proxy Kiszolgálók"
},
"proxy-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Proxy Kiszolgáló} other {Proxy Kiszolgálók}}"
},
"public": {
"defaultMessage": "Nyilvános"
},
"redirection-host": {
"defaultMessage": "Átirányító Kiszolgáló"
},
"redirection-host.forward-domain": {
"defaultMessage": "Továbbító domain"
},
"redirection-host.forward-http-code": {
"defaultMessage": "HTTP kód"
},
"redirection-hosts": {
"defaultMessage": "Átirányító Kiszolgálók"
},
"redirection-hosts.count": {
"defaultMessage": "{count} {count, plural, one {Átirányító Kiszolgáló} other {Átirányító Kiszolgálók}}"
},
"redirection-hosts.http-code.300": {
"defaultMessage": "300 Többszörös választás"
},
"redirection-hosts.http-code.301": {
"defaultMessage": "301 Véglegesen áthelyezve"
},
"redirection-hosts.http-code.302": {
"defaultMessage": "302 Ideiglenesen áthelyezve"
},
"redirection-hosts.http-code.303": {
"defaultMessage": "303 Lásd másik"
},
"redirection-hosts.http-code.307": {
"defaultMessage": "307 Ideiglenes átirányítás"
},
"redirection-hosts.http-code.308": {
"defaultMessage": "308 Végleges átirányítás"
},
"role.admin": {
"defaultMessage": "Adminisztrátor"
},
"role.standard-user": {
"defaultMessage": "Általános felhasználó"
},
"save": {
"defaultMessage": "Mentés"
},
"setting": {
"defaultMessage": "Beállítás"
},
"settings": {
"defaultMessage": "Beállítások"
},
"settings.default-site": {
"defaultMessage": "Alapértelmezett oldal"
},
"settings.default-site.404": {
"defaultMessage": "404-es oldal"
},
"settings.default-site.444": {
"defaultMessage": "Nincs válasz (444)"
},
"settings.default-site.congratulations": {
"defaultMessage": "Gratulálunk oldal"
},
"settings.default-site.description": {
"defaultMessage": "Mit mutasson az Nginx ismeretlen Kiszolgáló esetén"
},
"settings.default-site.html": {
"defaultMessage": "Egyéni HTML"
},
"settings.default-site.html.placeholder": {
"defaultMessage": "<!-- Adja meg az egyéni HTML tartalmát itt -->"
},
"settings.default-site.redirect": {
"defaultMessage": "Átirányítás"
},
"setup.preamble": {
"defaultMessage": "Kezdje az admin fiók létrehozásával."
},
"setup.title": {
"defaultMessage": "Üdvözöljük!"
},
"sign-in": {
"defaultMessage": "Bejelentkezés"
},
"ssl-certificate": {
"defaultMessage": "SSL tanúsítvány"
},
"stream": {
"defaultMessage": "Stream"
},
"stream.forward-host": {
"defaultMessage": "Továbbító kiszolgáló"
},
"stream.forward-host.placeholder": {
"defaultMessage": "example.com vagy 10.0.0.1 vagy 2001:db8:3333:4444:5555:6666:7777:8888"
},
"stream.incoming-port": {
"defaultMessage": "Bejövő port"
},
"streams": {
"defaultMessage": "Streamek"
},
"streams.count": {
"defaultMessage": "{count} {count, plural, one {Stream} other {Stream}}"
},
"streams.tcp": {
"defaultMessage": "TCP"
},
"streams.udp": {
"defaultMessage": "UDP"
},
"test": {
"defaultMessage": "Teszt"
},
"update-available": {
"defaultMessage": "Frissítés elérhető: {latestVersion}"
},
"user": {
"defaultMessage": "Felhasználó"
},
"user.change-password": {
"defaultMessage": "Jelszó megváltoztatása"
},
"user.confirm-password": {
"defaultMessage": "Jelszó megerősítése"
},
"user.current-password": {
"defaultMessage": "Jelenlegi jelszó"
},
"user.edit-profile": {
"defaultMessage": "Profil szerkesztése"
},
"user.full-name": {
"defaultMessage": "Teljes név"
},
"user.login-as": {
"defaultMessage": "Bejelentkezés mint {name}"
},
"user.logout": {
"defaultMessage": "Kijelentkezés"
},
"user.new-password": {
"defaultMessage": "Új jelszó"
},
"user.nickname": {
"defaultMessage": "Becenév"
},
"user.set-password": {
"defaultMessage": "Jelszó beállítása"
},
"user.set-permissions": {
"defaultMessage": "Engedélyek beállítása {name} számára"
},
"user.switch-dark": {
"defaultMessage": "Váltás sötét módra"
},
"user.switch-light": {
"defaultMessage": "Váltás világos módra"
},
"user.two-factor": {
"defaultMessage": "Kétfaktoros hitelesítés"
},
"username": {
"defaultMessage": "Felhasználónév"
},
"users": {
"defaultMessage": "Felhasználók"
}
}

View File

@@ -441,7 +441,7 @@
"defaultMessage": "Modifica {object}" "defaultMessage": "Modifica {object}"
}, },
"object.empty": { "object.empty": {
"defaultMessage": "Non ci sono {objects} presenti" "defaultMessage": "Nessun {objects} presente"
}, },
"object.event.created": { "object.event.created": {
"defaultMessage": "{object} creato" "defaultMessage": "{object} creato"

View File

@@ -1,62 +1,44 @@
{ {
"locale-en-US": { "locale-en-US": {
"defaultMessage": "English" "defaultMessage": "English"
}, },
"locale-es-ES": { "locale-es-ES": {
"defaultMessage": "Español" "defaultMessage": "Español"
}, },
"locale-ie-GA": { "locale-de-DE": {
"defaultMessage": "Gaeilge" "defaultMessage": "Deutsch"
}, },
"locale-de-DE": { "locale-ja-JP": {
"defaultMessage": "German" "defaultMessage": "日本語"
}, },
"locale-pt-PT": { "locale-ru-RU": {
"defaultMessage": "Português (Europeu)" "defaultMessage": "Русский"
}, },
"locale-fr-FR": { "locale-sk-SK": {
"defaultMessage": "Français" "defaultMessage": "Slovenčina"
}, },
"locale-id-ID": { "locale-zh-CN": {
"defaultMessage": "Bahasa Indonesia" "defaultMessage": "中文"
}, },
"locale-ja-JP": { "locale-pl-PL": {
"defaultMessage": "日本語" "defaultMessage": "Polski"
}, },
"locale-ru-RU": { "locale-it-IT": {
"defaultMessage": "Русский" "defaultMessage": "Italiano"
}, },
"locale-sk-SK": { "locale-vi-VN": {
"defaultMessage": "Slovenčina" "defaultMessage": "Tiếng Việt"
}, },
"locale-cs-CZ": { "locale-nl-NL": {
"defaultMessage": "Čeština" "defaultMessage": "Nederlands"
}, },
"locale-zh-CN": { "locale-ko-KR": {
"defaultMessage": "中文" "defaultMessage": "한국어"
}, },
"locale-pl-PL": { "locale-bg-BG": {
"defaultMessage": "Polski" "defaultMessage": "Български"
}, },
"locale-it-IT": { "locale-id-ID": {
"defaultMessage": "Italiano" "defaultMessage": "Bahasa Indonesia"
}, }
"locale-vi-VN": {
"defaultMessage": "Tiếng Việt"
},
"locale-nl-NL": {
"defaultMessage": "Nederlands"
},
"locale-ko-KR": {
"defaultMessage": "한국어"
},
"locale-bg-BG": {
"defaultMessage": "Български"
},
"locale-tr-TR": {
"defaultMessage": "Türkçe"
},
"locale-hu-HU": {
"defaultMessage": "Magyar"
}
} }

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