mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-11 04:12:26 +00:00
Compare commits
42 Commits
1.11.0
...
1.11.1-s.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5bab6bb80 | ||
|
|
7536c03f63 | ||
|
|
ada5d2ef0e | ||
|
|
b8bead0590 | ||
|
|
68f852d6d1 | ||
|
|
d9fe5a8819 | ||
|
|
346183a23f | ||
|
|
dcfd7f5443 | ||
|
|
e59cd6672b | ||
|
|
7c8c440f67 | ||
|
|
f258c41f15 | ||
|
|
ae4a24f4aa | ||
|
|
476cdcfe86 | ||
|
|
f869df2f65 | ||
|
|
03cfabacd9 | ||
|
|
47ac5875f3 | ||
|
|
f67327358e | ||
|
|
4901823f15 | ||
|
|
5407e3c821 | ||
|
|
1d5cdad8b7 | ||
|
|
cd2424cb77 | ||
|
|
c17efde6bf | ||
|
|
40cd8cdec7 | ||
|
|
6768672a44 | ||
|
|
240c5b005b | ||
|
|
8dde170a35 | ||
|
|
c07abf8ff9 | ||
|
|
e5a436593f | ||
|
|
bb6e093ac6 | ||
|
|
59a334ce24 | ||
|
|
d241dcfb27 | ||
|
|
af263e7913 | ||
|
|
6610e7d405 | ||
|
|
c476e65cf2 | ||
|
|
b69b2eeeb3 | ||
|
|
89dab0917b | ||
|
|
73efdb95ae | ||
|
|
1bcca88614 | ||
|
|
8387571c1d | ||
|
|
1d017f60b4 | ||
|
|
81effda9e8 | ||
|
|
9343906ab1 |
@@ -4,7 +4,7 @@ Contributions are welcome!
|
||||
|
||||
Please see the contribution and local development guide on the docs page before getting started:
|
||||
|
||||
https://docs.digpangolin.com/development/contributing
|
||||
https://docs.pangolin.net/development/contributing
|
||||
|
||||
### Licensing Considerations
|
||||
|
||||
|
||||
22
README.md
22
README.md
@@ -1,6 +1,6 @@
|
||||
<div align="center">
|
||||
<h2>
|
||||
<a href="https://digpangolin.com">
|
||||
<a href="https://pangolin.net/">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="public/logo/word_mark_white.png">
|
||||
<img alt="Pangolin Logo" src="public/logo/word_mark_black.png" width="350">
|
||||
@@ -11,15 +11,15 @@
|
||||
|
||||
<div align="center">
|
||||
<h5>
|
||||
<a href="https://digpangolin.com">
|
||||
<a href="https://pangolin.net/">
|
||||
Website
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://docs.digpangolin.com/">
|
||||
<a href="https://docs.pangolin.net/">
|
||||
Documentation
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="mailto:contact@fossorial.io">
|
||||
<a href="mailto:contact@pangolin.net">
|
||||
Contact Us
|
||||
</a>
|
||||
</h5>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div align="center">
|
||||
|
||||
[](https://discord.gg/HCJR8Xhme4)
|
||||
[](https://digpangolin.com/slack)
|
||||
[](https://pangolin.net/slack)
|
||||
[](https://hub.docker.com/r/fosrl/pangolin)
|
||||

|
||||
[](https://www.youtube.com/@fossorial-app)
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
<p align="center">
|
||||
<strong>
|
||||
Start testing Pangolin at <a href="https://pangolin.fossorial.io/auth/signup">pangolin.fossorial.io</a>
|
||||
Start testing Pangolin at <a href="https://app.pangolin.net/auth/signup">app.pangolin.net</a>
|
||||
</strong>
|
||||
</p>
|
||||
|
||||
@@ -45,7 +45,7 @@ Pangolin is a self-hosted tunneled reverse proxy server with identity and contex
|
||||
|
||||
## Installation
|
||||
|
||||
Check out the [quick install guide](https://docs.digpangolin.com/self-host/quick-install) for how to install and set up Pangolin.
|
||||
Check out the [quick install guide](https://docs.pangolin.net/self-host/quick-install) for how to install and set up Pangolin.
|
||||
|
||||
## Deployment Options
|
||||
|
||||
@@ -53,7 +53,7 @@ Check out the [quick install guide](https://docs.digpangolin.com/self-host/quick
|
||||
|-----------------|--------------|
|
||||
| **Self-Host: Community Edition** | Free, open source, and licensed under AGPL-3. |
|
||||
| **Self-Host: Enterprise Edition** | Licensed under Fossorial Commercial License. Free for personal and hobbyist use, and for businesses earning under \$100K USD annually. |
|
||||
| **Pangolin Cloud** | Fully managed service with instant setup and pay-as-you-go pricing — no infrastructure required. Or, self-host your own [remote node](https://docs.digpangolin.com/manage/remote-node/nodes) and connect to our control plane. |
|
||||
| **Pangolin Cloud** | Fully managed service with instant setup and pay-as-you-go pricing — no infrastructure required. Or, self-host your own [remote node](https://docs.pangolin.net/manage/remote-node/nodes) and connect to our control plane. |
|
||||
|
||||
## Key Features
|
||||
|
||||
@@ -71,17 +71,17 @@ Pangolin packages everything you need for seamless application access and exposu
|
||||
### Check out the docs
|
||||
|
||||
We encourage everyone to read the full documentation first, which is
|
||||
available at [docs.digpangolin.com](https://docs.digpangolin.com). This README provides only a very brief subset of
|
||||
available at [docs.pangolin.net](https://docs.pangolin.net). This README provides only a very brief subset of
|
||||
the docs to illustrate some basic ideas.
|
||||
|
||||
### Sign up and try now
|
||||
|
||||
For Pangolin's managed service, you will first need to create an account at
|
||||
[pangolin.fossorial.io](https://pangolin.fossorial.io). We have a generous free tier to get started.
|
||||
[app.pangolin.net](https://app.pangolin.net). We have a generous free tier to get started.
|
||||
|
||||
## Licensing
|
||||
|
||||
Pangolin is dual licensed under the AGPL-3 and the [Fossorial Commercial License](https://digpangolin.com/fcl.html). For inquiries about commercial licensing, please contact us at [contact@fossorial.io](mailto:contact@fossorial.io).
|
||||
Pangolin is dual licensed under the AGPL-3 and the [Fossorial Commercial License](https://pangolin.net/fcl.html). For inquiries about commercial licensing, please contact us at [contact@pangolin.net](mailto:contact@pangolin.net).
|
||||
|
||||
## Contributions
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
If you discover a security vulnerability, please follow the steps below to responsibly disclose it to us:
|
||||
|
||||
1. **Do not create a public GitHub issue or discussion post.** This could put the security of other users at risk.
|
||||
2. Send a detailed report to [security@fossorial.io](mailto:security@fossorial.io) or send a **private** message to a maintainer on [Discord](https://discord.gg/HCJR8Xhme4). Include:
|
||||
2. Send a detailed report to [security@pangolin.net](mailto:security@pangolin.net) or send a **private** message to a maintainer on [Discord](https://discord.gg/HCJR8Xhme4). Include:
|
||||
|
||||
- Description and location of the vulnerability.
|
||||
- Potential impact of the vulnerability.
|
||||
|
||||
@@ -8,7 +8,7 @@ import base64
|
||||
YAML_FILE_PATH = 'blueprint.yaml'
|
||||
|
||||
# The API endpoint and headers from the curl request
|
||||
API_URL = 'http://api.pangolin.fossorial.io/v1/org/test/blueprint'
|
||||
API_URL = 'http://api.pangolin.net/v1/org/test/blueprint'
|
||||
HEADERS = {
|
||||
'accept': '*/*',
|
||||
'Authorization': 'Bearer <your_token_here>',
|
||||
|
||||
@@ -28,9 +28,9 @@ proxy-resources:
|
||||
# sso-roles:
|
||||
# - Member
|
||||
# sso-users:
|
||||
# - owen@fossorial.io
|
||||
# - owen@pangolin.net
|
||||
# whitelist-users:
|
||||
# - owen@fossorial.io
|
||||
# - owen@pangolin.net
|
||||
headers:
|
||||
- name: X-Example-Header
|
||||
value: example-value
|
||||
|
||||
@@ -12,7 +12,7 @@ post {
|
||||
|
||||
body:json {
|
||||
{
|
||||
"email": "owen@fossorial.io",
|
||||
"email": "owen@pangolin.net",
|
||||
"password": "Password123!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ post {
|
||||
|
||||
body:json {
|
||||
{
|
||||
"email": "milo@fossorial.io"
|
||||
"email": "milo@pangolin.net"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ put {
|
||||
|
||||
body:json {
|
||||
{
|
||||
"email": "numbat@fossorial.io",
|
||||
"email": "numbat@pangolin.net",
|
||||
"password": "Password123!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# To see all available options, please visit the docs:
|
||||
# https://docs.digpangolin.com/self-host/advanced/config-file
|
||||
# https://docs.pangolin.net/self-host/advanced/config-file
|
||||
|
||||
app:
|
||||
dashboard_url: http://localhost:3002
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# To see all available options, please visit the docs:
|
||||
# https://docs.digpangolin.com/
|
||||
# https://docs.pangolin.net/
|
||||
|
||||
gerbil:
|
||||
start_port: 51820
|
||||
@@ -36,4 +36,4 @@ flags:
|
||||
require_email_verification: {{.EnableEmail}}
|
||||
disable_signup_without_invite: true
|
||||
disable_user_create_org: false
|
||||
allow_raw_resources: true
|
||||
allow_raw_resources: true
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Безплатен план",
|
||||
"billingWarningOverLimit": "Предупреждение: Превишили сте една или повече лимити за използване. Вашите сайтове няма да се свържат, докато не промените абонамента си или не коригирате използването.",
|
||||
"billingUsageLimitsOverview": "Преглед на лимитите за използване",
|
||||
"billingMonitorUsage": "Следете използването спрямо конфигурираните лимити. Ако ви е необходимо увеличаване на лимитите, моля, свържете се с нас на support@fossorial.io.",
|
||||
"billingMonitorUsage": "Следете използването спрямо конфигурираните лимити. Ако ви е необходимо увеличаване на лимитите, моля, свържете се с нас на support@pangolin.net.",
|
||||
"billingDataUsage": "Използване на данни",
|
||||
"billingOnlineTime": "Време на работа на сайта",
|
||||
"billingUsers": "Активни потребители",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Volná úroveň",
|
||||
"billingWarningOverLimit": "Upozornění: Překročili jste jeden nebo více omezení používání. Vaše stránky se nepřipojí dokud nezměníte předplatné nebo neupravíte své používání.",
|
||||
"billingUsageLimitsOverview": "Přehled omezení použití",
|
||||
"billingMonitorUsage": "Sledujte vaše využití pomocí nastavených limitů. Pokud potřebujete zvýšit limity, kontaktujte nás prosím support@fossorial.io.",
|
||||
"billingMonitorUsage": "Sledujte vaše využití pomocí nastavených limitů. Pokud potřebujete zvýšit limity, kontaktujte nás prosím support@pangolin.net.",
|
||||
"billingDataUsage": "Využití dat",
|
||||
"billingOnlineTime": "Stránka online čas",
|
||||
"billingUsers": "Aktivní uživatelé",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Kostenlose Stufe",
|
||||
"billingWarningOverLimit": "Warnung: Sie haben ein oder mehrere Nutzungslimits überschritten. Ihre Webseiten werden nicht verbunden, bis Sie Ihr Abonnement ändern oder Ihren Verbrauch anpassen.",
|
||||
"billingUsageLimitsOverview": "Übersicht über Nutzungsgrenzen",
|
||||
"billingMonitorUsage": "Überwachen Sie Ihren Verbrauch im Vergleich zu konfigurierten Grenzwerten. Wenn Sie eine Erhöhung der Limits benötigen, kontaktieren Sie uns bitte support@fossorial.io.",
|
||||
"billingMonitorUsage": "Überwachen Sie Ihren Verbrauch im Vergleich zu konfigurierten Grenzwerten. Wenn Sie eine Erhöhung der Limits benötigen, kontaktieren Sie uns bitte support@pangolin.net.",
|
||||
"billingDataUsage": "Datenverbrauch",
|
||||
"billingOnlineTime": "Online-Zeit der Seite",
|
||||
"billingUsers": "Aktive Benutzer",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -47,9 +47,8 @@
|
||||
"edit": "Edit",
|
||||
"siteConfirmDelete": "Confirm Delete Site",
|
||||
"siteDelete": "Delete Site",
|
||||
"siteMessageRemove": "Once removed, the site will no longer be accessible. All resources and targets associated with the site will also be removed.",
|
||||
"siteMessageConfirm": "To confirm, please type the name of the site below.",
|
||||
"siteQuestionRemove": "Are you sure you want to remove the site {selectedSite} from the organization?",
|
||||
"siteMessageRemove": "Once removed the site will no longer be accessible. All targets associated with the site will also be removed.",
|
||||
"siteQuestionRemove": "Are you sure you want to remove the site from the organization?",
|
||||
"siteManageSites": "Manage Sites",
|
||||
"siteDescription": "Allow connectivity to your network through secure tunnels",
|
||||
"siteCreate": "Create Site",
|
||||
@@ -154,8 +153,7 @@
|
||||
"protected": "Protected",
|
||||
"notProtected": "Not Protected",
|
||||
"resourceMessageRemove": "Once removed, the resource will no longer be accessible. All targets associated with the resource will also be removed.",
|
||||
"resourceMessageConfirm": "To confirm, please type the name of the resource below.",
|
||||
"resourceQuestionRemove": "Are you sure you want to remove the resource {selectedResource} from the organization?",
|
||||
"resourceQuestionRemove": "Are you sure you want to remove the resource from the organization?",
|
||||
"resourceHTTP": "HTTPS Resource",
|
||||
"resourceHTTPDescription": "Proxy requests to your app over HTTPS using a subdomain or base domain.",
|
||||
"resourceRaw": "Raw TCP/UDP Resource",
|
||||
@@ -220,7 +218,7 @@
|
||||
"orgDeleteConfirm": "Confirm Delete Organization",
|
||||
"orgMessageRemove": "This action is irreversible and will delete all associated data.",
|
||||
"orgMessageConfirm": "To confirm, please type the name of the organization below.",
|
||||
"orgQuestionRemove": "Are you sure you want to remove the organization {selectedOrg}?",
|
||||
"orgQuestionRemove": "Are you sure you want to remove the organization?",
|
||||
"orgUpdated": "Organization updated",
|
||||
"orgUpdatedDescription": "The organization has been updated.",
|
||||
"orgErrorUpdate": "Failed to update organization",
|
||||
@@ -287,9 +285,8 @@
|
||||
"apiKeysAdd": "Generate API Key",
|
||||
"apiKeysErrorDelete": "Error deleting API key",
|
||||
"apiKeysErrorDeleteMessage": "Error deleting API key",
|
||||
"apiKeysQuestionRemove": "Are you sure you want to remove the API key {selectedApiKey} from the organization?",
|
||||
"apiKeysQuestionRemove": "Are you sure you want to remove the API key from the organization?",
|
||||
"apiKeysMessageRemove": "Once removed, the API key will no longer be able to be used.",
|
||||
"apiKeysMessageConfirm": "To confirm, please type the name of the API key below.",
|
||||
"apiKeysDeleteConfirm": "Confirm Delete API Key",
|
||||
"apiKeysDelete": "Delete API Key",
|
||||
"apiKeysManage": "Manage API Keys",
|
||||
@@ -305,8 +302,7 @@
|
||||
"userDeleteConfirm": "Confirm Delete User",
|
||||
"userDeleteServer": "Delete User from Server",
|
||||
"userMessageRemove": "The user will be removed from all organizations and be completely removed from the server.",
|
||||
"userMessageConfirm": "To confirm, please type the name of the user below.",
|
||||
"userQuestionRemove": "Are you sure you want to permanently delete {selectedUser} from the server?",
|
||||
"userQuestionRemove": "Are you sure you want to permanently delete user from the server?",
|
||||
"licenseKey": "License Key",
|
||||
"valid": "Valid",
|
||||
"numberOfSites": "Number of Sites",
|
||||
@@ -339,7 +335,7 @@
|
||||
"fossorialLicense": "View Fossorial Commercial License & Subscription Terms",
|
||||
"licenseMessageRemove": "This will remove the license key and all associated permissions granted by it.",
|
||||
"licenseMessageConfirm": "To confirm, please type the license key below.",
|
||||
"licenseQuestionRemove": "Are you sure you want to delete the license key {selectedKey} ?",
|
||||
"licenseQuestionRemove": "Are you sure you want to delete the license key ?",
|
||||
"licenseKeyDelete": "Delete License Key",
|
||||
"licenseKeyDeleteConfirm": "Confirm Delete License Key",
|
||||
"licenseTitle": "Manage License Status",
|
||||
@@ -372,7 +368,7 @@
|
||||
"inviteRemoveErrorDescription": "An error occurred while removing the invitation.",
|
||||
"inviteRemoved": "Invitation removed",
|
||||
"inviteRemovedDescription": "The invitation for {email} has been removed.",
|
||||
"inviteQuestionRemove": "Are you sure you want to remove the invitation {email}?",
|
||||
"inviteQuestionRemove": "Are you sure you want to remove the invitation?",
|
||||
"inviteMessageRemove": "Once removed, this invitation will no longer be valid. You can always re-invite the user later.",
|
||||
"inviteMessageConfirm": "To confirm, please type the email address of the invitation below.",
|
||||
"inviteQuestionRegenerate": "Are you sure you want to regenerate the invitation for {email}? This will revoke the previous invitation.",
|
||||
@@ -398,9 +394,8 @@
|
||||
"userErrorOrgRemoveDescription": "An error occurred while removing the user.",
|
||||
"userOrgRemoved": "User removed",
|
||||
"userOrgRemovedDescription": "The user {email} has been removed from the organization.",
|
||||
"userQuestionOrgRemove": "Are you sure you want to remove {email} from the organization?",
|
||||
"userQuestionOrgRemove": "Are you sure you want to remove this user from the organization?",
|
||||
"userMessageOrgRemove": "Once removed, this user will no longer have access to the organization. You can always re-invite them later, but they will need to accept the invitation again.",
|
||||
"userMessageOrgConfirm": "To confirm, please type the name of the of the user below.",
|
||||
"userRemoveOrgConfirm": "Confirm Remove User",
|
||||
"userRemoveOrg": "Remove User from Organization",
|
||||
"users": "Users",
|
||||
@@ -742,7 +737,7 @@
|
||||
"idpManageDescription": "View and manage identity providers in the system",
|
||||
"idpDeletedDescription": "Identity provider deleted successfully",
|
||||
"idpOidc": "OAuth2/OIDC",
|
||||
"idpQuestionRemove": "Are you sure you want to permanently delete the identity provider {name}?",
|
||||
"idpQuestionRemove": "Are you sure you want to permanently delete the identity provider?",
|
||||
"idpMessageRemove": "This will remove the identity provider and all associated configurations. Users who authenticate through this provider will no longer be able to log in.",
|
||||
"idpMessageConfirm": "To confirm, please type the name of the identity provider below.",
|
||||
"idpConfirmDelete": "Confirm Delete Identity Provider",
|
||||
@@ -1211,9 +1206,8 @@
|
||||
"domainCreate": "Create Domain",
|
||||
"domainCreatedDescription": "Domain created successfully",
|
||||
"domainDeletedDescription": "Domain deleted successfully",
|
||||
"domainQuestionRemove": "Are you sure you want to remove the domain {domain} from your account?",
|
||||
"domainQuestionRemove": "Are you sure you want to remove the domain from your account?",
|
||||
"domainMessageRemove": "Once removed, the domain will no longer be associated with your account.",
|
||||
"domainMessageConfirm": "To confirm, please type the domain name below.",
|
||||
"domainConfirmDelete": "Confirm Delete Domain",
|
||||
"domainDelete": "Delete Domain",
|
||||
"domain": "Domain",
|
||||
@@ -1280,7 +1274,7 @@
|
||||
"billingFreeTier": "Free Tier",
|
||||
"billingWarningOverLimit": "Warning: You have exceeded one or more usage limits. Your sites will not connect until you modify your subscription or adjust your usage.",
|
||||
"billingUsageLimitsOverview": "Usage Limits Overview",
|
||||
"billingMonitorUsage": "Monitor your usage against configured limits. If you need limits increased please contact us support@fossorial.io.",
|
||||
"billingMonitorUsage": "Monitor your usage against configured limits. If you need limits increased please contact us support@pangolin.net.",
|
||||
"billingDataUsage": "Data Usage",
|
||||
"billingOnlineTime": "Site Online Time",
|
||||
"billingUsers": "Active Users",
|
||||
@@ -1563,9 +1557,8 @@
|
||||
"searchRemoteExitNodes": "Search nodes...",
|
||||
"remoteExitNodeAdd": "Add Node",
|
||||
"remoteExitNodeErrorDelete": "Error deleting node",
|
||||
"remoteExitNodeQuestionRemove": "Are you sure you want to remove the node {selectedNode} from the organization?",
|
||||
"remoteExitNodeQuestionRemove": "Are you sure you want to remove the node from the organization?",
|
||||
"remoteExitNodeMessageRemove": "Once removed, the node will no longer be accessible.",
|
||||
"remoteExitNodeMessageConfirm": "To confirm, please type the name of the node below.",
|
||||
"remoteExitNodeConfirmDelete": "Confirm Delete Node",
|
||||
"remoteExitNodeDelete": "Delete Node",
|
||||
"sidebarRemoteExitNodes": "Remote Nodes",
|
||||
@@ -1819,7 +1812,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
@@ -1894,5 +1887,9 @@
|
||||
"pathRewriteRegex": "Regex",
|
||||
"pathRewriteStrip": "Strip",
|
||||
"pathRewriteStripLabel": "strip",
|
||||
"sidebarEnableEnterpriseLicense": "Enable Enterprise License"
|
||||
"sidebarEnableEnterpriseLicense": "Enable Enterprise License",
|
||||
"cannotbeUndone": "This can not be undone.",
|
||||
"toConfirm": "to confirm",
|
||||
"deleteClientQuestion": "Are you sure you want to remove the client from the site and organization?",
|
||||
"clientMessageRemove": "Once removed, the client will no longer be able to connect to the site."
|
||||
}
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Nivel Gratis",
|
||||
"billingWarningOverLimit": "Advertencia: Has excedido uno o más límites de uso. Tus sitios no se conectarán hasta que modifiques tu suscripción o ajustes tu uso.",
|
||||
"billingUsageLimitsOverview": "Descripción general de los límites de uso",
|
||||
"billingMonitorUsage": "Monitorea tu uso comparado con los límites configurados. Si necesitas que aumenten los límites, contáctanos a soporte@fossorial.io.",
|
||||
"billingMonitorUsage": "Monitorea tu uso comparado con los límites configurados. Si necesitas que aumenten los límites, contáctanos a soporte@pangolin.net.",
|
||||
"billingDataUsage": "Uso de datos",
|
||||
"billingOnlineTime": "Tiempo en línea del sitio",
|
||||
"billingUsers": "Usuarios activos",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -6,45 +6,45 @@
|
||||
"setupOrgName": "Nom de l'organisation",
|
||||
"orgDisplayName": "Ceci est le nom d'affichage de votre organisation.",
|
||||
"orgId": "ID de l'organisation",
|
||||
"setupIdentifierMessage": "Ceci est l'identifiant unique pour votre organisation. Il est séparé du nom affiché.",
|
||||
"setupErrorIdentifier": "L'ID de l'organisation est déjà pris. Veuillez en choisir un autre.",
|
||||
"setupIdentifierMessage": "Ceci est l'identifiant de votre organisation. Il est différent du nom affiché.",
|
||||
"setupErrorIdentifier": "Cet identifiant est déjà pris. Veuillez en choisir un autre.",
|
||||
"componentsErrorNoMemberCreate": "Vous n'êtes actuellement membre d'aucune organisation. Créez une organisation pour commencer.",
|
||||
"componentsErrorNoMember": "Vous n'êtes actuellement membre d'aucune organisation.",
|
||||
"welcome": "Bienvenue à Pangolin",
|
||||
"welcome": "Bienvenue sur Pangolin",
|
||||
"welcomeTo": "Bienvenue chez",
|
||||
"componentsCreateOrg": "Créer une organisation",
|
||||
"componentsMember": "Vous êtes membre de {count, plural, =0 {aucune organisation} one {une organisation} other {# organisations}}.",
|
||||
"componentsMember": "Vous {count, plural, =0 {n'} other {}}êtes membre {count, plural, =0 {d'aucune organisation} one {d'une organisation} other {de # organisations}}.",
|
||||
"componentsInvalidKey": "Clés de licence invalides ou expirées détectées. Suivez les conditions de licence pour continuer à utiliser toutes les fonctionnalités.",
|
||||
"dismiss": "Refuser",
|
||||
"componentsLicenseViolation": "Violation de licence : Ce serveur utilise des sites {usedSites} qui dépassent la limite autorisée des sites {maxSites} . Suivez les conditions de licence pour continuer à utiliser toutes les fonctionnalités.",
|
||||
"componentsSupporterMessage": "Merci de soutenir Pangolin en tant que {tier}!",
|
||||
"inviteErrorNotValid": "Nous sommes désolés, mais il semble que l'invitation que vous essayez d'accéder n'ait pas été acceptée ou n'est plus valide.",
|
||||
"inviteErrorUser": "Nous sommes désolés, mais il semble que l'invitation que vous essayez d'accéder ne soit pas pour cet utilisateur.",
|
||||
"inviteLoginUser": "Assurez-vous que vous êtes bien connecté en tant qu'utilisateur correct.",
|
||||
"inviteErrorNoUser": "Nous sommes désolés, mais il semble que l'invitation que vous essayez d'accéder ne soit pas pour un utilisateur qui existe.",
|
||||
"inviteCreateUser": "Veuillez d'abord créer un compte.",
|
||||
"goHome": "Retour à la maison",
|
||||
"inviteErrorNotValid": "Nous sommes désolés, mais il semble que l'invitation via laquelle vous essayez d'accéder n'ait pas été acceptée ou n'est plus valide.",
|
||||
"inviteErrorUser": "Nous sommes désolés, mais il semble que l'invitation via laquelle vous essayez d'accéder ne soit pas pour cet utilisateur.",
|
||||
"inviteLoginUser": "Assurez-vous d'etre bien connecté au bon compte.",
|
||||
"inviteErrorNoUser": "Nous sommes désolés, mais il semble que l'invitation via laquelle vous essayez d'accéder ne soit pas pour un utilisateur qui existe.",
|
||||
"inviteCreateUser": "Vous n'avez aucun compte, veuillez en créer un.",
|
||||
"goHome": "Retour à l'accueil",
|
||||
"inviteLogInOtherUser": "Se connecter en tant qu'utilisateur différent",
|
||||
"createAnAccount": "Créer un compte",
|
||||
"inviteNotAccepted": "Invitation non acceptée",
|
||||
"authCreateAccount": "Créez un compte pour commencer",
|
||||
"authNoAccount": "Vous n'avez pas de compte ?",
|
||||
"email": "Courriel",
|
||||
"email": "Adresse email",
|
||||
"password": "Mot de passe",
|
||||
"confirmPassword": "Confirmer le mot de passe",
|
||||
"createAccount": "Créer un compte",
|
||||
"viewSettings": "Afficher les paramètres",
|
||||
"delete": "Supprimez",
|
||||
"delete": "Supprimer",
|
||||
"name": "Nom",
|
||||
"online": "En ligne",
|
||||
"offline": "Hors ligne",
|
||||
"site": "Site",
|
||||
"dataIn": "Données dans",
|
||||
"dataOut": "Données épuisées",
|
||||
"dataIn": "Données reçues",
|
||||
"dataOut": "Données émises",
|
||||
"connectionType": "Type de connexion",
|
||||
"tunnelType": "Type de tunnel",
|
||||
"local": "Locale",
|
||||
"edit": "Editer",
|
||||
"edit": "Modifier",
|
||||
"siteConfirmDelete": "Confirmer la suppression du site",
|
||||
"siteDelete": "Supprimer le site",
|
||||
"siteMessageRemove": "Une fois supprimé, le site ne sera plus accessible. Toutes les ressources et cibles associées au site seront également supprimées.",
|
||||
@@ -64,11 +64,11 @@
|
||||
"siteLearnNewt": "Apprenez à installer Newt sur votre système",
|
||||
"siteSeeConfigOnce": "Vous ne pourrez voir la configuration qu'une seule fois.",
|
||||
"siteLoadWGConfig": "Chargement de la configuration WireGuard...",
|
||||
"siteDocker": "Développer les détails du déploiement Docker",
|
||||
"siteDocker": "Afficher les détails du déploiement Docker",
|
||||
"toggle": "Activer/désactiver",
|
||||
"dockerCompose": "Composition Docker",
|
||||
"dockerRun": "Exécution Docker",
|
||||
"siteLearnLocal": "Les sites locaux ne tunnel, en savoir plus",
|
||||
"dockerCompose": "Docker Compose",
|
||||
"dockerRun": "Docker Run",
|
||||
"siteLearnLocal": "Les sites locaux ne permettent pas d'utiliser les tunnel, en savoir plus",
|
||||
"siteConfirmCopy": "J'ai copié la configuration",
|
||||
"searchSitesProgress": "Rechercher des sites...",
|
||||
"siteAdd": "Ajouter un site",
|
||||
@@ -79,9 +79,9 @@
|
||||
"operatingSystem": "Système d'exploitation",
|
||||
"commands": "Commandes",
|
||||
"recommended": "Recommandé",
|
||||
"siteNewtDescription": "Pour une meilleure expérience d'utilisateur, utilisez Newt. Il utilise WireGuard sous le capot et vous permet d'adresser vos ressources privées par leur adresse LAN sur votre réseau privé à partir du tableau de bord Pangolin.",
|
||||
"siteRunsInDocker": "Exécute dans Docker",
|
||||
"siteRunsInShell": "Exécute en shell sur macOS, Linux et Windows",
|
||||
"siteNewtDescription": "Pour une meilleure expérience d'utilisateur, utilisez Newt. Newt se base sur WireGuard et vous permet d'adresser vos ressources privées par leur adresse LAN sur votre réseau privé à partir du tableau de bord Pangolin.",
|
||||
"siteRunsInDocker": "S'exécute dans Docker",
|
||||
"siteRunsInShell": "S'exécute en shell sur macOS, Linux et Windows",
|
||||
"siteErrorDelete": "Erreur lors de la suppression du site",
|
||||
"siteErrorUpdate": "Impossible de mettre à jour le site",
|
||||
"siteErrorUpdateDescription": "Une erreur s'est produite lors de la mise à jour du site.",
|
||||
@@ -89,18 +89,18 @@
|
||||
"siteUpdatedDescription": "Le site a été mis à jour.",
|
||||
"siteGeneralDescription": "Configurer les paramètres généraux de ce site",
|
||||
"siteSettingDescription": "Configurer les paramètres de votre site",
|
||||
"siteSetting": "Réglages {siteName}",
|
||||
"siteSetting": "Réglages de {siteName}",
|
||||
"siteNewtTunnel": "Tunnel Newt (Recommandé)",
|
||||
"siteNewtTunnelDescription": "La façon la plus simple de créer un point d'entrée dans votre réseau. Pas de configuration supplémentaire.",
|
||||
"siteWg": "WireGuard basique",
|
||||
"siteWgDescription": "Utilisez n'importe quel client WireGuard pour établir un tunnel. Configuration NAT manuelle requise.",
|
||||
"siteWgDescriptionSaas": "Utilisez n'importe quel client WireGuard pour établir un tunnel. Configuration NAT manuelle requise. FONCTIONNE UNIQUEMENT SUR DES NŒUDS AUTONOMES",
|
||||
"siteLocalDescription": "Ressources locales seulement. Pas de tunneling.",
|
||||
"siteLocalDescriptionSaas": "Local resources only. No tunneling. Only available on remote nodes.",
|
||||
"siteLocalDescriptionSaas": "Ressources locales seulement. Pas de tunneling. Seulement disponible sur les noeuds distants",
|
||||
"siteSeeAll": "Voir tous les sites",
|
||||
"siteTunnelDescription": "Déterminez comment vous voulez vous connecter à votre site",
|
||||
"siteNewtCredentials": "Identifiants Newt",
|
||||
"siteNewtCredentialsDescription": "C'est ainsi que Newt s'authentifiera avec le serveur",
|
||||
"siteNewtCredentialsDescription": "C'est comme cela que Newt s'authentifiera avec le serveur",
|
||||
"siteCredentialsSave": "Enregistrez vos identifiants",
|
||||
"siteCredentialsSaveDescription": "Vous ne pourrez voir cela qu'une seule fois. Assurez-vous de le copier dans un endroit sécurisé.",
|
||||
"siteInfo": "Informations sur le site",
|
||||
@@ -112,7 +112,7 @@
|
||||
"shareErrorDelete": "Impossible de supprimer le lien",
|
||||
"shareErrorDeleteMessage": "Une erreur s'est produite lors de la suppression du lien",
|
||||
"shareDeleted": "Lien supprimé",
|
||||
"shareDeletedDescription": "Le lien a été supprimé",
|
||||
"shareDeletedDescription": "Le lien de partage a été supprimé",
|
||||
"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",
|
||||
@@ -134,7 +134,7 @@
|
||||
"shareExpireDescription": "Le temps d'expiration est combien de temps le lien sera utilisable et fournira un accès à la ressource. Après cette période, le lien ne fonctionnera plus et les utilisateurs qui ont utilisé ce lien perdront l'accès à la ressource.",
|
||||
"shareSeeOnce": "Vous ne pourrez voir ce lien. Assurez-vous de le copier.",
|
||||
"shareAccessHint": "N'importe qui avec ce lien peut accéder à la ressource. Partagez-le avec soin.",
|
||||
"shareTokenUsage": "Voir Utilisation du jeton d'accès",
|
||||
"shareTokenUsage": "Voir l'utilisation du jeton d'accès",
|
||||
"createLink": "Créer un lien",
|
||||
"resourcesNotFound": "Aucune ressource trouvée",
|
||||
"resourceSearch": "Rechercher des ressources",
|
||||
@@ -1234,7 +1234,7 @@
|
||||
"billing": "Facturation",
|
||||
"orgBillingDescription": "Gérez vos informations de facturation et vos abonnements",
|
||||
"github": "GitHub",
|
||||
"pangolinHosted": "Pangolin Hébergement",
|
||||
"pangolinHosted": "Hebergé par Pangolin",
|
||||
"fossorial": "Fossorial",
|
||||
"completeAccountSetup": "Complétez la configuration du compte",
|
||||
"completeAccountSetupDescription": "Définissez votre mot de passe pour commencer",
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Niveau gratuit",
|
||||
"billingWarningOverLimit": "Attention : Vous avez dépassé une ou plusieurs limites d'utilisation. Vos sites ne se connecteront pas tant que vous n'avez pas modifié votre abonnement ou ajusté votre utilisation.",
|
||||
"billingUsageLimitsOverview": "Vue d'ensemble des limites d'utilisation",
|
||||
"billingMonitorUsage": "Surveillez votre consommation par rapport aux limites configurées. Si vous avez besoin d'une augmentation des limites, veuillez nous contacter à support@fossorial.io.",
|
||||
"billingMonitorUsage": "Surveillez votre consommation par rapport aux limites configurées. Si vous avez besoin d'une augmentation des limites, veuillez nous contacter à support@pangolin.net.",
|
||||
"billingDataUsage": "Utilisation des données",
|
||||
"billingOnlineTime": "Temps en ligne du site",
|
||||
"billingUsers": "Utilisateurs actifs",
|
||||
@@ -1316,7 +1316,7 @@
|
||||
"billingRemoteExitNodesInfo": "Vous êtes facturé pour chaque nœud géré dans votre organisation. La facturation est calculée quotidiennement en fonction du nombre de nœuds gérés actifs dans votre organisation.",
|
||||
"domainNotFound": "Domaine introuvable",
|
||||
"domainNotFoundDescription": "Cette ressource est désactivée car le domaine n'existe plus dans notre système. Veuillez définir un nouveau domaine pour cette ressource.",
|
||||
"failed": "Échec",
|
||||
"failed": "Erreur",
|
||||
"createNewOrgDescription": "Créer une nouvelle organisation",
|
||||
"organization": "Organisation",
|
||||
"port": "Port",
|
||||
@@ -1370,7 +1370,7 @@
|
||||
"createDomainARecords": "Enregistrements A",
|
||||
"createDomainRecordNumber": "Enregistrement {number}",
|
||||
"createDomainTxtRecords": "Enregistrements TXT",
|
||||
"createDomainSaveTheseRecords": "Enregistrez ces enregistrements",
|
||||
"createDomainSaveTheseRecords": "Sauvegardez ces enregistrements",
|
||||
"createDomainSaveTheseRecordsDescription": "Assurez-vous de sauvegarder ces enregistrements DNS car vous ne les reverrez pas.",
|
||||
"createDomainDnsPropagation": "Propagation DNS",
|
||||
"createDomainDnsPropagationDescription": "Les modifications DNS peuvent mettre du temps à se propager sur internet. Cela peut prendre de quelques minutes à 48 heures selon votre fournisseur DNS et les réglages TTL.",
|
||||
@@ -1445,7 +1445,7 @@
|
||||
"IntervalSeconds": "Intervalle sain",
|
||||
"timeoutSeconds": "Délai",
|
||||
"timeIsInSeconds": "Le temps est exprimé en secondes",
|
||||
"retryAttempts": "Tentatives de réessai",
|
||||
"retryAttempts": "Tentatives",
|
||||
"expectedResponseCodes": "Codes de réponse attendus",
|
||||
"expectedResponseCodesDescription": "Code de statut HTTP indiquant un état de santé satisfaisant. Si non renseigné, 200-300 est considéré comme satisfaisant.",
|
||||
"customHeaders": "En-têtes personnalisés",
|
||||
@@ -1760,9 +1760,9 @@
|
||||
"enterpriseEdition": "Enterprise Edition",
|
||||
"unlicensed": "Unlicensed",
|
||||
"beta": "Beta",
|
||||
"manageClients": "Manage Clients",
|
||||
"manageClients": "Gérer les clients",
|
||||
"manageClientsDescription": "Clients are devices that can connect to your sites",
|
||||
"licenseTableValidUntil": "Valid Until",
|
||||
"licenseTableValidUntil": "Valide jusqu'au",
|
||||
"saasLicenseKeysSettingsTitle": "Enterprise Licenses",
|
||||
"saasLicenseKeysSettingsDescription": "Generate and manage Enterprise license keys for self-hosted Pangolin instances",
|
||||
"sidebarEnterpriseLicenses": "Licenses",
|
||||
@@ -1771,8 +1771,8 @@
|
||||
"validation": {
|
||||
"emailRequired": "Please enter a valid email address",
|
||||
"useCaseTypeRequired": "Please select a use case type",
|
||||
"firstNameRequired": "First name is required",
|
||||
"lastNameRequired": "Last name is required",
|
||||
"firstNameRequired": "Le prénom est requis",
|
||||
"lastNameRequired": "Le nom est requis",
|
||||
"primaryUseRequired": "Please describe your primary use",
|
||||
"jobTitleRequiredBusiness": "Job title is required for business use",
|
||||
"industryRequiredBusiness": "Industry is required for business use",
|
||||
@@ -1786,7 +1786,7 @@
|
||||
},
|
||||
"useCaseOptions": {
|
||||
"personal": {
|
||||
"title": "Personal Use",
|
||||
"title": "Utilisation personelle",
|
||||
"description": "For individual, non-commercial use such as learning, personal projects, or experimentation."
|
||||
},
|
||||
"business": {
|
||||
@@ -1819,32 +1819,32 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
"useCaseQuestion": "Are you using Pangolin for personal or business use?",
|
||||
"firstName": "First Name",
|
||||
"lastName": "Last Name",
|
||||
"jobTitle": "Job Title",
|
||||
"firstName": "Prénom",
|
||||
"lastName": "Nom",
|
||||
"jobTitle": "profession",
|
||||
"primaryUseQuestion": "What do you primarily plan to use Pangolin for?",
|
||||
"industryQuestion": "What is your industry?",
|
||||
"prospectiveUsersQuestion": "How many prospective users do you expect to have?",
|
||||
"prospectiveSitesQuestion": "How many prospective sites (tunnels) do you expect to have?",
|
||||
"companyName": "Company name",
|
||||
"countryOfResidence": "Country of residence",
|
||||
"stateProvinceRegion": "State / Province / Region",
|
||||
"postalZipCode": "Postal / ZIP Code",
|
||||
"companyWebsite": "Company website",
|
||||
"companyPhoneNumber": "Company phone number",
|
||||
"country": "Country",
|
||||
"phoneNumberOptional": "Phone number (optional)",
|
||||
"companyName": "Entreprise",
|
||||
"countryOfResidence": "Pays de résidence",
|
||||
"stateProvinceRegion": "État / Province / Région",
|
||||
"postalZipCode": "Code postal",
|
||||
"companyWebsite": "Site de l'entreprise",
|
||||
"companyPhoneNumber": "Numéro de téléphone professionnel",
|
||||
"country": "Pays",
|
||||
"phoneNumberOptional": "Numéro de téléphone (optionnel)",
|
||||
"complianceConfirmation": "I confirm that I am in compliance with the Fossorial Commercial License and that reporting inaccurate information or misidentifying use of the product is a violation of the license."
|
||||
},
|
||||
"buttons": {
|
||||
"close": "Close",
|
||||
"previous": "Previous",
|
||||
"next": "Next",
|
||||
"close": "Fermer",
|
||||
"previous": "Précédent",
|
||||
"next": "Suivant",
|
||||
"generateLicenseKey": "Generate License Key"
|
||||
},
|
||||
"toasts": {
|
||||
@@ -1860,16 +1860,16 @@
|
||||
},
|
||||
"priority": "Priorité",
|
||||
"priorityDescription": "Les routes de haute priorité sont évaluées en premier. La priorité = 100 signifie l'ordre automatique (décision du système). Utilisez un autre nombre pour imposer la priorité manuelle.",
|
||||
"instanceName": "Instance Name",
|
||||
"instanceName": "Nom de l'instance",
|
||||
"pathMatchModalTitle": "Configure Path Matching",
|
||||
"pathMatchModalDescription": "Set up how incoming requests should be matched based on their path.",
|
||||
"pathMatchType": "Match Type",
|
||||
"pathMatchPrefix": "Prefix",
|
||||
"pathMatchPrefix": "Préfix",
|
||||
"pathMatchExact": "Exact",
|
||||
"pathMatchRegex": "Regex",
|
||||
"pathMatchValue": "Path Value",
|
||||
"clear": "Clear",
|
||||
"saveChanges": "Save Changes",
|
||||
"saveChanges": "Sauvegarder",
|
||||
"pathMatchRegexPlaceholder": "^/api/.*",
|
||||
"pathMatchDefaultPlaceholder": "/path",
|
||||
"pathMatchPrefixHelp": "Example: /api matches /api, /api/users, etc.",
|
||||
@@ -1889,7 +1889,7 @@
|
||||
"pathRewriteExactHelp": "Replace the entire path with this value when the path matches exactly",
|
||||
"pathRewriteRegexHelp": "Use capture groups like $1, $2 for replacement",
|
||||
"pathRewriteStripPrefixHelp": "Leave empty to strip prefix or provide new prefix",
|
||||
"pathRewritePrefix": "Prefix",
|
||||
"pathRewritePrefix": "Préfix",
|
||||
"pathRewriteExact": "Exact",
|
||||
"pathRewriteRegex": "Regex",
|
||||
"pathRewriteStrip": "Strip",
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Piano Gratuito",
|
||||
"billingWarningOverLimit": "Avviso: Hai superato uno o più limiti di utilizzo. I tuoi siti non si connetteranno finché non modifichi il tuo abbonamento o non adegui il tuo utilizzo.",
|
||||
"billingUsageLimitsOverview": "Panoramica dei Limiti di Utilizzo",
|
||||
"billingMonitorUsage": "Monitora il tuo utilizzo rispetto ai limiti configurati. Se hai bisogno di aumentare i limiti, contattaci all'indirizzo support@fossorial.io.",
|
||||
"billingMonitorUsage": "Monitora il tuo utilizzo rispetto ai limiti configurati. Se hai bisogno di aumentare i limiti, contattaci all'indirizzo support@pangolin.net.",
|
||||
"billingDataUsage": "Utilizzo dei Dati",
|
||||
"billingOnlineTime": "Tempo Online del Sito",
|
||||
"billingUsers": "Utenti Attivi",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "무료 티어",
|
||||
"billingWarningOverLimit": "경고: 하나 이상의 사용 한도를 초과했습니다. 구독을 수정하거나 사용량을 조정하기 전까지 사이트는 연결되지 않습니다.",
|
||||
"billingUsageLimitsOverview": "사용 한도 개요",
|
||||
"billingMonitorUsage": "설정된 한도에 대한 사용량을 모니터링합니다. 한도를 늘려야 하는 경우 support@fossorial.io로 연락하십시오.",
|
||||
"billingMonitorUsage": "설정된 한도에 대한 사용량을 모니터링합니다. 한도를 늘려야 하는 경우 support@pangolin.net로 연락하십시오.",
|
||||
"billingDataUsage": "데이터 사용량",
|
||||
"billingOnlineTime": "사이트 온라인 시간",
|
||||
"billingUsers": "활성 사용자",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Gratis nivå",
|
||||
"billingWarningOverLimit": "Advarsel: Du har overskredet en eller flere bruksgrenser. Nettstedene dine vil ikke koble til før du endrer abonnementet ditt eller justerer bruken.",
|
||||
"billingUsageLimitsOverview": "Oversikt over bruksgrenser",
|
||||
"billingMonitorUsage": "Overvåk bruken din i forhold til konfigurerte grenser. Hvis du trenger økte grenser, vennligst kontakt support@fossorial.io.",
|
||||
"billingMonitorUsage": "Overvåk bruken din i forhold til konfigurerte grenser. Hvis du trenger økte grenser, vennligst kontakt support@pangolin.net.",
|
||||
"billingDataUsage": "Databruk",
|
||||
"billingOnlineTime": "Online tid for nettsteder",
|
||||
"billingUsers": "Aktive brukere",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Gratis Niveau",
|
||||
"billingWarningOverLimit": "Waarschuwing: U hebt een of meer gebruikslimieten overschreden. Uw sites maken geen verbinding totdat u uw abonnement aanpast of uw gebruik aanpast.",
|
||||
"billingUsageLimitsOverview": "Overzicht gebruikslimieten",
|
||||
"billingMonitorUsage": "Houd uw gebruik in de gaten ten opzichte van de ingestelde limieten. Als u verhoogde limieten nodig heeft, neem dan contact met ons op support@fossorial.io.",
|
||||
"billingMonitorUsage": "Houd uw gebruik in de gaten ten opzichte van de ingestelde limieten. Als u verhoogde limieten nodig heeft, neem dan contact met ons op support@pangolin.net.",
|
||||
"billingDataUsage": "Gegevensgebruik",
|
||||
"billingOnlineTime": "Site Online Tijd",
|
||||
"billingUsers": "Actieve Gebruikers",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Darmowy pakiet",
|
||||
"billingWarningOverLimit": "Ostrzeżenie: Przekroczyłeś jeden lub więcej limitów użytkowania. Twoje witryny nie połączą się, dopóki nie zmienisz subskrypcji lub nie dostosujesz użytkowania.",
|
||||
"billingUsageLimitsOverview": "Przegląd Limitów Użytkowania",
|
||||
"billingMonitorUsage": "Monitoruj swoje wykorzystanie w porównaniu do skonfigurowanych limitów. Jeśli potrzebujesz zwiększenia limitów, skontaktuj się z nami pod adresem support@fossorial.io.",
|
||||
"billingMonitorUsage": "Monitoruj swoje wykorzystanie w porównaniu do skonfigurowanych limitów. Jeśli potrzebujesz zwiększenia limitów, skontaktuj się z nami pod adresem support@pangolin.net.",
|
||||
"billingDataUsage": "Użycie danych",
|
||||
"billingOnlineTime": "Czas Online Strony",
|
||||
"billingUsers": "Aktywni użytkownicy",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Plano Gratuito",
|
||||
"billingWarningOverLimit": "Aviso: Você ultrapassou um ou mais limites de uso. Seus sites não se conectarão até você modificar sua assinatura ou ajustar seu uso.",
|
||||
"billingUsageLimitsOverview": "Visão Geral dos Limites de Uso",
|
||||
"billingMonitorUsage": "Monitore seu uso em relação aos limites configurados. Se precisar aumentar esses limites, entre em contato conosco support@fossorial.io.",
|
||||
"billingMonitorUsage": "Monitore seu uso em relação aos limites configurados. Se precisar aumentar esses limites, entre em contato conosco support@pangolin.net.",
|
||||
"billingDataUsage": "Uso de Dados",
|
||||
"billingOnlineTime": "Tempo Online do Site",
|
||||
"billingUsers": "Usuários Ativos",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Бесплатный уровень",
|
||||
"billingWarningOverLimit": "Предупреждение: Вы превысили одну или несколько границ использования. Ваши сайты не подключатся, пока вы не измените подписку или не скорректируете использование.",
|
||||
"billingUsageLimitsOverview": "Обзор лимитов использования",
|
||||
"billingMonitorUsage": "Контролируйте использование в соответствии с установленными лимитами. Если вам требуется увеличение лимитов, пожалуйста, свяжитесь с нами support@fossorial.io.",
|
||||
"billingMonitorUsage": "Контролируйте использование в соответствии с установленными лимитами. Если вам требуется увеличение лимитов, пожалуйста, свяжитесь с нами support@pangolin.net.",
|
||||
"billingDataUsage": "Использование данных",
|
||||
"billingOnlineTime": "Время работы сайта",
|
||||
"billingUsers": "Активные пользователи",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "Ücretsiz Dilim",
|
||||
"billingWarningOverLimit": "Uyarı: Bir veya daha fazla kullanım limitini aştınız. Aboneliğinizi değiştirmediğiniz veya kullanımı ayarlamadığınız sürece siteleriniz bağlanmayacaktır.",
|
||||
"billingUsageLimitsOverview": "Kullanım Limitleri Genel Görünümü",
|
||||
"billingMonitorUsage": "Kullanımınızı yapılandırılmış limitlerle karşılaştırın. Limitlerin artırılmasına ihtiyacınız varsa, lütfen support@fossorial.io adresinden bizimle iletişime geçin.",
|
||||
"billingMonitorUsage": "Kullanımınızı yapılandırılmış limitlerle karşılaştırın. Limitlerin artırılmasına ihtiyacınız varsa, lütfen support@pangolin.net adresinden bizimle iletişime geçin.",
|
||||
"billingDataUsage": "Veri Kullanımı",
|
||||
"billingOnlineTime": "Site Çevrimiçi Süresi",
|
||||
"billingUsers": "Aktif Kullanıcılar",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
@@ -1280,7 +1280,7 @@
|
||||
"billingFreeTier": "免费层",
|
||||
"billingWarningOverLimit": "警告:您已超出一个或多个使用限制。在您修改订阅或调整使用情况之前,您的站点将无法连接。",
|
||||
"billingUsageLimitsOverview": "使用限制概览",
|
||||
"billingMonitorUsage": "监控您的使用情况以对比已配置的限制。如需提高限制请联系我们 support@fossorial.io。",
|
||||
"billingMonitorUsage": "监控您的使用情况以对比已配置的限制。如需提高限制请联系我们 support@pangolin.net。",
|
||||
"billingDataUsage": "数据使用情况",
|
||||
"billingOnlineTime": "站点在线时间",
|
||||
"billingUsers": "活跃用户",
|
||||
@@ -1819,7 +1819,7 @@
|
||||
},
|
||||
"trialPeriodInformation": {
|
||||
"title": "Trial Period Information",
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@fossorial.io."
|
||||
"description": "This License Key enables Enterprise features for a 7-day evaluation period. Continued access to Paid Features beyond the evaluation period requires activation under a valid Personal or Enterprise License. For Enterprise licensing, contact sales@pangolin.net."
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
|
||||
919
package-lock.json
generated
919
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -56,7 +56,7 @@
|
||||
"@radix-ui/react-tabs": "1.1.13",
|
||||
"@radix-ui/react-toast": "1.2.15",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@react-email/components": "0.5.6",
|
||||
"@react-email/components": "0.5.7",
|
||||
"@react-email/render": "^1.3.2",
|
||||
"@react-email/tailwind": "1.2.2",
|
||||
"@simplewebauthn/browser": "^13.2.2",
|
||||
@@ -77,7 +77,7 @@
|
||||
"crypto-js": "^4.2.0",
|
||||
"drizzle-orm": "0.44.6",
|
||||
"eslint": "9.37.0",
|
||||
"eslint-config-next": "15.5.4",
|
||||
"eslint-config-next": "15.5.6",
|
||||
"express": "5.1.0",
|
||||
"express-rate-limit": "8.1.0",
|
||||
"glob": "11.0.3",
|
||||
@@ -92,7 +92,7 @@
|
||||
"lucide-react": "^0.545.0",
|
||||
"maxmind": "5.0.0",
|
||||
"moment": "2.30.1",
|
||||
"next": "15.5.4",
|
||||
"next": "15.5.6",
|
||||
"next-intl": "^4.3.12",
|
||||
"next-themes": "0.4.6",
|
||||
"node-cache": "5.1.2",
|
||||
@@ -143,13 +143,13 @@
|
||||
"@types/nodemailer": "7.0.2",
|
||||
"@types/pg": "8.15.5",
|
||||
"@types/react": "19.2.2",
|
||||
"@types/react-dom": "19.2.1",
|
||||
"@types/react-dom": "19.2.2",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/swagger-ui-express": "^4.1.8",
|
||||
"@types/ws": "8.18.1",
|
||||
"@types/yargs": "17.0.33",
|
||||
"drizzle-kit": "0.31.5",
|
||||
"esbuild": "0.25.10",
|
||||
"esbuild": "0.25.11",
|
||||
"esbuild-node-externals": "1.18.0",
|
||||
"postcss": "^8",
|
||||
"react-email": "4.3.0",
|
||||
|
||||
@@ -126,7 +126,7 @@ export const targets = pgTable("targets", {
|
||||
pathMatchType: text("pathMatchType"), // exact, prefix, regex
|
||||
rewritePath: text("rewritePath"), // if set, rewrites the path to this value before sending to the target
|
||||
rewritePathType: text("rewritePathType"), // exact, prefix, regex, stripPrefix
|
||||
priority: integer("priority").notNull().default(100)
|
||||
priority: integer("priority").default(100)
|
||||
});
|
||||
|
||||
export const targetHealthCheck = pgTable("targetHealthCheck", {
|
||||
|
||||
@@ -138,7 +138,7 @@ export const targets = sqliteTable("targets", {
|
||||
pathMatchType: text("pathMatchType"), // exact, prefix, regex
|
||||
rewritePath: text("rewritePath"), // if set, rewrites the path to this value before sending to the target
|
||||
rewritePathType: text("rewritePathType"), // exact, prefix, regex, stripPrefix
|
||||
priority: integer("priority").notNull().default(100)
|
||||
priority: integer("priority").default(100)
|
||||
});
|
||||
|
||||
export const targetHealthCheck = sqliteTable("targetHealthCheck", {
|
||||
|
||||
@@ -88,7 +88,7 @@ export const WelcomeQuickStart = ({
|
||||
To learn how to use Newt, including more
|
||||
installation methods, visit the{" "}
|
||||
<a
|
||||
href="https://docs.digpangolin.com/manage/sites/install-site"
|
||||
href="https://docs.pangolin.net/manage/sites/install-site"
|
||||
className="underline"
|
||||
>
|
||||
docs
|
||||
|
||||
@@ -89,7 +89,7 @@ export function EmailFooter({ children }: { children: React.ReactNode }) {
|
||||
<p className="text-xs text-gray-400 mt-4">
|
||||
For any questions or support, please contact us at:
|
||||
<br />
|
||||
support@fossorial.io
|
||||
support@pangolin.net
|
||||
</p>
|
||||
<p className="text-xs text-gray-300 text-center mt-4">
|
||||
© {new Date().getFullYear()} Fossorial, Inc. All
|
||||
|
||||
@@ -612,7 +612,8 @@ export class UsageService {
|
||||
|
||||
public async getUsage(
|
||||
orgId: string,
|
||||
featureId: FeatureId
|
||||
featureId: FeatureId,
|
||||
trx: Transaction | typeof db = db
|
||||
): Promise<Usage | null> {
|
||||
if (noop()) {
|
||||
return null;
|
||||
@@ -621,7 +622,7 @@ export class UsageService {
|
||||
const usageId = `${orgId}-${featureId}`;
|
||||
|
||||
try {
|
||||
const [result] = await db
|
||||
const [result] = await trx
|
||||
.select()
|
||||
.from(usage)
|
||||
.where(eq(usage.usageId, usageId))
|
||||
@@ -635,7 +636,7 @@ export class UsageService {
|
||||
const meterId = getFeatureMeterId(featureId);
|
||||
|
||||
try {
|
||||
const [newUsage] = await db
|
||||
const [newUsage] = await trx
|
||||
.insert(usage)
|
||||
.values({
|
||||
usageId,
|
||||
@@ -652,7 +653,7 @@ export class UsageService {
|
||||
return newUsage;
|
||||
} else {
|
||||
// Record was created by another process, fetch it
|
||||
const [existingUsage] = await db
|
||||
const [existingUsage] = await trx
|
||||
.select()
|
||||
.from(usage)
|
||||
.where(eq(usage.usageId, usageId))
|
||||
@@ -665,7 +666,7 @@ export class UsageService {
|
||||
`Insert failed for ${orgId}/${featureId}, attempting to fetch existing record:`,
|
||||
insertError
|
||||
);
|
||||
const [existingUsage] = await db
|
||||
const [existingUsage] = await trx
|
||||
.select()
|
||||
.from(usage)
|
||||
.where(eq(usage.usageId, usageId))
|
||||
@@ -812,7 +813,8 @@ export class UsageService {
|
||||
orgId: string,
|
||||
kickSites = false,
|
||||
featureId?: FeatureId,
|
||||
usage?: Usage
|
||||
usage?: Usage,
|
||||
trx: Transaction | typeof db = db
|
||||
): Promise<boolean> {
|
||||
if (noop()) {
|
||||
return false;
|
||||
@@ -825,7 +827,7 @@ export class UsageService {
|
||||
let orgLimits: Limit[] = [];
|
||||
if (featureId) {
|
||||
// Get all limits set for this organization
|
||||
orgLimits = await db
|
||||
orgLimits = await trx
|
||||
.select()
|
||||
.from(limits)
|
||||
.where(
|
||||
@@ -836,7 +838,7 @@ export class UsageService {
|
||||
);
|
||||
} else {
|
||||
// Get all limits set for this organization
|
||||
orgLimits = await db
|
||||
orgLimits = await trx
|
||||
.select()
|
||||
.from(limits)
|
||||
.where(eq(limits.orgId, orgId));
|
||||
@@ -855,7 +857,8 @@ export class UsageService {
|
||||
} else {
|
||||
currentUsage = await this.getUsage(
|
||||
orgId,
|
||||
limit.featureId as FeatureId
|
||||
limit.featureId as FeatureId,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
@@ -890,7 +893,7 @@ export class UsageService {
|
||||
);
|
||||
|
||||
// Get all sites for this organization
|
||||
const orgSites = await db
|
||||
const orgSites = await trx
|
||||
.select()
|
||||
.from(sites)
|
||||
.where(eq(sites.orgId, orgId));
|
||||
@@ -902,7 +905,7 @@ export class UsageService {
|
||||
// Send termination messages to newt sites
|
||||
for (const site of orgSites) {
|
||||
if (site.type === "newt") {
|
||||
const [newt] = await db
|
||||
const [newt] = await trx
|
||||
.select()
|
||||
.from(newts)
|
||||
.where(eq(newts.siteId, site.siteId))
|
||||
@@ -917,7 +920,7 @@ export class UsageService {
|
||||
};
|
||||
|
||||
// Don't await to prevent blocking
|
||||
sendToClient(newt.newtId, payload).catch(
|
||||
await sendToClient(newt.newtId, payload).catch(
|
||||
(error: any) => {
|
||||
logger.error(
|
||||
`Failed to send termination message to newt ${newt.newtId}:`,
|
||||
|
||||
@@ -139,8 +139,8 @@ export async function applyBlueprint(
|
||||
// password: "sadfasdfadsf",
|
||||
// "sso-enabled": true,
|
||||
// "sso-roles": ["Member"],
|
||||
// "sso-users": ["owen@fossorial.io"],
|
||||
// "whitelist-users": ["owen@fossorial.io"]
|
||||
// "sso-users": ["owen@pangolin.net"],
|
||||
// "whitelist-users": ["owen@pangolin.net"]
|
||||
// },
|
||||
// targets: [
|
||||
// {
|
||||
|
||||
@@ -87,8 +87,8 @@ export function convertValue(value: string): any {
|
||||
// "resources.resource-nice-id.auth.password": "sadfasdfadsf",
|
||||
// "resources.resource-nice-id.auth.sso-enabled": "true",
|
||||
// "resources.resource-nice-id.auth.sso-roles[0]": "Member",
|
||||
// "resources.resource-nice-id.auth.sso-users[0]": "owen@fossorial.io",
|
||||
// "resources.resource-nice-id.auth.whitelist-users[0]": "owen@fossorial.io",
|
||||
// "resources.resource-nice-id.auth.sso-users[0]": "owen@pangolin.net",
|
||||
// "resources.resource-nice-id.auth.whitelist-users[0]": "owen@pangolin.net",
|
||||
// "resources.resource-nice-id.targets[0].hostname": "localhost",
|
||||
// "resources.resource-nice-id.targets[0].method": "http",
|
||||
// "resources.resource-nice-id.targets[0].port": "8000",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { db, exitNodes } from "@server/db";
|
||||
import { db, exitNodes, Transaction } from "@server/db";
|
||||
import logger from "@server/logger";
|
||||
import { ExitNodePingResult } from "@server/routers/newt";
|
||||
import { eq } from "drizzle-orm";
|
||||
@@ -59,7 +59,11 @@ export function selectBestExitNode(
|
||||
return pingResults[0];
|
||||
}
|
||||
|
||||
export async function checkExitNodeOrg(exitNodeId: number, orgId: string) {
|
||||
export async function checkExitNodeOrg(
|
||||
exitNodeId: number,
|
||||
orgId: string,
|
||||
trx?: Transaction | typeof db
|
||||
): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -314,14 +314,11 @@ export const configSchema = z
|
||||
nameservers: z
|
||||
.array(z.string().optional().optional())
|
||||
.optional()
|
||||
.default(["ns1.fossorial.io", "ns2.fossorial.io"]),
|
||||
cname_extension: z.string().optional().default("fossorial.io")
|
||||
.default(["ns1.pangolin.net", "ns2.pangolin.net", "ns3.pangolin.net"]),
|
||||
cname_extension: z.string().optional().default("cname.pangolin.net")
|
||||
})
|
||||
.optional()
|
||||
.default({
|
||||
nameservers: ["ns1.fossorial.io", "ns2.fossorial.io"],
|
||||
cname_extension: "fossorial.io"
|
||||
})
|
||||
.default({})
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
@@ -392,7 +389,7 @@ export function readConfigFile() {
|
||||
|
||||
if (!environment) {
|
||||
throw new Error(
|
||||
"No configuration file found. Please create one. https://docs.digpangolin.com/self-host/advanced/config-file"
|
||||
"No configuration file found. Please create one. https://docs.pangolin.net/self-host/advanced/config-file"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class TelemetryClient {
|
||||
this.client = new PostHog(
|
||||
"phc_QYuATSSZt6onzssWcYJbXLzQwnunIpdGGDTYhzK3VjX",
|
||||
{
|
||||
host: "https://digpangolin.com/relay-O7yI"
|
||||
host: "https://pangolin.net/relay-O7yI"
|
||||
}
|
||||
);
|
||||
|
||||
@@ -48,11 +48,11 @@ class TelemetryClient {
|
||||
this.startAnalyticsInterval();
|
||||
|
||||
logger.info(
|
||||
"Pangolin now gathers anonymous usage data to help us better understand how the software is used and guide future improvements and feature development. You can find more details, including instructions for opting out of this anonymous data collection, at: https://docs.digpangolin.com/telemetry"
|
||||
"Pangolin now gathers anonymous usage data to help us better understand how the software is used and guide future improvements and feature development. You can find more details, including instructions for opting out of this anonymous data collection, at: https://docs.pangolin.net/telemetry"
|
||||
);
|
||||
} else if (!this.enabled) {
|
||||
logger.info(
|
||||
"Analytics usage statistics collection is disabled. If you enable this, you can help us make Pangolin better for everyone. Learn more at: https://docs.digpangolin.com/telemetry"
|
||||
"Analytics usage statistics collection is disabled. If you enable this, you can help us make Pangolin better for everyone. Learn more at: https://docs.pangolin.net/telemetry"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,13 +88,7 @@ export async function getTraefikConfig(
|
||||
and(
|
||||
eq(targets.enabled, true),
|
||||
eq(resources.enabled, true),
|
||||
or(
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
and(
|
||||
isNull(sites.exitNodeId),
|
||||
sql`(${siteTypes.includes("local") ? 1 : 0} = 1)` // only allow local sites if "local" is in siteTypes
|
||||
)
|
||||
),
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
or(
|
||||
ne(targetHealthCheck.hcHealth, "unhealthy"), // Exclude unhealthy targets
|
||||
isNull(targetHealthCheck.hcHealth) // Include targets with no health check record
|
||||
|
||||
@@ -18,7 +18,8 @@ import {
|
||||
resources,
|
||||
targets,
|
||||
sites,
|
||||
targetHealthCheck
|
||||
targetHealthCheck,
|
||||
Transaction
|
||||
} from "@server/db";
|
||||
import logger from "@server/logger";
|
||||
import { ExitNodePingResult } from "@server/routers/newt";
|
||||
@@ -333,8 +334,8 @@ export function selectBestExitNode(
|
||||
return fallbackNode;
|
||||
}
|
||||
|
||||
export async function checkExitNodeOrg(exitNodeId: number, orgId: string) {
|
||||
const [exitNodeOrg] = await db
|
||||
export async function checkExitNodeOrg(exitNodeId: number, orgId: string, trx: Transaction | typeof db = db) {
|
||||
const [exitNodeOrg] = await trx
|
||||
.select()
|
||||
.from(exitNodeOrgs)
|
||||
.where(
|
||||
|
||||
@@ -76,7 +76,7 @@ export const privateConfigSchema = z.object({
|
||||
local_exit_node_reachable_at: z
|
||||
.string()
|
||||
.optional()
|
||||
.default("http://gerbil:3003")
|
||||
.default("http://gerbil:3004")
|
||||
})
|
||||
.optional()
|
||||
.default({}),
|
||||
|
||||
@@ -120,19 +120,12 @@ export async function getTraefikConfig(
|
||||
and(
|
||||
eq(targets.enabled, true),
|
||||
eq(resources.enabled, true),
|
||||
or(
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
and(
|
||||
isNull(sites.exitNodeId),
|
||||
sql`(${siteTypes.includes("local") ? 1 : 0} = 1)` // only allow local sites if "local" is in siteTypes
|
||||
)
|
||||
),
|
||||
eq(sites.exitNodeId, exitNodeId),
|
||||
or(
|
||||
ne(targetHealthCheck.hcHealth, "unhealthy"), // Exclude unhealthy targets
|
||||
isNull(targetHealthCheck.hcHealth) // Include targets with no health check record
|
||||
),
|
||||
inArray(sites.type, siteTypes),
|
||||
// lets rewrite this using sql
|
||||
config.getRawConfig().traefik.allow_raw_resources
|
||||
? isNotNull(resources.http) // ignore the http check if allow_raw_resources is true
|
||||
: eq(resources.http, true)
|
||||
@@ -238,7 +231,7 @@ export async function getTraefikConfig(
|
||||
}
|
||||
// get the valid certs for these domains
|
||||
validCerts = await getValidCertificatesForDomains(domains, true); // we are caching here because this is called often
|
||||
logger.debug(`Valid certs for domains: ${JSON.stringify(validCerts)}`);
|
||||
// logger.debug(`Valid certs for domains: ${JSON.stringify(validCerts)}`);
|
||||
}
|
||||
|
||||
const config_output: any = {
|
||||
|
||||
@@ -65,10 +65,12 @@ export async function createExitNode(
|
||||
[exitNode] = await db
|
||||
.update(exitNodes)
|
||||
.set({
|
||||
reachableAt
|
||||
reachableAt,
|
||||
online: true
|
||||
})
|
||||
.where(eq(exitNodes.exitNodeId, exitNodeQuery.exitNodeId))
|
||||
.returning();
|
||||
|
||||
logger.info(`Updated exit node reachableAt to ${reachableAt}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ export async function createRemoteExitNode(
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
"Remote exit node limit exceeded. Please upgrade your plan or contact us at support@fossorial.io"
|
||||
"Remote exit node limit exceeded. Please upgrade your plan or contact us at support@pangolin.net"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ export async function createExitNode(publicKey: string, reachableAt: string | un
|
||||
.update(exitNodes)
|
||||
.set({
|
||||
reachableAt,
|
||||
publicKey
|
||||
publicKey,
|
||||
online: true
|
||||
})
|
||||
.where(eq(exitNodes.publicKey, publicKey))
|
||||
.returning();
|
||||
|
||||
@@ -98,7 +98,8 @@ export async function updateSiteBandwidth(
|
||||
if (
|
||||
await checkExitNodeOrg(
|
||||
exitNodeId,
|
||||
updatedSite.orgId
|
||||
updatedSite.orgId,
|
||||
trx
|
||||
)
|
||||
) {
|
||||
// not allowed
|
||||
@@ -148,7 +149,8 @@ export async function updateSiteBandwidth(
|
||||
orgId,
|
||||
true,
|
||||
FeatureId.EGRESS_DATA_MB,
|
||||
bandwidthUsage
|
||||
bandwidthUsage,
|
||||
trx
|
||||
)
|
||||
.catch((error: any) => {
|
||||
logger.error(
|
||||
@@ -174,7 +176,8 @@ export async function updateSiteBandwidth(
|
||||
orgId,
|
||||
true,
|
||||
FeatureId.SITE_UPTIME,
|
||||
uptimeUsage
|
||||
uptimeUsage,
|
||||
trx
|
||||
)
|
||||
.catch((error: any) => {
|
||||
logger.error(
|
||||
@@ -242,7 +245,8 @@ export async function updateSiteBandwidth(
|
||||
if (
|
||||
await checkExitNodeOrg(
|
||||
exitNodeId,
|
||||
updatedSite.orgId
|
||||
updatedSite.orgId,
|
||||
trx
|
||||
)
|
||||
) {
|
||||
// not allowed
|
||||
|
||||
@@ -414,6 +414,20 @@ authenticated.post(
|
||||
resource.setResourceWhitelist
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
`/resource/:resourceId/whitelist/add`,
|
||||
verifyApiKeyResourceAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.setResourceWhitelist),
|
||||
resource.addEmailToResourceWhitelist
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
`/resource/:resourceId/whitelist/remove`,
|
||||
verifyApiKeyResourceAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.setResourceWhitelist),
|
||||
resource.removeEmailFromResourceWhitelist
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
`/resource/:resourceId/whitelist`,
|
||||
verifyApiKeyResourceAccess,
|
||||
|
||||
147
server/routers/resource/addEmailToResourceWhitelist.ts
Normal file
147
server/routers/resource/addEmailToResourceWhitelist.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import { resources, resourceWhitelist } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
|
||||
const addEmailToResourceWhitelistBodySchema = z
|
||||
.object({
|
||||
email: z
|
||||
.string()
|
||||
.email()
|
||||
.or(
|
||||
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
|
||||
message:
|
||||
"Invalid email address. Wildcard (*) must be the entire local part."
|
||||
})
|
||||
)
|
||||
.transform((v) => v.toLowerCase())
|
||||
})
|
||||
.strict();
|
||||
|
||||
const addEmailToResourceWhitelistParamsSchema = z
|
||||
.object({
|
||||
resourceId: z
|
||||
.string()
|
||||
.transform(Number)
|
||||
.pipe(z.number().int().positive())
|
||||
})
|
||||
.strict();
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/resource/{resourceId}/whitelist/add",
|
||||
description: "Add a single email to the resource whitelist.",
|
||||
tags: [OpenAPITags.Resource],
|
||||
request: {
|
||||
params: addEmailToResourceWhitelistParamsSchema,
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: addEmailToResourceWhitelistBodySchema
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {}
|
||||
});
|
||||
|
||||
export async function addEmailToResourceWhitelist(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedBody = addEmailToResourceWhitelistBodySchema.safeParse(
|
||||
req.body
|
||||
);
|
||||
if (!parsedBody.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedBody.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { email } = parsedBody.data;
|
||||
|
||||
const parsedParams = addEmailToResourceWhitelistParamsSchema.safeParse(
|
||||
req.params
|
||||
);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { resourceId } = parsedParams.data;
|
||||
|
||||
const [resource] = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.where(eq(resources.resourceId, resourceId));
|
||||
|
||||
if (!resource) {
|
||||
return next(
|
||||
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||
);
|
||||
}
|
||||
|
||||
if (!resource.emailWhitelistEnabled) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Email whitelist is not enabled for this resource"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check if email already exists in whitelist
|
||||
const existingEntry = await db
|
||||
.select()
|
||||
.from(resourceWhitelist)
|
||||
.where(
|
||||
and(
|
||||
eq(resourceWhitelist.resourceId, resourceId),
|
||||
eq(resourceWhitelist.email, email)
|
||||
)
|
||||
);
|
||||
|
||||
if (existingEntry.length > 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.CONFLICT,
|
||||
"Email already exists in whitelist"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
await db.insert(resourceWhitelist).values({
|
||||
email,
|
||||
resourceId
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
data: {},
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Email added to whitelist successfully",
|
||||
status: HttpCode.CREATED
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -23,3 +23,5 @@ export * from "./listResourceRules";
|
||||
export * from "./updateResourceRule";
|
||||
export * from "./getUserResources";
|
||||
export * from "./setResourceHeaderAuth";
|
||||
export * from "./addEmailToResourceWhitelist";
|
||||
export * from "./removeEmailFromResourceWhitelist";
|
||||
|
||||
150
server/routers/resource/removeEmailFromResourceWhitelist.ts
Normal file
150
server/routers/resource/removeEmailFromResourceWhitelist.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import { resources, resourceWhitelist } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
|
||||
const removeEmailFromResourceWhitelistBodySchema = z
|
||||
.object({
|
||||
email: z
|
||||
.string()
|
||||
.email()
|
||||
.or(
|
||||
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
|
||||
message:
|
||||
"Invalid email address. Wildcard (*) must be the entire local part."
|
||||
})
|
||||
)
|
||||
.transform((v) => v.toLowerCase())
|
||||
})
|
||||
.strict();
|
||||
|
||||
const removeEmailFromResourceWhitelistParamsSchema = z
|
||||
.object({
|
||||
resourceId: z
|
||||
.string()
|
||||
.transform(Number)
|
||||
.pipe(z.number().int().positive())
|
||||
})
|
||||
.strict();
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/resource/{resourceId}/whitelist/remove",
|
||||
description: "Remove a single email from the resource whitelist.",
|
||||
tags: [OpenAPITags.Resource],
|
||||
request: {
|
||||
params: removeEmailFromResourceWhitelistParamsSchema,
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: removeEmailFromResourceWhitelistBodySchema
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {}
|
||||
});
|
||||
|
||||
export async function removeEmailFromResourceWhitelist(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedBody = removeEmailFromResourceWhitelistBodySchema.safeParse(
|
||||
req.body
|
||||
);
|
||||
if (!parsedBody.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedBody.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { email } = parsedBody.data;
|
||||
|
||||
const parsedParams =
|
||||
removeEmailFromResourceWhitelistParamsSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { resourceId } = parsedParams.data;
|
||||
|
||||
const [resource] = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.where(eq(resources.resourceId, resourceId));
|
||||
|
||||
if (!resource) {
|
||||
return next(
|
||||
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||
);
|
||||
}
|
||||
|
||||
if (!resource.emailWhitelistEnabled) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Email whitelist is not enabled for this resource"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check if email exists in whitelist
|
||||
const existingEntry = await db
|
||||
.select()
|
||||
.from(resourceWhitelist)
|
||||
.where(
|
||||
and(
|
||||
eq(resourceWhitelist.resourceId, resourceId),
|
||||
eq(resourceWhitelist.email, email)
|
||||
)
|
||||
);
|
||||
|
||||
if (existingEntry.length === 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.NOT_FOUND,
|
||||
"Email not found in whitelist"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
await db
|
||||
.delete(resourceWhitelist)
|
||||
.where(
|
||||
and(
|
||||
eq(resourceWhitelist.resourceId, resourceId),
|
||||
eq(resourceWhitelist.email, email)
|
||||
)
|
||||
);
|
||||
|
||||
return response(res, {
|
||||
data: {},
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Email removed from whitelist successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import { hashPassword } from "@server/auth/password";
|
||||
import { isValidIP } from "@server/lib/validators";
|
||||
import { isIpInCidr } from "@server/lib/ip";
|
||||
import { verifyExitNodeOrgAccess } from "#dynamic/lib/exitNodes";
|
||||
import { build } from "@server/build";
|
||||
|
||||
const createSiteParamsSchema = z
|
||||
.object({
|
||||
@@ -203,10 +204,10 @@ export async function createSite(
|
||||
|
||||
const niceId = await getUniqueSiteName(orgId);
|
||||
|
||||
await db.transaction(async (trx) => {
|
||||
let newSite: Site;
|
||||
let newSite: Site;
|
||||
|
||||
if ((type == "wireguard" || type == "newt") && exitNodeId) {
|
||||
await db.transaction(async (trx) => {
|
||||
if (type == "wireguard" || type == "newt") {
|
||||
// we are creating a site with an exit node (tunneled)
|
||||
if (!subnet) {
|
||||
return next(
|
||||
@@ -217,11 +218,19 @@ export async function createSite(
|
||||
);
|
||||
}
|
||||
|
||||
const { exitNode, hasAccess } =
|
||||
await verifyExitNodeOrgAccess(
|
||||
exitNodeId,
|
||||
orgId
|
||||
if (!exitNodeId) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Exit node ID is required for tunneled sites"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { exitNode, hasAccess } = await verifyExitNodeOrgAccess(
|
||||
exitNodeId,
|
||||
orgId
|
||||
);
|
||||
|
||||
if (!exitNode) {
|
||||
logger.warn("Exit node not found");
|
||||
@@ -257,13 +266,51 @@ export async function createSite(
|
||||
...(pubKey && type == "wireguard" && { pubKey })
|
||||
})
|
||||
.returning();
|
||||
} else {
|
||||
// we are creating a site with no tunneling
|
||||
} else if (type == "local") {
|
||||
let exitNodeIdToCreate = exitNodeId;
|
||||
if (!exitNodeIdToCreate) {
|
||||
if (build == "saas") {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Exit node ID of a remote node is required for local sites"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// select the exit node for local sites
|
||||
// TODO: THIS SHOULD BE CHOSEN IN THE FRONTEND OR SOMETHING BECAUSE
|
||||
// YOU CAN HAVE MORE THAN ONE NODE IN THE SYSTEM AND YOU SHOULD SELECT
|
||||
// WHICH GERBIL NODE TO PUT THE SITE ON BUT FOR NOW THIS WILL DO
|
||||
const [localExitNode] = await trx
|
||||
.select()
|
||||
.from(exitNodes)
|
||||
.where(eq(exitNodes.type, "gerbil"))
|
||||
.limit(1);
|
||||
|
||||
if (!localExitNode) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"No gerbil exit node found for organization. Please create a gerbil exit node first."
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
exitNodeIdToCreate = localExitNode.exitNodeId;
|
||||
} else {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Site type not recognized"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
[newSite] = await trx
|
||||
.insert(sites)
|
||||
.values({
|
||||
exitNodeId: exitNodeId,
|
||||
exitNodeId: exitNodeIdToCreate,
|
||||
orgId,
|
||||
name,
|
||||
niceId,
|
||||
|
||||
45
server/setup/scriptsPg/1.11.1.ts
Normal file
45
server/setup/scriptsPg/1.11.1.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { db } from "@server/db/pg/driver";
|
||||
import { sql } from "drizzle-orm";
|
||||
|
||||
const version = "1.11.1";
|
||||
|
||||
export default async function migration() {
|
||||
console.log(`Running setup script ${version}...`);
|
||||
|
||||
try {
|
||||
// Get the first exit node with type 'gerbil'
|
||||
const exitNodesQuery = await db.execute(
|
||||
sql`SELECT "exitNodeId" FROM "exitNodes" WHERE "type" = 'gerbil' LIMIT 1`
|
||||
);
|
||||
const exitNodes = exitNodesQuery.rows as {
|
||||
exitNodeId: number;
|
||||
}[];
|
||||
|
||||
const exitNodeId = exitNodes.length > 0 ? exitNodes[0].exitNodeId : null;
|
||||
|
||||
// Get all sites with type 'local'
|
||||
const sitesQuery = await db.execute(
|
||||
sql`SELECT "siteId" FROM "sites" WHERE "type" = 'local'`
|
||||
);
|
||||
const sites = sitesQuery.rows as {
|
||||
siteId: number;
|
||||
}[];
|
||||
|
||||
// Update sites to use the exit node
|
||||
for (const site of sites) {
|
||||
await db.execute(sql`
|
||||
UPDATE "sites" SET "exitNodeId" = ${exitNodeId} WHERE "siteId" = ${site.siteId}
|
||||
`);
|
||||
}
|
||||
|
||||
await db.execute(sql`COMMIT`);
|
||||
console.log(`Updated sites with exit node`);
|
||||
} catch (e) {
|
||||
await db.execute(sql`ROLLBACK`);
|
||||
console.log("Unable to update sites with exit node");
|
||||
console.log(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
console.log(`${version} migration complete`);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ export default async function migration() {
|
||||
fs.writeFileSync(filePath, updatedYaml, "utf8");
|
||||
} catch (e) {
|
||||
console.log(
|
||||
`Failed to add resource_session_request_param to config. Please add it manually. https://docs.digpangolin.com/self-host/advanced/config-file`
|
||||
`Failed to add resource_session_request_param to config. Please add it manually. https://docs.pangolin.net/self-host/advanced/config-file`
|
||||
);
|
||||
trx.rollback();
|
||||
return;
|
||||
|
||||
37
server/setup/scriptsSqlite/1.11.1.ts
Normal file
37
server/setup/scriptsSqlite/1.11.1.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { APP_PATH } from "@server/lib/consts";
|
||||
import Database from "better-sqlite3";
|
||||
import path from "path";
|
||||
|
||||
const version = "1.11.1";
|
||||
|
||||
export default async function migration() {
|
||||
console.log(`Running setup script ${version}...`);
|
||||
|
||||
const location = path.join(APP_PATH, "db", "db.sqlite");
|
||||
const db = new Database(location);
|
||||
|
||||
db.transaction(() => {
|
||||
const exitNodes = db.prepare(`SELECT * FROM exitNodes WHERE type = 'gerbil' LIMIT 1`).all() as {
|
||||
exitNodeId: number;
|
||||
name: string;
|
||||
}[];
|
||||
|
||||
const exitNodeId = exitNodes.length > 0 ? exitNodes[0].exitNodeId : null;
|
||||
|
||||
// get all of the targets
|
||||
const sites = db.prepare(`SELECT * FROM sites WHERE type = 'local'`).all() as {
|
||||
siteId: number;
|
||||
exitNodeId: number | null;
|
||||
}[];
|
||||
|
||||
const defineExitNodeOnSite = db.prepare(
|
||||
`UPDATE sites SET exitNodeId = ? WHERE siteId = ?`
|
||||
);
|
||||
|
||||
for (const site of sites) {
|
||||
defineExitNodeOnSite.run(exitNodeId, site.siteId);
|
||||
}
|
||||
})();
|
||||
|
||||
console.log(`${version} migration complete`);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ export default async function migration() {
|
||||
console.log(`Added new config option: resource_access_token_headers`);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
`Unable to add new config option: resource_access_token_headers. Please add it manually. https://docs.digpangolin.com/self-host/advanced/config-file`
|
||||
`Unable to add new config option: resource_access_token_headers. Please add it manually. https://docs.pangolin.net/self-host/advanced/config-file`
|
||||
);
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ export default function GeneralPage() {
|
||||
</Badge>
|
||||
<Link
|
||||
className="flex items-center gap-2 text-primary hover:underline"
|
||||
href="https://digpangolin.com/pricing"
|
||||
href="https://pangolin.net/pricing"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -270,17 +270,12 @@ export default function ExitNodesTable({
|
||||
setSelectedNode(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("remoteExitNodeQuestionRemove", {
|
||||
selectedNode:
|
||||
selectedNode?.name || selectedNode?.id
|
||||
})}
|
||||
{t("remoteExitNodeQuestionRemove")}
|
||||
</p>
|
||||
|
||||
<p>{t("remoteExitNodeMessageRemove")}</p>
|
||||
|
||||
<p>{t("remoteExitNodeMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("remoteExitNodeConfirmDelete")}
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
FaFreebsd,
|
||||
FaWindows
|
||||
} from "react-icons/fa";
|
||||
import {
|
||||
import {
|
||||
SiNixos,
|
||||
SiKubernetes
|
||||
} from "react-icons/si";
|
||||
@@ -150,33 +150,33 @@ export default function Page() {
|
||||
const commands = {
|
||||
mac: {
|
||||
"Apple Silicon (arm64)": [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
],
|
||||
"Intel x64 (amd64)": [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
]
|
||||
},
|
||||
linux: {
|
||||
amd64: [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
],
|
||||
arm64: [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
],
|
||||
arm32: [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
],
|
||||
arm32v6: [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
],
|
||||
riscv64: [
|
||||
`curl -fsSL https://digpangolin.com/get-olm.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-olm.sh | bash`,
|
||||
`sudo olm --id ${id} --secret ${secret} --endpoint ${endpoint}`
|
||||
]
|
||||
},
|
||||
@@ -342,14 +342,14 @@ export default function Page() {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
||||
|
||||
|
||||
const response = await fetch(
|
||||
`https://api.github.com/repos/fosrl/olm/releases/latest`,
|
||||
{ signal: controller.signal }
|
||||
);
|
||||
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
t("olmErrorFetchReleases", {
|
||||
|
||||
@@ -168,13 +168,10 @@ export default function GeneralPage() {
|
||||
}}
|
||||
dialog={
|
||||
<div>
|
||||
<p className="mb-2">
|
||||
{t("orgQuestionRemove", {
|
||||
selectedOrg: org?.org.name
|
||||
})}
|
||||
<p>
|
||||
{t("orgQuestionRemove")}
|
||||
</p>
|
||||
<p className="mb-2">{t("orgMessageRemove")}</p>
|
||||
<p>{t("orgMessageConfirm")}</p>
|
||||
<p>{t("orgMessageRemove")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("orgDeleteConfirm")}
|
||||
|
||||
@@ -854,6 +854,7 @@ export default function ReverseProxyTargets(props: {
|
||||
type="number"
|
||||
min="1"
|
||||
max="1000"
|
||||
onClick={(e) => e.currentTarget.focus()}
|
||||
defaultValue={row.original.priority || 100}
|
||||
className="w-full max-w-20"
|
||||
onBlur={(e) => {
|
||||
|
||||
@@ -438,6 +438,7 @@ export default function ResourceRules(props: {
|
||||
defaultValue={row.original.priority}
|
||||
className="w-[75px]"
|
||||
type="number"
|
||||
onClick={(e) => e.currentTarget.focus()}
|
||||
onBlur={(e) => {
|
||||
const parsed = z.coerce
|
||||
.number()
|
||||
|
||||
@@ -1874,7 +1874,7 @@ export default function Page() {
|
||||
|
||||
<Link
|
||||
className="text-sm text-primary flex items-center gap-1"
|
||||
href="https://docs.digpangolin.com/manage/resources/tcp-udp-resources"
|
||||
href="https://docs.pangolin.net/manage/resources/tcp-udp-resources"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -43,7 +43,7 @@ export default async function ResourcesPage(props: ResourcesPageProps) {
|
||||
await authCookieHeader()
|
||||
);
|
||||
resources = res.data.data.resources;
|
||||
} catch (e) {}
|
||||
} catch (e) { }
|
||||
|
||||
let siteResources: ListAllSiteResourcesByOrgResponse["siteResources"] = [];
|
||||
try {
|
||||
@@ -51,7 +51,7 @@ export default async function ResourcesPage(props: ResourcesPageProps) {
|
||||
AxiosResponse<ListAllSiteResourcesByOrgResponse>
|
||||
>(`/org/${params.orgId}/site-resources`, await authCookieHeader());
|
||||
siteResources = res.data.data.siteResources;
|
||||
} catch (e) {}
|
||||
} catch (e) { }
|
||||
|
||||
let org = null;
|
||||
try {
|
||||
@@ -88,8 +88,8 @@ export default async function ResourcesPage(props: ResourcesPageProps) {
|
||||
resource.passwordId !== null ||
|
||||
resource.whitelist ||
|
||||
resource.headerAuthId
|
||||
? "protected"
|
||||
: "not_protected",
|
||||
? "protected"
|
||||
: "not_protected",
|
||||
enabled: resource.enabled,
|
||||
domainId: resource.domainId || undefined,
|
||||
ssl: resource.ssl
|
||||
@@ -128,6 +128,10 @@ export default async function ResourcesPage(props: ResourcesPageProps) {
|
||||
defaultView={
|
||||
env.flags.enableClients ? defaultView : "proxy"
|
||||
}
|
||||
defaultSort={{
|
||||
id: "name",
|
||||
desc: false
|
||||
}}
|
||||
/>
|
||||
</OrgProvider>
|
||||
</>
|
||||
|
||||
@@ -238,7 +238,7 @@ export default function GeneralPage() {
|
||||
"enableDockerSocketDescription"
|
||||
)}{" "}
|
||||
<Link
|
||||
href="https://docs.digpangolin.com/manage/sites/configure-site#docker-socket-integration"
|
||||
href="https://docs.pangolin.net/manage/sites/configure-site#docker-socket-integration"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center"
|
||||
|
||||
@@ -252,43 +252,43 @@ PersistentKeepalive = 5`;
|
||||
const commands = {
|
||||
mac: {
|
||||
All: [
|
||||
`curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
`newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
]
|
||||
// "Intel x64 (amd64)": [
|
||||
// `curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
// `curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
// `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
// ]
|
||||
},
|
||||
linux: {
|
||||
All: [
|
||||
`curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
`newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
]
|
||||
// arm64: [
|
||||
// `curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
// `curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
// `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
// ],
|
||||
// arm32: [
|
||||
// `curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
// `curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
// `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
// ],
|
||||
// arm32v6: [
|
||||
// `curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
// `curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
// `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
// ],
|
||||
// riscv64: [
|
||||
// `curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
// `curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
// `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
// ]
|
||||
},
|
||||
freebsd: {
|
||||
All: [
|
||||
`curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
`curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
`newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
]
|
||||
// arm64: [
|
||||
// `curl -fsSL https://digpangolin.com/get-newt.sh | bash`,
|
||||
// `curl -fsSL https://pangolin.net/get-newt.sh | bash`,
|
||||
// `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}`
|
||||
// ]
|
||||
},
|
||||
|
||||
@@ -326,7 +326,7 @@ export default function PoliciesPage() {
|
||||
{/*TODO(vlalx): Validate replacing */}
|
||||
{t('orgPoliciesAboutDescription')}{" "}
|
||||
<Link
|
||||
href="https://docs.digpangolin.com/manage/identity-providers/auto-provisioning"
|
||||
href="https://docs.pangolin.net/manage/identity-providers/auto-provisioning"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
|
||||
@@ -315,18 +315,13 @@ export default function LicensePage() {
|
||||
setSelectedLicenseKey(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("licenseQuestionRemove", {
|
||||
selectedKey: obfuscateLicenseKey(
|
||||
selectedLicenseKey.licenseKey
|
||||
)
|
||||
})}
|
||||
{t("licenseQuestionRemove")}
|
||||
</p>
|
||||
<p>
|
||||
<b>{t("licenseMessageRemove")}</b>
|
||||
</p>
|
||||
<p>{t("licenseMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("licenseKeyDeleteConfirm")}
|
||||
|
||||
@@ -237,21 +237,14 @@ export default function UsersTable({ users }: Props) {
|
||||
setSelected(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("userQuestionRemove", {
|
||||
selectedUser:
|
||||
selected?.email ||
|
||||
selected?.name ||
|
||||
selected?.username
|
||||
})}
|
||||
{t("userQuestionRemove")}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>{t("userMessageRemove")}</b>
|
||||
{t("userMessageRemove")}
|
||||
</p>
|
||||
|
||||
<p>{t("userMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("userDeleteConfirm")}
|
||||
|
||||
@@ -147,7 +147,7 @@ export default async function OrgAuthPage(props: {
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("poweredBy")}{" "}
|
||||
<Link
|
||||
href="https://digpangolin.com/"
|
||||
href="https://pangolin.net/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
|
||||
@@ -193,7 +193,7 @@ export default function IdpTable({ idps }: Props) {
|
||||
setSelectedIdp(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("idpQuestionRemove", {
|
||||
name: selectedIdp.name
|
||||
|
||||
@@ -256,7 +256,7 @@ export default function UsersTable({ users }: Props) {
|
||||
setSelected(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("userQuestionRemove", {
|
||||
selectedUser:
|
||||
|
||||
@@ -177,19 +177,14 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
|
||||
setSelected(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("apiKeysQuestionRemove", {
|
||||
selectedApiKey:
|
||||
selected?.name || selected?.id
|
||||
})}
|
||||
{t("apiKeysQuestionRemove")}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>{t("apiKeysMessageRemove")}</b>
|
||||
{t("apiKeysMessageRemove")}
|
||||
</p>
|
||||
|
||||
<p>{t("apiKeysMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("apiKeysDeleteConfirm")}
|
||||
|
||||
@@ -277,25 +277,12 @@ export default function ClientsTable({ clients, orgId }: ClientTableProps) {
|
||||
setSelectedClient(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
Are you sure you want to remove the client{" "}
|
||||
<b>
|
||||
{selectedClient?.name || selectedClient?.id}
|
||||
</b>{" "}
|
||||
from the site and organization?
|
||||
{t("deleteClientQuestion")}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Once removed, the client will no longer be
|
||||
able to connect to the site.{" "}
|
||||
</b>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To confirm, please type the name of the client
|
||||
below.
|
||||
{t("clientMessageRemove")}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import { Description } from "@radix-ui/react-toast";
|
||||
import { createApiClient } from "@app/lib/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useTranslations } from "next-intl";
|
||||
import CopyToClipboard from "./CopyToClipboard";
|
||||
|
||||
type InviteUserFormProps = {
|
||||
open: boolean;
|
||||
@@ -110,6 +111,17 @@ export default function InviteUserForm({
|
||||
<CredenzaBody>
|
||||
<div className="mb-4 break-all overflow-hidden">
|
||||
{dialog}
|
||||
<div className="mt-2 mb-6 font-bold text-red-700">
|
||||
{t("cannotbeUndone")}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
{t("type")}
|
||||
<span className="px-2 py-1 rounded-md bg-secondary"><CopyToClipboard text={string} /></span>
|
||||
{t("toConfirm")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form
|
||||
|
||||
@@ -237,16 +237,13 @@ export default function DomainsTable({ domains }: Props) {
|
||||
setSelectedDomain(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("domainQuestionRemove", {
|
||||
domain: selectedDomain.baseDomain
|
||||
})}
|
||||
{t("domainQuestionRemove")}
|
||||
</p>
|
||||
<p>
|
||||
<b>{t("domainMessageRemove")}</b>
|
||||
{t("domainMessageRemove")}
|
||||
</p>
|
||||
<p>{t("domainMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("domainConfirmDelete")}
|
||||
|
||||
@@ -401,7 +401,7 @@ export default function GenerateLicenseKeyForm({
|
||||
{part}
|
||||
{index === 0 && (
|
||||
<a
|
||||
href="https://digpangolin.com/fcl.html"
|
||||
href="https://pangolin.net/fcl.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
@@ -580,7 +580,7 @@ export default function GenerateLicenseKeyForm({
|
||||
"signUpTerms.IAgreeToThe"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/terms-of-service.html"
|
||||
href="https://pangolin.net/terms-of-service.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
@@ -593,7 +593,7 @@ export default function GenerateLicenseKeyForm({
|
||||
"signUpTerms.and"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/privacy-policy.html"
|
||||
href="https://pangolin.net/privacy-policy.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
@@ -637,12 +637,12 @@ export default function GenerateLicenseKeyForm({
|
||||
license
|
||||
details:{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/fcl.html"
|
||||
href="https://pangolin.net/fcl.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
https://digpangolin.com/fcl.html
|
||||
https://pangolin.net/fcl.html
|
||||
</a>
|
||||
</div>
|
||||
</FormLabel>
|
||||
@@ -966,7 +966,7 @@ export default function GenerateLicenseKeyForm({
|
||||
"signUpTerms.IAgreeToThe"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/terms-of-service.html"
|
||||
href="https://pangolin.net/terms-of-service.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
@@ -979,7 +979,7 @@ export default function GenerateLicenseKeyForm({
|
||||
"signUpTerms.and"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/privacy-policy.html"
|
||||
href="https://pangolin.net/privacy-policy.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
@@ -1023,12 +1023,12 @@ export default function GenerateLicenseKeyForm({
|
||||
license
|
||||
details:{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/fcl.html"
|
||||
href="https://pangolin.net/fcl.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
https://digpangolin.com/fcl.html
|
||||
https://pangolin.net/fcl.html
|
||||
</a>
|
||||
</div>
|
||||
</FormLabel>
|
||||
|
||||
@@ -175,14 +175,11 @@ export default function InvitationsTable({
|
||||
setSelectedInvitation(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("inviteQuestionRemove", {
|
||||
email: selectedInvitation?.email || ""
|
||||
})}
|
||||
{t("inviteQuestionRemove")}
|
||||
</p>
|
||||
<p>{t("inviteMessageRemove")}</p>
|
||||
<p>{t("inviteMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("inviteRemoveConfirm")}
|
||||
|
||||
@@ -185,19 +185,14 @@ export default function OrgApiKeysTable({
|
||||
setSelected(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("apiKeysQuestionRemove", {
|
||||
selectedApiKey:
|
||||
selected?.name || selected?.id
|
||||
})}
|
||||
{t("apiKeysQuestionRemove")}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>{t("apiKeysMessageRemove")}</b>
|
||||
{t("apiKeysMessageRemove")}
|
||||
</p>
|
||||
|
||||
<p>{t("apiKeysMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("apiKeysDeleteConfirm")}
|
||||
|
||||
@@ -348,7 +348,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("poweredBy")}{" "}
|
||||
<Link
|
||||
href="https://digpangolin.com/"
|
||||
href="https://pangolin.net/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
@@ -363,7 +363,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{t("poweredBy")}{" "}
|
||||
<Link
|
||||
href="https://digpangolin.com/"
|
||||
href="https://pangolin.net/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
|
||||
@@ -100,6 +100,10 @@ type ResourcesTableProps = {
|
||||
internalResources: InternalResourceRow[];
|
||||
orgId: string;
|
||||
defaultView?: "proxy" | "internal";
|
||||
defaultSort?: {
|
||||
id: string;
|
||||
desc: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -143,7 +147,8 @@ export default function ResourcesTable({
|
||||
resources,
|
||||
internalResources,
|
||||
orgId,
|
||||
defaultView = "proxy"
|
||||
defaultView = "proxy",
|
||||
defaultSort
|
||||
}: ResourcesTableProps) {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -171,12 +176,16 @@ export default function ResourcesTable({
|
||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
||||
const [sites, setSites] = useState<Site[]>([]);
|
||||
|
||||
const [proxySorting, setProxySorting] = useState<SortingState>([]);
|
||||
const [proxySorting, setProxySorting] = useState<SortingState>(
|
||||
defaultSort ? [defaultSort] : []
|
||||
);
|
||||
const [proxyColumnFilters, setProxyColumnFilters] =
|
||||
useState<ColumnFiltersState>([]);
|
||||
const [proxyGlobalFilter, setProxyGlobalFilter] = useState<any>([]);
|
||||
|
||||
const [internalSorting, setInternalSorting] = useState<SortingState>([]);
|
||||
const [internalSorting, setInternalSorting] = useState<SortingState>(
|
||||
defaultSort ? [defaultSort] : []
|
||||
);
|
||||
const [internalColumnFilters, setInternalColumnFilters] =
|
||||
useState<ColumnFiltersState>([]);
|
||||
const [internalGlobalFilter, setInternalGlobalFilter] = useState<any>([]);
|
||||
@@ -695,17 +704,12 @@ export default function ResourcesTable({
|
||||
}}
|
||||
dialog={
|
||||
<div>
|
||||
<p className="mb-2">
|
||||
{t("resourceQuestionRemove", {
|
||||
selectedResource:
|
||||
selectedResource?.name ||
|
||||
selectedResource?.id
|
||||
})}
|
||||
<p>
|
||||
{t("resourceQuestionRemove")}
|
||||
</p>
|
||||
<p>
|
||||
{t("resourceMessageRemove")}
|
||||
</p>
|
||||
|
||||
<p className="mb-2">{t("resourceMessageRemove")}</p>
|
||||
|
||||
<p>{t("resourceMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("resourceDeleteConfirm")}
|
||||
@@ -724,17 +728,12 @@ export default function ResourcesTable({
|
||||
}}
|
||||
dialog={
|
||||
<div>
|
||||
<p className="mb-2">
|
||||
{t("resourceQuestionRemove", {
|
||||
selectedResource:
|
||||
selectedInternalResource?.name ||
|
||||
selectedInternalResource?.id
|
||||
})}
|
||||
<p>
|
||||
{t("resourceQuestionRemove")}
|
||||
</p>
|
||||
<p>
|
||||
{t("resourceMessageRemove")}
|
||||
</p>
|
||||
|
||||
<p className="mb-2">{t("resourceMessageRemove")}</p>
|
||||
|
||||
<p>{t("resourceMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("resourceDeleteConfirm")}
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function SidebarLicenseButton({
|
||||
}: SidebarLicenseButtonProps) {
|
||||
const { licenseStatus, updateLicenseStatus } = useLicenseStatusContext();
|
||||
|
||||
const url = "https://docs.digpangolin.com/self-host/enterprise-edition";
|
||||
const url = "https://docs.pangolin.net/self-host/enterprise-edition";
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
|
||||
@@ -512,7 +512,7 @@ export default function SignupForm({
|
||||
"signUpTerms.IAgreeToThe"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/terms-of-service.html"
|
||||
href="https://pangolin.net/terms-of-service.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
@@ -523,7 +523,7 @@ export default function SignupForm({
|
||||
</a>
|
||||
{t("signUpTerms.and")}{" "}
|
||||
<a
|
||||
href="https://digpangolin.com/privacy-policy.html"
|
||||
href="https://pangolin.net/privacy-policy.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
|
||||
@@ -64,7 +64,7 @@ export const SitesSplashCard = () => {
|
||||
|
||||
<div className="mt-4">
|
||||
<Link
|
||||
href="https://docs.digpangolin.com/manage/sites/install-site"
|
||||
href="https://docs.pangolin.net/manage/sites/install-site"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -418,17 +418,11 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
|
||||
setSelectedSite(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div className="">
|
||||
<p>
|
||||
{t("siteQuestionRemove", {
|
||||
selectedSite:
|
||||
selectedSite?.name || selectedSite?.id
|
||||
})}
|
||||
{t("siteQuestionRemove")}
|
||||
</p>
|
||||
|
||||
<p>{t("siteMessageRemove")}</p>
|
||||
|
||||
<p>{t("siteMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("siteConfirmDelete")}
|
||||
|
||||
@@ -219,7 +219,7 @@ export default function SupporterStatus({ isCollapsed = false }: SupporterStatus
|
||||
</Link>{" "}
|
||||
{t('supportKeyPurchase2')}{" "}
|
||||
<Link
|
||||
href="https://docs.digpangolin.com/self-host/supporter-program"
|
||||
href="https://docs.pangolin.net/self-host/supporter-program"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
|
||||
@@ -273,20 +273,11 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
setSelectedUser(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("userQuestionOrgRemove", {
|
||||
email:
|
||||
selectedUser?.email ||
|
||||
selectedUser?.name ||
|
||||
selectedUser?.username ||
|
||||
""
|
||||
})}
|
||||
{t("userQuestionOrgRemove")}
|
||||
</p>
|
||||
|
||||
<p>{t("userMessageOrgRemove")}</p>
|
||||
|
||||
<p>{t("userMessageOrgConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("userRemoveOrgConfirm")}
|
||||
|
||||
@@ -177,16 +177,13 @@ export default function IdpTable({ idps, orgId }: Props) {
|
||||
setSelectedIdp(null);
|
||||
}}
|
||||
dialog={
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p>
|
||||
{t("idpQuestionRemove", {
|
||||
name: selectedIdp.name
|
||||
})}
|
||||
{t("idpQuestionRemove")}
|
||||
</p>
|
||||
<p>
|
||||
<b>{t("idpMessageRemove")}</b>
|
||||
{t("idpMessageRemove")}
|
||||
</p>
|
||||
<p>{t("idpMessageConfirm")}</p>
|
||||
</div>
|
||||
}
|
||||
buttonText={t("idpConfirmDelete")}
|
||||
|
||||
Reference in New Issue
Block a user