Compare commits

..

4 Commits

Author SHA1 Message Date
Owen
b01fcc70fe Fix ts and add note about ipv4 2026-03-03 14:45:18 -08:00
Owen
35fed74e49 Merge branch 'dev' into msg-opt 2026-03-02 18:52:35 -08:00
Owen
6cf1b9b010 Support improved targets msg v2 2026-03-02 18:51:48 -08:00
Owen
dae169540b Fix defaults for orgs 2026-03-02 16:49:17 -08:00
125 changed files with 491 additions and 461 deletions

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Прокси заявки чрез HTTPS, използвайки напълно квалифицирано име на домейн.", "resourceHTTPDescription": "Прокси заявки чрез HTTPS, използвайки напълно квалифицирано име на домейн.",
"resourceRaw": "Суров TCP/UDP ресурс", "resourceRaw": "Суров TCP/UDP ресурс",
"resourceRawDescription": "Прокси заявки чрез сурови TCP/UDP, използвайки порт номер.", "resourceRawDescription": "Прокси заявки чрез сурови TCP/UDP, използвайки порт номер.",
"resourceRawDescriptionCloud": "Прокси заявките през суров TCP/UDP, използвайки номер на порт. ИЗИСКВА ИЗПОЛЗВАНЕ НА ОТДАЛЕЧЕН УЗЕЛ.",
"resourceCreate": "Създайте ресурс", "resourceCreate": "Създайте ресурс",
"resourceCreateDescription": "Следвайте стъпките по-долу, за да създадете нов ресурс", "resourceCreateDescription": "Следвайте стъпките по-долу, за да създадете нов ресурс",
"resourceSeeAll": "Вижте всички ресурси", "resourceSeeAll": "Вижте всички ресурси",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Получаване на потребител", "actionGetUser": "Получаване на потребител",
"actionGetOrgUser": "Вземете потребител на организация", "actionGetOrgUser": "Вземете потребител на организация",
"actionListOrgDomains": "Изброяване на домейни на организация", "actionListOrgDomains": "Изброяване на домейни на организация",
"actionGetDomain": "Вземи домейн",
"actionCreateOrgDomain": "Създай домейн",
"actionUpdateOrgDomain": "Актуализирай домейн",
"actionDeleteOrgDomain": "Изтрий домейн",
"actionGetDNSRecords": "Вземи DNS записи",
"actionRestartOrgDomain": "Рестартирай домейн",
"actionCreateSite": "Създаване на сайт", "actionCreateSite": "Създаване на сайт",
"actionDeleteSite": "Изтриване на сайта", "actionDeleteSite": "Изтриване на сайта",
"actionGetSite": "Вземете сайт", "actionGetSite": "Вземете сайт",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Потребителят може да изпълнява само определени команди с sudo.", "sshSudoModeCommandsDescription": "Потребителят може да изпълнява само определени команди с sudo.",
"sshSudo": "Разреши sudo", "sshSudo": "Разреши sudo",
"sshSudoCommands": "Sudo команди", "sshSudoCommands": "Sudo команди",
"sshSudoCommandsDescription": "Списък, разделен със запетаи, с команди, които потребителят е позволено да изпълнява с sudo.", "sshSudoCommandsDescription": "Списък с команди, които потребителят е разрешено да изпълнява с sudo.",
"sshCreateHomeDir": "Създай начална директория", "sshCreateHomeDir": "Създай начална директория",
"sshUnixGroups": "Unix групи", "sshUnixGroups": "Unix групи",
"sshUnixGroupsDescription": "Списък, разделен със запетаи, с Unix групи, към които да се добави потребителят на целевия хост.", "sshUnixGroupsDescription": "Unix групи, в които да добавите потребителя на целевия хост.",
"retryAttempts": "Опити за повторно", "retryAttempts": "Опити за повторно",
"expectedResponseCodes": "Очаквани кодове за отговор", "expectedResponseCodes": "Очаквани кодове за отговор",
"expectedResponseCodesDescription": "HTTP статус код, указващ здравословно състояние. Ако бъде оставено празно, между 200-300 се счита за здравословно.", "expectedResponseCodesDescription": "HTTP статус код, указващ здравословно състояние. Ако бъде оставено празно, между 200-300 се счита за здравословно.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy požadavky přes HTTPS pomocí plně kvalifikovaného názvu domény.", "resourceHTTPDescription": "Proxy požadavky přes HTTPS pomocí plně kvalifikovaného názvu domény.",
"resourceRaw": "Surový TCP/UDP zdroj", "resourceRaw": "Surový TCP/UDP zdroj",
"resourceRawDescription": "Proxy požadavky přes nezpracovaný TCP/UDP pomocí čísla portu.", "resourceRawDescription": "Proxy požadavky přes nezpracovaný TCP/UDP pomocí čísla portu.",
"resourceRawDescriptionCloud": "Požadavky na proxy přes syrové TCP/UDP pomocí portového čísla. ŽÁDOSTI POUŽÍVAT POUŽITÍ Z REMOTE NODE.",
"resourceCreate": "Vytvořit zdroj", "resourceCreate": "Vytvořit zdroj",
"resourceCreateDescription": "Postupujte podle níže uvedených kroků, abyste vytvořili a připojili nový zdroj", "resourceCreateDescription": "Postupujte podle níže uvedených kroků, abyste vytvořili a připojili nový zdroj",
"resourceSeeAll": "Zobrazit všechny zdroje", "resourceSeeAll": "Zobrazit všechny zdroje",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Získat uživatele", "actionGetUser": "Získat uživatele",
"actionGetOrgUser": "Získat uživatele organizace", "actionGetOrgUser": "Získat uživatele organizace",
"actionListOrgDomains": "Seznam domén organizace", "actionListOrgDomains": "Seznam domén organizace",
"actionGetDomain": "Získat doménu",
"actionCreateOrgDomain": "Vytvořit doménu",
"actionUpdateOrgDomain": "Aktualizovat doménu",
"actionDeleteOrgDomain": "Odstranit doménu",
"actionGetDNSRecords": "Získat záznamy DNS",
"actionRestartOrgDomain": "Restartovat doménu",
"actionCreateSite": "Vytvořit lokalitu", "actionCreateSite": "Vytvořit lokalitu",
"actionDeleteSite": "Odstranění lokality", "actionDeleteSite": "Odstranění lokality",
"actionGetSite": "Získat web", "actionGetSite": "Získat web",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Uživatel může spustit pouze zadané příkazy s sudo.", "sshSudoModeCommandsDescription": "Uživatel může spustit pouze zadané příkazy s sudo.",
"sshSudo": "Povolit sudo", "sshSudo": "Povolit sudo",
"sshSudoCommands": "Sudo příkazy", "sshSudoCommands": "Sudo příkazy",
"sshSudoCommandsDescription": "Čárkami oddělený seznam příkazů, které může uživatel spouštět s sudo.", "sshSudoCommandsDescription": "Seznam příkazů, které může uživatel spouštět s sudo.",
"sshCreateHomeDir": "Vytvořit domovský adresář", "sshCreateHomeDir": "Vytvořit domovský adresář",
"sshUnixGroups": "Unixové skupiny", "sshUnixGroups": "Unixové skupiny",
"sshUnixGroupsDescription": "Čárkou oddělené skupiny Unix přidají uživatele do cílového hostitele.", "sshUnixGroupsDescription": "Unix skupiny přidají uživatele do cílového hostitele.",
"retryAttempts": "Opakovat pokusy", "retryAttempts": "Opakovat pokusy",
"expectedResponseCodes": "Očekávané kódy odezvy", "expectedResponseCodes": "Očekávané kódy odezvy",
"expectedResponseCodesDescription": "HTTP kód stavu, který označuje zdravý stav. Ponecháte-li prázdné, 200-300 je považováno za zdravé.", "expectedResponseCodesDescription": "HTTP kód stavu, který označuje zdravý stav. Ponecháte-li prázdné, 200-300 je považováno za zdravé.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy-Anfragen über HTTPS mit einem voll qualifizierten Domain-Namen.", "resourceHTTPDescription": "Proxy-Anfragen über HTTPS mit einem voll qualifizierten Domain-Namen.",
"resourceRaw": "Direkte TCP/UDP Ressource (raw)", "resourceRaw": "Direkte TCP/UDP Ressource (raw)",
"resourceRawDescription": "Proxy-Anfragen über rohes TCP/UDP mit einer Portnummer.", "resourceRawDescription": "Proxy-Anfragen über rohes TCP/UDP mit einer Portnummer.",
"resourceRawDescriptionCloud": "Proxy-Anfragen über rohe TCP/UDP mit einer Portnummer. Erfordert die NUTZUNG eines REMOTE Knotens.",
"resourceCreate": "Ressource erstellen", "resourceCreate": "Ressource erstellen",
"resourceCreateDescription": "Folgen Sie den Schritten unten, um eine neue Ressource zu erstellen", "resourceCreateDescription": "Folgen Sie den Schritten unten, um eine neue Ressource zu erstellen",
"resourceSeeAll": "Alle Ressourcen anzeigen", "resourceSeeAll": "Alle Ressourcen anzeigen",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Benutzer abrufen", "actionGetUser": "Benutzer abrufen",
"actionGetOrgUser": "Organisationsbenutzer abrufen", "actionGetOrgUser": "Organisationsbenutzer abrufen",
"actionListOrgDomains": "Organisationsdomains auflisten", "actionListOrgDomains": "Organisationsdomains auflisten",
"actionGetDomain": "Domain abrufen",
"actionCreateOrgDomain": "Domain erstellen",
"actionUpdateOrgDomain": "Domain aktualisieren",
"actionDeleteOrgDomain": "Domain löschen",
"actionGetDNSRecords": "DNS-Einträge abrufen",
"actionRestartOrgDomain": "Domain neu starten",
"actionCreateSite": "Standort erstellen", "actionCreateSite": "Standort erstellen",
"actionDeleteSite": "Standort löschen", "actionDeleteSite": "Standort löschen",
"actionGetSite": "Standort abrufen", "actionGetSite": "Standort abrufen",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Benutzer kann nur die angegebenen Befehle mit sudo ausführen.", "sshSudoModeCommandsDescription": "Benutzer kann nur die angegebenen Befehle mit sudo ausführen.",
"sshSudo": "sudo erlauben", "sshSudo": "sudo erlauben",
"sshSudoCommands": "Sudo-Befehle", "sshSudoCommands": "Sudo-Befehle",
"sshSudoCommandsDescription": "Kommagetrennte Liste von Befehlen, die der Benutzer mit sudo ausführen darf.", "sshSudoCommandsDescription": "Liste der Befehle, die der Benutzer mit sudo ausführen darf.",
"sshCreateHomeDir": "Home-Verzeichnis erstellen", "sshCreateHomeDir": "Home-Verzeichnis erstellen",
"sshUnixGroups": "Unix-Gruppen", "sshUnixGroups": "Unix-Gruppen",
"sshUnixGroupsDescription": "Durch Komma getrennte Unix-Gruppen, um den Benutzer auf dem Zielhost hinzuzufügen.", "sshUnixGroupsDescription": "Unix-Gruppen, zu denen der Benutzer auf dem Ziel-Host hinzugefügt wird.",
"retryAttempts": "Wiederholungsversuche", "retryAttempts": "Wiederholungsversuche",
"expectedResponseCodes": "Erwartete Antwortcodes", "expectedResponseCodes": "Erwartete Antwortcodes",
"expectedResponseCodesDescription": "HTTP-Statuscode, der einen gesunden Zustand anzeigt. Wenn leer gelassen, wird 200-300 als gesund angesehen.", "expectedResponseCodesDescription": "HTTP-Statuscode, der einen gesunden Zustand anzeigt. Wenn leer gelassen, wird 200-300 als gesund angesehen.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy requests over HTTPS using a fully qualified domain name.", "resourceHTTPDescription": "Proxy requests over HTTPS using a fully qualified domain name.",
"resourceRaw": "Raw TCP/UDP Resource", "resourceRaw": "Raw TCP/UDP Resource",
"resourceRawDescription": "Proxy requests over raw TCP/UDP using a port number.", "resourceRawDescription": "Proxy requests over raw TCP/UDP using a port number.",
"resourceRawDescriptionCloud": "Proxy requests over raw TCP/UDP using a port number. REQUIRES THE USE OF A REMOTE NODE.",
"resourceCreate": "Create Resource", "resourceCreate": "Create Resource",
"resourceCreateDescription": "Follow the steps below to create a new resource", "resourceCreateDescription": "Follow the steps below to create a new resource",
"resourceSeeAll": "See All Resources", "resourceSeeAll": "See All Resources",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy proporciona solicitudes sobre HTTPS usando un nombre de dominio completamente calificado.", "resourceHTTPDescription": "Proxy proporciona solicitudes sobre HTTPS usando un nombre de dominio completamente calificado.",
"resourceRaw": "Recurso TCP/UDP sin procesar", "resourceRaw": "Recurso TCP/UDP sin procesar",
"resourceRawDescription": "Proxy proporciona solicitudes sobre TCP/UDP usando un número de puerto.", "resourceRawDescription": "Proxy proporciona solicitudes sobre TCP/UDP usando un número de puerto.",
"resourceRawDescriptionCloud": "Las peticiones de proxy sobre TCP/UDP crudas usando un número de puerto. REQUIERE EL USO DE UN NODO REMOTE.",
"resourceCreate": "Crear Recurso", "resourceCreate": "Crear Recurso",
"resourceCreateDescription": "Siga los siguientes pasos para crear un nuevo recurso", "resourceCreateDescription": "Siga los siguientes pasos para crear un nuevo recurso",
"resourceSeeAll": "Ver todos los recursos", "resourceSeeAll": "Ver todos los recursos",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Obtener usuario", "actionGetUser": "Obtener usuario",
"actionGetOrgUser": "Obtener usuario de la organización", "actionGetOrgUser": "Obtener usuario de la organización",
"actionListOrgDomains": "Listar dominios de la organización", "actionListOrgDomains": "Listar dominios de la organización",
"actionGetDomain": "Obtener dominio",
"actionCreateOrgDomain": "Crear dominio",
"actionUpdateOrgDomain": "Actualizar dominio",
"actionDeleteOrgDomain": "Eliminar dominio",
"actionGetDNSRecords": "Obtener registros DNS",
"actionRestartOrgDomain": "Reiniciar dominio",
"actionCreateSite": "Crear sitio", "actionCreateSite": "Crear sitio",
"actionDeleteSite": "Eliminar sitio", "actionDeleteSite": "Eliminar sitio",
"actionGetSite": "Obtener sitio", "actionGetSite": "Obtener sitio",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "El usuario sólo puede ejecutar los comandos especificados con sudo.", "sshSudoModeCommandsDescription": "El usuario sólo puede ejecutar los comandos especificados con sudo.",
"sshSudo": "Permitir sudo", "sshSudo": "Permitir sudo",
"sshSudoCommands": "Comandos Sudo", "sshSudoCommands": "Comandos Sudo",
"sshSudoCommandsDescription": "Lista separada por comas de comandos que el usuario puede ejecutar con sudo.", "sshSudoCommandsDescription": "Lista de comandos que el usuario puede ejecutar con sudo.",
"sshCreateHomeDir": "Crear directorio principal", "sshCreateHomeDir": "Crear directorio principal",
"sshUnixGroups": "Grupos Unix", "sshUnixGroups": "Grupos Unix",
"sshUnixGroupsDescription": "Grupos Unix separados por comas para agregar el usuario en el host de destino.", "sshUnixGroupsDescription": "Grupos Unix para agregar el usuario en el host de destino.",
"retryAttempts": "Intentos de Reintento", "retryAttempts": "Intentos de Reintento",
"expectedResponseCodes": "Códigos de respuesta esperados", "expectedResponseCodes": "Códigos de respuesta esperados",
"expectedResponseCodesDescription": "Código de estado HTTP que indica un estado saludable. Si se deja en blanco, se considera saludable de 200 a 300.", "expectedResponseCodesDescription": "Código de estado HTTP que indica un estado saludable. Si se deja en blanco, se considera saludable de 200 a 300.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy les demandes sur HTTPS en utilisant un nom de domaine entièrement qualifié.", "resourceHTTPDescription": "Proxy les demandes sur HTTPS en utilisant un nom de domaine entièrement qualifié.",
"resourceRaw": "Ressource TCP/UDP brute", "resourceRaw": "Ressource TCP/UDP brute",
"resourceRawDescription": "Proxy les demandes sur TCP/UDP brut en utilisant un numéro de port.", "resourceRawDescription": "Proxy les demandes sur TCP/UDP brut en utilisant un numéro de port.",
"resourceRawDescriptionCloud": "Requêtes de proxy sur TCP/UDP brute en utilisant un numéro de port. REQUISE L'UTILISATION D'UN Nœud DE REMOTE.",
"resourceCreate": "Créer une ressource", "resourceCreate": "Créer une ressource",
"resourceCreateDescription": "Suivez les étapes ci-dessous pour créer une nouvelle ressource", "resourceCreateDescription": "Suivez les étapes ci-dessous pour créer une nouvelle ressource",
"resourceSeeAll": "Voir toutes les ressources", "resourceSeeAll": "Voir toutes les ressources",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Obtenir l'utilisateur", "actionGetUser": "Obtenir l'utilisateur",
"actionGetOrgUser": "Obtenir l'utilisateur de l'organisation", "actionGetOrgUser": "Obtenir l'utilisateur de l'organisation",
"actionListOrgDomains": "Lister les domaines de l'organisation", "actionListOrgDomains": "Lister les domaines de l'organisation",
"actionGetDomain": "Obtenir un domaine",
"actionCreateOrgDomain": "Créer un domaine",
"actionUpdateOrgDomain": "Mettre à jour le domaine",
"actionDeleteOrgDomain": "Supprimer le domaine",
"actionGetDNSRecords": "Récupérer les enregistrements DNS",
"actionRestartOrgDomain": "Redémarrer le domaine",
"actionCreateSite": "Créer un site", "actionCreateSite": "Créer un site",
"actionDeleteSite": "Supprimer un site", "actionDeleteSite": "Supprimer un site",
"actionGetSite": "Obtenir un site", "actionGetSite": "Obtenir un site",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "L'utilisateur ne peut exécuter que les commandes spécifiées avec sudo.", "sshSudoModeCommandsDescription": "L'utilisateur ne peut exécuter que les commandes spécifiées avec sudo.",
"sshSudo": "Autoriser sudo", "sshSudo": "Autoriser sudo",
"sshSudoCommands": "Commandes Sudo", "sshSudoCommands": "Commandes Sudo",
"sshSudoCommandsDescription": "Liste des commandes séparées par des virgules que l'utilisateur est autorisé à exécuter avec sudo.", "sshSudoCommandsDescription": "Liste des commandes que l'utilisateur est autorisé à exécuter avec sudo.",
"sshCreateHomeDir": "Créer un répertoire personnel", "sshCreateHomeDir": "Créer un répertoire personnel",
"sshUnixGroups": "Groupes Unix", "sshUnixGroups": "Groupes Unix",
"sshUnixGroupsDescription": "Groupes Unix séparés par des virgules pour ajouter l'utilisateur sur l'hôte cible.", "sshUnixGroupsDescription": "Groupes Unix à ajouter à l'utilisateur sur l'hôte cible.",
"retryAttempts": "Tentatives de réessai", "retryAttempts": "Tentatives de réessai",
"expectedResponseCodes": "Codes de réponse attendus", "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.", "expectedResponseCodesDescription": "Code de statut HTTP indiquant un état de santé satisfaisant. Si non renseigné, 200-300 est considéré comme satisfaisant.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Richieste proxy su HTTPS usando un nome di dominio completo.", "resourceHTTPDescription": "Richieste proxy su HTTPS usando un nome di dominio completo.",
"resourceRaw": "Risorsa Raw TCP/UDP", "resourceRaw": "Risorsa Raw TCP/UDP",
"resourceRawDescription": "Richieste proxy su TCP/UDP grezzo utilizzando un numero di porta.", "resourceRawDescription": "Richieste proxy su TCP/UDP grezzo utilizzando un numero di porta.",
"resourceRawDescriptionCloud": "Richieste proxy su TCP/UDP grezzo utilizzando un numero di porta. RICHIEDE L'USO DI UN NODO REMOTO.",
"resourceCreate": "Crea Risorsa", "resourceCreate": "Crea Risorsa",
"resourceCreateDescription": "Segui i passaggi seguenti per creare una nuova risorsa", "resourceCreateDescription": "Segui i passaggi seguenti per creare una nuova risorsa",
"resourceSeeAll": "Vedi Tutte Le Risorse", "resourceSeeAll": "Vedi Tutte Le Risorse",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Ottieni Utente", "actionGetUser": "Ottieni Utente",
"actionGetOrgUser": "Ottieni Utente Organizzazione", "actionGetOrgUser": "Ottieni Utente Organizzazione",
"actionListOrgDomains": "Elenca Domini Organizzazione", "actionListOrgDomains": "Elenca Domini Organizzazione",
"actionGetDomain": "Ottieni Dominio",
"actionCreateOrgDomain": "Crea Dominio",
"actionUpdateOrgDomain": "Aggiorna Dominio",
"actionDeleteOrgDomain": "Elimina Dominio",
"actionGetDNSRecords": "Ottieni Record DNS",
"actionRestartOrgDomain": "Riavvia Dominio",
"actionCreateSite": "Crea Sito", "actionCreateSite": "Crea Sito",
"actionDeleteSite": "Elimina Sito", "actionDeleteSite": "Elimina Sito",
"actionGetSite": "Ottieni Sito", "actionGetSite": "Ottieni Sito",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "L'utente può eseguire solo i comandi specificati con sudo.", "sshSudoModeCommandsDescription": "L'utente può eseguire solo i comandi specificati con sudo.",
"sshSudo": "Consenti sudo", "sshSudo": "Consenti sudo",
"sshSudoCommands": "Comandi Sudo", "sshSudoCommands": "Comandi Sudo",
"sshSudoCommandsDescription": "Elenco di comandi separati da virgole che l'utente può eseguire con sudo.", "sshSudoCommandsDescription": "Elenco di comandi che l'utente può eseguire con sudo.",
"sshCreateHomeDir": "Crea Cartella Home", "sshCreateHomeDir": "Crea Cartella Home",
"sshUnixGroups": "Gruppi Unix", "sshUnixGroups": "Gruppi Unix",
"sshUnixGroupsDescription": "Gruppi Unix separati da virgole per aggiungere l'utente sull'host di destinazione.", "sshUnixGroupsDescription": "Gruppi Unix su cui aggiungere l'utente sull'host di destinazione.",
"retryAttempts": "Tentativi di Riprova", "retryAttempts": "Tentativi di Riprova",
"expectedResponseCodes": "Codici di Risposta Attesi", "expectedResponseCodes": "Codici di Risposta Attesi",
"expectedResponseCodesDescription": "Codice di stato HTTP che indica lo stato di salute. Se lasciato vuoto, considerato sano è compreso tra 200-300.", "expectedResponseCodesDescription": "Codice di stato HTTP che indica lo stato di salute. Se lasciato vuoto, considerato sano è compreso tra 200-300.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "완전한 도메인 이름을 사용해 RAW 또는 HTTPS로 프록시 요청을 수행합니다.", "resourceHTTPDescription": "완전한 도메인 이름을 사용해 RAW 또는 HTTPS로 프록시 요청을 수행합니다.",
"resourceRaw": "원시 TCP/UDP 리소스", "resourceRaw": "원시 TCP/UDP 리소스",
"resourceRawDescription": "포트 번호를 사용하여 RAW TCP/UDP로 요청을 프록시합니다.", "resourceRawDescription": "포트 번호를 사용하여 RAW TCP/UDP로 요청을 프록시합니다.",
"resourceRawDescriptionCloud": "원시 TCP/UDP를 포트 번호를 사용하여 프록시 요청합니다. 원격 노드 사용이 필요합니다.",
"resourceCreate": "리소스 생성", "resourceCreate": "리소스 생성",
"resourceCreateDescription": "아래 단계를 따라 새 리소스를 생성하세요.", "resourceCreateDescription": "아래 단계를 따라 새 리소스를 생성하세요.",
"resourceSeeAll": "모든 리소스 보기", "resourceSeeAll": "모든 리소스 보기",
@@ -1102,12 +1101,6 @@
"actionGetUser": "사용자 조회", "actionGetUser": "사용자 조회",
"actionGetOrgUser": "조직 사용자 가져오기", "actionGetOrgUser": "조직 사용자 가져오기",
"actionListOrgDomains": "조직 도메인 목록", "actionListOrgDomains": "조직 도메인 목록",
"actionGetDomain": "도메인 가져오기",
"actionCreateOrgDomain": "도메인 생성",
"actionUpdateOrgDomain": "도메인 업데이트",
"actionDeleteOrgDomain": "도메인 삭제",
"actionGetDNSRecords": "DNS 레코드 가져오기",
"actionRestartOrgDomain": "도메인 재시작",
"actionCreateSite": "사이트 생성", "actionCreateSite": "사이트 생성",
"actionDeleteSite": "사이트 삭제", "actionDeleteSite": "사이트 삭제",
"actionGetSite": "사이트 가져오기", "actionGetSite": "사이트 가져오기",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "사용자는 sudo로 지정된 명령만 실행할 수 있습니다.", "sshSudoModeCommandsDescription": "사용자는 sudo로 지정된 명령만 실행할 수 있습니다.",
"sshSudo": "Sudo 허용", "sshSudo": "Sudo 허용",
"sshSudoCommands": "Sudo 명령", "sshSudoCommands": "Sudo 명령",
"sshSudoCommandsDescription": "사용자가 sudo로 실행할 수 있는 명령어의 쉼표로 구분된 목록입니다.", "sshSudoCommandsDescription": "사용자가 sudo로 실행할 수 있도록 허용된 명령 목록입니다.",
"sshCreateHomeDir": "홈 디렉터리 생성", "sshCreateHomeDir": "홈 디렉터리 생성",
"sshUnixGroups": "유닉스 그룹", "sshUnixGroups": "유닉스 그룹",
"sshUnixGroupsDescription": "대상 호스트에서 사용자에게 추가할 유닉스 그룹의 쉼표로 구분된 목록입니다.", "sshUnixGroupsDescription": "대상 호스트에서 사용자 추가할 유닉스 그룹입니다.",
"retryAttempts": "재시도 횟수", "retryAttempts": "재시도 횟수",
"expectedResponseCodes": "예상 응답 코드", "expectedResponseCodes": "예상 응답 코드",
"expectedResponseCodesDescription": "정상 상태를 나타내는 HTTP 상태 코드입니다. 비워 두면 200-300이 정상으로 간주됩니다.", "expectedResponseCodesDescription": "정상 상태를 나타내는 HTTP 상태 코드입니다. 비워 두면 200-300이 정상으로 간주됩니다.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy forespørsler over HTTPS ved å bruke et fullstendig kvalifisert domenenavn.", "resourceHTTPDescription": "Proxy forespørsler over HTTPS ved å bruke et fullstendig kvalifisert domenenavn.",
"resourceRaw": "Rå TCP/UDP-ressurs", "resourceRaw": "Rå TCP/UDP-ressurs",
"resourceRawDescription": "Proxy forespørsler over rå TCP/UDP ved å bruke et portnummer.", "resourceRawDescription": "Proxy forespørsler over rå TCP/UDP ved å bruke et portnummer.",
"resourceRawDescriptionCloud": "Proxy ber om et portnummer. Om du vil bruke et sportsnummer.",
"resourceCreate": "Opprett ressurs", "resourceCreate": "Opprett ressurs",
"resourceCreateDescription": "Følg trinnene nedenfor for å opprette en ny ressurs", "resourceCreateDescription": "Følg trinnene nedenfor for å opprette en ny ressurs",
"resourceSeeAll": "Se alle ressurser", "resourceSeeAll": "Se alle ressurser",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Hent bruker", "actionGetUser": "Hent bruker",
"actionGetOrgUser": "Hent organisasjonsbruker", "actionGetOrgUser": "Hent organisasjonsbruker",
"actionListOrgDomains": "List opp organisasjonsdomener", "actionListOrgDomains": "List opp organisasjonsdomener",
"actionGetDomain": "Få Domene",
"actionCreateOrgDomain": "Opprett domene",
"actionUpdateOrgDomain": "Oppdater domene",
"actionDeleteOrgDomain": "Slett domene",
"actionGetDNSRecords": "Hent DNS-oppføringer",
"actionRestartOrgDomain": "Omstart Domene",
"actionCreateSite": "Opprett område", "actionCreateSite": "Opprett område",
"actionDeleteSite": "Slett område", "actionDeleteSite": "Slett område",
"actionGetSite": "Hent område", "actionGetSite": "Hent område",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Brukeren kan bare kjøre de angitte kommandoene med sudo.", "sshSudoModeCommandsDescription": "Brukeren kan bare kjøre de angitte kommandoene med sudo.",
"sshSudo": "Tillat sudo", "sshSudo": "Tillat sudo",
"sshSudoCommands": "Sudo kommandoer", "sshSudoCommands": "Sudo kommandoer",
"sshSudoCommandsDescription": "Kommaseparert liste med kommandoer brukeren kan kjøre med sudo.", "sshSudoCommandsDescription": "Liste av kommandoer brukeren har lov til å kjøre med sudo.",
"sshCreateHomeDir": "Opprett hjemmappe", "sshCreateHomeDir": "Opprett hjemmappe",
"sshUnixGroups": "Unix grupper", "sshUnixGroups": "Unix grupper",
"sshUnixGroupsDescription": "Kommaseparerte Unix grupper for å legge brukeren til mål-verten.", "sshUnixGroupsDescription": "Unix grupper for å legge til brukeren til målverten.",
"retryAttempts": "Forsøk på nytt", "retryAttempts": "Forsøk på nytt",
"expectedResponseCodes": "Forventede svarkoder", "expectedResponseCodes": "Forventede svarkoder",
"expectedResponseCodesDescription": "HTTP-statuskode som indikerer sunn status. Hvis den blir stående tom, regnes 200-300 som sunn.", "expectedResponseCodesDescription": "HTTP-statuskode som indikerer sunn status. Hvis den blir stående tom, regnes 200-300 som sunn.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxyverzoeken via HTTPS met een volledig gekwalificeerde domeinnaam.", "resourceHTTPDescription": "Proxyverzoeken via HTTPS met een volledig gekwalificeerde domeinnaam.",
"resourceRaw": "TCP/UDP bron", "resourceRaw": "TCP/UDP bron",
"resourceRawDescription": "Proxyverzoeken via ruwe TCP/UDP met een poortnummer.", "resourceRawDescription": "Proxyverzoeken via ruwe TCP/UDP met een poortnummer.",
"resourceRawDescriptionCloud": "Proxy vraagt om onbewerkte TCP/UDP met behulp van een poortnummer. VEREIST HET GEBRUIK VAN EEN AFSTANDSBEDIENING NODE.",
"resourceCreate": "Bron maken", "resourceCreate": "Bron maken",
"resourceCreateDescription": "Volg de onderstaande stappen om een nieuwe bron te maken", "resourceCreateDescription": "Volg de onderstaande stappen om een nieuwe bron te maken",
"resourceSeeAll": "Alle bronnen bekijken", "resourceSeeAll": "Alle bronnen bekijken",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Gebruiker ophalen", "actionGetUser": "Gebruiker ophalen",
"actionGetOrgUser": "Krijg organisatie-gebruiker", "actionGetOrgUser": "Krijg organisatie-gebruiker",
"actionListOrgDomains": "Lijst organisatie domeinen", "actionListOrgDomains": "Lijst organisatie domeinen",
"actionGetDomain": "Domein verkrijgen",
"actionCreateOrgDomain": "Domein aanmaken",
"actionUpdateOrgDomain": "Domein bijwerken",
"actionDeleteOrgDomain": "Domein verwijderen",
"actionGetDNSRecords": "Krijg DNS Records",
"actionRestartOrgDomain": "Domein opnieuw starten",
"actionCreateSite": "Site aanmaken", "actionCreateSite": "Site aanmaken",
"actionDeleteSite": "Site verwijderen", "actionDeleteSite": "Site verwijderen",
"actionGetSite": "Site ophalen", "actionGetSite": "Site ophalen",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Gebruiker kan alleen de opgegeven commando's uitvoeren met de sudo.", "sshSudoModeCommandsDescription": "Gebruiker kan alleen de opgegeven commando's uitvoeren met de sudo.",
"sshSudo": "sudo toestaan", "sshSudo": "sudo toestaan",
"sshSudoCommands": "Sudo Commando's", "sshSudoCommands": "Sudo Commando's",
"sshSudoCommandsDescription": "Komma's gescheiden lijst van commando's waar de gebruiker een sudo mee mag uitvoeren.", "sshSudoCommandsDescription": "Lijst van commando's die de gebruiker mag uitvoeren met een sudo.",
"sshCreateHomeDir": "Maak Home Directory", "sshCreateHomeDir": "Maak Home Directory",
"sshUnixGroups": "Unix groepen", "sshUnixGroups": "Unix groepen",
"sshUnixGroupsDescription": "Door komma's gescheiden Unix-groepen om de gebruiker toe te voegen aan de doelhost.", "sshUnixGroupsDescription": "Unix groepen om de gebruiker toe te voegen aan de doel host.",
"retryAttempts": "Herhaal Pogingen", "retryAttempts": "Herhaal Pogingen",
"expectedResponseCodes": "Verwachte Reactiecodes", "expectedResponseCodes": "Verwachte Reactiecodes",
"expectedResponseCodesDescription": "HTTP-statuscode die gezonde status aangeeft. Indien leeg wordt 200-300 als gezond beschouwd.", "expectedResponseCodesDescription": "HTTP-statuscode die gezonde status aangeeft. Indien leeg wordt 200-300 als gezond beschouwd.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxy zapytań przez HTTPS przy użyciu w pełni kwalifikowanej nazwy domeny.", "resourceHTTPDescription": "Proxy zapytań przez HTTPS przy użyciu w pełni kwalifikowanej nazwy domeny.",
"resourceRaw": "Surowy zasób TCP/UDP", "resourceRaw": "Surowy zasób TCP/UDP",
"resourceRawDescription": "Proxy zapytań przez surowe TCP/UDP przy użyciu numeru portu.", "resourceRawDescription": "Proxy zapytań przez surowe TCP/UDP przy użyciu numeru portu.",
"resourceRawDescriptionCloud": "Proxy żądania przesyłania danych nad surowym TCP/UDP przy użyciu numeru portu. Wymaga UŻYTKOWANIA PALIWA węzła.",
"resourceCreate": "Utwórz zasób", "resourceCreate": "Utwórz zasób",
"resourceCreateDescription": "Wykonaj poniższe kroki, aby utworzyć nowy zasób", "resourceCreateDescription": "Wykonaj poniższe kroki, aby utworzyć nowy zasób",
"resourceSeeAll": "Zobacz wszystkie zasoby", "resourceSeeAll": "Zobacz wszystkie zasoby",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Pobierz użytkownika", "actionGetUser": "Pobierz użytkownika",
"actionGetOrgUser": "Pobierz użytkownika organizacji", "actionGetOrgUser": "Pobierz użytkownika organizacji",
"actionListOrgDomains": "Lista domen organizacji", "actionListOrgDomains": "Lista domen organizacji",
"actionGetDomain": "Pobierz domenę",
"actionCreateOrgDomain": "Utwórz domenę",
"actionUpdateOrgDomain": "Aktualizuj domenę",
"actionDeleteOrgDomain": "Usuń domenę",
"actionGetDNSRecords": "Pobierz rekordy DNS",
"actionRestartOrgDomain": "Zrestartuj domenę",
"actionCreateSite": "Utwórz witrynę", "actionCreateSite": "Utwórz witrynę",
"actionDeleteSite": "Usuń witrynę", "actionDeleteSite": "Usuń witrynę",
"actionGetSite": "Pobierz witrynę", "actionGetSite": "Pobierz witrynę",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Użytkownik może uruchamiać tylko określone polecenia z sudo.", "sshSudoModeCommandsDescription": "Użytkownik może uruchamiać tylko określone polecenia z sudo.",
"sshSudo": "Zezwól na sudo", "sshSudo": "Zezwól na sudo",
"sshSudoCommands": "Komendy Sudo", "sshSudoCommands": "Komendy Sudo",
"sshSudoCommandsDescription": "Lista poleceń oddzielonych przecinkami, które użytkownik może uruchamiać z sudo.", "sshSudoCommandsDescription": "Lista poleceń, które użytkownik może uruchamiać z sudo.",
"sshCreateHomeDir": "Utwórz katalog domowy", "sshCreateHomeDir": "Utwórz katalog domowy",
"sshUnixGroups": "Grupy Unix", "sshUnixGroups": "Grupy Unix",
"sshUnixGroupsDescription": "Oddzielone przecinkami grupy Unix, aby dodać użytkownika do docelowego hosta.", "sshUnixGroupsDescription": "Grupy Unix do dodania użytkownika do docelowego hosta.",
"retryAttempts": "Próby Ponowienia", "retryAttempts": "Próby Ponowienia",
"expectedResponseCodes": "Oczekiwane Kody Odpowiedzi", "expectedResponseCodes": "Oczekiwane Kody Odpowiedzi",
"expectedResponseCodesDescription": "Kod statusu HTTP, który wskazuje zdrowy status. Jeśli pozostanie pusty, uznaje się 200-300 za zdrowy.", "expectedResponseCodesDescription": "Kod statusu HTTP, który wskazuje zdrowy status. Jeśli pozostanie pusty, uznaje się 200-300 za zdrowy.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Proxies requests sobre HTTPS usando um nome de domínio totalmente qualificado.", "resourceHTTPDescription": "Proxies requests sobre HTTPS usando um nome de domínio totalmente qualificado.",
"resourceRaw": "Recurso TCP/UDP bruto", "resourceRaw": "Recurso TCP/UDP bruto",
"resourceRawDescription": "Proxies solicitações sobre TCP/UDP bruto usando um número de porta.", "resourceRawDescription": "Proxies solicitações sobre TCP/UDP bruto usando um número de porta.",
"resourceRawDescriptionCloud": "Proxy solicita sobre TCP/UDP bruto usando um número de porta. OBRIGATÓRIO O USO DE UMA NOTA REMOTA.",
"resourceCreate": "Criar Recurso", "resourceCreate": "Criar Recurso",
"resourceCreateDescription": "Siga os passos abaixo para criar um novo recurso", "resourceCreateDescription": "Siga os passos abaixo para criar um novo recurso",
"resourceSeeAll": "Ver todos os recursos", "resourceSeeAll": "Ver todos os recursos",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Obter Usuário", "actionGetUser": "Obter Usuário",
"actionGetOrgUser": "Obter Utilizador da Organização", "actionGetOrgUser": "Obter Utilizador da Organização",
"actionListOrgDomains": "Listar Domínios da Organização", "actionListOrgDomains": "Listar Domínios da Organização",
"actionGetDomain": "Obter domínio",
"actionCreateOrgDomain": "Criar domínio",
"actionUpdateOrgDomain": "Atualizar domínio",
"actionDeleteOrgDomain": "Excluir domínio",
"actionGetDNSRecords": "Obter registros de DNS",
"actionRestartOrgDomain": "Reiniciar domínio",
"actionCreateSite": "Criar Site", "actionCreateSite": "Criar Site",
"actionDeleteSite": "Eliminar Site", "actionDeleteSite": "Eliminar Site",
"actionGetSite": "Obter Site", "actionGetSite": "Obter Site",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Usuário só pode executar os comandos especificados com sudo.", "sshSudoModeCommandsDescription": "Usuário só pode executar os comandos especificados com sudo.",
"sshSudo": "Permitir sudo", "sshSudo": "Permitir sudo",
"sshSudoCommands": "Comandos Sudo", "sshSudoCommands": "Comandos Sudo",
"sshSudoCommandsDescription": "Lista separada por vírgulas de comandos que o usuário pode executar com sudo.", "sshSudoCommandsDescription": "Lista de comandos com permissão de executar com o sudo.",
"sshCreateHomeDir": "Criar Diretório Inicial", "sshCreateHomeDir": "Criar Diretório Inicial",
"sshUnixGroups": "Grupos Unix", "sshUnixGroups": "Grupos Unix",
"sshUnixGroupsDescription": "Grupos Unix separados por vírgulas para adicionar o usuário no host alvo.", "sshUnixGroupsDescription": "Grupos Unix para adicionar o usuário no host de destino.",
"retryAttempts": "Tentativas de Repetição", "retryAttempts": "Tentativas de Repetição",
"expectedResponseCodes": "Códigos de Resposta Esperados", "expectedResponseCodes": "Códigos de Resposta Esperados",
"expectedResponseCodesDescription": "Código de status HTTP que indica estado saudável. Se deixado em branco, 200-300 é considerado saudável.", "expectedResponseCodesDescription": "Código de status HTTP que indica estado saudável. Se deixado em branco, 200-300 é considerado saudável.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Проксировать запросы через HTTPS с использованием полного доменного имени.", "resourceHTTPDescription": "Проксировать запросы через HTTPS с использованием полного доменного имени.",
"resourceRaw": "Сырой TCP/UDP-ресурс", "resourceRaw": "Сырой TCP/UDP-ресурс",
"resourceRawDescription": "Проксировать запросы по сырому TCP/UDP с использованием номера порта.", "resourceRawDescription": "Проксировать запросы по сырому TCP/UDP с использованием номера порта.",
"resourceRawDescriptionCloud": "Прокси-запросы через необработанный TCP/UDP с использованием номера порта. ТРЕБУЕТЕСЬ ИСПОЛЬЗОВАТЬ НЕОБХОДИМЫ.",
"resourceCreate": "Создание ресурса", "resourceCreate": "Создание ресурса",
"resourceCreateDescription": "Следуйте инструкциям ниже для создания нового ресурса", "resourceCreateDescription": "Следуйте инструкциям ниже для создания нового ресурса",
"resourceSeeAll": "Посмотреть все ресурсы", "resourceSeeAll": "Посмотреть все ресурсы",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Получить пользователя", "actionGetUser": "Получить пользователя",
"actionGetOrgUser": "Получить пользователя организации", "actionGetOrgUser": "Получить пользователя организации",
"actionListOrgDomains": "Список доменов организации", "actionListOrgDomains": "Список доменов организации",
"actionGetDomain": "Получить домен",
"actionCreateOrgDomain": "Создать домен",
"actionUpdateOrgDomain": "Обновить домен",
"actionDeleteOrgDomain": "Удалить домен",
"actionGetDNSRecords": "Получить записи DNS",
"actionRestartOrgDomain": "Перезапустить домен",
"actionCreateSite": "Создать сайт", "actionCreateSite": "Создать сайт",
"actionDeleteSite": "Удалить сайт", "actionDeleteSite": "Удалить сайт",
"actionGetSite": "Получить сайт", "actionGetSite": "Получить сайт",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Пользователь может запускать только указанные команды с помощью sudo.", "sshSudoModeCommandsDescription": "Пользователь может запускать только указанные команды с помощью sudo.",
"sshSudo": "Разрешить sudo", "sshSudo": "Разрешить sudo",
"sshSudoCommands": "Sudo Команды", "sshSudoCommands": "Sudo Команды",
"sshSudoCommandsDescription": "Список команд, разделенных запятыми, которые пользователю разрешено запускать с помощью sudo.", "sshSudoCommandsDescription": "Список команд, которые пользователю разрешено запускать с помощью sudo.",
"sshCreateHomeDir": "Создать домашний каталог", "sshCreateHomeDir": "Создать домашний каталог",
"sshUnixGroups": "Unix группы", "sshUnixGroups": "Unix группы",
"sshUnixGroupsDescription": "Группы Unix через запятую, чтобы добавить пользователя на целевой хост.", "sshUnixGroupsDescription": "Unix группы для добавления пользователя на целевой хост.",
"retryAttempts": "Количество попыток повторного запроса", "retryAttempts": "Количество попыток повторного запроса",
"expectedResponseCodes": "Ожидаемые коды ответов", "expectedResponseCodes": "Ожидаемые коды ответов",
"expectedResponseCodesDescription": "HTTP-код состояния, указывающий на здоровое состояние. Если оставить пустым, 200-300 считается здоровым.", "expectedResponseCodesDescription": "HTTP-код состояния, указывающий на здоровое состояние. Если оставить пустым, 200-300 считается здоровым.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "Tam nitelikli bir etki alanı adı kullanarak HTTPS üzerinden proxy isteklerini yönlendirin.", "resourceHTTPDescription": "Tam nitelikli bir etki alanı adı kullanarak HTTPS üzerinden proxy isteklerini yönlendirin.",
"resourceRaw": "Ham TCP/UDP Kaynağı", "resourceRaw": "Ham TCP/UDP Kaynağı",
"resourceRawDescription": "Port numarası kullanarak ham TCP/UDP üzerinden proxy isteklerini yönlendirin.", "resourceRawDescription": "Port numarası kullanarak ham TCP/UDP üzerinden proxy isteklerini yönlendirin.",
"resourceRawDescriptionCloud": "Bir port numarası kullanarak ham TCP/UDP üzerinden istekleri proxy ile yönlendirin. UZAKTAN BİR DÜĞÜM KULLANIMINI GEREKTİRİR.",
"resourceCreate": "Kaynak Oluştur", "resourceCreate": "Kaynak Oluştur",
"resourceCreateDescription": "Yeni bir kaynak oluşturmak için aşağıdaki adımları izleyin", "resourceCreateDescription": "Yeni bir kaynak oluşturmak için aşağıdaki adımları izleyin",
"resourceSeeAll": "Tüm Kaynakları Gör", "resourceSeeAll": "Tüm Kaynakları Gör",
@@ -1102,12 +1101,6 @@
"actionGetUser": "Kullanıcıyı Getir", "actionGetUser": "Kullanıcıyı Getir",
"actionGetOrgUser": "Kuruluş Kullanıcısını Al", "actionGetOrgUser": "Kuruluş Kullanıcısını Al",
"actionListOrgDomains": "Kuruluş Alan Adlarını Listele", "actionListOrgDomains": "Kuruluş Alan Adlarını Listele",
"actionGetDomain": "Alan Adını Al",
"actionCreateOrgDomain": "Alan Adı Oluştur",
"actionUpdateOrgDomain": "Alan Adını Güncelle",
"actionDeleteOrgDomain": "Alan Adını Sil",
"actionGetDNSRecords": "DNS Kayıtlarını Al",
"actionRestartOrgDomain": "Alanı Yeniden Başlat",
"actionCreateSite": "Site Oluştur", "actionCreateSite": "Site Oluştur",
"actionDeleteSite": "Siteyi Sil", "actionDeleteSite": "Siteyi Sil",
"actionGetSite": "Siteyi Al", "actionGetSite": "Siteyi Al",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "Kullanıcı sadece belirtilen komutları sudo ile çalıştırabilir.", "sshSudoModeCommandsDescription": "Kullanıcı sadece belirtilen komutları sudo ile çalıştırabilir.",
"sshSudo": "Sudo'ya izin ver", "sshSudo": "Sudo'ya izin ver",
"sshSudoCommands": "Sudo Komutları", "sshSudoCommands": "Sudo Komutları",
"sshSudoCommandsDescription": "Kullanıcının sudo ile çalıştırmasına izin verilen komutların virgülle ayrılmış listesi.", "sshSudoCommandsDescription": "Kullanıcının sudo ile çalıştırmasına izin verilen komutların listesi.",
"sshCreateHomeDir": "Ev Dizini Oluştur", "sshCreateHomeDir": "Ev Dizini Oluştur",
"sshUnixGroups": "Unix Grupları", "sshUnixGroups": "Unix Grupları",
"sshUnixGroupsDescription": "Hedef konakta kullanıcıya eklenecek Unix gruplarının virgülle ayrılmış listesi.", "sshUnixGroupsDescription": "Hedef ana bilgisayarda kullanıcıya eklemek için Unix grupları.",
"retryAttempts": "Tekrar Deneme Girişimleri", "retryAttempts": "Tekrar Deneme Girişimleri",
"expectedResponseCodes": "Beklenen Yanıt Kodları", "expectedResponseCodes": "Beklenen Yanıt Kodları",
"expectedResponseCodesDescription": "Sağlıklı durumu gösteren HTTP durum kodu. Boş bırakılırsa, 200-300 arası sağlıklı kabul edilir.", "expectedResponseCodesDescription": "Sağlıklı durumu gösteren HTTP durum kodu. Boş bırakılırsa, 200-300 arası sağlıklı kabul edilir.",

View File

@@ -175,7 +175,6 @@
"resourceHTTPDescription": "通过使用完全限定的域名的HTTPS代理请求。", "resourceHTTPDescription": "通过使用完全限定的域名的HTTPS代理请求。",
"resourceRaw": "TCP/UDP 资源", "resourceRaw": "TCP/UDP 资源",
"resourceRawDescription": "通过使用端口号的原始TCP/UDP代理请求。", "resourceRawDescription": "通过使用端口号的原始TCP/UDP代理请求。",
"resourceRawDescriptionCloud": "正在使用端口号的 TCP/UDP 代理请求。请使用一个REMOTE",
"resourceCreate": "创建资源", "resourceCreate": "创建资源",
"resourceCreateDescription": "按照下面的步骤创建新资源", "resourceCreateDescription": "按照下面的步骤创建新资源",
"resourceSeeAll": "查看所有资源", "resourceSeeAll": "查看所有资源",
@@ -1102,12 +1101,6 @@
"actionGetUser": "获取用户", "actionGetUser": "获取用户",
"actionGetOrgUser": "获取组织用户", "actionGetOrgUser": "获取组织用户",
"actionListOrgDomains": "列出组织域", "actionListOrgDomains": "列出组织域",
"actionGetDomain": "获取域",
"actionCreateOrgDomain": "创建域",
"actionUpdateOrgDomain": "更新域",
"actionDeleteOrgDomain": "删除域",
"actionGetDNSRecords": "获取 DNS 记录",
"actionRestartOrgDomain": "重新启动域",
"actionCreateSite": "创建站点", "actionCreateSite": "创建站点",
"actionDeleteSite": "删除站点", "actionDeleteSite": "删除站点",
"actionGetSite": "获取站点", "actionGetSite": "获取站点",
@@ -1676,10 +1669,10 @@
"sshSudoModeCommandsDescription": "用户只能用 sudo 运行指定的命令。", "sshSudoModeCommandsDescription": "用户只能用 sudo 运行指定的命令。",
"sshSudo": "允许Sudo", "sshSudo": "允许Sudo",
"sshSudoCommands": "Sudo 命令", "sshSudoCommands": "Sudo 命令",
"sshSudoCommandsDescription": "逗号分隔的用户允许使用 sudo 运行的命令列表。", "sshSudoCommandsDescription": "允许用户使用 sudo 运行的命令列表。",
"sshCreateHomeDir": "创建主目录", "sshCreateHomeDir": "创建主目录",
"sshUnixGroups": "Unix 组", "sshUnixGroups": "Unix 组",
"sshUnixGroupsDescription": "用逗号分隔了Unix组将用户添加到目标主机。", "sshUnixGroupsDescription": "将用户添加到目标主机的Unix组。",
"retryAttempts": "重试次数", "retryAttempts": "重试次数",
"expectedResponseCodes": "期望响应代码", "expectedResponseCodes": "期望响应代码",
"expectedResponseCodesDescription": "HTTP 状态码表示健康状态。如留空200-300 被视为健康。", "expectedResponseCodesDescription": "HTTP 状态码表示健康状态。如留空200-300 被视为健康。",

View File

@@ -17,7 +17,6 @@ import fs from "fs";
import path from "path"; import path from "path";
import { APP_PATH } from "./lib/consts"; import { APP_PATH } from "./lib/consts";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { z } from "zod";
const dev = process.env.ENVIRONMENT !== "prod"; const dev = process.env.ENVIRONMENT !== "prod";
const externalPort = config.getRawConfig().server.integration_port; const externalPort = config.getRawConfig().server.integration_port;
@@ -39,24 +38,12 @@ export function createIntegrationApiServer() {
apiServer.use(cookieParser()); apiServer.use(cookieParser());
apiServer.use(express.json()); apiServer.use(express.json());
const openApiDocumentation = getOpenApiDocumentation();
apiServer.use( apiServer.use(
"/v1/docs", "/v1/docs",
swaggerUi.serve, swaggerUi.serve,
swaggerUi.setup(openApiDocumentation) swaggerUi.setup(getOpenApiDocumentation())
); );
// Unauthenticated OpenAPI spec endpoints
apiServer.get("/v1/openapi.json", (_req, res) => {
res.json(openApiDocumentation);
});
apiServer.get("/v1/openapi.yaml", (_req, res) => {
const yamlOutput = yaml.dump(openApiDocumentation);
res.type("application/yaml").send(yamlOutput);
});
// API routes // API routes
const prefix = `/v1`; const prefix = `/v1`;
apiServer.use(logIncomingMiddleware); apiServer.use(logIncomingMiddleware);
@@ -88,6 +75,16 @@ function getOpenApiDocumentation() {
} }
); );
for (const def of registry.definitions) {
if (def.type === "route") {
def.route.security = [
{
[bearerAuth.name]: []
}
];
}
}
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/", path: "/",
@@ -97,74 +94,6 @@ function getOpenApiDocumentation() {
responses: {} responses: {}
}); });
registry.registerPath({
method: "get",
path: "/openapi.json",
description: "Get OpenAPI specification as JSON",
tags: [],
request: {},
responses: {
"200": {
description: "OpenAPI specification as JSON",
content: {
"application/json": {
schema: {
type: "object"
}
}
}
}
}
});
registry.registerPath({
method: "get",
path: "/openapi.yaml",
description: "Get OpenAPI specification as YAML",
tags: [],
request: {},
responses: {
"200": {
description: "OpenAPI specification as YAML",
content: {
"application/yaml": {
schema: {
type: "string"
}
}
}
}
}
});
for (const def of registry.definitions) {
if (def.type === "route") {
def.route.security = [
{
[bearerAuth.name]: []
}
];
// Ensure every route has a generic JSON response schema so Swagger UI can render responses
const existingResponses = def.route.responses;
const hasExistingResponses =
existingResponses && Object.keys(existingResponses).length > 0;
if (!hasExistingResponses) {
def.route.responses = {
"*": {
description: "",
content: {
"application/json": {
schema: z.object({})
}
}
}
};
}
}
}
const generator = new OpenApiGeneratorV3(registry.definitions); const generator = new OpenApiGeneratorV3(registry.definitions);
const generated = generator.generateDocument({ const generated = generator.generateDocument({

View File

@@ -571,6 +571,129 @@ export function generateSubnetProxyTargets(
return targets; return targets;
} }
export type SubnetProxyTargetV2 = {
sourcePrefixes: string[]; // must be cidrs
destPrefix: string; // must be a cidr
disableIcmp?: boolean;
rewriteTo?: string; // must be a cidr
portRange?: {
min: number;
max: number;
protocol: "tcp" | "udp";
}[];
};
export function generateSubnetProxyTargetV2(
siteResource: SiteResource,
clients: {
clientId: number;
pubKey: string | null;
subnet: string | null;
}[]
): SubnetProxyTargetV2 | undefined {
if (clients.length === 0) {
logger.debug(
`No clients have access to site resource ${siteResource.siteResourceId}, skipping target generation.`
);
return;
}
let target: SubnetProxyTargetV2 | null = null;
const portRange = [
...parsePortRangeString(siteResource.tcpPortRangeString, "tcp"),
...parsePortRangeString(siteResource.udpPortRangeString, "udp")
];
const disableIcmp = siteResource.disableIcmp ?? false;
if (siteResource.mode == "host") {
let destination = siteResource.destination;
// check if this is a valid ip
const ipSchema = z.union([z.ipv4(), z.ipv6()]);
if (ipSchema.safeParse(destination).success) {
destination = `${destination}/32`;
target = {
sourcePrefixes: [],
destPrefix: destination,
portRange,
disableIcmp
};
}
if (siteResource.alias && siteResource.aliasAddress) {
// also push a match for the alias address
target = {
sourcePrefixes: [],
destPrefix: `${siteResource.aliasAddress}/32`,
rewriteTo: destination,
portRange,
disableIcmp
};
}
} else if (siteResource.mode == "cidr") {
target = {
sourcePrefixes: [],
destPrefix: siteResource.destination,
portRange,
disableIcmp
};
}
if (!target) {
return;
}
for (const clientSite of clients) {
if (!clientSite.subnet) {
logger.debug(
`Client ${clientSite.clientId} has no subnet, skipping for site resource ${siteResource.siteResourceId}.`
);
continue;
}
const clientPrefix = `${clientSite.subnet.split("/")[0]}/32`;
// add client prefix to source prefixes
target.sourcePrefixes.push(clientPrefix);
}
// print a nice representation of the targets
// logger.debug(
// `Generated subnet proxy targets for: ${JSON.stringify(targets, null, 2)}`
// );
return target;
}
/**
* Converts a SubnetProxyTargetV2 to an array of SubnetProxyTarget (v1)
* by expanding each source prefix into its own target entry.
* @param targetV2 - The v2 target to convert
* @returns Array of v1 SubnetProxyTarget objects
*/
export function convertSubnetProxyTargetsV2ToV1(
targetsV2: SubnetProxyTargetV2[]
): SubnetProxyTarget[] {
return targetsV2.flatMap((targetV2) =>
targetV2.sourcePrefixes.map((sourcePrefix) => ({
sourcePrefix,
destPrefix: targetV2.destPrefix,
...(targetV2.disableIcmp !== undefined && {
disableIcmp: targetV2.disableIcmp
}),
...(targetV2.rewriteTo !== undefined && {
rewriteTo: targetV2.rewriteTo
}),
...(targetV2.portRange !== undefined && {
portRange: targetV2.portRange
})
}))
);
}
// Custom schema for validating port range strings // Custom schema for validating port range strings
// Format: "80,443,8000-9000" or "*" for all ports, or empty string // Format: "80,443,8000-9000" or "*" for all ports, or empty string
export const portRangeStringSchema = z export const portRangeStringSchema = z

View File

@@ -302,8 +302,8 @@ export const configSchema = z
.optional() .optional()
.default({ .default({
block_size: 24, block_size: 24,
subnet_group: "100.90.128.0/24", subnet_group: "100.90.128.0/20",
utility_subnet_group: "100.96.128.0/24" utility_subnet_group: "100.96.128.0/20"
}), }),
rate_limits: z rate_limits: z
.object({ .object({

View File

@@ -32,7 +32,7 @@ import logger from "@server/logger";
import { import {
generateAliasConfig, generateAliasConfig,
generateRemoteSubnets, generateRemoteSubnets,
generateSubnetProxyTargets, generateSubnetProxyTargetV2,
parseEndpoint, parseEndpoint,
formatEndpoint formatEndpoint
} from "@server/lib/ip"; } from "@server/lib/ip";
@@ -659,17 +659,14 @@ async function handleSubnetProxyTargetUpdates(
); );
if (addedClients.length > 0) { if (addedClients.length > 0) {
const targetsToAdd = generateSubnetProxyTargets( const targetToAdd = generateSubnetProxyTargetV2(
siteResource, siteResource,
addedClients addedClients
); );
if (targetsToAdd.length > 0) { if (targetToAdd) {
logger.info(
`Adding ${targetsToAdd.length} subnet proxy targets for siteResource ${siteResource.siteResourceId}`
);
proxyJobs.push( proxyJobs.push(
addSubnetProxyTargets(newt.newtId, targetsToAdd) addSubnetProxyTargets(newt.newtId, [targetToAdd])
); );
} }
@@ -695,17 +692,14 @@ async function handleSubnetProxyTargetUpdates(
); );
if (removedClients.length > 0) { if (removedClients.length > 0) {
const targetsToRemove = generateSubnetProxyTargets( const targetToRemove = generateSubnetProxyTargetV2(
siteResource, siteResource,
removedClients removedClients
); );
if (targetsToRemove.length > 0) { if (targetToRemove) {
logger.info(
`Removing ${targetsToRemove.length} subnet proxy targets for siteResource ${siteResource.siteResourceId}`
);
proxyJobs.push( proxyJobs.push(
removeSubnetProxyTargets(newt.newtId, targetsToRemove) removeSubnetProxyTargets(newt.newtId, [targetToRemove])
); );
} }
@@ -1159,7 +1153,7 @@ async function handleMessagesForClientResources(
} }
for (const resource of resources) { for (const resource of resources) {
const targets = generateSubnetProxyTargets(resource, [ const target = generateSubnetProxyTargetV2(resource, [
{ {
clientId: client.clientId, clientId: client.clientId,
pubKey: client.pubKey, pubKey: client.pubKey,
@@ -1167,8 +1161,8 @@ async function handleMessagesForClientResources(
} }
]); ]);
if (targets.length > 0) { if (target) {
proxyJobs.push(addSubnetProxyTargets(newt.newtId, targets)); proxyJobs.push(addSubnetProxyTargets(newt.newtId, [target]));
} }
try { try {
@@ -1230,7 +1224,7 @@ async function handleMessagesForClientResources(
} }
for (const resource of resources) { for (const resource of resources) {
const targets = generateSubnetProxyTargets(resource, [ const target = generateSubnetProxyTargetV2(resource, [
{ {
clientId: client.clientId, clientId: client.clientId,
pubKey: client.pubKey, pubKey: client.pubKey,
@@ -1238,9 +1232,9 @@ async function handleMessagesForClientResources(
} }
]); ]);
if (targets.length > 0) { if (target) {
proxyJobs.push( proxyJobs.push(
removeSubnetProxyTargets(newt.newtId, targets) removeSubnetProxyTargets(newt.newtId, [target])
); );
} }

View File

@@ -5,20 +5,17 @@ export const registry = new OpenAPIRegistry();
export enum OpenAPITags { export enum OpenAPITags {
Site = "Site", Site = "Site",
Org = "Organization", Org = "Organization",
PublicResource = "Public Resource", Resource = "Resource",
PrivateResource = "Private Resource",
Role = "Role", Role = "Role",
User = "User", User = "User",
Invitation = "User Invitation", Invitation = "Invitation",
Target = "Resource Target", Target = "Target",
Rule = "Rule", Rule = "Rule",
AccessToken = "Access Token", AccessToken = "Access Token",
GlobalIdp = "Identity Provider (Global)", Idp = "Identity Provider",
OrgIdp = "Identity Provider (Organization Only)",
Client = "Client", Client = "Client",
ApiKey = "API Key", ApiKey = "API Key",
Domain = "Domain", Domain = "Domain",
Blueprint = "Blueprint", Blueprint = "Blueprint",
Ssh = "SSH", Ssh = "SSH"
Logs = "Logs"
} }

View File

@@ -32,7 +32,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/access/export", path: "/org/{orgId}/logs/access/export",
description: "Export the access audit log for an organization as CSV", description: "Export the access audit log for an organization as CSV",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryAccessAuditLogsQuery, query: queryAccessAuditLogsQuery,
params: queryAccessAuditLogsParams params: queryAccessAuditLogsParams

View File

@@ -32,7 +32,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/action/export", path: "/org/{orgId}/logs/action/export",
description: "Export the action audit log for an organization as CSV", description: "Export the action audit log for an organization as CSV",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryActionAuditLogsQuery, query: queryActionAuditLogsQuery,
params: queryActionAuditLogsParams params: queryActionAuditLogsParams

View File

@@ -249,7 +249,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/access", path: "/org/{orgId}/logs/access",
description: "Query the access audit log for an organization", description: "Query the access audit log for an organization",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryAccessAuditLogsQuery, query: queryAccessAuditLogsQuery,
params: queryAccessAuditLogsParams params: queryAccessAuditLogsParams

View File

@@ -160,7 +160,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/action", path: "/org/{orgId}/logs/action",
description: "Query the action audit log for an organization", description: "Query the action audit log for an organization",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryActionAuditLogsQuery, query: queryActionAuditLogsQuery,
params: queryActionAuditLogsParams params: queryActionAuditLogsParams

View File

@@ -31,16 +31,16 @@ const getOrgSchema = z.strictObject({
orgId: z.string() orgId: z.string()
}); });
// registry.registerPath({ registry.registerPath({
// method: "get", method: "get",
// path: "/org/{orgId}/billing/usage", path: "/org/{orgId}/billing/usage",
// description: "Get an organization's billing usage", description: "Get an organization's billing usage",
// tags: [OpenAPITags.Org], tags: [OpenAPITags.Org],
// request: { request: {
// params: getOrgSchema params: getOrgSchema
// }, },
// responses: {} responses: {}
// }); });
export async function getOrgUsage( export async function getOrgUsage(
req: Request, req: Request,

View File

@@ -52,7 +52,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/idp/oidc", path: "/org/{orgId}/idp/oidc",
description: "Create an OIDC IdP for a specific organization.", description: "Create an OIDC IdP for a specific organization.",
tags: [OpenAPITags.OrgIdp], tags: [OpenAPITags.Idp, OpenAPITags.Org],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -35,7 +35,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/org/{orgId}/idp/{idpId}", path: "/org/{orgId}/idp/{idpId}",
description: "Delete IDP for a specific organization.", description: "Delete IDP for a specific organization.",
tags: [OpenAPITags.OrgIdp], tags: [OpenAPITags.Idp, OpenAPITags.Org],
request: { request: {
params: paramsSchema params: paramsSchema
}, },

View File

@@ -50,9 +50,9 @@ async function query(idpId: number, orgId: string) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/idp/{idpId}", path: "/org/:orgId/idp/:idpId",
description: "Get an IDP by its IDP ID for a specific organization.", description: "Get an IDP by its IDP ID for a specific organization.",
tags: [OpenAPITags.OrgIdp], tags: [OpenAPITags.Idp, OpenAPITags.Org],
request: { request: {
params: paramsSchema params: paramsSchema
}, },

View File

@@ -67,7 +67,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/idp", path: "/org/{orgId}/idp",
description: "List all IDP for a specific organization.", description: "List all IDP for a specific organization.",
tags: [OpenAPITags.OrgIdp], tags: [OpenAPITags.Idp, OpenAPITags.Org],
request: { request: {
query: querySchema, query: querySchema,
params: paramsSchema params: paramsSchema

View File

@@ -59,7 +59,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/org/{orgId}/idp/{idpId}/oidc", path: "/org/{orgId}/idp/{idpId}/oidc",
description: "Update an OIDC IdP for a specific organization.", description: "Update an OIDC IdP for a specific organization.",
tags: [OpenAPITags.OrgIdp], tags: [OpenAPITags.Idp, OpenAPITags.Org],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -52,7 +52,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/maintenance/info", path: "/maintenance/info",
description: "Get maintenance information for a resource by domain.", description: "Get maintenance information for a resource by domain.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
query: z.object({ query: z.object({
fullDomain: z.string() fullDomain: z.string()

View File

@@ -43,7 +43,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/access-token", path: "/resource/{resourceId}/access-token",
description: "Generate a new access token for a resource.", description: "Generate a new access token for a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.AccessToken], tags: [OpenAPITags.Resource, OpenAPITags.AccessToken],
request: { request: {
params: generateAccssTokenParamsSchema, params: generateAccssTokenParamsSchema,
body: { body: {

View File

@@ -122,7 +122,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/access-tokens", path: "/org/{orgId}/access-tokens",
description: "List all access tokens in an organization.", description: "List all access tokens in an organization.",
tags: [OpenAPITags.AccessToken], tags: [OpenAPITags.Org, OpenAPITags.AccessToken],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string() orgId: z.string()
@@ -135,8 +135,8 @@ registry.registerPath({
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/resource/{resourceId}/access-tokens", path: "/resource/{resourceId}/access-tokens",
description: "List all access tokens for a resource.", description: "List all access tokens in an organization.",
tags: [OpenAPITags.PublicResource, OpenAPITags.AccessToken], tags: [OpenAPITags.Resource, OpenAPITags.AccessToken],
request: { request: {
params: z.object({ params: z.object({
resourceId: z.number() resourceId: z.number()

View File

@@ -37,7 +37,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/api-key", path: "/org/{orgId}/api-key",
description: "Create a new API key scoped to the organization.", description: "Create a new API key scoped to the organization.",
tags: [OpenAPITags.ApiKey], tags: [OpenAPITags.Org, OpenAPITags.ApiKey],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -18,7 +18,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/org/{orgId}/api-key/{apiKeyId}", path: "/org/{orgId}/api-key/{apiKeyId}",
description: "Delete an API key.", description: "Delete an API key.",
tags: [OpenAPITags.ApiKey], tags: [OpenAPITags.Org, OpenAPITags.ApiKey],
request: { request: {
params: paramsSchema params: paramsSchema
}, },

View File

@@ -48,7 +48,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/api-key/{apiKeyId}/actions", path: "/org/{orgId}/api-key/{apiKeyId}/actions",
description: "List all actions set for an API key.", description: "List all actions set for an API key.",
tags: [OpenAPITags.ApiKey], tags: [OpenAPITags.Org, OpenAPITags.ApiKey],
request: { request: {
params: paramsSchema, params: paramsSchema,
query: querySchema query: querySchema

View File

@@ -52,7 +52,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/api-keys", path: "/org/{orgId}/api-keys",
description: "List all API keys for an organization", description: "List all API keys for an organization",
tags: [OpenAPITags.ApiKey], tags: [OpenAPITags.Org, OpenAPITags.ApiKey],
request: { request: {
params: paramsSchema, params: paramsSchema,
query: querySchema query: querySchema

View File

@@ -25,7 +25,7 @@ registry.registerPath({
path: "/org/{orgId}/api-key/{apiKeyId}/actions", path: "/org/{orgId}/api-key/{apiKeyId}/actions",
description: description:
"Set actions for an API key. This will replace any existing actions.", "Set actions for an API key. This will replace any existing actions.",
tags: [OpenAPITags.ApiKey], tags: [OpenAPITags.Org, OpenAPITags.ApiKey],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -20,7 +20,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/request", path: "/org/{orgId}/logs/request",
description: "Query the request audit log for an organization", description: "Query the request audit log for an organization",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryAccessAuditLogsQuery.omit({ query: queryAccessAuditLogsQuery.omit({
limit: true, limit: true,

View File

@@ -151,7 +151,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/analytics", path: "/org/{orgId}/logs/analytics",
description: "Query the request audit analytics for an organization", description: "Query the request audit analytics for an organization",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryAccessAuditLogsQuery, query: queryAccessAuditLogsQuery,
params: queryRequestAuditLogsParams params: queryRequestAuditLogsParams

View File

@@ -182,7 +182,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/logs/request", path: "/org/{orgId}/logs/request",
description: "Query the request audit log for an organization", description: "Query the request audit log for an organization",
tags: [OpenAPITags.Logs], tags: [OpenAPITags.Org],
request: { request: {
query: queryAccessAuditLogsQuery, query: queryAccessAuditLogsQuery,
params: queryRequestAuditLogsParams params: queryRequestAuditLogsParams

View File

@@ -20,7 +20,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/blueprint", path: "/org/{orgId}/blueprint",
description: "Apply a base64 encoded JSON blueprint to an organization", description: "Apply a base64 encoded JSON blueprint to an organization",
tags: [OpenAPITags.Blueprint], tags: [OpenAPITags.Org, OpenAPITags.Blueprint],
request: { request: {
params: applyBlueprintParamsSchema, params: applyBlueprintParamsSchema,
body: { body: {

View File

@@ -43,7 +43,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/blueprint", path: "/org/{orgId}/blueprint",
description: "Create and apply a YAML blueprint to an organization", description: "Create and apply a YAML blueprint to an organization",
tags: [OpenAPITags.Blueprint], tags: [OpenAPITags.Org, OpenAPITags.Blueprint],
request: { request: {
params: applyBlueprintParamsSchema, params: applyBlueprintParamsSchema,
body: { body: {

View File

@@ -53,7 +53,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/blueprint/{blueprintId}", path: "/org/{orgId}/blueprint/{blueprintId}",
description: "Get a blueprint by its blueprint ID.", description: "Get a blueprint by its blueprint ID.",
tags: [OpenAPITags.Blueprint], tags: [OpenAPITags.Org, OpenAPITags.Blueprint],
request: { request: {
params: getBlueprintSchema params: getBlueprintSchema
}, },

View File

@@ -67,7 +67,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/blueprints", path: "/org/{orgId}/blueprints",
description: "List all blueprints for a organization.", description: "List all blueprints for a organization.",
tags: [OpenAPITags.Blueprint], tags: [OpenAPITags.Org, OpenAPITags.Blueprint],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string() orgId: z.string()

View File

@@ -48,7 +48,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/client", path: "/org/{orgId}/client",
description: "Create a new client for an organization.", description: "Create a new client for an organization.",
tags: [OpenAPITags.Client], tags: [OpenAPITags.Client, OpenAPITags.Org],
request: { request: {
params: createClientParamsSchema, params: createClientParamsSchema,
body: { body: {

View File

@@ -49,7 +49,7 @@ registry.registerPath({
path: "/org/{orgId}/user/{userId}/client", path: "/org/{orgId}/user/{userId}/client",
description: description:
"Create a new client for a user and associate it with an existing olm.", "Create a new client for a user and associate it with an existing olm.",
tags: [OpenAPITags.Client], tags: [OpenAPITags.Client, OpenAPITags.Org, OpenAPITags.User],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -243,7 +243,7 @@ registry.registerPath({
path: "/org/{orgId}/client/{niceId}", path: "/org/{orgId}/client/{niceId}",
description: description:
"Get a client by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.", "Get a client by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.",
tags: [OpenAPITags.Site], tags: [OpenAPITags.Org, OpenAPITags.Site],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string(), orgId: z.string(),

View File

@@ -237,7 +237,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/clients", path: "/org/{orgId}/clients",
description: "List all clients for an organization.", description: "List all clients for an organization.",
tags: [OpenAPITags.Client], tags: [OpenAPITags.Client, OpenAPITags.Org],
request: { request: {
query: listClientsSchema, query: listClientsSchema,
params: listClientsParamsSchema params: listClientsParamsSchema

View File

@@ -256,7 +256,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/user-devices", path: "/org/{orgId}/user-devices",
description: "List all user devices for an organization.", description: "List all user devices for an organization.",
tags: [OpenAPITags.Client], tags: [OpenAPITags.Client, OpenAPITags.Org],
request: { request: {
query: listUserDevicesSchema, query: listUserDevicesSchema,
params: listUserDevicesParamsSchema params: listUserDevicesParamsSchema

View File

@@ -23,7 +23,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/pick-client-defaults", path: "/org/{orgId}/pick-client-defaults",
description: "Return pre-requisite data for creating a client.", description: "Return pre-requisite data for creating a client.",
tags: [OpenAPITags.Client], tags: [OpenAPITags.Client, OpenAPITags.Site],
request: { request: {
params: pickClientDefaultsSchema params: pickClientDefaultsSchema
}, },

View File

@@ -1,8 +1,15 @@
import { sendToClient } from "#dynamic/routers/ws"; import { sendToClient } from "#dynamic/routers/ws";
import { db, olms, Transaction } from "@server/db"; import { S } from "@faker-js/faker/dist/airline-Dz1uGqgJ";
import { Alias, SubnetProxyTarget } from "@server/lib/ip"; import { db, newts, olms, Transaction } from "@server/db";
import {
Alias,
convertSubnetProxyTargetsV2ToV1,
SubnetProxyTarget,
SubnetProxyTargetV2
} from "@server/lib/ip";
import logger from "@server/logger"; import logger from "@server/logger";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import semver from "semver";
const BATCH_SIZE = 50; const BATCH_SIZE = 50;
const BATCH_DELAY_MS = 50; const BATCH_DELAY_MS = 50;
@@ -19,57 +26,149 @@ function chunkArray<T>(array: T[], size: number): T[][] {
return chunks; return chunks;
} }
export async function addTargets(newtId: string, targets: SubnetProxyTarget[]) { const NEWT_V2_TARGETS_VERSION = ">=1.11.0";
const batches = chunkArray(targets, BATCH_SIZE);
export async function convertTargetsIfNessicary(
newtId: string,
targets: SubnetProxyTarget[] | SubnetProxyTargetV2[]
) {
// get the newt
const [newt] = await db
.select()
.from(newts)
.where(eq(newts.newtId, newtId));
if (!newt) {
throw new Error(`No newt found for id: ${newtId}`);
}
// check the semver
if (
newt.version &&
!semver.satisfies(newt.version, NEWT_V2_TARGETS_VERSION)
) {
logger.debug(
`addTargets Newt version ${newt.version} does not support targets v2 falling back`
);
targets = convertSubnetProxyTargetsV2ToV1(
targets as SubnetProxyTargetV2[]
);
}
return targets;
}
export async function addTargets(
newtId: string,
targets: SubnetProxyTarget[] | SubnetProxyTargetV2[]
) {
targets = await convertTargetsIfNessicary(newtId, targets);
const batches = chunkArray<SubnetProxyTarget | SubnetProxyTargetV2>(
targets,
BATCH_SIZE
);
for (let i = 0; i < batches.length; i++) { for (let i = 0; i < batches.length; i++) {
if (i > 0) { if (i > 0) {
await sleep(BATCH_DELAY_MS); await sleep(BATCH_DELAY_MS);
} }
await sendToClient(newtId, { await sendToClient(
newtId,
{
type: `newt/wg/targets/add`, type: `newt/wg/targets/add`,
data: batches[i] data: batches[i]
}, { incrementConfigVersion: true }); },
{ incrementConfigVersion: true }
);
} }
} }
export async function removeTargets( export async function removeTargets(
newtId: string, newtId: string,
targets: SubnetProxyTarget[] targets: SubnetProxyTarget[] | SubnetProxyTargetV2[]
) { ) {
const batches = chunkArray(targets, BATCH_SIZE); targets = await convertTargetsIfNessicary(newtId, targets);
const batches = chunkArray<SubnetProxyTarget | SubnetProxyTargetV2>(
targets,
BATCH_SIZE
);
for (let i = 0; i < batches.length; i++) { for (let i = 0; i < batches.length; i++) {
if (i > 0) { if (i > 0) {
await sleep(BATCH_DELAY_MS); await sleep(BATCH_DELAY_MS);
} }
await sendToClient(newtId, { await sendToClient(
newtId,
{
type: `newt/wg/targets/remove`, type: `newt/wg/targets/remove`,
data: batches[i] data: batches[i]
},{ incrementConfigVersion: true }); },
{ incrementConfigVersion: true }
);
} }
} }
export async function updateTargets( export async function updateTargets(
newtId: string, newtId: string,
targets: { targets: {
oldTargets: SubnetProxyTarget[]; oldTargets: SubnetProxyTarget[] | SubnetProxyTargetV2[];
newTargets: SubnetProxyTarget[]; newTargets: SubnetProxyTarget[] | SubnetProxyTargetV2[];
} }
) { ) {
const oldBatches = chunkArray(targets.oldTargets, BATCH_SIZE); // get the newt
const newBatches = chunkArray(targets.newTargets, BATCH_SIZE); const [newt] = await db
.select()
.from(newts)
.where(eq(newts.newtId, newtId));
if (!newt) {
logger.error(`addTargetsL No newt found for id: ${newtId}`);
return;
}
// check the semver
if (
newt.version &&
!semver.satisfies(newt.version, NEWT_V2_TARGETS_VERSION)
) {
logger.debug(
`addTargets Newt version ${newt.version} does not support targets v2 falling back`
);
targets = {
oldTargets: convertSubnetProxyTargetsV2ToV1(
targets.oldTargets as SubnetProxyTargetV2[]
),
newTargets: convertSubnetProxyTargetsV2ToV1(
targets.newTargets as SubnetProxyTargetV2[]
)
};
}
const oldBatches = chunkArray<SubnetProxyTarget | SubnetProxyTargetV2>(
targets.oldTargets,
BATCH_SIZE
);
const newBatches = chunkArray<SubnetProxyTarget | SubnetProxyTargetV2>(
targets.newTargets,
BATCH_SIZE
);
const maxBatches = Math.max(oldBatches.length, newBatches.length); const maxBatches = Math.max(oldBatches.length, newBatches.length);
for (let i = 0; i < maxBatches; i++) { for (let i = 0; i < maxBatches; i++) {
if (i > 0) { if (i > 0) {
await sleep(BATCH_DELAY_MS); await sleep(BATCH_DELAY_MS);
} }
await sendToClient(newtId, { await sendToClient(
newtId,
{
type: `newt/wg/targets/update`, type: `newt/wg/targets/update`,
data: { data: {
oldTargets: oldBatches[i] || [], oldTargets: oldBatches[i] || [],
newTargets: newBatches[i] || [] newTargets: newBatches[i] || []
} }
}, { incrementConfigVersion: true }).catch((error) => { },
{ incrementConfigVersion: true }
).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
@@ -94,14 +193,18 @@ export async function addPeerData(
olmId = olm.olmId; olmId = olm.olmId;
} }
await sendToClient(olmId, { await sendToClient(
olmId,
{
type: `olm/wg/peer/data/add`, type: `olm/wg/peer/data/add`,
data: { data: {
siteId: siteId, siteId: siteId,
remoteSubnets: remoteSubnets, remoteSubnets: remoteSubnets,
aliases: aliases aliases: aliases
} }
}, { incrementConfigVersion: true }).catch((error) => { },
{ incrementConfigVersion: true }
).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
@@ -125,14 +228,18 @@ export async function removePeerData(
olmId = olm.olmId; olmId = olm.olmId;
} }
await sendToClient(olmId, { await sendToClient(
olmId,
{
type: `olm/wg/peer/data/remove`, type: `olm/wg/peer/data/remove`,
data: { data: {
siteId: siteId, siteId: siteId,
remoteSubnets: remoteSubnets, remoteSubnets: remoteSubnets,
aliases: aliases aliases: aliases
} }
}, { incrementConfigVersion: true }).catch((error) => { },
{ incrementConfigVersion: true }
).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
@@ -166,14 +273,18 @@ export async function updatePeerData(
olmId = olm.olmId; olmId = olm.olmId;
} }
await sendToClient(olmId, { await sendToClient(
olmId,
{
type: `olm/wg/peer/data/update`, type: `olm/wg/peer/data/update`,
data: { data: {
siteId: siteId, siteId: siteId,
...remoteSubnets, ...remoteSubnets,
...aliases ...aliases
} }
}, { incrementConfigVersion: true }).catch((error) => { },
{ incrementConfigVersion: true }
).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }

View File

@@ -59,7 +59,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/domains", path: "/org/{orgId}/domains",
description: "List all domains for a organization.", description: "List all domains for a organization.",
tags: [OpenAPITags.Domain], tags: [OpenAPITags.Org],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string() orgId: z.string()

View File

@@ -27,7 +27,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/idp/{idpId}/org/{orgId}", path: "/idp/{idpId}/org/{orgId}",
description: "Create an IDP policy for an existing IDP on an organization.", description: "Create an IDP policy for an existing IDP on an organization.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -37,7 +37,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/idp/oidc", path: "/idp/oidc",
description: "Create an OIDC IdP.", description: "Create an OIDC IdP.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
body: { body: {
content: { content: {

View File

@@ -21,7 +21,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/idp/{idpId}", path: "/idp/{idpId}",
description: "Delete IDP.", description: "Delete IDP.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema params: paramsSchema
}, },

View File

@@ -19,7 +19,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/idp/{idpId}/org/{orgId}", path: "/idp/{idpId}/org/{orgId}",
description: "Create an OIDC IdP for an organization.", description: "Create an OIDC IdP for an organization.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema params: paramsSchema
}, },

View File

@@ -34,7 +34,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/idp/{idpId}", path: "/idp/{idpId}",
description: "Get an IDP by its IDP ID.", description: "Get an IDP by its IDP ID.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema params: paramsSchema
}, },

View File

@@ -48,7 +48,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/idp/{idpId}/org", path: "/idp/{idpId}/org",
description: "List all org policies on an IDP.", description: "List all org policies on an IDP.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema, params: paramsSchema,
query: querySchema query: querySchema

View File

@@ -58,7 +58,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/idp", path: "/idp",
description: "List all IDP in the system.", description: "List all IDP in the system.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
query: querySchema query: querySchema
}, },

View File

@@ -26,7 +26,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/idp/{idpId}/org/{orgId}", path: "/idp/{idpId}/org/{orgId}",
description: "Update an IDP org policy.", description: "Update an IDP org policy.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -42,7 +42,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/idp/{idpId}/oidc", path: "/idp/{idpId}/oidc",
description: "Update an OIDC IdP.", description: "Update an OIDC IdP.",
tags: [OpenAPITags.GlobalIdp], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema, params: paramsSchema,
body: { body: {

View File

@@ -1,9 +1,23 @@
import { clients, clientSiteResourcesAssociationsCache, clientSitesAssociationsCache, db, ExitNode, resources, Site, siteResources, targetHealthCheck, targets } from "@server/db"; import {
clients,
clientSiteResourcesAssociationsCache,
clientSitesAssociationsCache,
db,
ExitNode,
resources,
Site,
siteResources,
targetHealthCheck,
targets
} from "@server/db";
import logger from "@server/logger"; import logger from "@server/logger";
import { initPeerAddHandshake, updatePeer } from "../olm/peers"; import { initPeerAddHandshake, updatePeer } from "../olm/peers";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import config from "@server/lib/config"; import config from "@server/lib/config";
import { generateSubnetProxyTargets, SubnetProxyTarget } from "@server/lib/ip"; import {
generateSubnetProxyTargetV2,
SubnetProxyTargetV2
} from "@server/lib/ip";
export async function buildClientConfigurationForNewtClient( export async function buildClientConfigurationForNewtClient(
site: Site, site: Site,
@@ -126,7 +140,7 @@ export async function buildClientConfigurationForNewtClient(
.from(siteResources) .from(siteResources)
.where(eq(siteResources.siteId, siteId)); .where(eq(siteResources.siteId, siteId));
const targetsToSend: SubnetProxyTarget[] = []; const targetsToSend: SubnetProxyTargetV2[] = [];
for (const resource of allSiteResources) { for (const resource of allSiteResources) {
// Get clients associated with this specific resource // Get clients associated with this specific resource
@@ -151,12 +165,14 @@ export async function buildClientConfigurationForNewtClient(
) )
); );
const resourceTargets = generateSubnetProxyTargets( const resourceTarget = generateSubnetProxyTargetV2(
resource, resource,
resourceClients resourceClients
); );
targetsToSend.push(...resourceTargets); if (resourceTarget) {
targetsToSend.push(resourceTarget);
}
} }
return { return {
@@ -230,7 +246,7 @@ export async function buildTargetConfigurationForNewtClient(siteId: number) {
!target.hcMethod !target.hcMethod
) { ) {
logger.debug( logger.debug(
`Skipping adding target health check ${target.targetId} due to missing health check fields` `Skipping target ${target.targetId} due to missing health check fields`
); );
return null; // Skip targets with missing health check fields return null; // Skip targets with missing health check fields
} }

View File

@@ -6,6 +6,7 @@ import { db, ExitNode, exitNodes, Newt, sites } from "@server/db";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { sendToExitNode } from "#dynamic/lib/exitNodes"; import { sendToExitNode } from "#dynamic/lib/exitNodes";
import { buildClientConfigurationForNewtClient } from "./buildConfiguration"; import { buildClientConfigurationForNewtClient } from "./buildConfiguration";
import { convertTargetsIfNessicary } from "../client/targets";
const inputSchema = z.object({ const inputSchema = z.object({
publicKey: z.string(), publicKey: z.string(),
@@ -126,13 +127,15 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
exitNode exitNode
); );
const targetsToSend = await convertTargetsIfNessicary(newt.newtId, targets);
return { return {
message: { message: {
type: "newt/wg/receive-config", type: "newt/wg/receive-config",
data: { data: {
ipAddress: site.address, ipAddress: site.address,
peers, peers,
targets targets: targetsToSend
} }
}, },
broadcast: false, broadcast: false,

View File

@@ -29,7 +29,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/whitelist/add", path: "/resource/{resourceId}/whitelist/add",
description: "Add a single email to the resource whitelist.", description: "Add a single email to the resource whitelist.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: addEmailToResourceWhitelistParamsSchema, params: addEmailToResourceWhitelistParamsSchema,
body: { body: {

View File

@@ -29,7 +29,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/roles/add", path: "/resource/{resourceId}/roles/add",
description: "Add a single role to a resource.", description: "Add a single role to a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Role], tags: [OpenAPITags.Resource, OpenAPITags.Role],
request: { request: {
params: addRoleToResourceParamsSchema, params: addRoleToResourceParamsSchema,
body: { body: {

View File

@@ -29,7 +29,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/users/add", path: "/resource/{resourceId}/users/add",
description: "Add a single user to a resource.", description: "Add a single user to a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.User], tags: [OpenAPITags.Resource, OpenAPITags.User],
request: { request: {
params: addUserToResourceParamsSchema, params: addUserToResourceParamsSchema,
body: { body: {

View File

@@ -79,7 +79,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/resource", path: "/org/{orgId}/resource",
description: "Create a resource.", description: "Create a resource.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Org, OpenAPITags.Resource],
request: { request: {
params: createResourceParamsSchema, params: createResourceParamsSchema,
body: { body: {

View File

@@ -31,7 +31,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/resource/{resourceId}/rule", path: "/resource/{resourceId}/rule",
description: "Create a resource rule.", description: "Create a resource rule.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Rule], tags: [OpenAPITags.Resource, OpenAPITags.Rule],
request: { request: {
params: createResourceRuleParamsSchema, params: createResourceRuleParamsSchema,
body: { body: {

View File

@@ -22,7 +22,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/resource/{resourceId}", path: "/resource/{resourceId}",
description: "Delete a resource.", description: "Delete a resource.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: deleteResourceSchema params: deleteResourceSchema
}, },

View File

@@ -19,7 +19,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/resource/{resourceId}/rule/{ruleId}", path: "/resource/{resourceId}/rule/{ruleId}",
description: "Delete a resource rule.", description: "Delete a resource rule.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Rule], tags: [OpenAPITags.Resource, OpenAPITags.Rule],
request: { request: {
params: deleteResourceRuleSchema params: deleteResourceRuleSchema
}, },

View File

@@ -54,7 +54,7 @@ registry.registerPath({
path: "/org/{orgId}/resource/{niceId}", path: "/org/{orgId}/resource/{niceId}",
description: description:
"Get a resource by orgId and niceId. NiceId is a readable ID for the resource and unique on a per org basis.", "Get a resource by orgId and niceId. NiceId is a readable ID for the resource and unique on a per org basis.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Org, OpenAPITags.Resource],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string(), orgId: z.string(),
@@ -68,7 +68,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/resource/{resourceId}", path: "/resource/{resourceId}",
description: "Get a resource by resourceId.", description: "Get a resource by resourceId.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: z.object({ params: z.object({
resourceId: z.number() resourceId: z.number()

View File

@@ -31,7 +31,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/resource/{resourceId}/whitelist", path: "/resource/{resourceId}/whitelist",
description: "Get the whitelist of emails for a specific resource.", description: "Get the whitelist of emails for a specific resource.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: getResourceWhitelistSchema params: getResourceWhitelistSchema
}, },

View File

@@ -33,7 +33,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/resources-names", path: "/org/{orgId}/resources-names",
description: "List all resource names for an organization.", description: "List all resource names for an organization.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Org, OpenAPITags.Resource],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string() orgId: z.string()

View File

@@ -35,7 +35,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/resource/{resourceId}/roles", path: "/resource/{resourceId}/roles",
description: "List all roles for a resource.", description: "List all roles for a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Role], tags: [OpenAPITags.Resource, OpenAPITags.Role],
request: { request: {
params: listResourceRolesSchema params: listResourceRolesSchema
}, },

View File

@@ -56,7 +56,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/resource/{resourceId}/rules", path: "/resource/{resourceId}/rules",
description: "List rules for a resource.", description: "List rules for a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Rule], tags: [OpenAPITags.Resource, OpenAPITags.Rule],
request: { request: {
params: listResourceRulesParamsSchema, params: listResourceRulesParamsSchema,
query: listResourceRulesSchema query: listResourceRulesSchema

View File

@@ -38,7 +38,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/resource/{resourceId}/users", path: "/resource/{resourceId}/users",
description: "List all users for a resource.", description: "List all users for a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.User], tags: [OpenAPITags.Resource, OpenAPITags.User],
request: { request: {
params: listResourceUsersSchema params: listResourceUsersSchema
}, },

View File

@@ -225,7 +225,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/resources", path: "/org/{orgId}/resources",
description: "List resources for an organization.", description: "List resources for an organization.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Org, OpenAPITags.Resource],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string() orgId: z.string()

View File

@@ -29,7 +29,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/whitelist/remove", path: "/resource/{resourceId}/whitelist/remove",
description: "Remove a single email from the resource whitelist.", description: "Remove a single email from the resource whitelist.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: removeEmailFromResourceWhitelistParamsSchema, params: removeEmailFromResourceWhitelistParamsSchema,
body: { body: {

View File

@@ -29,7 +29,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/roles/remove", path: "/resource/{resourceId}/roles/remove",
description: "Remove a single role from a resource.", description: "Remove a single role from a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Role], tags: [OpenAPITags.Resource, OpenAPITags.Role],
request: { request: {
params: removeRoleFromResourceParamsSchema, params: removeRoleFromResourceParamsSchema,
body: { body: {

View File

@@ -29,7 +29,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/users/remove", path: "/resource/{resourceId}/users/remove",
description: "Remove a single user from a resource.", description: "Remove a single user from a resource.",
tags: [OpenAPITags.PublicResource, OpenAPITags.User], tags: [OpenAPITags.Resource, OpenAPITags.User],
request: { request: {
params: removeUserFromResourceParamsSchema, params: removeUserFromResourceParamsSchema,
body: { body: {

View File

@@ -29,7 +29,7 @@ registry.registerPath({
path: "/resource/{resourceId}/header-auth", path: "/resource/{resourceId}/header-auth",
description: description:
"Set or update the header authentication for a resource. If user and password is not provided, it will remove the header authentication.", "Set or update the header authentication for a resource. If user and password is not provided, it will remove the header authentication.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: setResourceAuthMethodsParamsSchema, params: setResourceAuthMethodsParamsSchema,
body: { body: {

View File

@@ -25,7 +25,7 @@ registry.registerPath({
path: "/resource/{resourceId}/password", path: "/resource/{resourceId}/password",
description: description:
"Set the password for a resource. Setting the password to null will remove it.", "Set the password for a resource. Setting the password to null will remove it.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: setResourceAuthMethodsParamsSchema, params: setResourceAuthMethodsParamsSchema,
body: { body: {

View File

@@ -29,7 +29,7 @@ registry.registerPath({
path: "/resource/{resourceId}/pincode", path: "/resource/{resourceId}/pincode",
description: description:
"Set the PIN code for a resource. Setting the PIN code to null will remove it.", "Set the PIN code for a resource. Setting the PIN code to null will remove it.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: setResourceAuthMethodsParamsSchema, params: setResourceAuthMethodsParamsSchema,
body: { body: {

View File

@@ -23,7 +23,7 @@ registry.registerPath({
path: "/resource/{resourceId}/roles", path: "/resource/{resourceId}/roles",
description: description:
"Set roles for a resource. This will replace all existing roles.", "Set roles for a resource. This will replace all existing roles.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Role], tags: [OpenAPITags.Resource, OpenAPITags.Role],
request: { request: {
params: setResourceRolesParamsSchema, params: setResourceRolesParamsSchema,
body: { body: {

View File

@@ -23,7 +23,7 @@ registry.registerPath({
path: "/resource/{resourceId}/users", path: "/resource/{resourceId}/users",
description: description:
"Set users for a resource. This will replace all existing users.", "Set users for a resource. This will replace all existing users.",
tags: [OpenAPITags.PublicResource, OpenAPITags.User], tags: [OpenAPITags.Resource, OpenAPITags.User],
request: { request: {
params: setUserResourcesParamsSchema, params: setUserResourcesParamsSchema,
body: { body: {

View File

@@ -32,7 +32,7 @@ registry.registerPath({
path: "/resource/{resourceId}/whitelist", path: "/resource/{resourceId}/whitelist",
description: description:
"Set email whitelist for a resource. This will replace all existing emails.", "Set email whitelist for a resource. This will replace all existing emails.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: setResourceWhitelistParamsSchema, params: setResourceWhitelistParamsSchema,
body: { body: {

View File

@@ -101,49 +101,6 @@ const updateHttpResourceBodySchema = z
{ {
error: "Invalid custom Host Header value. Use domain name format, or save empty to unset custom Host Header." error: "Invalid custom Host Header value. Use domain name format, or save empty to unset custom Host Header."
} }
)
.refine(
(data) => {
if (data.headers) {
// HTTP header names must be valid token characters (RFC 7230)
const validHeaderName = /^[a-zA-Z0-9!#$%&'*+\-.^_`|~]+$/;
return data.headers.every((h) => validHeaderName.test(h.name));
}
return true;
},
{
error: "Header names may only contain valid HTTP token characters (letters, digits, and !#$%&'*+-.^_`|~)."
}
)
.refine(
(data) => {
if (data.headers) {
// HTTP header values must be visible ASCII or horizontal whitespace, no control chars (RFC 7230)
const validHeaderValue = /^[\t\x20-\x7E]*$/;
return data.headers.every((h) => validHeaderValue.test(h.value));
}
return true;
},
{
error: "Header values may only contain printable ASCII characters and horizontal whitespace."
}
)
.refine(
(data) => {
if (data.headers) {
// Reject Traefik template syntax {{word}} in names or values
const templatePattern = /\{\{[^}]+\}\}/;
return data.headers.every(
(h) =>
!templatePattern.test(h.name) &&
!templatePattern.test(h.value)
);
}
return true;
},
{
error: "Header names and values must not contain template expressions such as {{value}}."
}
); );
export type UpdateResourceResponse = Resource; export type UpdateResourceResponse = Resource;
@@ -179,7 +136,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}", path: "/resource/{resourceId}",
description: "Update a resource.", description: "Update a resource.",
tags: [OpenAPITags.PublicResource], tags: [OpenAPITags.Resource],
request: { request: {
params: updateResourceParamsSchema, params: updateResourceParamsSchema,
body: { body: {

View File

@@ -38,7 +38,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/rule/{ruleId}", path: "/resource/{resourceId}/rule/{ruleId}",
description: "Update a resource rule.", description: "Update a resource rule.",
tags: [OpenAPITags.PublicResource, OpenAPITags.Rule], tags: [OpenAPITags.Resource, OpenAPITags.Rule],
request: { request: {
params: updateResourceRuleParamsSchema, params: updateResourceRuleParamsSchema,
body: { body: {

View File

@@ -45,7 +45,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/role", path: "/org/{orgId}/role",
description: "Create a role.", description: "Create a role.",
tags: [OpenAPITags.Role], tags: [OpenAPITags.Org, OpenAPITags.Role],
request: { request: {
params: createRoleParamsSchema, params: createRoleParamsSchema,
body: { body: {

View File

@@ -7,7 +7,7 @@ import { and, eq, inArray, sql } from "drizzle-orm";
import { ActionsEnum } from "@server/auth/actions"; import { ActionsEnum } from "@server/auth/actions";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import { object, z } from "zod"; import { z } from "zod";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
const listRolesParamsSchema = z.strictObject({ const listRolesParamsSchema = z.strictObject({
@@ -64,7 +64,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/roles", path: "/org/{orgId}/roles",
description: "List roles.", description: "List roles.",
tags: [OpenAPITags.Role], tags: [OpenAPITags.Org, OpenAPITags.Role],
request: { request: {
params: listRolesParamsSchema, params: listRolesParamsSchema,
query: listRolesSchema query: listRolesSchema

View File

@@ -58,7 +58,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/site", path: "/org/{orgId}/site",
description: "Create a new site.", description: "Create a new site.",
tags: [OpenAPITags.Site], tags: [OpenAPITags.Site, OpenAPITags.Org],
request: { request: {
params: createSiteParamsSchema, params: createSiteParamsSchema,
body: { body: {

View File

@@ -51,7 +51,7 @@ registry.registerPath({
path: "/org/{orgId}/site/{niceId}", path: "/org/{orgId}/site/{niceId}",
description: description:
"Get a site by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.", "Get a site by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.",
tags: [OpenAPITags.Site], tags: [OpenAPITags.Org, OpenAPITags.Site],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string(), orgId: z.string(),

View File

@@ -180,7 +180,7 @@ registry.registerPath({
method: "get", method: "get",
path: "/org/{orgId}/sites", path: "/org/{orgId}/sites",
description: "List all sites in an organization", description: "List all sites in an organization",
tags: [OpenAPITags.Site], tags: [OpenAPITags.Org, OpenAPITags.Site],
request: { request: {
params: listSitesParamsSchema, params: listSitesParamsSchema,
query: listSitesSchema query: listSitesSchema

View File

@@ -35,7 +35,7 @@ registry.registerPath({
path: "/org/{orgId}/pick-site-defaults", path: "/org/{orgId}/pick-site-defaults",
description: description:
"Return pre-requisite data for creating a site, such as the exit node, subnet, Newt credentials, etc.", "Return pre-requisite data for creating a site, such as the exit node, subnet, Newt credentials, etc.",
tags: [OpenAPITags.Site], tags: [OpenAPITags.Org, OpenAPITags.Site],
request: { request: {
params: z.object({ params: z.object({
orgId: z.string() orgId: z.string()

View File

@@ -30,7 +30,7 @@ registry.registerPath({
path: "/site-resource/{siteResourceId}/clients/add", path: "/site-resource/{siteResourceId}/clients/add",
description: description:
"Add a single client to a site resource. Clients with a userId cannot be added.", "Add a single client to a site resource. Clients with a userId cannot be added.",
tags: [OpenAPITags.PrivateResource, OpenAPITags.Client], tags: [OpenAPITags.Resource, OpenAPITags.Client],
request: { request: {
params: addClientToSiteResourceParamsSchema, params: addClientToSiteResourceParamsSchema,
body: { body: {

View File

@@ -30,7 +30,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/site-resource/{siteResourceId}/roles/add", path: "/site-resource/{siteResourceId}/roles/add",
description: "Add a single role to a site resource.", description: "Add a single role to a site resource.",
tags: [OpenAPITags.PrivateResource, OpenAPITags.Role], tags: [OpenAPITags.Resource, OpenAPITags.Role],
request: { request: {
params: addRoleToSiteResourceParamsSchema, params: addRoleToSiteResourceParamsSchema,
body: { body: {

View File

@@ -30,7 +30,7 @@ registry.registerPath({
method: "post", method: "post",
path: "/site-resource/{siteResourceId}/users/add", path: "/site-resource/{siteResourceId}/users/add",
description: "Add a single user to a site resource.", description: "Add a single user to a site resource.",
tags: [OpenAPITags.PrivateResource, OpenAPITags.User], tags: [OpenAPITags.Resource, OpenAPITags.User],
request: { request: {
params: addUserToSiteResourceParamsSchema, params: addUserToSiteResourceParamsSchema,
body: { body: {

View File

@@ -88,7 +88,7 @@ const createSiteResourceSchema = z
}, },
{ {
message: message:
"Destination must be a valid IP address or valid domain AND alias is required" "Destination must be a valid IPV4 address or valid domain AND alias is required"
} }
) )
.refine( .refine(
@@ -114,7 +114,7 @@ registry.registerPath({
method: "put", method: "put",
path: "/org/{orgId}/site-resource", path: "/org/{orgId}/site-resource",
description: "Create a new site resource.", description: "Create a new site resource.",
tags: [OpenAPITags.PrivateResource], tags: [OpenAPITags.Client, OpenAPITags.Org],
request: { request: {
params: createSiteResourceParamsSchema, params: createSiteResourceParamsSchema,
body: { body: {

View File

@@ -23,7 +23,7 @@ registry.registerPath({
method: "delete", method: "delete",
path: "/site-resource/{siteResourceId}", path: "/site-resource/{siteResourceId}",
description: "Delete a site resource.", description: "Delete a site resource.",
tags: [OpenAPITags.PrivateResource], tags: [OpenAPITags.Client, OpenAPITags.Org],
request: { request: {
params: deleteSiteResourceParamsSchema params: deleteSiteResourceParamsSchema
}, },

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