Merge branch 'dev' into clients-pops

This commit is contained in:
miloschwartz 2025-06-22 17:50:39 -04:00
commit 0e87b6e48b
No known key found for this signature in database
21 changed files with 231 additions and 208 deletions

View file

@ -4,7 +4,6 @@
app:
dashboard_url: "https://{{.DashboardDomain}}"
log_level: "info"
save_logs: false
domains:
domain1:
@ -12,44 +11,21 @@ domains:
cert_resolver: "letsencrypt"
server:
external_port: 3000
internal_port: 3001
next_port: 3002
internal_hostname: "pangolin"
session_cookie_name: "p_session_token"
resource_access_token_param: "p_token"
resource_access_token_headers:
id: "P-Access-Token-Id"
token: "P-Access-Token"
resource_session_request_param: "p_session_request"
secret: {{.Secret}}
secret: "{{.Secret}}"
cors:
origins: ["https://{{.DashboardDomain}}"]
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
allowed_headers: ["X-CSRF-Token", "Content-Type"]
credentials: false
traefik:
cert_resolver: "letsencrypt"
http_entrypoint: "web"
https_entrypoint: "websecure"
gerbil:
start_port: 51820
base_endpoint: "{{.DashboardDomain}}"
use_subdomain: false
block_size: 24
site_block_size: 30
subnet_group: 100.89.137.0/20
orgs:
block_size: 24
subnet_group: 100.89.138.0/20
rate_limits:
global:
window_minutes: 1
max_requests: 500
{{if .EnableEmail}}
email:
smtp_host: "{{.EmailSMTPHost}}"
@ -61,7 +37,7 @@ email:
flags:
require_email_verification: {{.EnableEmail}}
disable_signup_without_invite: {{.DisableSignupWithoutInvite}}
disable_user_create_org: {{.DisableUserCreateOrg}}
disable_signup_without_invite: true
disable_user_create_org: false
allow_raw_resources: true
allow_base_domain_resources: true

View file

@ -39,8 +39,6 @@ type Config struct {
BaseDomain string
DashboardDomain string
LetsEncryptEmail string
DisableSignupWithoutInvite bool
DisableUserCreateOrg bool
EnableEmail bool
EmailSMTPHost string
EmailSMTPPort int
@ -234,14 +232,9 @@ func collectUserInput(reader *bufio.Reader) Config {
config.LetsEncryptEmail = readString(reader, "Enter email for Let's Encrypt certificates", "")
config.InstallGerbil = readBool(reader, "Do you want to use Gerbil to allow tunneled connections", true)
// Security settings
fmt.Println("\n=== Security Settings ===")
config.DisableSignupWithoutInvite = readBool(reader, "Disable signup without invite", true)
config.DisableUserCreateOrg = readBool(reader, "Disable users from creating organizations", false)
// Email configuration
fmt.Println("\n=== Email Configuration ===")
config.EnableEmail = readBool(reader, "Enable email functionality", false)
config.EnableEmail = readBool(reader, "Enable email functionality (SMTP)", false)
if config.EnableEmail {
config.EmailSMTPHost = readString(reader, "Enter SMTP host", "")

View file

@ -37,7 +37,7 @@
"name": "Name",
"online": "Online",
"offline": "Offline",
"site": "Site",
"site": "Seite",
"dataIn": "Daten eingehend",
"dataOut": "Daten ausgehend",
"connectionType": "Verbindungstyp",
@ -114,7 +114,7 @@
"shareTokenDescription": "Ihr Zugriffstoken kann auf zwei Arten übergeben werden: als Abfrageparameter oder in den Anfrage-Headern. Diese müssen vom Client auf jeder Anfrage für authentifizierten Zugriff weitergegeben werden.",
"accessToken": "Zugangs-Token",
"usageExamples": "Nutzungsbeispiele",
"tokenId": "Token ID",
"tokenId": "Token-ID",
"requestHeades": "Anfrage-Header",
"queryParameter": "Abfrageparameter",
"importantNote": "Wichtige Notiz",
@ -177,8 +177,8 @@
"subdomnainDescription": "Die Subdomäne, auf die Ihre Ressource zugegriffen werden soll.",
"resourceRawSettings": "TCP/UDP Einstellungen",
"resourceRawSettingsDescription": "Konfigurieren Sie den Zugriff auf Ihre Ressource über TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocol": "Protokoll",
"protocolSelect": "Wählen Sie ein Protokoll",
"resourcePortNumber": "Portnummer",
"resourcePortNumberDescription": "Die externe Portnummer für Proxy-Anfragen.",
"cancel": "Abbrechen",
@ -300,7 +300,7 @@
"userMessageConfirm": "Um zu bestätigen, geben Sie bitte den Namen des Benutzers unten ein.",
"userQuestionRemove": "Sind Sie sicher, dass Sie {selectedUser} dauerhaft vom Server löschen möchten?",
"licenseKey": "Lizenzschlüssel",
"valid": "Valid",
"valid": "Gültig",
"numberOfSites": "Anzahl der Sites",
"licenseKeySearch": "Lizenzschlüssel suchen...",
"licenseKeyAdd": "Lizenzschlüssel hinzufügen",
@ -700,7 +700,7 @@
"accessRoleRequiredRemove": "Bevor Sie diese Rolle löschen, wählen Sie bitte eine neue Rolle aus, zu der die bestehenden Mitglieder übertragen werden sollen.",
"manage": "Verwalten",
"sitesNotFound": "Keine Sites gefunden.",
"pangolinServerAdmin": "Server Admin - Pangolin",
"pangolinServerAdmin": "Server-Admin - Pangolin",
"licenseTierProfessional": "Professional Lizenz",
"licenseTierEnterprise": "Enterprise Lizenz",
"licenseTierCommercial": "Gewerbliche Lizenz",
@ -805,7 +805,7 @@
"redirectUrl": "Weiterleitungs-URL",
"redirectUrlAbout": "Über die Weiterleitungs-URL",
"redirectUrlAboutDescription": "Dies ist die URL, zu der Benutzer nach der Authentifizierung weitergeleitet werden. Sie müssen diese URL in den Einstellungen Ihres Identitätsanbieters konfigurieren.",
"pangolinAuth": "Auth - Pangolin",
"pangolinAuth": "Authentifizierung - Pangolin",
"verificationCodeLengthRequirements": "Ihr Verifizierungscode muss 8 Zeichen lang sein.",
"errorOccurred": "Ein Fehler ist aufgetreten",
"emailErrorVerify": "E-Mail konnte nicht verifiziert werden:",
@ -1104,7 +1104,7 @@
"containerLabels": "Etiketten",
"containerLabelsCount": "{count} Label{s,plural,one{} other{s}}",
"containerLabelsTitle": "Container-Labels",
"containerLabelEmpty": "<empty>",
"containerLabelEmpty": "<leer>",
"containerPorts": "Häfen",
"containerPortsMore": "+{count} mehr",
"containerActions": "Aktionen",
@ -1127,6 +1127,10 @@
"noContainersFoundMatching": "Keine Container gefunden mit \"{filter}\".",
"light": "hell",
"dark": "dunkel",
"system": "system",
"theme": "Design"
"system": "System",
"theme": "Design",
"initialSetupTitle": "Initial Einrichtung des Servers",
"initialSetupDescription": "Erstellen Sie das initiale Server-Admin-Konto. Es kann nur einen Server-Admin geben. Sie können diese Anmeldedaten später immer ändern.",
"createAdminAccount": "Admin-Konto erstellen",
"setupErrorCreateAdmin": "Beim Erstellen des Server-Admin-Kontos ist ein Fehler aufgetreten."
}

View file

@ -114,7 +114,7 @@
"shareTokenDescription": "Su token de acceso puede ser pasado de dos maneras: como parámetro de consulta o en las cabeceras de solicitud. Estos deben ser pasados del cliente en cada solicitud de acceso autenticado.",
"accessToken": "Token de acceso",
"usageExamples": "Ejemplos de uso",
"tokenId": "Token ID",
"tokenId": "ID de token",
"requestHeades": "Solicitar cabeceras",
"queryParameter": "Parámetro de consulta",
"importantNote": "Nota Importante",
@ -177,8 +177,8 @@
"subdomnainDescription": "El subdominio al que su recurso será accesible.",
"resourceRawSettings": "Configuración TCP/UDP",
"resourceRawSettingsDescription": "Configurar cómo se accederá a su recurso a través de TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocol": "Protocolo",
"protocolSelect": "Seleccionar un protocolo",
"resourcePortNumber": "Número de puerto",
"resourcePortNumberDescription": "El número de puerto externo a las solicitudes de proxy.",
"cancel": "Cancelar",
@ -300,7 +300,7 @@
"userMessageConfirm": "Para confirmar, por favor escriba el nombre del usuario a continuación.",
"userQuestionRemove": "¿Está seguro que desea eliminar permanentemente {selectedUser} del servidor?",
"licenseKey": "Clave de licencia",
"valid": "Valid",
"valid": "Válido",
"numberOfSites": "Número de sitios",
"licenseKeySearch": "Buscar claves de licencia...",
"licenseKeyAdd": "Añadir clave de licencia",
@ -373,7 +373,7 @@
"inviteSent": "Se ha enviado una nueva invitación a {email}.",
"inviteSentEmail": "Enviar notificación por correo electrónico al usuario",
"inviteGenerate": "Se ha generado una nueva invitación para {email}.",
"inviteDuplicateError": "Duplicate Invite",
"inviteDuplicateError": "Invitación duplicada",
"inviteDuplicateErrorDescription": "Ya existe una invitación para este usuario.",
"inviteRateLimitError": "Límite de tasa excedido",
"inviteRateLimitErrorDescription": "Has superado el límite de 3 regeneraciones por hora. Inténtalo de nuevo más tarde.",
@ -463,9 +463,9 @@
"targetErrorFetchDescription": "Se ha producido un error al recuperar los objetivos",
"siteErrorFetch": "No se pudo obtener el recurso",
"siteErrorFetchDescription": "Se ha producido un error al recuperar el recurso",
"targetErrorDuplicate": "Duplicate target",
"targetErrorDuplicate": "Objetivo duplicado",
"targetErrorDuplicateDescription": "Ya existe un objetivo con estos ajustes",
"targetWireGuardErrorInvalidIp": "Invalid target IP",
"targetWireGuardErrorInvalidIp": "IP de destino no válida",
"targetWireGuardErrorInvalidIpDescription": "La IP de destino debe estar dentro de la subred del sitio",
"targetsUpdated": "Objetivos actualizados",
"targetsUpdatedDescription": "Objetivos y ajustes actualizados correctamente",
@ -479,9 +479,9 @@
"proxyUpdatedDescription": "La configuración del proxy se ha actualizado correctamente",
"proxyErrorUpdate": "Error al actualizar la configuración del proxy",
"proxyErrorUpdateDescription": "Se ha producido un error al actualizar la configuración del proxy",
"targetAddr": "IP / Hostname",
"targetAddr": "IP / Nombre del host",
"targetPort": "Puerto",
"targetProtocol": "Protocol",
"targetProtocol": "Protocolo",
"targetTlsSettings": "Configuración de conexión segura",
"targetTlsSettingsDescription": "Configurar ajustes SSL/TLS para su recurso",
"targetTlsSettingsAdvanced": "Ajustes avanzados de TLS",
@ -493,7 +493,7 @@
"targetStickySessions": "Activar Sesiones Pegadas",
"targetStickySessionsDescription": "Mantener conexiones en el mismo objetivo de backend para toda su sesión.",
"methodSelect": "Seleccionar método",
"targetSubmit": "Add Target",
"targetSubmit": "Añadir destino",
"targetNoOne": "No hay objetivos. Agregue un objetivo usando el formulario.",
"targetNoOneDescription": "Si se añade más de un objetivo anterior se activará el balance de carga.",
"targetsSubmit": "Guardar objetivos",
@ -585,8 +585,8 @@
"unknownCommand": "Comando desconocido",
"newtErrorFetchReleases": "No se pudo obtener la información del lanzamiento: {err}",
"newtErrorFetchLatest": "Error obteniendo la última versión: {err}",
"newtEndpoint": "Newt Endpoint",
"newtId": "Newt ID",
"newtEndpoint": "Punto final de Newt",
"newtId": "ID de Newt",
"newtSecretKey": "Clave secreta de Newt",
"architecture": "Arquitectura",
"sites": "Sitios",
@ -867,7 +867,7 @@
"passwordReset": "Restablecer contraseña",
"passwordResetDescription": "Siga los pasos para restablecer su contraseña",
"passwordResetSent": "Enviaremos un código para restablecer la contraseña a esta dirección de correo electrónico.",
"passwordResetCode": "Reset Code",
"passwordResetCode": "Código de restablecimiento",
"passwordResetCodeDescription": "Revisa tu correo electrónico para ver el código de restablecimiento.",
"passwordNew": "Nueva contraseña",
"passwordNewConfirm": "Confirmar nueva contraseña",
@ -895,7 +895,7 @@
"inviteErrorExpired": "La invitación puede haber caducado",
"inviteErrorRevoked": "La invitación podría haber sido revocada",
"inviteErrorTypo": "Puede haber un error en el enlace de invitación",
"pangolinSetup": "Setup - Pangolin",
"pangolinSetup": "Configuración - Pangolin",
"orgNameRequired": "El nombre de la organización es obligatorio",
"orgIdRequired": "El ID de la organización es obligatorio",
"orgErrorCreate": "Se ha producido un error al crear el org",
@ -923,7 +923,7 @@
"tagWarnDuplicate": "Etiqueta {tagText} duplicada no añadida",
"supportKeyInvalid": "Clave inválida",
"supportKeyInvalidDescription": "Tu clave de seguidor no es válida.",
"supportKeyValid": "Valid Key",
"supportKeyValid": "Clave válida",
"supportKeyValidDescription": "Su clave de seguidor ha sido validada. ¡Gracias por su apoyo!",
"supportKeyErrorValidationDescription": "Error al validar la clave de seguidor.",
"supportKey": "¡Apoya el Desarrollo y Adopte un Pangolin!",
@ -945,7 +945,7 @@
"supportKeyHideSevenDays": "Ocultar durante 7 días",
"supportKeyEnter": "Introduzca Clave de Soporter",
"supportKeyEnterDescription": "Conoce a tu propia mascota Pangolin!",
"githubUsername": "GitHub Username",
"githubUsername": "Nombre de usuario de GitHub",
"supportKeyInput": "Clave de apoyo",
"supportKeyBuy": "Comprar Clave de Apoyo",
"logoutError": "Error al cerrar sesión",
@ -979,11 +979,11 @@
"actionSetResourcePincode": "Establecer Pincode del recurso",
"actionSetResourceEmailWhitelist": "Establecer lista blanca de correo de recursos",
"actionGetResourceEmailWhitelist": "Obtener correo electrónico de recursos",
"actionCreateTarget": "Create Target",
"actionCreateTarget": "Crear destino",
"actionDeleteTarget": "Eliminar destino",
"actionGetTarget": "Obtener objetivo",
"actionListTargets": "Lista de objetivos",
"actionUpdateTarget": "Update Target",
"actionUpdateTarget": "Actualizar destino",
"actionCreateRole": "Crear rol",
"actionDeleteRole": "Eliminar rol",
"actionGetRole": "Obtener rol",
@ -1031,7 +1031,7 @@
"otpAuthSubmit": "Enviar código",
"idpContinue": "O continuar con",
"otpAuthBack": "Volver a iniciar sesión",
"navbar": "Navigation Menu",
"navbar": "Menú de navegación",
"navbarDescription": "Menú de navegación principal para la aplicación",
"navbarDocsLink": "Documentación",
"commercialEdition": "Edición Comercial",
@ -1100,11 +1100,11 @@
"containerImage": "Imagen",
"containerState": "Estado",
"containerNetworks": "Redes",
"containerHostnameIp": "Hostname/IP",
"containerHostnameIp": "Nombre del host/IP",
"containerLabels": "Etiquetas",
"containerLabelsCount": "{count} etiqueta{s,plural,one{} other{s}}",
"containerLabelsTitle": "Etiquetas de contenedor",
"containerLabelEmpty": "<empty>",
"containerLabelEmpty": "<vacío>",
"containerPorts": "Puertos",
"containerPortsMore": "+{count} más",
"containerActions": "Acciones",
@ -1128,5 +1128,9 @@
"light": "claro",
"dark": "oscuro",
"system": "sistema",
"theme": "Tema"
"theme": "Tema",
"initialSetupTitle": "Configuración inicial del servidor",
"initialSetupDescription": "Cree la cuenta de administrador del servidor inicial. Solo puede existir un administrador del servidor. Siempre puede cambiar estas credenciales más tarde.",
"createAdminAccount": "Crear cuenta de administrador",
"setupErrorCreateAdmin": "Se produjo un error al crear la cuenta de administrador del servidor."
}

View file

@ -114,7 +114,7 @@
"shareTokenDescription": "Votre jeton d'accès peut être passé de deux façons : en tant que paramètre de requête ou dans les en-têtes de la requête. Elles doivent être transmises par le client à chaque demande d'accès authentifié.",
"accessToken": "Jeton d'accès",
"usageExamples": "Exemples d'utilisation",
"tokenId": "Token ID",
"tokenId": "ID du jeton",
"requestHeades": "En-têtes de la requête",
"queryParameter": "Paramètre de requête",
"importantNote": "Note importante",
@ -177,8 +177,8 @@
"subdomnainDescription": "Le sous-domaine où votre ressource sera accessible.",
"resourceRawSettings": "Paramètres TCP/UDP",
"resourceRawSettingsDescription": "Configurer comment votre ressource sera accédée via TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocol": "Protocole",
"protocolSelect": "Sélectionner un protocole",
"resourcePortNumber": "Numéro de port",
"resourcePortNumberDescription": "Le numéro de port externe pour les requêtes de proxy.",
"cancel": "Abandonner",
@ -300,7 +300,7 @@
"userMessageConfirm": "Pour confirmer, veuillez saisir le nom de l'utilisateur ci-dessous.",
"userQuestionRemove": "Êtes-vous sûr de vouloir supprimer définitivement {selectedUser} du serveur?",
"licenseKey": "Clé de licence",
"valid": "Valid",
"valid": "Valide",
"numberOfSites": "Nombre de sites",
"licenseKeySearch": "Rechercher des clés de licence...",
"licenseKeyAdd": "Ajouter une clé de licence",
@ -1100,11 +1100,11 @@
"containerImage": "Image",
"containerState": "État",
"containerNetworks": "Réseaux",
"containerHostnameIp": "Hostname/IP",
"containerHostnameIp": "Nom d'hôte/IP",
"containerLabels": "Étiquettes",
"containerLabelsCount": "{count} label{s,plural,one{} other{s}}",
"containerLabelsCount": "{count} étiquette{s,plural,one{} other{s}}",
"containerLabelsTitle": "Étiquettes de conteneur",
"containerLabelEmpty": "<empty>",
"containerLabelEmpty": "<vide>",
"containerPorts": "Ports",
"containerPortsMore": "+{count} de plus",
"containerActions": "Actions",
@ -1128,5 +1128,9 @@
"light": "clair",
"dark": "sombre",
"system": "système",
"theme": "Thème"
"theme": "Thème",
"initialSetupTitle": "Configuration initiale du serveur",
"initialSetupDescription": "Créer le compte administrateur du serveur initial. Un seul administrateur serveur peut exister. Vous pouvez toujours changer ces informations d'identification plus tard.",
"createAdminAccount": "Créer un compte administrateur",
"setupErrorCreateAdmin": "Une erreur s'est produite lors de la création du compte administrateur du serveur."
}

View file

@ -73,7 +73,7 @@
"searchSitesProgress": "Cerca siti...",
"siteAdd": "Aggiungi Sito",
"siteInstallNewt": "Installa Newt",
"siteInstallNewtDescription": "Get Newt running on your system",
"siteInstallNewtDescription": "Esegui Newt sul tuo sistema",
"WgConfiguration": "Configurazione WireGuard",
"WgConfigurationDescription": "Usa la seguente configurazione per connetterti alla tua rete",
"operatingSystem": "Sistema Operativo",
@ -114,7 +114,7 @@
"shareTokenDescription": "Il token di accesso può essere passato in due modi: come parametro di interrogazione o nelle intestazioni della richiesta. Questi devono essere passati dal client su ogni richiesta di accesso autenticato.",
"accessToken": "Token Di Accesso",
"usageExamples": "Esempi Di Utilizzo",
"tokenId": "Token ID",
"tokenId": "ID del Token",
"requestHeades": "Richiedi Intestazioni",
"queryParameter": "Parametro Query",
"importantNote": "Nota Importante",
@ -177,8 +177,8 @@
"subdomnainDescription": "Il sottodominio in cui la tua risorsa sarà accessibile.",
"resourceRawSettings": "Impostazioni TCP/UDP",
"resourceRawSettingsDescription": "Configura come accedere alla tua risorsa tramite TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocol": "Protocollo",
"protocolSelect": "Seleziona un protocollo",
"resourcePortNumber": "Numero Porta",
"resourcePortNumberDescription": "Il numero di porta esterna per le richieste di proxy.",
"cancel": "Annulla",
@ -230,7 +230,7 @@
"accessUsersSearch": "Cerca utenti...",
"accessUserCreate": "Crea Utente",
"accessUserRemove": "Rimuovi Utente",
"username": "Username",
"username": "Nome utente",
"identityProvider": "Provider Di Identità",
"role": "Ruolo",
"nameRequired": "Il nome è obbligatorio",
@ -300,7 +300,7 @@
"userMessageConfirm": "Per confermare, digita il nome dell'utente qui sotto.",
"userQuestionRemove": "Sei sicuro di voler eliminare definitivamente {selectedUser} dal server?",
"licenseKey": "Chiave Di Licenza",
"valid": "Valid",
"valid": "Valido",
"numberOfSites": "Numero di siti",
"licenseKeySearch": "Cerca chiavi di licenza...",
"licenseKeyAdd": "Aggiungi Chiave Di Licenza",
@ -316,7 +316,7 @@
"licenseErrorKeyActivate": "Attivazione della chiave di licenza non riuscita",
"licenseErrorKeyActivateDescription": "Si è verificato un errore nell'attivazione della chiave di licenza.",
"licenseAbout": "Informazioni Su Licenze",
"communityEdition": "Community Edition",
"communityEdition": "Edizione Community",
"licenseAboutDescription": "Questo è per gli utenti aziendali e aziendali che utilizzano Pangolin in un ambiente commerciale. Se stai usando Pangolin per uso personale, puoi ignorare questa sezione.",
"licenseKeyActivated": "Chiave di licenza attivata",
"licenseKeyActivatedDescription": "La chiave di licenza è stata attivata correttamente.",
@ -339,7 +339,7 @@
"licenseHost": "Licenza Host",
"licenseHostDescription": "Gestisci la chiave di licenza principale per l'host.",
"licensedNot": "Non Licenziato",
"hostId": "Host ID",
"hostId": "ID Host",
"licenseReckeckAll": "Ricontrolla Tutte Le Tasti",
"licenseSiteUsage": "Utilizzo Siti",
"licenseSiteUsageDecsription": "Visualizza il numero di siti che utilizzano questa licenza.",
@ -1104,7 +1104,7 @@
"containerLabels": "Etichette",
"containerLabelsCount": "{count} etichetta{s,plural,one{} other{s}}",
"containerLabelsTitle": "Etichette Del Contenitore",
"containerLabelEmpty": "<empty>",
"containerLabelEmpty": "<vuoto>",
"containerPorts": "Porte",
"containerPortsMore": "+{count} in più",
"containerActions": "Azioni",
@ -1128,5 +1128,9 @@
"light": "chiaro",
"dark": "scuro",
"system": "sistema",
"theme": "Tema"
"theme": "Tema",
"initialSetupTitle": "Impostazione Iniziale del Server",
"initialSetupDescription": "Crea l'account amministratore del server iniziale. Può esistere solo un amministratore del server. È sempre possibile modificare queste credenziali in seguito.",
"createAdminAccount": "Crea Account Admin",
"setupErrorCreateAdmin": "Si è verificato un errore durante la creazione dell'account amministratore del server."
}

View file

@ -12,7 +12,7 @@
"componentsErrorNoMember": "U bent momenteel geen lid van een organisatie.",
"welcome": "Welkom bij Pangolin",
"componentsCreateOrg": "Maak een Organisatie",
"componentsMember": "You're a member of {count, plural, =0 {no organization} =1 {one organization} other {# organizations}}.",
"componentsMember": "Je bent lid van {count, plural, =0 {geen organisatie} =1 {één organisatie} other {# organisaties}}.",
"componentsInvalidKey": "Ongeldige of verlopen licentiesleutels gedetecteerd. Volg de licentievoorwaarden om alle functies te blijven gebruiken.",
"dismiss": "Uitschakelen",
"componentsLicenseViolation": "Licentie overtreding: Deze server gebruikt {usedSites} sites die de gelicentieerde limiet van {maxSites} sites overschrijden. Volg de licentievoorwaarden om door te gaan met het gebruik van alle functies.",
@ -92,7 +92,7 @@
"siteSetting": "{siteName} instellingen",
"siteNewtTunnel": "Nieuwstunnel (Aanbevolen)",
"siteNewtTunnelDescription": "Gemakkelijkste manier om een ingangspunt in uw netwerk te maken. Geen extra opzet.",
"siteWg": "Basic WireGuard",
"siteWg": "Basis WireGuard",
"siteWgDescription": "Gebruik een WireGuard client om een tunnel te bouwen. Handmatige NAT installatie vereist.",
"siteLocalDescription": "Alleen lokale bronnen. Geen tunneling.",
"siteSeeAll": "Alle werkruimtes bekijken",
@ -116,7 +116,7 @@
"usageExamples": "Voorbeelden van gebruik",
"tokenId": "Token ID",
"requestHeades": "Aanvraag van headers",
"queryParameter": "Query Parameter",
"queryParameter": "Queryparameter",
"importantNote": "Belangrijke opmerking",
"shareImportantDescription": "Om veiligheidsredenen wordt het gebruik van headers aanbevolen over queryparameters indien mogelijk, omdat query parameters kunnen worden aangemeld in serverlogboeken of browsergeschiedenis.",
"token": "Token",
@ -178,7 +178,7 @@
"resourceRawSettings": "TCP/UDP instellingen",
"resourceRawSettingsDescription": "Stel in hoe je bron wordt benaderd via TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocolSelect": "Selecteer een protocol",
"resourcePortNumber": "Nummer van poort",
"resourcePortNumberDescription": "Het externe poortnummer naar proxyverzoeken.",
"cancel": "annuleren",
@ -300,7 +300,7 @@
"userMessageConfirm": "Typ de naam van de gebruiker hieronder om te bevestigen.",
"userQuestionRemove": "Weet je zeker dat je {selectedUser} permanent van de server wilt verwijderen?",
"licenseKey": "Licentie sleutel",
"valid": "Valid",
"valid": "Geldig",
"numberOfSites": "Aantal sites",
"licenseKeySearch": "Licentiesleutels zoeken...",
"licenseKeyAdd": "Licentiesleutel toevoegen",
@ -339,7 +339,7 @@
"licenseHost": "Host Licentie",
"licenseHostDescription": "Beheer de belangrijkste licentiesleutel voor de host.",
"licensedNot": "Niet gelicentieerd",
"hostId": "Host ID",
"hostId": "Host-ID",
"licenseReckeckAll": "Alle sleutels opnieuw selecteren",
"licenseSiteUsage": "Websites gebruik",
"licenseSiteUsageDecsription": "Bekijk het aantal sites dat deze licentie gebruikt.",
@ -373,7 +373,7 @@
"inviteSent": "Een nieuwe uitnodiging is verstuurd naar {email}.",
"inviteSentEmail": "Stuur e-mail notificatie naar de gebruiker",
"inviteGenerate": "Er is een nieuwe uitnodiging aangemaakt voor {email}.",
"inviteDuplicateError": "Duplicate Invite",
"inviteDuplicateError": "Dubbele uitnodiging",
"inviteDuplicateErrorDescription": "Er bestaat al een uitnodiging voor deze gebruiker.",
"inviteRateLimitError": "Tarief limiet overschreden",
"inviteRateLimitErrorDescription": "U hebt de limiet van 3 regeneratie per uur overschreden. Probeer het later opnieuw.",
@ -436,7 +436,7 @@
"accessRoleSelect": "Selecteer rol",
"inviteEmailSentDescription": "Een e-mail is verstuurd naar de gebruiker met de link hieronder. Ze moeten toegang krijgen tot de link om de uitnodiging te accepteren.",
"inviteSentDescription": "De gebruiker is uitgenodigd. Ze moeten toegang krijgen tot de link hieronder om de uitnodiging te accepteren.",
"inviteExpiresIn": "The invite will expire in {days, plural, =1 {# day} other {# days}}.",
"inviteExpiresIn": "De uitnodiging vervalt in {days, plural, =1 {# dag} other {# dagen}}.",
"idpTitle": "Identiteit Provider",
"idpSelect": "Identiteitsprovider voor de externe gebruiker selecteren",
"idpNotConfigured": "Er zijn geen identiteitsproviders geconfigureerd. Configureer een identiteitsprovider voordat u externe gebruikers aanmaakt.",
@ -463,9 +463,9 @@
"targetErrorFetchDescription": "Er is een fout opgetreden bij het ophalen van de objecten",
"siteErrorFetch": "Mislukt om resource op te halen",
"siteErrorFetchDescription": "Er is een fout opgetreden tijdens het ophalen van het document",
"targetErrorDuplicate": "Duplicate target",
"targetErrorDuplicate": "Dubbel doelwit",
"targetErrorDuplicateDescription": "Een doel met deze instellingen bestaat al",
"targetWireGuardErrorInvalidIp": "Invalid target IP",
"targetWireGuardErrorInvalidIp": "Ongeldig doel-IP",
"targetWireGuardErrorInvalidIpDescription": "Doel IP moet binnen de site subnet zijn",
"targetsUpdated": "Doelstellingen bijgewerkt",
"targetsUpdatedDescription": "Doelstellingen en instellingen succesvol bijgewerkt",
@ -479,7 +479,7 @@
"proxyUpdatedDescription": "Uw proxyinstellingen zijn succesvol bijgewerkt",
"proxyErrorUpdate": "Bijwerken van proxy-instellingen mislukt",
"proxyErrorUpdateDescription": "Fout opgetreden tijdens het bijwerken van de proxy-instellingen",
"targetAddr": "IP / Hostname",
"targetAddr": "IP / Hostnaam",
"targetPort": "Poort",
"targetProtocol": "Protocol",
"targetTlsSettings": "HTTPS & TLS instellingen",
@ -493,7 +493,7 @@
"targetStickySessions": "Sticky sessies inschakelen",
"targetStickySessionsDescription": "Behoud verbindingen op hetzelfde backend doel voor hun hele sessie.",
"methodSelect": "Selecteer methode",
"targetSubmit": "Add Target",
"targetSubmit": "Doelwit toevoegen",
"targetNoOne": "Geen doelwitten. Voeg een doel toe via het formulier.",
"targetNoOneDescription": "Het toevoegen van meer dan één doel hierboven zal de load balancering mogelijk maken.",
"targetsSubmit": "Doelstellingen opslaan",
@ -585,8 +585,8 @@
"unknownCommand": "Onbekende opdracht",
"newtErrorFetchReleases": "Kan release-informatie niet ophalen: {err}",
"newtErrorFetchLatest": "Fout bij ophalen van laatste release: {err}",
"newtEndpoint": "Newt Endpoint",
"newtId": "Newt ID",
"newtEndpoint": "Newt Eindoordeel",
"newtId": "Newt-ID",
"newtSecretKey": "Nieuwe geheime sleutel",
"architecture": "Architectuur",
"sites": "Werkruimtes",
@ -639,7 +639,7 @@
"resourcePasswordSetupDescription": "Het wachtwoord voor de bron is succesvol ingesteld",
"resourcePasswordSetupTitle": "Wachtwoord instellen",
"resourcePasswordSetupTitleDescription": "Stel een wachtwoord in om deze bron te beschermen",
"resourcePincode": "PIN Code",
"resourcePincode": "Pincode",
"resourcePincodeSubmit": "PIN-Code bescherming inschakelen",
"resourcePincodeProtection": "PIN Code bescherming {status}",
"resourcePincodeRemove": "Pijncode van resource verwijderd",
@ -700,7 +700,7 @@
"accessRoleRequiredRemove": "Voordat u deze rol verwijdert, selecteer een nieuwe rol om bestaande leden aan te dragen.",
"manage": "Beheren",
"sitesNotFound": "Geen sites gevonden.",
"pangolinServerAdmin": "Server Admin - Pangolin",
"pangolinServerAdmin": "Serverbeheer - Pangolin",
"licenseTierProfessional": "Professionele licentie",
"licenseTierEnterprise": "Enterprise Licentie",
"licenseTierCommercial": "Commerciële licentie",
@ -745,7 +745,7 @@
"idpOidcConfigureDescription": "Configureer de eindpunten van de OAuth2/OIDC provider en referenties",
"idpClientId": "Klant ID",
"idpClientIdDescription": "De OAuth2-client-ID van uw identiteitsprovider",
"idpClientSecret": "Client Secret",
"idpClientSecret": "Clientgeheim",
"idpClientSecretDescription": "Het OAuth2-clientgeheim van je identiteitsprovider",
"idpAuthUrl": "URL autorisatie",
"idpAuthUrlDescription": "De URL voor autorisatie OAuth2",
@ -826,7 +826,7 @@
"inviteAlready": "Het lijkt erop dat je bent uitgenodigd!",
"inviteAlreadyDescription": "Om de uitnodiging te accepteren, moet je inloggen of een account aanmaken.",
"signupQuestion": "Heeft u al een account?",
"login": "Log in",
"login": "Inloggen",
"resourceNotFound": "Bron niet gevonden",
"resourceNotFoundDescription": "De bron die u probeert te benaderen bestaat niet.",
"pincodeRequirementsLength": "Pincode moet precies 6 cijfers zijn",
@ -867,11 +867,11 @@
"passwordReset": "Wachtwoord opnieuw instellen",
"passwordResetDescription": "Volg de stappen om uw wachtwoord opnieuw in te stellen",
"passwordResetSent": "We sturen een wachtwoord reset code naar dit e-mailadres.",
"passwordResetCode": "Reset Code",
"passwordResetCode": "Resetcode",
"passwordResetCodeDescription": "Controleer je e-mail voor de reset code.",
"passwordNew": "Nieuw wachtwoord",
"passwordNewConfirm": "Bevestig nieuw wachtwoord",
"pincodeAuth": "Authenticator Code",
"pincodeAuth": "Authenticatiecode",
"pincodeSubmit2": "Code indienen",
"passwordResetSubmit": "Opnieuw instellen aanvragen",
"passwordBack": "Terug naar wachtwoord",
@ -923,7 +923,7 @@
"tagWarnDuplicate": "Dubbele tag {tagText} niet toegevoegd",
"supportKeyInvalid": "Ongeldige sleutel",
"supportKeyInvalidDescription": "Je supporter sleutel is ongeldig.",
"supportKeyValid": "Valid Key",
"supportKeyValid": "Geldige sleutel",
"supportKeyValidDescription": "Uw supporter sleutel is gevalideerd. Bedankt voor uw steun!",
"supportKeyErrorValidationDescription": "Niet gelukt om de supportersleutel te valideren.",
"supportKey": "Ondersteun ontwikkeling en Adopt een Pangolin!",
@ -945,7 +945,7 @@
"supportKeyHideSevenDays": "Verbergen voor 7 dagen",
"supportKeyEnter": "Voer de supportersleutel in",
"supportKeyEnterDescription": "Ontmoet je eigen huisdier Pangolin!",
"githubUsername": "GitHub Username",
"githubUsername": "GitHub-gebruikersnaam",
"supportKeyInput": "Supporter Sleutel",
"supportKeyBuy": "Koop Supportersleutel",
"logoutError": "Fout bij uitloggen",
@ -979,11 +979,11 @@
"actionSetResourcePincode": "Stel Resource Pincode in",
"actionSetResourceEmailWhitelist": "Stel Resource e-mail whitelist in",
"actionGetResourceEmailWhitelist": "Verkrijg Resource E-mail Whitelist",
"actionCreateTarget": "Create Target",
"actionCreateTarget": "Doelwit aanmaken",
"actionDeleteTarget": "Verwijder doel",
"actionGetTarget": "Verkrijg Doel",
"actionListTargets": "Doelstellingen weergeven",
"actionUpdateTarget": "Update Target",
"actionUpdateTarget": "Doelwit bijwerken",
"actionCreateRole": "Rol aanmaken",
"actionDeleteRole": "Verwijder rol",
"actionGetRole": "Krijg Rol",
@ -1018,7 +1018,7 @@
"actionCreateIdpOrg": "Maak IDP Org Policy",
"actionDeleteIdpOrg": "Verwijder IDP Org Beleid",
"actionListIdpOrgs": "Toon IDP Orgs",
"actionUpdateIdpOrg": "Update IDP Org",
"actionUpdateIdpOrg": "IDP-org bijwerken",
"noneSelected": "Niet geselecteerd",
"orgNotFound2": "Geen organisaties gevonden.",
"searchProgress": "Zoeken...",
@ -1031,7 +1031,7 @@
"otpAuthSubmit": "Code indienen",
"idpContinue": "Of ga verder met",
"otpAuthBack": "Terug naar inloggen",
"navbar": "Navigation Menu",
"navbar": "Navigatiemenu",
"navbarDescription": "Hoofd navigatie menu voor de applicatie",
"navbarDocsLink": "Documentatie",
"commercialEdition": "Commerciële editie",
@ -1042,7 +1042,7 @@
"otpSetup": "Tweestapsverificatie inschakelen",
"otpSetupDescription": "Beveilig je account met een extra beveiligingslaag",
"otpSetupScanQr": "Scan deze QR-code met je authenticator-app of voer de geheime sleutel handmatig in:",
"otpSetupSecretCode": "Authenticator Code",
"otpSetupSecretCode": "Authenticatiecode",
"otpSetupSuccess": "Tweestapsverificatie ingeschakeld",
"otpSetupSuccessStoreBackupCodes": "Uw account is nu veiliger. Vergeet niet uw back-upcodes op te slaan.",
"otpErrorDisable": "Kan 2FA niet uitschakelen",
@ -1100,11 +1100,11 @@
"containerImage": "Afbeelding",
"containerState": "Provincie",
"containerNetworks": "Netwerken",
"containerHostnameIp": "Hostname/IP",
"containerHostnameIp": "Hostnaam/IP",
"containerLabels": "Labels",
"containerLabelsCount": "{count} label{s,plural,one{} other{s}}",
"containerLabelsTitle": "Container labels",
"containerLabelEmpty": "<empty>",
"containerLabelEmpty": "<leeg>",
"containerPorts": "Poorten",
"containerPortsMore": "+{count} meer",
"containerActions": "acties",
@ -1128,5 +1128,9 @@
"light": "licht",
"dark": "donker",
"system": "systeem",
"theme": "Thema"
"theme": "Thema",
"initialSetupTitle": "Initiële serverconfiguratie",
"initialSetupDescription": "Maak het eerste serverbeheeraccount aan. Er kan slechts één serverbeheerder bestaan. U kunt deze inloggegevens later altijd wijzigen.",
"createAdminAccount": "Maak een beheeraccount aan",
"setupErrorCreateAdmin": "Er is een fout opgetreden bij het maken van het serverbeheerdersaccount."
}

View file

@ -114,7 +114,7 @@
"shareTokenDescription": "Twój token dostępu może być przekazywany na dwa sposoby: jako parametr zapytania lub w nagłówkach żądania. Muszą być przekazywane z klienta na każde żądanie uwierzytelnionego dostępu.",
"accessToken": "Token dostępu",
"usageExamples": "Przykłady użycia",
"tokenId": "Token ID",
"tokenId": "Identyfikator tokena",
"requestHeades": "Nagłówki żądania",
"queryParameter": "Parametr zapytania",
"importantNote": "Ważna uwaga",
@ -177,8 +177,8 @@
"subdomnainDescription": "Poddomena, w której twój zasób będzie dostępny.",
"resourceRawSettings": "Ustawienia TCP/UDP",
"resourceRawSettingsDescription": "Skonfiguruj jak twój zasób będzie dostępny przez TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocol": "Protokół",
"protocolSelect": "Wybierz protokół",
"resourcePortNumber": "Numer portu",
"resourcePortNumberDescription": "Numer portu zewnętrznego do żądań proxy.",
"cancel": "Anuluj",
@ -196,7 +196,7 @@
"disabled": "Wyłączone",
"general": "Ogólny",
"generalSettings": "Ustawienia ogólne",
"proxy": "Proxy",
"proxy": "Serwer pośredniczący",
"rules": "Regulamin",
"resourceSettingDescription": "Skonfiguruj ustawienia zasobu",
"resourceSetting": "Ustawienia {resourceName}",
@ -300,7 +300,7 @@
"userMessageConfirm": "Aby potwierdzić, wpisz nazwę użytkownika poniżej.",
"userQuestionRemove": "Czy na pewno chcesz trwale usunąć {selectedUser} z serwera?",
"licenseKey": "Klucz licencyjny",
"valid": "Valid",
"valid": "Prawidłowy",
"numberOfSites": "Liczba witryn",
"licenseKeySearch": "Szukaj kluczy licencyjnych...",
"licenseKeyAdd": "Dodaj klucz licencyjny",
@ -1100,7 +1100,7 @@
"containerImage": "Obraz",
"containerState": "Stan",
"containerNetworks": "Sieci",
"containerHostnameIp": "Hostname/IP",
"containerHostnameIp": "Nazwa hosta/IP",
"containerLabels": "Etykiety",
"containerLabelsCount": "{count} etykieta{s,plural,one{} other{s}}",
"containerLabelsTitle": "Etykiety kontenera",
@ -1127,6 +1127,10 @@
"noContainersFoundMatching": "Nie znaleziono kontenerów pasujących do \"{filter}\".",
"light": "jasny",
"dark": "ciemny",
"system": "system",
"theme": "Motyw"
"system": "System",
"theme": "Motyw",
"initialSetupTitle": "Wstępna konfiguracja serwera",
"initialSetupDescription": "Utwórz początkowe konto administratora serwera. Może istnieć tylko jeden administrator serwera. Zawsze można zmienić te dane uwierzytelniające.",
"createAdminAccount": "Utwórz konto administratora",
"setupErrorCreateAdmin": "Wystąpił błąd podczas tworzenia konta administratora serwera."
}

View file

@ -114,7 +114,7 @@
"shareTokenDescription": "Seu token de acesso pode ser passado de duas maneiras: como um parâmetro de consulta ou nos cabeçalhos da solicitação. Estes devem ser passados do cliente em todas as solicitações para acesso autenticado.",
"accessToken": "Token de acesso",
"usageExamples": "Exemplos de uso",
"tokenId": "Token ID",
"tokenId": "ID do Token",
"requestHeades": "Cabeçalhos de solicitação",
"queryParameter": "Parâmetro de consulta",
"importantNote": "Nota importante",
@ -177,8 +177,8 @@
"subdomnainDescription": "O subdomínio onde seu recurso estará acessível.",
"resourceRawSettings": "Configurações TCP/UDP",
"resourceRawSettingsDescription": "Configure como seu recurso será acessado sobre TCP/UDP",
"protocol": "Protocol",
"protocolSelect": "Select a protocol",
"protocol": "Protocolo",
"protocolSelect": "Selecione um protocolo",
"resourcePortNumber": "Número da Porta",
"resourcePortNumberDescription": "O número da porta externa para requisições de proxy.",
"cancel": "cancelar",
@ -300,7 +300,7 @@
"userMessageConfirm": "Para confirmar, por favor digite o nome do usuário abaixo.",
"userQuestionRemove": "Tem certeza que deseja excluir o {selectedUser} permanentemente do servidor?",
"licenseKey": "Chave de Licença",
"valid": "Valid",
"valid": "Válido",
"numberOfSites": "Número de sites",
"licenseKeySearch": "Pesquisar chaves da licença...",
"licenseKeyAdd": "Adicionar chave de licença",
@ -1102,9 +1102,9 @@
"containerNetworks": "Redes",
"containerHostnameIp": "Hostname/IP",
"containerLabels": "Marcadores",
"containerLabelsCount": "{count} label{s,plural,one{} other{s}}",
"containerLabelsCount": "{count} rótulo{s,plural,one{} other{s}}",
"containerLabelsTitle": "Etiquetas do Contêiner",
"containerLabelEmpty": "<empty>",
"containerLabelEmpty": "<vazio>",
"containerPorts": "Portas",
"containerPortsMore": "+ Mais{count}",
"containerActions": "Ações.",
@ -1114,7 +1114,7 @@
"showStoppedContainers": "Mostrar contêineres parados",
"noContainersFound": "Nenhum contêiner encontrado. Certifique-se de que os contêineres Docker estão em execução.",
"searchContainersPlaceholder": "Pesquisar entre os contêineres {count}...",
"searchResultsCount": "{count} result{s,plural,one{} other{s}}",
"searchResultsCount": "{count} resultado{s,plural,one{} other{s}}",
"filters": "Filtros",
"filterOptions": "Opções de Filtro",
"filterPorts": "Portas",
@ -1128,5 +1128,9 @@
"light": "claro",
"dark": "escuro",
"system": "sistema",
"theme": "Tema"
"theme": "Tema",
"initialSetupTitle": "Configuração Inicial do Servidor",
"initialSetupDescription": "Crie a conta de administrador inicial do servidor. Apenas um administrador do servidor pode existir. Você sempre pode alterar essas credenciais posteriormente.",
"createAdminAccount": "Criar Conta de Administrador",
"setupErrorCreateAdmin": "Ocorreu um erro ao criar a conta de administrador do servidor."
}

View file

@ -1128,5 +1128,9 @@
"light": "açık",
"dark": "koyu",
"system": "sistem",
"theme": "Tema"
"theme": "Tema",
"initialSetupTitle": "İlk Sunucu Kurulumu",
"initialSetupDescription": "İlk sunucu yönetici hesabını oluşturun. Yalnızca bir sunucu yöneticisi olabilir. Bu kimlik bilgilerini daha sonra her zaman değiştirebilirsiniz.",
"createAdminAccount": "Yönetici Hesabı Oluştur",
"setupErrorCreateAdmin": "Sunucu yönetici hesabı oluşturulurken bir hata oluştu."
}

View file

@ -12,7 +12,7 @@
"componentsErrorNoMember": "您目前不是任何组织的成员。",
"welcome": "欢迎使用 Pangolin",
"componentsCreateOrg": "创建组织",
"componentsMember": "You're a member of {count, plural, =0 {no organization} =1 {one organization} other {# organizations}}.",
"componentsMember": "您属于 {count, plural, =0 {无组织} =1 {一个组织} other {# 个组织}}。",
"componentsInvalidKey": "检测到无效或过期的许可证密钥。按照许可证条款操作以继续使用所有功能。",
"dismiss": "忽略",
"componentsLicenseViolation": "许可证超限:该服务器使用了 {usedSites} 个站点,已超过授权的 {maxSites} 个。请遵守许可证条款以继续使用全部功能。",
@ -66,8 +66,8 @@
"siteLoadWGConfig": "正在载入 WireGuard 配置...",
"siteDocker": "扩展 Docker 部署详细信息",
"toggle": "切换",
"dockerCompose": "Docker Compose",
"dockerRun": "Docker Run",
"dockerCompose": "Docker 配置",
"dockerRun": "停靠栏",
"siteLearnLocal": "本地站点不需要隧道连接,点击了解更多",
"siteConfirmCopy": "我已经复制了配置信息",
"searchSitesProgress": "搜索站点...",
@ -331,7 +331,7 @@
"fossorialLicense": "查看Fossorial Commercial License和订阅条款",
"licenseMessageRemove": "这将删除许可证密钥和它授予的所有相关权限。",
"licenseMessageConfirm": "要确认,请在下面输入许可证密钥。",
"licenseQuestionRemove": "Are you sure you want to delete the license key {selectedKey} ?",
"licenseQuestionRemove": "您确定要删除 {selectedKey} 的邀请吗?",
"licenseKeyDelete": "删除许可证密钥",
"licenseKeyDeleteConfirm": "确认删除许可证密钥",
"licenseTitle": "管理许可证状态",
@ -465,7 +465,7 @@
"siteErrorFetchDescription": "获取资源时出错",
"targetErrorDuplicate": "重复的目标",
"targetErrorDuplicateDescription": "具有这些设置的目标已存在",
"targetWireGuardErrorInvalidIp": "Invalid target IP",
"targetWireGuardErrorInvalidIp": "无效的目标IP",
"targetWireGuardErrorInvalidIpDescription": "目标IP必须在站点子网内",
"targetsUpdated": "目标已更新",
"targetsUpdatedDescription": "目标和设置更新成功",
@ -691,7 +691,7 @@
"accessRoleErrorRemove": "删除角色失败",
"accessRoleErrorRemoveDescription": "删除角色时出错。",
"accessRoleName": "角色名称",
"accessRoleQuestionRemove": "You're about to delete the {name} role. You cannot undo this action.",
"accessRoleQuestionRemove": "您即将删除 {name} 角色。 此操作无法撤销。",
"accessRoleRemove": "删除角色",
"accessRoleRemoveDescription": "从组织中删除角色",
"accessRoleRemoveSubmit": "删除角色",
@ -822,7 +822,7 @@
"emailVerifyResend": "没有收到代码?点击此处重新发送",
"passwordNotMatch": "密码不匹配",
"signupError": "注册时出错",
"pangolinLogoAlt": "Pangolin Logo",
"pangolinLogoAlt": "Pangolin 标志",
"inviteAlready": "看起来您已被邀请!",
"inviteAlreadyDescription": "要接受邀请,您必须登录或创建一个帐户。",
"signupQuestion": "已经有一个帐户?",
@ -881,7 +881,7 @@
"idpOidcTokenValidating": "正在验证 OIDC 令牌",
"idpOidcTokenResponse": "验证 OIDC 令牌响应",
"idpErrorOidcTokenValidating": "验证 OIDC 令牌出错",
"idpConnectingTo": "Connecting to {name}",
"idpConnectingTo": "连接到{name}",
"idpConnectingToDescription": "正在验证您的身份",
"idpConnectingToProcess": "正在连接...",
"idpConnectingToFinished": "已连接",
@ -895,7 +895,7 @@
"inviteErrorExpired": "邀请可能已过期",
"inviteErrorRevoked": "邀请可能已被吊销了",
"inviteErrorTypo": "邀请链接中可能有一个类型",
"pangolinSetup": "Setup - Pangolin",
"pangolinSetup": "认证 - Pangolin",
"orgNameRequired": "组织名称是必需的",
"orgIdRequired": "组织ID是必需的",
"orgErrorCreate": "创建组织时出错",
@ -1094,7 +1094,7 @@
"enableDockerSocketDescription": "启用 Docker Socket 发现以填充容器信息。必须向 Newt 提供 Socket 路径。",
"enableDockerSocketLink": "了解更多",
"viewDockerContainers": "查看停靠容器",
"containersIn": "Containers in {siteName}",
"containersIn": "{siteName} 中的容器",
"selectContainerDescription": "选择任何容器作为目标的主机名。点击端口使用端口。",
"containerName": "名称",
"containerImage": "图片",
@ -1128,5 +1128,9 @@
"light": "浅色",
"dark": "深色",
"system": "系统",
"theme": "主题"
"theme": "主题",
"initialSetupTitle": "初始服务器设置",
"initialSetupDescription": "创建初始服务器管理员帐户。 只能存在一个服务器管理员。 您可以随时更改这些凭据。",
"createAdminAccount": "创建管理员帐户",
"setupErrorCreateAdmin": "创建服务器管理员帐户时出错。"
}

View file

@ -5,6 +5,12 @@ import { withReplicas } from "drizzle-orm/pg-core";
function createDb() {
const config = readConfigFile();
if (!config.postgres) {
throw new Error(
"Postgres configuration is missing in the configuration file."
);
}
const connectionString = config.postgres?.connection_string;
const replicaConnections = config.postgres?.replicas || [];

View file

@ -5,7 +5,6 @@ import path from "path";
import fs from "fs/promises";
import { APP_PATH } from "@server/lib/consts";
import { existsSync, mkdirSync } from "fs";
import { readConfigFile } from "@server/lib/readConfigFile";
export const location = path.join(APP_PATH, "db", "db.sqlite");
export const exists = await checkFileExists(location);
@ -13,8 +12,6 @@ export const exists = await checkFileExists(location);
bootstrapVolume();
function createDb() {
const config = readConfigFile();
const sqlite = new Database(location);
return DrizzleSqlite(sqlite, { schema });
}

View file

@ -5,6 +5,7 @@ import { SupporterKey, supporterKey } from "@server/db";
import { eq } from "drizzle-orm";
import { license } from "@server/license/license";
import { configSchema, readConfigFile } from "./readConfigFile";
import { fromError } from "zod-validation-error";
export class Config {
private rawConfig!: z.infer<typeof configSchema>;
@ -20,7 +21,35 @@ export class Config {
}
public load() {
const parsedConfig = readConfigFile();
const environment = readConfigFile();
const {
data: parsedConfig,
success,
error
} = configSchema.safeParse(environment);
if (!success) {
const errors = fromError(error);
throw new Error(`Invalid configuration file: ${errors}`);
}
if (process.env.APP_BASE_DOMAIN) {
console.log(
"WARNING: You're using deprecated environment variables. Transition to the configuration file. https://docs.fossorial.io/"
);
}
if (
// @ts-ignore
parsedConfig.users ||
process.env.USERS_SERVERADMIN_EMAIL ||
process.env.USERS_SERVERADMIN_PASSWORD
) {
console.log(
"WARNING: Your admin credentials are still in the config file or environment variables. This method of setting admin credentials is no longer supported. It is recommended to remove them."
);
}
process.env.APP_VERSION = APP_VERSION;

View file

@ -2,7 +2,7 @@ import path from "path";
import { fileURLToPath } from "url";
// This is a placeholder value replaced by the build process
export const APP_VERSION = "1.5.1";
export const APP_VERSION = "1.6.0";
export const __FILENAME = fileURLToPath(import.meta.url);
export const __DIRNAME = path.dirname(__FILENAME);

View file

@ -295,24 +295,11 @@ export function readConfigFile() {
environment = loadConfig(configFilePath2);
}
if (process.env.APP_BASE_DOMAIN) {
console.log(
"You're using deprecated environment variables. Transition to the configuration file. https://docs.fossorial.io/"
);
}
if (!environment) {
throw new Error(
"No configuration file found. Please create one. https://docs.fossorial.io/"
);
}
const parsedConfig = configSchema.safeParse(environment);
if (!parsedConfig.success) {
const errors = fromError(parsedConfig.error);
throw new Error(`Invalid configuration file: ${errors}`);
}
return parsedConfig.data;
return environment;
}

View file

@ -1,4 +1,4 @@
import { rateLimit } from "express-rate-limit";
import { MemoryStore, rateLimit, Store } from "express-rate-limit";
import createHttpError from "http-errors";
import { NextFunction, Request, Response } from "express";
import logger from "@server/logger";
@ -6,7 +6,15 @@ import HttpCode from "@server/types/HttpCode";
import config from "@server/lib/config";
import { RedisStore } from "rate-limit-redis";
import redisManager from "@server/db/redis";
import { Command as RedisCommand } from "ioredis";
export let rateLimitStore: Store = new MemoryStore();
if (config.getRawConfig().flags?.enable_redis) {
const client = redisManager.client!;
rateLimitStore = new RedisStore({
sendCommand: async (command: string, ...args: string[]) =>
(await client.call(command, args)) as any
});
}
export function rateLimitMiddleware({
windowMin,
@ -19,11 +27,8 @@ export function rateLimitMiddleware({
type: "IP_ONLY" | "IP_AND_PATH";
skipCondition?: (req: Request, res: Response) => boolean;
}) {
const enableRedis = config.getRawConfig().flags?.enable_redis;
let opts;
if (type === "IP_AND_PATH") {
opts = {
return rateLimit({
windowMs: windowMin * 60 * 1000,
max,
skip: skipCondition,
@ -38,10 +43,11 @@ export function rateLimitMiddleware({
return next(
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
);
}
} as any;
},
store: rateLimitStore
});
} else {
opts = {
return rateLimit({
windowMs: windowMin * 60 * 1000,
max,
skip: skipCondition,
@ -52,18 +58,8 @@ export function rateLimitMiddleware({
createHttpError(HttpCode.TOO_MANY_REQUESTS, message)
);
}
};
}
if (enableRedis) {
const client = redisManager.client!;
opts.store = new RedisStore({
sendCommand: async (command: string, ...args: string[]) =>
(await client.call(command, args)) as any
});
}
return rateLimit(opts);
}
export default rateLimitMiddleware;

View file

@ -32,6 +32,7 @@ import {
verifyIsLoggedInUser,
verifyClientAccess,
verifyApiKeyAccess,
rateLimitStore,
} from "@server/middlewares";
import { verifyUserHasAction } from "../middlewares/verifyUserHasAction";
import { ActionsEnum } from "@server/auth/actions";
@ -782,7 +783,8 @@ authRouter.post(
handler: (req, res, next) => {
const message = `You can only request an email verification code ${3} times every ${15} minutes. Please try again later.`;
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
}
},
store: rateLimitStore
}),
auth.requestEmailVerificationCode
);
@ -802,7 +804,8 @@ authRouter.post(
handler: (req, res, next) => {
const message = `You can only request a password reset ${3} times every ${15} minutes. Please try again later.`;
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
}
},
store: rateLimitStore
}),
auth.requestPasswordReset
);
@ -821,7 +824,8 @@ authRouter.post(
handler: (req, res, next) => {
const message = `You can only request an email OTP ${10} times every ${15} minutes. Please try again later.`;
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
}
},
store: rateLimitStore
}),
resource.authWithWhitelist
);

View file

@ -33,7 +33,6 @@ export default async function Page(props: {
>(`/auth/initial-setup-complete`, await authCookieHeader());
const complete = setupRes.data.data.complete;
if (!complete) {
console.log("compelte", complete);
redirect("/auth/initial-setup");
}

View file

@ -308,13 +308,13 @@ export default function StepperForm() {
)}
/>
{orgIdTaken && (
{orgIdTaken && !orgCreated ? (
<Alert variant="destructive">
<AlertDescription>
{t('setupErrorIdentifier')}
</AlertDescription>
</Alert>
)}
) : null}
{error && (
<Alert variant="destructive">