Merge branch 'dev' of github.com:fosrl/pangolin into dev

This commit is contained in:
Owen
2025-08-04 20:02:08 -07:00
51 changed files with 1691 additions and 237 deletions

View File

@@ -38,3 +38,25 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
- package-ecosystem: "gomod"
directory: "/install"
schedule:
interval: "daily"
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"

View File

@@ -30,7 +30,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: 1.23.0 go-version: 1.24
- name: Update version in package.json - name: Update version in package.json
run: | run: |

View File

@@ -4,7 +4,7 @@ Contributions are welcome!
Please see the contribution and local development guide on the docs page before getting started: Please see the contribution and local development guide on the docs page before getting started:
https://docs.fossorial.io/development https://docs.digpangolin.com/development/contributing
### Licensing Considerations ### Licensing Considerations
@@ -17,4 +17,4 @@ By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content. represent that I have the right to grant this license for all contributed content.
``` ```

View File

@@ -20,7 +20,7 @@ _Pangolin tunnels your services to the internet so you can access anything from
Website Website
</a> </a>
<span> | </span> <span> | </span>
<a href="https://docs.fossorial.io/Getting%20Started/quick-install"> <a href="https://docs.digpangolin.com/self-host/quick-install">
Install Guide Install Guide
</a> </a>
<span> | </span> <span> | </span>
@@ -104,7 +104,7 @@ Pangolin is a self-hosted tunneled reverse proxy server with identity and access
### Fully Self Hosted ### Fully Self Hosted
Host the full application on your own server or on the cloud with a VPS. Take a look at the [documentation](https://docs.fossorial.io/Getting%20Started/quick-install) to get started. Host the full application on your own server or on the cloud with a VPS. Take a look at the [documentation](https://docs.digpangolin.com/self-host/quick-install) to get started.
> Many of our users have had a great experience with [RackNerd](https://my.racknerd.com/aff.php?aff=13788). Depending on promotions, you can get a [**VPS with 1 vCPU, 1GB RAM, and ~20GB SSD for just around $12/year**](https://my.racknerd.com/aff.php?aff=13788&pid=912). That's a great deal! > Many of our users have had a great experience with [RackNerd](https://my.racknerd.com/aff.php?aff=13788). Depending on promotions, you can get a [**VPS with 1 vCPU, 1GB RAM, and ~20GB SSD for just around $12/year**](https://my.racknerd.com/aff.php?aff=13788&pid=912). That's a great deal!

View File

@@ -1,5 +1,5 @@
# To see all available options, please visit the docs: # To see all available options, please visit the docs:
# https://docs.fossorial.io/Pangolin/Configuration/config # https://docs.digpangolin.com/self-host/advanced/config-file
app: app:
dashboard_url: "http://localhost:3002" dashboard_url: "http://localhost:3002"

View File

@@ -36,7 +36,7 @@ services:
- 80:80 # Port for traefik because of the network_mode - 80:80 # Port for traefik because of the network_mode
traefik: traefik:
image: traefik:v3.4.0 image: traefik:v3.5
container_name: traefik container_name: traefik
restart: unless-stopped restart: unless-stopped
network_mode: service:gerbil # Ports appear on the gerbil service network_mode: service:gerbil # Ports appear on the gerbil service

View File

@@ -1,5 +1,5 @@
# To see all available options, please visit the docs: # To see all available options, please visit the docs:
# https://docs.fossorial.io/Pangolin/Configuration/config # https://docs.digpangolin.com/self-host/dns-and-networking
app: app:
dashboard_url: "https://{{.DashboardDomain}}" dashboard_url: "https://{{.DashboardDomain}}"

View File

@@ -16,7 +16,7 @@ experimental:
version: "{{.BadgerVersion}}" version: "{{.BadgerVersion}}"
crowdsec: # CrowdSec plugin configuration added crowdsec: # CrowdSec plugin configuration added
moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
version: "v1.4.2" version: "v1.4.4"
log: log:
level: "INFO" level: "INFO"

View File

@@ -36,7 +36,7 @@ services:
- 80:80 # Port for traefik because of the network_mode - 80:80 # Port for traefik because of the network_mode
{{end}} {{end}}
traefik: traefik:
image: docker.io/traefik:v3.4.1 image: docker.io/traefik:v3.5
container_name: traefik container_name: traefik
restart: unless-stopped restart: unless-stopped
{{if .InstallGerbil}} {{if .InstallGerbil}}

View File

@@ -1,10 +1,10 @@
module installer module installer
go 1.23.0 go 1.24
require ( require (
golang.org/x/term v0.28.0 golang.org/x/term v0.33.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require golang.org/x/sys v0.29.0 // indirect require golang.org/x/sys v0.34.0 // indirect

View File

@@ -1,7 +1,7 @@
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -70,7 +70,7 @@ func main() {
fmt.Println("- Open TCP ports 80 and 443 and UDP ports 51820 and 21820 on your VPS and firewall.") fmt.Println("- Open TCP ports 80 and 443 and UDP ports 51820 and 21820 on your VPS and firewall.")
fmt.Println("- Point your domain to the VPS IP with A records.") fmt.Println("- Point your domain to the VPS IP with A records.")
fmt.Println("") fmt.Println("")
fmt.Println("http://docs.fossorial.io/Getting%20Started/dns-networking") fmt.Println("https://docs.digpangolin.com/self-host/dns-and-networking")
fmt.Println("") fmt.Println("")
fmt.Println("Lets get started!") fmt.Println("Lets get started!")
fmt.Println("") fmt.Println("")

1327
messages/bg-BG.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Delete IDP Org Policy", "actionDeleteIdpOrg": "Delete IDP Org Policy",
"actionListIdpOrgs": "List IDP Orgs", "actionListIdpOrgs": "List IDP Orgs",
"actionUpdateIdpOrg": "Update IDP Org", "actionUpdateIdpOrg": "Update IDP Org",
"actionCreateClient": "Create Client",
"actionDeleteClient": "Delete Client",
"actionUpdateClient": "Update Client",
"actionListClients": "List Clients",
"actionGetClient": "Get Client",
"noneSelected": "None selected", "noneSelected": "None selected",
"orgNotFound2": "No organizations found.", "orgNotFound2": "No organizations found.",
"searchProgress": "Search...", "searchProgress": "Search...",

View File

@@ -1,5 +1,5 @@
{ {
"setupCreate": "Erstelle eine Organisation, Site und Ressourcen", "setupCreate": "Erstelle eine Organisation, einen Standort und Ressourcen",
"setupNewOrg": "Neue Organisation", "setupNewOrg": "Neue Organisation",
"setupCreateOrg": "Organisation erstellen", "setupCreateOrg": "Organisation erstellen",
"setupCreateResources": "Ressource erstellen", "setupCreateResources": "Ressource erstellen",
@@ -16,7 +16,7 @@
"componentsMember": "Du bist Mitglied von {count, plural, =0 {keiner Organisation} one {einer Organisation} other {# Organisationen}}.", "componentsMember": "Du bist Mitglied von {count, plural, =0 {keiner Organisation} one {einer Organisation} other {# Organisationen}}.",
"componentsInvalidKey": "Ungültige oder abgelaufene Lizenzschlüssel erkannt. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.", "componentsInvalidKey": "Ungültige oder abgelaufene Lizenzschlüssel erkannt. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
"dismiss": "Verwerfen", "dismiss": "Verwerfen",
"componentsLicenseViolation": "Lizenzverstoß: Dieser Server benutzt {usedSites} Sites, die das Lizenzlimit der {maxSites} Sites überschreiten. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.", "componentsLicenseViolation": "Lizenzverstoß: Dieser Server benutzt {usedSites} Standorte, was das Lizenzlimit von {maxSites} Standorten überschreitet. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
"componentsSupporterMessage": "Vielen Dank für die Unterstützung von Pangolin als {tier}!", "componentsSupporterMessage": "Vielen Dank für die Unterstützung von Pangolin als {tier}!",
"inviteErrorNotValid": "Es tut uns leid, aber es sieht so aus, als wäre die Einladung, auf die du zugreifen möchtest, entweder nicht angenommen worden oder nicht mehr gültig.", "inviteErrorNotValid": "Es tut uns leid, aber es sieht so aus, als wäre die Einladung, auf die du zugreifen möchtest, entweder nicht angenommen worden oder nicht mehr gültig.",
"inviteErrorUser": "Es tut uns leid, aber es scheint, als sei die Einladung, auf die du zugreifen möchtest, nicht für diesen Benutzer bestimmt.", "inviteErrorUser": "Es tut uns leid, aber es scheint, als sei die Einladung, auf die du zugreifen möchtest, nicht für diesen Benutzer bestimmt.",
@@ -38,25 +38,25 @@
"name": "Name", "name": "Name",
"online": "Online", "online": "Online",
"offline": "Offline", "offline": "Offline",
"site": "Seite", "site": "Standort",
"dataIn": "Daten eingehend", "dataIn": "Daten eingehend",
"dataOut": "Daten ausgehend", "dataOut": "Daten ausgehend",
"connectionType": "Verbindungstyp", "connectionType": "Verbindungstyp",
"tunnelType": "Tunneltyp", "tunnelType": "Tunneltyp",
"local": "Lokal", "local": "Lokal",
"edit": "Bearbeiten", "edit": "Bearbeiten",
"siteConfirmDelete": "Site löschen bestätigen", "siteConfirmDelete": "Standort löschen bestätigen",
"siteDelete": "Site löschen", "siteDelete": "Standort löschen",
"siteMessageRemove": "Sobald diese Seite entfernt ist, wird sie nicht mehr zugänglich sein. Alle Ressourcen und Ziele, die mit der Site verbunden sind, werden ebenfalls entfernt.", "siteMessageRemove": "Sobald dieser Standort entfernt ist, wird er nicht mehr zugänglich sein. Alle Ressourcen und Ziele, die mit diesem Standort verbunden sind, werden ebenfalls entfernt.",
"siteMessageConfirm": "Um zu bestätigen, gib den Namen der Site ein.", "siteMessageConfirm": "Um zu bestätigen, gib den Namen des Standortes unten ein.",
"siteQuestionRemove": "Bist du sicher, dass Sie die Site {selectedSite} aus der Organisation entfernt werden soll?", "siteQuestionRemove": "Bist du sicher, dass der Standort {selectedSite} aus der Organisation entfernt werden soll?",
"siteManageSites": "Sites verwalten", "siteManageSites": "Standorte verwalten",
"siteDescription": "Verbindung zum Netzwerk durch sichere Tunnel erlauben", "siteDescription": "Verbindung zum Netzwerk durch sichere Tunnel erlauben",
"siteCreate": "Site erstellen", "siteCreate": "Standort erstellen",
"siteCreateDescription2": "Folge den nachfolgenden Schritten, um eine neue Site zu erstellen und zu verbinden", "siteCreateDescription2": "Folge den nachfolgenden Schritten, um einen neuen Standort zu erstellen und zu verbinden",
"siteCreateDescription": "Erstelle eine neue Site, um Ressourcen zu verbinden", "siteCreateDescription": "Erstelle einen neuen Standort, um Ressourcen zu verbinden",
"close": "Schließen", "close": "Schließen",
"siteErrorCreate": "Fehler beim Erstellen der Site", "siteErrorCreate": "Fehler beim Erstellen des Standortes",
"siteErrorCreateKeyPair": "Schlüsselpaar oder Standardwerte nicht gefunden", "siteErrorCreateKeyPair": "Schlüsselpaar oder Standardwerte nicht gefunden",
"siteErrorCreateDefaults": "Standardwerte der Site nicht gefunden", "siteErrorCreateDefaults": "Standardwerte der Site nicht gefunden",
"method": "Methode", "method": "Methode",
@@ -70,8 +70,8 @@
"dockerRun": "Docker Run", "dockerRun": "Docker Run",
"siteLearnLocal": "Mehr Infos zu lokalen Sites", "siteLearnLocal": "Mehr Infos zu lokalen Sites",
"siteConfirmCopy": "Ich habe die Konfiguration kopiert", "siteConfirmCopy": "Ich habe die Konfiguration kopiert",
"searchSitesProgress": "Sites durchsuchen...", "searchSitesProgress": "Standorte durchsuchen...",
"siteAdd": "Site hinzufügen", "siteAdd": "Standort hinzufügen",
"siteInstallNewt": "Newt installieren", "siteInstallNewt": "Newt installieren",
"siteInstallNewtDescription": "Installiere Newt auf deinem System.", "siteInstallNewtDescription": "Installiere Newt auf deinem System.",
"WgConfiguration": "WireGuard Konfiguration", "WgConfiguration": "WireGuard Konfiguration",
@@ -82,26 +82,26 @@
"siteNewtDescription": "Nutze Newt für die beste Benutzererfahrung. Newt verwendet WireGuard as Basis und erlaubt Ihnen, Ihre privaten Ressourcen über ihre LAN-Adresse in Ihrem privaten Netzwerk aus dem Pangolin-Dashboard heraus zu adressieren.", "siteNewtDescription": "Nutze Newt für die beste Benutzererfahrung. Newt verwendet WireGuard as Basis und erlaubt Ihnen, Ihre privaten Ressourcen über ihre LAN-Adresse in Ihrem privaten Netzwerk aus dem Pangolin-Dashboard heraus zu adressieren.",
"siteRunsInDocker": "Läuft in Docker", "siteRunsInDocker": "Läuft in Docker",
"siteRunsInShell": "Läuft in der Konsole auf macOS, Linux und Windows", "siteRunsInShell": "Läuft in der Konsole auf macOS, Linux und Windows",
"siteErrorDelete": "Fehler beim Löschen der Site", "siteErrorDelete": "Fehler beim Löschen des Standortes",
"siteErrorUpdate": "Fehler beim Aktualisieren der Site", "siteErrorUpdate": "Fehler beim Aktualisieren des Standortes",
"siteErrorUpdateDescription": "Beim Aktualisieren der Site ist ein Fehler aufgetreten.", "siteErrorUpdateDescription": "Beim Aktualisieren des Standortes ist ein Fehler aufgetreten.",
"siteUpdated": "Site aktualisiert", "siteUpdated": "Standort aktualisiert",
"siteUpdatedDescription": "Die Site wurde aktualisiert.", "siteUpdatedDescription": "Der Standort wurde aktualisiert.",
"siteGeneralDescription": "Allgemeine Einstellungen für diese Site konfigurieren", "siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren",
"siteSettingDescription": "Konfigurieren der Site Einstellungen", "siteSettingDescription": "Konfigurieren der Standort Einstellungen",
"siteSetting": "{siteName} Einstellungen", "siteSetting": "{siteName} Einstellungen",
"siteNewtTunnel": "Newt-Tunnel (empfohlen)", "siteNewtTunnel": "Newt-Tunnel (empfohlen)",
"siteNewtTunnelDescription": "Einfachster Weg, einen Zugriffspunkt zu deinem Netzwerk zu erstellen. Keine zusätzliche Einrichtung erforderlich.", "siteNewtTunnelDescription": "Einfachster Weg, einen Zugriffspunkt zu deinem Netzwerk zu erstellen. Keine zusätzliche Einrichtung erforderlich.",
"siteWg": "Einfacher WireGuard Tunnel", "siteWg": "Einfacher WireGuard Tunnel",
"siteWgDescription": "Verwende jeden WireGuard-Client, um einen Tunnel einzurichten. Manuelles NAT-Setup erforderlich.", "siteWgDescription": "Verwende jeden WireGuard-Client, um einen Tunnel einzurichten. Manuelles NAT-Setup erforderlich.",
"siteLocalDescription": "Nur lokale Ressourcen. Kein Tunneling.", "siteLocalDescription": "Nur lokale Ressourcen. Kein Tunneling.",
"siteSeeAll": "Alle Sites anzeigen", "siteSeeAll": "Alle Standorte anzeigen",
"siteTunnelDescription": "Lege fest, wie du dich mit deiner Site verbinden möchtest", "siteTunnelDescription": "Lege fest, wie du dich mit deinem Standort verbinden möchtest",
"siteNewtCredentials": "Neue Newt Zugangsdaten", "siteNewtCredentials": "Neue Newt Zugangsdaten",
"siteNewtCredentialsDescription": "So wird sich Newt mit dem Server authentifizieren", "siteNewtCredentialsDescription": "So wird sich Newt mit dem Server authentifizieren",
"siteCredentialsSave": "Ihre Zugangsdaten speichern", "siteCredentialsSave": "Ihre Zugangsdaten speichern",
"siteCredentialsSaveDescription": "Du kannst das nur einmal sehen. Stelle sicher, dass du es an einen sicheren Ort kopierst.", "siteCredentialsSaveDescription": "Du kannst das nur einmal sehen. Stelle sicher, dass du es an einen sicheren Ort kopierst.",
"siteInfo": "Site-Informationen", "siteInfo": "Standort-Informationen",
"status": "Status", "status": "Status",
"shareTitle": "Links zum Teilen verwalten", "shareTitle": "Links zum Teilen verwalten",
"shareDescription": "Erstellen Sie teilbare Links, um temporären oder permanenten Zugriff auf Ihre Ressourcen zu gewähren", "shareDescription": "Erstellen Sie teilbare Links, um temporären oder permanenten Zugriff auf Ihre Ressourcen zu gewähren",
@@ -163,10 +163,10 @@
"resourceSeeAll": "Alle Ressourcen anzeigen", "resourceSeeAll": "Alle Ressourcen anzeigen",
"resourceInfo": "Ressourcen-Informationen", "resourceInfo": "Ressourcen-Informationen",
"resourceNameDescription": "Dies ist der Anzeigename für die Ressource.", "resourceNameDescription": "Dies ist der Anzeigename für die Ressource.",
"siteSelect": "Site auswählen", "siteSelect": "Standort auswählen",
"siteSearch": "Website durchsuchen", "siteSearch": "Standorte durchsuchen",
"siteNotFound": "Keine Site gefunden.", "siteNotFound": "Keinen Standort gefunden.",
"siteSelectionDescription": "Diese Seite wird die Verbindung zu der Ressource herstellen.", "siteSelectionDescription": "Dieser Standort wird die Verbindung zu der Ressource herstellen.",
"resourceType": "Ressourcentyp", "resourceType": "Ressourcentyp",
"resourceTypeDescription": "Legen Sie fest, wie Sie auf Ihre Ressource zugreifen möchten", "resourceTypeDescription": "Legen Sie fest, wie Sie auf Ihre Ressource zugreifen möchten",
"resourceHTTPSSettings": "HTTPS-Einstellungen", "resourceHTTPSSettings": "HTTPS-Einstellungen",
@@ -302,7 +302,7 @@
"userQuestionRemove": "Sind Sie sicher, dass Sie {selectedUser} dauerhaft vom Server löschen möchten?", "userQuestionRemove": "Sind Sie sicher, dass Sie {selectedUser} dauerhaft vom Server löschen möchten?",
"licenseKey": "Lizenzschlüssel", "licenseKey": "Lizenzschlüssel",
"valid": "Gültig", "valid": "Gültig",
"numberOfSites": "Anzahl der Sites", "numberOfSites": "Anzahl der Standorte",
"licenseKeySearch": "Lizenzschlüssel suchen...", "licenseKeySearch": "Lizenzschlüssel suchen...",
"licenseKeyAdd": "Lizenzschlüssel hinzufügen", "licenseKeyAdd": "Lizenzschlüssel hinzufügen",
"type": "Typ", "type": "Typ",
@@ -342,16 +342,16 @@
"licensedNot": "Nicht lizenziert", "licensedNot": "Nicht lizenziert",
"hostId": "Host-ID", "hostId": "Host-ID",
"licenseReckeckAll": "Überprüfe alle Schlüssel", "licenseReckeckAll": "Überprüfe alle Schlüssel",
"licenseSiteUsage": "Website-Nutzung", "licenseSiteUsage": "Standort-Nutzung",
"licenseSiteUsageDecsription": "Sehen Sie sich die Anzahl der Sites an, die diese Lizenz verwenden.", "licenseSiteUsageDecsription": "Sehen Sie sich die Anzahl der Standorte an, die diese Lizenz verwenden.",
"licenseNoSiteLimit": "Die Anzahl der Sites, die einen nicht lizenzierten Host verwenden, ist unbegrenzt.", "licenseNoSiteLimit": "Die Anzahl der Standorte, die einen nicht lizenzierten Host verwenden, ist unbegrenzt.",
"licensePurchase": "Lizenz kaufen", "licensePurchase": "Lizenz kaufen",
"licensePurchaseSites": "Zusätzliche Seiten kaufen", "licensePurchaseSites": "Zusätzliche Standorte kaufen\n",
"licenseSitesUsedMax": "{usedSites} der {maxSites} Seiten verwendet", "licenseSitesUsedMax": "{usedSites} von {maxSites} Standorten verwendet",
"licenseSitesUsed": "{count, plural, =0 {# Seiten} one {# Seite} other {# Seiten}} im System.", "licenseSitesUsed": "{count, plural, =0 {# Standorte} one {# Standort} other {# Standorte}} im System.",
"licensePurchaseDescription": "Wähle aus, für wieviele Seiten du möchtest {selectedMode, select, license {kaufe eine Lizenz. Du kannst später immer weitere Seiten hinzufügen.} other {Füge zu deiner bestehenden Lizenz hinzu.}}", "licensePurchaseDescription": "Wähle aus, für wieviele Seiten du möchtest {selectedMode, select, license {kaufe eine Lizenz. Du kannst später immer weitere Seiten hinzufügen.} other {Füge zu deiner bestehenden Lizenz hinzu.}}",
"licenseFee": "Lizenzgebühr", "licenseFee": "Lizenzgebühr",
"licensePriceSite": "Preis pro Seite", "licensePriceSite": "Preis pro Standort",
"total": "Gesamt", "total": "Gesamt",
"licenseContinuePayment": "Weiter zur Zahlung", "licenseContinuePayment": "Weiter zur Zahlung",
"pricingPage": "Preisseite", "pricingPage": "Preisseite",
@@ -467,7 +467,7 @@
"targetErrorDuplicate": "Doppeltes Ziel", "targetErrorDuplicate": "Doppeltes Ziel",
"targetErrorDuplicateDescription": "Ein Ziel mit diesen Einstellungen existiert bereits", "targetErrorDuplicateDescription": "Ein Ziel mit diesen Einstellungen existiert bereits",
"targetWireGuardErrorInvalidIp": "Ungültige Ziel-IP", "targetWireGuardErrorInvalidIp": "Ungültige Ziel-IP",
"targetWireGuardErrorInvalidIpDescription": "Die Ziel-IP muss innerhalb des Site-Subnets liegen", "targetWireGuardErrorInvalidIpDescription": "Die Ziel-IP muss innerhalb des Standort-Subnets liegen",
"targetsUpdated": "Ziele aktualisiert", "targetsUpdated": "Ziele aktualisiert",
"targetsUpdatedDescription": "Ziele und Einstellungen erfolgreich aktualisiert", "targetsUpdatedDescription": "Ziele und Einstellungen erfolgreich aktualisiert",
"targetsErrorUpdate": "Fehler beim Aktualisieren der Ziele", "targetsErrorUpdate": "Fehler beim Aktualisieren der Ziele",
@@ -558,8 +558,8 @@
"resourceErrorCreateDescription": "Beim Erstellen der Ressource ist ein Fehler aufgetreten", "resourceErrorCreateDescription": "Beim Erstellen der Ressource ist ein Fehler aufgetreten",
"resourceErrorCreateMessage": "Fehler beim Erstellen der Ressource:", "resourceErrorCreateMessage": "Fehler beim Erstellen der Ressource:",
"resourceErrorCreateMessageDescription": "Ein unerwarteter Fehler ist aufgetreten", "resourceErrorCreateMessageDescription": "Ein unerwarteter Fehler ist aufgetreten",
"sitesErrorFetch": "Fehler beim Abrufen der Sites", "sitesErrorFetch": "Fehler beim Abrufen der Standorte",
"sitesErrorFetchDescription": "Beim Abrufen der Sites ist ein Fehler aufgetreten", "sitesErrorFetchDescription": "Beim Abrufen der Standorte ist ein Fehler aufgetreten",
"domainsErrorFetch": "Fehler beim Abrufen der Domains", "domainsErrorFetch": "Fehler beim Abrufen der Domains",
"domainsErrorFetchDescription": "Beim Abrufen der Domains ist ein Fehler aufgetreten", "domainsErrorFetchDescription": "Beim Abrufen der Domains ist ein Fehler aufgetreten",
"none": "Keine", "none": "Keine",
@@ -677,10 +677,10 @@
"resourceGeneralDescription": "Konfigurieren Sie die allgemeinen Einstellungen für diese Ressource", "resourceGeneralDescription": "Konfigurieren Sie die allgemeinen Einstellungen für diese Ressource",
"resourceEnable": "Ressource aktivieren", "resourceEnable": "Ressource aktivieren",
"resourceTransfer": "Ressource übertragen", "resourceTransfer": "Ressource übertragen",
"resourceTransferDescription": "Diese Ressource auf eine andere Site übertragen", "resourceTransferDescription": "Diese Ressource auf einen anderen Standort übertragen",
"resourceTransferSubmit": "Ressource übertragen", "resourceTransferSubmit": "Ressource übertragen",
"siteDestination": "Zielsite", "siteDestination": "Zielort",
"searchSites": "Sites durchsuchen", "searchSites": "Standorte durchsuchen",
"accessRoleCreate": "Rolle erstellen", "accessRoleCreate": "Rolle erstellen",
"accessRoleCreateDescription": "Erstellen Sie eine neue Rolle, um Benutzer zu gruppieren und ihre Berechtigungen zu verwalten.", "accessRoleCreateDescription": "Erstellen Sie eine neue Rolle, um Benutzer zu gruppieren und ihre Berechtigungen zu verwalten.",
"accessRoleCreateSubmit": "Rolle erstellen", "accessRoleCreateSubmit": "Rolle erstellen",
@@ -700,7 +700,7 @@
"accessRoleRemovedDescription": "Die Rolle wurde erfolgreich entfernt.", "accessRoleRemovedDescription": "Die Rolle wurde erfolgreich entfernt.",
"accessRoleRequiredRemove": "Bevor Sie diese Rolle löschen, wählen Sie bitte eine neue Rolle aus, zu der die bestehenden Mitglieder übertragen werden sollen.", "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", "manage": "Verwalten",
"sitesNotFound": "Keine Sites gefunden.", "sitesNotFound": "Keine Standorte gefunden.",
"pangolinServerAdmin": "Server-Admin - Pangolin", "pangolinServerAdmin": "Server-Admin - Pangolin",
"licenseTierProfessional": "Professional Lizenz", "licenseTierProfessional": "Professional Lizenz",
"licenseTierEnterprise": "Enterprise Lizenz", "licenseTierEnterprise": "Enterprise Lizenz",
@@ -708,10 +708,10 @@
"licensed": "Lizenziert", "licensed": "Lizenziert",
"yes": "Ja", "yes": "Ja",
"no": "Nein", "no": "Nein",
"sitesAdditional": "Zusätzliche Sites", "sitesAdditional": "Zusätzliche Standorte",
"licenseKeys": "Lizenzschlüssel", "licenseKeys": "Lizenzschlüssel",
"sitestCountDecrease": "Anzahl der Sites verringern", "sitestCountDecrease": "Anzahl der Standorte verringern",
"sitestCountIncrease": "Anzahl der Sites erhöhen", "sitestCountIncrease": "Anzahl der Standorte erhöhen",
"idpManage": "Identitätsanbieter verwalten", "idpManage": "Identitätsanbieter verwalten",
"idpManageDescription": "Identitätsanbieter im System anzeigen und verwalten", "idpManageDescription": "Identitätsanbieter im System anzeigen und verwalten",
"idpDeletedDescription": "Identitätsanbieter erfolgreich gelöscht", "idpDeletedDescription": "Identitätsanbieter erfolgreich gelöscht",
@@ -963,12 +963,12 @@
"actionGetUser": "Benutzer abrufen", "actionGetUser": "Benutzer abrufen",
"actionGetOrgUser": "Organisationsbenutzer abrufen", "actionGetOrgUser": "Organisationsbenutzer abrufen",
"actionListOrgDomains": "Organisationsdomänen auflisten", "actionListOrgDomains": "Organisationsdomänen auflisten",
"actionCreateSite": "Site erstellen", "actionCreateSite": "Standort erstellen",
"actionDeleteSite": "Site löschen", "actionDeleteSite": "Standort löschen",
"actionGetSite": "Site abrufen", "actionGetSite": "Standort abrufen",
"actionListSites": "Sites auflisten", "actionListSites": "Standorte auflisten",
"actionUpdateSite": "Site aktualisieren", "actionUpdateSite": "Standorte aktualisieren",
"actionListSiteRoles": "Erlaubte Site-Rollen auflisten", "actionListSiteRoles": "Erlaubte Standort-Rollen auflisten",
"actionCreateResource": "Ressource erstellen", "actionCreateResource": "Ressource erstellen",
"actionDeleteResource": "Ressource löschen", "actionDeleteResource": "Ressource löschen",
"actionGetResource": "Ressource abrufen", "actionGetResource": "Ressource abrufen",
@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "IDP-Organisationsrichtlinie löschen", "actionDeleteIdpOrg": "IDP-Organisationsrichtlinie löschen",
"actionListIdpOrgs": "IDP-Organisationen auflisten", "actionListIdpOrgs": "IDP-Organisationen auflisten",
"actionUpdateIdpOrg": "IDP-Organisation aktualisieren", "actionUpdateIdpOrg": "IDP-Organisation aktualisieren",
"actionCreateClient": "Kunde erstellen",
"actionDeleteClient": "Kunde löschen",
"actionUpdateClient": "Kunde aktualisieren",
"actionListClients": "Kunden auflisten",
"actionGetClient": "Kunde holen",
"noneSelected": "Keine ausgewählt", "noneSelected": "Keine ausgewählt",
"orgNotFound2": "Keine Organisationen gefunden.", "orgNotFound2": "Keine Organisationen gefunden.",
"searchProgress": "Suche...", "searchProgress": "Suche...",
@@ -1073,7 +1078,7 @@
"language": "Sprache", "language": "Sprache",
"verificationCodeRequired": "Code ist erforderlich", "verificationCodeRequired": "Code ist erforderlich",
"userErrorNoUpdate": "Kein Benutzer zum Aktualisieren", "userErrorNoUpdate": "Kein Benutzer zum Aktualisieren",
"siteErrorNoUpdate": "Keine Site zum Aktualisieren", "siteErrorNoUpdate": "Keine Standorte zum Aktualisieren",
"resourceErrorNoUpdate": "Keine Ressource zum Aktualisieren", "resourceErrorNoUpdate": "Keine Ressource zum Aktualisieren",
"authErrorNoUpdate": "Keine Auth-Informationen zum Aktualisieren", "authErrorNoUpdate": "Keine Auth-Informationen zum Aktualisieren",
"orgErrorNoUpdate": "Keine Organisation zum Aktualisieren", "orgErrorNoUpdate": "Keine Organisation zum Aktualisieren",
@@ -1081,7 +1086,7 @@
"apiKeysErrorNoUpdate": "Kein API-Schlüssel zum Aktualisieren", "apiKeysErrorNoUpdate": "Kein API-Schlüssel zum Aktualisieren",
"sidebarOverview": "Übersicht", "sidebarOverview": "Übersicht",
"sidebarHome": "Zuhause", "sidebarHome": "Zuhause",
"sidebarSites": "Seiten", "sidebarSites": "Standorte",
"sidebarResources": "Ressourcen", "sidebarResources": "Ressourcen",
"sidebarAccessControl": "Zugriffskontrolle", "sidebarAccessControl": "Zugriffskontrolle",
"sidebarUsers": "Benutzer", "sidebarUsers": "Benutzer",
@@ -1280,21 +1285,21 @@
"and": "und", "and": "und",
"privacyPolicy": "Datenschutzrichtlinie" "privacyPolicy": "Datenschutzrichtlinie"
}, },
"siteRequired": "Site ist erforderlich.", "siteRequired": "Standort ist erforderlich.",
"olmTunnel": "Olm Tunnel", "olmTunnel": "Olm Tunnel",
"olmTunnelDescription": "Nutzen Sie Olm für die Kundenverbindung", "olmTunnelDescription": "Nutzen Sie Olm für die Kundenverbindung",
"errorCreatingClient": "Fehler beim Erstellen des Clients", "errorCreatingClient": "Fehler beim Erstellen des Clients",
"clientDefaultsNotFound": "Kundenvorgaben nicht gefunden", "clientDefaultsNotFound": "Kundenvorgaben nicht gefunden",
"createClient": "Client erstellen", "createClient": "Client erstellen",
"createClientDescription": "Erstellen Sie einen neuen Client für die Verbindung zu Ihren Sites.", "createClientDescription": "Erstellen Sie einen neuen Client für die Verbindung zu Ihren Standorten.",
"seeAllClients": "Alle Clients anzeigen", "seeAllClients": "Alle Clients anzeigen",
"clientInformation": "Kundeninformationen", "clientInformation": "Kundeninformationen",
"clientNamePlaceholder": "Kundenname", "clientNamePlaceholder": "Kundenname",
"address": "Adresse", "address": "Adresse",
"subnetPlaceholder": "Subnetz", "subnetPlaceholder": "Subnetz",
"addressDescription": "Die Adresse, die dieser Client für die Verbindung verwenden wird.", "addressDescription": "Die Adresse, die dieser Client für die Verbindung verwenden wird.",
"selectSites": "Sites auswählen", "selectSites": "Standorte auswählen",
"sitesDescription": "Der Client wird zu den ausgewählten Sites eine Verbindung haben.", "sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.",
"clientInstallOlm": "Olm installieren", "clientInstallOlm": "Olm installieren",
"clientInstallOlmDescription": "Olm auf Ihrem System zum Laufen bringen", "clientInstallOlmDescription": "Olm auf Ihrem System zum Laufen bringen",
"clientOlmCredentials": "Olm-Zugangsdaten", "clientOlmCredentials": "Olm-Zugangsdaten",
@@ -1309,13 +1314,13 @@
"clientUpdatedDescription": "Der Client wurde aktualisiert.", "clientUpdatedDescription": "Der Client wurde aktualisiert.",
"clientUpdateFailed": "Fehler beim Aktualisieren des Clients", "clientUpdateFailed": "Fehler beim Aktualisieren des Clients",
"clientUpdateError": "Beim Aktualisieren des Clients ist ein Fehler aufgetreten.", "clientUpdateError": "Beim Aktualisieren des Clients ist ein Fehler aufgetreten.",
"sitesFetchFailed": "Fehler beim Abrufen von Sites", "sitesFetchFailed": "Fehler beim Abrufen von Standorten",
"sitesFetchError": "Beim Abrufen von Sites ist ein Fehler aufgetreten.", "sitesFetchError": "Beim Abrufen von Standorten ist ein Fehler aufgetreten.",
"olmErrorFetchReleases": "Beim Abrufen von Olm-Veröffentlichungen ist ein Fehler aufgetreten.", "olmErrorFetchReleases": "Beim Abrufen von Olm-Veröffentlichungen ist ein Fehler aufgetreten.",
"olmErrorFetchLatest": "Beim Abrufen der neuesten Olm-Veröffentlichung ist ein Fehler aufgetreten.", "olmErrorFetchLatest": "Beim Abrufen der neuesten Olm-Veröffentlichung ist ein Fehler aufgetreten.",
"remoteSubnets": "Remote-Subnetze", "remoteSubnets": "Remote-Subnetze",
"enterCidrRange": "Geben Sie den CIDR-Bereich ein", "enterCidrRange": "Geben Sie den CIDR-Bereich ein",
"remoteSubnetsDescription": "Fügen Sie CIDR-Bereiche hinzu, die aus der Ferne auf diese Site zugreifen können. Verwenden Sie das Format wie 10.0.0.0/24 oder 192.168.1.0/24.", "remoteSubnetsDescription": "Fügen Sie CIDR-Bereiche hinzu, die aus der Ferne auf diesen Standort zugreifen können. Verwenden Sie das Format wie 10.0.0.0/24 oder 192.168.1.0/24.",
"resourceEnableProxy": "Öffentlichen Proxy aktivieren", "resourceEnableProxy": "Öffentlichen Proxy aktivieren",
"resourceEnableProxyDescription": "Ermöglichen Sie öffentliches Proxieren zu dieser Ressource. Dies ermöglicht den Zugriff auf die Ressource von außerhalb des Netzwerks durch die Cloud über einen offenen Port. Erfordert Traefik-Config.", "resourceEnableProxyDescription": "Ermöglichen Sie öffentliches Proxieren zu dieser Ressource. Dies ermöglicht den Zugriff auf die Ressource von außerhalb des Netzwerks durch die Cloud über einen offenen Port. Erfordert Traefik-Config.",
"externalProxyEnabled": "Externer Proxy aktiviert" "externalProxyEnabled": "Externer Proxy aktiviert"

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Eliminar política de IDP Org", "actionDeleteIdpOrg": "Eliminar política de IDP Org",
"actionListIdpOrgs": "Listar Orgs IDP", "actionListIdpOrgs": "Listar Orgs IDP",
"actionUpdateIdpOrg": "Actualizar IDP Org", "actionUpdateIdpOrg": "Actualizar IDP Org",
"actionCreateClient": "Crear cliente",
"actionDeleteClient": "Eliminar cliente",
"actionUpdateClient": "Actualizar cliente",
"actionListClients": "Listar clientes",
"actionGetClient": "Obtener cliente",
"noneSelected": "Ninguno seleccionado", "noneSelected": "Ninguno seleccionado",
"orgNotFound2": "No se encontraron organizaciones.", "orgNotFound2": "No se encontraron organizaciones.",
"searchProgress": "Buscar...", "searchProgress": "Buscar...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Supprimer une politique d'organisation IDP", "actionDeleteIdpOrg": "Supprimer une politique d'organisation IDP",
"actionListIdpOrgs": "Lister les organisations IDP", "actionListIdpOrgs": "Lister les organisations IDP",
"actionUpdateIdpOrg": "Mettre à jour une organisation IDP", "actionUpdateIdpOrg": "Mettre à jour une organisation IDP",
"actionCreateClient": "Créer un client",
"actionDeleteClient": "Supprimer le client",
"actionUpdateClient": "Mettre à jour le client",
"actionListClients": "Liste des clients",
"actionGetClient": "Obtenir le client",
"noneSelected": "Aucune sélection", "noneSelected": "Aucune sélection",
"orgNotFound2": "Aucune organisation trouvée.", "orgNotFound2": "Aucune organisation trouvée.",
"searchProgress": "Rechercher...", "searchProgress": "Rechercher...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Elimina Politica Org IDP", "actionDeleteIdpOrg": "Elimina Politica Org IDP",
"actionListIdpOrgs": "Elenca Org IDP", "actionListIdpOrgs": "Elenca Org IDP",
"actionUpdateIdpOrg": "Aggiorna Org IDP", "actionUpdateIdpOrg": "Aggiorna Org IDP",
"actionCreateClient": "Crea Client",
"actionDeleteClient": "Elimina Client",
"actionUpdateClient": "Aggiorna Client",
"actionListClients": "Elenco Clienti",
"actionGetClient": "Ottieni Client",
"noneSelected": "Nessuna selezione", "noneSelected": "Nessuna selezione",
"orgNotFound2": "Nessuna organizzazione trovata.", "orgNotFound2": "Nessuna organizzazione trovata.",
"searchProgress": "Ricerca...", "searchProgress": "Ricerca...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "IDP 조직 정책 삭제", "actionDeleteIdpOrg": "IDP 조직 정책 삭제",
"actionListIdpOrgs": "IDP 조직 목록", "actionListIdpOrgs": "IDP 조직 목록",
"actionUpdateIdpOrg": "IDP 조직 업데이트", "actionUpdateIdpOrg": "IDP 조직 업데이트",
"actionCreateClient": "Create Client",
"actionDeleteClient": "Delete Client",
"actionUpdateClient": "Update Client",
"actionListClients": "List Clients",
"actionGetClient": "Get Client",
"noneSelected": "선택된 항목 없음", "noneSelected": "선택된 항목 없음",
"orgNotFound2": "조직이 없습니다.", "orgNotFound2": "조직이 없습니다.",
"searchProgress": "검색...", "searchProgress": "검색...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Verwijder IDP Org Beleid", "actionDeleteIdpOrg": "Verwijder IDP Org Beleid",
"actionListIdpOrgs": "Toon IDP Orgs", "actionListIdpOrgs": "Toon IDP Orgs",
"actionUpdateIdpOrg": "IDP-org bijwerken", "actionUpdateIdpOrg": "IDP-org bijwerken",
"actionCreateClient": "Client aanmaken",
"actionDeleteClient": "Verwijder klant",
"actionUpdateClient": "Klant bijwerken",
"actionListClients": "Lijst klanten",
"actionGetClient": "Client ophalen",
"noneSelected": "Niet geselecteerd", "noneSelected": "Niet geselecteerd",
"orgNotFound2": "Geen organisaties gevonden.", "orgNotFound2": "Geen organisaties gevonden.",
"searchProgress": "Zoeken...", "searchProgress": "Zoeken...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Usuń politykę organizacji IDP", "actionDeleteIdpOrg": "Usuń politykę organizacji IDP",
"actionListIdpOrgs": "Lista organizacji IDP", "actionListIdpOrgs": "Lista organizacji IDP",
"actionUpdateIdpOrg": "Aktualizuj organizację IDP", "actionUpdateIdpOrg": "Aktualizuj organizację IDP",
"actionCreateClient": "Utwórz klienta",
"actionDeleteClient": "Usuń klienta",
"actionUpdateClient": "Aktualizuj klienta",
"actionListClients": "Lista klientów",
"actionGetClient": "Pobierz klienta",
"noneSelected": "Nie wybrano", "noneSelected": "Nie wybrano",
"orgNotFound2": "Nie znaleziono organizacji.", "orgNotFound2": "Nie znaleziono organizacji.",
"searchProgress": "Szukaj...", "searchProgress": "Szukaj...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Eliminar Política de Organização IDP", "actionDeleteIdpOrg": "Eliminar Política de Organização IDP",
"actionListIdpOrgs": "Listar Organizações IDP", "actionListIdpOrgs": "Listar Organizações IDP",
"actionUpdateIdpOrg": "Atualizar Organização IDP", "actionUpdateIdpOrg": "Atualizar Organização IDP",
"actionCreateClient": "Criar Cliente",
"actionDeleteClient": "Excluir Cliente",
"actionUpdateClient": "Atualizar Cliente",
"actionListClients": "Listar Clientes",
"actionGetClient": "Obter Cliente",
"noneSelected": "Nenhum selecionado", "noneSelected": "Nenhum selecionado",
"orgNotFound2": "Nenhuma organização encontrada.", "orgNotFound2": "Nenhuma organização encontrada.",
"searchProgress": "Pesquisar...", "searchProgress": "Pesquisar...",

View File

@@ -925,74 +925,74 @@
"supportKeyInvalid": "Недействительный ключ", "supportKeyInvalid": "Недействительный ключ",
"supportKeyInvalidDescription": "Ваш ключ поддержки недействителен.", "supportKeyInvalidDescription": "Ваш ключ поддержки недействителен.",
"supportKeyValid": "Действительный ключ", "supportKeyValid": "Действительный ключ",
"supportKeyValidDescription": "Your supporter key has been validated. Thank you for your support!", "supportKeyValidDescription": "Ваш ключ поддержки был проверен. Спасибо за поддержку!",
"supportKeyErrorValidationDescription": "Failed to validate supporter key.", "supportKeyErrorValidationDescription": "Не удалось проверить ключ поддержки.",
"supportKey": "Support Development and Adopt a Pangolin!", "supportKey": "Поддержите разработку и усыновите Панголина!",
"supportKeyDescription": "Приобретите ключ поддержки, чтобы помочь нам продолжать разработку Pangolin для сообщества. Ваш вклад позволяет нам уделять больше времени поддержке и добавлению новых функций в приложение для всех. Мы никогда не будем использовать это для платного доступа к функциям. Это отдельно от любой коммерческой версии.", "supportKeyDescription": "Приобретите ключ поддержки, чтобы помочь нам продолжать разработку Pangolin для сообщества. Ваш вклад позволяет нам уделять больше времени поддержке и добавлению новых функций в приложение для всех. Мы никогда не будем использовать это для платного доступа к функциям. Это отдельно от любой коммерческой версии.",
"supportKeyPet": "You will also get to adopt and meet your very own pet Pangolin!", "supportKeyPet": "Вы также сможете усыновить и встретить вашего собственного питомца Панголина!",
"supportKeyPurchase": "Payments are processed via GitHub. Afterward, you can retrieve your key on", "supportKeyPurchase": "Платежи обрабатываются через GitHub. После этого вы сможете получить свой ключ на",
"supportKeyPurchaseLink": "our website", "supportKeyPurchaseLink": "нашем сайте",
"supportKeyPurchase2": "and redeem it here.", "supportKeyPurchase2": "и активировать его здесь.",
"supportKeyLearnMore": "Learn more.", "supportKeyLearnMore": "Узнать больше.",
"supportKeyOptions": "Please select the option that best suits you.", "supportKeyOptions": "Пожалуйста, выберите подходящий вам вариант.",
"supportKetOptionFull": "Full Supporter", "supportKetOptionFull": "Полная поддержка",
"forWholeServer": "For the whole server", "forWholeServer": "За весь сервер",
"lifetimePurchase": "Lifetime purchase", "lifetimePurchase": "Пожизненная покупка",
"supporterStatus": "Supporter status", "supporterStatus": "Статус поддержки",
"buy": "Buy", "buy": "Купить",
"supportKeyOptionLimited": "Limited Supporter", "supportKeyOptionLimited": "Лимитированная поддержка",
"forFiveUsers": "For 5 or less users", "forFiveUsers": "За 5 или меньше пользователей",
"supportKeyRedeem": "Redeem Supporter Key", "supportKeyRedeem": "Использовать ключ Поддержки",
"supportKeyHideSevenDays": "Hide for 7 days", "supportKeyHideSevenDays": "Скрыть на 7 дней",
"supportKeyEnter": "Enter Supporter Key", "supportKeyEnter": "Введите ключ поддержки",
"supportKeyEnterDescription": "Meet your very own pet Pangolin!", "supportKeyEnterDescription": "Встречайте своего питомца Панголина!",
"githubUsername": "GitHub Username", "githubUsername": "Имя пользователя Github",
"supportKeyInput": "Supporter Key", "supportKeyInput": "Ключ поддержки",
"supportKeyBuy": "Buy Supporter Key", "supportKeyBuy": "Ключ поддержки",
"logoutError": "Error logging out", "logoutError": "Ошибка при выходе",
"signingAs": "Signed in as", "signingAs": "Вы вошли как",
"serverAdmin": "Server Admin", "serverAdmin": "Администратор сервера",
"otpEnable": "Enable Two-factor", "otpEnable": "Включить Двухфакторную Аутентификацию",
"otpDisable": "Disable Two-factor", "otpDisable": "Отключить двухфакторную аутентификацию",
"logout": "Log Out", "logout": "Выйти",
"licenseTierProfessionalRequired": "Professional Edition Required", "licenseTierProfessionalRequired": "Требуется профессиональная версия",
"licenseTierProfessionalRequiredDescription": "Эта функция доступна только в профессиональной версии.", "licenseTierProfessionalRequiredDescription": "Эта функция доступна только в профессиональной версии.",
"actionGetOrg": "Get Organization", "actionGetOrg": "Получить организацию",
"actionUpdateOrg": "Update Organization", "actionUpdateOrg": "Обновить организацию",
"actionUpdateUser": "Update User", "actionUpdateUser": "Обновить пользователя",
"actionGetUser": "Get User", "actionGetUser": "Получить пользователя",
"actionGetOrgUser": "Get Organization User", "actionGetOrgUser": "Получить пользователя организации",
"actionListOrgDomains": "List Organization Domains", "actionListOrgDomains": "Список доменов организации",
"actionCreateSite": "Create Site", "actionCreateSite": "Создать сайт",
"actionDeleteSite": "Delete Site", "actionDeleteSite": "Удалить сайт",
"actionGetSite": "Get Site", "actionGetSite": "Получить сайт",
"actionListSites": "List Sites", "actionListSites": "Список сайтов",
"actionUpdateSite": "Update Site", "actionUpdateSite": "Обновить сайт",
"actionListSiteRoles": "List Allowed Site Roles", "actionListSiteRoles": "Список разрешенных ролей сайта",
"actionCreateResource": "Create Resource", "actionCreateResource": "Создать ресурс",
"actionDeleteResource": "Delete Resource", "actionDeleteResource": "Удалить ресурс",
"actionGetResource": "Get Resource", "actionGetResource": "Получить ресурсы",
"actionListResource": "List Resources", "actionListResource": "Список ресурсов",
"actionUpdateResource": "Update Resource", "actionUpdateResource": "Обновить ресурс",
"actionListResourceUsers": "List Resource Users", "actionListResourceUsers": "Список пользователей ресурсов",
"actionSetResourceUsers": "Set Resource Users", "actionSetResourceUsers": "Список пользователей ресурсов",
"actionSetAllowedResourceRoles": "Set Allowed Resource Roles", "actionSetAllowedResourceRoles": "Набор разрешенных ролей ресурсов",
"actionListAllowedResourceRoles": "List Allowed Resource Roles", "actionListAllowedResourceRoles": "Список разрешенных ролей сайта",
"actionSetResourcePassword": "Set Resource Password", "actionSetResourcePassword": "Задать пароль ресурса",
"actionSetResourcePincode": "Set Resource Pincode", "actionSetResourcePincode": "Установить ПИН-код ресурса",
"actionSetResourceEmailWhitelist": "Set Resource Email Whitelist", "actionSetResourceEmailWhitelist": "Set Resource Email Whitelist",
"actionGetResourceEmailWhitelist": "Get Resource Email Whitelist", "actionGetResourceEmailWhitelist": "Get Resource Email Whitelist",
"actionCreateTarget": "Create Target", "actionCreateTarget": "Создать цель",
"actionDeleteTarget": "Delete Target", "actionDeleteTarget": "Удалить цель",
"actionGetTarget": "Get Target", "actionGetTarget": "Получить цель",
"actionListTargets": "List Targets", "actionListTargets": "Список целей",
"actionUpdateTarget": "Update Target", "actionUpdateTarget": "Обновить цель",
"actionCreateRole": "Create Role", "actionCreateRole": "Создать роль",
"actionDeleteRole": "Delete Role", "actionDeleteRole": "Удалить роль",
"actionGetRole": "Get Role", "actionGetRole": "Получить Роль",
"actionListRole": "List Roles", "actionListRole": "Список ролей",
"actionUpdateRole": "Update Role", "actionUpdateRole": "Обновить роль",
"actionListAllowedRoleResources": "List Allowed Role Resources", "actionListAllowedRoleResources": "Список разрешенных ролей сайта",
"actionInviteUser": "Пригласить пользователя", "actionInviteUser": "Пригласить пользователя",
"actionRemoveUser": "Удалить пользователя", "actionRemoveUser": "Удалить пользователя",
"actionListUsers": "Список пользователей", "actionListUsers": "Список пользователей",
@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Удалить политику IDP организации", "actionDeleteIdpOrg": "Удалить политику IDP организации",
"actionListIdpOrgs": "Список организаций IDP", "actionListIdpOrgs": "Список организаций IDP",
"actionUpdateIdpOrg": "Обновить организацию IDP", "actionUpdateIdpOrg": "Обновить организацию IDP",
"actionCreateClient": "Создать Клиента",
"actionDeleteClient": "Удалить Клиента",
"actionUpdateClient": "Обновить Клиента",
"actionListClients": "Список Клиентов",
"actionGetClient": "Получить Клиента",
"noneSelected": "Ничего не выбрано", "noneSelected": "Ничего не выбрано",
"orgNotFound2": "Организации не найдены.", "orgNotFound2": "Организации не найдены.",
"searchProgress": "Поиск...", "searchProgress": "Поиск...",
@@ -1093,8 +1098,8 @@
"sidebarAllUsers": "Все пользователи", "sidebarAllUsers": "Все пользователи",
"sidebarIdentityProviders": "Поставщики удостоверений", "sidebarIdentityProviders": "Поставщики удостоверений",
"sidebarLicense": "Лицензия", "sidebarLicense": "Лицензия",
"sidebarClients": "Clients (Beta)", "sidebarClients": "Клиенты (бета)",
"sidebarDomains": "Domains", "sidebarDomains": "Домены",
"enableDockerSocket": "Включить Docker Socket", "enableDockerSocket": "Включить Docker Socket",
"enableDockerSocketDescription": "Включить обнаружение Docker Socket для заполнения информации о контейнерах. Путь к сокету должен быть предоставлен Newt.", "enableDockerSocketDescription": "Включить обнаружение Docker Socket для заполнения информации о контейнерах. Путь к сокету должен быть предоставлен Newt.",
"enableDockerSocketLink": "Узнать больше", "enableDockerSocketLink": "Узнать больше",
@@ -1134,36 +1139,36 @@
"dark": "тёмная", "dark": "тёмная",
"system": "системная", "system": "системная",
"theme": "Тема", "theme": "Тема",
"subnetRequired": "Subnet is required", "subnetRequired": "Требуется подсеть",
"initialSetupTitle": "Начальная настройка сервера", "initialSetupTitle": "Начальная настройка сервера",
"initialSetupDescription": "Создайте первоначальную учётную запись администратора сервера. Может существовать только один администратор сервера. Вы всегда можете изменить эти учётные данные позже.", "initialSetupDescription": "Создайте первоначальную учётную запись администратора сервера. Может существовать только один администратор сервера. Вы всегда можете изменить эти учётные данные позже.",
"createAdminAccount": "Создать учётную запись администратора", "createAdminAccount": "Создать учётную запись администратора",
"setupErrorCreateAdmin": "Произошла ошибка при создании учётной записи администратора сервера.", "setupErrorCreateAdmin": "Произошла ошибка при создании учётной записи администратора сервера.",
"certificateStatus": "Certificate Status", "certificateStatus": "Статус сертификата",
"loading": "Loading", "loading": "Загрузка",
"restart": "Restart", "restart": "Перезагрузка",
"domains": "Domains", "domains": "Домены",
"domainsDescription": "Manage domains for your organization", "domainsDescription": "Управление доменами для вашей организации",
"domainsSearch": "Search domains...", "domainsSearch": "Поиск доменов...",
"domainAdd": "Add Domain", "domainAdd": "Добавить Домен",
"domainAddDescription": "Register a new domain with your organization", "domainAddDescription": "Зарегистрировать новый домен в вашей организации",
"domainCreate": "Create Domain", "domainCreate": "Создать Домен",
"domainCreatedDescription": "Domain created successfully", "domainCreatedDescription": "Домен успешно создан",
"domainDeletedDescription": "Domain deleted successfully", "domainDeletedDescription": "Домен успешно удален",
"domainQuestionRemove": "Are you sure you want to remove the domain {domain} from your account?", "domainQuestionRemove": "Вы уверены, что хотите удалить домен {domain} из вашего аккаунта?",
"domainMessageRemove": "Once removed, the domain will no longer be associated with your account.", "domainMessageRemove": "После удаления домен больше не будет связан с вашей учетной записью.",
"domainMessageConfirm": "To confirm, please type the domain name below.", "domainMessageConfirm": "Для подтверждения введите ниже имя домена.",
"domainConfirmDelete": "Confirm Delete Domain", "domainConfirmDelete": "Подтвердить удаление домена",
"domainDelete": "Delete Domain", "domainDelete": "Удалить Домен",
"domain": "Domain", "domain": "Домен",
"selectDomainTypeNsName": "Domain Delegation (NS)", "selectDomainTypeNsName": "Делегация домена (NS)",
"selectDomainTypeNsDescription": "This domain and all its subdomains. Use this when you want to control an entire domain zone.", "selectDomainTypeNsDescription": "Этот домен и все его субдомены. Используйте это, когда вы хотите управлять всей доменной зоной.",
"selectDomainTypeCnameName": "Single Domain (CNAME)", "selectDomainTypeCnameName": "Одиночный домен (CNAME)",
"selectDomainTypeCnameDescription": "Just this specific domain. Use this for individual subdomains or specific domain entries.", "selectDomainTypeCnameDescription": "Только этот конкретный домен. Используйте это для отдельных субдоменов или отдельных записей домена.",
"selectDomainTypeWildcardName": "Wildcard Domain", "selectDomainTypeWildcardName": "Wildcard Domain",
"selectDomainTypeWildcardDescription": "This domain and its subdomains.", "selectDomainTypeWildcardDescription": "Этот домен и его субдомены.",
"domainDelegation": "Single Domain", "domainDelegation": "Единый домен",
"selectType": "Select a type", "selectType": "Выберите тип",
"actions": "Actions", "actions": "Actions",
"refresh": "Refresh", "refresh": "Refresh",
"refreshError": "Failed to refresh data", "refreshError": "Failed to refresh data",
@@ -1268,19 +1273,19 @@
"createDomainARecords": "A Records", "createDomainARecords": "A Records",
"createDomainRecordNumber": "Record {number}", "createDomainRecordNumber": "Record {number}",
"createDomainTxtRecords": "TXT Records", "createDomainTxtRecords": "TXT Records",
"createDomainSaveTheseRecords": "Save These Records", "createDomainSaveTheseRecords": "Сохранить эти записи",
"createDomainSaveTheseRecordsDescription": "Make sure to save these DNS records as you will not see them again.", "createDomainSaveTheseRecordsDescription": "Обязательно сохраните эти DNS записи, так как вы их больше не увидите.",
"createDomainDnsPropagation": "DNS Propagation", "createDomainDnsPropagation": "Распространение DNS",
"createDomainDnsPropagationDescription": "DNS changes may take some time to propagate across the internet. This can take anywhere from a few minutes to 48 hours, depending on your DNS provider and TTL settings.", "createDomainDnsPropagationDescription": "Изменения DNS могут занять некоторое время для распространения через интернет. Это может занять от нескольких минут до 48 часов в зависимости от вашего DNS провайдера и настроек TTL.",
"resourcePortRequired": "Port number is required for non-HTTP resources", "resourcePortRequired": "Номер порта необходим для не-HTTP ресурсов",
"resourcePortNotAllowed": "Port number should not be set for HTTP resources", "resourcePortNotAllowed": "Номер порта не должен быть установлен для HTTP ресурсов",
"signUpTerms": { "signUpTerms": {
"IAgreeToThe": "I agree to the", "IAgreeToThe": "Я согласен с",
"termsOfService": "terms of service", "termsOfService": "условия использования",
"and": "and", "and": "и",
"privacyPolicy": "privacy policy" "privacyPolicy": "политика конфиденциальности"
}, },
"siteRequired": "Site is required.", "siteRequired": "Необходимо указать сайт.",
"olmTunnel": "Olm Tunnel", "olmTunnel": "Olm Tunnel",
"olmTunnelDescription": "Use Olm for client connectivity", "olmTunnelDescription": "Use Olm for client connectivity",
"errorCreatingClient": "Error creating client", "errorCreatingClient": "Error creating client",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "Kimlik Sağlayıcı Organizasyon Politikasını Sil", "actionDeleteIdpOrg": "Kimlik Sağlayıcı Organizasyon Politikasını Sil",
"actionListIdpOrgs": "Kimlik Sağlayıcı Organizasyonları Listele", "actionListIdpOrgs": "Kimlik Sağlayıcı Organizasyonları Listele",
"actionUpdateIdpOrg": "Kimlik Sağlayıcı Organizasyonu Güncelle", "actionUpdateIdpOrg": "Kimlik Sağlayıcı Organizasyonu Güncelle",
"actionCreateClient": "Müşteri Oluştur",
"actionDeleteClient": "Müşteri Sil",
"actionUpdateClient": "Müşteri Güncelle",
"actionListClients": "Müşterileri Listele",
"actionGetClient": "Müşteriyi Al",
"noneSelected": "Hiçbiri seçili değil", "noneSelected": "Hiçbiri seçili değil",
"orgNotFound2": "Hiçbir organizasyon bulunamadı.", "orgNotFound2": "Hiçbir organizasyon bulunamadı.",
"searchProgress": "Ara...", "searchProgress": "Ara...",

View File

@@ -1022,6 +1022,11 @@
"actionDeleteIdpOrg": "删除 IDP组织策略", "actionDeleteIdpOrg": "删除 IDP组织策略",
"actionListIdpOrgs": "列出 IDP组织", "actionListIdpOrgs": "列出 IDP组织",
"actionUpdateIdpOrg": "更新 IDP组织", "actionUpdateIdpOrg": "更新 IDP组织",
"actionCreateClient": "创建客户端",
"actionDeleteClient": "删除客户端",
"actionUpdateClient": "更新客户端",
"actionListClients": "列出客户端",
"actionGetClient": "获取客户端",
"noneSelected": "未选择", "noneSelected": "未选择",
"orgNotFound2": "未找到组织。", "orgNotFound2": "未找到组织。",
"searchProgress": "搜索中...", "searchProgress": "搜索中...",

View File

@@ -88,7 +88,7 @@ export const WelcomeQuickStart = ({
To learn how to use Newt, including more To learn how to use Newt, including more
installation methods, visit the{" "} installation methods, visit the{" "}
<a <a
href="https://docs.fossorial.io" href="https://docs.digpangolin.com/manage/sites/install-site"
className="underline" className="underline"
> >
docs docs

View File

@@ -30,12 +30,6 @@ export class Config {
throw new Error(`Invalid configuration file: ${errors}`); 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 ( if (
// @ts-ignore // @ts-ignore
parsedConfig.users || parsedConfig.users ||

View File

@@ -287,7 +287,7 @@ export function readConfigFile() {
if (!environment) { if (!environment) {
throw new Error( throw new Error(
"No configuration file found. Please create one. https://docs.fossorial.io/" "No configuration file found. Please create one. https://docs.digpangolin.com/self-host/advanced/config-file"
); );
} }

View File

@@ -35,6 +35,11 @@ export async function verifyApiKeyApiKeyAccess(
); );
} }
if (callerApiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
const [callerApiKeyOrg] = await db const [callerApiKeyOrg] = await db
.select() .select()
.from(apiKeyOrg) .from(apiKeyOrg)

View File

@@ -28,6 +28,11 @@ export async function verifyApiKeyClientAccess(
); );
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
const client = await db const client = await db
.select() .select()
.from(clients) .from(clients)

View File

@@ -27,6 +27,11 @@ export async function verifyApiKeyOrgAccess(
); );
} }
if (req.apiKey?.isRoot) {
// Root keys can access any key in any org
return next();
}
if (!req.apiKeyOrg) { if (!req.apiKeyOrg) {
const apiKeyOrgRes = await db const apiKeyOrgRes = await db
.select() .select()

View File

@@ -37,6 +37,11 @@ export async function verifyApiKeyResourceAccess(
); );
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
if (!resource.orgId) { if (!resource.orgId) {
return next( return next(
createHttpError( createHttpError(

View File

@@ -45,6 +45,11 @@ export async function verifyApiKeyRoleAccess(
); );
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
const orgIds = new Set(rolesData.map((role) => role.orgId)); const orgIds = new Set(rolesData.map((role) => role.orgId));
for (const role of rolesData) { for (const role of rolesData) {

View File

@@ -32,6 +32,11 @@ export async function verifyApiKeySetResourceUsers(
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid user IDs")); return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid user IDs"));
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
if (userIds.length === 0) { if (userIds.length === 0) {
return next(); return next();
} }

View File

@@ -1,9 +1,6 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
import { db } from "@server/db"; import { db } from "@server/db";
import { import { sites, apiKeyOrg } from "@server/db";
sites,
apiKeyOrg
} from "@server/db";
import { and, eq, or } from "drizzle-orm"; import { and, eq, or } from "drizzle-orm";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
@@ -31,6 +28,11 @@ export async function verifyApiKeySiteAccess(
); );
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
const site = await db const site = await db
.select() .select()
.from(sites) .from(sites)

View File

@@ -66,6 +66,11 @@ export async function verifyApiKeyTargetAccess(
); );
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
if (!resource.orgId) { if (!resource.orgId) {
return next( return next(
createHttpError( createHttpError(

View File

@@ -27,6 +27,11 @@ export async function verifyApiKeyUserAccess(
); );
} }
if (apiKey.isRoot) {
// Root keys can access any key in any org
return next();
}
if (!req.apiKeyOrg || !req.apiKeyOrg.orgId) { if (!req.apiKeyOrg || !req.apiKeyOrg.orgId) {
return next( return next(
createHttpError( createHttpError(

View File

@@ -63,15 +63,6 @@ export async function createRootApiKey(
lastChars, lastChars,
isRoot: true isRoot: true
}); });
const allOrgs = await trx.select().from(orgs);
for (const org of allOrgs) {
await trx.insert(apiKeyOrg).values({
apiKeyId,
orgId: org.orgId
});
}
}); });
try { try {

View File

@@ -52,20 +52,26 @@ export async function exchangeSession(
try { try {
const { requestToken, host, requestIp } = parsedBody.data; const { requestToken, host, requestIp } = parsedBody.data;
let cleanHost = host;
// if the host ends with :port
if (cleanHost.match(/:[0-9]{1,5}$/)) {
let matched = ''+cleanHost.match(/:[0-9]{1,5}$/);
cleanHost = cleanHost.slice(0, -1*matched.length);
}
const clientIp = requestIp?.split(":")[0]; const clientIp = requestIp?.split(":")[0];
const [resource] = await db const [resource] = await db
.select() .select()
.from(resources) .from(resources)
.where(eq(resources.fullDomain, host)) .where(eq(resources.fullDomain, cleanHost))
.limit(1); .limit(1);
if (!resource) { if (!resource) {
return next( return next(
createHttpError( createHttpError(
HttpCode.NOT_FOUND, HttpCode.NOT_FOUND,
`Resource with host ${host} not found` `Resource with host ${cleanHost} not found`
) )
); );
} }

View File

@@ -121,11 +121,10 @@ export async function verifyResourceSession(
logger.debug("Client IP:", { clientIp }); logger.debug("Client IP:", { clientIp });
let cleanHost = host; let cleanHost = host;
// if the host ends with :443 or :80 remove it // if the host ends with :port, strip it
if (cleanHost.endsWith(":443")) { if (cleanHost.match(/:[0-9]{1,5}$/)) {
cleanHost = cleanHost.slice(0, -4); let matched = ''+cleanHost.match(/:[0-9]{1,5}$/);
} else if (cleanHost.endsWith(":80")) { cleanHost = cleanHost.slice(0, -1*matched.length);
cleanHost = cleanHost.slice(0, -3);
} }
const resourceCacheKey = `resource:${cleanHost}`; const resourceCacheKey = `resource:${cleanHost}`;

View File

@@ -215,7 +215,7 @@ export async function createOrg(
orgId: newOrg[0].orgId, orgId: newOrg[0].orgId,
roleId: roleId, roleId: roleId,
isOwner: true isOwner: true
}); });
} }
const memberRole = await trx const memberRole = await trx
@@ -234,18 +234,6 @@ export async function createOrg(
orgId orgId
})) }))
); );
const rootApiKeys = await trx
.select()
.from(apiKeys)
.where(eq(apiKeys.isRoot, true));
for (const apiKey of rootApiKeys) {
await trx.insert(apiKeyOrg).values({
apiKeyId: apiKey.apiKeyId,
orgId: newOrg[0].orgId
});
}
}); });
if (!org) { if (!org) {

View File

@@ -78,7 +78,7 @@ export default async function migration() {
fs.writeFileSync(filePath, updatedYaml, "utf8"); fs.writeFileSync(filePath, updatedYaml, "utf8");
} catch (e) { } catch (e) {
console.log( console.log(
`Failed to add resource_session_request_param to config. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config` `Failed to add resource_session_request_param to config. Please add it manually. https://docs.digpangolin.com/self-host/advanced/config-file`
); );
trx.rollback(); trx.rollback();
return; return;

View File

@@ -63,7 +63,7 @@ export default async function migration() {
console.log(`Added new config option: resource_access_token_headers`); console.log(`Added new config option: resource_access_token_headers`);
} catch (e) { } catch (e) {
console.log( console.log(
`Unable to add new config option: resource_access_token_headers. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config` `Unable to add new config option: resource_access_token_headers. Please add it manually. https://docs.digpangolin.com/self-host/advanced/config-file`
); );
console.error(e); console.error(e);
} }

View File

@@ -734,7 +734,7 @@ export default function Page() {
<Link <Link
className="text-sm text-primary flex items-center gap-1" className="text-sm text-primary flex items-center gap-1"
href="https://docs.fossorial.io/Pangolin/tcp-udp" href="https://docs.digpangolin.com/manage/resources/tcp-udp-resources"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >

View File

@@ -64,7 +64,7 @@ export const SitesSplashCard = () => {
<div className="mt-4"> <div className="mt-4">
<Link <Link
href="https://docs.fossorial.io/Newt/install" href="https://docs.digpangolin.com/manage/sites/install-site"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >

View File

@@ -65,7 +65,7 @@ export default function GeneralPage() {
defaultValues: { defaultValues: {
name: site?.name, name: site?.name,
dockerSocketEnabled: site?.dockerSocketEnabled ?? false, dockerSocketEnabled: site?.dockerSocketEnabled ?? false,
remoteSubnets: site?.remoteSubnets remoteSubnets: site?.remoteSubnets
? site.remoteSubnets.split(',').map((subnet, index) => ({ ? site.remoteSubnets.split(',').map((subnet, index) => ({
id: subnet.trim(), id: subnet.trim(),
text: subnet.trim() text: subnet.trim()
@@ -144,7 +144,7 @@ export default function GeneralPage() {
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="remoteSubnets" name="remoteSubnets"
@@ -208,7 +208,7 @@ export default function GeneralPage() {
"enableDockerSocketDescription" "enableDockerSocketDescription"
)}{" "} )}{" "}
<Link <Link
href="https://docs.fossorial.io/Newt/overview#docker-socket-integration" href="https://docs.digpangolin.com/manage/sites/configure-site#docker-socket-integration"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-primary hover:underline inline-flex items-center" className="text-primary hover:underline inline-flex items-center"

View File

@@ -326,7 +326,7 @@ export default function PoliciesPage() {
{/*TODO(vlalx): Validate replacing */} {/*TODO(vlalx): Validate replacing */}
{t('orgPoliciesAboutDescription')}{" "} {t('orgPoliciesAboutDescription')}{" "}
<Link <Link
href="https://docs.fossorial.io/Pangolin/Identity%20Providers/auto-provision" href="https://docs.digpangolin.com/manage/identity-providers/auto-provisioning"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-primary hover:underline" className="text-primary hover:underline"

View File

@@ -59,9 +59,14 @@ export default async function ResourceAuthPage(props: {
try { try {
const serverResourceHost = new URL(authInfo.url).host; const serverResourceHost = new URL(authInfo.url).host;
const redirectHost = new URL(searchParams.redirect).host; const redirectHost = new URL(searchParams.redirect).host;
const redirectPort = new URL(searchParams.redirect).port;
const serverResourceHostWithPort = `${serverResourceHost}:${redirectPort}`;
if (serverResourceHost === redirectHost) { if (serverResourceHost === redirectHost) {
redirectUrl = searchParams.redirect; redirectUrl = searchParams.redirect;
} else if ( serverResourceHostWithPort === redirectHost ) {
redirectUrl = searchParams.redirect;
} }
} catch (e) {} } catch (e) {}
} }

View File

@@ -126,7 +126,7 @@ export function LayoutSidebar({
</div> </div>
<div className="text-xs text-muted-foreground "> <div className="text-xs text-muted-foreground ">
<Link <Link
href="https://docs.fossorial.io/" href="https://docs.digpangolin.com/"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center justify-center gap-1" className="flex items-center justify-center gap-1"

View File

@@ -219,7 +219,7 @@ export default function SupporterStatus({ isCollapsed = false }: SupporterStatus
</Link>{" "} </Link>{" "}
{t('supportKeyPurchase2')}{" "} {t('supportKeyPurchase2')}{" "}
<Link <Link
href="https://docs.fossorial.io/supporter-program" href="https://docs.digpangolin.com/self-host/supporter-program"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="underline" className="underline"

View File

@@ -1,16 +1,36 @@
'use server'; 'use server';
import {cookies} from 'next/headers'; import { cookies, headers } from 'next/headers';
import {Locale, defaultLocale} from '@/i18n/config'; import { Locale, defaultLocale, locales } from '@/i18n/config';
// In this example the locale is read from a cookie. You could alternatively // In this example the locale is read from a cookie. You could alternatively
// also read it from a database, backend service, or any other source. // also read it from a database, backend service, or any other source.
const COOKIE_NAME = 'NEXT_LOCALE'; const COOKIE_NAME = 'NEXT_LOCALE';
export async function getUserLocale() { export async function getUserLocale(): Promise<Locale> {
return (await cookies()).get(COOKIE_NAME)?.value || defaultLocale; const cookieLocale = (await cookies()).get(COOKIE_NAME)?.value;
if (cookieLocale && locales.includes(cookieLocale as Locale)) {
return cookieLocale as Locale;
}
const headerList = await headers();
const acceptLang = headerList.get('accept-language');
if (acceptLang) {
const browserLang = acceptLang.split(',')[0];
const matched = locales.find((locale) =>
browserLang.toLowerCase().startsWith(locale.split('-')[0].toLowerCase())
);
if (matched) {
return matched;
}
}
return defaultLocale;
} }
export async function setUserLocale(locale: Locale) { export async function setUserLocale(locale: Locale) {
(await cookies()).set(COOKIE_NAME, locale); (await cookies()).set(COOKIE_NAME, locale);
} }