Compare commits

..

169 Commits

Author SHA1 Message Date
Owen Schwartz c207372f75 New translations en-us.json (Norwegian Bokmal) 2026-01-19 22:30:26 -08:00
Owen Schwartz 6606ec0abb New translations en-us.json (Chinese Simplified) 2026-01-19 22:30:24 -08:00
Owen Schwartz d17c821b77 New translations en-us.json (Turkish) 2026-01-19 22:30:23 -08:00
Owen Schwartz 08681fceff New translations en-us.json (Russian) 2026-01-19 22:30:21 -08:00
Owen Schwartz cc8dd44d92 New translations en-us.json (Portuguese) 2026-01-19 22:30:19 -08:00
Owen Schwartz 761666b0f1 New translations en-us.json (Polish) 2026-01-19 22:30:18 -08:00
Owen Schwartz 71b483e95e New translations en-us.json (Dutch) 2026-01-19 22:30:16 -08:00
Owen Schwartz 4f5ceb054a New translations en-us.json (Korean) 2026-01-19 22:30:15 -08:00
Owen Schwartz 560b5b48dc New translations en-us.json (Italian) 2026-01-19 22:30:13 -08:00
Owen Schwartz eb5d7f1c97 New translations en-us.json (German) 2026-01-19 22:30:12 -08:00
Owen Schwartz ae0245b35f New translations en-us.json (Czech) 2026-01-19 22:30:10 -08:00
Owen Schwartz 0fdbea622c New translations en-us.json (Bulgarian) 2026-01-19 22:30:08 -08:00
Owen Schwartz a69a29ef70 New translations en-us.json (Spanish) 2026-01-19 22:30:07 -08:00
Owen Schwartz d7089403f6 New translations en-us.json (French) 2026-01-19 22:30:05 -08:00
Owen Schwartz 37f943edd2 New translations en-us.json (Norwegian Bokmal) 2026-01-18 12:15:10 -08:00
Owen Schwartz a437b8937e New translations en-us.json (Chinese Simplified) 2026-01-18 12:15:08 -08:00
Owen Schwartz fa9de6db42 New translations en-us.json (Turkish) 2026-01-18 12:15:07 -08:00
Owen Schwartz 533bd1b68a New translations en-us.json (Russian) 2026-01-18 12:15:06 -08:00
Owen Schwartz eba84db036 New translations en-us.json (Portuguese) 2026-01-18 12:15:04 -08:00
Owen Schwartz 07d848a40e New translations en-us.json (Polish) 2026-01-18 12:15:03 -08:00
Owen Schwartz 9f54e2efff New translations en-us.json (Dutch) 2026-01-18 12:15:01 -08:00
Owen Schwartz 77f1172640 New translations en-us.json (Korean) 2026-01-18 12:15:00 -08:00
Owen Schwartz f35946860a New translations en-us.json (Italian) 2026-01-18 12:14:59 -08:00
Owen Schwartz 5d28c3e50c New translations en-us.json (German) 2026-01-18 12:14:57 -08:00
Owen Schwartz 6d37c419c2 New translations en-us.json (Czech) 2026-01-18 12:14:56 -08:00
Owen Schwartz bcc0658a20 New translations en-us.json (Bulgarian) 2026-01-18 12:14:55 -08:00
Owen Schwartz 24e49d85e9 New translations en-us.json (Spanish) 2026-01-18 12:14:53 -08:00
Owen Schwartz cc06503fbe New translations en-us.json (French) 2026-01-18 12:14:52 -08:00
Owen Schwartz 984799b854 New translations en-us.json (Norwegian Bokmal) 2026-01-17 21:13:21 -08:00
Owen Schwartz 141d3db56c New translations en-us.json (Chinese Simplified) 2026-01-17 21:13:20 -08:00
Owen Schwartz 1d46a151ff New translations en-us.json (Turkish) 2026-01-17 21:13:18 -08:00
Owen Schwartz b03cb24d1d New translations en-us.json (Russian) 2026-01-17 21:13:17 -08:00
Owen Schwartz ffbd3931be New translations en-us.json (Portuguese) 2026-01-17 21:13:16 -08:00
Owen Schwartz 47f812616a New translations en-us.json (Polish) 2026-01-17 21:13:14 -08:00
Owen Schwartz b1d7d56a7a New translations en-us.json (Dutch) 2026-01-17 21:13:13 -08:00
Owen Schwartz 4bceb70d87 New translations en-us.json (Korean) 2026-01-17 21:13:12 -08:00
Owen Schwartz d23fbf2810 New translations en-us.json (Italian) 2026-01-17 21:13:11 -08:00
Owen Schwartz efb373503c New translations en-us.json (German) 2026-01-17 21:13:09 -08:00
Owen Schwartz 98d8c91f82 New translations en-us.json (Czech) 2026-01-17 21:13:08 -08:00
Owen Schwartz 04697abc41 New translations en-us.json (Bulgarian) 2026-01-17 21:13:07 -08:00
Owen Schwartz 6f63292b26 New translations en-us.json (Spanish) 2026-01-17 21:13:05 -08:00
Owen Schwartz c416dd275f New translations en-us.json (French) 2026-01-17 21:13:04 -08:00
Owen Schwartz 603b66780d New translations en-us.json (Norwegian Bokmal) 2026-01-16 14:50:10 -08:00
Owen Schwartz 6bb72a7447 New translations en-us.json (Chinese Simplified) 2026-01-16 14:50:08 -08:00
Owen Schwartz a679588d3b New translations en-us.json (Turkish) 2026-01-16 14:50:07 -08:00
Owen Schwartz 56114cb11a New translations en-us.json (Russian) 2026-01-16 14:50:06 -08:00
Owen Schwartz ccc6a64332 New translations en-us.json (Portuguese) 2026-01-16 14:50:04 -08:00
Owen Schwartz aee8d0131e New translations en-us.json (Polish) 2026-01-16 14:50:03 -08:00
Owen Schwartz 20fc347182 New translations en-us.json (Dutch) 2026-01-16 14:50:02 -08:00
Owen Schwartz 6462b3c482 New translations en-us.json (Korean) 2026-01-16 14:50:00 -08:00
Owen Schwartz c3d620a9b2 New translations en-us.json (Italian) 2026-01-16 14:49:59 -08:00
Owen Schwartz 1cfab08262 New translations en-us.json (German) 2026-01-16 14:49:58 -08:00
Owen Schwartz e70919b9e4 New translations en-us.json (Czech) 2026-01-16 14:49:57 -08:00
Owen Schwartz 157b673b64 New translations en-us.json (Bulgarian) 2026-01-16 14:49:55 -08:00
Owen Schwartz 2d71293a7c New translations en-us.json (Spanish) 2026-01-16 14:49:54 -08:00
Owen Schwartz ac30d28d7e New translations en-us.json (French) 2026-01-16 14:49:52 -08:00
Owen Schwartz 23cf7bf745 New translations en-us.json (Norwegian Bokmal) 2026-01-15 21:54:41 -08:00
Owen Schwartz d63de9ba40 New translations en-us.json (Chinese Simplified) 2026-01-15 21:54:40 -08:00
Owen Schwartz e7ac5c34a2 New translations en-us.json (Turkish) 2026-01-15 21:54:38 -08:00
Owen Schwartz 1f88876e3c New translations en-us.json (Russian) 2026-01-15 21:54:37 -08:00
Owen Schwartz e0425e2458 New translations en-us.json (Portuguese) 2026-01-15 21:54:36 -08:00
Owen Schwartz 10e9f017fb New translations en-us.json (Polish) 2026-01-15 21:54:34 -08:00
Owen Schwartz 6d2cb69e45 New translations en-us.json (Dutch) 2026-01-15 21:54:33 -08:00
Owen Schwartz 2fab9b65a8 New translations en-us.json (Korean) 2026-01-15 21:54:31 -08:00
Owen Schwartz 47a7a3f230 New translations en-us.json (Italian) 2026-01-15 21:54:30 -08:00
Owen Schwartz 61835ca0e6 New translations en-us.json (German) 2026-01-15 21:54:29 -08:00
Owen Schwartz f4b22c5b31 New translations en-us.json (Czech) 2026-01-15 21:54:27 -08:00
Owen Schwartz 65afe23dd8 New translations en-us.json (Bulgarian) 2026-01-15 21:54:26 -08:00
Owen Schwartz 371e44e235 New translations en-us.json (Spanish) 2026-01-15 21:54:25 -08:00
Owen Schwartz d349795995 New translations en-us.json (French) 2026-01-15 21:54:23 -08:00
Owen Schwartz 7d106294bc New translations en-us.json (Norwegian Bokmal) 2026-01-14 19:55:40 -08:00
Owen Schwartz 8c3e094534 New translations en-us.json (Chinese Simplified) 2026-01-14 19:55:38 -08:00
Owen Schwartz b20a7231bc New translations en-us.json (Turkish) 2026-01-14 19:55:37 -08:00
Owen Schwartz 84998fdb6e New translations en-us.json (Russian) 2026-01-14 19:55:36 -08:00
Owen Schwartz 0d9ece1329 New translations en-us.json (Portuguese) 2026-01-14 19:55:34 -08:00
Owen Schwartz eb7107016b New translations en-us.json (Polish) 2026-01-14 19:55:33 -08:00
Owen Schwartz a7608424b7 New translations en-us.json (Dutch) 2026-01-14 19:55:31 -08:00
Owen Schwartz 6710657789 New translations en-us.json (Korean) 2026-01-14 19:55:30 -08:00
Owen Schwartz b25069ab49 New translations en-us.json (Italian) 2026-01-14 19:55:29 -08:00
Owen Schwartz 6e8d1f9149 New translations en-us.json (German) 2026-01-14 19:55:27 -08:00
Owen Schwartz 825da82e56 New translations en-us.json (Czech) 2026-01-14 19:55:26 -08:00
Owen Schwartz 8d28063724 New translations en-us.json (Bulgarian) 2026-01-14 19:55:25 -08:00
Owen Schwartz a7eed886ab New translations en-us.json (Spanish) 2026-01-14 19:55:23 -08:00
Owen Schwartz 4e965f1e83 New translations en-us.json (French) 2026-01-14 19:55:22 -08:00
Owen Schwartz ea3011afca New translations en-us.json (Norwegian Bokmal) 2026-01-13 15:50:55 -08:00
Owen Schwartz b20e5b4af1 New translations en-us.json (Chinese Simplified) 2026-01-13 15:50:53 -08:00
Owen Schwartz 577660c656 New translations en-us.json (Turkish) 2026-01-13 15:50:52 -08:00
Owen Schwartz f9a9007ed9 New translations en-us.json (Russian) 2026-01-13 15:50:50 -08:00
Owen Schwartz 19873a0b3d New translations en-us.json (Portuguese) 2026-01-13 15:50:49 -08:00
Owen Schwartz 4f13267bc8 New translations en-us.json (Polish) 2026-01-13 15:50:47 -08:00
Owen Schwartz c820fcc518 New translations en-us.json (Dutch) 2026-01-13 15:50:46 -08:00
Owen Schwartz c612972f38 New translations en-us.json (Korean) 2026-01-13 15:50:45 -08:00
Owen Schwartz 395c4eff53 New translations en-us.json (Italian) 2026-01-13 15:50:44 -08:00
Owen Schwartz 6aa40bfd61 New translations en-us.json (German) 2026-01-13 15:50:42 -08:00
Owen Schwartz f5744d0dcd New translations en-us.json (Czech) 2026-01-13 15:50:41 -08:00
Owen Schwartz a975b33b7e New translations en-us.json (Bulgarian) 2026-01-13 15:50:40 -08:00
Owen Schwartz 92be668a55 New translations en-us.json (Spanish) 2026-01-13 15:50:38 -08:00
Owen Schwartz 15153d5e3a New translations en-us.json (French) 2026-01-13 15:50:37 -08:00
Owen Schwartz 212800d365 New translations en-us.json (Norwegian Bokmal) 2026-01-12 21:08:36 -08:00
Owen Schwartz 24ac9a1623 New translations en-us.json (Chinese Simplified) 2026-01-12 21:08:35 -08:00
Owen Schwartz 78bcfed668 New translations en-us.json (Turkish) 2026-01-12 21:08:33 -08:00
Owen Schwartz bf8be14c3a New translations en-us.json (Russian) 2026-01-12 21:08:32 -08:00
Owen Schwartz fe1f7bee60 New translations en-us.json (Portuguese) 2026-01-12 21:08:30 -08:00
Owen Schwartz fbe14acdd1 New translations en-us.json (Polish) 2026-01-12 21:08:29 -08:00
Owen Schwartz 11c0afd9ab New translations en-us.json (Dutch) 2026-01-12 21:08:27 -08:00
Owen Schwartz 52e6b36c2d New translations en-us.json (Korean) 2026-01-12 21:08:26 -08:00
Owen Schwartz dcce15036c New translations en-us.json (Italian) 2026-01-12 21:08:24 -08:00
Owen Schwartz fd27682bbb New translations en-us.json (German) 2026-01-12 21:08:23 -08:00
Owen Schwartz 0cffeda5da New translations en-us.json (Czech) 2026-01-12 21:08:21 -08:00
Owen Schwartz aff486ca57 New translations en-us.json (Bulgarian) 2026-01-12 21:08:20 -08:00
Owen Schwartz d3eb950888 New translations en-us.json (Spanish) 2026-01-12 21:08:18 -08:00
Owen Schwartz 1b98f44588 New translations en-us.json (French) 2026-01-12 21:08:16 -08:00
Owen Schwartz 8a5a0c7c18 New translations en-us.json (Norwegian Bokmal) 2026-01-12 16:20:12 -08:00
Owen Schwartz d2f0825498 New translations en-us.json (Chinese Simplified) 2026-01-12 16:20:11 -08:00
Owen Schwartz ac88b79066 New translations en-us.json (Turkish) 2026-01-12 16:20:09 -08:00
Owen Schwartz 9160d94c7b New translations en-us.json (Russian) 2026-01-12 16:20:08 -08:00
Owen Schwartz de6ce7aa10 New translations en-us.json (Portuguese) 2026-01-12 16:20:06 -08:00
Owen Schwartz 91a4b11632 New translations en-us.json (Polish) 2026-01-12 16:20:05 -08:00
Owen Schwartz 99ed4ea683 New translations en-us.json (Dutch) 2026-01-12 16:20:04 -08:00
Owen Schwartz 1a0d4870ed New translations en-us.json (Korean) 2026-01-12 16:20:02 -08:00
Owen Schwartz f1bd315a96 New translations en-us.json (Italian) 2026-01-12 16:20:01 -08:00
Owen Schwartz 42d8e932ff New translations en-us.json (German) 2026-01-12 16:19:59 -08:00
Owen Schwartz 658ec87d1b New translations en-us.json (Czech) 2026-01-12 16:19:58 -08:00
Owen Schwartz e9bbee13c0 New translations en-us.json (Bulgarian) 2026-01-12 16:19:57 -08:00
Owen Schwartz 99164bf7ab New translations en-us.json (Spanish) 2026-01-12 16:19:55 -08:00
Owen Schwartz 6a3cc578a7 New translations en-us.json (French) 2026-01-12 16:19:54 -08:00
Owen Schwartz 720c3d7c41 New translations en-us.json (German) 2026-01-11 17:43:02 -08:00
Owen Schwartz 72733a9b77 New translations en-us.json (Norwegian Bokmal) 2026-01-11 14:32:28 -08:00
Owen Schwartz 1295141eaf New translations en-us.json (Chinese Simplified) 2026-01-11 14:32:26 -08:00
Owen Schwartz e8099795b3 New translations en-us.json (Turkish) 2026-01-11 14:32:25 -08:00
Owen Schwartz d65fbcc28b New translations en-us.json (Russian) 2026-01-11 14:32:24 -08:00
Owen Schwartz ad0a17f642 New translations en-us.json (Portuguese) 2026-01-11 14:32:23 -08:00
Owen Schwartz c2ecabab33 New translations en-us.json (Polish) 2026-01-11 14:32:21 -08:00
Owen Schwartz 7170b14b1f New translations en-us.json (Dutch) 2026-01-11 14:32:20 -08:00
Owen Schwartz 343ba64eb4 New translations en-us.json (Korean) 2026-01-11 14:32:19 -08:00
Owen Schwartz 242c314e42 New translations en-us.json (Italian) 2026-01-11 14:32:17 -08:00
Owen Schwartz 16f9191bc5 New translations en-us.json (German) 2026-01-11 14:32:16 -08:00
Owen Schwartz 6ec51e50d1 New translations en-us.json (Czech) 2026-01-11 14:32:15 -08:00
Owen Schwartz f1d73c5f8c New translations en-us.json (Bulgarian) 2026-01-11 14:32:13 -08:00
Owen Schwartz 6093add470 New translations en-us.json (Spanish) 2026-01-11 14:32:12 -08:00
Owen Schwartz 4af6bd43ef New translations en-us.json (French) 2026-01-11 14:32:11 -08:00
Owen Schwartz 99ad7c6bef New translations en-us.json (Norwegian Bokmal) 2026-01-09 18:42:36 -08:00
Owen Schwartz fc192d955b New translations en-us.json (Chinese Simplified) 2026-01-09 18:42:35 -08:00
Owen Schwartz 914f1b41c6 New translations en-us.json (Turkish) 2026-01-09 18:42:34 -08:00
Owen Schwartz 0601eacfd5 New translations en-us.json (Russian) 2026-01-09 18:42:33 -08:00
Owen Schwartz 5481eae606 New translations en-us.json (Portuguese) 2026-01-09 18:42:31 -08:00
Owen Schwartz d868c85ebe New translations en-us.json (Polish) 2026-01-09 18:42:30 -08:00
Owen Schwartz ff0f0aa4e0 New translations en-us.json (Dutch) 2026-01-09 18:42:29 -08:00
Owen Schwartz d4f9f20ef9 New translations en-us.json (Korean) 2026-01-09 18:42:27 -08:00
Owen Schwartz 30808ce2db New translations en-us.json (Italian) 2026-01-09 18:42:26 -08:00
Owen Schwartz db5f7ed731 New translations en-us.json (German) 2026-01-09 18:42:25 -08:00
Owen Schwartz 6fd69f1293 New translations en-us.json (Czech) 2026-01-09 18:42:23 -08:00
Owen Schwartz 9f1dd42a85 New translations en-us.json (Bulgarian) 2026-01-09 18:42:22 -08:00
Owen Schwartz 7b55ef1cc8 New translations en-us.json (Spanish) 2026-01-09 18:42:20 -08:00
Owen Schwartz b988f21b15 New translations en-us.json (French) 2026-01-09 18:42:19 -08:00
Owen Schwartz a688757f5c New translations en-us.json (Norwegian Bokmal) 2026-01-09 15:04:27 -08:00
Owen Schwartz 0ed1852a35 New translations en-us.json (Chinese Simplified) 2026-01-09 15:04:26 -08:00
Owen Schwartz a5c3702b8d New translations en-us.json (Turkish) 2026-01-09 15:04:25 -08:00
Owen Schwartz b25f43da9a New translations en-us.json (Russian) 2026-01-09 15:04:23 -08:00
Owen Schwartz ea0f0de802 New translations en-us.json (Portuguese) 2026-01-09 15:04:22 -08:00
Owen Schwartz 476131859d New translations en-us.json (Polish) 2026-01-09 15:04:21 -08:00
Owen Schwartz 8573c38332 New translations en-us.json (Dutch) 2026-01-09 15:04:19 -08:00
Owen Schwartz bc9d2835be New translations en-us.json (Korean) 2026-01-09 15:04:18 -08:00
Owen Schwartz df582b0409 New translations en-us.json (Italian) 2026-01-09 15:04:17 -08:00
Owen Schwartz e3865dcd4d New translations en-us.json (German) 2026-01-09 15:04:15 -08:00
Owen Schwartz 0eba5cdb0b New translations en-us.json (Czech) 2026-01-09 15:04:14 -08:00
Owen Schwartz 2284f2cafc New translations en-us.json (Bulgarian) 2026-01-09 15:04:12 -08:00
Owen Schwartz 80215a7de0 New translations en-us.json (Spanish) 2026-01-09 15:04:11 -08:00
Owen Schwartz ddd829064a New translations en-us.json (French) 2026-01-09 15:04:10 -08:00
255 changed files with 9264 additions and 19371 deletions
+26 -129
View File
@@ -29,7 +29,7 @@ jobs:
permissions: write-all permissions: write-all
steps: steps:
- name: Configure AWS credentials - name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v5 uses: aws-actions/configure-aws-credentials@v2
with: with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }} role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600 role-duration-seconds: 3600
@@ -264,7 +264,7 @@ jobs:
shell: bash shell: bash
- name: Install Go - name: Install Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with: with:
go-version: 1.24 go-version: 1.24
@@ -329,89 +329,20 @@ jobs:
skopeo login ghcr.io -u "${{ github.actor }}" -p "${{ secrets.GITHUB_TOKEN }}" skopeo login ghcr.io -u "${{ github.actor }}" -p "${{ secrets.GITHUB_TOKEN }}"
shell: bash shell: bash
- name: Copy tags from Docker Hub to GHCR - name: Copy tag from Docker Hub to GHCR
# Mirror the already-built images (all architectures) to GHCR so we can sign them # Mirror the already-built image (all architectures) to GHCR so we can sign it
# Wait a bit for both architectures to be available in Docker Hub manifest # Wait a bit for both architectures to be available in Docker Hub manifest
env: env:
REGISTRY_AUTH_FILE: ${{ runner.temp }}/containers/auth.json REGISTRY_AUTH_FILE: ${{ runner.temp }}/containers/auth.json
run: | run: |
set -euo pipefail set -euo pipefail
TAG=${{ env.TAG }} TAG=${{ env.TAG }}
MAJOR_TAG=$(echo $TAG | cut -d. -f1) echo "Waiting for multi-arch manifest to be ready..."
MINOR_TAG=$(echo $TAG | cut -d. -f1,2)
echo "Waiting for multi-arch manifests to be ready..."
sleep 30 sleep 30
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:${TAG} -> ${{ env.GHCR_IMAGE }}:${TAG}"
# Determine if this is an RC release skopeo copy --all --retry-times 3 \
IS_RC="false" docker://$DOCKERHUB_IMAGE:$TAG \
if [[ "$TAG" == *"-rc."* ]]; then docker://$GHCR_IMAGE:$TAG
IS_RC="true"
fi
if [ "$IS_RC" = "true" ]; then
echo "RC release detected - copying version-specific tags only"
# SQLite OSS
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:${TAG} -> ${{ env.GHCR_IMAGE }}:${TAG}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:$TAG \
docker://$GHCR_IMAGE:$TAG
# PostgreSQL OSS
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:postgresql-${TAG} -> ${{ env.GHCR_IMAGE }}:postgresql-${TAG}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:postgresql-$TAG \
docker://$GHCR_IMAGE:postgresql-$TAG
# SQLite Enterprise
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:ee-${TAG} -> ${{ env.GHCR_IMAGE }}:ee-${TAG}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:ee-$TAG \
docker://$GHCR_IMAGE:ee-$TAG
# PostgreSQL Enterprise
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:ee-postgresql-${TAG} -> ${{ env.GHCR_IMAGE }}:ee-postgresql-${TAG}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:ee-postgresql-$TAG \
docker://$GHCR_IMAGE:ee-postgresql-$TAG
else
echo "Regular release detected - copying all tags (latest, major, minor, full version)"
# SQLite OSS - all tags
for TAG_SUFFIX in "latest" "$MAJOR_TAG" "$MINOR_TAG" "$TAG"; do
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:${TAG_SUFFIX} -> ${{ env.GHCR_IMAGE }}:${TAG_SUFFIX}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:$TAG_SUFFIX \
docker://$GHCR_IMAGE:$TAG_SUFFIX
done
# PostgreSQL OSS - all tags
for TAG_SUFFIX in "latest" "$MAJOR_TAG" "$MINOR_TAG" "$TAG"; do
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:postgresql-${TAG_SUFFIX} -> ${{ env.GHCR_IMAGE }}:postgresql-${TAG_SUFFIX}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:postgresql-$TAG_SUFFIX \
docker://$GHCR_IMAGE:postgresql-$TAG_SUFFIX
done
# SQLite Enterprise - all tags
for TAG_SUFFIX in "latest" "$MAJOR_TAG" "$MINOR_TAG" "$TAG"; do
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:ee-${TAG_SUFFIX} -> ${{ env.GHCR_IMAGE }}:ee-${TAG_SUFFIX}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:ee-$TAG_SUFFIX \
docker://$GHCR_IMAGE:ee-$TAG_SUFFIX
done
# PostgreSQL Enterprise - all tags
for TAG_SUFFIX in "latest" "$MAJOR_TAG" "$MINOR_TAG" "$TAG"; do
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:ee-postgresql-${TAG_SUFFIX} -> ${{ env.GHCR_IMAGE }}:ee-postgresql-${TAG_SUFFIX}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:ee-postgresql-$TAG_SUFFIX \
docker://$GHCR_IMAGE:ee-postgresql-$TAG_SUFFIX
done
fi
echo "All images copied successfully to GHCR!"
shell: bash shell: bash
- name: Login to GitHub Container Registry (for cosign) - name: Login to GitHub Container Registry (for cosign)
@@ -440,62 +371,28 @@ jobs:
issuer="https://token.actions.githubusercontent.com" issuer="https://token.actions.githubusercontent.com"
id_regex="^https://github.com/${{ github.repository }}/.+" # accept this repo (all workflows/refs) id_regex="^https://github.com/${{ github.repository }}/.+" # accept this repo (all workflows/refs)
# Determine if this is an RC release for IMAGE in "${GHCR_IMAGE}" "${DOCKERHUB_IMAGE}"; do
IS_RC="false" echo "Processing ${IMAGE}:${TAG}"
if [[ "$TAG" == *"-rc."* ]]; then
IS_RC="true"
fi
# Define image variants to sign DIGEST="$(skopeo inspect --retry-times 3 docker://${IMAGE}:${TAG} | jq -r '.Digest')"
if [ "$IS_RC" = "true" ]; then REF="${IMAGE}@${DIGEST}"
echo "RC release - signing version-specific tags only" echo "Resolved digest: ${REF}"
IMAGE_TAGS=(
"${TAG}"
"postgresql-${TAG}"
"ee-${TAG}"
"ee-postgresql-${TAG}"
)
else
echo "Regular release - signing all tags"
MAJOR_TAG=$(echo $TAG | cut -d. -f1)
MINOR_TAG=$(echo $TAG | cut -d. -f1,2)
IMAGE_TAGS=(
"latest" "$MAJOR_TAG" "$MINOR_TAG" "$TAG"
"postgresql-latest" "postgresql-$MAJOR_TAG" "postgresql-$MINOR_TAG" "postgresql-$TAG"
"ee-latest" "ee-$MAJOR_TAG" "ee-$MINOR_TAG" "ee-$TAG"
"ee-postgresql-latest" "ee-postgresql-$MAJOR_TAG" "ee-postgresql-$MINOR_TAG" "ee-postgresql-$TAG"
)
fi
# Sign each image variant for both registries echo "==> cosign sign (keyless) --recursive ${REF}"
for BASE_IMAGE in "${GHCR_IMAGE}" "${DOCKERHUB_IMAGE}"; do cosign sign --recursive "${REF}"
for IMAGE_TAG in "${IMAGE_TAGS[@]}"; do
echo "Processing ${BASE_IMAGE}:${IMAGE_TAG}"
DIGEST="$(skopeo inspect --retry-times 3 docker://${BASE_IMAGE}:${IMAGE_TAG} | jq -r '.Digest')" echo "==> cosign sign (key) --recursive ${REF}"
REF="${BASE_IMAGE}@${DIGEST}" cosign sign --key env://COSIGN_PRIVATE_KEY --recursive "${REF}"
echo "Resolved digest: ${REF}"
echo "==> cosign sign (keyless) --recursive ${REF}" echo "==> cosign verify (public key) ${REF}"
cosign sign --recursive "${REF}" cosign verify --key env://COSIGN_PUBLIC_KEY "${REF}" -o text
echo "==> cosign sign (key) --recursive ${REF}" echo "==> cosign verify (keyless policy) ${REF}"
cosign sign --key env://COSIGN_PRIVATE_KEY --recursive "${REF}" cosign verify \
--certificate-oidc-issuer "${issuer}" \
echo "==> cosign verify (public key) ${REF}" --certificate-identity-regexp "${id_regex}" \
cosign verify --key env://COSIGN_PUBLIC_KEY "${REF}" -o text "${REF}" -o text
echo "==> cosign verify (keyless policy) ${REF}"
cosign verify \
--certificate-oidc-issuer "${issuer}" \
--certificate-identity-regexp "${id_regex}" \
"${REF}" -o text
echo "✓ Successfully signed and verified ${BASE_IMAGE}:${IMAGE_TAG}"
done
done done
echo "All images signed and verified successfully!"
shell: bash shell: bash
post-run: post-run:
@@ -513,7 +410,7 @@ jobs:
permissions: write-all permissions: write-all
steps: steps:
- name: Configure AWS credentials - name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v5 uses: aws-actions/configure-aws-credentials@v2
with: with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }} role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600 role-duration-seconds: 3600
-426
View File
@@ -1,426 +0,0 @@
name: CI/CD Pipeline
# CI/CD workflow for building, publishing, mirroring, signing container images and building release binaries.
# Actions are pinned to specific SHAs to reduce supply-chain risk. This workflow triggers on tag push events.
permissions:
contents: read
packages: write # for GHCR push
id-token: write # for Cosign Keyless (OIDC) Signing
# Required secrets:
# - DOCKER_HUB_USERNAME / DOCKER_HUB_ACCESS_TOKEN: push to Docker Hub
# - GITHUB_TOKEN: used for GHCR login and OIDC keyless signing
# - COSIGN_PRIVATE_KEY / COSIGN_PASSWORD / COSIGN_PUBLIC_KEY: for key-based signing
on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+"
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
pre-run:
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600
aws-region: ${{ secrets.AWS_REGION }}
- name: Verify AWS identity
run: aws sts get-caller-identity
- name: Start EC2 instances
run: |
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_ARM_RUNNER }}
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_AMD_RUNNER }}
echo "EC2 instances started"
release-arm:
name: Build and Release (ARM64)
runs-on: [self-hosted, linux, arm64, us-east-1]
needs: [pre-run]
if: >-
${{
needs.pre-run.result == 'success'
}}
# Job-level timeout to avoid runaway or stuck runs
timeout-minutes: 120
env:
# Target images
DOCKERHUB_IMAGE: docker.io/fosrl/${{ github.event.repository.name }}
GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Monitor storage space
run: |
THRESHOLD=75
USED_SPACE=$(df / | grep / | awk '{ print $5 }' | sed 's/%//g')
echo "Used space: $USED_SPACE%"
if [ "$USED_SPACE" -ge "$THRESHOLD" ]; then
echo "Used space is below the threshold of 75% free. Running Docker system prune."
echo y | docker system prune -a
else
echo "Storage space is above the threshold. No action needed."
fi
- name: Log in to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: docker.io
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Extract tag name
id: get-tag
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
shell: bash
- name: Update version in package.json
run: |
TAG=${{ env.TAG }}
sed -i "s/export const APP_VERSION = \".*\";/export const APP_VERSION = \"$TAG\";/" server/lib/consts.ts
cat server/lib/consts.ts
shell: bash
- name: Check if release candidate
id: check-rc
run: |
TAG=${{ env.TAG }}
if [[ "$TAG" == *"-rc."* ]]; then
echo "IS_RC=true" >> $GITHUB_ENV
else
echo "IS_RC=false" >> $GITHUB_ENV
fi
shell: bash
- name: Build and push Docker images (Docker Hub - ARM64)
run: |
TAG=${{ env.TAG }}
if [ "$IS_RC" = "true" ]; then
make build-rc-arm tag=$TAG
else
make build-release-arm tag=$TAG
fi
echo "Built & pushed ARM64 images to: ${{ env.DOCKERHUB_IMAGE }}:${TAG}"
shell: bash
release-amd:
name: Build and Release (AMD64)
runs-on: [self-hosted, linux, x64, us-east-1]
needs: [pre-run]
if: >-
${{
needs.pre-run.result == 'success'
}}
# Job-level timeout to avoid runaway or stuck runs
timeout-minutes: 120
env:
# Target images
DOCKERHUB_IMAGE: docker.io/fosrl/${{ github.event.repository.name }}
GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Monitor storage space
run: |
THRESHOLD=75
USED_SPACE=$(df / | grep / | awk '{ print $5 }' | sed 's/%//g')
echo "Used space: $USED_SPACE%"
if [ "$USED_SPACE" -ge "$THRESHOLD" ]; then
echo "Used space is below the threshold of 75% free. Running Docker system prune."
echo y | docker system prune -a
else
echo "Storage space is above the threshold. No action needed."
fi
- name: Log in to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: docker.io
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Extract tag name
id: get-tag
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
shell: bash
- name: Update version in package.json
run: |
TAG=${{ env.TAG }}
sed -i "s/export const APP_VERSION = \".*\";/export const APP_VERSION = \"$TAG\";/" server/lib/consts.ts
cat server/lib/consts.ts
shell: bash
- name: Check if release candidate
id: check-rc
run: |
TAG=${{ env.TAG }}
if [[ "$TAG" == *"-rc."* ]]; then
echo "IS_RC=true" >> $GITHUB_ENV
else
echo "IS_RC=false" >> $GITHUB_ENV
fi
shell: bash
- name: Build and push Docker images (Docker Hub - AMD64)
run: |
TAG=${{ env.TAG }}
if [ "$IS_RC" = "true" ]; then
make build-rc-amd tag=$TAG
else
make build-release-amd tag=$TAG
fi
echo "Built & pushed AMD64 images to: ${{ env.DOCKERHUB_IMAGE }}:${TAG}"
shell: bash
create-manifest:
name: Create Multi-Arch Manifests
runs-on: [self-hosted, linux, x64, us-east-1]
needs: [release-arm, release-amd]
if: >-
${{
needs.release-arm.result == 'success' &&
needs.release-amd.result == 'success'
}}
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Log in to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: docker.io
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Extract tag name
id: get-tag
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
shell: bash
- name: Check if release candidate
id: check-rc
run: |
TAG=${{ env.TAG }}
if [[ "$TAG" == *"-rc."* ]]; then
echo "IS_RC=true" >> $GITHUB_ENV
else
echo "IS_RC=false" >> $GITHUB_ENV
fi
shell: bash
- name: Create multi-arch manifests
run: |
TAG=${{ env.TAG }}
if [ "$IS_RC" = "true" ]; then
make create-manifests-rc tag=$TAG
else
make create-manifests tag=$TAG
fi
echo "Created multi-arch manifests for tag: ${TAG}"
shell: bash
sign-and-package:
name: Sign and Package
runs-on: [self-hosted, linux, x64, us-east-1]
needs: [release-arm, release-amd, create-manifest]
if: >-
${{
needs.release-arm.result == 'success' &&
needs.release-amd.result == 'success' &&
needs.create-manifest.result == 'success'
}}
# Job-level timeout to avoid runaway or stuck runs
timeout-minutes: 120
env:
# Target images
DOCKERHUB_IMAGE: docker.io/fosrl/${{ github.event.repository.name }}
GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Extract tag name
id: get-tag
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
shell: bash
- name: Install Go
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version: 1.24
- name: Update version in package.json
run: |
TAG=${{ env.TAG }}
sed -i "s/export const APP_VERSION = \".*\";/export const APP_VERSION = \"$TAG\";/" server/lib/consts.ts
cat server/lib/consts.ts
shell: bash
- name: Pull latest Gerbil version
id: get-gerbil-tag
run: |
LATEST_TAG=$(curl -s https://api.github.com/repos/fosrl/gerbil/tags | jq -r '.[0].name')
echo "LATEST_GERBIL_TAG=$LATEST_TAG" >> $GITHUB_ENV
shell: bash
- name: Pull latest Badger version
id: get-badger-tag
run: |
LATEST_TAG=$(curl -s https://api.github.com/repos/fosrl/badger/tags | jq -r '.[0].name')
echo "LATEST_BADGER_TAG=$LATEST_TAG" >> $GITHUB_ENV
shell: bash
- name: Update install/main.go
run: |
PANGOLIN_VERSION=${{ env.TAG }}
GERBIL_VERSION=${{ env.LATEST_GERBIL_TAG }}
BADGER_VERSION=${{ env.LATEST_BADGER_TAG }}
sed -i "s/config.PangolinVersion = \".*\"/config.PangolinVersion = \"$PANGOLIN_VERSION\"/" install/main.go
sed -i "s/config.GerbilVersion = \".*\"/config.GerbilVersion = \"$GERBIL_VERSION\"/" install/main.go
sed -i "s/config.BadgerVersion = \".*\"/config.BadgerVersion = \"$BADGER_VERSION\"/" install/main.go
echo "Updated install/main.go with Pangolin version $PANGOLIN_VERSION, Gerbil version $GERBIL_VERSION, and Badger version $BADGER_VERSION"
cat install/main.go
shell: bash
- name: Build installer
working-directory: install
run: |
make go-build-release
- name: Upload artifacts from /install/bin
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: install-bin
path: install/bin/
- name: Install skopeo + jq
# skopeo: copy/inspect images between registries
# jq: JSON parsing tool used to extract digest values
run: |
sudo apt-get update -y
sudo apt-get install -y skopeo jq
skopeo --version
shell: bash
- name: Login to GHCR
env:
REGISTRY_AUTH_FILE: ${{ runner.temp }}/containers/auth.json
run: |
mkdir -p "$(dirname "$REGISTRY_AUTH_FILE")"
skopeo login ghcr.io -u "${{ github.actor }}" -p "${{ secrets.GITHUB_TOKEN }}"
shell: bash
- name: Copy tag from Docker Hub to GHCR
# Mirror the already-built image (all architectures) to GHCR so we can sign it
# Wait a bit for both architectures to be available in Docker Hub manifest
env:
REGISTRY_AUTH_FILE: ${{ runner.temp }}/containers/auth.json
run: |
set -euo pipefail
TAG=${{ env.TAG }}
echo "Waiting for multi-arch manifest to be ready..."
sleep 30
echo "Copying ${{ env.DOCKERHUB_IMAGE }}:${TAG} -> ${{ env.GHCR_IMAGE }}:${TAG}"
skopeo copy --all --retry-times 3 \
docker://$DOCKERHUB_IMAGE:$TAG \
docker://$GHCR_IMAGE:$TAG
shell: bash
- name: Login to GitHub Container Registry (for cosign)
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Install cosign
# cosign is used to sign and verify container images (key and keyless)
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
- name: Dual-sign and verify (GHCR & Docker Hub)
# Sign each image by digest using keyless (OIDC) and key-based signing,
# then verify both the public key signature and the keyless OIDC signature.
env:
TAG: ${{ env.TAG }}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
COSIGN_PUBLIC_KEY: ${{ secrets.COSIGN_PUBLIC_KEY }}
COSIGN_YES: "true"
run: |
set -euo pipefail
issuer="https://token.actions.githubusercontent.com"
id_regex="^https://github.com/${{ github.repository }}/.+" # accept this repo (all workflows/refs)
for IMAGE in "${GHCR_IMAGE}" "${DOCKERHUB_IMAGE}"; do
echo "Processing ${IMAGE}:${TAG}"
DIGEST="$(skopeo inspect --retry-times 3 docker://${IMAGE}:${TAG} | jq -r '.Digest')"
REF="${IMAGE}@${DIGEST}"
echo "Resolved digest: ${REF}"
echo "==> cosign sign (keyless) --recursive ${REF}"
cosign sign --recursive "${REF}"
echo "==> cosign sign (key) --recursive ${REF}"
cosign sign --key env://COSIGN_PRIVATE_KEY --recursive "${REF}"
echo "==> cosign verify (public key) ${REF}"
cosign verify --key env://COSIGN_PUBLIC_KEY "${REF}" -o text
echo "==> cosign verify (keyless policy) ${REF}"
cosign verify \
--certificate-oidc-issuer "${issuer}" \
--certificate-identity-regexp "${id_regex}" \
"${REF}" -o text
done
shell: bash
post-run:
needs: [pre-run, release-arm, release-amd, create-manifest, sign-and-package]
if: >-
${{
always() &&
needs.pre-run.result == 'success' &&
(needs.release-arm.result == 'success' || needs.release-arm.result == 'skipped' || needs.release-arm.result == 'failure') &&
(needs.release-amd.result == 'success' || needs.release-amd.result == 'skipped' || needs.release-amd.result == 'failure') &&
(needs.create-manifest.result == 'success' || needs.create-manifest.result == 'skipped' || needs.create-manifest.result == 'failure') &&
(needs.sign-and-package.result == 'success' || needs.sign-and-package.result == 'skipped' || needs.sign-and-package.result == 'failure')
}}
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600
aws-region: ${{ secrets.AWS_REGION }}
- name: Verify AWS identity
run: aws sts get-caller-identity
- name: Stop EC2 instances
run: |
aws ec2 stop-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_ARM_RUNNER }}
aws ec2 stop-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_AMD_RUNNER }}
echo "EC2 instances stopped"
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with: with:
node-version: '22' node-version: '22'
-125
View File
@@ -1,125 +0,0 @@
name: CI/CD Pipeline
# CI/CD workflow for building, publishing, mirroring, signing container images and building release binaries.
# Actions are pinned to specific SHAs to reduce supply-chain risk. This workflow triggers on tag push events.
permissions:
contents: read
packages: write # for GHCR push
id-token: write # for Cosign Keyless (OIDC) Signing
on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+-s.[0-9]+"
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
pre-run:
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600
aws-region: ${{ secrets.AWS_REGION }}
- name: Verify AWS identity
run: aws sts get-caller-identity
- name: Start EC2 instances
run: |
aws ec2 start-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_ARM_RUNNER }}
echo "EC2 instances started"
release-arm:
name: Build and Release (ARM64)
runs-on: [self-hosted, linux, arm64, us-east-1]
needs: [pre-run]
if: >-
${{
needs.pre-run.result == 'success'
}}
# Job-level timeout to avoid runaway or stuck runs
timeout-minutes: 120
env:
# Target images
AWS_IMAGE: ${{ secrets.aws_account_id }}.dkr.ecr.us-east-1.amazonaws.com/${{ github.event.repository.name }}
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Monitor storage space
run: |
THRESHOLD=75
USED_SPACE=$(df / | grep / | awk '{ print $5 }' | sed 's/%//g')
echo "Used space: $USED_SPACE%"
if [ "$USED_SPACE" -ge "$THRESHOLD" ]; then
echo "Used space is below the threshold of 75% free. Running Docker system prune."
echo y | docker system prune -a
else
echo "Storage space is above the threshold. No action needed."
fi
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.aws_account_id }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Extract tag name
id: get-tag
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
shell: bash
- name: Update version in package.json
run: |
TAG=${{ env.TAG }}
sed -i "s/export const APP_VERSION = \".*\";/export const APP_VERSION = \"$TAG\";/" server/lib/consts.ts
cat server/lib/consts.ts
shell: bash
- name: Build and push Docker images (Docker Hub - ARM64)
run: |
TAG=${{ env.TAG }}
make build-saas tag=$TAG
echo "Built & pushed ARM64 images to: ${{ env.AWS_IMAGE }}:${TAG}"
shell: bash
post-run:
needs: [pre-run, release-arm]
if: >-
${{
always() &&
needs.pre-run.result == 'success' &&
(needs.release-arm.result == 'success' || needs.release-arm.result == 'skipped' || needs.release-arm.result == 'failure')
}}
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-duration-seconds: 3600
aws-region: ${{ secrets.AWS_REGION }}
- name: Verify AWS identity
run: aws sts get-caller-identity
- name: Stop EC2 instances
run: |
aws ec2 stop-instances --instance-ids ${{ secrets.EC2_INSTANCE_ID_ARM_RUNNER }}
echo "EC2 instances stopped"
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install Node - name: Install Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with: with:
node-version: '22' node-version: '22'
+1 -2
View File
@@ -50,5 +50,4 @@ dynamic/
*.mmdb *.mmdb
scratch/ scratch/
tsconfig.json tsconfig.json
hydrateSaas.ts hydrateSaas.ts
CLAUDE.md
+3 -3
View File
@@ -4,13 +4,13 @@
}, },
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"[jsonc]": { "[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[javascript]": { "[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[typescriptreact]": { "[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
@@ -19,4 +19,4 @@
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"editor.formatOnSave": true "editor.formatOnSave": true
} }
-25
View File
@@ -1,20 +1,10 @@
FROM node:24-alpine AS builder FROM node:24-alpine AS builder
# OCI Image Labels - Build Args for dynamic values
ARG VERSION="dev"
ARG REVISION=""
ARG CREATED=""
ARG LICENSE="AGPL-3.0"
WORKDIR /app WORKDIR /app
ARG BUILD=oss ARG BUILD=oss
ARG DATABASE=sqlite ARG DATABASE=sqlite
# Derive title and description based on BUILD type
ARG IMAGE_TITLE="Pangolin"
ARG IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere"
RUN apk add --no-cache curl tzdata python3 make g++ RUN apk add --no-cache curl tzdata python3 make g++
# COPY package.json package-lock.json ./ # COPY package.json package-lock.json ./
@@ -77,21 +67,6 @@ COPY ./cli/wrapper.sh /usr/local/bin/pangctl
RUN chmod +x /usr/local/bin/pangctl ./dist/cli.mjs RUN chmod +x /usr/local/bin/pangctl ./dist/cli.mjs
COPY server/db/names.json ./dist/names.json COPY server/db/names.json ./dist/names.json
COPY server/db/ios_models.json ./dist/ios_models.json
COPY server/db/mac_models.json ./dist/mac_models.json
COPY public ./public COPY public ./public
# OCI Image Labels
# https://github.com/opencontainers/image-spec/blob/main/annotations.md
LABEL org.opencontainers.image.source="https://github.com/fosrl/pangolin" \
org.opencontainers.image.url="https://github.com/fosrl/pangolin" \
org.opencontainers.image.documentation="https://docs.pangolin.net" \
org.opencontainers.image.vendor="Fossorial" \
org.opencontainers.image.licenses="${LICENSE}" \
org.opencontainers.image.title="${IMAGE_TITLE}" \
org.opencontainers.image.description="${IMAGE_DESCRIPTION}" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${REVISION}" \
org.opencontainers.image.created="${CREATED}"
CMD ["npm", "run", "start"] CMD ["npm", "run", "start"]
+7 -198
View File
@@ -3,25 +3,6 @@
major_tag := $(shell echo $(tag) | cut -d. -f1) major_tag := $(shell echo $(tag) | cut -d. -f1)
minor_tag := $(shell echo $(tag) | cut -d. -f1,2) minor_tag := $(shell echo $(tag) | cut -d. -f1,2)
# OCI label variables
CREATED := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
# Common OCI build args for OSS builds
OCI_ARGS_OSS = --build-arg VERSION=$(tag) \
--build-arg REVISION=$(REVISION) \
--build-arg CREATED=$(CREATED) \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere"
# Common OCI build args for Enterprise builds
OCI_ARGS_EE = --build-arg VERSION=$(tag) \
--build-arg REVISION=$(REVISION) \
--build-arg CREATED=$(CREATED) \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere"
.PHONY: build-release build-sqlite build-postgresql build-ee-sqlite build-ee-postgresql .PHONY: build-release build-sqlite build-postgresql build-ee-sqlite build-ee-postgresql
build-release: build-sqlite build-postgresql build-ee-sqlite build-ee-postgresql build-release: build-sqlite build-postgresql build-ee-sqlite build-ee-postgresql
@@ -34,7 +15,6 @@ build-sqlite:
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
$(OCI_ARGS_OSS) \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:latest \ --tag fosrl/pangolin:latest \
--tag fosrl/pangolin:$(major_tag) \ --tag fosrl/pangolin:$(major_tag) \
@@ -50,7 +30,6 @@ build-postgresql:
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
$(OCI_ARGS_OSS) \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:postgresql-latest \ --tag fosrl/pangolin:postgresql-latest \
--tag fosrl/pangolin:postgresql-$(major_tag) \ --tag fosrl/pangolin:postgresql-$(major_tag) \
@@ -66,7 +45,6 @@ build-ee-sqlite:
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
$(OCI_ARGS_EE) \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:ee-latest \ --tag fosrl/pangolin:ee-latest \
--tag fosrl/pangolin:ee-$(major_tag) \ --tag fosrl/pangolin:ee-$(major_tag) \
@@ -82,7 +60,6 @@ build-ee-postgresql:
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
$(OCI_ARGS_EE) \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:ee-postgresql-latest \ --tag fosrl/pangolin:ee-postgresql-latest \
--tag fosrl/pangolin:ee-postgresql-$(major_tag) \ --tag fosrl/pangolin:ee-postgresql-$(major_tag) \
@@ -90,18 +67,6 @@ build-ee-postgresql:
--tag fosrl/pangolin:ee-postgresql-$(tag) \ --tag fosrl/pangolin:ee-postgresql-$(tag) \
--push . --push .
build-saas:
@if [ -z "$(tag)" ]; then \
echo "Error: tag is required. Usage: make build-release tag=<tag>"; \
exit 1; \
fi
docker buildx build \
--build-arg BUILD=saas \
--build-arg DATABASE=pg \
--platform linux/arm64 \
--tag $(AWS_IMAGE):$(tag) \
--push .
build-release-arm: build-release-arm:
@if [ -z "$(tag)" ]; then \ @if [ -z "$(tag)" ]; then \
echo "Error: tag is required. Usage: make build-release-arm tag=<tag>"; \ echo "Error: tag is required. Usage: make build-release-arm tag=<tag>"; \
@@ -109,16 +74,9 @@ build-release-arm:
fi fi
@MAJOR_TAG=$$(echo $(tag) | cut -d. -f1); \ @MAJOR_TAG=$$(echo $(tag) | cut -d. -f1); \
MINOR_TAG=$$(echo $(tag) | cut -d. -f1,2); \ MINOR_TAG=$$(echo $(tag) | cut -d. -f1,2); \
CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:latest-arm64 \ --tag fosrl/pangolin:latest-arm64 \
--tag fosrl/pangolin:$$MAJOR_TAG-arm64 \ --tag fosrl/pangolin:$$MAJOR_TAG-arm64 \
@@ -128,11 +86,6 @@ build-release-arm:
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:postgresql-latest-arm64 \ --tag fosrl/pangolin:postgresql-latest-arm64 \
--tag fosrl/pangolin:postgresql-$$MAJOR_TAG-arm64 \ --tag fosrl/pangolin:postgresql-$$MAJOR_TAG-arm64 \
@@ -142,12 +95,6 @@ build-release-arm:
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:ee-latest-arm64 \ --tag fosrl/pangolin:ee-latest-arm64 \
--tag fosrl/pangolin:ee-$$MAJOR_TAG-arm64 \ --tag fosrl/pangolin:ee-$$MAJOR_TAG-arm64 \
@@ -157,12 +104,6 @@ build-release-arm:
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:ee-postgresql-latest-arm64 \ --tag fosrl/pangolin:ee-postgresql-latest-arm64 \
--tag fosrl/pangolin:ee-postgresql-$$MAJOR_TAG-arm64 \ --tag fosrl/pangolin:ee-postgresql-$$MAJOR_TAG-arm64 \
@@ -177,16 +118,9 @@ build-release-amd:
fi fi
@MAJOR_TAG=$$(echo $(tag) | cut -d. -f1); \ @MAJOR_TAG=$$(echo $(tag) | cut -d. -f1); \
MINOR_TAG=$$(echo $(tag) | cut -d. -f1,2); \ MINOR_TAG=$$(echo $(tag) | cut -d. -f1,2); \
CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:latest-amd64 \ --tag fosrl/pangolin:latest-amd64 \
--tag fosrl/pangolin:$$MAJOR_TAG-amd64 \ --tag fosrl/pangolin:$$MAJOR_TAG-amd64 \
@@ -196,11 +130,6 @@ build-release-amd:
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:postgresql-latest-amd64 \ --tag fosrl/pangolin:postgresql-latest-amd64 \
--tag fosrl/pangolin:postgresql-$$MAJOR_TAG-amd64 \ --tag fosrl/pangolin:postgresql-$$MAJOR_TAG-amd64 \
@@ -210,12 +139,6 @@ build-release-amd:
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:ee-latest-amd64 \ --tag fosrl/pangolin:ee-latest-amd64 \
--tag fosrl/pangolin:ee-$$MAJOR_TAG-amd64 \ --tag fosrl/pangolin:ee-$$MAJOR_TAG-amd64 \
@@ -225,12 +148,6 @@ build-release-amd:
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:ee-postgresql-latest-amd64 \ --tag fosrl/pangolin:ee-postgresql-latest-amd64 \
--tag fosrl/pangolin:ee-postgresql-$$MAJOR_TAG-amd64 \ --tag fosrl/pangolin:ee-postgresql-$$MAJOR_TAG-amd64 \
@@ -284,51 +201,27 @@ build-rc:
echo "Error: tag is required. Usage: make build-release tag=<tag>"; \ echo "Error: tag is required. Usage: make build-release tag=<tag>"; \
exit 1; \ exit 1; \
fi fi
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:$(tag) \ --tag fosrl/pangolin:$(tag) \
--push . && \ --push .
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:postgresql-$(tag) \ --tag fosrl/pangolin:postgresql-$(tag) \
--push . && \ --push .
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:ee-$(tag) \ --tag fosrl/pangolin:ee-$(tag) \
--push . && \ --push .
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64,linux/amd64 \ --platform linux/arm64,linux/amd64 \
--tag fosrl/pangolin:ee-postgresql-$(tag) \ --tag fosrl/pangolin:ee-postgresql-$(tag) \
--push . --push .
@@ -338,51 +231,27 @@ build-rc-arm:
echo "Error: tag is required. Usage: make build-rc-arm tag=<tag>"; \ echo "Error: tag is required. Usage: make build-rc-arm tag=<tag>"; \
exit 1; \ exit 1; \
fi fi
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:$(tag)-arm64 \ --tag fosrl/pangolin:$(tag)-arm64 \
--push . && \ --push . && \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:postgresql-$(tag)-arm64 \ --tag fosrl/pangolin:postgresql-$(tag)-arm64 \
--push . && \ --push . && \
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:ee-$(tag)-arm64 \ --tag fosrl/pangolin:ee-$(tag)-arm64 \
--push . && \ --push . && \
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \ --platform linux/arm64 \
--tag fosrl/pangolin:ee-postgresql-$(tag)-arm64 \ --tag fosrl/pangolin:ee-postgresql-$(tag)-arm64 \
--push . --push .
@@ -392,51 +261,27 @@ build-rc-amd:
echo "Error: tag is required. Usage: make build-rc-amd tag=<tag>"; \ echo "Error: tag is required. Usage: make build-rc-amd tag=<tag>"; \
exit 1; \ exit 1; \
fi fi
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:$(tag)-amd64 \ --tag fosrl/pangolin:$(tag)-amd64 \
--push . && \ --push . && \
docker buildx build \ docker buildx build \
--build-arg BUILD=oss \ --build-arg BUILD=oss \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:postgresql-$(tag)-amd64 \ --tag fosrl/pangolin:postgresql-$(tag)-amd64 \
--push . && \ --push . && \
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=sqlite \ --build-arg DATABASE=sqlite \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:ee-$(tag)-amd64 \ --tag fosrl/pangolin:ee-$(tag)-amd64 \
--push . && \ --push . && \
docker buildx build \ docker buildx build \
--build-arg BUILD=enterprise \ --build-arg BUILD=enterprise \
--build-arg DATABASE=pg \ --build-arg DATABASE=pg \
--build-arg VERSION=$(tag) \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg LICENSE="Fossorial Commercial" \
--build-arg IMAGE_TITLE="Pangolin EE" \
--build-arg IMAGE_DESCRIPTION="Pangolin Enterprise Edition - Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \ --platform linux/amd64 \
--tag fosrl/pangolin:ee-postgresql-$(tag)-amd64 \ --tag fosrl/pangolin:ee-postgresql-$(tag)-amd64 \
--push . --push .
@@ -469,52 +314,16 @@ create-manifests-rc:
echo "All RC multi-arch manifests created successfully!" echo "All RC multi-arch manifests created successfully!"
build-arm: build-arm:
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \ docker buildx build --platform linux/arm64 -t fosrl/pangolin:latest .
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \
--build-arg VERSION=dev \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/arm64 \
-t fosrl/pangolin:latest .
build-x86: build-x86:
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \ docker buildx build --platform linux/amd64 -t fosrl/pangolin:latest .
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker buildx build \
--build-arg VERSION=dev \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
--platform linux/amd64 \
-t fosrl/pangolin:latest .
dev-build-sqlite: dev-build-sqlite:
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \ docker build --build-arg DATABASE=sqlite -t fosrl/pangolin:latest .
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker build \
--build-arg DATABASE=sqlite \
--build-arg VERSION=dev \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
-t fosrl/pangolin:latest .
dev-build-pg: dev-build-pg:
@CREATED=$$(date -u +"%Y-%m-%dT%H:%M:%SZ"); \ docker build --build-arg DATABASE=pg -t fosrl/pangolin:postgresql-latest .
REVISION=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
docker build \
--build-arg DATABASE=pg \
--build-arg VERSION=dev \
--build-arg REVISION=$$REVISION \
--build-arg CREATED=$$CREATED \
--build-arg IMAGE_TITLE="Pangolin" \
--build-arg IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" \
-t fosrl/pangolin:postgresql-latest .
test: test:
docker run -it -p 3000:3000 -p 3001:3001 -p 3002:3002 -v ./config:/app/config fosrl/pangolin:latest docker run -it -p 3000:3000 -p 3001:3001 -p 3002:3002 -v ./config:/app/config fosrl/pangolin:latest
-8
View File
@@ -35,12 +35,6 @@
</div> </div>
<p align="center">
<a href="https://docs.pangolin.net/careers/join-us">
<img src="https://img.shields.io/badge/🚀_We're_Hiring!-Join_Our_Team-brightgreen?style=for-the-badge" alt="We're Hiring!" />
</a>
</p>
<p align="center"> <p align="center">
<strong> <strong>
Start testing Pangolin at <a href="https://app.pangolin.net/auth/signup">app.pangolin.net</a> Start testing Pangolin at <a href="https://app.pangolin.net/auth/signup">app.pangolin.net</a>
@@ -80,8 +74,6 @@ Download the Pangolin client for your platform:
- [Mac](https://pangolin.net/downloads/mac) - [Mac](https://pangolin.net/downloads/mac)
- [Windows](https://pangolin.net/downloads/windows) - [Windows](https://pangolin.net/downloads/windows)
- [Linux](https://pangolin.net/downloads/linux) - [Linux](https://pangolin.net/downloads/linux)
- [iOS](https://pangolin.net/downloads/ios)
- [Android](https://pangolin.net/downloads/android)
## Get Started ## Get Started
+72
View File
@@ -0,0 +1,72 @@
import requests
import yaml
import json
import base64
# The file path for the YAML file to be read
# You can change this to the path of your YAML file
YAML_FILE_PATH = 'blueprint.yaml'
# The API endpoint and headers from the curl request
API_URL = 'http://api.pangolin.net/v1/org/test/blueprint'
HEADERS = {
'accept': '*/*',
'Authorization': 'Bearer <your_token_here>',
'Content-Type': 'application/json'
}
def convert_and_send(file_path, url, headers):
"""
Reads a YAML file, converts its content to a JSON payload,
and sends it via a PUT request to a specified URL.
"""
try:
# Read the YAML file content
with open(file_path, 'r') as file:
yaml_content = file.read()
# Parse the YAML string to a Python dictionary
# This will be used to ensure the YAML is valid before sending
parsed_yaml = yaml.safe_load(yaml_content)
# convert the parsed YAML to a JSON string
json_payload = json.dumps(parsed_yaml)
print("Converted JSON payload:")
print(json_payload)
# Encode the JSON string to Base64
encoded_json = base64.b64encode(json_payload.encode('utf-8')).decode('utf-8')
# Create the final payload with the base64 encoded data
final_payload = {
"blueprint": encoded_json
}
print("Sending the following Base64 encoded JSON payload:")
print(final_payload)
print("-" * 20)
# Make the PUT request with the base64 encoded payload
response = requests.put(url, headers=headers, json=final_payload)
# Print the API response for debugging
print(f"API Response Status Code: {response.status_code}")
print("API Response Content:")
print(response.text)
# Raise an exception for bad status codes (4xx or 5xx)
response.raise_for_status()
except FileNotFoundError:
print(f"Error: The file '{file_path}' was not found.")
except yaml.YAMLError as e:
print(f"Error parsing YAML file: {e}")
except requests.exceptions.RequestException as e:
print(f"An error occurred during the API request: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# Run the function
if __name__ == "__main__":
convert_and_send(YAML_FILE_PATH, API_URL, HEADERS)
+70
View File
@@ -0,0 +1,70 @@
client-resources:
client-resource-nice-id-uno:
name: this is my resource
protocol: tcp
proxy-port: 3001
hostname: localhost
internal-port: 3000
site: lively-yosemite-toad
client-resource-nice-id-duce:
name: this is my resource
protocol: udp
proxy-port: 3000
hostname: localhost
internal-port: 3000
site: lively-yosemite-toad
proxy-resources:
resource-nice-id-uno:
name: this is my resource
protocol: http
full-domain: duce.test.example.com
host-header: example.com
tls-server-name: example.com
# auth:
# pincode: 123456
# password: sadfasdfadsf
# sso-enabled: true
# sso-roles:
# - Member
# sso-users:
# - owen@pangolin.net
# whitelist-users:
# - owen@pangolin.net
# auto-login-idp: 1
headers:
- name: X-Example-Header
value: example-value
- name: X-Another-Header
value: another-value
rules:
- action: allow
match: ip
value: 1.1.1.1
- action: deny
match: cidr
value: 2.2.2.2/32
- action: pass
match: path
value: /admin
targets:
- site: lively-yosemite-toad
path: /path
pathMatchType: prefix
hostname: localhost
method: http
port: 8000
- site: slim-alpine-chipmunk
hostname: localhost
path: /yoman
pathMatchType: exact
method: http
port: 8001
resource-nice-id-duce:
name: this is other resource
protocol: tcp
proxy-port: 3000
targets:
- site: lively-yosemite-toad
hostname: localhost
port: 3000
-36
View File
@@ -1,36 +0,0 @@
import { CommandModule } from "yargs";
import { db, licenseKey } from "@server/db";
import { eq } from "drizzle-orm";
type ClearLicenseKeysArgs = { };
export const clearLicenseKeys: CommandModule<
{},
ClearLicenseKeysArgs
> = {
command: "clear-license-keys",
describe:
"Clear all license keys from the database",
// no args
builder: (yargs) => {
return yargs;
},
handler: async (argv: {}) => {
try {
console.log(`Clearing all license keys from the database`);
// Delete all license keys
const deletedCount = await db
.delete(licenseKey)
.where(eq(licenseKey.licenseKeyId, licenseKey.licenseKeyId)) .returning();; // delete all
console.log(`Deleted ${deletedCount.length} license key(s) from the database`);
process.exit(0);
} catch (error) {
console.error("Error:", error);
process.exit(1);
}
}
};
-123
View File
@@ -1,123 +0,0 @@
import { CommandModule } from "yargs";
import { db, clients, olms, currentFingerprint, userClients, approvals } from "@server/db";
import { eq, and, inArray } from "drizzle-orm";
type DeleteClientArgs = {
orgId: string;
niceId: string;
};
export const deleteClient: CommandModule<{}, DeleteClientArgs> = {
command: "delete-client",
describe:
"Delete a client and all associated data (OLMs, current fingerprint, userClients, approvals). Snapshots are preserved.",
builder: (yargs) => {
return yargs
.option("orgId", {
type: "string",
demandOption: true,
describe: "The organization ID"
})
.option("niceId", {
type: "string",
demandOption: true,
describe: "The client niceId (identifier)"
});
},
handler: async (argv: { orgId: string; niceId: string }) => {
try {
const { orgId, niceId } = argv;
console.log(
`Deleting client with orgId: ${orgId}, niceId: ${niceId}...`
);
// Find the client
const [client] = await db
.select()
.from(clients)
.where(and(eq(clients.orgId, orgId), eq(clients.niceId, niceId)))
.limit(1);
if (!client) {
console.error(
`Error: Client with orgId "${orgId}" and niceId "${niceId}" not found.`
);
process.exit(1);
}
const clientId = client.clientId;
console.log(`Found client with clientId: ${clientId}`);
// Find all OLMs associated with this client
const associatedOlms = await db
.select()
.from(olms)
.where(eq(olms.clientId, clientId));
console.log(`Found ${associatedOlms.length} OLM(s) associated with this client`);
// Delete in a transaction to ensure atomicity
await db.transaction(async (trx) => {
// Delete currentFingerprint entries for the associated OLMs
// Note: We delete these explicitly before deleting OLMs to ensure
// we have control, even though cascade would handle it
let fingerprintCount = 0;
if (associatedOlms.length > 0) {
const olmIds = associatedOlms.map((olm) => olm.olmId);
const deletedFingerprints = await trx
.delete(currentFingerprint)
.where(inArray(currentFingerprint.olmId, olmIds))
.returning();
fingerprintCount = deletedFingerprints.length;
}
console.log(`Deleted ${fingerprintCount} current fingerprint(s)`);
// Delete OLMs
// Note: OLMs have onDelete: "set null" for clientId, so we need to delete them explicitly
const deletedOlms = await trx
.delete(olms)
.where(eq(olms.clientId, clientId))
.returning();
console.log(`Deleted ${deletedOlms.length} OLM(s)`);
// Delete approvals
// Note: Approvals have onDelete: "cascade" but we delete explicitly for clarity
const deletedApprovals = await trx
.delete(approvals)
.where(eq(approvals.clientId, clientId))
.returning();
console.log(`Deleted ${deletedApprovals.length} approval(s)`);
// Delete userClients
// Note: userClients have onDelete: "cascade" but we delete explicitly for clarity
const deletedUserClients = await trx
.delete(userClients)
.where(eq(userClients.clientId, clientId))
.returning();
console.log(`Deleted ${deletedUserClients.length} userClient association(s)`);
// Finally, delete the client itself
const deletedClients = await trx
.delete(clients)
.where(eq(clients.clientId, clientId))
.returning();
console.log(`Deleted client: ${deletedClients[0]?.name || niceId}`);
});
console.log("\nClient deletion completed successfully!");
console.log("\nSummary:");
console.log(` - Client: ${niceId} (clientId: ${clientId})`);
console.log(` - Olm(s): ${associatedOlms.length}`);
console.log(` - Current fingerprints: deleted`);
console.log(` - Approvals: deleted`);
console.log(` - UserClients: deleted`);
console.log(` - Snapshots: preserved (not deleted)`);
process.exit(0);
} catch (error) {
console.error("Error deleting client:", error);
process.exit(1);
}
}
};
-4
View File
@@ -6,8 +6,6 @@ import { setAdminCredentials } from "@cli/commands/setAdminCredentials";
import { resetUserSecurityKeys } from "@cli/commands/resetUserSecurityKeys"; import { resetUserSecurityKeys } from "@cli/commands/resetUserSecurityKeys";
import { clearExitNodes } from "./commands/clearExitNodes"; import { clearExitNodes } from "./commands/clearExitNodes";
import { rotateServerSecret } from "./commands/rotateServerSecret"; import { rotateServerSecret } from "./commands/rotateServerSecret";
import { clearLicenseKeys } from "./commands/clearLicenseKeys";
import { deleteClient } from "./commands/deleteClient";
yargs(hideBin(process.argv)) yargs(hideBin(process.argv))
.scriptName("pangctl") .scriptName("pangctl")
@@ -15,7 +13,5 @@ yargs(hideBin(process.argv))
.command(resetUserSecurityKeys) .command(resetUserSecurityKeys)
.command(clearExitNodes) .command(clearExitNodes)
.command(rotateServerSecret) .command(rotateServerSecret)
.command(clearLicenseKeys)
.command(deleteClient)
.demandCommand() .demandCommand()
.help().argv; .help().argv;
+18 -21
View File
@@ -1,30 +1,27 @@
# To see all available options, please visit the docs: # To see all available options, please visit the docs:
# https://docs.pangolin.net/ # https://docs.pangolin.net/self-host/advanced/config-file
gerbil:
start_port: 51820
base_endpoint: "{{.DashboardDomain}}"
app: app:
dashboard_url: "https://{{.DashboardDomain}}" dashboard_url: http://localhost:3002
log_level: "info" log_level: debug
telemetry:
anonymous_usage: true
domains: domains:
domain1: domain1:
base_domain: "{{.BaseDomain}}" base_domain: example.com
server: server:
secret: "{{.Secret}}" secret: my_secret_key
cors:
origins: ["https://{{.DashboardDomain}}"] gerbil:
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"] base_endpoint: example.com
allowed_headers: ["X-CSRF-Token", "Content-Type"]
credentials: false orgs:
block_size: 24
subnet_group: 100.90.137.0/20
flags: flags:
require_email_verification: false require_email_verification: false
disable_signup_without_invite: true disable_signup_without_invite: true
disable_user_create_org: false disable_user_create_org: true
allow_raw_resources: true allow_raw_resources: true
enable_integration_api: true
+3 -19
View File
@@ -1,9 +1,5 @@
http: http:
middlewares: middlewares:
badger:
plugin:
badger:
disableForwardAuth: true
redirect-to-https: redirect-to-https:
redirectScheme: redirectScheme:
scheme: https scheme: https
@@ -17,16 +13,14 @@ http:
- web - web
middlewares: middlewares:
- redirect-to-https - redirect-to-https
- badger
# Next.js router (handles everything except API and WebSocket paths) # Next.js router (handles everything except API and WebSocket paths)
next-router: next-router:
rule: "Host(`{{.DashboardDomain}}`) && !PathPrefix(`/api/v1`)" rule: "Host(`{{.DashboardDomain}}`)"
service: next-service service: next-service
priority: 10
entryPoints: entryPoints:
- websecure - websecure
middlewares:
- badger
tls: tls:
certResolver: letsencrypt certResolver: letsencrypt
@@ -34,10 +28,9 @@ http:
api-router: api-router:
rule: "Host(`{{.DashboardDomain}}`) && PathPrefix(`/api/v1`)" rule: "Host(`{{.DashboardDomain}}`) && PathPrefix(`/api/v1`)"
service: api-service service: api-service
priority: 100
entryPoints: entryPoints:
- websecure - websecure
middlewares:
- badger
tls: tls:
certResolver: letsencrypt certResolver: letsencrypt
@@ -51,12 +44,3 @@ http:
loadBalancer: loadBalancer:
servers: servers:
- url: "http://pangolin:3000" # API/WebSocket server - url: "http://pangolin:3000" # API/WebSocket server
tcp:
serversTransports:
pp-transport-v1:
proxyProtocol:
version: 1
pp-transport-v2:
proxyProtocol:
version: 2
+5 -25
View File
@@ -3,52 +3,32 @@ api:
dashboard: true dashboard: true
providers: providers:
http:
endpoint: "http://pangolin:3001/api/v1/traefik-config"
pollInterval: "5s"
file: file:
filename: "/etc/traefik/dynamic_config.yml" directory: "/var/dynamic"
watch: true
experimental: experimental:
plugins: plugins:
badger: badger:
moduleName: "github.com/fosrl/badger" moduleName: "github.com/fosrl/badger"
version: "{{.BadgerVersion}}" version: "v1.3.0"
log: log:
level: "INFO" level: "DEBUG"
format: "common" format: "common"
maxSize: 100 maxSize: 100
maxBackups: 3 maxBackups: 3
maxAge: 3 maxAge: 3
compress: true compress: true
certificatesResolvers:
letsencrypt:
acme:
httpChallenge:
entryPoint: web
email: "{{.LetsEncryptEmail}}"
storage: "/letsencrypt/acme.json"
caServer: "https://acme-v02.api.letsencrypt.org/directory"
entryPoints: entryPoints:
web: web:
address: ":80" address: ":80"
websecure: websecure:
address: ":443" address: ":9443"
transport: transport:
respondingTimeouts: respondingTimeouts:
readTimeout: "30m" readTimeout: "30m"
http:
tls:
certResolver: "letsencrypt"
encodedCharacters:
allowEncodedSlash: true
allowEncodedQuestionMark: true
serversTransport: serversTransport:
insecureSkipVerify: true insecureSkipVerify: true
ping:
entryPoint: "web"
+1 -4
View File
@@ -43,12 +43,9 @@ entryPoints:
http: http:
tls: tls:
certResolver: "letsencrypt" certResolver: "letsencrypt"
encodedCharacters:
allowEncodedSlash: true
allowEncodedQuestionMark: true
serversTransport: serversTransport:
insecureSkipVerify: true insecureSkipVerify: true
ping: ping:
entryPoint: "web" entryPoint: "web"
-41
View File
@@ -210,47 +210,6 @@ func isDockerRunning() bool {
return true return true
} }
func isPodmanRunning() bool {
cmd := exec.Command("podman", "info")
if err := cmd.Run(); err != nil {
return false
}
return true
}
// detectContainerType detects whether the system is currently using Docker or Podman
// by checking which container runtime is running and has containers
func detectContainerType() SupportedContainer {
// Check if we have running containers with podman
if isPodmanRunning() {
cmd := exec.Command("podman", "ps", "-q")
output, err := cmd.Output()
if err == nil && len(strings.TrimSpace(string(output))) > 0 {
return Podman
}
}
// Check if we have running containers with docker
if isDockerRunning() {
cmd := exec.Command("docker", "ps", "-q")
output, err := cmd.Output()
if err == nil && len(strings.TrimSpace(string(output))) > 0 {
return Docker
}
}
// If no containers are running, check which one is installed and running
if isPodmanRunning() && isPodmanInstalled() {
return Podman
}
if isDockerRunning() && isDockerInstalled() {
return Docker
}
return Undefined
}
// executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied // executeDockerComposeCommandWithArgs executes the appropriate docker command with arguments supplied
func executeDockerComposeCommandWithArgs(args ...string) error { func executeDockerComposeCommandWithArgs(args ...string) error {
var cmd *exec.Cmd var cmd *exec.Cmd
+2 -2
View File
@@ -93,7 +93,7 @@ func installCrowdsec(config Config) error {
if checkIfTextInFile("config/traefik/dynamic_config.yml", "PUT_YOUR_BOUNCER_KEY_HERE_OR_IT_WILL_NOT_WORK") { if checkIfTextInFile("config/traefik/dynamic_config.yml", "PUT_YOUR_BOUNCER_KEY_HERE_OR_IT_WILL_NOT_WORK") {
fmt.Println("Failed to replace bouncer key! Please retrieve the key and replace it in the config/traefik/dynamic_config.yml file using the following command:") fmt.Println("Failed to replace bouncer key! Please retrieve the key and replace it in the config/traefik/dynamic_config.yml file using the following command:")
fmt.Printf(" %s exec crowdsec cscli bouncers add traefik-bouncer\n", config.InstallationContainerType) fmt.Println(" docker exec crowdsec cscli bouncers add traefik-bouncer")
} }
return nil return nil
@@ -117,7 +117,7 @@ func GetCrowdSecAPIKey(containerType SupportedContainer) (string, error) {
} }
// Execute the command to get the API key // Execute the command to get the API key
cmd := exec.Command(string(containerType), "exec", "crowdsec", "cscli", "bouncers", "add", "traefik-bouncer", "-o", "raw") cmd := exec.Command("docker", "exec", "crowdsec", "cscli", "bouncers", "add", "traefik-bouncer", "-o", "raw")
var out bytes.Buffer var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
+2 -2
View File
@@ -3,8 +3,8 @@ module installer
go 1.24.0 go 1.24.0
require ( require (
golang.org/x/term v0.39.0 golang.org/x/term v0.38.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require golang.org/x/sys v0.40.0 // indirect require golang.org/x/sys v0.39.0 // indirect
+4 -4
View File
@@ -1,7 +1,7 @@
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+5 -14
View File
@@ -229,16 +229,7 @@ func main() {
} }
} }
// Try to detect container type from existing installation config.InstallationContainerType = podmanOrDocker(reader)
detectedType := detectContainerType()
if detectedType == Undefined {
// If detection fails, prompt the user
fmt.Println("Unable to detect container type from existing installation.")
config.InstallationContainerType = podmanOrDocker(reader)
} else {
config.InstallationContainerType = detectedType
fmt.Printf("Detected container type: %s\n", config.InstallationContainerType)
}
config.DoCrowdsecInstall = true config.DoCrowdsecInstall = true
err := installCrowdsec(config) err := installCrowdsec(config)
@@ -295,10 +286,10 @@ func podmanOrDocker(reader *bufio.Reader) SupportedContainer {
os.Exit(1) os.Exit(1)
} }
if err := exec.Command("bash", "-c", "cat /etc/sysctl.d/99-podman.conf 2>/dev/null | grep 'net.ipv4.ip_unprivileged_port_start=' || cat /etc/sysctl.conf 2>/dev/null | grep 'net.ipv4.ip_unprivileged_port_start='").Run(); err != nil { if err := exec.Command("bash", "-c", "cat /etc/sysctl.conf | grep 'net.ipv4.ip_unprivileged_port_start='").Run(); err != nil {
fmt.Println("Would you like to configure ports >= 80 as unprivileged ports? This enables podman containers to listen on low-range ports.") fmt.Println("Would you like to configure ports >= 80 as unprivileged ports? This enables podman containers to listen on low-range ports.")
fmt.Println("Pangolin will experience startup issues if this is not configured, because it needs to listen on port 80/443 by default.") fmt.Println("Pangolin will experience startup issues if this is not configured, because it needs to listen on port 80/443 by default.")
approved := readBool(reader, "The installer is about to execute \"echo 'net.ipv4.ip_unprivileged_port_start=80' > /etc/sysctl.d/99-podman.conf && sysctl --system\". Approve?", true) approved := readBool(reader, "The installer is about to execute \"echo 'net.ipv4.ip_unprivileged_port_start=80' >> /etc/sysctl.conf && sysctl -p\". Approve?", true)
if approved { if approved {
if os.Geteuid() != 0 { if os.Geteuid() != 0 {
fmt.Println("You need to run the installer as root for such a configuration.") fmt.Println("You need to run the installer as root for such a configuration.")
@@ -309,7 +300,7 @@ func podmanOrDocker(reader *bufio.Reader) SupportedContainer {
// container low-range ports as unprivileged ports. // container low-range ports as unprivileged ports.
// Linux only. // Linux only.
if err := run("bash", "-c", "echo 'net.ipv4.ip_unprivileged_port_start=80' > /etc/sysctl.d/99-podman.conf && sysctl --system"); err != nil { if err := run("bash", "-c", "echo 'net.ipv4.ip_unprivileged_port_start=80' >> /etc/sysctl.conf && sysctl -p"); err != nil {
fmt.Printf("Error configuring unprivileged ports: %v\n", err) fmt.Printf("Error configuring unprivileged ports: %v\n", err)
os.Exit(1) os.Exit(1)
} }
@@ -349,7 +340,7 @@ func collectUserInput(reader *bufio.Reader) Config {
// Basic configuration // Basic configuration
fmt.Println("\n=== Basic Configuration ===") fmt.Println("\n=== Basic Configuration ===")
config.IsEnterprise = readBoolNoDefault(reader, "Do you want to install the Enterprise version of Pangolin? The EE is free for personal use or for businesses making less than 100k USD annually.") config.IsEnterprise = readBoolNoDefault(reader, "Do you want to install the Enterprise version of Pangolin? The EE is free for persoal use or for businesses making less than 100k USD annually.")
config.BaseDomain = readString(reader, "Enter your base domain (no subdomain e.g. example.com)", "") config.BaseDomain = readString(reader, "Enter your base domain (no subdomain e.g. example.com)", "")
+139 -153
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Свържете се с мрежа.", "sitesBannerTitle": "Свържете се с мрежа.",
"sitesBannerDescription": "Сайтът е връзка с отдалечена мрежа, която позволява на Pangolin да предоставя достъп до ресурси, било то публични или частни, на потребители навсякъде. Инсталирайте мрежовия конектор на сайта (Newt) навсякъде, където можете да стартирате бинарен или контейнер, за да създадете връзката.", "sitesBannerDescription": "Сайтът е връзка с отдалечена мрежа, която позволява на Pangolin да предоставя достъп до ресурси, било то публични или частни, на потребители навсякъде. Инсталирайте мрежовия конектор на сайта (Newt) навсякъде, където можете да стартирате бинарен или контейнер, за да създадете връзката.",
"sitesBannerButtonText": "Инсталиране на сайт.", "sitesBannerButtonText": "Инсталиране на сайт.",
"approvalsBannerTitle": "Одобрете или откажете достъп до устройство", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Прегледайте и одобрите или откажете искания за достъп до устройства от потребители. Когато се изисква одобрение на устройства, потребителите трябва да получат администраторско одобрение, преди техните устройства да могат да се свържат с ресурсите на вашата организация.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Научете повече", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Създайте сайт", "siteCreate": "Създайте сайт",
"siteCreateDescription2": "Следвайте стъпките по-долу, за да създадете и свържете нов сайт", "siteCreateDescription2": "Следвайте стъпките по-долу, за да създадете и свържете нов сайт",
"siteCreateDescription": "Създайте нов сайт, за да започнете да свързвате ресурси", "siteCreateDescription": "Създайте нов сайт, за да започнете да свързвате ресурси",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Търсене на роли...", "accessRolesSearch": "Търсене на роли...",
"accessRolesAdd": "Добавете роля", "accessRolesAdd": "Добавете роля",
"accessRoleDelete": "Изтриване на роля", "accessRoleDelete": "Изтриване на роля",
"accessApprovalsManage": "Управление на одобрения", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Прегледайте и управлявайте чакащи одобрения за достъп до тази организация", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Описание", "description": "Описание",
"inviteTitle": "Отворени покани", "inviteTitle": "Отворени покани",
"inviteDescription": "Управлявайте покани за други потребители да се присъединят към организацията", "inviteDescription": "Управлявайте покани за други потребители да се присъединят към организацията",
@@ -455,18 +455,18 @@
"selectDuration": "Изберете продължителност", "selectDuration": "Изберете продължителност",
"selectResource": "Изберете Ресурс", "selectResource": "Изберете Ресурс",
"filterByResource": "Филтрирай По Ресурс", "filterByResource": "Филтрирай По Ресурс",
"selectApprovalState": "Изберете състояние на одобрение", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Филтрирайте по състояние на одобрение", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Няма одобрения", "approvalListEmpty": "No approvals",
"approvalState": "Състояние на одобрение", "approvalState": "Approval State",
"approve": "Одобряване", "approve": "Approve",
"approved": "Одобрен", "approved": "Approved",
"denied": "Отказан", "denied": "Denied",
"deniedApproval": "Одобрение е отказано", "deniedApproval": "Denied Approval",
"all": "Всички", "all": "All",
"deny": "Откажете", "deny": "Deny",
"viewDetails": "Разгледай подробности", "viewDetails": "View Details",
"requestingNewDeviceApproval": "поискана нова устройство", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Нулиране на Филтрите", "resetFilters": "Нулиране на Филтрите",
"totalBlocked": "Заявки Блокирани От Pangolin", "totalBlocked": "Заявки Блокирани От Pangolin",
"totalRequests": "Общо Заявки", "totalRequests": "Общо Заявки",
@@ -746,28 +746,28 @@
"countries": "Държави", "countries": "Държави",
"accessRoleCreate": "Създайте роля", "accessRoleCreate": "Създайте роля",
"accessRoleCreateDescription": "Създайте нова роля за групиране на потребители и управление на техните разрешения.", "accessRoleCreateDescription": "Създайте нова роля за групиране на потребители и управление на техните разрешения.",
"accessRoleEdit": "Редактиране на роля", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Редактирайте информацията за ролята.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Създайте роля", "accessRoleCreateSubmit": "Създайте роля",
"accessRoleCreated": "Ролята е създадена", "accessRoleCreated": "Ролята е създадена",
"accessRoleCreatedDescription": "Ролята беше успешно създадена.", "accessRoleCreatedDescription": "Ролята беше успешно създадена.",
"accessRoleErrorCreate": "Неуспешно създаване на роля", "accessRoleErrorCreate": "Неуспешно създаване на роля",
"accessRoleErrorCreateDescription": "Възникна грешка при създаването на ролята.", "accessRoleErrorCreateDescription": "Възникна грешка при създаването на ролята.",
"accessRoleUpdateSubmit": "Обновете роля", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Ролята е актуализирана", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Ролята беше успешно актуализирана.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Одобрението е обработено", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Задайте решение на заявка за одобрение да бъде одобрено.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Задайте решение на заявка за одобрение да бъде отказано.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Неуспешно актуализиране на ролята", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Възникна грешка при актуализиране на ролята.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Неуспешно обработване на одобрение", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Възникна грешка при обработване на одобрението.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Нова роля е необходима", "accessRoleErrorNewRequired": "Нова роля е необходима",
"accessRoleErrorRemove": "Неуспешно премахване на роля", "accessRoleErrorRemove": "Неуспешно премахване на роля",
"accessRoleErrorRemoveDescription": "Възникна грешка при премахването на роля.", "accessRoleErrorRemoveDescription": "Възникна грешка при премахването на роля.",
"accessRoleName": "Име на роля", "accessRoleName": "Име на роля",
"accessRoleQuestionRemove": "Ще изтриете ролята `{name}`. Не можете да отмените това действие.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Премахни роля", "accessRoleRemove": "Премахни роля",
"accessRoleRemoveDescription": "Премахни роля от организацията", "accessRoleRemoveDescription": "Премахни роля от организацията",
"accessRoleRemoveSubmit": "Премахни роля", "accessRoleRemoveSubmit": "Премахни роля",
@@ -903,7 +903,7 @@
"inviteAlready": "Изглежда, че сте били поканени!", "inviteAlready": "Изглежда, че сте били поканени!",
"inviteAlreadyDescription": "За да приемете поканата, трябва да влезете или да създадете акаунт.", "inviteAlreadyDescription": "За да приемете поканата, трябва да влезете или да създадете акаунт.",
"signupQuestion": "Вече имате акаунт?", "signupQuestion": "Вече имате акаунт?",
"login": "Вход", "login": "Log In",
"resourceNotFound": "Ресурсът не е намерен", "resourceNotFound": "Ресурсът не е намерен",
"resourceNotFoundDescription": "Ресурсът, който се опитвате да достъпите, не съществува.", "resourceNotFoundDescription": "Ресурсът, който се опитвате да достъпите, не съществува.",
"pincodeRequirementsLength": "ПИН трябва да бъде точно 6 цифри", "pincodeRequirementsLength": "ПИН трябва да бъде точно 6 цифри",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Тази организация изисква да сменяте паролата си на всеки {maxDays} дни.", "passwordExpiryDescription": "Тази организация изисква да сменяте паролата си на всеки {maxDays} дни.",
"changePasswordNow": "Сменете паролата сега", "changePasswordNow": "Сменете паролата сега",
"pincodeAuth": "Код на удостоверителя", "pincodeAuth": "Код на удостоверителя",
"pincodeSubmit2": "Изпратете кода", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Заявка за нулиране", "passwordResetSubmit": "Заявка за нулиране",
"passwordResetAlreadyHaveCode": "Въведете код.", "passwordResetAlreadyHaveCode": "Въведете код.",
"passwordResetSmtpRequired": "Моля, свържете се с вашия администратор", "passwordResetSmtpRequired": "Моля, свържете се с вашия администратор",
"passwordResetSmtpRequiredDescription": "Кодът за нулиране на парола е задължителен за нулиране на паролата ви. Моля, свържете се с вашия администратор за помощ.", "passwordResetSmtpRequiredDescription": "Кодът за нулиране на парола е задължителен за нулиране на паролата ви. Моля, свържете се с вашия администратор за помощ.",
"passwordBack": "Назад към Парола", "passwordBack": "Назад към Парола",
"loginBack": "Върнете се на главната страница за вход", "loginBack": "Go back to main login page",
"signup": "Регистрация", "signup": "Регистрация",
"loginStart": "Влезте, за да започнете", "loginStart": "Влезте, за да започнете",
"idpOidcTokenValidating": "Валидиране на OIDC токен", "idpOidcTokenValidating": "Валидиране на OIDC токен",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Актуализиране на IdP организация", "actionUpdateIdpOrg": "Актуализиране на IdP организация",
"actionCreateClient": "Създаване на клиент", "actionCreateClient": "Създаване на клиент",
"actionDeleteClient": "Изтриване на клиент", "actionDeleteClient": "Изтриване на клиент",
"actionArchiveClient": "Архивиране на клиента", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Разархивиране на клиента", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Блокиране на клиента", "actionBlockClient": "Block Client",
"actionUnblockClient": "Деблокиране на клиента", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Актуализиране на клиент", "actionUpdateClient": "Актуализиране на клиент",
"actionListClients": "Списък с клиенти", "actionListClients": "Списък с клиенти",
"actionGetClient": "Получаване на клиент", "actionGetClient": "Получаване на клиент",
@@ -1167,14 +1167,14 @@
"searchProgress": "Търсене...", "searchProgress": "Търсене...",
"create": "Създаване", "create": "Създаване",
"orgs": "Организации", "orgs": "Организации",
"loginError": "Възникна неочаквана грешка. Моля, опитайте отново.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Необходим е вход за вашето устройство.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Забравена парола?", "passwordForgot": "Забравена парола?",
"otpAuth": "Двуфакторно удостоверяване", "otpAuth": "Двуфакторно удостоверяване",
"otpAuthDescription": "Въведете кода от приложението за удостоверяване или един от вашите резервни кодове за еднократна употреба.", "otpAuthDescription": "Въведете кода от приложението за удостоверяване или един от вашите резервни кодове за еднократна употреба.",
"otpAuthSubmit": "Изпрати код", "otpAuthSubmit": "Изпрати код",
"idpContinue": "Или продължете със", "idpContinue": "Или продължете със",
"otpAuthBack": "Назад към парола", "otpAuthBack": "Back to Password",
"navbar": "Навигационно меню", "navbar": "Навигационно меню",
"navbarDescription": "Главно навигационно меню за приложението", "navbarDescription": "Главно навигационно меню за приложението",
"navbarDocsLink": "Документация", "navbarDocsLink": "Документация",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Общ преглед", "sidebarOverview": "Общ преглед",
"sidebarHome": "Начало", "sidebarHome": "Начало",
"sidebarSites": "Сайтове", "sidebarSites": "Сайтове",
"sidebarApprovals": "Заявки за одобрение", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Ресурси", "sidebarResources": "Ресурси",
"sidebarProxyResources": "Публично", "sidebarProxyResources": "Публично",
"sidebarClientResources": "Частно", "sidebarClientResources": "Частно",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Идентификационни доставчици", "sidebarIdentityProviders": "Идентификационни доставчици",
"sidebarLicense": "Лиценз", "sidebarLicense": "Лиценз",
"sidebarClients": "Клиенти", "sidebarClients": "Клиенти",
"sidebarUserDevices": "Устройства на потребителя", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Машини", "sidebarMachineClients": "Машини",
"sidebarDomains": "Домейни", "sidebarDomains": "Домейни",
"sidebarGeneral": "Управление.", "sidebarGeneral": "Управление.",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Възникна грешка при създаване на админ акаунт.", "setupErrorCreateAdmin": "Възникна грешка при създаване на админ акаунт.",
"certificateStatus": "Статус на сертификата", "certificateStatus": "Статус на сертификата",
"loading": "Зареждане", "loading": "Зареждане",
"loadingAnalytics": "Зареждане на анализи", "loadingAnalytics": "Loading Analytics",
"restart": "Рестарт", "restart": "Рестарт",
"domains": "Домейни", "domains": "Домейни",
"domainsDescription": "Създайте и управлявайте наличните домейни в организацията", "domainsDescription": "Създайте и управлявайте наличните домейни в организацията",
@@ -1339,7 +1339,7 @@
"refreshError": "Неуспешно обновяване на данни", "refreshError": "Неуспешно обновяване на данни",
"verified": "Потвърдено", "verified": "Потвърдено",
"pending": "Чакащо", "pending": "Чакащо",
"pendingApproval": "Очаква одобрение", "pendingApproval": "Pending Approval",
"sidebarBilling": "Фактуриране", "sidebarBilling": "Фактуриране",
"billing": "Фактуриране", "billing": "Фактуриране",
"orgBillingDescription": "Управлявайте информацията за плащане и абонаментите", "orgBillingDescription": "Управлявайте информацията за плащане и абонаментите",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Ключът за защита е премахнат успешно", "securityKeyRemoveSuccess": "Ключът за защита е премахнат успешно",
"securityKeyRemoveError": "Неуспешно премахване на ключ за защита", "securityKeyRemoveError": "Неуспешно премахване на ключ за защита",
"securityKeyLoadError": "Неуспешно зареждане на ключове за защита", "securityKeyLoadError": "Неуспешно зареждане на ключове за защита",
"securityKeyLogin": "Използвайте ключ за защита", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Неуспешно удостоверяване с ключ за сигурност", "securityKeyAuthError": "Неуспешно удостоверяване с ключ за сигурност",
"securityKeyRecommendation": "Регистрирайте резервен ключ за безопасност на друго устройство, за да сте сигурни, че винаги ще имате достъп до профила си", "securityKeyRecommendation": "Регистрирайте резервен ключ за безопасност на друго устройство, за да сте сигурни, че винаги ще имате достъп до профила си",
"registering": "Регистрация...", "registering": "Регистрация...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Интервал за здраве", "IntervalSeconds": "Интервал за здраве",
"timeoutSeconds": "Време за изчакване (сек)", "timeoutSeconds": "Време за изчакване (сек)",
"timeIsInSeconds": "Времето е в секунди", "timeIsInSeconds": "Времето е в секунди",
"requireDeviceApproval": "Изискват одобрение на устройства", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Потребители с тази роля трябва да имат нови устройства одобрени от администратор преди да могат да се свържат и да имат достъп до ресурси.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"retryAttempts": "Опити за повторно", "retryAttempts": "Опити за повторно",
"expectedResponseCodes": "Очаквани кодове за отговор", "expectedResponseCodes": "Очаквани кодове за отговор",
"expectedResponseCodesDescription": "HTTP статус код, указващ здравословно състояние. Ако бъде оставено празно, между 200-300 се счита за здравословно.", "expectedResponseCodesDescription": "HTTP статус код, указващ здравословно състояние. Ако бъде оставено празно, между 200-300 се счита за здравословно.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Не са намерени вътрешни ресурси.", "resourcesTableNoInternalResourcesFound": "Не са намерени вътрешни ресурси.",
"resourcesTableDestination": "Дестинация", "resourcesTableDestination": "Дестинация",
"resourcesTableAlias": "Псевдоним", "resourcesTableAlias": "Псевдоним",
"resourcesTableAliasAddress": "Адрес на псевдоним.",
"resourcesTableAliasAddressInfo": "Този адрес е част от подсистемата на организацията. Използва се за разрешаване на псевдонимни записи чрез вътрешно DNS разрешаване.",
"resourcesTableClients": "Клиенти", "resourcesTableClients": "Клиенти",
"resourcesTableAndOnlyAccessibleInternally": "и са достъпни само вътрешно при свързване с клиент.", "resourcesTableAndOnlyAccessibleInternally": "и са достъпни само вътрешно при свързване с клиент.",
"resourcesTableNoTargets": "Без цели", "resourcesTableNoTargets": "Без цели",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Изберете своя доставчик на идентичност, за да продължите", "orgAuthChooseIdpDescription": "Изберете своя доставчик на идентичност, за да продължите",
"orgAuthNoIdpConfigured": "Тази организация няма конфигурирани доставчици на идентичност. Можете да влезете с вашата Pangolin идентичност.", "orgAuthNoIdpConfigured": "Тази организация няма конфигурирани доставчици на идентичност. Можете да влезете с вашата Pangolin идентичност.",
"orgAuthSignInWithPangolin": "Впишете се с Pangolin", "orgAuthSignInWithPangolin": "Впишете се с Pangolin",
"orgAuthSignInToOrg": "Влезте в организация", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Вход в организация.", "orgAuthSelectOrgTitle": "Вход в организация.",
"orgAuthSelectOrgDescription": "Въведете идентификатора на вашата организация, за да продължите.", "orgAuthSelectOrgDescription": "Въведете идентификатора на вашата организация, за да продължите.",
"orgAuthOrgIdPlaceholder": "вашата-организация", "orgAuthOrgIdPlaceholder": "вашата-организация",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Кодът трябва да бъде 9 символа (напр. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Кодът трябва да бъде 9 символа (напр. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Невалиден или изтекъл код", "deviceCodeInvalidOrExpired": "Невалиден или изтекъл код",
"deviceCodeVerifyFailed": "Неуспешна проверка на кода на устройството", "deviceCodeVerifyFailed": "Неуспешна проверка на кода на устройството",
"deviceCodeValidating": "Валидиране на кода на устройството...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Проверка на оторизацията на устройството...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Вписан като", "signedInAs": "Вписан като",
"deviceCodeEnterPrompt": "Въведете кода, показан на устройството", "deviceCodeEnterPrompt": "Въведете кода, показан на устройството",
"continue": "Продължете", "continue": "Продължете",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Достъп до всички организации, до които има достъп акаунтът ви", "deviceOrganizationsAccess": "Достъп до всички организации, до които има достъп акаунтът ви",
"deviceAuthorize": "Разрешете {applicationName}", "deviceAuthorize": "Разрешете {applicationName}",
"deviceConnected": "Устройството е свързано!", "deviceConnected": "Устройството е свързано!",
"deviceAuthorizedMessage": "Устройството е оторизирано да има достъп до акаунта ви. Моля, върнете се към клиентското приложение.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Pangolin Cloud", "pangolinCloud": "Pangolin Cloud",
"viewDevices": "Преглед на устройствата", "viewDevices": "Преглед на устройствата",
"viewDevicesDescription": "Управлявайте свързаните си устройства", "viewDevicesDescription": "Управлявайте свързаните си устройства",
@@ -2348,7 +2346,7 @@
"identifier": "Идентификатор", "identifier": "Идентификатор",
"deviceLoginUseDifferentAccount": "Не сте вие? Използвайте друг акаунт.", "deviceLoginUseDifferentAccount": "Не сте вие? Използвайте друг акаунт.",
"deviceLoginDeviceRequestingAccessToAccount": "Устройство запитващо достъп до този акаунт.", "deviceLoginDeviceRequestingAccessToAccount": "Устройство запитващо достъп до този акаунт.",
"loginSelectAuthenticationMethod": "Изберете метод на удостоверяване, за да продължите.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Няма Данни", "noData": "Няма Данни",
"machineClients": "Машинни клиенти", "machineClients": "Машинни клиенти",
"install": "Инсталирай", "install": "Инсталирай",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "В момента срещаме технически затруднения. Моля, проверете отново скоро.", "maintenanceScreenMessage": "В момента срещаме технически затруднения. Моля, проверете отново скоро.",
"maintenanceScreenEstimatedCompletion": "Прогнозно завършване:", "maintenanceScreenEstimatedCompletion": "Прогнозно завършване:",
"createInternalResourceDialogDestinationRequired": "Дестинацията е задължителна.", "createInternalResourceDialogDestinationRequired": "Дестинацията е задължителна.",
"available": "Налично", "available": "Available",
"archived": "Архивирано", "archived": "Archived",
"noArchivedDevices": "Не са намерени архивирани устройства.", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Устройството е архивирано.", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Устройството беше успешно архивирано.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Грешка при архивиране на устройството.", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Неуспех при архивиране на устройството.", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Сигурни ли сте, че искате да архивирате това устройство?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Устройството ще бъде архивирано и премахнато от вашия списък с активни устройства.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Архивиране на устройството", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Архивиране на устройство", "archiveDevice": "Archive Device",
"archive": "Архив", "archive": "Archive",
"deviceUnarchived": "Устройството е разархивирано.", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Устройството беше успешно разархивирано.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Грешка при разархивиране на устройството.", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Неуспешно разархивиране на устройството.", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Разархивиране", "unarchive": "Unarchive",
"archiveClient": "Архивиране на клиента", "archiveClient": "Archive Client",
"archiveClientQuestion": "Сигурни ли сте, че искате да архивирате този клиент?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Клиентът ще бъде архивиран и премахнат от вашия списък с активни клиенти.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Архивиране на клиента", "archiveClientConfirm": "Archive Client",
"blockClient": "Блокиране на клиента", "blockClient": "Block Client",
"blockClientQuestion": "Сигурни ли сте, че искате да блокирате този клиент?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Устройството ще бъде принудено да прекъсне, ако е в момента свързано. Можете да го отблокирате по-късно.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Блокиране на клиента", "blockClientConfirm": "Block Client",
"active": "Активно", "active": "Active",
"usernameOrEmail": "Потребителско име или имейл", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Изберете вашата организация", "selectYourOrganization": "Select your organization",
"signInTo": "Влезте в", "signInTo": "Log in in to",
"signInWithPassword": "Продължете с парола", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Няма налични методи за удостоверяване за тази организация.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Въведете вашата парола", "enterPassword": "Enter your password",
"enterMfaCode": "Въведете кода от вашето приложение за удостоверяване", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Моля, използвайте ключа за сигурност, за да влезете.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Трябва ли да използвате различен акаунт?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "С натискането на бутоните по-долу, потвърждавате, че сте прочели, разбирате и се съгласявате с <termsOfService>Условията за ползване</termsOfService> и <privacyPolicy>Политиката за поверителност</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Условия за ползване", "termsOfService": "Terms of Service",
"privacyPolicy": "Политика за поверителност", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Не е намерен потребител с това потребителско име.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Потвърждение", "verify": "Verify",
"signIn": "Вход", "signIn": "Sign In",
"forgotPassword": "Забравена парола?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Ако сте влизали преди, можете да въведете вашето потребителско име или имейл по-горе, за да се удостовери с идентификатора на вашата организация. Лесно е!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Продължете въпреки това", "continueAnyway": "Continue anyway",
"dontShowAgain": "Не показвайте повече", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Знаете ли?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Опитвате се да влезете?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Опитвате ли се да влезете чрез идентификационния доставчик на вашата организация?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Влезте или се регистрирайте с вашата организация вместо това.", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Използвайте различен акаунт", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Вход", "logIn": "Log In",
"deviceInformation": "Информация за устройството", "deviceInformation": "Device Information",
"deviceInformationDescription": "Информация за устройството и агента", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Защита на устройството.", "platform": "Platform",
"deviceSecurityDescription": "Информация за състоянието на защитата на устройството.", "macosVersion": "macOS Version",
"platform": "Платформа", "windowsVersion": "Windows Version",
"macosVersion": "Версия на macOS", "iosVersion": "iOS Version",
"windowsVersion": "Версия на Windows", "androidVersion": "Android Version",
"iosVersion": "Версия на iOS", "osVersion": "OS Version",
"androidVersion": "Версия на Android", "kernelVersion": "Kernel Version",
"osVersion": "Версия на ОС", "deviceModel": "Device Model",
"kernelVersion": "Версия на ядрото", "serialNumber": "Serial Number",
"deviceModel": "Модел на устройството", "hostname": "Hostname",
"serialNumber": "Сериен номер", "firstSeen": "First Seen",
"hostname": "Име на хост", "lastSeen": "Last Seen",
"firstSeen": "Видян за първи път", "deviceSettingsDescription": "View device information and settings",
"lastSeen": "Последно видян", "devicePendingApprovalDescription": "This device is waiting for approval",
"biometricsEnabled": "Активирани биометрични данни.", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"diskEncrypted": "Криптиран диск.", "unblockClient": "Unblock Client",
"firewallEnabled": "Активирана защитна стена.", "unblockClientDescription": "The device has been unblocked",
"autoUpdatesEnabled": "Активирани автоматични актуализации.", "unarchiveClient": "Unarchive Client",
"tpmAvailable": "TPM е на разположение.", "unarchiveClientDescription": "The device has been unarchived",
"macosSipEnabled": "Protection на системната цялост (SIP).", "block": "Block",
"macosGatekeeperEnabled": "Gatekeeper.", "unblock": "Unblock",
"macosFirewallStealthMode": "Скрит режим на защитната стена.", "deviceActions": "Device Actions",
"linuxAppArmorEnabled": "AppArmor.", "deviceActionsDescription": "Manage device status and access",
"linuxSELinuxEnabled": "SELinux.", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceSettingsDescription": "Разгледайте информация и настройки на устройството", "connected": "Connected",
"devicePendingApprovalDescription": "Това устройство чака одобрение", "disconnected": "Disconnected",
"deviceBlockedDescription": "Това устройство е в момента блокирано. Няма да може да се свърже с никакви ресурси, освен ако не бъде деблокирано.", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unblockClient": "Деблокирайте клиента", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unblockClientDescription": "Устройството е деблокирано", "approvalsEmptyStateStep1Title": "Go to Roles",
"unarchiveClient": "Разархивиране на клиента", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unarchiveClientDescription": "Устройството е разархивирано", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"block": "Блокирането", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"unblock": "Деблокиране", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"deviceActions": "Действия с устройствата", "approvalsEmptyStateButtonText": "Manage Roles"
"deviceActionsDescription": "Управлявайте състоянието и достъпа на устройството",
"devicePendingApprovalBannerDescription": "Това устройство чака одобрение. Няма да може да се свърже с ресурси, докато не бъде одобрено.",
"connected": "Свързан",
"disconnected": "Прекъснат",
"approvalsEmptyStateTitle": "Одобрения на устройство не са активирани",
"approvalsEmptyStateDescription": "Активирайте одобрения на устройства за роли, така че да изискват администраторско одобрение, преди потребителите да могат да свързват нови устройства.",
"approvalsEmptyStateStep1Title": "Отидете на роли",
"approvalsEmptyStateStep1Description": "Навигирайте до настройките на ролите на вашата организация, за да конфигурирате одобренията на устройства.",
"approvalsEmptyStateStep2Title": "Активирайте одобрения на устройства",
"approvalsEmptyStateStep2Description": "Редактирайте ролята и активирайте опцията 'Изискване на одобрения за устройства'. Потребители с тази роля ще трябва администраторско одобрение за нови устройства.",
"approvalsEmptyStatePreviewDescription": "Преглед: Когато е активирано, чакащите заявки за устройства ще се появят тук за преглед",
"approvalsEmptyStateButtonText": "Управлявайте роли"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Připojit jakoukoli síť", "sitesBannerTitle": "Připojit jakoukoli síť",
"sitesBannerDescription": "Lokalita je připojení k vzdálené síti, která umožňuje Pangolinu poskytovat přístup k prostředkům, ať už veřejným nebo soukromým, uživatelům kdekoli. Nainstalujte síťový konektor (Newt) kamkoli, kam můžete spustit binární soubor nebo kontejner, aby bylo možné připojení navázat.", "sitesBannerDescription": "Lokalita je připojení k vzdálené síti, která umožňuje Pangolinu poskytovat přístup k prostředkům, ať už veřejným nebo soukromým, uživatelům kdekoli. Nainstalujte síťový konektor (Newt) kamkoli, kam můžete spustit binární soubor nebo kontejner, aby bylo možné připojení navázat.",
"sitesBannerButtonText": "Nainstalovat lokalitu", "sitesBannerButtonText": "Nainstalovat lokalitu",
"approvalsBannerTitle": "Schválit nebo zakázat přístup k zařízení", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Zkontrolovat a schválit nebo zakázat žádosti uživatelů o přístup k zařízení. Pokud jsou vyžadována schválení zařízení, musí být uživatelé oprávněni před tím, než se jejich zařízení mohou připojit k zdrojům vaší organizace.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Zjistit více", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Vytvořit lokalitu", "siteCreate": "Vytvořit lokalitu",
"siteCreateDescription2": "Postupujte podle níže uvedených kroků, abyste vytvořili a připojili novou lokalitu", "siteCreateDescription2": "Postupujte podle níže uvedených kroků, abyste vytvořili a připojili novou lokalitu",
"siteCreateDescription": "Vytvořit nový web pro zahájení připojování zdrojů", "siteCreateDescription": "Vytvořit nový web pro zahájení připojování zdrojů",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Hledat role...", "accessRolesSearch": "Hledat role...",
"accessRolesAdd": "Přidat roli", "accessRolesAdd": "Přidat roli",
"accessRoleDelete": "Odstranit roli", "accessRoleDelete": "Odstranit roli",
"accessApprovalsManage": "Spravovat schválení", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Zobrazit a spravovat čekající oprávnění pro přístup k této organizaci", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "L 343, 22.12.2009, s. 1).", "description": "L 343, 22.12.2009, s. 1).",
"inviteTitle": "Otevřít pozvánky", "inviteTitle": "Otevřít pozvánky",
"inviteDescription": "Spravovat pozvánky pro ostatní uživatele do organizace", "inviteDescription": "Spravovat pozvánky pro ostatní uživatele do organizace",
@@ -455,18 +455,18 @@
"selectDuration": "Vyberte dobu trvání", "selectDuration": "Vyberte dobu trvání",
"selectResource": "Vybrat dokument", "selectResource": "Vybrat dokument",
"filterByResource": "Filtrovat podle zdroje", "filterByResource": "Filtrovat podle zdroje",
"selectApprovalState": "Vyberte stát schválení", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtrovat podle státu schválení", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Žádná schválení", "approvalListEmpty": "No approvals",
"approvalState": "Země schválení", "approvalState": "Approval State",
"approve": "Schválit", "approve": "Approve",
"approved": "Schváleno", "approved": "Approved",
"denied": "Zamítnuto", "denied": "Denied",
"deniedApproval": "Odmítnuto schválení", "deniedApproval": "Denied Approval",
"all": "Vše", "all": "All",
"deny": "Zamítnout", "deny": "Deny",
"viewDetails": "Zobrazit detaily", "viewDetails": "View Details",
"requestingNewDeviceApproval": "vyžádal si nové zařízení", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Resetovat filtry", "resetFilters": "Resetovat filtry",
"totalBlocked": "Požadavky blokovány Pangolinem", "totalBlocked": "Požadavky blokovány Pangolinem",
"totalRequests": "Celkem požadavků", "totalRequests": "Celkem požadavků",
@@ -746,28 +746,28 @@
"countries": "Země", "countries": "Země",
"accessRoleCreate": "Vytvořit roli", "accessRoleCreate": "Vytvořit roli",
"accessRoleCreateDescription": "Vytvořte novou roli pro seskupení uživatelů a spravujte jejich oprávnění.", "accessRoleCreateDescription": "Vytvořte novou roli pro seskupení uživatelů a spravujte jejich oprávnění.",
"accessRoleEdit": "Upravit roli", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Upravit informace o roli.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Vytvořit roli", "accessRoleCreateSubmit": "Vytvořit roli",
"accessRoleCreated": "Role vytvořena", "accessRoleCreated": "Role vytvořena",
"accessRoleCreatedDescription": "Role byla úspěšně vytvořena.", "accessRoleCreatedDescription": "Role byla úspěšně vytvořena.",
"accessRoleErrorCreate": "Nepodařilo se vytvořit roli", "accessRoleErrorCreate": "Nepodařilo se vytvořit roli",
"accessRoleErrorCreateDescription": "Došlo k chybě při vytváření role.", "accessRoleErrorCreateDescription": "Došlo k chybě při vytváření role.",
"accessRoleUpdateSubmit": "Aktualizovat roli", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Role aktualizována", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Role byla úspěšně aktualizována.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Zpracovaná schválení", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Nastavit rozhodnutí o schválení žádosti o schválení.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Nastavit žádost o schválení rozhodnutí o zamítnutí.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Nepodařilo se aktualizovat roli", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Došlo k chybě při aktualizaci role.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Zpracování schválení se nezdařilo", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Při zpracování schválení došlo k chybě.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Je vyžadována nová role", "accessRoleErrorNewRequired": "Je vyžadována nová role",
"accessRoleErrorRemove": "Nepodařilo se odstranit roli", "accessRoleErrorRemove": "Nepodařilo se odstranit roli",
"accessRoleErrorRemoveDescription": "Došlo k chybě při odstraňování role.", "accessRoleErrorRemoveDescription": "Došlo k chybě při odstraňování role.",
"accessRoleName": "Název role", "accessRoleName": "Název role",
"accessRoleQuestionRemove": "Chystáte se odstranit roli `{name}`. Tuto akci nelze vrátit zpět.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Odstranit roli", "accessRoleRemove": "Odstranit roli",
"accessRoleRemoveDescription": "Odebrat roli z organizace", "accessRoleRemoveDescription": "Odebrat roli z organizace",
"accessRoleRemoveSubmit": "Odstranit roli", "accessRoleRemoveSubmit": "Odstranit roli",
@@ -903,7 +903,7 @@
"inviteAlready": "Vypadá to, že jste byli pozváni!", "inviteAlready": "Vypadá to, že jste byli pozváni!",
"inviteAlreadyDescription": "Chcete-li přijmout pozvánku, musíte se přihlásit nebo vytvořit účet.", "inviteAlreadyDescription": "Chcete-li přijmout pozvánku, musíte se přihlásit nebo vytvořit účet.",
"signupQuestion": "Již máte účet?", "signupQuestion": "Již máte účet?",
"login": "Přihlásit se", "login": "Log In",
"resourceNotFound": "Zdroj nebyl nalezen", "resourceNotFound": "Zdroj nebyl nalezen",
"resourceNotFoundDescription": "Dokument, ke kterému se snažíte přistupovat, neexistuje.", "resourceNotFoundDescription": "Dokument, ke kterému se snažíte přistupovat, neexistuje.",
"pincodeRequirementsLength": "PIN musí být přesně 6 číslic", "pincodeRequirementsLength": "PIN musí být přesně 6 číslic",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Tato organizace vyžaduje změnu hesla každých {maxDays} dní.", "passwordExpiryDescription": "Tato organizace vyžaduje změnu hesla každých {maxDays} dní.",
"changePasswordNow": "Změnit heslo", "changePasswordNow": "Změnit heslo",
"pincodeAuth": "Ověřovací kód", "pincodeAuth": "Ověřovací kód",
"pincodeSubmit2": "Odeslat kód", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Žádost o obnovení", "passwordResetSubmit": "Žádost o obnovení",
"passwordResetAlreadyHaveCode": "Zadejte kód", "passwordResetAlreadyHaveCode": "Zadejte kód",
"passwordResetSmtpRequired": "Obraťte se na správce", "passwordResetSmtpRequired": "Obraťte se na správce",
"passwordResetSmtpRequiredDescription": "Pro obnovení hesla je vyžadován kód pro obnovení hesla. Kontaktujte prosím svého administrátora.", "passwordResetSmtpRequiredDescription": "Pro obnovení hesla je vyžadován kód pro obnovení hesla. Kontaktujte prosím svého administrátora.",
"passwordBack": "Zpět na heslo", "passwordBack": "Zpět na heslo",
"loginBack": "Přejít zpět na hlavní přihlašovací stránku", "loginBack": "Go back to main login page",
"signup": "Zaregistrovat se", "signup": "Zaregistrovat se",
"loginStart": "Přihlaste se a začněte", "loginStart": "Přihlaste se a začněte",
"idpOidcTokenValidating": "Ověřování OIDC tokenu", "idpOidcTokenValidating": "Ověřování OIDC tokenu",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Aktualizovat IDP Org", "actionUpdateIdpOrg": "Aktualizovat IDP Org",
"actionCreateClient": "Vytvořit klienta", "actionCreateClient": "Vytvořit klienta",
"actionDeleteClient": "Odstranit klienta", "actionDeleteClient": "Odstranit klienta",
"actionArchiveClient": "Archivovat klienta", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Zrušit archiv klienta", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Blokovat klienta", "actionBlockClient": "Block Client",
"actionUnblockClient": "Odblokovat klienta", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Aktualizovat klienta", "actionUpdateClient": "Aktualizovat klienta",
"actionListClients": "Seznam klientů", "actionListClients": "Seznam klientů",
"actionGetClient": "Získat klienta", "actionGetClient": "Získat klienta",
@@ -1167,14 +1167,14 @@
"searchProgress": "Hledat...", "searchProgress": "Hledat...",
"create": "Vytvořit", "create": "Vytvořit",
"orgs": "Organizace", "orgs": "Organizace",
"loginError": "Došlo k neočekávané chybě. Zkuste to prosím znovu.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Přihlášení je vyžadováno pro vaše zařízení.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Zapomněli jste heslo?", "passwordForgot": "Zapomněli jste heslo?",
"otpAuth": "Dvoufaktorové ověření", "otpAuth": "Dvoufaktorové ověření",
"otpAuthDescription": "Zadejte kód z vaší autentizační aplikace nebo jeden z vlastních záložních kódů.", "otpAuthDescription": "Zadejte kód z vaší autentizační aplikace nebo jeden z vlastních záložních kódů.",
"otpAuthSubmit": "Odeslat kód", "otpAuthSubmit": "Odeslat kód",
"idpContinue": "Nebo pokračovat s", "idpContinue": "Nebo pokračovat s",
"otpAuthBack": "Zpět na heslo", "otpAuthBack": "Back to Password",
"navbar": "Navigation Menu", "navbar": "Navigation Menu",
"navbarDescription": "Hlavní navigační menu aplikace", "navbarDescription": "Hlavní navigační menu aplikace",
"navbarDocsLink": "Dokumentace", "navbarDocsLink": "Dokumentace",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Přehled", "sidebarOverview": "Přehled",
"sidebarHome": "Domů", "sidebarHome": "Domů",
"sidebarSites": "Stránky", "sidebarSites": "Stránky",
"sidebarApprovals": "Žádosti o schválení", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Zdroje", "sidebarResources": "Zdroje",
"sidebarProxyResources": "Veřejnost", "sidebarProxyResources": "Veřejnost",
"sidebarClientResources": "Soukromé", "sidebarClientResources": "Soukromé",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Poskytovatelé identity", "sidebarIdentityProviders": "Poskytovatelé identity",
"sidebarLicense": "Licence", "sidebarLicense": "Licence",
"sidebarClients": "Klienti", "sidebarClients": "Klienti",
"sidebarUserDevices": "Uživatelská zařízení", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Stroje a přístroje", "sidebarMachineClients": "Stroje a přístroje",
"sidebarDomains": "Domény", "sidebarDomains": "Domény",
"sidebarGeneral": "Spravovat", "sidebarGeneral": "Spravovat",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Došlo k chybě při vytváření účtu správce serveru.", "setupErrorCreateAdmin": "Došlo k chybě při vytváření účtu správce serveru.",
"certificateStatus": "Stav certifikátu", "certificateStatus": "Stav certifikátu",
"loading": "Načítání", "loading": "Načítání",
"loadingAnalytics": "Načítání analytiky", "loadingAnalytics": "Loading Analytics",
"restart": "Restartovat", "restart": "Restartovat",
"domains": "Domény", "domains": "Domény",
"domainsDescription": "Vytvořit a spravovat domény dostupné v organizaci", "domainsDescription": "Vytvořit a spravovat domény dostupné v organizaci",
@@ -1339,7 +1339,7 @@
"refreshError": "Obnovení dat se nezdařilo", "refreshError": "Obnovení dat se nezdařilo",
"verified": "Ověřeno", "verified": "Ověřeno",
"pending": "Nevyřízeno", "pending": "Nevyřízeno",
"pendingApproval": "Čeká na schválení", "pendingApproval": "Pending Approval",
"sidebarBilling": "Fakturace", "sidebarBilling": "Fakturace",
"billing": "Fakturace", "billing": "Fakturace",
"orgBillingDescription": "Spravovat fakturační informace a předplatné", "orgBillingDescription": "Spravovat fakturační informace a předplatné",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Bezpečnostní klíč byl úspěšně odstraněn", "securityKeyRemoveSuccess": "Bezpečnostní klíč byl úspěšně odstraněn",
"securityKeyRemoveError": "Odstranění bezpečnostního klíče se nezdařilo", "securityKeyRemoveError": "Odstranění bezpečnostního klíče se nezdařilo",
"securityKeyLoadError": "Nepodařilo se načíst bezpečnostní klíče", "securityKeyLoadError": "Nepodařilo se načíst bezpečnostní klíče",
"securityKeyLogin": "Použít bezpečnostní klíč", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Ověření bezpečnostním klíčem se nezdařilo", "securityKeyAuthError": "Ověření bezpečnostním klíčem se nezdařilo",
"securityKeyRecommendation": "Registrujte záložní bezpečnostní klíč na jiném zařízení, abyste zajistili, že budete mít vždy přístup ke svému účtu.", "securityKeyRecommendation": "Registrujte záložní bezpečnostní klíč na jiném zařízení, abyste zajistili, že budete mít vždy přístup ke svému účtu.",
"registering": "Registrace...", "registering": "Registrace...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Interval zdraví", "IntervalSeconds": "Interval zdraví",
"timeoutSeconds": "Časový limit (sek)", "timeoutSeconds": "Časový limit (sek)",
"timeIsInSeconds": "Čas je v sekundách", "timeIsInSeconds": "Čas je v sekundách",
"requireDeviceApproval": "Vyžadovat schválení zařízení", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Uživatelé s touto rolí potřebují nová zařízení schválená správcem, než se mohou připojit a přistupovat ke zdrojům.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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é.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Nebyly nalezeny žádné vnitřní zdroje.", "resourcesTableNoInternalResourcesFound": "Nebyly nalezeny žádné vnitřní zdroje.",
"resourcesTableDestination": "Místo určení", "resourcesTableDestination": "Místo určení",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Adresa aliasu",
"resourcesTableAliasAddressInfo": "Tato adresa je součástí subsítě veřejných služeb organizace. Používá se k řešení záznamů aliasů pomocí interního rozlišení DNS.",
"resourcesTableClients": "Klienti", "resourcesTableClients": "Klienti",
"resourcesTableAndOnlyAccessibleInternally": "a jsou interně přístupné pouze v případě, že jsou propojeni s klientem.", "resourcesTableAndOnlyAccessibleInternally": "a jsou interně přístupné pouze v případě, že jsou propojeni s klientem.",
"resourcesTableNoTargets": "Žádné cíle", "resourcesTableNoTargets": "Žádné cíle",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Chcete-li pokračovat, vyberte svého poskytovatele identity", "orgAuthChooseIdpDescription": "Chcete-li pokračovat, vyberte svého poskytovatele identity",
"orgAuthNoIdpConfigured": "Tato organizace nemá nakonfigurovány žádné poskytovatele identity. Místo toho se můžete přihlásit s vaší Pangolinovou identitou.", "orgAuthNoIdpConfigured": "Tato organizace nemá nakonfigurovány žádné poskytovatele identity. Místo toho se můžete přihlásit s vaší Pangolinovou identitou.",
"orgAuthSignInWithPangolin": "Přihlásit se pomocí Pangolinu", "orgAuthSignInWithPangolin": "Přihlásit se pomocí Pangolinu",
"orgAuthSignInToOrg": "Přihlásit se do organizace", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Přihlášení do organizace", "orgAuthSelectOrgTitle": "Přihlášení do organizace",
"orgAuthSelectOrgDescription": "Zadejte ID vaší organizace pro pokračování", "orgAuthSelectOrgDescription": "Zadejte ID vaší organizace pro pokračování",
"orgAuthOrgIdPlaceholder": "vaše-organizace", "orgAuthOrgIdPlaceholder": "vaše-organizace",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Kód musí být 9 znaků (např. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Kód musí být 9 znaků (např. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Neplatný nebo prošlý kód", "deviceCodeInvalidOrExpired": "Neplatný nebo prošlý kód",
"deviceCodeVerifyFailed": "Ověření kódu zařízení se nezdařilo", "deviceCodeVerifyFailed": "Ověření kódu zařízení se nezdařilo",
"deviceCodeValidating": "Ověřování kódu zařízení...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Ověřování autorizace zařízení...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Přihlášen jako", "signedInAs": "Přihlášen jako",
"deviceCodeEnterPrompt": "Zadejte kód zobrazený na zařízení", "deviceCodeEnterPrompt": "Zadejte kód zobrazený na zařízení",
"continue": "Pokračovat", "continue": "Pokračovat",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Přístup ke všem organizacím má přístup k vašemu účtu", "deviceOrganizationsAccess": "Přístup ke všem organizacím má přístup k vašemu účtu",
"deviceAuthorize": "Autorizovat {applicationName}", "deviceAuthorize": "Autorizovat {applicationName}",
"deviceConnected": "Zařízení připojeno!", "deviceConnected": "Zařízení připojeno!",
"deviceAuthorizedMessage": "Zařízení má oprávnění k přístupu k vašemu účtu. Vraťte se prosím do klientské aplikace.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Pangolin Cloud", "pangolinCloud": "Pangolin Cloud",
"viewDevices": "Zobrazit zařízení", "viewDevices": "Zobrazit zařízení",
"viewDevicesDescription": "Spravovat připojená zařízení", "viewDevicesDescription": "Spravovat připojená zařízení",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Nejste vy? Použijte jiný účet.", "deviceLoginUseDifferentAccount": "Nejste vy? Použijte jiný účet.",
"deviceLoginDeviceRequestingAccessToAccount": "Zařízení žádá o přístup k tomuto účtu.", "deviceLoginDeviceRequestingAccessToAccount": "Zařízení žádá o přístup k tomuto účtu.",
"loginSelectAuthenticationMethod": "Chcete-li pokračovat, vyberte metodu ověřování.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Žádná data", "noData": "Žádná data",
"machineClients": "Strojoví klienti", "machineClients": "Strojoví klienti",
"install": "Instalovat", "install": "Instalovat",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Momentálně máme technické potíže. Zkontrolujte později.", "maintenanceScreenMessage": "Momentálně máme technické potíže. Zkontrolujte později.",
"maintenanceScreenEstimatedCompletion": "Odhadované dokončení:", "maintenanceScreenEstimatedCompletion": "Odhadované dokončení:",
"createInternalResourceDialogDestinationRequired": "Cíl je povinný", "createInternalResourceDialogDestinationRequired": "Cíl je povinný",
"available": "Dostupné", "available": "Available",
"archived": "Archivováno", "archived": "Archived",
"noArchivedDevices": "Nebyla nalezena žádná archivovaná zařízení", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Zařízení archivováno", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Zařízení bylo úspěšně archivováno.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Chyba při archivaci zařízení", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Archivace zařízení se nezdařila", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Opravdu chcete archivovat toto zařízení?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Zařízení bude archivováno a odebráno ze seznamu aktivních zařízení.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Archivovat zařízení", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Archivovat zařízení", "archiveDevice": "Archive Device",
"archive": "Archiv", "archive": "Archive",
"deviceUnarchived": "Zařízení bylo odarchivováno", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Zařízení bylo úspěšně odarchivováno.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Chyba při odarchivování zařízení", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Nepodařilo se odarchivovat zařízení", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Zrušit archiv", "unarchive": "Unarchive",
"archiveClient": "Archivovat klienta", "archiveClient": "Archive Client",
"archiveClientQuestion": "Jste si jisti, že chcete archivovat tohoto klienta?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Klient bude archivován a odstraněn z vašeho aktivního seznamu klientů.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Archivovat klienta", "archiveClientConfirm": "Archive Client",
"blockClient": "Blokovat klienta", "blockClient": "Block Client",
"blockClientQuestion": "Jste si jisti, že chcete zablokovat tohoto klienta?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Zařízení bude nuceno odpojit, pokud je připojeno. Zařízení můžete později odblokovat.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Blokovat klienta", "blockClientConfirm": "Block Client",
"active": "Aktiv", "active": "Active",
"usernameOrEmail": "Uživatelské jméno nebo e-mail", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Vyberte vaši organizaci", "selectYourOrganization": "Select your organization",
"signInTo": "Přihlásit se do", "signInTo": "Log in in to",
"signInWithPassword": "Pokračovat s heslem", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Pro tuto organizaci nejsou k dispozici žádné metody ověřování.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Zadejte své heslo", "enterPassword": "Enter your password",
"enterMfaCode": "Zadejte kód z vaší ověřovací aplikace", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Pro přihlášení použijte svůj bezpečnostní klíč.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Potřebujete použít jiný účet?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Kliknutím na tlačítka níže potvrzujete, že jste si přečetli, chápali, a souhlasím s <termsOfService>obchodními podmínkami</termsOfService> a <privacyPolicy>Zásadami ochrany osobních údajů</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Podmínky služby", "termsOfService": "Terms of Service",
"privacyPolicy": "Ochrana osobních údajů", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Nebyl nalezen žádný uživatel s tímto uživatelským jménem.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Ověřit", "verify": "Verify",
"signIn": "Přihlásit se", "signIn": "Sign In",
"forgotPassword": "Zapomněli jste heslo?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Pokud jste se přihlásili dříve, můžete místo toho zadat své uživatelské jméno nebo e-mail výše pro ověření u poskytovatele identity vaší organizace. Je to jednodušší!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Přesto pokračovat", "continueAnyway": "Continue anyway",
"dontShowAgain": "Znovu nezobrazovat", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Věděli jste, že?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Chcete se přihlásit?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Snažíte se přihlásit prostřednictvím poskytovatele identity vaší organizace?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Namísto toho se přihlaste nebo se zaregistrujte pomocí své organizace", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Použít jiný účet", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Přihlásit se", "logIn": "Log In",
"deviceInformation": "Informace o zařízení", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informace o zařízení a agentovi", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Zabezpečení zařízení", "platform": "Platform",
"deviceSecurityDescription": "Informace o bezpečnostní pozici zařízení", "macosVersion": "macOS Version",
"platform": "Platforma", "windowsVersion": "Windows Version",
"macosVersion": "macOS verze", "iosVersion": "iOS Version",
"windowsVersion": "Verze Windows", "androidVersion": "Android Version",
"iosVersion": "Verze iOS", "osVersion": "OS Version",
"androidVersion": "Verze Androidu", "kernelVersion": "Kernel Version",
"osVersion": "Verze OS", "deviceModel": "Device Model",
"kernelVersion": "Verze jádra", "serialNumber": "Serial Number",
"deviceModel": "Model zařízení",
"serialNumber": "Pořadové číslo",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "První vidění", "firstSeen": "First Seen",
"lastSeen": "Naposledy viděno", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometrie povolena", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Šifrovaný disk", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Firewall povolen", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Automatické aktualizace povoleny", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM k dispozici", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Ochrana systémové integrity (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Režim neviditelnosti firewallu", "block": "Block",
"linuxAppArmorEnabled": "Pancíř aplikace", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Zobrazit informace o zařízení a nastavení", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Toto zařízení čeká na schválení", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Toto zařízení je momentálně blokováno. Nebude se moci připojit k žádným zdrojům, dokud nebude odblokováno.", "connected": "Connected",
"unblockClient": "Odblokovat klienta", "disconnected": "Disconnected",
"unblockClientDescription": "Zařízení bylo odblokováno", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Zrušit archiv klienta", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Zařízení bylo odarchivováno", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Blokovat", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Odblokovat", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Akce zařízení", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Spravovat stav zařízení a přístup", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Toto zařízení čeká na schválení. Nebude se moci připojit ke zdrojům, dokud nebude schváleno.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Připojeno",
"disconnected": "Odpojeno",
"approvalsEmptyStateTitle": "Schvalování zařízení není povoleno",
"approvalsEmptyStateDescription": "Povolte oprávnění oprávnění pro role správce před připojením nových zařízení.",
"approvalsEmptyStateStep1Title": "Přejít na role",
"approvalsEmptyStateStep1Description": "Přejděte do nastavení rolí vaší organizace pro konfiguraci schválení zařízení.",
"approvalsEmptyStateStep2Title": "Povolit schválení zařízení",
"approvalsEmptyStateStep2Description": "Upravte roli a povolte možnost 'Vyžadovat schválení zařízení'. Uživatelé s touto rolí budou potřebovat schválení pro nová zařízení správce.",
"approvalsEmptyStatePreviewDescription": "Náhled: Pokud je povoleno, čekající na zařízení se zde zobrazí žádosti o recenzi",
"approvalsEmptyStateButtonText": "Spravovat role"
} }
+124 -138
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Verbinde ein beliebiges Netzwerk", "sitesBannerTitle": "Verbinde ein beliebiges Netzwerk",
"sitesBannerDescription": "Ein Standort ist eine Verbindung zu einem Remote-Netzwerk, die es Pangolin ermöglicht, Zugriff auf öffentliche oder private Ressourcen für Benutzer überall zu gewähren. Installieren Sie den Site Netzwerk Connector (Newt) wo auch immer Sie eine Binärdatei oder einen Container starten können, um die Verbindung herzustellen.", "sitesBannerDescription": "Ein Standort ist eine Verbindung zu einem Remote-Netzwerk, die es Pangolin ermöglicht, Zugriff auf öffentliche oder private Ressourcen für Benutzer überall zu gewähren. Installieren Sie den Site Netzwerk Connector (Newt) wo auch immer Sie eine Binärdatei oder einen Container starten können, um die Verbindung herzustellen.",
"sitesBannerButtonText": "Standort installieren", "sitesBannerButtonText": "Standort installieren",
"approvalsBannerTitle": "Gerätezugriff genehmigen oder verweigern", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Überprüfen und genehmigen oder verweigern Gerätezugriffsanfragen von Benutzern. Wenn Gerätegenehmigungen erforderlich sind, müssen Benutzer eine Administratorgenehmigung erhalten, bevor ihre Geräte sich mit den Ressourcen Ihrer Organisation verbinden können.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Mehr erfahren", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Standort erstellen", "siteCreate": "Standort erstellen",
"siteCreateDescription2": "Folge den nachfolgenden Schritten, um einen neuen Standort zu erstellen und zu verbinden", "siteCreateDescription2": "Folge den nachfolgenden Schritten, um einen neuen Standort zu erstellen und zu verbinden",
"siteCreateDescription": "Erstellen Sie einen neuen Standort, um Ressourcen zu verbinden", "siteCreateDescription": "Erstellen Sie einen neuen Standort, um Ressourcen zu verbinden",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Rollen suchen...", "accessRolesSearch": "Rollen suchen...",
"accessRolesAdd": "Rolle hinzufügen", "accessRolesAdd": "Rolle hinzufügen",
"accessRoleDelete": "Rolle löschen", "accessRoleDelete": "Rolle löschen",
"accessApprovalsManage": "Genehmigungen verwalten", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Zeige und verwalte ausstehende Genehmigungen für den Zugriff auf diese Organisation", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Beschreibung", "description": "Beschreibung",
"inviteTitle": "Einladungen öffnen", "inviteTitle": "Einladungen öffnen",
"inviteDescription": "Einladungen für andere Benutzer verwalten, der Organisation beizutreten", "inviteDescription": "Einladungen für andere Benutzer verwalten, der Organisation beizutreten",
@@ -455,18 +455,18 @@
"selectDuration": "Dauer auswählen", "selectDuration": "Dauer auswählen",
"selectResource": "Ressource auswählen", "selectResource": "Ressource auswählen",
"filterByResource": "Nach Ressource filtern", "filterByResource": "Nach Ressource filtern",
"selectApprovalState": "Genehmigungsstatus auswählen", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtern nach Genehmigungsstatus", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Keine Genehmigungen", "approvalListEmpty": "No approvals",
"approvalState": "Genehmigungsstatus", "approvalState": "Approval State",
"approve": "Bestätigen", "approve": "Approve",
"approved": "Genehmigt", "approved": "Approved",
"denied": "Verweigert", "denied": "Denied",
"deniedApproval": "Genehmigung verweigert", "deniedApproval": "Denied Approval",
"all": "Alle", "all": "All",
"deny": "Leugnen", "deny": "Deny",
"viewDetails": "Details anzeigen", "viewDetails": "View Details",
"requestingNewDeviceApproval": "hat ein neues Gerät angefordert", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Filter zurücksetzen", "resetFilters": "Filter zurücksetzen",
"totalBlocked": "Anfragen blockiert von Pangolin", "totalBlocked": "Anfragen blockiert von Pangolin",
"totalRequests": "Gesamte Anfragen", "totalRequests": "Gesamte Anfragen",
@@ -746,28 +746,28 @@
"countries": "Länder", "countries": "Länder",
"accessRoleCreate": "Rolle erstellen", "accessRoleCreate": "Rolle erstellen",
"accessRoleCreateDescription": "Erstellen Sie eine neue Rolle, um Benutzer zu gruppieren und ihre Berechtigungen zu verwalten.", "accessRoleCreateDescription": "Erstellen Sie eine neue Rolle, um Benutzer zu gruppieren und ihre Berechtigungen zu verwalten.",
"accessRoleEdit": "Rolle bearbeiten", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Rolleninformationen bearbeiten.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Rolle erstellen", "accessRoleCreateSubmit": "Rolle erstellen",
"accessRoleCreated": "Rolle erstellt", "accessRoleCreated": "Rolle erstellt",
"accessRoleCreatedDescription": "Die Rolle wurde erfolgreich erstellt.", "accessRoleCreatedDescription": "Die Rolle wurde erfolgreich erstellt.",
"accessRoleErrorCreate": "Fehler beim Erstellen der Rolle", "accessRoleErrorCreate": "Fehler beim Erstellen der Rolle",
"accessRoleErrorCreateDescription": "Beim Erstellen der Rolle ist ein Fehler aufgetreten.", "accessRoleErrorCreateDescription": "Beim Erstellen der Rolle ist ein Fehler aufgetreten.",
"accessRoleUpdateSubmit": "Rolle aktualisieren", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rolle aktualisiert", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Die Rolle wurde erfolgreich aktualisiert.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Genehmigung bearbeitet", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Entscheidung für Genehmigungsanfrage setzen.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Entscheidung für Genehmigungsanfrage ablehnen.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Fehler beim Aktualisieren der Rolle", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Beim Aktualisieren der Rolle ist ein Fehler aufgetreten.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Genehmigung konnte nicht verarbeitet werden", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Bei der Bearbeitung der Genehmigung ist ein Fehler aufgetreten.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Neue Rolle ist erforderlich", "accessRoleErrorNewRequired": "Neue Rolle ist erforderlich",
"accessRoleErrorRemove": "Fehler beim Entfernen der Rolle", "accessRoleErrorRemove": "Fehler beim Entfernen der Rolle",
"accessRoleErrorRemoveDescription": "Beim Entfernen der Rolle ist ein Fehler aufgetreten.", "accessRoleErrorRemoveDescription": "Beim Entfernen der Rolle ist ein Fehler aufgetreten.",
"accessRoleName": "Rollenname", "accessRoleName": "Rollenname",
"accessRoleQuestionRemove": "Du bist dabei die Rolle `{name}` zu löschen. Du kannst diese Aktion nicht rückgängig machen.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Rolle entfernen", "accessRoleRemove": "Rolle entfernen",
"accessRoleRemoveDescription": "Eine Rolle aus der Organisation entfernen", "accessRoleRemoveDescription": "Eine Rolle aus der Organisation entfernen",
"accessRoleRemoveSubmit": "Rolle entfernen", "accessRoleRemoveSubmit": "Rolle entfernen",
@@ -903,7 +903,7 @@
"inviteAlready": "Sieht aus, als wären Sie eingeladen worden!", "inviteAlready": "Sieht aus, als wären Sie eingeladen worden!",
"inviteAlreadyDescription": "Um die Einladung anzunehmen, müssen Sie sich einloggen oder ein Konto erstellen.", "inviteAlreadyDescription": "Um die Einladung anzunehmen, müssen Sie sich einloggen oder ein Konto erstellen.",
"signupQuestion": "Haben Sie bereits ein Konto?", "signupQuestion": "Haben Sie bereits ein Konto?",
"login": "Anmelden", "login": "Log In",
"resourceNotFound": "Ressource nicht gefunden", "resourceNotFound": "Ressource nicht gefunden",
"resourceNotFoundDescription": "Die Ressource, auf die Sie zugreifen möchten, existiert nicht.", "resourceNotFoundDescription": "Die Ressource, auf die Sie zugreifen möchten, existiert nicht.",
"pincodeRequirementsLength": "PIN muss genau 6 Ziffern lang sein", "pincodeRequirementsLength": "PIN muss genau 6 Ziffern lang sein",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Diese Organisation erfordert, dass Sie Ihr Passwort alle {maxDays} Tage ändern.", "passwordExpiryDescription": "Diese Organisation erfordert, dass Sie Ihr Passwort alle {maxDays} Tage ändern.",
"changePasswordNow": "Passwort jetzt ändern", "changePasswordNow": "Passwort jetzt ändern",
"pincodeAuth": "Authentifizierungscode", "pincodeAuth": "Authentifizierungscode",
"pincodeSubmit2": "Code einreichen", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Zurücksetzung anfordern", "passwordResetSubmit": "Zurücksetzung anfordern",
"passwordResetAlreadyHaveCode": "Code eingeben", "passwordResetAlreadyHaveCode": "Code eingeben",
"passwordResetSmtpRequired": "Bitte kontaktieren Sie Ihren Administrator", "passwordResetSmtpRequired": "Bitte kontaktieren Sie Ihren Administrator",
"passwordResetSmtpRequiredDescription": "Zum Zurücksetzen Ihres Passworts ist ein Passwort erforderlich. Bitte wenden Sie sich an Ihren Administrator.", "passwordResetSmtpRequiredDescription": "Zum Zurücksetzen Ihres Passworts ist ein Passwort erforderlich. Bitte wenden Sie sich an Ihren Administrator.",
"passwordBack": "Zurück zum Passwort", "passwordBack": "Zurück zum Passwort",
"loginBack": "Zurück zur Haupt-Login-Seite", "loginBack": "Go back to main login page",
"signup": "Registrieren", "signup": "Registrieren",
"loginStart": "Melden Sie sich an, um zu beginnen", "loginStart": "Melden Sie sich an, um zu beginnen",
"idpOidcTokenValidating": "OIDC-Token wird validiert", "idpOidcTokenValidating": "OIDC-Token wird validiert",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "IDP-Organisation aktualisieren", "actionUpdateIdpOrg": "IDP-Organisation aktualisieren",
"actionCreateClient": "Client erstellen", "actionCreateClient": "Client erstellen",
"actionDeleteClient": "Client löschen", "actionDeleteClient": "Client löschen",
"actionArchiveClient": "Kunde archivieren", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Client dearchivieren", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Klient sperren", "actionBlockClient": "Block Client",
"actionUnblockClient": "Client entsperren", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Client aktualisieren", "actionUpdateClient": "Client aktualisieren",
"actionListClients": "Clients auflisten", "actionListClients": "Clients auflisten",
"actionGetClient": "Clients abrufen", "actionGetClient": "Clients abrufen",
@@ -1167,14 +1167,14 @@
"searchProgress": "Suche...", "searchProgress": "Suche...",
"create": "Erstellen", "create": "Erstellen",
"orgs": "Organisationen", "orgs": "Organisationen",
"loginError": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Anmeldung ist für Ihr Gerät erforderlich.", "loginRequiredForDevice": "Anmeldung ist für Ihr Gerät erforderlich.",
"passwordForgot": "Passwort vergessen?", "passwordForgot": "Passwort vergessen?",
"otpAuth": "Zwei-Faktor-Authentifizierung", "otpAuth": "Zwei-Faktor-Authentifizierung",
"otpAuthDescription": "Geben Sie den Code aus Ihrer Authenticator-App oder einen Ihrer einmaligen Backup-Codes ein.", "otpAuthDescription": "Geben Sie den Code aus Ihrer Authenticator-App oder einen Ihrer einmaligen Backup-Codes ein.",
"otpAuthSubmit": "Code absenden", "otpAuthSubmit": "Code absenden",
"idpContinue": "Oder weiter mit", "idpContinue": "Oder weiter mit",
"otpAuthBack": "Zurück zum Passwort", "otpAuthBack": "Back to Password",
"navbar": "Navigationsmenü", "navbar": "Navigationsmenü",
"navbarDescription": "Hauptnavigationsmenü für die Anwendung", "navbarDescription": "Hauptnavigationsmenü für die Anwendung",
"navbarDocsLink": "Dokumentation", "navbarDocsLink": "Dokumentation",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Übersicht", "sidebarOverview": "Übersicht",
"sidebarHome": "Zuhause", "sidebarHome": "Zuhause",
"sidebarSites": "Standorte", "sidebarSites": "Standorte",
"sidebarApprovals": "Genehmigungsanfragen", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Ressourcen", "sidebarResources": "Ressourcen",
"sidebarProxyResources": "Öffentlich", "sidebarProxyResources": "Öffentlich",
"sidebarClientResources": "Privat", "sidebarClientResources": "Privat",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Identitätsanbieter", "sidebarIdentityProviders": "Identitätsanbieter",
"sidebarLicense": "Lizenz", "sidebarLicense": "Lizenz",
"sidebarClients": "Clients", "sidebarClients": "Clients",
"sidebarUserDevices": "Benutzer-Geräte", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Maschinen", "sidebarMachineClients": "Maschinen",
"sidebarDomains": "Domänen", "sidebarDomains": "Domänen",
"sidebarGeneral": "Verwalten", "sidebarGeneral": "Verwalten",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Beim Erstellen des Server-Admin-Kontos ist ein Fehler aufgetreten.", "setupErrorCreateAdmin": "Beim Erstellen des Server-Admin-Kontos ist ein Fehler aufgetreten.",
"certificateStatus": "Zertifikatsstatus", "certificateStatus": "Zertifikatsstatus",
"loading": "Laden", "loading": "Laden",
"loadingAnalytics": "Analytik wird geladen", "loadingAnalytics": "Loading Analytics",
"restart": "Neustart", "restart": "Neustart",
"domains": "Domänen", "domains": "Domänen",
"domainsDescription": "Erstellen und verwalten der in der Organisation verfügbaren Domänen", "domainsDescription": "Erstellen und verwalten der in der Organisation verfügbaren Domänen",
@@ -1339,7 +1339,7 @@
"refreshError": "Datenaktualisierung fehlgeschlagen", "refreshError": "Datenaktualisierung fehlgeschlagen",
"verified": "Verifiziert", "verified": "Verifiziert",
"pending": "Ausstehend", "pending": "Ausstehend",
"pendingApproval": "Ausstehende Genehmigung", "pendingApproval": "Pending Approval",
"sidebarBilling": "Abrechnung", "sidebarBilling": "Abrechnung",
"billing": "Abrechnung", "billing": "Abrechnung",
"orgBillingDescription": "Zahlungsinformationen und Abonnements verwalten", "orgBillingDescription": "Zahlungsinformationen und Abonnements verwalten",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Sicherheitsschlüssel erfolgreich entfernt", "securityKeyRemoveSuccess": "Sicherheitsschlüssel erfolgreich entfernt",
"securityKeyRemoveError": "Fehler beim Entfernen des Sicherheitsschlüssels", "securityKeyRemoveError": "Fehler beim Entfernen des Sicherheitsschlüssels",
"securityKeyLoadError": "Fehler beim Laden der Sicherheitsschlüssel", "securityKeyLoadError": "Fehler beim Laden der Sicherheitsschlüssel",
"securityKeyLogin": "Sicherheitsschlüssel verwenden", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Fehler bei der Authentifizierung mit Sicherheitsschlüssel", "securityKeyAuthError": "Fehler bei der Authentifizierung mit Sicherheitsschlüssel",
"securityKeyRecommendation": "Erwägen Sie die Registrierung eines weiteren Sicherheitsschlüssels auf einem anderen Gerät, um sicherzustellen, dass Sie sich nicht aus Ihrem Konto aussperren.", "securityKeyRecommendation": "Erwägen Sie die Registrierung eines weiteren Sicherheitsschlüssels auf einem anderen Gerät, um sicherzustellen, dass Sie sich nicht aus Ihrem Konto aussperren.",
"registering": "Registrierung...", "registering": "Registrierung...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Gesunder Intervall", "IntervalSeconds": "Gesunder Intervall",
"timeoutSeconds": "Timeout (Sek.)", "timeoutSeconds": "Timeout (Sek.)",
"timeIsInSeconds": "Zeit ist in Sekunden", "timeIsInSeconds": "Zeit ist in Sekunden",
"requireDeviceApproval": "Gerätegenehmigungen erforderlich", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Benutzer mit dieser Rolle benötigen neue Geräte, die von einem Administrator genehmigt wurden, bevor sie sich verbinden und auf Ressourcen zugreifen können.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Keine internen Ressourcen gefunden.", "resourcesTableNoInternalResourcesFound": "Keine internen Ressourcen gefunden.",
"resourcesTableDestination": "Ziel", "resourcesTableDestination": "Ziel",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias-Adresse",
"resourcesTableAliasAddressInfo": "Diese Adresse ist Teil des Utility-Subnetzes der Organisation. Sie wird verwendet, um Alias-Einträge mit interner DNS-Auflösung aufzulösen.",
"resourcesTableClients": "Clients", "resourcesTableClients": "Clients",
"resourcesTableAndOnlyAccessibleInternally": "und sind nur intern zugänglich, wenn mit einem Client verbunden.", "resourcesTableAndOnlyAccessibleInternally": "und sind nur intern zugänglich, wenn mit einem Client verbunden.",
"resourcesTableNoTargets": "Keine Ziele", "resourcesTableNoTargets": "Keine Ziele",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Wähle deinen Identitätsanbieter um fortzufahren", "orgAuthChooseIdpDescription": "Wähle deinen Identitätsanbieter um fortzufahren",
"orgAuthNoIdpConfigured": "Diese Organisation hat keine Identitätsanbieter konfiguriert. Sie können sich stattdessen mit Ihrer Pangolin-Identität anmelden.", "orgAuthNoIdpConfigured": "Diese Organisation hat keine Identitätsanbieter konfiguriert. Sie können sich stattdessen mit Ihrer Pangolin-Identität anmelden.",
"orgAuthSignInWithPangolin": "Mit Pangolin anmelden", "orgAuthSignInWithPangolin": "Mit Pangolin anmelden",
"orgAuthSignInToOrg": "Bei einer Organisation anmelden", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Organisations-Anmeldung", "orgAuthSelectOrgTitle": "Organisations-Anmeldung",
"orgAuthSelectOrgDescription": "Geben Sie Ihre Organisations-ID ein, um fortzufahren", "orgAuthSelectOrgDescription": "Geben Sie Ihre Organisations-ID ein, um fortzufahren",
"orgAuthOrgIdPlaceholder": "Ihre Organisation", "orgAuthOrgIdPlaceholder": "Ihre Organisation",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Code muss 9 Zeichen lang sein (z.B. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Code muss 9 Zeichen lang sein (z.B. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Ungültiger oder abgelaufener Code", "deviceCodeInvalidOrExpired": "Ungültiger oder abgelaufener Code",
"deviceCodeVerifyFailed": "Fehler beim Überprüfen des Gerätecodes", "deviceCodeVerifyFailed": "Fehler beim Überprüfen des Gerätecodes",
"deviceCodeValidating": "Überprüfe Gerätecode...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Geräteautorisierung wird überprüft...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Angemeldet als", "signedInAs": "Angemeldet als",
"deviceCodeEnterPrompt": "Geben Sie den auf dem Gerät angezeigten Code ein", "deviceCodeEnterPrompt": "Geben Sie den auf dem Gerät angezeigten Code ein",
"continue": "Weiter", "continue": "Weiter",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Nicht du? Verwenden Sie ein anderes Konto.", "deviceLoginUseDifferentAccount": "Nicht du? Verwenden Sie ein anderes Konto.",
"deviceLoginDeviceRequestingAccessToAccount": "Ein Gerät fordert Zugriff auf dieses Konto an.", "deviceLoginDeviceRequestingAccessToAccount": "Ein Gerät fordert Zugriff auf dieses Konto an.",
"loginSelectAuthenticationMethod": "Wählen Sie eine Authentifizierungsmethode aus, um fortzufahren.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Keine Daten", "noData": "Keine Daten",
"machineClients": "Maschinen-Clients", "machineClients": "Maschinen-Clients",
"install": "Installieren", "install": "Installieren",
@@ -2450,91 +2448,79 @@
"deviceArchiveConfirm": "Gerät archivieren", "deviceArchiveConfirm": "Gerät archivieren",
"archiveDevice": "Gerät archivieren", "archiveDevice": "Gerät archivieren",
"archive": "Archiv", "archive": "Archiv",
"deviceUnarchived": "Gerät nicht archiviert", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Das Gerät wurde erfolgreich deinstalliert.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Fehler beim Entarchivieren des Geräts", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Fehler beim Entfernen des Geräts", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Archivieren", "unarchive": "Unarchive",
"archiveClient": "Kunde archivieren", "archiveClient": "Archive Client",
"archiveClientQuestion": "Sind Sie sicher, dass Sie diesen Client archivieren möchten?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Der Client wird archiviert und aus der Liste Ihrer aktiven Clients entfernt.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Kunde archivieren", "archiveClientConfirm": "Archive Client",
"blockClient": "Klient sperren", "blockClient": "Block Client",
"blockClientQuestion": "Sind Sie sicher, dass Sie diesen Client blockieren möchten?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Das Gerät wird gezwungen, die Verbindung zu trennen, wenn es gerade verbunden ist. Sie können das Gerät später entsperren.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Klient sperren", "blockClientConfirm": "Block Client",
"active": "Aktiv", "active": "Active",
"usernameOrEmail": "Benutzername oder E-Mail", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Wählen Sie Ihre Organisation", "selectYourOrganization": "Select your organization",
"signInTo": "Einloggen in", "signInTo": "Log in in to",
"signInWithPassword": "Mit Passwort fortfahren", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Keine Authentifizierungsmethoden für diese Organisation verfügbar.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Geben Sie Ihr Passwort ein", "enterPassword": "Enter your password",
"enterMfaCode": "Geben Sie den Code aus Ihrer Authentifizierungs-App ein", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Bitte verwenden Sie Ihren Sicherheitsschlüssel zum Anmelden.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Benötigen Sie ein anderes Konto?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Indem Sie auf die Buttons unten klicken, bestätigen Sie, dass Sie gelesen haben, verstehen, und stimmen den <termsOfService>Nutzungsbedingungen</termsOfService> und <privacyPolicy>Datenschutzrichtlinien</privacyPolicy> zu.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Nutzungsbedingungen", "termsOfService": "Terms of Service",
"privacyPolicy": "Datenschutzerklärung", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Kein Benutzer mit diesem Benutzernamen gefunden.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Überprüfen", "verify": "Verify",
"signIn": "Anmelden", "signIn": "Sign In",
"forgotPassword": "Passwort vergessen?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Wenn Sie sich vorher angemeldet haben, können Sie Ihren Benutzernamen oder Ihre E-Mail-Adresse eingeben, um sich stattdessen beim Identifikationsprovider Ihrer Organisation zu authentifizieren. Es ist einfacher!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Trotzdem fortfahren", "continueAnyway": "Continue anyway",
"dontShowAgain": "Nicht mehr anzeigen", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Wussten Sie schon?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Versucht sich anzumelden?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Versuchen Sie, sich über den Identitätsanbieter Ihrer Organisation anzumelden?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Melden Sie sich an oder melden Sie sich stattdessen bei Ihrer Organisation an", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Anderes Konto verwenden", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Anmelden", "logIn": "Log In",
"deviceInformation": "Geräteinformationen", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informationen über das Gerät und den Agent", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Gerätesicherheit", "platform": "Platform",
"deviceSecurityDescription": "Informationen zur Gerätesicherheit", "macosVersion": "macOS Version",
"platform": "Plattform", "windowsVersion": "Windows Version",
"macosVersion": "macOS-Version", "iosVersion": "iOS Version",
"windowsVersion": "Windows-Version", "androidVersion": "Android Version",
"iosVersion": "iOS-Version", "osVersion": "OS Version",
"androidVersion": "Android-Version", "kernelVersion": "Kernel Version",
"osVersion": "OS-Version", "deviceModel": "Device Model",
"kernelVersion": "Kernel-Version", "serialNumber": "Serial Number",
"deviceModel": "Gerätemodell",
"serialNumber": "Seriennummer",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Erster Blick", "firstSeen": "First Seen",
"lastSeen": "Zuletzt gesehen", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometrie aktiviert", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Festplatte verschlüsselt", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Firewall aktiviert", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Automatische Updates aktiviert", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM verfügbar", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Schutz der Systemintegrität (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Firewall Stealth-Modus", "block": "Block",
"linuxAppArmorEnabled": "AppRüstung", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Geräteinformationen und -einstellungen anzeigen", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Dieses Gerät wartet auf Freigabe", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Dieses Gerät ist derzeit gesperrt. Es kann keine Verbindung zu anderen Ressourcen herstellen, es sei denn, es entsperrt.", "connected": "Connected",
"unblockClient": "Client entsperren", "disconnected": "Disconnected",
"unblockClientDescription": "Das Gerät wurde entsperrt", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Client dearchivieren", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Das Gerät wurde nicht archiviert", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Blockieren", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Entsperren", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Geräte-Aktionen", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Gerätestatus und Zugriff verwalten", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Dieses Gerät wartet auf Genehmigung. Es kann sich erst mit Ressourcen verbinden.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Verbunden",
"disconnected": "Verbindung getrennt",
"approvalsEmptyStateTitle": "Gerätezulassungen nicht aktiviert",
"approvalsEmptyStateDescription": "Aktiviere Gerätegenehmigungen für Rollen, um Administratorgenehmigungen zu benötigen, bevor Benutzer neue Geräte verbinden können.",
"approvalsEmptyStateStep1Title": "Gehe zu Rollen",
"approvalsEmptyStateStep1Description": "Navigieren Sie zu den Rolleneinstellungen Ihrer Organisation, um die Gerätefreigaben zu konfigurieren.",
"approvalsEmptyStateStep2Title": "Gerätegenehmigungen aktivieren",
"approvalsEmptyStateStep2Description": "Bearbeite eine Rolle und aktiviere die Option 'Gerätegenehmigung erforderlich'. Benutzer mit dieser Rolle benötigen Administrator-Genehmigung für neue Geräte.",
"approvalsEmptyStatePreviewDescription": "Vorschau: Wenn aktiviert, werden ausstehende Geräteanfragen hier zur Überprüfung angezeigt",
"approvalsEmptyStateButtonText": "Rollen verwalten"
} }
+11 -154
View File
@@ -56,9 +56,6 @@
"sitesBannerTitle": "Connect Any Network", "sitesBannerTitle": "Connect Any Network",
"sitesBannerDescription": "A site is a connection to a remote network that allows Pangolin to provide access to resources, whether public or private, to users anywhere. Install the site network connector (Newt) anywhere you can run a binary or container to establish the connection.", "sitesBannerDescription": "A site is a connection to a remote network that allows Pangolin to provide access to resources, whether public or private, to users anywhere. Install the site network connector (Newt) anywhere you can run a binary or container to establish the connection.",
"sitesBannerButtonText": "Install Site", "sitesBannerButtonText": "Install Site",
"approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Learn More",
"siteCreate": "Create Site", "siteCreate": "Create Site",
"siteCreateDescription2": "Follow the steps below to create and connect a new site", "siteCreateDescription2": "Follow the steps below to create and connect a new site",
"siteCreateDescription": "Create a new site to start connecting resources", "siteCreateDescription": "Create a new site to start connecting resources",
@@ -260,8 +257,6 @@
"accessRolesSearch": "Search roles...", "accessRolesSearch": "Search roles...",
"accessRolesAdd": "Add Role", "accessRolesAdd": "Add Role",
"accessRoleDelete": "Delete Role", "accessRoleDelete": "Delete Role",
"accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Description", "description": "Description",
"inviteTitle": "Open Invitations", "inviteTitle": "Open Invitations",
"inviteDescription": "Manage invitations for other users to join the organization", "inviteDescription": "Manage invitations for other users to join the organization",
@@ -455,18 +450,6 @@
"selectDuration": "Select duration", "selectDuration": "Select duration",
"selectResource": "Select Resource", "selectResource": "Select Resource",
"filterByResource": "Filter By Resource", "filterByResource": "Filter By Resource",
"selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "No approvals",
"approvalState": "Approval State",
"approve": "Approve",
"approved": "Approved",
"denied": "Denied",
"deniedApproval": "Denied Approval",
"all": "All",
"deny": "Deny",
"viewDetails": "View Details",
"requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Reset Filters", "resetFilters": "Reset Filters",
"totalBlocked": "Requests Blocked By Pangolin", "totalBlocked": "Requests Blocked By Pangolin",
"totalRequests": "Total Requests", "totalRequests": "Total Requests",
@@ -746,28 +729,16 @@
"countries": "Countries", "countries": "Countries",
"accessRoleCreate": "Create Role", "accessRoleCreate": "Create Role",
"accessRoleCreateDescription": "Create a new role to group users and manage their permissions.", "accessRoleCreateDescription": "Create a new role to group users and manage their permissions.",
"accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Create Role", "accessRoleCreateSubmit": "Create Role",
"accessRoleCreated": "Role created", "accessRoleCreated": "Role created",
"accessRoleCreatedDescription": "The role has been successfully created.", "accessRoleCreatedDescription": "The role has been successfully created.",
"accessRoleErrorCreate": "Failed to create role", "accessRoleErrorCreate": "Failed to create role",
"accessRoleErrorCreateDescription": "An error occurred while creating the role.", "accessRoleErrorCreateDescription": "An error occurred while creating the role.",
"accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "New role is required", "accessRoleErrorNewRequired": "New role is required",
"accessRoleErrorRemove": "Failed to remove role", "accessRoleErrorRemove": "Failed to remove role",
"accessRoleErrorRemoveDescription": "An error occurred while removing the role.", "accessRoleErrorRemoveDescription": "An error occurred while removing the role.",
"accessRoleName": "Role Name", "accessRoleName": "Role Name",
"accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.", "accessRoleQuestionRemove": "You're about to delete the {name} role. You cannot undo this action.",
"accessRoleRemove": "Remove Role", "accessRoleRemove": "Remove Role",
"accessRoleRemoveDescription": "Remove a role from the organization", "accessRoleRemoveDescription": "Remove a role from the organization",
"accessRoleRemoveSubmit": "Remove Role", "accessRoleRemoveSubmit": "Remove Role",
@@ -903,7 +874,7 @@
"inviteAlready": "Looks like you've been invited!", "inviteAlready": "Looks like you've been invited!",
"inviteAlreadyDescription": "To accept the invite, you must log in or create an account.", "inviteAlreadyDescription": "To accept the invite, you must log in or create an account.",
"signupQuestion": "Already have an account?", "signupQuestion": "Already have an account?",
"login": "Log In", "login": "Log in",
"resourceNotFound": "Resource Not Found", "resourceNotFound": "Resource Not Found",
"resourceNotFoundDescription": "The resource you're trying to access does not exist.", "resourceNotFoundDescription": "The resource you're trying to access does not exist.",
"pincodeRequirementsLength": "PIN must be exactly 6 digits", "pincodeRequirementsLength": "PIN must be exactly 6 digits",
@@ -983,13 +954,13 @@
"passwordExpiryDescription": "This organization requires you to change your password every {maxDays} days.", "passwordExpiryDescription": "This organization requires you to change your password every {maxDays} days.",
"changePasswordNow": "Change Password Now", "changePasswordNow": "Change Password Now",
"pincodeAuth": "Authenticator Code", "pincodeAuth": "Authenticator Code",
"pincodeSubmit2": "Submit code", "pincodeSubmit2": "Submit Code",
"passwordResetSubmit": "Request Reset", "passwordResetSubmit": "Request Reset",
"passwordResetAlreadyHaveCode": "Enter Code", "passwordResetAlreadyHaveCode": "Enter Code",
"passwordResetSmtpRequired": "Please contact your administrator", "passwordResetSmtpRequired": "Please contact your administrator",
"passwordResetSmtpRequiredDescription": "A password reset code is required to reset your password. Please contact your administrator for assistance.", "passwordResetSmtpRequiredDescription": "A password reset code is required to reset your password. Please contact your administrator for assistance.",
"passwordBack": "Back to Password", "passwordBack": "Back to Password",
"loginBack": "Go back to main login page", "loginBack": "Go back to log in",
"signup": "Sign up", "signup": "Sign up",
"loginStart": "Log in to get started", "loginStart": "Log in to get started",
"idpOidcTokenValidating": "Validating OIDC token", "idpOidcTokenValidating": "Validating OIDC token",
@@ -1147,10 +1118,6 @@
"actionUpdateIdpOrg": "Update IDP Org", "actionUpdateIdpOrg": "Update IDP Org",
"actionCreateClient": "Create Client", "actionCreateClient": "Create Client",
"actionDeleteClient": "Delete Client", "actionDeleteClient": "Delete Client",
"actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Block Client",
"actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Update Client", "actionUpdateClient": "Update Client",
"actionListClients": "List Clients", "actionListClients": "List Clients",
"actionGetClient": "Get Client", "actionGetClient": "Get Client",
@@ -1167,14 +1134,14 @@
"searchProgress": "Search...", "searchProgress": "Search...",
"create": "Create", "create": "Create",
"orgs": "Organizations", "orgs": "Organizations",
"loginError": "An unexpected error occurred. Please try again.", "loginError": "An error occurred while logging in",
"loginRequiredForDevice": "Login is required for your device.", "loginRequiredForDevice": "Login is required to authenticate your device.",
"passwordForgot": "Forgot your password?", "passwordForgot": "Forgot your password?",
"otpAuth": "Two-Factor Authentication", "otpAuth": "Two-Factor Authentication",
"otpAuthDescription": "Enter the code from your authenticator app or one of your single-use backup codes.", "otpAuthDescription": "Enter the code from your authenticator app or one of your single-use backup codes.",
"otpAuthSubmit": "Submit Code", "otpAuthSubmit": "Submit Code",
"idpContinue": "Or continue with", "idpContinue": "Or continue with",
"otpAuthBack": "Back to Password", "otpAuthBack": "Back to Log In",
"navbar": "Navigation Menu", "navbar": "Navigation Menu",
"navbarDescription": "Main navigation menu for the application", "navbarDescription": "Main navigation menu for the application",
"navbarDocsLink": "Documentation", "navbarDocsLink": "Documentation",
@@ -1222,7 +1189,6 @@
"sidebarOverview": "Overview", "sidebarOverview": "Overview",
"sidebarHome": "Home", "sidebarHome": "Home",
"sidebarSites": "Sites", "sidebarSites": "Sites",
"sidebarApprovals": "Approval Requests",
"sidebarResources": "Resources", "sidebarResources": "Resources",
"sidebarProxyResources": "Public", "sidebarProxyResources": "Public",
"sidebarClientResources": "Private", "sidebarClientResources": "Private",
@@ -1239,7 +1205,7 @@
"sidebarIdentityProviders": "Identity Providers", "sidebarIdentityProviders": "Identity Providers",
"sidebarLicense": "License", "sidebarLicense": "License",
"sidebarClients": "Clients", "sidebarClients": "Clients",
"sidebarUserDevices": "User Devices", "sidebarUserDevices": "Users",
"sidebarMachineClients": "Machines", "sidebarMachineClients": "Machines",
"sidebarDomains": "Domains", "sidebarDomains": "Domains",
"sidebarGeneral": "Manage", "sidebarGeneral": "Manage",
@@ -1311,7 +1277,6 @@
"setupErrorCreateAdmin": "An error occurred while creating the server admin account.", "setupErrorCreateAdmin": "An error occurred while creating the server admin account.",
"certificateStatus": "Certificate Status", "certificateStatus": "Certificate Status",
"loading": "Loading", "loading": "Loading",
"loadingAnalytics": "Loading Analytics",
"restart": "Restart", "restart": "Restart",
"domains": "Domains", "domains": "Domains",
"domainsDescription": "Create and manage domains available in the organization", "domainsDescription": "Create and manage domains available in the organization",
@@ -1339,7 +1304,6 @@
"refreshError": "Failed to refresh data", "refreshError": "Failed to refresh data",
"verified": "Verified", "verified": "Verified",
"pending": "Pending", "pending": "Pending",
"pendingApproval": "Pending Approval",
"sidebarBilling": "Billing", "sidebarBilling": "Billing",
"billing": "Billing", "billing": "Billing",
"orgBillingDescription": "Manage billing information and subscriptions", "orgBillingDescription": "Manage billing information and subscriptions",
@@ -1456,7 +1420,7 @@
"securityKeyRemoveSuccess": "Security key removed successfully", "securityKeyRemoveSuccess": "Security key removed successfully",
"securityKeyRemoveError": "Failed to remove security key", "securityKeyRemoveError": "Failed to remove security key",
"securityKeyLoadError": "Failed to load security keys", "securityKeyLoadError": "Failed to load security keys",
"securityKeyLogin": "Use Security Key", "securityKeyLogin": "Continue with security key",
"securityKeyAuthError": "Failed to authenticate with security key", "securityKeyAuthError": "Failed to authenticate with security key",
"securityKeyRecommendation": "Register a backup security key on another device to ensure you always have access to your account.", "securityKeyRecommendation": "Register a backup security key on another device to ensure you always have access to your account.",
"registering": "Registering...", "registering": "Registering...",
@@ -1583,8 +1547,6 @@
"IntervalSeconds": "Healthy Interval", "IntervalSeconds": "Healthy Interval",
"timeoutSeconds": "Timeout (sec)", "timeoutSeconds": "Timeout (sec)",
"timeIsInSeconds": "Time is in seconds", "timeIsInSeconds": "Time is in seconds",
"requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"retryAttempts": "Retry Attempts", "retryAttempts": "Retry Attempts",
"expectedResponseCodes": "Expected Response Codes", "expectedResponseCodes": "Expected Response Codes",
"expectedResponseCodesDescription": "HTTP status code that indicates healthy status. If left blank, 200-300 is considered healthy.", "expectedResponseCodesDescription": "HTTP status code that indicates healthy status. If left blank, 200-300 is considered healthy.",
@@ -1625,8 +1587,6 @@
"resourcesTableNoInternalResourcesFound": "No internal resources found.", "resourcesTableNoInternalResourcesFound": "No internal resources found.",
"resourcesTableDestination": "Destination", "resourcesTableDestination": "Destination",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias Address",
"resourcesTableAliasAddressInfo": "This address is part of the organization's utility subnet. It's used to resolve alias records using internal DNS resolution.",
"resourcesTableClients": "Clients", "resourcesTableClients": "Clients",
"resourcesTableAndOnlyAccessibleInternally": "and are only accessible internally when connected with a client.", "resourcesTableAndOnlyAccessibleInternally": "and are only accessible internally when connected with a client.",
"resourcesTableNoTargets": "No targets", "resourcesTableNoTargets": "No targets",
@@ -2272,8 +2232,6 @@
"deviceCodeInvalidFormat": "Code must be 9 characters (e.g., A1AJ-N5JD)", "deviceCodeInvalidFormat": "Code must be 9 characters (e.g., A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Invalid or expired code", "deviceCodeInvalidOrExpired": "Invalid or expired code",
"deviceCodeVerifyFailed": "Failed to verify device code", "deviceCodeVerifyFailed": "Failed to verify device code",
"deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Signed in as", "signedInAs": "Signed in as",
"deviceCodeEnterPrompt": "Enter the code displayed on the device", "deviceCodeEnterPrompt": "Enter the code displayed on the device",
"continue": "Continue", "continue": "Continue",
@@ -2286,7 +2244,7 @@
"deviceOrganizationsAccess": "Access to all organizations your account has access to", "deviceOrganizationsAccess": "Access to all organizations your account has access to",
"deviceAuthorize": "Authorize {applicationName}", "deviceAuthorize": "Authorize {applicationName}",
"deviceConnected": "Device Connected!", "deviceConnected": "Device Connected!",
"deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.", "deviceAuthorizedMessage": "Device is authorized to access your account.",
"pangolinCloud": "Pangolin Cloud", "pangolinCloud": "Pangolin Cloud",
"viewDevices": "View Devices", "viewDevices": "View Devices",
"viewDevicesDescription": "Manage your connected devices", "viewDevicesDescription": "Manage your connected devices",
@@ -2348,7 +2306,6 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Not you? Use a different account.", "deviceLoginUseDifferentAccount": "Not you? Use a different account.",
"deviceLoginDeviceRequestingAccessToAccount": "A device is requesting access to this account.", "deviceLoginDeviceRequestingAccessToAccount": "A device is requesting access to this account.",
"loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "No Data", "noData": "No Data",
"machineClients": "Machine Clients", "machineClients": "Machine Clients",
"install": "Install", "install": "Install",
@@ -2437,105 +2394,5 @@
"maintenanceScreenTitle": "Service Temporarily Unavailable", "maintenanceScreenTitle": "Service Temporarily Unavailable",
"maintenanceScreenMessage": "We are currently experiencing technical difficulties. Please check back soon.", "maintenanceScreenMessage": "We are currently experiencing technical difficulties. Please check back soon.",
"maintenanceScreenEstimatedCompletion": "Estimated Completion:", "maintenanceScreenEstimatedCompletion": "Estimated Completion:",
"createInternalResourceDialogDestinationRequired": "Destination is required", "createInternalResourceDialogDestinationRequired": "Destination is required"
"available": "Available",
"archived": "Archived",
"noArchivedDevices": "No archived devices found",
"deviceArchived": "Device archived",
"deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Archive Device",
"archive": "Archive",
"deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Unarchive",
"archiveClient": "Archive Client",
"archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Archive Client",
"blockClient": "Block Client",
"blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Block Client",
"active": "Active",
"usernameOrEmail": "Username or Email",
"selectYourOrganization": "Select your organization",
"signInTo": "Log in in to",
"signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Enter your password",
"enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Terms of Service",
"privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "No user found with that username.",
"verify": "Verify",
"signIn": "Sign In",
"forgotPassword": "Forgot password?",
"orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Continue anyway",
"dontShowAgain": "Don't show again",
"orgSignInNotice": "Did you know?",
"signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Log In",
"deviceInformation": "Device Information",
"deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Device Security",
"deviceSecurityDescription": "Device security posture information",
"platform": "Platform",
"macosVersion": "macOS Version",
"windowsVersion": "Windows Version",
"iosVersion": "iOS Version",
"androidVersion": "Android Version",
"osVersion": "OS Version",
"kernelVersion": "Kernel Version",
"deviceModel": "Device Model",
"serialNumber": "Serial Number",
"hostname": "Hostname",
"firstSeen": "First Seen",
"lastSeen": "Last Seen",
"biometricsEnabled": "Biometrics Enabled",
"diskEncrypted": "Disk Encrypted",
"firewallEnabled": "Firewall Enabled",
"autoUpdatesEnabled": "Auto Updates Enabled",
"tpmAvailable": "TPM Available",
"windowsAntivirusEnabled": "Antivirus Enabled",
"macosSipEnabled": "System Integrity Protection (SIP)",
"macosGatekeeperEnabled": "Gatekeeper",
"macosFirewallStealthMode": "Firewall Stealth Mode",
"linuxAppArmorEnabled": "AppArmor",
"linuxSELinuxEnabled": "SELinux",
"deviceSettingsDescription": "View device information and settings",
"devicePendingApprovalDescription": "This device is waiting for approval",
"deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"unblockClient": "Unblock Client",
"unblockClientDescription": "The device has been unblocked",
"unarchiveClient": "Unarchive Client",
"unarchiveClientDescription": "The device has been unarchived",
"block": "Block",
"unblock": "Unblock",
"deviceActions": "Device Actions",
"deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"connected": "Connected",
"disconnected": "Disconnected",
"approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"approvalsEmptyStateStep1Title": "Go to Roles",
"approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"approvalsEmptyStateStep2Title": "Enable Device Approvals",
"approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"approvalsEmptyStateButtonText": "Manage Roles"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Conectar cualquier red", "sitesBannerTitle": "Conectar cualquier red",
"sitesBannerDescription": "Un sitio es una conexión a una red remota que permite a Pangolin proporcionar acceso a recursos, públicos o privados, a usuarios en cualquier lugar. Instale el conector de red del sitio (Newt) en cualquier lugar donde pueda ejecutar un binario o contenedor para establecer la conexión.", "sitesBannerDescription": "Un sitio es una conexión a una red remota que permite a Pangolin proporcionar acceso a recursos, públicos o privados, a usuarios en cualquier lugar. Instale el conector de red del sitio (Newt) en cualquier lugar donde pueda ejecutar un binario o contenedor para establecer la conexión.",
"sitesBannerButtonText": "Instalar sitio", "sitesBannerButtonText": "Instalar sitio",
"approvalsBannerTitle": "Aprobar o denegar el acceso al dispositivo", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Revisar y aprobar o denegar las solicitudes de acceso al dispositivo de los usuarios. Cuando se requieren aprobaciones de dispositivos, los usuarios deben obtener la aprobación del administrador antes de que sus dispositivos puedan conectarse a los recursos de su organización.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Saber más", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Crear sitio", "siteCreate": "Crear sitio",
"siteCreateDescription2": "Siga los pasos siguientes para crear y conectar un nuevo sitio", "siteCreateDescription2": "Siga los pasos siguientes para crear y conectar un nuevo sitio",
"siteCreateDescription": "Crear un nuevo sitio para empezar a conectar recursos", "siteCreateDescription": "Crear un nuevo sitio para empezar a conectar recursos",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Buscar roles...", "accessRolesSearch": "Buscar roles...",
"accessRolesAdd": "Añadir rol", "accessRolesAdd": "Añadir rol",
"accessRoleDelete": "Eliminar rol", "accessRoleDelete": "Eliminar rol",
"accessApprovalsManage": "Administrar aprobaciones", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Ver y administrar aprobaciones pendientes para el acceso a esta organización", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Descripción", "description": "Descripción",
"inviteTitle": "Invitaciones abiertas", "inviteTitle": "Invitaciones abiertas",
"inviteDescription": "Administrar invitaciones para que otros usuarios se unan a la organización", "inviteDescription": "Administrar invitaciones para que otros usuarios se unan a la organización",
@@ -455,18 +455,18 @@
"selectDuration": "Seleccionar duración", "selectDuration": "Seleccionar duración",
"selectResource": "Seleccionar Recurso", "selectResource": "Seleccionar Recurso",
"filterByResource": "Filtrar por Recurso", "filterByResource": "Filtrar por Recurso",
"selectApprovalState": "Seleccionar Estado de Aprobación", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtrar por estado de aprobación", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "No hay aprobaciones", "approvalListEmpty": "No approvals",
"approvalState": "Estado de aprobación", "approvalState": "Approval State",
"approve": "Aprobar", "approve": "Approve",
"approved": "Aprobado", "approved": "Approved",
"denied": "Denegado", "denied": "Denied",
"deniedApproval": "Aprobación denegada", "deniedApproval": "Denied Approval",
"all": "Todo", "all": "All",
"deny": "Denegar", "deny": "Deny",
"viewDetails": "Ver detalles", "viewDetails": "View Details",
"requestingNewDeviceApproval": "solicitó un nuevo dispositivo", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Reiniciar filtros", "resetFilters": "Reiniciar filtros",
"totalBlocked": "Solicitudes bloqueadas por Pangolin", "totalBlocked": "Solicitudes bloqueadas por Pangolin",
"totalRequests": "Solicitudes totales", "totalRequests": "Solicitudes totales",
@@ -746,28 +746,28 @@
"countries": "Países", "countries": "Países",
"accessRoleCreate": "Crear rol", "accessRoleCreate": "Crear rol",
"accessRoleCreateDescription": "Crear un nuevo rol para agrupar usuarios y administrar sus permisos.", "accessRoleCreateDescription": "Crear un nuevo rol para agrupar usuarios y administrar sus permisos.",
"accessRoleEdit": "Editar rol", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Editar información de rol.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Crear rol", "accessRoleCreateSubmit": "Crear rol",
"accessRoleCreated": "Rol creado", "accessRoleCreated": "Rol creado",
"accessRoleCreatedDescription": "El rol se ha creado correctamente.", "accessRoleCreatedDescription": "El rol se ha creado correctamente.",
"accessRoleErrorCreate": "Error al crear el rol", "accessRoleErrorCreate": "Error al crear el rol",
"accessRoleErrorCreateDescription": "Se ha producido un error al crear el rol.", "accessRoleErrorCreateDescription": "Se ha producido un error al crear el rol.",
"accessRoleUpdateSubmit": "Actualizar rol", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rol actualizado", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "El rol se ha actualizado correctamente.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Aprobación procesada", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Establezca la decisión de Solicitud de Aprobación a aprobar.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Define la decisión de Solicitud de Aprobación a denegar.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Error al actualizar el rol", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Se ha producido un error al actualizar el rol.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Error al procesar la aprobación", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Se ha producido un error al procesar la aprobación.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Se requiere un nuevo rol", "accessRoleErrorNewRequired": "Se requiere un nuevo rol",
"accessRoleErrorRemove": "Error al eliminar el rol", "accessRoleErrorRemove": "Error al eliminar el rol",
"accessRoleErrorRemoveDescription": "Ocurrió un error mientras se eliminaba el rol.", "accessRoleErrorRemoveDescription": "Ocurrió un error mientras se eliminaba el rol.",
"accessRoleName": "Nombre del Rol", "accessRoleName": "Nombre del Rol",
"accessRoleQuestionRemove": "Estás a punto de eliminar el rol `{name}`. No puedes deshacer esta acción.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Quitar rol", "accessRoleRemove": "Quitar rol",
"accessRoleRemoveDescription": "Eliminar un rol de la organización", "accessRoleRemoveDescription": "Eliminar un rol de la organización",
"accessRoleRemoveSubmit": "Quitar rol", "accessRoleRemoveSubmit": "Quitar rol",
@@ -903,7 +903,7 @@
"inviteAlready": "¡Parece que has sido invitado!", "inviteAlready": "¡Parece que has sido invitado!",
"inviteAlreadyDescription": "Para aceptar la invitación, debes iniciar sesión o crear una cuenta.", "inviteAlreadyDescription": "Para aceptar la invitación, debes iniciar sesión o crear una cuenta.",
"signupQuestion": "¿Ya tienes una cuenta?", "signupQuestion": "¿Ya tienes una cuenta?",
"login": "Iniciar sesión", "login": "Log In",
"resourceNotFound": "Recurso no encontrado", "resourceNotFound": "Recurso no encontrado",
"resourceNotFoundDescription": "El recurso al que intentas acceder no existe.", "resourceNotFoundDescription": "El recurso al que intentas acceder no existe.",
"pincodeRequirementsLength": "El PIN debe tener exactamente 6 dígitos", "pincodeRequirementsLength": "El PIN debe tener exactamente 6 dígitos",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Esta organización requiere que cambies tu contraseña cada {maxDays} días.", "passwordExpiryDescription": "Esta organización requiere que cambies tu contraseña cada {maxDays} días.",
"changePasswordNow": "Cambiar Contraseña Ahora", "changePasswordNow": "Cambiar Contraseña Ahora",
"pincodeAuth": "Código de autenticación", "pincodeAuth": "Código de autenticación",
"pincodeSubmit2": "Enviar código", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Reiniciar Solicitud", "passwordResetSubmit": "Reiniciar Solicitud",
"passwordResetAlreadyHaveCode": "Ingresar código", "passwordResetAlreadyHaveCode": "Ingresar código",
"passwordResetSmtpRequired": "Póngase en contacto con su administrador", "passwordResetSmtpRequired": "Póngase en contacto con su administrador",
"passwordResetSmtpRequiredDescription": "Se requiere un código de restablecimiento de contraseña para restablecer su contraseña. Póngase en contacto con su administrador para obtener asistencia.", "passwordResetSmtpRequiredDescription": "Se requiere un código de restablecimiento de contraseña para restablecer su contraseña. Póngase en contacto con su administrador para obtener asistencia.",
"passwordBack": "Volver a la contraseña", "passwordBack": "Volver a la contraseña",
"loginBack": "Volver a la página principal de acceso", "loginBack": "Go back to main login page",
"signup": "Regístrate", "signup": "Regístrate",
"loginStart": "Inicia sesión para empezar", "loginStart": "Inicia sesión para empezar",
"idpOidcTokenValidating": "Validando token OIDC", "idpOidcTokenValidating": "Validando token OIDC",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Actualizar IDP Org", "actionUpdateIdpOrg": "Actualizar IDP Org",
"actionCreateClient": "Crear cliente", "actionCreateClient": "Crear cliente",
"actionDeleteClient": "Eliminar cliente", "actionDeleteClient": "Eliminar cliente",
"actionArchiveClient": "Archivar cliente", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Desarchivar cliente", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Bloquear cliente", "actionBlockClient": "Block Client",
"actionUnblockClient": "Desbloquear cliente", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Actualizar cliente", "actionUpdateClient": "Actualizar cliente",
"actionListClients": "Listar clientes", "actionListClients": "Listar clientes",
"actionGetClient": "Obtener cliente", "actionGetClient": "Obtener cliente",
@@ -1167,14 +1167,14 @@
"searchProgress": "Buscar...", "searchProgress": "Buscar...",
"create": "Crear", "create": "Crear",
"orgs": "Organizaciones", "orgs": "Organizaciones",
"loginError": "Ocurrió un error inesperado. Por favor, inténtelo de nuevo.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Es necesario iniciar sesión para tu dispositivo.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "¿Olvidaste tu contraseña?", "passwordForgot": "¿Olvidaste tu contraseña?",
"otpAuth": "Autenticación de dos factores", "otpAuth": "Autenticación de dos factores",
"otpAuthDescription": "Introduzca el código de su aplicación de autenticación o uno de sus códigos de copia de seguridad de un solo uso.", "otpAuthDescription": "Introduzca el código de su aplicación de autenticación o uno de sus códigos de copia de seguridad de un solo uso.",
"otpAuthSubmit": "Enviar código", "otpAuthSubmit": "Enviar código",
"idpContinue": "O continuar con", "idpContinue": "O continuar con",
"otpAuthBack": "Volver a la contraseña", "otpAuthBack": "Back to Password",
"navbar": "Menú de navegación", "navbar": "Menú de navegación",
"navbarDescription": "Menú de navegación principal para la aplicación", "navbarDescription": "Menú de navegación principal para la aplicación",
"navbarDocsLink": "Documentación", "navbarDocsLink": "Documentación",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Resumen", "sidebarOverview": "Resumen",
"sidebarHome": "Inicio", "sidebarHome": "Inicio",
"sidebarSites": "Sitios", "sidebarSites": "Sitios",
"sidebarApprovals": "Solicitudes de aprobación", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Recursos", "sidebarResources": "Recursos",
"sidebarProxyResources": "Público", "sidebarProxyResources": "Público",
"sidebarClientResources": "Privado", "sidebarClientResources": "Privado",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Proveedores de identidad", "sidebarIdentityProviders": "Proveedores de identidad",
"sidebarLicense": "Licencia", "sidebarLicense": "Licencia",
"sidebarClients": "Clientes", "sidebarClients": "Clientes",
"sidebarUserDevices": "Dispositivos de usuario", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Máquinas", "sidebarMachineClients": "Máquinas",
"sidebarDomains": "Dominios", "sidebarDomains": "Dominios",
"sidebarGeneral": "Gestionar", "sidebarGeneral": "Gestionar",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Se produjo un error al crear la cuenta de administrador del servidor.", "setupErrorCreateAdmin": "Se produjo un error al crear la cuenta de administrador del servidor.",
"certificateStatus": "Estado del certificado", "certificateStatus": "Estado del certificado",
"loading": "Cargando", "loading": "Cargando",
"loadingAnalytics": "Cargando analíticas", "loadingAnalytics": "Loading Analytics",
"restart": "Reiniciar", "restart": "Reiniciar",
"domains": "Dominios", "domains": "Dominios",
"domainsDescription": "Crear y administrar dominios disponibles en la organización", "domainsDescription": "Crear y administrar dominios disponibles en la organización",
@@ -1339,7 +1339,7 @@
"refreshError": "Error al actualizar datos", "refreshError": "Error al actualizar datos",
"verified": "Verificado", "verified": "Verificado",
"pending": "Pendiente", "pending": "Pendiente",
"pendingApproval": "Pendientes de aprobación", "pendingApproval": "Pending Approval",
"sidebarBilling": "Facturación", "sidebarBilling": "Facturación",
"billing": "Facturación", "billing": "Facturación",
"orgBillingDescription": "Administrar información de facturación y suscripciones", "orgBillingDescription": "Administrar información de facturación y suscripciones",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Llave de seguridad eliminada exitosamente", "securityKeyRemoveSuccess": "Llave de seguridad eliminada exitosamente",
"securityKeyRemoveError": "Error al eliminar la llave de seguridad", "securityKeyRemoveError": "Error al eliminar la llave de seguridad",
"securityKeyLoadError": "Error al cargar las llaves de seguridad", "securityKeyLoadError": "Error al cargar las llaves de seguridad",
"securityKeyLogin": "Usar clave de seguridad", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Error al autenticar con llave de seguridad", "securityKeyAuthError": "Error al autenticar con llave de seguridad",
"securityKeyRecommendation": "Considere registrar otra llave de seguridad en un dispositivo diferente para asegurarse de no quedar bloqueado de su cuenta.", "securityKeyRecommendation": "Considere registrar otra llave de seguridad en un dispositivo diferente para asegurarse de no quedar bloqueado de su cuenta.",
"registering": "Registrando...", "registering": "Registrando...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Intervalo Saludable", "IntervalSeconds": "Intervalo Saludable",
"timeoutSeconds": "Tiempo agotado (seg)", "timeoutSeconds": "Tiempo agotado (seg)",
"timeIsInSeconds": "El tiempo está en segundos", "timeIsInSeconds": "El tiempo está en segundos",
"requireDeviceApproval": "Requiere aprobaciones del dispositivo", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Los usuarios con este rol necesitan nuevos dispositivos aprobados por un administrador antes de poder conectarse y acceder a los recursos.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos internos.", "resourcesTableNoInternalResourcesFound": "No se encontraron recursos internos.",
"resourcesTableDestination": "Destino", "resourcesTableDestination": "Destino",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Dirección del alias",
"resourcesTableAliasAddressInfo": "Esta dirección es parte de la subred de utilidad de la organización. Se utiliza para resolver registros de alias usando resolución DNS interna.",
"resourcesTableClients": "Clientes", "resourcesTableClients": "Clientes",
"resourcesTableAndOnlyAccessibleInternally": "y solo son accesibles internamente cuando se conectan con un cliente.", "resourcesTableAndOnlyAccessibleInternally": "y solo son accesibles internamente cuando se conectan con un cliente.",
"resourcesTableNoTargets": "Sin objetivos", "resourcesTableNoTargets": "Sin objetivos",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Elige tu proveedor de identidad para continuar", "orgAuthChooseIdpDescription": "Elige tu proveedor de identidad para continuar",
"orgAuthNoIdpConfigured": "Esta organización no tiene ningún proveedor de identidad configurado. En su lugar puedes iniciar sesión con tu identidad de Pangolin.", "orgAuthNoIdpConfigured": "Esta organización no tiene ningún proveedor de identidad configurado. En su lugar puedes iniciar sesión con tu identidad de Pangolin.",
"orgAuthSignInWithPangolin": "Iniciar sesión con Pangolin", "orgAuthSignInWithPangolin": "Iniciar sesión con Pangolin",
"orgAuthSignInToOrg": "Iniciar sesión en una organización", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Inicio de sesión de organización", "orgAuthSelectOrgTitle": "Inicio de sesión de organización",
"orgAuthSelectOrgDescription": "Ingrese el ID de su organización para continuar", "orgAuthSelectOrgDescription": "Ingrese el ID de su organización para continuar",
"orgAuthOrgIdPlaceholder": "tu-organización", "orgAuthOrgIdPlaceholder": "tu-organización",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "El código debe tener 9 caracteres (por ejemplo, A1AJ-N5JD)", "deviceCodeInvalidFormat": "El código debe tener 9 caracteres (por ejemplo, A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Código no válido o caducado", "deviceCodeInvalidOrExpired": "Código no válido o caducado",
"deviceCodeVerifyFailed": "Error al verificar el código del dispositivo", "deviceCodeVerifyFailed": "Error al verificar el código del dispositivo",
"deviceCodeValidating": "Validando código de dispositivo...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Verificando autorización del dispositivo...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Conectado como", "signedInAs": "Conectado como",
"deviceCodeEnterPrompt": "Introduzca el código mostrado en el dispositivo", "deviceCodeEnterPrompt": "Introduzca el código mostrado en el dispositivo",
"continue": "Continuar", "continue": "Continuar",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Acceso a todas las organizaciones a las que su cuenta tiene acceso", "deviceOrganizationsAccess": "Acceso a todas las organizaciones a las que su cuenta tiene acceso",
"deviceAuthorize": "Autorizar a {applicationName}", "deviceAuthorize": "Autorizar a {applicationName}",
"deviceConnected": "¡Dispositivo conectado!", "deviceConnected": "¡Dispositivo conectado!",
"deviceAuthorizedMessage": "El dispositivo está autorizado para acceder a su cuenta. Por favor, vuelva a la aplicación cliente.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Nube de Pangolin", "pangolinCloud": "Nube de Pangolin",
"viewDevices": "Ver dispositivos", "viewDevices": "Ver dispositivos",
"viewDevicesDescription": "Administra tus dispositivos conectados", "viewDevicesDescription": "Administra tus dispositivos conectados",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "¿No tú? Utilice una cuenta diferente.", "deviceLoginUseDifferentAccount": "¿No tú? Utilice una cuenta diferente.",
"deviceLoginDeviceRequestingAccessToAccount": "Un dispositivo está solicitando acceso a esta cuenta.", "deviceLoginDeviceRequestingAccessToAccount": "Un dispositivo está solicitando acceso a esta cuenta.",
"loginSelectAuthenticationMethod": "Seleccione un método de autenticación para continuar.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Sin datos", "noData": "Sin datos",
"machineClients": "Clientes de la máquina", "machineClients": "Clientes de la máquina",
"install": "Instalar", "install": "Instalar",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Actualmente estamos experimentando dificultades técnicas. Por favor regrese pronto.", "maintenanceScreenMessage": "Actualmente estamos experimentando dificultades técnicas. Por favor regrese pronto.",
"maintenanceScreenEstimatedCompletion": "Estimado completado:", "maintenanceScreenEstimatedCompletion": "Estimado completado:",
"createInternalResourceDialogDestinationRequired": "Se requiere destino", "createInternalResourceDialogDestinationRequired": "Se requiere destino",
"available": "Disponible", "available": "Available",
"archived": "Archivado", "archived": "Archived",
"noArchivedDevices": "No se encontraron dispositivos archivados", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Dispositivo archivado", "deviceArchived": "Device archived",
"deviceArchivedDescription": "El dispositivo se ha archivado correctamente.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Error al archivar dispositivo", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Error al archivar el dispositivo", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "¿Está seguro que desea archivar este dispositivo?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "El dispositivo será archivado y eliminado de su lista de dispositivos activos.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Archivar dispositivo", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Archivar dispositivo", "archiveDevice": "Archive Device",
"archive": "Archivar", "archive": "Archive",
"deviceUnarchived": "Dispositivo desarchivado", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "El dispositivo se ha desarchivado correctamente.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Error al desarchivar dispositivo", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Error al desarchivar el dispositivo", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Desarchivar", "unarchive": "Unarchive",
"archiveClient": "Archivar cliente", "archiveClient": "Archive Client",
"archiveClientQuestion": "¿Está seguro que desea archivar este cliente?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "El cliente será archivado y eliminado de su lista de clientes activos.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Archivar cliente", "archiveClientConfirm": "Archive Client",
"blockClient": "Bloquear cliente", "blockClient": "Block Client",
"blockClientQuestion": "¿Estás seguro de que quieres bloquear a este cliente?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "El dispositivo será forzado a desconectarse si está conectado actualmente. Puede desbloquear el dispositivo más tarde.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Bloquear cliente", "blockClientConfirm": "Block Client",
"active": "Activo", "active": "Active",
"usernameOrEmail": "Nombre de usuario o email", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Seleccione su organización", "selectYourOrganization": "Select your organization",
"signInTo": "Iniciar sesión en", "signInTo": "Log in in to",
"signInWithPassword": "Continuar con la contraseña", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "No hay métodos de autenticación disponibles para esta organización.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Introduzca su contraseña", "enterPassword": "Enter your password",
"enterMfaCode": "Introduzca el código de su aplicación de autenticación", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Utilice su clave de seguridad para iniciar sesión.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "¿Necesitas usar una cuenta diferente?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Al hacer clic en los botones de abajo, reconoces que has leído, comprendido, y acepta los <termsOfService>Términos de Servicio</termsOfService> y <privacyPolicy>Política de Privacidad</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Términos de Servicio", "termsOfService": "Terms of Service",
"privacyPolicy": "Política de privacidad", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Ningún usuario encontrado con ese nombre de usuario.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Verificar", "verify": "Verify",
"signIn": "Iniciar sesión", "signIn": "Sign In",
"forgotPassword": "¿Olvidaste la contraseña?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Si has iniciado sesión antes, puedes introducir tu nombre de usuario o correo electrónico arriba para autenticarte con el proveedor de identidad de tu organización. ¡Es más fácil!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Continuar de todos modos", "continueAnyway": "Continue anyway",
"dontShowAgain": "No volver a mostrar", "dontShowAgain": "Don't show again",
"orgSignInNotice": "¿Sabía usted?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "¿Intentando iniciar sesión?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "¿Estás intentando iniciar sesión a través del proveedor de identidad de tu organización?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Inicia sesión o regístrate con tu organización", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Usar una cuenta diferente", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Iniciar sesión", "logIn": "Log In",
"deviceInformation": "Información del dispositivo", "deviceInformation": "Device Information",
"deviceInformationDescription": "Información sobre el dispositivo y el agente", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Seguridad del dispositivo", "platform": "Platform",
"deviceSecurityDescription": "Información de postura de seguridad del dispositivo", "macosVersion": "macOS Version",
"platform": "Plataforma", "windowsVersion": "Windows Version",
"macosVersion": "versión macOS", "iosVersion": "iOS Version",
"windowsVersion": "Versión de Windows", "androidVersion": "Android Version",
"iosVersion": "Versión de iOS", "osVersion": "OS Version",
"androidVersion": "Versión de Android", "kernelVersion": "Kernel Version",
"osVersion": "Versión del SO", "deviceModel": "Device Model",
"kernelVersion": "Versión de Kernel", "serialNumber": "Serial Number",
"deviceModel": "Modelo de dispositivo",
"serialNumber": "Número Serial",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Primer detectado", "firstSeen": "First Seen",
"lastSeen": "Último Visto", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometría habilitada", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Disco cifrado", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Cortafuegos activado", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Actualizaciones automáticas habilitadas", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM disponible", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Protección de integridad del sistema (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Modo Sigilo Firewall", "block": "Block",
"linuxAppArmorEnabled": "AppArmor", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Ver información y ajustes del dispositivo", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Este dispositivo está esperando su aprobación", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Este dispositivo está actualmente bloqueado. No podrá conectarse a ningún recurso a menos que sea desbloqueado.", "connected": "Connected",
"unblockClient": "Desbloquear cliente", "disconnected": "Disconnected",
"unblockClientDescription": "El dispositivo ha sido desbloqueado", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Desarchivar cliente", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "El dispositivo ha sido desarchivado", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Bloque", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Desbloquear", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Acciones del dispositivo", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Administrar estado y acceso al dispositivo", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Este dispositivo está pendiente de aprobación. No podrá conectarse a recursos hasta que sea aprobado.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Conectado",
"disconnected": "Desconectado",
"approvalsEmptyStateTitle": "Aprobaciones de dispositivo no habilitadas",
"approvalsEmptyStateDescription": "Habilita las aprobaciones de dispositivos para que los roles requieran aprobación del administrador antes de que los usuarios puedan conectar nuevos dispositivos.",
"approvalsEmptyStateStep1Title": "Ir a roles",
"approvalsEmptyStateStep1Description": "Navega a la configuración de roles de tu organización para configurar las aprobaciones de dispositivos.",
"approvalsEmptyStateStep2Title": "Habilitar aprobaciones de dispositivo",
"approvalsEmptyStateStep2Description": "Editar un rol y habilitar la opción 'Requerir aprobaciones de dispositivos'. Los usuarios con este rol necesitarán la aprobación del administrador para nuevos dispositivos.",
"approvalsEmptyStatePreviewDescription": "Vista previa: Cuando está habilitado, las solicitudes de dispositivo pendientes aparecerán aquí para su revisión",
"approvalsEmptyStateButtonText": "Administrar roles"
} }
+137 -151
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Se connecter à n'importe quel réseau", "sitesBannerTitle": "Se connecter à n'importe quel réseau",
"sitesBannerDescription": "Un site est une connexion à un réseau distant qui permet à Pangolin de fournir aux utilisateurs l'accès à des ressources, publiques ou privées, n'importe où. Installez le connecteur de réseau du site (Newt) partout où vous pouvez exécuter un binaire ou un conteneur pour établir la connexion.", "sitesBannerDescription": "Un site est une connexion à un réseau distant qui permet à Pangolin de fournir aux utilisateurs l'accès à des ressources, publiques ou privées, n'importe où. Installez le connecteur de réseau du site (Newt) partout où vous pouvez exécuter un binaire ou un conteneur pour établir la connexion.",
"sitesBannerButtonText": "Installer le site", "sitesBannerButtonText": "Installer le site",
"approvalsBannerTitle": "Approuver ou refuser l'accès à l'appareil", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Examinez et approuvez ou refusez les demandes d'accès à l'appareil des utilisateurs. Lorsque les autorisations de l'appareil sont requises, les utilisateurs doivent obtenir l'approbation de l'administrateur avant que leurs appareils puissent se connecter aux ressources de votre organisation.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "En savoir plus", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Créer un nœud", "siteCreate": "Créer un nœud",
"siteCreateDescription2": "Suivez les étapes ci-dessous pour créer et connecter un nouveau nœud", "siteCreateDescription2": "Suivez les étapes ci-dessous pour créer et connecter un nouveau nœud",
"siteCreateDescription": "Créer un nouveau site pour commencer à connecter des ressources", "siteCreateDescription": "Créer un nouveau site pour commencer à connecter des ressources",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Chercher des rôles...", "accessRolesSearch": "Chercher des rôles...",
"accessRolesAdd": "Ajouter un rôle", "accessRolesAdd": "Ajouter un rôle",
"accessRoleDelete": "Supprimer le rôle", "accessRoleDelete": "Supprimer le rôle",
"accessApprovalsManage": "Gérer les approbations", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Voir et gérer les approbations en attente pour accéder à cette organisation", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Libellé", "description": "Libellé",
"inviteTitle": "Invitations actives", "inviteTitle": "Invitations actives",
"inviteDescription": "Gérer les invitations des autres utilisateurs à rejoindre l'organisation", "inviteDescription": "Gérer les invitations des autres utilisateurs à rejoindre l'organisation",
@@ -455,18 +455,18 @@
"selectDuration": "Sélectionner la durée", "selectDuration": "Sélectionner la durée",
"selectResource": "Sélectionner une ressource", "selectResource": "Sélectionner une ressource",
"filterByResource": "Filtrer par ressource", "filterByResource": "Filtrer par ressource",
"selectApprovalState": "Sélectionnez l'État d'Approbation", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtrer par État d'Approbation", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Aucune approbation", "approvalListEmpty": "No approvals",
"approvalState": "État d'approbation", "approvalState": "Approval State",
"approve": "Approuver", "approve": "Approve",
"approved": "Approuvé", "approved": "Approved",
"denied": "Refusé", "denied": "Denied",
"deniedApproval": "Approbation refusée", "deniedApproval": "Denied Approval",
"all": "Tous", "all": "All",
"deny": "Refuser", "deny": "Deny",
"viewDetails": "Voir les détails", "viewDetails": "View Details",
"requestingNewDeviceApproval": "a demandé un nouvel appareil", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Réinitialiser les filtres", "resetFilters": "Réinitialiser les filtres",
"totalBlocked": "Demandes bloquées par le Pangolin", "totalBlocked": "Demandes bloquées par le Pangolin",
"totalRequests": "Total des demandes", "totalRequests": "Total des demandes",
@@ -746,28 +746,28 @@
"countries": "Pays", "countries": "Pays",
"accessRoleCreate": "Créer un rôle", "accessRoleCreate": "Créer un rôle",
"accessRoleCreateDescription": "Créer un nouveau rôle pour regrouper les utilisateurs et gérer leurs permissions.", "accessRoleCreateDescription": "Créer un nouveau rôle pour regrouper les utilisateurs et gérer leurs permissions.",
"accessRoleEdit": "Modifier le rôle", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Modifier les informations du rôle.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Créer un rôle", "accessRoleCreateSubmit": "Créer un rôle",
"accessRoleCreated": "Rôle créé", "accessRoleCreated": "Rôle créé",
"accessRoleCreatedDescription": "Le rôle a été créé avec succès.", "accessRoleCreatedDescription": "Le rôle a été créé avec succès.",
"accessRoleErrorCreate": "Échec de la création du rôle", "accessRoleErrorCreate": "Échec de la création du rôle",
"accessRoleErrorCreateDescription": "Une erreur s'est produite lors de la création du rôle.", "accessRoleErrorCreateDescription": "Une erreur s'est produite lors de la création du rôle.",
"accessRoleUpdateSubmit": "Mettre à jour un rôle", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rôle mis à jour", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Le rôle a été mis à jour avec succès.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Approbation traitée", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Définir la décision de la demande d'approbation à approuver.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Définir la décision de la demande d'approbation comme refusée.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Impossible de mettre à jour le rôle", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Une erreur s'est produite lors de la mise à jour du rôle.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Impossible de traiter l'approbation", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Une erreur s'est produite lors du traitement de l'approbation.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Un nouveau rôle est requis", "accessRoleErrorNewRequired": "Un nouveau rôle est requis",
"accessRoleErrorRemove": "Échec de la suppression du rôle", "accessRoleErrorRemove": "Échec de la suppression du rôle",
"accessRoleErrorRemoveDescription": "Une erreur s'est produite lors de la suppression du rôle.", "accessRoleErrorRemoveDescription": "Une erreur s'est produite lors de la suppression du rôle.",
"accessRoleName": "Nom du rôle", "accessRoleName": "Nom du rôle",
"accessRoleQuestionRemove": "Vous êtes sur le point de supprimer le rôle `{name}`. Vous ne pouvez pas annuler cette action.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Supprimer le rôle", "accessRoleRemove": "Supprimer le rôle",
"accessRoleRemoveDescription": "Retirer un rôle de l'organisation", "accessRoleRemoveDescription": "Retirer un rôle de l'organisation",
"accessRoleRemoveSubmit": "Supprimer le rôle", "accessRoleRemoveSubmit": "Supprimer le rôle",
@@ -903,7 +903,7 @@
"inviteAlready": "On dirait que vous avez été invité !", "inviteAlready": "On dirait que vous avez été invité !",
"inviteAlreadyDescription": "Pour accepter l'invitation, vous devez vous connecter ou créer un compte.", "inviteAlreadyDescription": "Pour accepter l'invitation, vous devez vous connecter ou créer un compte.",
"signupQuestion": "Vous avez déjà un compte ?", "signupQuestion": "Vous avez déjà un compte ?",
"login": "Se connecter", "login": "Log In",
"resourceNotFound": "Ressource introuvable", "resourceNotFound": "Ressource introuvable",
"resourceNotFoundDescription": "La ressource que vous essayez d'accéder n'existe pas.", "resourceNotFoundDescription": "La ressource que vous essayez d'accéder n'existe pas.",
"pincodeRequirementsLength": "Le code PIN doit comporter exactement 6 chiffres", "pincodeRequirementsLength": "Le code PIN doit comporter exactement 6 chiffres",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Cette organisation vous demande de changer votre mot de passe tous les {maxDays} jours.", "passwordExpiryDescription": "Cette organisation vous demande de changer votre mot de passe tous les {maxDays} jours.",
"changePasswordNow": "Changer le mot de passe maintenant", "changePasswordNow": "Changer le mot de passe maintenant",
"pincodeAuth": "Code d'authentification", "pincodeAuth": "Code d'authentification",
"pincodeSubmit2": "Soumettre le code", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Demander la réinitialisation", "passwordResetSubmit": "Demander la réinitialisation",
"passwordResetAlreadyHaveCode": "Entrer le code", "passwordResetAlreadyHaveCode": "Entrer le code",
"passwordResetSmtpRequired": "Veuillez contacter votre administrateur", "passwordResetSmtpRequired": "Veuillez contacter votre administrateur",
"passwordResetSmtpRequiredDescription": "Un code de réinitialisation du mot de passe est requis pour réinitialiser votre mot de passe. Veuillez contacter votre administrateur pour obtenir de l'aide.", "passwordResetSmtpRequiredDescription": "Un code de réinitialisation du mot de passe est requis pour réinitialiser votre mot de passe. Veuillez contacter votre administrateur pour obtenir de l'aide.",
"passwordBack": "Retour au mot de passe", "passwordBack": "Retour au mot de passe",
"loginBack": "Revenir à la page de connexion principale", "loginBack": "Go back to main login page",
"signup": "S'inscrire", "signup": "S'inscrire",
"loginStart": "Connectez-vous pour commencer", "loginStart": "Connectez-vous pour commencer",
"idpOidcTokenValidating": "Validation du jeton OIDC", "idpOidcTokenValidating": "Validation du jeton OIDC",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Mettre à jour une organisation IDP", "actionUpdateIdpOrg": "Mettre à jour une organisation IDP",
"actionCreateClient": "Créer un client", "actionCreateClient": "Créer un client",
"actionDeleteClient": "Supprimer le client", "actionDeleteClient": "Supprimer le client",
"actionArchiveClient": "Archiver le client", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Désarchiver le client", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Bloquer le client", "actionBlockClient": "Block Client",
"actionUnblockClient": "bloquer le client", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Mettre à jour le client", "actionUpdateClient": "Mettre à jour le client",
"actionListClients": "Liste des clients", "actionListClients": "Liste des clients",
"actionGetClient": "Obtenir le client", "actionGetClient": "Obtenir le client",
@@ -1167,14 +1167,14 @@
"searchProgress": "Rechercher...", "searchProgress": "Rechercher...",
"create": "Créer", "create": "Créer",
"orgs": "Organisations", "orgs": "Organisations",
"loginError": "Une erreur inattendue s'est produite. Veuillez réessayer.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "La connexion est requise pour votre appareil.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Mot de passe oublié ?", "passwordForgot": "Mot de passe oublié ?",
"otpAuth": "Authentification à deux facteurs", "otpAuth": "Authentification à deux facteurs",
"otpAuthDescription": "Entrez le code de votre application d'authentification ou l'un de vos codes de secours à usage unique.", "otpAuthDescription": "Entrez le code de votre application d'authentification ou l'un de vos codes de secours à usage unique.",
"otpAuthSubmit": "Soumettre le code", "otpAuthSubmit": "Soumettre le code",
"idpContinue": "Ou continuer avec", "idpContinue": "Ou continuer avec",
"otpAuthBack": "Retour au mot de passe", "otpAuthBack": "Back to Password",
"navbar": "Menu de navigation", "navbar": "Menu de navigation",
"navbarDescription": "Menu de navigation principal de l'application", "navbarDescription": "Menu de navigation principal de l'application",
"navbarDocsLink": "Documentation", "navbarDocsLink": "Documentation",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Aperçu", "sidebarOverview": "Aperçu",
"sidebarHome": "Domicile", "sidebarHome": "Domicile",
"sidebarSites": "Nœuds", "sidebarSites": "Nœuds",
"sidebarApprovals": "Demandes d'approbation", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Ressource", "sidebarResources": "Ressource",
"sidebarProxyResources": "Publique", "sidebarProxyResources": "Publique",
"sidebarClientResources": "Privé", "sidebarClientResources": "Privé",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Fournisseurs d'identité", "sidebarIdentityProviders": "Fournisseurs d'identité",
"sidebarLicense": "Licence", "sidebarLicense": "Licence",
"sidebarClients": "Clients", "sidebarClients": "Clients",
"sidebarUserDevices": "Périphériques utilisateur", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Machines", "sidebarMachineClients": "Machines",
"sidebarDomains": "Domaines", "sidebarDomains": "Domaines",
"sidebarGeneral": "Gérer", "sidebarGeneral": "Gérer",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Une erreur s'est produite lors de la création du compte administrateur du serveur.", "setupErrorCreateAdmin": "Une erreur s'est produite lors de la création du compte administrateur du serveur.",
"certificateStatus": "Statut du certificat", "certificateStatus": "Statut du certificat",
"loading": "Chargement", "loading": "Chargement",
"loadingAnalytics": "Chargement de l'analyse", "loadingAnalytics": "Loading Analytics",
"restart": "Redémarrer", "restart": "Redémarrer",
"domains": "Domaines", "domains": "Domaines",
"domainsDescription": "Créer et gérer les domaines disponibles dans l'organisation", "domainsDescription": "Créer et gérer les domaines disponibles dans l'organisation",
@@ -1339,7 +1339,7 @@
"refreshError": "Échec de l'actualisation des données", "refreshError": "Échec de l'actualisation des données",
"verified": "Vérifié", "verified": "Vérifié",
"pending": "En attente", "pending": "En attente",
"pendingApproval": "En attente d'approbation", "pendingApproval": "Pending Approval",
"sidebarBilling": "Facturation", "sidebarBilling": "Facturation",
"billing": "Facturation", "billing": "Facturation",
"orgBillingDescription": "Gérer les informations de facturation et les abonnements", "orgBillingDescription": "Gérer les informations de facturation et les abonnements",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Clé de sécurité supprimée avec succès", "securityKeyRemoveSuccess": "Clé de sécurité supprimée avec succès",
"securityKeyRemoveError": "Échec de la suppression de la clé de sécurité", "securityKeyRemoveError": "Échec de la suppression de la clé de sécurité",
"securityKeyLoadError": "Échec du chargement des clés de sécurité", "securityKeyLoadError": "Échec du chargement des clés de sécurité",
"securityKeyLogin": "Utiliser la clé de sécurité", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Échec de l'authentification avec la clé de sécurité", "securityKeyAuthError": "Échec de l'authentification avec la clé de sécurité",
"securityKeyRecommendation": "Envisagez d'enregistrer une autre clé de sécurité sur un appareil différent pour vous assurer de ne pas être bloqué de votre compte.", "securityKeyRecommendation": "Envisagez d'enregistrer une autre clé de sécurité sur un appareil différent pour vous assurer de ne pas être bloqué de votre compte.",
"registering": "Enregistrement...", "registering": "Enregistrement...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Intervalle sain", "IntervalSeconds": "Intervalle sain",
"timeoutSeconds": "Délai d'attente (sec)", "timeoutSeconds": "Délai d'attente (sec)",
"timeIsInSeconds": "Le temps est exprimé en secondes", "timeIsInSeconds": "Le temps est exprimé en secondes",
"requireDeviceApproval": "Exiger les autorisations de l'appareil", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Les utilisateurs ayant ce rôle ont besoin de nouveaux périphériques approuvés par un administrateur avant de pouvoir se connecter et accéder aux ressources.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Aucune ressource interne trouvée.", "resourcesTableNoInternalResourcesFound": "Aucune ressource interne trouvée.",
"resourcesTableDestination": "Destination", "resourcesTableDestination": "Destination",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Adresse de l'alias",
"resourcesTableAliasAddressInfo": "Cette adresse fait partie du sous-réseau utilitaire de l'organisation. Elle est utilisée pour résoudre les enregistrements d'alias en utilisant une résolution DNS interne.",
"resourcesTableClients": "Clients", "resourcesTableClients": "Clients",
"resourcesTableAndOnlyAccessibleInternally": "et sont uniquement accessibles en interne lorsqu'elles sont connectées avec un client.", "resourcesTableAndOnlyAccessibleInternally": "et sont uniquement accessibles en interne lorsqu'elles sont connectées avec un client.",
"resourcesTableNoTargets": "Aucune cible", "resourcesTableNoTargets": "Aucune cible",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Choisissez votre fournisseur d'identité pour continuer", "orgAuthChooseIdpDescription": "Choisissez votre fournisseur d'identité pour continuer",
"orgAuthNoIdpConfigured": "Cette organisation n'a aucun fournisseur d'identité configuré. Vous pouvez vous connecter avec votre identité Pangolin à la place.", "orgAuthNoIdpConfigured": "Cette organisation n'a aucun fournisseur d'identité configuré. Vous pouvez vous connecter avec votre identité Pangolin à la place.",
"orgAuthSignInWithPangolin": "Se connecter avec Pangolin", "orgAuthSignInWithPangolin": "Se connecter avec Pangolin",
"orgAuthSignInToOrg": "Se connecter à une organisation", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Connexion à l'organisation", "orgAuthSelectOrgTitle": "Connexion à l'organisation",
"orgAuthSelectOrgDescription": "Entrez votre identifiant d'organisation pour continuer", "orgAuthSelectOrgDescription": "Entrez votre identifiant d'organisation pour continuer",
"orgAuthOrgIdPlaceholder": "votre-organisation", "orgAuthOrgIdPlaceholder": "votre-organisation",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Le code doit contenir 9 caractères (par exemple, A1AJ-N5JD)", "deviceCodeInvalidFormat": "Le code doit contenir 9 caractères (par exemple, A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Code invalide ou expiré", "deviceCodeInvalidOrExpired": "Code invalide ou expiré",
"deviceCodeVerifyFailed": "Impossible de vérifier le code de l'appareil", "deviceCodeVerifyFailed": "Impossible de vérifier le code de l'appareil",
"deviceCodeValidating": "Validation du code de l'appareil...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Vérification de l'autorisation de l'appareil...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Connecté en tant que", "signedInAs": "Connecté en tant que",
"deviceCodeEnterPrompt": "Entrez le code affiché sur l'appareil", "deviceCodeEnterPrompt": "Entrez le code affiché sur l'appareil",
"continue": "Continuer", "continue": "Continuer",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Accès à toutes les organisations auxquelles votre compte a accès", "deviceOrganizationsAccess": "Accès à toutes les organisations auxquelles votre compte a accès",
"deviceAuthorize": "Autoriser {applicationName}", "deviceAuthorize": "Autoriser {applicationName}",
"deviceConnected": "Appareil connecté !", "deviceConnected": "Appareil connecté !",
"deviceAuthorizedMessage": "L'appareil est autorisé à accéder à votre compte. Veuillez retourner à l'application client.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Nuage de Pangolin", "pangolinCloud": "Nuage de Pangolin",
"viewDevices": "Voir les appareils", "viewDevices": "Voir les appareils",
"viewDevicesDescription": "Gérer vos appareils connectés", "viewDevicesDescription": "Gérer vos appareils connectés",
@@ -2348,7 +2346,7 @@
"identifier": "Identifiant", "identifier": "Identifiant",
"deviceLoginUseDifferentAccount": "Pas vous ? Utilisez un autre compte.", "deviceLoginUseDifferentAccount": "Pas vous ? Utilisez un autre compte.",
"deviceLoginDeviceRequestingAccessToAccount": "Un appareil demande l'accès à ce compte.", "deviceLoginDeviceRequestingAccessToAccount": "Un appareil demande l'accès à ce compte.",
"loginSelectAuthenticationMethod": "Sélectionnez une méthode d'authentification pour continuer.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Aucune donnée", "noData": "Aucune donnée",
"machineClients": "Clients Machines", "machineClients": "Clients Machines",
"install": "Installer", "install": "Installer",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Nous rencontrons actuellement des difficultés techniques. Veuillez vérifier ultérieurement.", "maintenanceScreenMessage": "Nous rencontrons actuellement des difficultés techniques. Veuillez vérifier ultérieurement.",
"maintenanceScreenEstimatedCompletion": "Achèvement estimé :", "maintenanceScreenEstimatedCompletion": "Achèvement estimé :",
"createInternalResourceDialogDestinationRequired": "La destination est requise", "createInternalResourceDialogDestinationRequired": "La destination est requise",
"available": "Disponible", "available": "Available",
"archived": "Archivé", "archived": "Archived",
"noArchivedDevices": "Aucun périphérique archivé trouvé", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Appareil archivé", "deviceArchived": "Device archived",
"deviceArchivedDescription": "L'appareil a été archivé avec succès.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Erreur lors de l'archivage du périphérique", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Impossible d'archiver l'appareil", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Êtes-vous sûr de vouloir archiver cet appareil ?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Le périphérique sera archivé et retiré de la liste des périphériques actifs.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Dispositif d'archivage", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Dispositif d'archivage", "archiveDevice": "Archive Device",
"archive": "Archive", "archive": "Archive",
"deviceUnarchived": "Appareil désarchivé", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "L'appareil a été désarchivé avec succès.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Erreur lors de la désarchivage du périphérique", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Échec de la désarchivage de l'appareil", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Désarchiver", "unarchive": "Unarchive",
"archiveClient": "Archiver le client", "archiveClient": "Archive Client",
"archiveClientQuestion": "Êtes-vous sûr de vouloir archiver ce client?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Le client sera archivé et retiré de votre liste de clients actifs.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Archiver le client", "archiveClientConfirm": "Archive Client",
"blockClient": "Bloquer le client", "blockClient": "Block Client",
"blockClientQuestion": "Êtes-vous sûr de vouloir bloquer ce client?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "L'appareil sera forcé de se déconnecter si vous êtes actuellement connecté. Vous pourrez débloquer l'appareil plus tard.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Bloquer le client", "blockClientConfirm": "Block Client",
"active": "Actif", "active": "Active",
"usernameOrEmail": "Nom d'utilisateur ou email", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Sélectionnez votre organisation", "selectYourOrganization": "Select your organization",
"signInTo": "Se connecter à", "signInTo": "Log in in to",
"signInWithPassword": "Continuer avec le mot de passe", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Aucune méthode d'authentification disponible pour cette organisation.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Entrez votre mot de passe", "enterPassword": "Enter your password",
"enterMfaCode": "Entrez le code de votre application d'authentification", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Veuillez utiliser votre clé de sécurité pour vous connecter.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Besoin d'un autre compte ?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "En cliquant sur les boutons ci-dessous, vous reconnaissez avoir lu, compris et accepté les <termsOfService>Conditions d'utilisation</termsOfService> et la <privacyPolicy>Politique de confidentialité</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Conditions d'utilisation", "termsOfService": "Terms of Service",
"privacyPolicy": "Politique de confidentialité", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Aucun utilisateur trouvé avec ce nom d'utilisateur.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Vérifier", "verify": "Verify",
"signIn": "Se connecter", "signIn": "Sign In",
"forgotPassword": "Mot de passe oublié ?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Si vous vous êtes déjà connecté, vous pouvez entrer votre nom d'utilisateur ou votre e-mail ci-dessus pour vous authentifier auprès du fournisseur d'identité de votre organisation. C'est plus facile !", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Continuer quand même", "continueAnyway": "Continue anyway",
"dontShowAgain": "Ne plus afficher", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Le saviez-vous ?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Vous essayez de vous connecter ?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Essayez-vous de vous connecter par l'intermédiaire du fournisseur d'identité de votre organisme?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Connectez-vous ou inscrivez-vous avec votre organisation à la place", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Utiliser un compte différent", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Se connecter", "logIn": "Log In",
"deviceInformation": "Informations sur l'appareil", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informations sur l'appareil et l'agent", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Sécurité de l'appareil", "platform": "Platform",
"deviceSecurityDescription": "Informations sur la posture de sécurité de l'appareil", "macosVersion": "macOS Version",
"platform": "Plateforme", "windowsVersion": "Windows Version",
"macosVersion": "Version macOS", "iosVersion": "iOS Version",
"windowsVersion": "Version de Windows", "androidVersion": "Android Version",
"iosVersion": "Version iOS", "osVersion": "OS Version",
"androidVersion": "Version d'Android", "kernelVersion": "Kernel Version",
"osVersion": "Version du système d'exploitation", "deviceModel": "Device Model",
"kernelVersion": "Version du noyau", "serialNumber": "Serial Number",
"deviceModel": "Modèle de l'appareil",
"serialNumber": "Numéro de série",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Première vue", "firstSeen": "First Seen",
"lastSeen": "Dernière vue", "lastSeen": "Last Seen",
"biometricsEnabled": "biométrique activée", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Disque chiffré", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Pare-feu activé", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Mises à jour automatiques activées", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM disponible", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Protection contre l'intégrité du système (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Mode furtif du pare-feu", "block": "Block",
"linuxAppArmorEnabled": "Armure d'application", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Afficher les informations et les paramètres de l'appareil", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Cet appareil est en attente d'approbation", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Cet appareil est actuellement bloqué. Il ne pourra se connecter à aucune ressource à moins d'être débloqué.", "connected": "Connected",
"unblockClient": "Débloquer le client", "disconnected": "Disconnected",
"unblockClientDescription": "L'appareil a été débloqué", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Désarchiver le client", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "L'appareil a été désarchivé", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Bloquer", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Débloquer", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Actions de l'appareil", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Gérer le statut et l'accès de l'appareil", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Cet appareil est en attente d'approbation. Il ne sera pas en mesure de se connecter aux ressources jusqu'à ce qu'il soit approuvé.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Connecté",
"disconnected": "Déconnecté",
"approvalsEmptyStateTitle": "Approbations de l'appareil non activées",
"approvalsEmptyStateDescription": "Activer les autorisations de l'appareil pour les rôles qui nécessitent l'approbation de l'administrateur avant que les utilisateurs puissent connecter de nouveaux appareils.",
"approvalsEmptyStateStep1Title": "Aller aux Rôles",
"approvalsEmptyStateStep1Description": "Accédez aux paramètres de rôles de votre organisation pour configurer les autorisations de l'appareil.",
"approvalsEmptyStateStep2Title": "Activer les autorisations de l'appareil",
"approvalsEmptyStateStep2Description": "Modifier un rôle et activer l'option 'Exiger les autorisations de l'appareil'. Les utilisateurs avec ce rôle auront besoin de l'approbation de l'administrateur pour les nouveaux appareils.",
"approvalsEmptyStatePreviewDescription": "Aperçu: Lorsque cette option est activée, les demandes de périphérique en attente apparaîtront ici pour vérification",
"approvalsEmptyStateButtonText": "Gérer les rôles"
} }
+136 -150
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Connetti Qualsiasi Rete", "sitesBannerTitle": "Connetti Qualsiasi Rete",
"sitesBannerDescription": "Un sito è una connessione a una rete remota che consente a Pangolin di fornire accesso alle risorse, pubbliche o private, agli utenti ovunque. Installa il connettore di rete del sito (Newt) ovunque tu possa eseguire un binario o un container per stabilire la connessione.", "sitesBannerDescription": "Un sito è una connessione a una rete remota che consente a Pangolin di fornire accesso alle risorse, pubbliche o private, agli utenti ovunque. Installa il connettore di rete del sito (Newt) ovunque tu possa eseguire un binario o un container per stabilire la connessione.",
"sitesBannerButtonText": "Installa Sito", "sitesBannerButtonText": "Installa Sito",
"approvalsBannerTitle": "Approva o nega l'accesso al dispositivo", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Controlla e approva o nega le richieste di accesso al dispositivo da parte degli utenti. Quando le approvazioni del dispositivo sono richieste, gli utenti devono ottenere l'approvazione dell'amministratore prima che i loro dispositivi possano connettersi alle risorse della vostra organizzazione.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Scopri di più", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Crea Sito", "siteCreate": "Crea Sito",
"siteCreateDescription2": "Segui i passaggi qui sotto per creare e collegare un nuovo sito", "siteCreateDescription2": "Segui i passaggi qui sotto per creare e collegare un nuovo sito",
"siteCreateDescription": "Crea un nuovo sito per iniziare a connettere le risorse", "siteCreateDescription": "Crea un nuovo sito per iniziare a connettere le risorse",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Ricerca ruoli...", "accessRolesSearch": "Ricerca ruoli...",
"accessRolesAdd": "Aggiungi Ruolo", "accessRolesAdd": "Aggiungi Ruolo",
"accessRoleDelete": "Elimina Ruolo", "accessRoleDelete": "Elimina Ruolo",
"accessApprovalsManage": "Gestisci Approvazioni", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Visualizza e gestisci le approvazioni in attesa per accedere a questa organizzazione", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Descrizione", "description": "Descrizione",
"inviteTitle": "Inviti Aperti", "inviteTitle": "Inviti Aperti",
"inviteDescription": "Gestisci gli inviti per gli altri utenti a unirsi all'organizzazione", "inviteDescription": "Gestisci gli inviti per gli altri utenti a unirsi all'organizzazione",
@@ -455,18 +455,18 @@
"selectDuration": "Seleziona durata", "selectDuration": "Seleziona durata",
"selectResource": "Seleziona Risorsa", "selectResource": "Seleziona Risorsa",
"filterByResource": "Filtra Per Risorsa", "filterByResource": "Filtra Per Risorsa",
"selectApprovalState": "Seleziona Stato Di Approvazione", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtra Per Stato Di Approvazione", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Nessuna approvazione", "approvalListEmpty": "No approvals",
"approvalState": "Stato Di Approvazione", "approvalState": "Approval State",
"approve": "Approva", "approve": "Approve",
"approved": "Approvato", "approved": "Approved",
"denied": "Negato", "denied": "Denied",
"deniedApproval": "Omologazione Negata", "deniedApproval": "Denied Approval",
"all": "Tutti", "all": "All",
"deny": "Nega", "deny": "Deny",
"viewDetails": "Visualizza Dettagli", "viewDetails": "View Details",
"requestingNewDeviceApproval": "ha richiesto un nuovo dispositivo", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Ripristina Filtri", "resetFilters": "Ripristina Filtri",
"totalBlocked": "Richieste Bloccate Da Pangolino", "totalBlocked": "Richieste Bloccate Da Pangolino",
"totalRequests": "Totale Richieste", "totalRequests": "Totale Richieste",
@@ -746,28 +746,28 @@
"countries": "Paesi", "countries": "Paesi",
"accessRoleCreate": "Crea Ruolo", "accessRoleCreate": "Crea Ruolo",
"accessRoleCreateDescription": "Crea un nuovo ruolo per raggruppare gli utenti e gestire i loro permessi.", "accessRoleCreateDescription": "Crea un nuovo ruolo per raggruppare gli utenti e gestire i loro permessi.",
"accessRoleEdit": "Modifica Ruolo", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Modifica informazioni sul ruolo.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Crea Ruolo", "accessRoleCreateSubmit": "Crea Ruolo",
"accessRoleCreated": "Ruolo creato", "accessRoleCreated": "Ruolo creato",
"accessRoleCreatedDescription": "Il ruolo è stato creato con successo.", "accessRoleCreatedDescription": "Il ruolo è stato creato con successo.",
"accessRoleErrorCreate": "Impossibile creare il ruolo", "accessRoleErrorCreate": "Impossibile creare il ruolo",
"accessRoleErrorCreateDescription": "Si è verificato un errore durante la creazione del ruolo.", "accessRoleErrorCreateDescription": "Si è verificato un errore durante la creazione del ruolo.",
"accessRoleUpdateSubmit": "Aggiorna Ruolo", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Ruolo aggiornato", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Il ruolo è stato aggiornato con successo.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Approvazione trattata", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Impostare la decisione di richiesta di approvazione da approvare.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Imposta la decisione di richiesta di approvazione negata.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Impossibile aggiornare il ruolo", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Si è verificato un errore nell'aggiornamento del ruolo.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Impossibile elaborare l'approvazione", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Si è verificato un errore durante l'elaborazione dell'approvazione.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Nuovo ruolo richiesto", "accessRoleErrorNewRequired": "Nuovo ruolo richiesto",
"accessRoleErrorRemove": "Impossibile rimuovere il ruolo", "accessRoleErrorRemove": "Impossibile rimuovere il ruolo",
"accessRoleErrorRemoveDescription": "Si è verificato un errore durante la rimozione del ruolo.", "accessRoleErrorRemoveDescription": "Si è verificato un errore durante la rimozione del ruolo.",
"accessRoleName": "Nome Del Ruolo", "accessRoleName": "Nome Del Ruolo",
"accessRoleQuestionRemove": "Stai per eliminare il ruolo `{name}`. Non puoi annullare questa azione.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Rimuovi Ruolo", "accessRoleRemove": "Rimuovi Ruolo",
"accessRoleRemoveDescription": "Rimuovi un ruolo dall'organizzazione", "accessRoleRemoveDescription": "Rimuovi un ruolo dall'organizzazione",
"accessRoleRemoveSubmit": "Rimuovi Ruolo", "accessRoleRemoveSubmit": "Rimuovi Ruolo",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Questa organizzazione richiede di cambiare la password ogni {maxDays} giorni.", "passwordExpiryDescription": "Questa organizzazione richiede di cambiare la password ogni {maxDays} giorni.",
"changePasswordNow": "Cambia Password Ora", "changePasswordNow": "Cambia Password Ora",
"pincodeAuth": "Codice Autenticatore", "pincodeAuth": "Codice Autenticatore",
"pincodeSubmit2": "Invia codice", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Richiedi Reset", "passwordResetSubmit": "Richiedi Reset",
"passwordResetAlreadyHaveCode": "Inserisci Codice", "passwordResetAlreadyHaveCode": "Inserisci Codice",
"passwordResetSmtpRequired": "Si prega di contattare l'amministratore", "passwordResetSmtpRequired": "Si prega di contattare l'amministratore",
"passwordResetSmtpRequiredDescription": "Per reimpostare la password è necessario un codice di reimpostazione della password. Si prega di contattare l'amministratore per assistenza.", "passwordResetSmtpRequiredDescription": "Per reimpostare la password è necessario un codice di reimpostazione della password. Si prega di contattare l'amministratore per assistenza.",
"passwordBack": "Torna alla Password", "passwordBack": "Torna alla Password",
"loginBack": "Torna alla pagina di accesso principale", "loginBack": "Go back to main login page",
"signup": "Registrati", "signup": "Registrati",
"loginStart": "Accedi per iniziare", "loginStart": "Accedi per iniziare",
"idpOidcTokenValidating": "Convalida token OIDC", "idpOidcTokenValidating": "Convalida token OIDC",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Aggiorna Org IDP", "actionUpdateIdpOrg": "Aggiorna Org IDP",
"actionCreateClient": "Crea Client", "actionCreateClient": "Crea Client",
"actionDeleteClient": "Elimina Client", "actionDeleteClient": "Elimina Client",
"actionArchiveClient": "Archivia Client", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Annulla Archiviazione Client", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Blocca Client", "actionBlockClient": "Block Client",
"actionUnblockClient": "Sblocca Client", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Aggiorna Client", "actionUpdateClient": "Aggiorna Client",
"actionListClients": "Elenco Clienti", "actionListClients": "Elenco Clienti",
"actionGetClient": "Ottieni Client", "actionGetClient": "Ottieni Client",
@@ -1167,14 +1167,14 @@
"searchProgress": "Ricerca...", "searchProgress": "Ricerca...",
"create": "Crea", "create": "Crea",
"orgs": "Organizzazioni", "orgs": "Organizzazioni",
"loginError": "Si è verificato un errore imprevisto. Riprova.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Il login è richiesto per il tuo dispositivo.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Password dimenticata?", "passwordForgot": "Password dimenticata?",
"otpAuth": "Autenticazione a Due Fattori", "otpAuth": "Autenticazione a Due Fattori",
"otpAuthDescription": "Inserisci il codice dalla tua app di autenticazione o uno dei tuoi codici di backup monouso.", "otpAuthDescription": "Inserisci il codice dalla tua app di autenticazione o uno dei tuoi codici di backup monouso.",
"otpAuthSubmit": "Invia Codice", "otpAuthSubmit": "Invia Codice",
"idpContinue": "O continua con", "idpContinue": "O continua con",
"otpAuthBack": "Torna alla Password", "otpAuthBack": "Back to Password",
"navbar": "Menu di Navigazione", "navbar": "Menu di Navigazione",
"navbarDescription": "Menu di navigazione principale dell'applicazione", "navbarDescription": "Menu di navigazione principale dell'applicazione",
"navbarDocsLink": "Documentazione", "navbarDocsLink": "Documentazione",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Panoramica", "sidebarOverview": "Panoramica",
"sidebarHome": "Home", "sidebarHome": "Home",
"sidebarSites": "Siti", "sidebarSites": "Siti",
"sidebarApprovals": "Richieste Di Approvazione", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Risorse", "sidebarResources": "Risorse",
"sidebarProxyResources": "Pubblico", "sidebarProxyResources": "Pubblico",
"sidebarClientResources": "Privato", "sidebarClientResources": "Privato",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Fornitori Di Identità", "sidebarIdentityProviders": "Fornitori Di Identità",
"sidebarLicense": "Licenza", "sidebarLicense": "Licenza",
"sidebarClients": "Client", "sidebarClients": "Client",
"sidebarUserDevices": "Dispositivi Utente", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Macchine", "sidebarMachineClients": "Macchine",
"sidebarDomains": "Domini", "sidebarDomains": "Domini",
"sidebarGeneral": "Gestisci", "sidebarGeneral": "Gestisci",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Si è verificato un errore durante la creazione dell'account amministratore del server.", "setupErrorCreateAdmin": "Si è verificato un errore durante la creazione dell'account amministratore del server.",
"certificateStatus": "Stato del Certificato", "certificateStatus": "Stato del Certificato",
"loading": "Caricamento", "loading": "Caricamento",
"loadingAnalytics": "Caricamento Delle Analisi", "loadingAnalytics": "Loading Analytics",
"restart": "Riavvia", "restart": "Riavvia",
"domains": "Domini", "domains": "Domini",
"domainsDescription": "Creare e gestire i domini disponibili nell'organizzazione", "domainsDescription": "Creare e gestire i domini disponibili nell'organizzazione",
@@ -1339,7 +1339,7 @@
"refreshError": "Impossibile aggiornare i dati", "refreshError": "Impossibile aggiornare i dati",
"verified": "Verificato", "verified": "Verificato",
"pending": "In attesa", "pending": "In attesa",
"pendingApproval": "Approvazione In Attesa", "pendingApproval": "Pending Approval",
"sidebarBilling": "Fatturazione", "sidebarBilling": "Fatturazione",
"billing": "Fatturazione", "billing": "Fatturazione",
"orgBillingDescription": "Gestisci le informazioni di fatturazione e gli abbonamenti", "orgBillingDescription": "Gestisci le informazioni di fatturazione e gli abbonamenti",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Chiave di sicurezza rimossa con successo", "securityKeyRemoveSuccess": "Chiave di sicurezza rimossa con successo",
"securityKeyRemoveError": "Errore durante la rimozione della chiave di sicurezza", "securityKeyRemoveError": "Errore durante la rimozione della chiave di sicurezza",
"securityKeyLoadError": "Errore durante il caricamento delle chiavi di sicurezza", "securityKeyLoadError": "Errore durante il caricamento delle chiavi di sicurezza",
"securityKeyLogin": "Usa Chiave Di Sicurezza", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Errore durante l'autenticazione con chiave di sicurezza", "securityKeyAuthError": "Errore durante l'autenticazione con chiave di sicurezza",
"securityKeyRecommendation": "Considera di registrare un'altra chiave di sicurezza su un dispositivo diverso per assicurarti di non rimanere bloccato fuori dal tuo account.", "securityKeyRecommendation": "Considera di registrare un'altra chiave di sicurezza su un dispositivo diverso per assicurarti di non rimanere bloccato fuori dal tuo account.",
"registering": "Registrazione in corso...", "registering": "Registrazione in corso...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Intervallo Sano", "IntervalSeconds": "Intervallo Sano",
"timeoutSeconds": "Timeout (sec)", "timeoutSeconds": "Timeout (sec)",
"timeIsInSeconds": "Il tempo è in secondi", "timeIsInSeconds": "Il tempo è in secondi",
"requireDeviceApproval": "Richiede Approvazioni Dispositivo", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Gli utenti con questo ruolo hanno bisogno di nuovi dispositivi approvati da un amministratore prima di poter connettersi e accedere alle risorse.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa interna trovata.", "resourcesTableNoInternalResourcesFound": "Nessuna risorsa interna trovata.",
"resourcesTableDestination": "Destinazione", "resourcesTableDestination": "Destinazione",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Indirizzo Alias",
"resourcesTableAliasAddressInfo": "Questo indirizzo fa parte della subnet di utilità dell'organizzazione. È usato per risolvere i record alias usando la risoluzione DNS interna.",
"resourcesTableClients": "Client", "resourcesTableClients": "Client",
"resourcesTableAndOnlyAccessibleInternally": "e sono accessibili solo internamente quando connessi con un client.", "resourcesTableAndOnlyAccessibleInternally": "e sono accessibili solo internamente quando connessi con un client.",
"resourcesTableNoTargets": "Nessun obiettivo", "resourcesTableNoTargets": "Nessun obiettivo",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Scegli il tuo provider di identità per continuare", "orgAuthChooseIdpDescription": "Scegli il tuo provider di identità per continuare",
"orgAuthNoIdpConfigured": "Questa organizzazione non ha nessun provider di identità configurato. Puoi accedere con la tua identità Pangolin.", "orgAuthNoIdpConfigured": "Questa organizzazione non ha nessun provider di identità configurato. Puoi accedere con la tua identità Pangolin.",
"orgAuthSignInWithPangolin": "Accedi con Pangolino", "orgAuthSignInWithPangolin": "Accedi con Pangolino",
"orgAuthSignInToOrg": "Accedi a un'organizzazione", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Accesso Organizzazione", "orgAuthSelectOrgTitle": "Accesso Organizzazione",
"orgAuthSelectOrgDescription": "Inserisci l'ID dell'organizzazione per continuare", "orgAuthSelectOrgDescription": "Inserisci l'ID dell'organizzazione per continuare",
"orgAuthOrgIdPlaceholder": "la-tua-organizzazione", "orgAuthOrgIdPlaceholder": "la-tua-organizzazione",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Il codice deve contenere 9 caratteri (es. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Il codice deve contenere 9 caratteri (es. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Codice non valido o scaduto", "deviceCodeInvalidOrExpired": "Codice non valido o scaduto",
"deviceCodeVerifyFailed": "Impossibile verificare il codice del dispositivo", "deviceCodeVerifyFailed": "Impossibile verificare il codice del dispositivo",
"deviceCodeValidating": "Convalida codice dispositivo...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Verifica autorizzazione dispositivo...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Accesso come", "signedInAs": "Accesso come",
"deviceCodeEnterPrompt": "Inserisci il codice visualizzato sul dispositivo", "deviceCodeEnterPrompt": "Inserisci il codice visualizzato sul dispositivo",
"continue": "Continua", "continue": "Continua",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Accesso a tutte le organizzazioni a cui il tuo account ha accesso", "deviceOrganizationsAccess": "Accesso a tutte le organizzazioni a cui il tuo account ha accesso",
"deviceAuthorize": "Autorizza {applicationName}", "deviceAuthorize": "Autorizza {applicationName}",
"deviceConnected": "Dispositivo Connesso!", "deviceConnected": "Dispositivo Connesso!",
"deviceAuthorizedMessage": "Il dispositivo è autorizzato ad accedere al tuo account. Ritorna all'applicazione client.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Pangolin Cloud", "pangolinCloud": "Pangolin Cloud",
"viewDevices": "Visualizza Dispositivi", "viewDevices": "Visualizza Dispositivi",
"viewDevicesDescription": "Gestisci i tuoi dispositivi connessi", "viewDevicesDescription": "Gestisci i tuoi dispositivi connessi",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Non tu? Usa un account diverso.", "deviceLoginUseDifferentAccount": "Non tu? Usa un account diverso.",
"deviceLoginDeviceRequestingAccessToAccount": "Un dispositivo sta richiedendo l'accesso a questo account.", "deviceLoginDeviceRequestingAccessToAccount": "Un dispositivo sta richiedendo l'accesso a questo account.",
"loginSelectAuthenticationMethod": "Selezionare un metodo di autenticazione per continuare.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Nessun Dato", "noData": "Nessun Dato",
"machineClients": "Machine Clients", "machineClients": "Machine Clients",
"install": "Installa", "install": "Installa",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Stiamo attualmente riscontrando difficoltà tecniche. Si prega di ricontrollare a breve.", "maintenanceScreenMessage": "Stiamo attualmente riscontrando difficoltà tecniche. Si prega di ricontrollare a breve.",
"maintenanceScreenEstimatedCompletion": "Completamento Stimato:", "maintenanceScreenEstimatedCompletion": "Completamento Stimato:",
"createInternalResourceDialogDestinationRequired": "Destinazione richiesta", "createInternalResourceDialogDestinationRequired": "Destinazione richiesta",
"available": "Disponibile", "available": "Available",
"archived": "Archiviato", "archived": "Archived",
"noArchivedDevices": "Nessun dispositivo archiviato trovato", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Dispositivo archiviato", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Il dispositivo è stato archiviato con successo.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Errore nell'archiviazione del dispositivo", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Impossibile archiviare il dispositivo", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "È sicuro di voler archiviare questo dispositivo?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Il dispositivo verrà archiviato e rimosso dalla lista dei dispositivi attivi.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Archivia Dispositivo", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Archivia Dispositivo", "archiveDevice": "Archive Device",
"archive": "Archivio", "archive": "Archive",
"deviceUnarchived": "Dispositivo non archiviato", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Il dispositivo è stato disarchiviato con successo.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Errore nel disarchiviare il dispositivo", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Disarchiviazione del dispositivo non riuscita", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Disarchivia", "unarchive": "Unarchive",
"archiveClient": "Archivia Client", "archiveClient": "Archive Client",
"archiveClientQuestion": "È sicuro di voler archiviare questo client?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Il client verrà archiviato e rimosso dalla lista dei client attivi.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Archivia Client", "archiveClientConfirm": "Archive Client",
"blockClient": "Blocca Client", "blockClient": "Block Client",
"blockClientQuestion": "Sei sicuro di voler bloccare questo client?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Il dispositivo sarà forzato a disconnettersi se attualmente connesso. Puoi sbloccare il dispositivo più tardi.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Blocca Client", "blockClientConfirm": "Block Client",
"active": "Attivo", "active": "Active",
"usernameOrEmail": "Nome utente o Email", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Seleziona la tua organizzazione", "selectYourOrganization": "Select your organization",
"signInTo": "Accedi a", "signInTo": "Log in in to",
"signInWithPassword": "Continua con la password", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Nessun metodo di autenticazione disponibile per questa organizzazione.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Inserisci la tua password", "enterPassword": "Enter your password",
"enterMfaCode": "Inserisci il codice dalla tua app di autenticazione", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Utilizza la tua chiave di sicurezza per accedere.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Hai bisogno di utilizzare un account diverso?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Facendo clic sui pulsanti qui sotto, si riconosce di aver letto, capire, e accettare i Termini di Servizio <termsOfService></termsOfService> e <privacyPolicy>Privacy Policy</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Termini di servizio", "termsOfService": "Terms of Service",
"privacyPolicy": "Politica Sulla Privacy", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Nessun utente trovato con questo nome utente.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Verifica", "verify": "Verify",
"signIn": "Accedi", "signIn": "Sign In",
"forgotPassword": "Password dimenticata?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Se hai effettuato l'accesso prima, puoi inserire il tuo nome utente o email qui sopra per autenticarti con il provider di identità della tua organizzazione. È più facile!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Continua comunque", "continueAnyway": "Continue anyway",
"dontShowAgain": "Non mostrare più", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Lo sapevate?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Cercando di accedere?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Stai cercando di accedere tramite il provider di identità della tua organizzazione?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Accedi o registrati con la tua organizzazione", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Usa un account diverso", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Log In", "logIn": "Log In",
"deviceInformation": "Informazioni Sul Dispositivo", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informazioni sul dispositivo e sull'agente", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Sicurezza Del Dispositivo", "platform": "Platform",
"deviceSecurityDescription": "Informazioni postura sicurezza dispositivo", "macosVersion": "macOS Version",
"platform": "Piattaforma", "windowsVersion": "Windows Version",
"macosVersion": "versione macOS", "iosVersion": "iOS Version",
"windowsVersion": "Versione Windows", "androidVersion": "Android Version",
"iosVersion": "Versione iOS", "osVersion": "OS Version",
"androidVersion": "Versione Android", "kernelVersion": "Kernel Version",
"osVersion": "Versione OS", "deviceModel": "Device Model",
"kernelVersion": "Versione Del Kernel", "serialNumber": "Serial Number",
"deviceModel": "Modello Di Dispositivo",
"serialNumber": "Numero D'Ordine",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Prima Visto", "firstSeen": "First Seen",
"lastSeen": "Visto L'Ultima", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometria Abilitata", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Cifratura Del Disco", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Firewall Abilitato", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Aggiornamenti Automatici Abilitati", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM Disponibile", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Protezione Dell'Integrità Del Sistema (Sip)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Modo Furtivo Del Firewall", "block": "Block",
"linuxAppArmorEnabled": "AppArmor", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Visualizza informazioni e impostazioni del dispositivo", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Questo dispositivo è in attesa di approvazione", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Questo dispositivo è attualmente bloccato. Non sarà in grado di connettersi a nessuna risorsa a meno che non sia sbloccato.", "connected": "Connected",
"unblockClient": "Sblocca Client", "disconnected": "Disconnected",
"unblockClientDescription": "Il dispositivo è stato sbloccato", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Annulla Archiviazione Client", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Il dispositivo è stato disarchiviato", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Blocca", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Sblocca", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Azioni Dispositivo", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Gestisci lo stato del dispositivo e l'accesso", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Questo dispositivo è in attesa di approvazione. Non sarà in grado di connettersi alle risorse fino all'approvazione.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Connesso",
"disconnected": "Disconnesso",
"approvalsEmptyStateTitle": "Approvazioni Dispositivo Non Abilitato",
"approvalsEmptyStateDescription": "Abilita le approvazioni del dispositivo per i ruoli per richiedere l'approvazione dell'amministratore prima che gli utenti possano collegare nuovi dispositivi.",
"approvalsEmptyStateStep1Title": "Vai ai ruoli",
"approvalsEmptyStateStep1Description": "Vai alle impostazioni dei ruoli della tua organizzazione per configurare le approvazioni del dispositivo.",
"approvalsEmptyStateStep2Title": "Abilita Approvazioni Dispositivo",
"approvalsEmptyStateStep2Description": "Modifica un ruolo e abilita l'opzione 'Richiedi l'approvazione del dispositivo'. Gli utenti con questo ruolo avranno bisogno dell'approvazione dell'amministratore per i nuovi dispositivi.",
"approvalsEmptyStatePreviewDescription": "Anteprima: quando abilitato, le richieste di dispositivo in attesa appariranno qui per la revisione",
"approvalsEmptyStateButtonText": "Gestisci Ruoli"
} }
+139 -153
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "모든 네트워크 연결", "sitesBannerTitle": "모든 네트워크 연결",
"sitesBannerDescription": "사이트는 원격 네트워크와의 연결로 Pangolin이 어디서나 사용자에게 공공 및 개인 리소스에 대한 접근을 제공할 수 있게 해 줍니다. 연결을 설정하려면 바이너리 또는 컨테이너로 실행할 수 있는 어디서든 사이트 네트워크 커넥터(Newt)를 설치하세요.", "sitesBannerDescription": "사이트는 원격 네트워크와의 연결로 Pangolin이 어디서나 사용자에게 공공 및 개인 리소스에 대한 접근을 제공할 수 있게 해 줍니다. 연결을 설정하려면 바이너리 또는 컨테이너로 실행할 수 있는 어디서든 사이트 네트워크 커넥터(Newt)를 설치하세요.",
"sitesBannerButtonText": "사이트 설치", "sitesBannerButtonText": "사이트 설치",
"approvalsBannerTitle": "장치 접근 승인 또는 거부", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "사용자의 장치 접근 요청을 검토하고 승인하거나 거부하세요. 장치 승인 요구 시, 관리자의 승인이 필요합니다.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "자세히 알아보기", "approvalsBannerButtonText": "Learn More",
"siteCreate": "사이트 생성", "siteCreate": "사이트 생성",
"siteCreateDescription2": "아래 단계를 따라 새 사이트를 생성하고 연결하십시오", "siteCreateDescription2": "아래 단계를 따라 새 사이트를 생성하고 연결하십시오",
"siteCreateDescription": "리소스를 연결하기 위해 새 사이트를 생성하세요.", "siteCreateDescription": "리소스를 연결하기 위해 새 사이트를 생성하세요.",
@@ -260,8 +260,8 @@
"accessRolesSearch": "역할 검색...", "accessRolesSearch": "역할 검색...",
"accessRolesAdd": "역할 추가", "accessRolesAdd": "역할 추가",
"accessRoleDelete": "역할 삭제", "accessRoleDelete": "역할 삭제",
"accessApprovalsManage": "승인 관리", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "이 조직의 접근 승인 대기를 보고 관리하세요.", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "설명", "description": "설명",
"inviteTitle": "열린 초대", "inviteTitle": "열린 초대",
"inviteDescription": "다른 사용자가 조직에 참여하도록 초대장을 관리합니다.", "inviteDescription": "다른 사용자가 조직에 참여하도록 초대장을 관리합니다.",
@@ -455,18 +455,18 @@
"selectDuration": "지속 시간 선택", "selectDuration": "지속 시간 선택",
"selectResource": "리소스 선택", "selectResource": "리소스 선택",
"filterByResource": "리소스별 필터", "filterByResource": "리소스별 필터",
"selectApprovalState": "승인 상태 선택", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "승인 상태로 필터링", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "승인이 없습니다.", "approvalListEmpty": "No approvals",
"approvalState": "승인 상태", "approvalState": "Approval State",
"approve": "승인", "approve": "Approve",
"approved": "승인됨", "approved": "Approved",
"denied": "거부됨", "denied": "Denied",
"deniedApproval": "승인 거부됨", "deniedApproval": "Denied Approval",
"all": "모두", "all": "All",
"deny": "거부", "deny": "Deny",
"viewDetails": "세부 정보 보기", "viewDetails": "View Details",
"requestingNewDeviceApproval": "새 장치를 요청함", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "필터 재설정", "resetFilters": "필터 재설정",
"totalBlocked": "Pangolin으로 차단된 요청", "totalBlocked": "Pangolin으로 차단된 요청",
"totalRequests": "총 요청 수", "totalRequests": "총 요청 수",
@@ -746,28 +746,28 @@
"countries": "국가", "countries": "국가",
"accessRoleCreate": "역할 생성", "accessRoleCreate": "역할 생성",
"accessRoleCreateDescription": "사용자를 그룹화하고 권한을 관리하기 위해 새 역할을 생성하세요.", "accessRoleCreateDescription": "사용자를 그룹화하고 권한을 관리하기 위해 새 역할을 생성하세요.",
"accessRoleEdit": "역할 편집", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "역할 정보 편집.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "역할 생성", "accessRoleCreateSubmit": "역할 생성",
"accessRoleCreated": "역할이 생성되었습니다.", "accessRoleCreated": "역할이 생성되었습니다.",
"accessRoleCreatedDescription": "역할이 성공적으로 생성되었습니다.", "accessRoleCreatedDescription": "역할이 성공적으로 생성되었습니다.",
"accessRoleErrorCreate": "역할 생성 실패", "accessRoleErrorCreate": "역할 생성 실패",
"accessRoleErrorCreateDescription": "역할 생성 중 오류가 발생했습니다.", "accessRoleErrorCreateDescription": "역할 생성 중 오류가 발생했습니다.",
"accessRoleUpdateSubmit": "역할 업데이트", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "역할 업데이트됨", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "역할이 성공적으로 업데이트되었습니다.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "승인 처리됨", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "승인 요청을 승인으로 설정.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "승인 요청을 거부로 설정.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "역할 업데이트 실패", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "역할 업데이트 중 오류 발생.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "승인 처리 실패", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "승인 처리 중 오류가 발생했습니다.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "새 역할이 필요합니다.", "accessRoleErrorNewRequired": "새 역할이 필요합니다.",
"accessRoleErrorRemove": "역할 제거에 실패했습니다.", "accessRoleErrorRemove": "역할 제거에 실패했습니다.",
"accessRoleErrorRemoveDescription": "역할을 제거하는 동안 오류가 발생했습니다.", "accessRoleErrorRemoveDescription": "역할을 제거하는 동안 오류가 발생했습니다.",
"accessRoleName": "역할 이름", "accessRoleName": "역할 이름",
"accessRoleQuestionRemove": "`{name}` 역할을 삭제하려고 합니다. 이 작업은 되돌릴 수 없습니다.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "역할 제거", "accessRoleRemove": "역할 제거",
"accessRoleRemoveDescription": "조직에서 역할 제거", "accessRoleRemoveDescription": "조직에서 역할 제거",
"accessRoleRemoveSubmit": "역할 제거", "accessRoleRemoveSubmit": "역할 제거",
@@ -903,7 +903,7 @@
"inviteAlready": "초대받은 것 같습니다!", "inviteAlready": "초대받은 것 같습니다!",
"inviteAlreadyDescription": "초대를 수락하려면 로그인하거나 계정을 생성해야 합니다.", "inviteAlreadyDescription": "초대를 수락하려면 로그인하거나 계정을 생성해야 합니다.",
"signupQuestion": "이미 계정이 있습니까?", "signupQuestion": "이미 계정이 있습니까?",
"login": "로그인", "login": "Log In",
"resourceNotFound": "리소스를 찾을 수 없습니다", "resourceNotFound": "리소스를 찾을 수 없습니다",
"resourceNotFoundDescription": "접근하려는 리소스가 존재하지 않습니다.", "resourceNotFoundDescription": "접근하려는 리소스가 존재하지 않습니다.",
"pincodeRequirementsLength": "PIN은 정확히 6자리여야 합니다", "pincodeRequirementsLength": "PIN은 정확히 6자리여야 합니다",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "이 조직은 {maxDays}일마다 비밀번호 변경을 요구합니다.", "passwordExpiryDescription": "이 조직은 {maxDays}일마다 비밀번호 변경을 요구합니다.",
"changePasswordNow": "지금 비밀번호 변경", "changePasswordNow": "지금 비밀번호 변경",
"pincodeAuth": "인증 코드", "pincodeAuth": "인증 코드",
"pincodeSubmit2": "코드 제출", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "재설정 요청", "passwordResetSubmit": "재설정 요청",
"passwordResetAlreadyHaveCode": "코드를 입력하십시오.", "passwordResetAlreadyHaveCode": "코드를 입력하십시오.",
"passwordResetSmtpRequired": "관리자에게 문의하십시오", "passwordResetSmtpRequired": "관리자에게 문의하십시오",
"passwordResetSmtpRequiredDescription": "비밀번호를 재설정하려면 비밀번호 초기화 코드가 필요합니다. 지원을 받으려면 관리자에게 문의하십시오.", "passwordResetSmtpRequiredDescription": "비밀번호를 재설정하려면 비밀번호 초기화 코드가 필요합니다. 지원을 받으려면 관리자에게 문의하십시오.",
"passwordBack": "비밀번호로 돌아가기", "passwordBack": "비밀번호로 돌아가기",
"loginBack": "메인 로그인 페이지로 돌아갑니다.", "loginBack": "Go back to main login page",
"signup": "가입하기", "signup": "가입하기",
"loginStart": "시작하려면 로그인하세요.", "loginStart": "시작하려면 로그인하세요.",
"idpOidcTokenValidating": "OIDC 토큰 검증 중", "idpOidcTokenValidating": "OIDC 토큰 검증 중",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "IDP 조직 업데이트", "actionUpdateIdpOrg": "IDP 조직 업데이트",
"actionCreateClient": "클라이언트 생성", "actionCreateClient": "클라이언트 생성",
"actionDeleteClient": "클라이언트 삭제", "actionDeleteClient": "클라이언트 삭제",
"actionArchiveClient": "클라이언트 보관", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "클라이언트 보관 취소", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "클라이언트 차단", "actionBlockClient": "Block Client",
"actionUnblockClient": "클라이언트 차단 해제", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "클라이언트 업데이트", "actionUpdateClient": "클라이언트 업데이트",
"actionListClients": "클라이언트 목록", "actionListClients": "클라이언트 목록",
"actionGetClient": "클라이언트 가져오기", "actionGetClient": "클라이언트 가져오기",
@@ -1167,14 +1167,14 @@
"searchProgress": "검색...", "searchProgress": "검색...",
"create": "생성", "create": "생성",
"orgs": "조직", "orgs": "조직",
"loginError": "예기치 않은 오류가 발생했습니다. 다시 시도해주세요.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "로그인이 필요합니다.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "비밀번호를 잊으셨나요?", "passwordForgot": "비밀번호를 잊으셨나요?",
"otpAuth": "이중 인증", "otpAuth": "이중 인증",
"otpAuthDescription": "인증 앱에서 코드를 입력하거나 단일 사용 백업 코드 중 하나를 입력하세요.", "otpAuthDescription": "인증 앱에서 코드를 입력하거나 단일 사용 백업 코드 중 하나를 입력하세요.",
"otpAuthSubmit": "코드 제출", "otpAuthSubmit": "코드 제출",
"idpContinue": "또는 계속 진행하십시오.", "idpContinue": "또는 계속 진행하십시오.",
"otpAuthBack": "비밀번호로 돌아가기", "otpAuthBack": "Back to Password",
"navbar": "탐색 메뉴", "navbar": "탐색 메뉴",
"navbarDescription": "애플리케이션의 주요 탐색 메뉴", "navbarDescription": "애플리케이션의 주요 탐색 메뉴",
"navbarDocsLink": "문서", "navbarDocsLink": "문서",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "개요", "sidebarOverview": "개요",
"sidebarHome": "홈", "sidebarHome": "홈",
"sidebarSites": "사이트", "sidebarSites": "사이트",
"sidebarApprovals": "승인 요청", "sidebarApprovals": "Approval Requests",
"sidebarResources": "리소스", "sidebarResources": "리소스",
"sidebarProxyResources": "공유", "sidebarProxyResources": "공유",
"sidebarClientResources": "비공개", "sidebarClientResources": "비공개",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "신원 공급자", "sidebarIdentityProviders": "신원 공급자",
"sidebarLicense": "라이선스", "sidebarLicense": "라이선스",
"sidebarClients": "클라이언트", "sidebarClients": "클라이언트",
"sidebarUserDevices": "사용자 장치", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "기계", "sidebarMachineClients": "기계",
"sidebarDomains": "도메인", "sidebarDomains": "도메인",
"sidebarGeneral": "관리", "sidebarGeneral": "관리",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "서버 관리자 계정을 생성하는 동안 오류가 발생했습니다.", "setupErrorCreateAdmin": "서버 관리자 계정을 생성하는 동안 오류가 발생했습니다.",
"certificateStatus": "인증서 상태", "certificateStatus": "인증서 상태",
"loading": "로딩 중", "loading": "로딩 중",
"loadingAnalytics": "분석 로딩 중", "loadingAnalytics": "Loading Analytics",
"restart": "재시작", "restart": "재시작",
"domains": "도메인", "domains": "도메인",
"domainsDescription": "조직에서 사용 가능한 도메인 생성 및 관리", "domainsDescription": "조직에서 사용 가능한 도메인 생성 및 관리",
@@ -1339,7 +1339,7 @@
"refreshError": "데이터 새로고침 실패", "refreshError": "데이터 새로고침 실패",
"verified": "검증됨", "verified": "검증됨",
"pending": "대기 중", "pending": "대기 중",
"pendingApproval": "승인 대기 중", "pendingApproval": "Pending Approval",
"sidebarBilling": "청구", "sidebarBilling": "청구",
"billing": "청구", "billing": "청구",
"orgBillingDescription": "청구 정보 및 구독을 관리하세요", "orgBillingDescription": "청구 정보 및 구독을 관리하세요",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "보안 키가 성공적으로 제거되었습니다", "securityKeyRemoveSuccess": "보안 키가 성공적으로 제거되었습니다",
"securityKeyRemoveError": "보안 키 제거 실패", "securityKeyRemoveError": "보안 키 제거 실패",
"securityKeyLoadError": "보안 키를 불러오는 데 실패했습니다", "securityKeyLoadError": "보안 키를 불러오는 데 실패했습니다",
"securityKeyLogin": "보안 키 사용", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "보안 키를 사용한 인증 실패", "securityKeyAuthError": "보안 키를 사용한 인증 실패",
"securityKeyRecommendation": "항상 계정에 액세스할 수 있도록 다른 장치에 백업 보안 키를 등록하세요.", "securityKeyRecommendation": "항상 계정에 액세스할 수 있도록 다른 장치에 백업 보안 키를 등록하세요.",
"registering": "등록 중...", "registering": "등록 중...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "정상 간격", "IntervalSeconds": "정상 간격",
"timeoutSeconds": "타임아웃(초)", "timeoutSeconds": "타임아웃(초)",
"timeIsInSeconds": "시간은 초 단위입니다", "timeIsInSeconds": "시간은 초 단위입니다",
"requireDeviceApproval": "장치 승인 요구", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "이 역할을 가진 사용자는 장치가 연결되기 전에 관리자의 승인이 필요합니다.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"retryAttempts": "재시도 횟수", "retryAttempts": "재시도 횟수",
"expectedResponseCodes": "예상 응답 코드", "expectedResponseCodes": "예상 응답 코드",
"expectedResponseCodesDescription": "정상 상태를 나타내는 HTTP 상태 코드입니다. 비워 두면 200-300이 정상으로 간주됩니다.", "expectedResponseCodesDescription": "정상 상태를 나타내는 HTTP 상태 코드입니다. 비워 두면 200-300이 정상으로 간주됩니다.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "내부 리소스를 찾을 수 없습니다.", "resourcesTableNoInternalResourcesFound": "내부 리소스를 찾을 수 없습니다.",
"resourcesTableDestination": "대상지", "resourcesTableDestination": "대상지",
"resourcesTableAlias": "별칭", "resourcesTableAlias": "별칭",
"resourcesTableAliasAddress": "별칭 주소",
"resourcesTableAliasAddressInfo": "이 주소는 조직의 유틸리티 서브넷의 일부로, 내부 DNS 해석을 사용하여 별칭 레코드를 해석하는 데 사용됩니다.",
"resourcesTableClients": "클라이언트", "resourcesTableClients": "클라이언트",
"resourcesTableAndOnlyAccessibleInternally": "클라이언트와 연결되었을 때만 내부적으로 접근 가능합니다.", "resourcesTableAndOnlyAccessibleInternally": "클라이언트와 연결되었을 때만 내부적으로 접근 가능합니다.",
"resourcesTableNoTargets": "대상 없음", "resourcesTableNoTargets": "대상 없음",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "계속하려면 신원 공급자를 선택하세요.", "orgAuthChooseIdpDescription": "계속하려면 신원 공급자를 선택하세요.",
"orgAuthNoIdpConfigured": "이 조직은 구성된 신원 공급자가 없습니다. 대신 Pangolin 아이덴티티로 로그인할 수 있습니다.", "orgAuthNoIdpConfigured": "이 조직은 구성된 신원 공급자가 없습니다. 대신 Pangolin 아이덴티티로 로그인할 수 있습니다.",
"orgAuthSignInWithPangolin": "Pangolin으로 로그인", "orgAuthSignInWithPangolin": "Pangolin으로 로그인",
"orgAuthSignInToOrg": "조직에 로그인", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "조직 로그인", "orgAuthSelectOrgTitle": "조직 로그인",
"orgAuthSelectOrgDescription": "계속하려면 조직 ID를 입력하십시오.", "orgAuthSelectOrgDescription": "계속하려면 조직 ID를 입력하십시오.",
"orgAuthOrgIdPlaceholder": "your-organization", "orgAuthOrgIdPlaceholder": "your-organization",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "코드는 9자리여야 합니다 (예: A1AJ-N5JD)", "deviceCodeInvalidFormat": "코드는 9자리여야 합니다 (예: A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "무효하거나 만료된 코드", "deviceCodeInvalidOrExpired": "무효하거나 만료된 코드",
"deviceCodeVerifyFailed": "이메일 확인에 실패했습니다:", "deviceCodeVerifyFailed": "이메일 확인에 실패했습니다:",
"deviceCodeValidating": "장치 코드 검증 중...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "장치 권한 검증 중...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "로그인한 사용자", "signedInAs": "로그인한 사용자",
"deviceCodeEnterPrompt": "기기에 표시된 코드를 입력하세요", "deviceCodeEnterPrompt": "기기에 표시된 코드를 입력하세요",
"continue": "계속 진행하기", "continue": "계속 진행하기",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "계정이 접근할 수 있는 모든 조직에 대한 접근", "deviceOrganizationsAccess": "계정이 접근할 수 있는 모든 조직에 대한 접근",
"deviceAuthorize": "{applicationName} 권한 부여", "deviceAuthorize": "{applicationName} 권한 부여",
"deviceConnected": "장치가 연결되었습니다!", "deviceConnected": "장치가 연결되었습니다!",
"deviceAuthorizedMessage": "장치가 계정 접속을 승인받았습니다. 클라이언트 응용프로그램으로 돌아가세요.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "판골린 클라우드", "pangolinCloud": "판골린 클라우드",
"viewDevices": "장치 보기", "viewDevices": "장치 보기",
"viewDevicesDescription": "연결된 장치를 관리하십시오", "viewDevicesDescription": "연결된 장치를 관리하십시오",
@@ -2348,7 +2346,7 @@
"identifier": "식별자", "identifier": "식별자",
"deviceLoginUseDifferentAccount": "본인이 아닙니까? 다른 계정을 사용하세요.", "deviceLoginUseDifferentAccount": "본인이 아닙니까? 다른 계정을 사용하세요.",
"deviceLoginDeviceRequestingAccessToAccount": "장치가 이 계정에 접근하려고 합니다.", "deviceLoginDeviceRequestingAccessToAccount": "장치가 이 계정에 접근하려고 합니다.",
"loginSelectAuthenticationMethod": "계속하려면 인증 방법을 선택하세요.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "데이터 없음", "noData": "데이터 없음",
"machineClients": "기계 클라이언트", "machineClients": "기계 클라이언트",
"install": "설치", "install": "설치",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "현재 기술적 문제를 겪고 있습니다. 곧 다시 확인하십시오.", "maintenanceScreenMessage": "현재 기술적 문제를 겪고 있습니다. 곧 다시 확인하십시오.",
"maintenanceScreenEstimatedCompletion": "예상 완료:", "maintenanceScreenEstimatedCompletion": "예상 완료:",
"createInternalResourceDialogDestinationRequired": "목적지가 필요합니다.", "createInternalResourceDialogDestinationRequired": "목적지가 필요합니다.",
"available": "사용 가능", "available": "Available",
"archived": "보관된", "archived": "Archived",
"noArchivedDevices": "보관된 장치가 없습니다.", "noArchivedDevices": "No archived devices found",
"deviceArchived": "장치가 보관되었습니다.", "deviceArchived": "Device archived",
"deviceArchivedDescription": "장치가 성공적으로 보관되었습니다.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "장치를 보관하는 동안 오류가 발생했습니다.", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "장치를 보관하는 데 실패했습니다.", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "이 장치를 보관하시겠습니까?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "장치가 보관되며 당신의 활성 장치 목록에서 제거됩니다.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "장치 보관", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "장치 보관", "archiveDevice": "Archive Device",
"archive": "보관", "archive": "Archive",
"deviceUnarchived": "장치의 보관이 취소되었습니다.", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "장치의 보관이 성공적으로 취소되었습니다.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "장치 보관 해제 중 오류가 발생했습니다.", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "장치 보관 해제 실패", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "보관 해제", "unarchive": "Unarchive",
"archiveClient": "클라이언트 보관", "archiveClient": "Archive Client",
"archiveClientQuestion": "이 클라이언트를 보관하시겠습니까?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "클라이언트가 보관되며 당신의 활성 클라이언트 목록에서 제거됩니다.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "클라이언트 보관 확인", "archiveClientConfirm": "Archive Client",
"blockClient": "클라이언트 차단", "blockClient": "Block Client",
"blockClientQuestion": "이 클라이언트를 차단하시겠습니까?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "장치가 현재 연결되어 있는 경우 강제로 연결이 해제됩니다. 이후에도 차단 해제가 가능합니다.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "클라이언트 차단 확인", "blockClientConfirm": "Block Client",
"active": "활성", "active": "Active",
"usernameOrEmail": "사용자 이름 또는 이메일", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "조직 선택", "selectYourOrganization": "Select your organization",
"signInTo": "로그인 중", "signInTo": "Log in in to",
"signInWithPassword": "비밀번호로 계속", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "이 조직에는 사용할 수 있는 인증 방법이 없습니다.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "비밀번호를 입력하세요.", "enterPassword": "Enter your password",
"enterMfaCode": "인증 앱에서 제공한 코드를 입력하세요.", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "보안 키를 사용해 로그인하세요.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "다른 계정을 사용해야 합니까?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "아래 버튼을 클릭하여 <termsOfService>서비스 약관</termsOfService> <privacyPolicy>개인 정보 보호 정책</privacyPolicy>을 읽고 이해했으며 동의함을 인정합니다.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "서비스 약관", "termsOfService": "Terms of Service",
"privacyPolicy": "개인 정보 보호 정책", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "해당 사용자 이름으로 사용자를 찾지 못했습니다.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "확인", "verify": "Verify",
"signIn": "로그인", "signIn": "Sign In",
"forgotPassword": "비밀번호를 잊으셨나요?", "forgotPassword": "Forgot password?",
"orgSignInTip": "이전에 로그인한 적이 있다면, 위의 사용자 이름 또는 이메일을 입력하여 조직의 ID 공급자로 인증할 수 있습니다. 더 쉬워요!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "계속하기", "continueAnyway": "Continue anyway",
"dontShowAgain": "다시 보기 않습니다.", "dontShowAgain": "Don't show again",
"orgSignInNotice": "아셨나요?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "로그인 중이신가요?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "조직의 ID 공급자를 통해 로그인하려고 하십니까?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "대신 조직을 사용하여 로그인 또는 가입", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "다른 계정 사용", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "로그인", "logIn": "Log In",
"deviceInformation": "장치 정보", "deviceInformation": "Device Information",
"deviceInformationDescription": "장치와 에이전트 정보", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "디바이스 보안", "platform": "Platform",
"deviceSecurityDescription": "디바이스 보안 상태 정보", "macosVersion": "macOS Version",
"platform": "플랫폼", "windowsVersion": "Windows Version",
"macosVersion": "macOS 버전", "iosVersion": "iOS Version",
"windowsVersion": "Windows 버전", "androidVersion": "Android Version",
"iosVersion": "iOS 버전", "osVersion": "OS Version",
"androidVersion": "Android 버전", "kernelVersion": "Kernel Version",
"osVersion": "OS 버전", "deviceModel": "Device Model",
"kernelVersion": "커널 버전", "serialNumber": "Serial Number",
"deviceModel": "장치 모델", "hostname": "Hostname",
"serialNumber": "일련 번호", "firstSeen": "First Seen",
"hostname": "호스트 이름", "lastSeen": "Last Seen",
"firstSeen": "처음 발견됨", "deviceSettingsDescription": "View device information and settings",
"lastSeen": "마지막으로 발견됨", "devicePendingApprovalDescription": "This device is waiting for approval",
"biometricsEnabled": "생체 인식 활성화", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"diskEncrypted": "디스크 암호화됨", "unblockClient": "Unblock Client",
"firewallEnabled": "방화벽 활성화", "unblockClientDescription": "The device has been unblocked",
"autoUpdatesEnabled": "자동 업데이트 활성화", "unarchiveClient": "Unarchive Client",
"tpmAvailable": "TPM 사용 가능", "unarchiveClientDescription": "The device has been unarchived",
"macosSipEnabled": "시스템 무결성 보호 (SIP)", "block": "Block",
"macosGatekeeperEnabled": "Gatekeeper", "unblock": "Unblock",
"macosFirewallStealthMode": "방화벽 스텔스 모드", "deviceActions": "Device Actions",
"linuxAppArmorEnabled": "AppArmor", "deviceActionsDescription": "Manage device status and access",
"linuxSELinuxEnabled": "SELinux", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceSettingsDescription": "장치 정보 및 설정 보기", "connected": "Connected",
"devicePendingApprovalDescription": "이 장치는 승인을 기다리고 있습니다.", "disconnected": "Disconnected",
"deviceBlockedDescription": "이 장치는 현재 차단되었습니다. 차단이 해제되지 않으면 리소스에 연결할 수 없습니다.", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unblockClient": "클라이언트 차단 해제", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unblockClientDescription": "장치가 차단 해제되었습니다.", "approvalsEmptyStateStep1Title": "Go to Roles",
"unarchiveClient": "클라이언트 보관 취소", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unarchiveClientDescription": "장치가 보관 해제되었습니다.", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"block": "차단", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"unblock": "차단 해제", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"deviceActions": "장치 작업", "approvalsEmptyStateButtonText": "Manage Roles"
"deviceActionsDescription": "장치 상태 및 접근 관리",
"devicePendingApprovalBannerDescription": "이 장치는 승인 대기 중입니다. 승인될 때까지 리소스에 연결할 수 없습니다.",
"connected": "연결됨",
"disconnected": "연결 해제됨",
"approvalsEmptyStateTitle": "장치 승인 비활성화됨",
"approvalsEmptyStateDescription": "사용자가 새 장치를 연결하기 전에 관리자의 승인을 필요로 하도록 역할에 대해 장치 승인을 활성화하세요.",
"approvalsEmptyStateStep1Title": "역할로 이동",
"approvalsEmptyStateStep1Description": "조직의 역할 설정으로 이동하여 장치 승인을 구성하십시오.",
"approvalsEmptyStateStep2Title": "장치 승인 활성화",
"approvalsEmptyStateStep2Description": "역할을 편집하고 '장치 승인 요구' 옵션을 활성화하세요. 이 역할을 가진 사용자는 새 장치에 대해 관리자의 승인이 필요합니다.",
"approvalsEmptyStatePreviewDescription": "미리 보기: 활성화된 경우, 승인 대기 중인 장치 요청이 검토용으로 여기에 표시됩니다.",
"approvalsEmptyStateButtonText": "역할 관리"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Koble til alle nettverk", "sitesBannerTitle": "Koble til alle nettverk",
"sitesBannerDescription": "Et nettverk er en tilkobling til et eksternt nettverk som tillater Pangolin å gi tilgang til ressurser, enten offentlige eller private, til brukere hvor som helst. Installer nettverkskontaktet (Newt) hvor som helst du kan kjøre en binærfil eller container for å opprette forbindelsen.", "sitesBannerDescription": "Et nettverk er en tilkobling til et eksternt nettverk som tillater Pangolin å gi tilgang til ressurser, enten offentlige eller private, til brukere hvor som helst. Installer nettverkskontaktet (Newt) hvor som helst du kan kjøre en binærfil eller container for å opprette forbindelsen.",
"sitesBannerButtonText": "Installer nettsted", "sitesBannerButtonText": "Installer nettsted",
"approvalsBannerTitle": "Godkjenn eller avslå tilgang til enhet", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Gjennomgå og godkjenne eller avslå forespørsler om tilgang fra brukere. Når enhetsgodkjenninger er nødvendig, må brukere få admingodkjenning før enhetene kan koble seg til organisasjonens ressurser.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Lær mer", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Opprett område", "siteCreate": "Opprett område",
"siteCreateDescription2": "Følg trinnene nedenfor for å opprette og koble til et nytt område", "siteCreateDescription2": "Følg trinnene nedenfor for å opprette og koble til et nytt område",
"siteCreateDescription": "Opprett et nytt nettsted for å koble til ressurser", "siteCreateDescription": "Opprett et nytt nettsted for å koble til ressurser",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Søk etter roller...", "accessRolesSearch": "Søk etter roller...",
"accessRolesAdd": "Legg til rolle", "accessRolesAdd": "Legg til rolle",
"accessRoleDelete": "Slett rolle", "accessRoleDelete": "Slett rolle",
"accessApprovalsManage": "Behandle godkjenninger", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Se og administrer ventende godkjenninger for tilgang til denne organisasjonen", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Beskrivelse", "description": "Beskrivelse",
"inviteTitle": "Åpne invitasjoner", "inviteTitle": "Åpne invitasjoner",
"inviteDescription": "Administrer invitasjoner til andre brukere for å bli med i organisasjonen", "inviteDescription": "Administrer invitasjoner til andre brukere for å bli med i organisasjonen",
@@ -455,18 +455,18 @@
"selectDuration": "Velg varighet", "selectDuration": "Velg varighet",
"selectResource": "Velg ressurs", "selectResource": "Velg ressurs",
"filterByResource": "Filtrer etter ressurser", "filterByResource": "Filtrer etter ressurser",
"selectApprovalState": "Velg godkjenningsstatus", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtrer etter godkjenningsstatus", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Ingen godkjenninger", "approvalListEmpty": "No approvals",
"approvalState": "Godkjennings tilstand", "approvalState": "Approval State",
"approve": "Godkjenn", "approve": "Approve",
"approved": "Godkjent", "approved": "Approved",
"denied": "Avvist", "denied": "Denied",
"deniedApproval": "Avslått godkjenning", "deniedApproval": "Denied Approval",
"all": "Alle", "all": "All",
"deny": "Avslå", "deny": "Deny",
"viewDetails": "Vis detaljer", "viewDetails": "View Details",
"requestingNewDeviceApproval": "forespurt en ny enhet", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Tilbakestill filtre", "resetFilters": "Tilbakestill filtre",
"totalBlocked": "Forespørsler blokkert av Pangolin", "totalBlocked": "Forespørsler blokkert av Pangolin",
"totalRequests": "Totalt antall forespørsler", "totalRequests": "Totalt antall forespørsler",
@@ -746,28 +746,28 @@
"countries": "Land", "countries": "Land",
"accessRoleCreate": "Opprett rolle", "accessRoleCreate": "Opprett rolle",
"accessRoleCreateDescription": "Opprett en ny rolle for å gruppere brukere og administrere deres tillatelser.", "accessRoleCreateDescription": "Opprett en ny rolle for å gruppere brukere og administrere deres tillatelser.",
"accessRoleEdit": "Rediger rolle", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Rediger rolleinformasjon.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Opprett rolle", "accessRoleCreateSubmit": "Opprett rolle",
"accessRoleCreated": "Rolle opprettet", "accessRoleCreated": "Rolle opprettet",
"accessRoleCreatedDescription": "Rollen er vellykket opprettet.", "accessRoleCreatedDescription": "Rollen er vellykket opprettet.",
"accessRoleErrorCreate": "Klarte ikke å opprette rolle", "accessRoleErrorCreate": "Klarte ikke å opprette rolle",
"accessRoleErrorCreateDescription": "Det oppstod en feil under opprettelse av rollen.", "accessRoleErrorCreateDescription": "Det oppstod en feil under opprettelse av rollen.",
"accessRoleUpdateSubmit": "Oppdater rolle", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rollen oppdatert", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Rollen har blitt oppdatert.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Godkjenning behandlet", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Sett godkjenningsforespørsel om å godta.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Sett godkjenningsforespørsel om å nekte.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Kunne ikke oppdatere rolle", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Det oppstod en feil under oppdatering av rollen.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Kunne ikke behandle godkjenning", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Det oppstod en feil under behandling av godkjenningen.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Ny rolle kreves", "accessRoleErrorNewRequired": "Ny rolle kreves",
"accessRoleErrorRemove": "Kunne ikke fjerne rolle", "accessRoleErrorRemove": "Kunne ikke fjerne rolle",
"accessRoleErrorRemoveDescription": "Det oppstod en feil under fjerning av rollen.", "accessRoleErrorRemoveDescription": "Det oppstod en feil under fjerning av rollen.",
"accessRoleName": "Rollenavn", "accessRoleName": "Rollenavn",
"accessRoleQuestionRemove": "Du er ferd med å slette rollen `{name}. Du kan ikke angre denne handlingen.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Fjern Rolle", "accessRoleRemove": "Fjern Rolle",
"accessRoleRemoveDescription": "Fjern en rolle fra organisasjonen", "accessRoleRemoveDescription": "Fjern en rolle fra organisasjonen",
"accessRoleRemoveSubmit": "Fjern Rolle", "accessRoleRemoveSubmit": "Fjern Rolle",
@@ -903,7 +903,7 @@
"inviteAlready": "Ser ut til at du har blitt invitert!", "inviteAlready": "Ser ut til at du har blitt invitert!",
"inviteAlreadyDescription": "For å godta invitasjonen, må du logge inn eller opprette en konto.", "inviteAlreadyDescription": "For å godta invitasjonen, må du logge inn eller opprette en konto.",
"signupQuestion": "Har du allerede en konto?", "signupQuestion": "Har du allerede en konto?",
"login": "Logg inn", "login": "Log In",
"resourceNotFound": "Ressurs ikke funnet", "resourceNotFound": "Ressurs ikke funnet",
"resourceNotFoundDescription": "Ressursen du prøver å få tilgang til eksisterer ikke.", "resourceNotFoundDescription": "Ressursen du prøver å få tilgang til eksisterer ikke.",
"pincodeRequirementsLength": "PIN må være nøyaktig 6 siffer", "pincodeRequirementsLength": "PIN må være nøyaktig 6 siffer",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Denne organisasjonen krever at du bytter passord hver {maxDays} dag.", "passwordExpiryDescription": "Denne organisasjonen krever at du bytter passord hver {maxDays} dag.",
"changePasswordNow": "Bytt passord nå", "changePasswordNow": "Bytt passord nå",
"pincodeAuth": "Autentiseringskode", "pincodeAuth": "Autentiseringskode",
"pincodeSubmit2": "Send kode", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Be om tilbakestilling", "passwordResetSubmit": "Be om tilbakestilling",
"passwordResetAlreadyHaveCode": "Skriv inn koden", "passwordResetAlreadyHaveCode": "Skriv inn koden",
"passwordResetSmtpRequired": "Kontakt din administrator", "passwordResetSmtpRequired": "Kontakt din administrator",
"passwordResetSmtpRequiredDescription": "En passord tilbakestillingskode kreves for å tilbakestille passordet. Kontakt systemansvarlig for assistanse.", "passwordResetSmtpRequiredDescription": "En passord tilbakestillingskode kreves for å tilbakestille passordet. Kontakt systemansvarlig for assistanse.",
"passwordBack": "Tilbake til passord", "passwordBack": "Tilbake til passord",
"loginBack": "Gå tilbake til innloggingssiden for hovedkontoen", "loginBack": "Go back to main login page",
"signup": "Registrer deg", "signup": "Registrer deg",
"loginStart": "Logg inn for å komme i gang", "loginStart": "Logg inn for å komme i gang",
"idpOidcTokenValidating": "Validerer OIDC-token", "idpOidcTokenValidating": "Validerer OIDC-token",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Oppdater IDP-organisasjon", "actionUpdateIdpOrg": "Oppdater IDP-organisasjon",
"actionCreateClient": "Opprett Klient", "actionCreateClient": "Opprett Klient",
"actionDeleteClient": "Slett klient", "actionDeleteClient": "Slett klient",
"actionArchiveClient": "Arkiver klient", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Fjern arkivering klient", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Blokker kunde", "actionBlockClient": "Block Client",
"actionUnblockClient": "Avblokker klient", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Oppdater klient", "actionUpdateClient": "Oppdater klient",
"actionListClients": "List klienter", "actionListClients": "List klienter",
"actionGetClient": "Hent klient", "actionGetClient": "Hent klient",
@@ -1167,14 +1167,14 @@
"searchProgress": "Søker...", "searchProgress": "Søker...",
"create": "Opprett", "create": "Opprett",
"orgs": "Organisasjoner", "orgs": "Organisasjoner",
"loginError": "En uventet feil oppstod. Vennligst prøv igjen.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Innlogging er nødvendig for enheten din.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Glemt passordet ditt?", "passwordForgot": "Glemt passordet ditt?",
"otpAuth": "Tofaktorautentisering", "otpAuth": "Tofaktorautentisering",
"otpAuthDescription": "Skriv inn koden fra autentiseringsappen din eller en av dine engangs reservekoder.", "otpAuthDescription": "Skriv inn koden fra autentiseringsappen din eller en av dine engangs reservekoder.",
"otpAuthSubmit": "Send inn kode", "otpAuthSubmit": "Send inn kode",
"idpContinue": "Eller fortsett med", "idpContinue": "Eller fortsett med",
"otpAuthBack": "Tilbake til passord", "otpAuthBack": "Back to Password",
"navbar": "Navigasjonsmeny", "navbar": "Navigasjonsmeny",
"navbarDescription": "Hovednavigasjonsmeny for applikasjonen", "navbarDescription": "Hovednavigasjonsmeny for applikasjonen",
"navbarDocsLink": "Dokumentasjon", "navbarDocsLink": "Dokumentasjon",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Oversikt", "sidebarOverview": "Oversikt",
"sidebarHome": "Hjem", "sidebarHome": "Hjem",
"sidebarSites": "Områder", "sidebarSites": "Områder",
"sidebarApprovals": "Godkjenningsforespørsler", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Ressurser", "sidebarResources": "Ressurser",
"sidebarProxyResources": "Offentlig", "sidebarProxyResources": "Offentlig",
"sidebarClientResources": "Privat", "sidebarClientResources": "Privat",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Identitetsleverandører", "sidebarIdentityProviders": "Identitetsleverandører",
"sidebarLicense": "Lisens", "sidebarLicense": "Lisens",
"sidebarClients": "Klienter", "sidebarClients": "Klienter",
"sidebarUserDevices": "Bruker Enheter", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Maskiner", "sidebarMachineClients": "Maskiner",
"sidebarDomains": "Domener", "sidebarDomains": "Domener",
"sidebarGeneral": "Administrer", "sidebarGeneral": "Administrer",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "En feil oppstod under opprettelsen av serveradministratorkontoen.", "setupErrorCreateAdmin": "En feil oppstod under opprettelsen av serveradministratorkontoen.",
"certificateStatus": "Sertifikatstatus", "certificateStatus": "Sertifikatstatus",
"loading": "Laster inn", "loading": "Laster inn",
"loadingAnalytics": "Laster inn analyser", "loadingAnalytics": "Loading Analytics",
"restart": "Start på nytt", "restart": "Start på nytt",
"domains": "Domener", "domains": "Domener",
"domainsDescription": "Opprett og behandle domener som er tilgjengelige i organisasjonen", "domainsDescription": "Opprett og behandle domener som er tilgjengelige i organisasjonen",
@@ -1339,7 +1339,7 @@
"refreshError": "Klarte ikke å oppdatere data", "refreshError": "Klarte ikke å oppdatere data",
"verified": "Verifisert", "verified": "Verifisert",
"pending": "Venter", "pending": "Venter",
"pendingApproval": "Venter på godkjenning", "pendingApproval": "Pending Approval",
"sidebarBilling": "Fakturering", "sidebarBilling": "Fakturering",
"billing": "Fakturering", "billing": "Fakturering",
"orgBillingDescription": "Administrer faktureringsinformasjon og abonnementer", "orgBillingDescription": "Administrer faktureringsinformasjon og abonnementer",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Sikkerhetsnøkkel fjernet", "securityKeyRemoveSuccess": "Sikkerhetsnøkkel fjernet",
"securityKeyRemoveError": "Klarte ikke å fjerne sikkerhetsnøkkel", "securityKeyRemoveError": "Klarte ikke å fjerne sikkerhetsnøkkel",
"securityKeyLoadError": "Klarte ikke å laste inn sikkerhetsnøkler", "securityKeyLoadError": "Klarte ikke å laste inn sikkerhetsnøkler",
"securityKeyLogin": "Bruk sikkerhetsnøkkel", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Klarte ikke å autentisere med sikkerhetsnøkkel", "securityKeyAuthError": "Klarte ikke å autentisere med sikkerhetsnøkkel",
"securityKeyRecommendation": "Registrer en reservesikkerhetsnøkkel på en annen enhet for å sikre at du alltid har tilgang til kontoen din.", "securityKeyRecommendation": "Registrer en reservesikkerhetsnøkkel på en annen enhet for å sikre at du alltid har tilgang til kontoen din.",
"registering": "Registrerer...", "registering": "Registrerer...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Sunt intervall", "IntervalSeconds": "Sunt intervall",
"timeoutSeconds": "Tidsavbrudd (sek)", "timeoutSeconds": "Tidsavbrudd (sek)",
"timeIsInSeconds": "Tid er i sekunder", "timeIsInSeconds": "Tid er i sekunder",
"requireDeviceApproval": "Krev enhetsgodkjenning", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Brukere med denne rollen trenger nye enheter godkjent av en admin før de kan koble seg og få tilgang til ressurser.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Ingen interne ressurser funnet.", "resourcesTableNoInternalResourcesFound": "Ingen interne ressurser funnet.",
"resourcesTableDestination": "Destinasjon", "resourcesTableDestination": "Destinasjon",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias adresse",
"resourcesTableAliasAddressInfo": "Denne adressen er en del av organisasjonens undernettverk. Den brukes til å løse aliasposter ved hjelp av intern DNS-oppløsning.",
"resourcesTableClients": "Klienter", "resourcesTableClients": "Klienter",
"resourcesTableAndOnlyAccessibleInternally": "og er kun tilgjengelig internt når de er koblet til med en klient.", "resourcesTableAndOnlyAccessibleInternally": "og er kun tilgjengelig internt når de er koblet til med en klient.",
"resourcesTableNoTargets": "Ingen mål", "resourcesTableNoTargets": "Ingen mål",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Velg din identitet leverandør for å fortsette", "orgAuthChooseIdpDescription": "Velg din identitet leverandør for å fortsette",
"orgAuthNoIdpConfigured": "Denne organisasjonen har ikke noen identitetstjeneste konfigurert. Du kan i stedet logge inn med Pangolin identiteten din.", "orgAuthNoIdpConfigured": "Denne organisasjonen har ikke noen identitetstjeneste konfigurert. Du kan i stedet logge inn med Pangolin identiteten din.",
"orgAuthSignInWithPangolin": "Logg inn med Pangolin", "orgAuthSignInWithPangolin": "Logg inn med Pangolin",
"orgAuthSignInToOrg": "Logg inn på en organisasjon", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Organisasjonsinnlogging", "orgAuthSelectOrgTitle": "Organisasjonsinnlogging",
"orgAuthSelectOrgDescription": "Skriv inn organisasjons-ID-en din for å fortsette", "orgAuthSelectOrgDescription": "Skriv inn organisasjons-ID-en din for å fortsette",
"orgAuthOrgIdPlaceholder": "din-organisasjon", "orgAuthOrgIdPlaceholder": "din-organisasjon",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Kode må inneholde 9 tegn (f.eks A1AJ-N5JD)", "deviceCodeInvalidFormat": "Kode må inneholde 9 tegn (f.eks A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Ugyldig eller utløpt kode", "deviceCodeInvalidOrExpired": "Ugyldig eller utløpt kode",
"deviceCodeVerifyFailed": "Klarte ikke å bekrefte enhetskoden", "deviceCodeVerifyFailed": "Klarte ikke å bekrefte enhetskoden",
"deviceCodeValidating": "Validerer enhetskode...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Bekrefter enhetens godkjennelse...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Logget inn som", "signedInAs": "Logget inn som",
"deviceCodeEnterPrompt": "Skriv inn koden som vises på enheten", "deviceCodeEnterPrompt": "Skriv inn koden som vises på enheten",
"continue": "Fortsett", "continue": "Fortsett",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Tilgang til alle organisasjoner din konto har tilgang til", "deviceOrganizationsAccess": "Tilgang til alle organisasjoner din konto har tilgang til",
"deviceAuthorize": "Autoriser {applicationName}", "deviceAuthorize": "Autoriser {applicationName}",
"deviceConnected": "Enhet tilkoblet!", "deviceConnected": "Enhet tilkoblet!",
"deviceAuthorizedMessage": "Enheten er autorisert for tilgang til kontoen. Vennligst gå tilbake til klientapplikasjonen.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Pangolin Sky", "pangolinCloud": "Pangolin Sky",
"viewDevices": "Vis enheter", "viewDevices": "Vis enheter",
"viewDevicesDescription": "Administrer tilkoblede enheter", "viewDevicesDescription": "Administrer tilkoblede enheter",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Ikke du? Bruk en annen konto.", "deviceLoginUseDifferentAccount": "Ikke du? Bruk en annen konto.",
"deviceLoginDeviceRequestingAccessToAccount": "En enhet ber om tilgang til denne kontoen.", "deviceLoginDeviceRequestingAccessToAccount": "En enhet ber om tilgang til denne kontoen.",
"loginSelectAuthenticationMethod": "Velg en autentiseringsmetode for å fortsette.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Ingen data", "noData": "Ingen data",
"machineClients": "Maskinklienter", "machineClients": "Maskinklienter",
"install": "Installer", "install": "Installer",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Vi opplever for øyeblikket tekniske problemer. Vennligst sjekk igjen snart.", "maintenanceScreenMessage": "Vi opplever for øyeblikket tekniske problemer. Vennligst sjekk igjen snart.",
"maintenanceScreenEstimatedCompletion": "Estimert ferdigstillelse:", "maintenanceScreenEstimatedCompletion": "Estimert ferdigstillelse:",
"createInternalResourceDialogDestinationRequired": "Destinasjonen er nødvendig", "createInternalResourceDialogDestinationRequired": "Destinasjonen er nødvendig",
"available": "Tilgjengelig", "available": "Available",
"archived": "Arkivert", "archived": "Archived",
"noArchivedDevices": "Ingen arkiverte enheter funnet", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Enhet arkivert", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Enheten er blitt arkivert.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Feil ved arkivering av enhet", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Kunne ikke arkivere enhet", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Er du sikker på at du vil arkivere denne enheten?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Enheten blir arkivert og fjernet fra listen over aktive enheter.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Arkiver enhet", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Arkiver enhet", "archiveDevice": "Archive Device",
"archive": "Arkiv", "archive": "Archive",
"deviceUnarchived": "Enheten er uarkivert", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Enheten er blitt avarkivert.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Feil ved arkivering av enhet", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Kunne ikke fjerne arkivere enheten", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Avarkiver", "unarchive": "Unarchive",
"archiveClient": "Arkiver klient", "archiveClient": "Archive Client",
"archiveClientQuestion": "Er du sikker på at du vil arkivere denne klienten?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Klienten arkiveres og fjernes fra listen over aktive klienter.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Arkiver klient", "archiveClientConfirm": "Archive Client",
"blockClient": "Blokker kunde", "blockClient": "Block Client",
"blockClientQuestion": "Er du sikker på at du vil blokkere denne klienten?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Enheten blir tvunget til å koble fra hvis den er koblet til. Du kan fjerne blokkeringen av enheten senere.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Blokker kunde", "blockClientConfirm": "Block Client",
"active": "Aktiv", "active": "Active",
"usernameOrEmail": "Brukernavn eller e-post", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Velg din organisasjon", "selectYourOrganization": "Select your organization",
"signInTo": "Logg inn på", "signInTo": "Log in in to",
"signInWithPassword": "Fortsett med passord", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Ingen autentiseringsmetoder er tilgjengelige for denne organisasjonen.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Angi ditt passord", "enterPassword": "Enter your password",
"enterMfaCode": "Angi koden fra din autentiseringsapp", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Vennligst bruk sikkerhetsnøkkelen til å logge på.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Trenger du å bruke en annen konto?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Ved å klikke på knappene nedenfor, erkjenner du at du har lest, forstår, og godtar <termsOfService>Vilkår for bruk</termsOfService> og <privacyPolicy>for Personvernerklæring</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Vilkår for bruk", "termsOfService": "Terms of Service",
"privacyPolicy": "Retningslinjer for personvern", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Ingen bruker med det brukernavnet funnet.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Verifiser", "verify": "Verify",
"signIn": "Logg inn", "signIn": "Sign In",
"forgotPassword": "Glemt passord?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Hvis du har logget inn før, kan du skrive inn brukernavnet eller e-postadressen ovenfor for å autentisere med organisasjonens identitetstjeneste i stedet. Det er enklere!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Fortsett likevel", "continueAnyway": "Continue anyway",
"dontShowAgain": "Ikke vis igjen", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Visste du?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Prøver å logge inn?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Prøver du å logge inn gjennom din organisasjons identitetsleverandør?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Logg inn eller registrer deg med organisasjonen din i stedet", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Bruk en annen konto", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Logg inn", "logIn": "Log In",
"deviceInformation": "Enhetens informasjon", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informasjon om enheten og agenten", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Enhetens sikkerhet", "platform": "Platform",
"deviceSecurityDescription": "Sikkerhetsstillings informasjon om utstyr", "macosVersion": "macOS Version",
"platform": "Plattform", "windowsVersion": "Windows Version",
"macosVersion": "macOS versjon", "iosVersion": "iOS Version",
"windowsVersion": "Windows versjon", "androidVersion": "Android Version",
"iosVersion": "iOS Versjon", "osVersion": "OS Version",
"androidVersion": "Android versjon", "kernelVersion": "Kernel Version",
"osVersion": "OS versjon", "deviceModel": "Device Model",
"kernelVersion": "Kjerne versjon", "serialNumber": "Serial Number",
"deviceModel": "Enhets modell",
"serialNumber": "Serienummer",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Først sett", "firstSeen": "First Seen",
"lastSeen": "Sist sett", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometri aktivert", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Disk kryptert", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Brannmur aktivert", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Automatiske oppdateringer aktivert", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM tilgjengelig", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "System Integritetsbeskyttelse (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Brannmur Usynlig Modus", "block": "Block",
"linuxAppArmorEnabled": "Rustning", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Vis enhetsinformasjon og innstillinger", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Denne enheten venter på godkjenning", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Denne enheten er blokkert. Det kan ikke kobles til noen ressurser med mindre de ikke blir blokkert.", "connected": "Connected",
"unblockClient": "Avblokker klient", "disconnected": "Disconnected",
"unblockClientDescription": "Enheten har blitt blokkert", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Fjern arkivering klient", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Enheten er arkivert", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Blokker", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Avblokker", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Enhetens handlinger", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Administrer enhetsstatus og tilgang", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Denne enheten venter på godkjenning. Den kan ikke koble til ressurser før den er godkjent.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Tilkoblet",
"disconnected": "Frakoblet",
"approvalsEmptyStateTitle": "Enhetsgodkjenninger er ikke aktivert",
"approvalsEmptyStateDescription": "Aktivere godkjenninger av enheter for at roller må godkjennes av admin før brukere kan koble til nye enheter.",
"approvalsEmptyStateStep1Title": "Gå til roller",
"approvalsEmptyStateStep1Description": "Naviger til organisasjonens roller innstillinger for å konfigurere enhetsgodkjenninger.",
"approvalsEmptyStateStep2Title": "Aktiver enhetsgodkjenninger",
"approvalsEmptyStateStep2Description": "Rediger en rolle og aktiver alternativet 'Kreve enhetsgodkjenninger'. Brukere med denne rollen vil trenge administratorgodkjenning for nye enheter.",
"approvalsEmptyStatePreviewDescription": "Forhåndsvisning: Når aktivert, ventende enhets forespørsler vil vises her for vurdering",
"approvalsEmptyStateButtonText": "Administrer Roller"
} }
+137 -151
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Verbind elk netwerk", "sitesBannerTitle": "Verbind elk netwerk",
"sitesBannerDescription": "Een site is een verbinding met een extern netwerk waarmee Pangolin toegang biedt tot bronnen, zowel openbaar als privé, aan gebruikers overal. Installeer de sitedatacenterconnector (Newt) overal waar je een binaire of container kunt uitvoeren om de verbinding tot stand te brengen.", "sitesBannerDescription": "Een site is een verbinding met een extern netwerk waarmee Pangolin toegang biedt tot bronnen, zowel openbaar als privé, aan gebruikers overal. Installeer de sitedatacenterconnector (Newt) overal waar je een binaire of container kunt uitvoeren om de verbinding tot stand te brengen.",
"sitesBannerButtonText": "Site installeren", "sitesBannerButtonText": "Site installeren",
"approvalsBannerTitle": "Toegang tot het apparaat goedkeuren of weigeren", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Bekijk en keur toestelverzoeken goed of weiger toegang van gebruikers. Wanneer apparaatgoedkeuringen vereist zijn, moeten gebruikers de goedkeuring van beheerders krijgen voordat hun apparaten verbinding kunnen maken met de bronnen van uw organisatie.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Meer informatie", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Site maken", "siteCreate": "Site maken",
"siteCreateDescription2": "Volg de onderstaande stappen om een nieuwe site aan te maken en te verbinden", "siteCreateDescription2": "Volg de onderstaande stappen om een nieuwe site aan te maken en te verbinden",
"siteCreateDescription": "Maak een nieuwe site aan om bronnen te verbinden", "siteCreateDescription": "Maak een nieuwe site aan om bronnen te verbinden",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Rollen zoeken...", "accessRolesSearch": "Rollen zoeken...",
"accessRolesAdd": "Rol toevoegen", "accessRolesAdd": "Rol toevoegen",
"accessRoleDelete": "Verwijder rol", "accessRoleDelete": "Verwijder rol",
"accessApprovalsManage": "Goedkeuringen beheren", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Bekijk en beheer openstaande goedkeuringen voor toegang tot deze organisatie", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Beschrijving", "description": "Beschrijving",
"inviteTitle": "Open uitnodigingen", "inviteTitle": "Open uitnodigingen",
"inviteDescription": "Beheer uitnodigingen voor andere gebruikers om deel te nemen aan de organisatie", "inviteDescription": "Beheer uitnodigingen voor andere gebruikers om deel te nemen aan de organisatie",
@@ -455,18 +455,18 @@
"selectDuration": "Selecteer duur", "selectDuration": "Selecteer duur",
"selectResource": "Selecteer Document", "selectResource": "Selecteer Document",
"filterByResource": "Filter op pagina", "filterByResource": "Filter op pagina",
"selectApprovalState": "Selecteer goedkeuringsstatus", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filter op goedkeuringsstatus", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Geen goedkeuringen", "approvalListEmpty": "No approvals",
"approvalState": "Goedkeuring status", "approvalState": "Approval State",
"approve": "Goedkeuren", "approve": "Approve",
"approved": "Goedgekeurd", "approved": "Approved",
"denied": "Geweigerd", "denied": "Denied",
"deniedApproval": "Geweigerde goedkeuring", "deniedApproval": "Denied Approval",
"all": "Alles", "all": "All",
"deny": "Weigeren", "deny": "Deny",
"viewDetails": "Details bekijken", "viewDetails": "View Details",
"requestingNewDeviceApproval": "heeft een nieuw apparaat aangevraagd", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Filters resetten", "resetFilters": "Filters resetten",
"totalBlocked": "Verzoeken geblokkeerd door Pangolin", "totalBlocked": "Verzoeken geblokkeerd door Pangolin",
"totalRequests": "Totaal verzoeken", "totalRequests": "Totaal verzoeken",
@@ -746,28 +746,28 @@
"countries": "Landen", "countries": "Landen",
"accessRoleCreate": "Rol aanmaken", "accessRoleCreate": "Rol aanmaken",
"accessRoleCreateDescription": "Maak een nieuwe rol aan om gebruikers te groeperen en hun rechten te beheren.", "accessRoleCreateDescription": "Maak een nieuwe rol aan om gebruikers te groeperen en hun rechten te beheren.",
"accessRoleEdit": "Rol bewerken", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Bewerk rol informatie.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Rol aanmaken", "accessRoleCreateSubmit": "Rol aanmaken",
"accessRoleCreated": "Rol aangemaakt", "accessRoleCreated": "Rol aangemaakt",
"accessRoleCreatedDescription": "De rol is succesvol aangemaakt.", "accessRoleCreatedDescription": "De rol is succesvol aangemaakt.",
"accessRoleErrorCreate": "Rol aanmaken mislukt", "accessRoleErrorCreate": "Rol aanmaken mislukt",
"accessRoleErrorCreateDescription": "Fout opgetreden tijdens het aanmaken van de rol.", "accessRoleErrorCreateDescription": "Fout opgetreden tijdens het aanmaken van de rol.",
"accessRoleUpdateSubmit": "Rol bijwerken", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rol bijgewerkt", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "De rol is succesvol bijgewerkt.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Afgewerkt met goedkeuring", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Stel het goedkeuringsverzoek in op goedkeuring.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Stel de beslissing over het goedkeuringsverzoek in als geweigerd.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Bijwerken van rol mislukt", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Fout opgetreden tijdens het bijwerken van de rol.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Kan goedkeuring niet verwerken", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Er is een fout opgetreden bij het verwerken van de goedkeuring.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Nieuwe rol is vereist", "accessRoleErrorNewRequired": "Nieuwe rol is vereist",
"accessRoleErrorRemove": "Rol verwijderen mislukt", "accessRoleErrorRemove": "Rol verwijderen mislukt",
"accessRoleErrorRemoveDescription": "Er is een fout opgetreden tijdens het verwijderen van de rol.", "accessRoleErrorRemoveDescription": "Er is een fout opgetreden tijdens het verwijderen van de rol.",
"accessRoleName": "Rol naam", "accessRoleName": "Rol naam",
"accessRoleQuestionRemove": "Je staat op het punt de `{name}` rol te verwijderen. Je kunt deze actie niet ongedaan maken.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Rol verwijderen", "accessRoleRemove": "Rol verwijderen",
"accessRoleRemoveDescription": "Verwijder een rol van de organisatie", "accessRoleRemoveDescription": "Verwijder een rol van de organisatie",
"accessRoleRemoveSubmit": "Rol verwijderen", "accessRoleRemoveSubmit": "Rol verwijderen",
@@ -903,7 +903,7 @@
"inviteAlready": "Het lijkt erop dat je bent uitgenodigd!", "inviteAlready": "Het lijkt erop dat je bent uitgenodigd!",
"inviteAlreadyDescription": "Om de uitnodiging te accepteren, moet je inloggen of een account aanmaken.", "inviteAlreadyDescription": "Om de uitnodiging te accepteren, moet je inloggen of een account aanmaken.",
"signupQuestion": "Heeft u al een account?", "signupQuestion": "Heeft u al een account?",
"login": "Log in", "login": "Log In",
"resourceNotFound": "Bron niet gevonden", "resourceNotFound": "Bron niet gevonden",
"resourceNotFoundDescription": "De bron die u probeert te benaderen bestaat niet.", "resourceNotFoundDescription": "De bron die u probeert te benaderen bestaat niet.",
"pincodeRequirementsLength": "Pincode moet precies 6 cijfers zijn", "pincodeRequirementsLength": "Pincode moet precies 6 cijfers zijn",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Deze organisatie vereist dat u om de {maxDays} dagen uw wachtwoord wijzigt.", "passwordExpiryDescription": "Deze organisatie vereist dat u om de {maxDays} dagen uw wachtwoord wijzigt.",
"changePasswordNow": "Wijzig wachtwoord nu", "changePasswordNow": "Wijzig wachtwoord nu",
"pincodeAuth": "Authenticatiecode", "pincodeAuth": "Authenticatiecode",
"pincodeSubmit2": "Code indienen", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Opnieuw instellen aanvragen", "passwordResetSubmit": "Opnieuw instellen aanvragen",
"passwordResetAlreadyHaveCode": "Code invoeren", "passwordResetAlreadyHaveCode": "Code invoeren",
"passwordResetSmtpRequired": "Neem contact op met uw beheerder", "passwordResetSmtpRequired": "Neem contact op met uw beheerder",
"passwordResetSmtpRequiredDescription": "Er is een wachtwoord reset code nodig om uw wachtwoord opnieuw in te stellen. Neem contact op met uw beheerder voor hulp.", "passwordResetSmtpRequiredDescription": "Er is een wachtwoord reset code nodig om uw wachtwoord opnieuw in te stellen. Neem contact op met uw beheerder voor hulp.",
"passwordBack": "Terug naar wachtwoord", "passwordBack": "Terug naar wachtwoord",
"loginBack": "Ga terug naar de hoofdinlogpagina", "loginBack": "Go back to main login page",
"signup": "Registreer nu", "signup": "Registreer nu",
"loginStart": "Log in om te beginnen", "loginStart": "Log in om te beginnen",
"idpOidcTokenValidating": "Valideer OIDC-token", "idpOidcTokenValidating": "Valideer OIDC-token",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "IDP-org bijwerken", "actionUpdateIdpOrg": "IDP-org bijwerken",
"actionCreateClient": "Client aanmaken", "actionCreateClient": "Client aanmaken",
"actionDeleteClient": "Verwijder klant", "actionDeleteClient": "Verwijder klant",
"actionArchiveClient": "Archiveer client", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Dearchiveer client", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Blokkeer klant", "actionBlockClient": "Block Client",
"actionUnblockClient": "Deblokkeer client", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Klant bijwerken", "actionUpdateClient": "Klant bijwerken",
"actionListClients": "Lijst klanten", "actionListClients": "Lijst klanten",
"actionGetClient": "Client ophalen", "actionGetClient": "Client ophalen",
@@ -1167,14 +1167,14 @@
"searchProgress": "Zoeken...", "searchProgress": "Zoeken...",
"create": "Aanmaken", "create": "Aanmaken",
"orgs": "Organisaties", "orgs": "Organisaties",
"loginError": "Er is een onverwachte fout opgetreden. Probeer het opnieuw.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Inloggen is vereist voor je apparaat.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Wachtwoord vergeten?", "passwordForgot": "Wachtwoord vergeten?",
"otpAuth": "Tweestapsverificatie verificatie", "otpAuth": "Tweestapsverificatie verificatie",
"otpAuthDescription": "Voer de code van je authenticator-app of een van je reservekopiecodes voor het eenmalig gebruik in.", "otpAuthDescription": "Voer de code van je authenticator-app of een van je reservekopiecodes voor het eenmalig gebruik in.",
"otpAuthSubmit": "Code indienen", "otpAuthSubmit": "Code indienen",
"idpContinue": "Of ga verder met", "idpContinue": "Of ga verder met",
"otpAuthBack": "Terug naar wachtwoord", "otpAuthBack": "Back to Password",
"navbar": "Navigatiemenu", "navbar": "Navigatiemenu",
"navbarDescription": "Hoofd navigatie menu voor de applicatie", "navbarDescription": "Hoofd navigatie menu voor de applicatie",
"navbarDocsLink": "Documentatie", "navbarDocsLink": "Documentatie",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Overzicht.", "sidebarOverview": "Overzicht.",
"sidebarHome": "Startpagina", "sidebarHome": "Startpagina",
"sidebarSites": "Werkruimtes", "sidebarSites": "Werkruimtes",
"sidebarApprovals": "Goedkeuringsverzoeken", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Bronnen", "sidebarResources": "Bronnen",
"sidebarProxyResources": "Openbaar", "sidebarProxyResources": "Openbaar",
"sidebarClientResources": "Privé", "sidebarClientResources": "Privé",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Identiteit aanbieders", "sidebarIdentityProviders": "Identiteit aanbieders",
"sidebarLicense": "Licentie", "sidebarLicense": "Licentie",
"sidebarClients": "Clienten", "sidebarClients": "Clienten",
"sidebarUserDevices": "Gebruiker Apparaten", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Machines", "sidebarMachineClients": "Machines",
"sidebarDomains": "Domeinen", "sidebarDomains": "Domeinen",
"sidebarGeneral": "Beheren", "sidebarGeneral": "Beheren",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Er is een fout opgetreden bij het maken van het serverbeheerdersaccount.", "setupErrorCreateAdmin": "Er is een fout opgetreden bij het maken van het serverbeheerdersaccount.",
"certificateStatus": "Certificaatstatus", "certificateStatus": "Certificaatstatus",
"loading": "Bezig met laden", "loading": "Bezig met laden",
"loadingAnalytics": "Laden van Analytics", "loadingAnalytics": "Loading Analytics",
"restart": "Herstarten", "restart": "Herstarten",
"domains": "Domeinen", "domains": "Domeinen",
"domainsDescription": "Maak en beheer domeinen die beschikbaar zijn in de organisatie", "domainsDescription": "Maak en beheer domeinen die beschikbaar zijn in de organisatie",
@@ -1339,7 +1339,7 @@
"refreshError": "Het vernieuwen van gegevens is mislukt", "refreshError": "Het vernieuwen van gegevens is mislukt",
"verified": "Gecontroleerd", "verified": "Gecontroleerd",
"pending": "In afwachting", "pending": "In afwachting",
"pendingApproval": "Wachten op goedkeuring", "pendingApproval": "Pending Approval",
"sidebarBilling": "Facturering", "sidebarBilling": "Facturering",
"billing": "Facturering", "billing": "Facturering",
"orgBillingDescription": "Beheer factureringsinformatie en abonnementen", "orgBillingDescription": "Beheer factureringsinformatie en abonnementen",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Beveiligingssleutel succesvol verwijderd", "securityKeyRemoveSuccess": "Beveiligingssleutel succesvol verwijderd",
"securityKeyRemoveError": "Fout bij verwijderen van beveiligingssleutel", "securityKeyRemoveError": "Fout bij verwijderen van beveiligingssleutel",
"securityKeyLoadError": "Fout bij laden van beveiligingssleutels", "securityKeyLoadError": "Fout bij laden van beveiligingssleutels",
"securityKeyLogin": "Gebruik beveiligingssleutel", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Fout bij authenticatie met beveiligingssleutel", "securityKeyAuthError": "Fout bij authenticatie met beveiligingssleutel",
"securityKeyRecommendation": "Overweeg om een andere beveiligingssleutel te registreren op een ander apparaat om ervoor te zorgen dat u niet buitengesloten raakt van uw account.", "securityKeyRecommendation": "Overweeg om een andere beveiligingssleutel te registreren op een ander apparaat om ervoor te zorgen dat u niet buitengesloten raakt van uw account.",
"registering": "Registreren...", "registering": "Registreren...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Gezonde Interval", "IntervalSeconds": "Gezonde Interval",
"timeoutSeconds": "Timeout (sec)", "timeoutSeconds": "Timeout (sec)",
"timeIsInSeconds": "Tijd is in seconden", "timeIsInSeconds": "Tijd is in seconden",
"requireDeviceApproval": "Vereist goedkeuring van apparaat", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Gebruikers met deze rol hebben nieuwe apparaten nodig die door een beheerder zijn goedgekeurd voordat ze verbinding kunnen maken met bronnen en deze kunnen gebruiken.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Geen interne bronnen gevonden.", "resourcesTableNoInternalResourcesFound": "Geen interne bronnen gevonden.",
"resourcesTableDestination": "Bestemming", "resourcesTableDestination": "Bestemming",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias adres",
"resourcesTableAliasAddressInfo": "Dit adres is onderdeel van het hulpprogramma subnet van de organisatie. Het wordt gebruikt om aliasrecords op te lossen met behulp van interne DNS-resolutie.",
"resourcesTableClients": "Clienten", "resourcesTableClients": "Clienten",
"resourcesTableAndOnlyAccessibleInternally": "en zijn alleen intern toegankelijk wanneer verbonden met een client.", "resourcesTableAndOnlyAccessibleInternally": "en zijn alleen intern toegankelijk wanneer verbonden met een client.",
"resourcesTableNoTargets": "Geen doelen", "resourcesTableNoTargets": "Geen doelen",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Kies uw identiteitsprovider om door te gaan", "orgAuthChooseIdpDescription": "Kies uw identiteitsprovider om door te gaan",
"orgAuthNoIdpConfigured": "Deze organisatie heeft geen identiteitsproviders geconfigureerd. Je kunt in plaats daarvan inloggen met je Pangolin-identiteit.", "orgAuthNoIdpConfigured": "Deze organisatie heeft geen identiteitsproviders geconfigureerd. Je kunt in plaats daarvan inloggen met je Pangolin-identiteit.",
"orgAuthSignInWithPangolin": "Log in met Pangolin", "orgAuthSignInWithPangolin": "Log in met Pangolin",
"orgAuthSignInToOrg": "Log in bij een organisatie", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Organisatie Inloggen", "orgAuthSelectOrgTitle": "Organisatie Inloggen",
"orgAuthSelectOrgDescription": "Voer je organisatie-ID in om verder te gaan", "orgAuthSelectOrgDescription": "Voer je organisatie-ID in om verder te gaan",
"orgAuthOrgIdPlaceholder": "jouw-organisatie", "orgAuthOrgIdPlaceholder": "jouw-organisatie",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Code moet 9 tekens bevatten (bijv. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Code moet 9 tekens bevatten (bijv. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Ongeldige of verlopen code", "deviceCodeInvalidOrExpired": "Ongeldige of verlopen code",
"deviceCodeVerifyFailed": "Apparaatcode verifiëren mislukt", "deviceCodeVerifyFailed": "Apparaatcode verifiëren mislukt",
"deviceCodeValidating": "Apparaatcode valideren...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Apparaatmachtiging verifiëren...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Ingelogd als", "signedInAs": "Ingelogd als",
"deviceCodeEnterPrompt": "Voer de op het apparaat weergegeven code in", "deviceCodeEnterPrompt": "Voer de op het apparaat weergegeven code in",
"continue": "Doorgaan", "continue": "Doorgaan",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Toegang tot alle organisaties waar uw account toegang tot heeft", "deviceOrganizationsAccess": "Toegang tot alle organisaties waar uw account toegang tot heeft",
"deviceAuthorize": "Autoriseer {applicationName}", "deviceAuthorize": "Autoriseer {applicationName}",
"deviceConnected": "Apparaat verbonden!", "deviceConnected": "Apparaat verbonden!",
"deviceAuthorizedMessage": "Apparaat is gemachtigd om toegang te krijgen tot je account. Ga terug naar de client applicatie.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Pangoline Cloud", "pangolinCloud": "Pangoline Cloud",
"viewDevices": "Bekijk apparaten", "viewDevices": "Bekijk apparaten",
"viewDevicesDescription": "Beheer uw aangesloten apparaten", "viewDevicesDescription": "Beheer uw aangesloten apparaten",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Niet u? Gebruik een ander account.", "deviceLoginUseDifferentAccount": "Niet u? Gebruik een ander account.",
"deviceLoginDeviceRequestingAccessToAccount": "Een apparaat vraagt om toegang tot dit account.", "deviceLoginDeviceRequestingAccessToAccount": "Een apparaat vraagt om toegang tot dit account.",
"loginSelectAuthenticationMethod": "Selecteer een verificatiemethode om door te gaan.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Geen gegevens", "noData": "Geen gegevens",
"machineClients": "Machine Clienten", "machineClients": "Machine Clienten",
"install": "Installeren", "install": "Installeren",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "We hebben momenteel technische problemen. Probeer het later opnieuw.", "maintenanceScreenMessage": "We hebben momenteel technische problemen. Probeer het later opnieuw.",
"maintenanceScreenEstimatedCompletion": "Geschatte voltooiing:", "maintenanceScreenEstimatedCompletion": "Geschatte voltooiing:",
"createInternalResourceDialogDestinationRequired": "Bestemming is vereist", "createInternalResourceDialogDestinationRequired": "Bestemming is vereist",
"available": "Beschikbaar", "available": "Available",
"archived": "Gearchiveerd", "archived": "Archived",
"noArchivedDevices": "Geen gearchiveerde apparaten gevonden", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Apparaat gearchiveerd", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Het apparaat is met succes gearchiveerd.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Fout bij archiveren apparaat", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Kan apparaat niet archiveren", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Weet u zeker dat u dit apparaat wilt archiveren?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Het apparaat wordt gearchiveerd en verwijderd uit de lijst met actieve apparaten.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Archiveer apparaat", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Archiveer apparaat", "archiveDevice": "Archive Device",
"archive": "Archief", "archive": "Archive",
"deviceUnarchived": "Apparaat niet gearchiveerd", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Het apparaat is met succes gedearchiveerd.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Fout bij dearchiveren van apparaat", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Apparaat dearchiveren mislukt", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Dearchiveren", "unarchive": "Unarchive",
"archiveClient": "Archiveer client", "archiveClient": "Archive Client",
"archiveClientQuestion": "Weet u zeker dat u deze client wilt archiveren?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "De klant zal worden gearchiveerd en verwijderd uit de lijst met actieve cliënten.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Archiveer client", "archiveClientConfirm": "Archive Client",
"blockClient": "Blokkeer klant", "blockClient": "Block Client",
"blockClientQuestion": "Weet u zeker dat u deze cliënt wilt blokkeren?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Het apparaat zal worden gedwongen de verbinding te verbreken als het momenteel is verbonden. U kunt het apparaat later deblokkeren.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Blokkeer klant", "blockClientConfirm": "Block Client",
"active": "actief", "active": "Active",
"usernameOrEmail": "Gebruikersnaam of e-mailadres", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Selecteer uw organisatie", "selectYourOrganization": "Select your organization",
"signInTo": "Log in op", "signInTo": "Log in in to",
"signInWithPassword": "Ga verder met wachtwoord", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Geen verificatiemethoden beschikbaar voor deze organisatie.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Voer je wachtwoord in", "enterPassword": "Enter your password",
"enterMfaCode": "Voer de code van je authenticator-app in", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Gebruik uw beveiligingssleutel om in te loggen.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Wilt u een ander account gebruiken?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Door op de knoppen hieronder te klikken, erken je dat je gelezen en begrepen hebt en ga akkoord met de <termsOfService>Gebruiksvoorwaarden</termsOfService> en <privacyPolicy>Privacybeleid</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Algemene gebruiksvoorwaarden", "termsOfService": "Terms of Service",
"privacyPolicy": "Privacy Beleid", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Geen gebruiker gevonden met die gebruikersnaam.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Verifiëren", "verify": "Verify",
"signIn": "Log in", "signIn": "Sign In",
"forgotPassword": "Wachtwoord vergeten?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Als u eerder bent ingelogd, kunt u uw gebruikersnaam of e-mail hierboven invoeren om in plaats daarvan te verifiëren met de identiteitsprovider van uw organisatie! Het is makkelijk!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Toch doorgaan", "continueAnyway": "Continue anyway",
"dontShowAgain": "Niet meer weergeven", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Wist u dat?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Proberen je aan te melden?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Probeert u zich aan te melden via de identiteitsprovider van uw organisatie?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Log in of meld je aan bij je organisatie", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Gebruik een ander account", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Log in", "logIn": "Log In",
"deviceInformation": "Apparaat informatie", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informatie over het apparaat en de agent", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Apparaat beveiliging",
"deviceSecurityDescription": "Apparaat beveiligingsinformatie",
"platform": "Platform", "platform": "Platform",
"macosVersion": "macOS versie", "macosVersion": "macOS Version",
"windowsVersion": "Windows versie", "windowsVersion": "Windows Version",
"iosVersion": "iOS versie", "iosVersion": "iOS Version",
"androidVersion": "Android versie", "androidVersion": "Android Version",
"osVersion": "OS versie", "osVersion": "OS Version",
"kernelVersion": "Kernel versie", "kernelVersion": "Kernel Version",
"deviceModel": "Apparaat model", "deviceModel": "Device Model",
"serialNumber": "Serienummer", "serialNumber": "Serial Number",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Eerst gezien", "firstSeen": "First Seen",
"lastSeen": "Laatst gezien op", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometrie ingeschakeld", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Schijf versleuteld", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Firewall ingeschakeld", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Auto Updates Ingeschakeld", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM beschikbaar", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Systeemintegriteitsbescherming (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Firewall Verberg Modus", "block": "Block",
"linuxAppArmorEnabled": "Appharnas", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Apparaatinformatie en -instellingen bekijken", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Dit apparaat wacht op goedkeuring", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Dit apparaat is momenteel geblokkeerd. Het kan geen verbinding maken met bronnen tenzij het wordt gedeblokkeerd.", "connected": "Connected",
"unblockClient": "Deblokkeer client", "disconnected": "Disconnected",
"unblockClientDescription": "Het apparaat is gedeblokkeerd", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Dearchiveer client", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Het apparaat is gedearchiveerd", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Blokkeren", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Deblokkeer", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Apparaat Acties", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Apparaatstatus en toegang beheren", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Dit apparaat wacht op goedkeuring. Het zal niet in staat zijn verbinding te maken met bronnen totdat het is goedgekeurd.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Verbonden",
"disconnected": "Losgekoppeld",
"approvalsEmptyStateTitle": "Apparaat goedkeuringen niet ingeschakeld",
"approvalsEmptyStateDescription": "Apparaatgoedkeuringen voor rollen inschakelen om goedkeuring van de beheerder te vereisen voordat gebruikers nieuwe apparaten kunnen koppelen.",
"approvalsEmptyStateStep1Title": "Ga naar rollen",
"approvalsEmptyStateStep1Description": "Navigeer naar de rolinstellingen van uw organisatie om apparaatgoedkeuringen te configureren.",
"approvalsEmptyStateStep2Title": "Toestel goedkeuringen inschakelen",
"approvalsEmptyStateStep2Description": "Bewerk een rol en schakel de optie 'Vereist Apparaat Goedkeuringen' in. Gebruikers met deze rol hebben admin goedkeuring nodig voor nieuwe apparaten.",
"approvalsEmptyStatePreviewDescription": "Voorbeeld: Indien ingeschakeld, zullen in afwachting van apparaatverzoeken hier verschijnen om te beoordelen",
"approvalsEmptyStateButtonText": "Rollen beheren"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Połącz dowolną sieć", "sitesBannerTitle": "Połącz dowolną sieć",
"sitesBannerDescription": "Witryna to połączenie z siecią zdalną, które umożliwia Pangolinowi zapewnienie dostępu do zasobów, publicznych lub prywatnych, użytkownikom w dowolnym miejscu. Zainstaluj łącznik sieci w witrynie (Newt) w dowolnym miejscu, w którym możesz uruchomić binarkę lub kontener, aby ustanowić połączenie.", "sitesBannerDescription": "Witryna to połączenie z siecią zdalną, które umożliwia Pangolinowi zapewnienie dostępu do zasobów, publicznych lub prywatnych, użytkownikom w dowolnym miejscu. Zainstaluj łącznik sieci w witrynie (Newt) w dowolnym miejscu, w którym możesz uruchomić binarkę lub kontener, aby ustanowić połączenie.",
"sitesBannerButtonText": "Zainstaluj witrynę", "sitesBannerButtonText": "Zainstaluj witrynę",
"approvalsBannerTitle": "Zatwierdź lub odmów dostępu do urządzenia", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Przejrzyj i zatwierdzaj lub odmawiaj użytkownikom dostępu do urządzenia. Gdy wymagane jest zatwierdzenie urządzenia, użytkownicy muszą uzyskać zatwierdzenie administratora, zanim ich urządzenia będą mogły połączyć się z zasobami Twojej organizacji.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Dowiedz się więcej", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Utwórz witrynę", "siteCreate": "Utwórz witrynę",
"siteCreateDescription2": "Wykonaj poniższe kroki, aby utworzyć i połączyć nową witrynę", "siteCreateDescription2": "Wykonaj poniższe kroki, aby utworzyć i połączyć nową witrynę",
"siteCreateDescription": "Utwórz nową witrynę, aby rozpocząć łączenie zasobów", "siteCreateDescription": "Utwórz nową witrynę, aby rozpocząć łączenie zasobów",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Szukaj ról...", "accessRolesSearch": "Szukaj ról...",
"accessRolesAdd": "Dodaj rolę", "accessRolesAdd": "Dodaj rolę",
"accessRoleDelete": "Usuń rolę", "accessRoleDelete": "Usuń rolę",
"accessApprovalsManage": "Zarządzaj zatwierdzaniem", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Przeglądaj i zarządzaj oczekującymi zatwierdzeniami dostępu do tej organizacji", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Opis", "description": "Opis",
"inviteTitle": "Otwórz zaproszenia", "inviteTitle": "Otwórz zaproszenia",
"inviteDescription": "Zarządzaj zaproszeniami dla innych użytkowników do dołączenia do organizacji", "inviteDescription": "Zarządzaj zaproszeniami dla innych użytkowników do dołączenia do organizacji",
@@ -455,18 +455,18 @@
"selectDuration": "Wybierz okres", "selectDuration": "Wybierz okres",
"selectResource": "Wybierz zasób", "selectResource": "Wybierz zasób",
"filterByResource": "Filtruj według zasobów", "filterByResource": "Filtruj według zasobów",
"selectApprovalState": "Wybierz województwo zatwierdzające", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtruj według państwa zatwierdzenia", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Brak zatwierdzeń", "approvalListEmpty": "No approvals",
"approvalState": "Państwo zatwierdzające", "approvalState": "Approval State",
"approve": "Zatwierdź", "approve": "Approve",
"approved": "Zatwierdzone", "approved": "Approved",
"denied": "Odmowa", "denied": "Denied",
"deniedApproval": "Odrzucono zatwierdzenie", "deniedApproval": "Denied Approval",
"all": "Wszystko", "all": "All",
"deny": "Odmowa", "deny": "Deny",
"viewDetails": "Zobacz szczegóły", "viewDetails": "View Details",
"requestingNewDeviceApproval": "zażądano nowego urządzenia", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Resetuj filtry", "resetFilters": "Resetuj filtry",
"totalBlocked": "Żądania zablokowane przez Pangolina", "totalBlocked": "Żądania zablokowane przez Pangolina",
"totalRequests": "Wszystkich Żądań", "totalRequests": "Wszystkich Żądań",
@@ -746,28 +746,28 @@
"countries": "Kraje", "countries": "Kraje",
"accessRoleCreate": "Utwórz rolę", "accessRoleCreate": "Utwórz rolę",
"accessRoleCreateDescription": "Utwórz nową rolę aby zgrupować użytkowników i zarządzać ich uprawnieniami.", "accessRoleCreateDescription": "Utwórz nową rolę aby zgrupować użytkowników i zarządzać ich uprawnieniami.",
"accessRoleEdit": "Edytuj rolę", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Edytuj informacje o rolach.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Utwórz rolę", "accessRoleCreateSubmit": "Utwórz rolę",
"accessRoleCreated": "Rola utworzona", "accessRoleCreated": "Rola utworzona",
"accessRoleCreatedDescription": "Rola została pomyślnie utworzona.", "accessRoleCreatedDescription": "Rola została pomyślnie utworzona.",
"accessRoleErrorCreate": "Nie udało się utworzyć roli", "accessRoleErrorCreate": "Nie udało się utworzyć roli",
"accessRoleErrorCreateDescription": "Wystąpił błąd podczas tworzenia roli.", "accessRoleErrorCreateDescription": "Wystąpił błąd podczas tworzenia roli.",
"accessRoleUpdateSubmit": "Aktualizuj rolę", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rola zaktualizowana", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Rola została pomyślnie zaktualizowana.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Zatwierdzenie przetworzone", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Ustaw decyzję o zatwierdzeniu wniosku o zatwierdzenie.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Ustaw decyzję o odrzuceniu wniosku o zatwierdzenie.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Nie udało się zaktualizować roli", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Wystąpił błąd podczas aktualizowania roli.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Nie udało się przetworzyć zatwierdzenia", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Wystąpił błąd podczas przetwarzania zatwierdzenia.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Nowa rola jest wymagana", "accessRoleErrorNewRequired": "Nowa rola jest wymagana",
"accessRoleErrorRemove": "Nie udało się usunąć roli", "accessRoleErrorRemove": "Nie udało się usunąć roli",
"accessRoleErrorRemoveDescription": "Wystąpił błąd podczas usuwania roli.", "accessRoleErrorRemoveDescription": "Wystąpił błąd podczas usuwania roli.",
"accessRoleName": "Nazwa roli", "accessRoleName": "Nazwa roli",
"accessRoleQuestionRemove": "Zamierzasz usunąć rolę `{name}`. Nie możesz cofnąć tej czynności.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Usuń rolę", "accessRoleRemove": "Usuń rolę",
"accessRoleRemoveDescription": "Usuń rolę z organizacji", "accessRoleRemoveDescription": "Usuń rolę z organizacji",
"accessRoleRemoveSubmit": "Usuń rolę", "accessRoleRemoveSubmit": "Usuń rolę",
@@ -903,7 +903,7 @@
"inviteAlready": "Wygląda na to, że zostałeś już zaproszony!", "inviteAlready": "Wygląda na to, że zostałeś już zaproszony!",
"inviteAlreadyDescription": "Aby zaakceptować zaproszenie, musisz się zalogować lub utworzyć konto.", "inviteAlreadyDescription": "Aby zaakceptować zaproszenie, musisz się zalogować lub utworzyć konto.",
"signupQuestion": "Masz już konto?", "signupQuestion": "Masz już konto?",
"login": "Zaloguj się", "login": "Log In",
"resourceNotFound": "Nie znaleziono zasobu", "resourceNotFound": "Nie znaleziono zasobu",
"resourceNotFoundDescription": "Zasób, do którego próbujesz uzyskać dostęp, nie istnieje.", "resourceNotFoundDescription": "Zasób, do którego próbujesz uzyskać dostęp, nie istnieje.",
"pincodeRequirementsLength": "PIN musi składać się dokładnie z 6 cyfr", "pincodeRequirementsLength": "PIN musi składać się dokładnie z 6 cyfr",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Organizacja wymaga zmiany hasła co {maxDays} dni.", "passwordExpiryDescription": "Organizacja wymaga zmiany hasła co {maxDays} dni.",
"changePasswordNow": "Zmień hasło teraz", "changePasswordNow": "Zmień hasło teraz",
"pincodeAuth": "Kod uwierzytelniający", "pincodeAuth": "Kod uwierzytelniający",
"pincodeSubmit2": "Prześlij kod", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Zażądaj resetowania", "passwordResetSubmit": "Zażądaj resetowania",
"passwordResetAlreadyHaveCode": "Wprowadź kod", "passwordResetAlreadyHaveCode": "Wprowadź kod",
"passwordResetSmtpRequired": "Skontaktuj się z administratorem", "passwordResetSmtpRequired": "Skontaktuj się z administratorem",
"passwordResetSmtpRequiredDescription": "Aby zresetować hasło, wymagany jest kod resetowania hasła. Skontaktuj się z administratorem.", "passwordResetSmtpRequiredDescription": "Aby zresetować hasło, wymagany jest kod resetowania hasła. Skontaktuj się z administratorem.",
"passwordBack": "Powrót do hasła", "passwordBack": "Powrót do hasła",
"loginBack": "Wróć do strony logowania głównego", "loginBack": "Go back to main login page",
"signup": "Zarejestruj się", "signup": "Zarejestruj się",
"loginStart": "Zaloguj się, aby rozpocząć", "loginStart": "Zaloguj się, aby rozpocząć",
"idpOidcTokenValidating": "Walidacja tokena OIDC", "idpOidcTokenValidating": "Walidacja tokena OIDC",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Aktualizuj organizację IDP", "actionUpdateIdpOrg": "Aktualizuj organizację IDP",
"actionCreateClient": "Utwórz klienta", "actionCreateClient": "Utwórz klienta",
"actionDeleteClient": "Usuń klienta", "actionDeleteClient": "Usuń klienta",
"actionArchiveClient": "Zarchiwizuj klienta", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Usuń archiwizację klienta", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Zablokuj klienta", "actionBlockClient": "Block Client",
"actionUnblockClient": "Odblokuj klienta", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Aktualizuj klienta", "actionUpdateClient": "Aktualizuj klienta",
"actionListClients": "Lista klientów", "actionListClients": "Lista klientów",
"actionGetClient": "Pobierz klienta", "actionGetClient": "Pobierz klienta",
@@ -1167,14 +1167,14 @@
"searchProgress": "Szukaj...", "searchProgress": "Szukaj...",
"create": "Utwórz", "create": "Utwórz",
"orgs": "Organizacje", "orgs": "Organizacje",
"loginError": "Wystąpił nieoczekiwany błąd. Spróbuj ponownie.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Logowanie jest wymagane dla Twojego urządzenia.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Zapomniałeś hasła?", "passwordForgot": "Zapomniałeś hasła?",
"otpAuth": "Uwierzytelnianie dwuskładnikowe", "otpAuth": "Uwierzytelnianie dwuskładnikowe",
"otpAuthDescription": "Wprowadź kod z aplikacji uwierzytelniającej lub jeden z jednorazowych kodów zapasowych.", "otpAuthDescription": "Wprowadź kod z aplikacji uwierzytelniającej lub jeden z jednorazowych kodów zapasowych.",
"otpAuthSubmit": "Wyślij kod", "otpAuthSubmit": "Wyślij kod",
"idpContinue": "Lub kontynuuj z", "idpContinue": "Lub kontynuuj z",
"otpAuthBack": "Powrót do hasła", "otpAuthBack": "Back to Password",
"navbar": "Menu nawigacyjne", "navbar": "Menu nawigacyjne",
"navbarDescription": "Główne menu nawigacyjne aplikacji", "navbarDescription": "Główne menu nawigacyjne aplikacji",
"navbarDocsLink": "Dokumentacja", "navbarDocsLink": "Dokumentacja",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Przegląd", "sidebarOverview": "Przegląd",
"sidebarHome": "Strona główna", "sidebarHome": "Strona główna",
"sidebarSites": "Witryny", "sidebarSites": "Witryny",
"sidebarApprovals": "Wnioski o zatwierdzenie", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Zasoby", "sidebarResources": "Zasoby",
"sidebarProxyResources": "Publiczne", "sidebarProxyResources": "Publiczne",
"sidebarClientResources": "Prywatny", "sidebarClientResources": "Prywatny",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Dostawcy tożsamości", "sidebarIdentityProviders": "Dostawcy tożsamości",
"sidebarLicense": "Licencja", "sidebarLicense": "Licencja",
"sidebarClients": "Klienty", "sidebarClients": "Klienty",
"sidebarUserDevices": "Urządzenia użytkownika", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Maszyny", "sidebarMachineClients": "Maszyny",
"sidebarDomains": "Domeny", "sidebarDomains": "Domeny",
"sidebarGeneral": "Zarządzaj", "sidebarGeneral": "Zarządzaj",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Wystąpił błąd podczas tworzenia konta administratora serwera.", "setupErrorCreateAdmin": "Wystąpił błąd podczas tworzenia konta administratora serwera.",
"certificateStatus": "Status certyfikatu", "certificateStatus": "Status certyfikatu",
"loading": "Ładowanie", "loading": "Ładowanie",
"loadingAnalytics": "Ładowanie Analityki", "loadingAnalytics": "Loading Analytics",
"restart": "Uruchom ponownie", "restart": "Uruchom ponownie",
"domains": "Domeny", "domains": "Domeny",
"domainsDescription": "Tworzenie domen dostępnych w organizacji i zarządzanie nimi", "domainsDescription": "Tworzenie domen dostępnych w organizacji i zarządzanie nimi",
@@ -1339,7 +1339,7 @@
"refreshError": "Nie udało się odświeżyć danych", "refreshError": "Nie udało się odświeżyć danych",
"verified": "Zatwierdzony", "verified": "Zatwierdzony",
"pending": "Oczekuje", "pending": "Oczekuje",
"pendingApproval": "Oczekujące na zatwierdzenie", "pendingApproval": "Pending Approval",
"sidebarBilling": "Fakturowanie", "sidebarBilling": "Fakturowanie",
"billing": "Fakturowanie", "billing": "Fakturowanie",
"orgBillingDescription": "Zarządzaj informacjami rozliczeniowymi i subskrypcjami", "orgBillingDescription": "Zarządzaj informacjami rozliczeniowymi i subskrypcjami",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Klucz bezpieczeństwa został pomyślnie usunięty", "securityKeyRemoveSuccess": "Klucz bezpieczeństwa został pomyślnie usunięty",
"securityKeyRemoveError": "Błąd podczas usuwania klucza bezpieczeństwa", "securityKeyRemoveError": "Błąd podczas usuwania klucza bezpieczeństwa",
"securityKeyLoadError": "Błąd podczas ładowania kluczy bezpieczeństwa", "securityKeyLoadError": "Błąd podczas ładowania kluczy bezpieczeństwa",
"securityKeyLogin": "Użyj klucza bezpieczeństwa", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Błąd podczas uwierzytelniania kluczem bezpieczeństwa", "securityKeyAuthError": "Błąd podczas uwierzytelniania kluczem bezpieczeństwa",
"securityKeyRecommendation": "Rozważ zarejestrowanie innego klucza bezpieczeństwa na innym urządzeniu, aby upewnić się, że nie zostaniesz zablokowany z dostępu do swojego konta.", "securityKeyRecommendation": "Rozważ zarejestrowanie innego klucza bezpieczeństwa na innym urządzeniu, aby upewnić się, że nie zostaniesz zablokowany z dostępu do swojego konta.",
"registering": "Rejestracja...", "registering": "Rejestracja...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Interwał Zdrowy", "IntervalSeconds": "Interwał Zdrowy",
"timeoutSeconds": "Limit czasu (sek)", "timeoutSeconds": "Limit czasu (sek)",
"timeIsInSeconds": "Czas w sekundach", "timeIsInSeconds": "Czas w sekundach",
"requireDeviceApproval": "Wymagaj zatwierdzenia urządzenia", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Użytkownicy o tej roli potrzebują nowych urządzeń zatwierdzonych przez administratora, zanim będą mogli połączyć się i uzyskać dostęp do zasobów.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Nie znaleziono wewnętrznych zasobów.", "resourcesTableNoInternalResourcesFound": "Nie znaleziono wewnętrznych zasobów.",
"resourcesTableDestination": "Miejsce docelowe", "resourcesTableDestination": "Miejsce docelowe",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Adres aliasu",
"resourcesTableAliasAddressInfo": "Ten adres jest częścią podsieci użyteczności organizacji. Jest używany do rozwiązywania rekordów aliasu przy użyciu wewnętrznej rozdzielczości DNS.",
"resourcesTableClients": "Klientami", "resourcesTableClients": "Klientami",
"resourcesTableAndOnlyAccessibleInternally": "i są dostępne tylko wewnętrznie po połączeniu z klientem.", "resourcesTableAndOnlyAccessibleInternally": "i są dostępne tylko wewnętrznie po połączeniu z klientem.",
"resourcesTableNoTargets": "Brak celów", "resourcesTableNoTargets": "Brak celów",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Wybierz swojego dostawcę tożsamości, aby kontynuować", "orgAuthChooseIdpDescription": "Wybierz swojego dostawcę tożsamości, aby kontynuować",
"orgAuthNoIdpConfigured": "Ta organizacja nie ma skonfigurowanych żadnych dostawców tożsamości. Zamiast tego możesz zalogować się za pomocą swojej tożsamości Pangolin.", "orgAuthNoIdpConfigured": "Ta organizacja nie ma skonfigurowanych żadnych dostawców tożsamości. Zamiast tego możesz zalogować się za pomocą swojej tożsamości Pangolin.",
"orgAuthSignInWithPangolin": "Zaloguj się używając Pangolin", "orgAuthSignInWithPangolin": "Zaloguj się używając Pangolin",
"orgAuthSignInToOrg": "Zaloguj się do organizacji", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Logowanie do organizacji", "orgAuthSelectOrgTitle": "Logowanie do organizacji",
"orgAuthSelectOrgDescription": "Wprowadź identyfikator organizacji, aby kontynuować", "orgAuthSelectOrgDescription": "Wprowadź identyfikator organizacji, aby kontynuować",
"orgAuthOrgIdPlaceholder": "twoja-organizacja", "orgAuthOrgIdPlaceholder": "twoja-organizacja",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Kod musi mieć 9 znaków (np. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Kod musi mieć 9 znaków (np. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Nieprawidłowy lub wygasły kod", "deviceCodeInvalidOrExpired": "Nieprawidłowy lub wygasły kod",
"deviceCodeVerifyFailed": "Nie udało się zweryfikować kodu urządzenia", "deviceCodeVerifyFailed": "Nie udało się zweryfikować kodu urządzenia",
"deviceCodeValidating": "Sprawdzanie kodu urządzenia...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Weryfikowanie autoryzacji urządzenia...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Zalogowany jako", "signedInAs": "Zalogowany jako",
"deviceCodeEnterPrompt": "Wprowadź kod wyświetlany na urządzeniu", "deviceCodeEnterPrompt": "Wprowadź kod wyświetlany na urządzeniu",
"continue": "Kontynuuj", "continue": "Kontynuuj",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Dostęp do wszystkich organizacji, do których Twoje konto ma dostęp", "deviceOrganizationsAccess": "Dostęp do wszystkich organizacji, do których Twoje konto ma dostęp",
"deviceAuthorize": "Autoryzuj {applicationName}", "deviceAuthorize": "Autoryzuj {applicationName}",
"deviceConnected": "Urządzenie podłączone!", "deviceConnected": "Urządzenie podłączone!",
"deviceAuthorizedMessage": "Urządzenie jest autoryzowane do uzyskania dostępu do Twojego konta. Proszę wróć do aplikacji klienckiej.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Chmura Pangolin", "pangolinCloud": "Chmura Pangolin",
"viewDevices": "Zobacz urządzenia", "viewDevices": "Zobacz urządzenia",
"viewDevicesDescription": "Zarządzaj podłączonymi urządzeniami", "viewDevicesDescription": "Zarządzaj podłączonymi urządzeniami",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Nie ty? Użyj innego konta.", "deviceLoginUseDifferentAccount": "Nie ty? Użyj innego konta.",
"deviceLoginDeviceRequestingAccessToAccount": "Urządzenie żąda dostępu do tego konta.", "deviceLoginDeviceRequestingAccessToAccount": "Urządzenie żąda dostępu do tego konta.",
"loginSelectAuthenticationMethod": "Wybierz metodę uwierzytelniania aby kontynuować.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Brak danych", "noData": "Brak danych",
"machineClients": "Klienci maszyn", "machineClients": "Klienci maszyn",
"install": "Zainstaluj", "install": "Zainstaluj",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Obecnie doświadczamy problemów technicznych. Proszę sprawdzić ponownie wkrótce.", "maintenanceScreenMessage": "Obecnie doświadczamy problemów technicznych. Proszę sprawdzić ponownie wkrótce.",
"maintenanceScreenEstimatedCompletion": "Szacowane zakończenie:", "maintenanceScreenEstimatedCompletion": "Szacowane zakończenie:",
"createInternalResourceDialogDestinationRequired": "Miejsce docelowe jest wymagane", "createInternalResourceDialogDestinationRequired": "Miejsce docelowe jest wymagane",
"available": "Dostępny", "available": "Available",
"archived": "Zarchiwizowane", "archived": "Archived",
"noArchivedDevices": "Nie znaleziono zarchiwizowanych urządzeń", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Urządzenie zarchiwizowane", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Urządzenie zostało pomyślnie zarchiwizowane.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Błąd podczas archiwizacji urządzenia", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Nie udało się zarchiwizować urządzenia", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Czy na pewno chcesz zarchiwizować to urządzenie?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Urządzenie zostanie zarchiwizowane i usunięte z listy aktywnych urządzeń.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Archiwizuj urządzenie", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Archiwizuj urządzenie", "archiveDevice": "Archive Device",
"archive": "Archiwum", "archive": "Archive",
"deviceUnarchived": "Urządzenie niezarchiwizowane", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Urządzenie zostało pomyślnie usunięte.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Błąd podczas usuwania archiwizacji urządzenia", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Nie udało się odarchiwizować urządzenia", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Usuń z archiwum", "unarchive": "Unarchive",
"archiveClient": "Zarchiwizuj klienta", "archiveClient": "Archive Client",
"archiveClientQuestion": "Czy na pewno chcesz zarchiwizować tego klienta?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Klient zostanie zarchiwizowany i usunięty z listy aktywnych klientów.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Zarchiwizuj klienta", "archiveClientConfirm": "Archive Client",
"blockClient": "Zablokuj klienta", "blockClient": "Block Client",
"blockClientQuestion": "Czy na pewno chcesz zablokować tego klienta?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Urządzenie zostanie wymuszone do rozłączenia, jeśli jest obecnie podłączone. Możesz odblokować urządzenie później.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Zablokuj klienta", "blockClientConfirm": "Block Client",
"active": "Aktywne", "active": "Active",
"usernameOrEmail": "Nazwa użytkownika lub e-mail", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Wybierz swoją organizację", "selectYourOrganization": "Select your organization",
"signInTo": "Zaloguj się do", "signInTo": "Log in in to",
"signInWithPassword": "Kontynuuj z hasłem", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Brak dostępnych metod uwierzytelniania dla tej organizacji.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Wprowadź hasło", "enterPassword": "Enter your password",
"enterMfaCode": "Wprowadź kod z aplikacji uwierzytelniającej", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Aby się zalogować, użyj klucza bezpieczeństwa.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Potrzebujesz użyć innego konta?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Klikając na przycisk poniżej, potwierdzasz, że przeczytałeś, rozumiesz, i zaakceptuj <termsOfService>Warunki świadczenia usługi</termsOfService> i <privacyPolicy>Polityka prywatności</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Warunki korzystania z usługi", "termsOfService": "Terms of Service",
"privacyPolicy": "Polityka prywatności", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Nie znaleziono użytkownika o tej nazwie użytkownika.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Weryfikacja", "verify": "Verify",
"signIn": "Zaloguj się", "signIn": "Sign In",
"forgotPassword": "Zapomniałeś hasła?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Jeśli zalogowałeś się wcześniej, możesz wprowadzić nazwę użytkownika lub e-mail powyżej, aby uwierzytelnić się z dostawcą tożsamości organizacji. To łatwiejsze!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Kontynuuj mimo to", "continueAnyway": "Continue anyway",
"dontShowAgain": "Nie pokazuj ponownie", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Czy wiedziałeś?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Próbujesz się zalogować?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Czy próbujesz zalogować się za pośrednictwem dostawcy tożsamości organizacji?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Zamiast tego zaloguj się lub zarejestruj w swojej organizacji", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Użyj innego konta", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Zaloguj się", "logIn": "Log In",
"deviceInformation": "Informacje o urządzeniu", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informacje o urządzeniu i agentach", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Bezpieczeństwo urządzenia", "platform": "Platform",
"deviceSecurityDescription": "Informacje o bezpieczeństwie urządzenia", "macosVersion": "macOS Version",
"platform": "Platforma", "windowsVersion": "Windows Version",
"macosVersion": "Wersja macOS", "iosVersion": "iOS Version",
"windowsVersion": "Wersja Windows", "androidVersion": "Android Version",
"iosVersion": "Wersja iOS", "osVersion": "OS Version",
"androidVersion": "Wersja Androida", "kernelVersion": "Kernel Version",
"osVersion": "Wersja systemu operacyjnego", "deviceModel": "Device Model",
"kernelVersion": "Wersja jądra", "serialNumber": "Serial Number",
"deviceModel": "Model urządzenia",
"serialNumber": "Numer seryjny",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Widziany po raz pierwszy", "firstSeen": "First Seen",
"lastSeen": "Ostatnio widziane", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometria włączona", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Dysk zaszyfrowany", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Zapora włączona", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Automatyczne aktualizacje włączone", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM dostępne", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Ochrona integralności systemu (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Tryb Stealth zapory", "block": "Block",
"linuxAppArmorEnabled": "Zbroja aplikacji", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Wyświetl informacje o urządzeniu i ustawienia", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "To urządzenie czeka na zatwierdzenie", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "To urządzenie jest obecnie zablokowane. Nie będzie można połączyć się z żadnymi zasobami, chyba że zostanie odblokowane.", "connected": "Connected",
"unblockClient": "Odblokuj klienta", "disconnected": "Disconnected",
"unblockClientDescription": "Urządzenie zostało odblokowane", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Usuń archiwizację klienta", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Urządzenie zostało odarchiwizowane", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Blok", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Odblokuj", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Akcje urządzenia", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Zarządzaj stanem urządzenia i dostępem", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "To urządzenie oczekuje na zatwierdzenie. Nie będzie można połączyć się z zasobami, dopóki nie zostanie zatwierdzone.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Połączono",
"disconnected": "Rozłączony",
"approvalsEmptyStateTitle": "Zatwierdzanie urządzenia nie włączone",
"approvalsEmptyStateDescription": "Włącz zatwierdzanie urządzeń dla ról aby wymagać zgody administratora, zanim użytkownicy będą mogli podłączyć nowe urządzenia.",
"approvalsEmptyStateStep1Title": "Przejdź do ról",
"approvalsEmptyStateStep1Description": "Przejdź do ustawień ról swojej organizacji, aby skonfigurować zatwierdzenia urządzenia.",
"approvalsEmptyStateStep2Title": "Włącz zatwierdzanie urządzenia",
"approvalsEmptyStateStep2Description": "Edytuj rolę i włącz opcję \"Wymagaj zatwierdzenia urządzenia\". Użytkownicy z tą rolą będą potrzebowali zatwierdzenia administratora dla nowych urządzeń.",
"approvalsEmptyStatePreviewDescription": "Podgląd: Gdy włączone, oczekujące prośby o sprawdzenie pojawią się tutaj",
"approvalsEmptyStateButtonText": "Zarządzaj rolami"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Conectar a Qualquer Rede", "sitesBannerTitle": "Conectar a Qualquer Rede",
"sitesBannerDescription": "Um site é uma conexão a uma rede remota que permite ao Pangolin fornecer acesso a recursos, sejam eles públicos ou privados, a usuários em qualquer lugar. Instale o conector de rede do site (Newt) em qualquer lugar onde você possa executar um binário ou contêiner para estabelecer a conexão.", "sitesBannerDescription": "Um site é uma conexão a uma rede remota que permite ao Pangolin fornecer acesso a recursos, sejam eles públicos ou privados, a usuários em qualquer lugar. Instale o conector de rede do site (Newt) em qualquer lugar onde você possa executar um binário ou contêiner para estabelecer a conexão.",
"sitesBannerButtonText": "Instalar Site", "sitesBannerButtonText": "Instalar Site",
"approvalsBannerTitle": "Aprovar ou negar acesso ao dispositivo", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Revisar e aprovar ou negar solicitações de acesso ao dispositivo de usuários. Quando as aprovações do dispositivo são necessárias, os usuários devem obter a aprovação do administrador antes que seus dispositivos possam se conectar aos recursos da sua organização.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Saiba mais", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Criar site", "siteCreate": "Criar site",
"siteCreateDescription2": "Siga os passos abaixo para criar e conectar um novo site", "siteCreateDescription2": "Siga os passos abaixo para criar e conectar um novo site",
"siteCreateDescription": "Crie um novo site para começar a conectar os recursos", "siteCreateDescription": "Crie um novo site para começar a conectar os recursos",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Pesquisar funções...", "accessRolesSearch": "Pesquisar funções...",
"accessRolesAdd": "Adicionar função", "accessRolesAdd": "Adicionar função",
"accessRoleDelete": "Excluir Papel", "accessRoleDelete": "Excluir Papel",
"accessApprovalsManage": "Gerenciar aprovações", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Visualizar e gerenciar aprovações pendentes para acesso a esta organização", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Descrição:", "description": "Descrição:",
"inviteTitle": "Convites Abertos", "inviteTitle": "Convites Abertos",
"inviteDescription": "Gerenciar convites para outros usuários participarem da organização", "inviteDescription": "Gerenciar convites para outros usuários participarem da organização",
@@ -455,18 +455,18 @@
"selectDuration": "Selecionar duração", "selectDuration": "Selecionar duração",
"selectResource": "Selecionar Recurso", "selectResource": "Selecionar Recurso",
"filterByResource": "Filtrar por Recurso", "filterByResource": "Filtrar por Recurso",
"selectApprovalState": "Selecionar Estado de Aprovação", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Filtrar por estado de aprovação", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Sem aprovações", "approvalListEmpty": "No approvals",
"approvalState": "Estado de aprovação", "approvalState": "Approval State",
"approve": "Aprovar", "approve": "Approve",
"approved": "Aceito", "approved": "Approved",
"denied": "Negado", "denied": "Denied",
"deniedApproval": "Aprovação Negada", "deniedApproval": "Denied Approval",
"all": "Todos", "all": "All",
"deny": "Recusar", "deny": "Deny",
"viewDetails": "Visualizar Detalhes", "viewDetails": "View Details",
"requestingNewDeviceApproval": "solicitou um novo dispositivo", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Redefinir filtros", "resetFilters": "Redefinir filtros",
"totalBlocked": "Solicitações bloqueadas pelo Pangolin", "totalBlocked": "Solicitações bloqueadas pelo Pangolin",
"totalRequests": "Total de pedidos", "totalRequests": "Total de pedidos",
@@ -746,28 +746,28 @@
"countries": "Países", "countries": "Países",
"accessRoleCreate": "Criar Função", "accessRoleCreate": "Criar Função",
"accessRoleCreateDescription": "Crie uma nova função para agrupar utilizadores e gerir suas permissões.", "accessRoleCreateDescription": "Crie uma nova função para agrupar utilizadores e gerir suas permissões.",
"accessRoleEdit": "Editar Permissão", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Editar informações do papel.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Criar Função", "accessRoleCreateSubmit": "Criar Função",
"accessRoleCreated": "Função criada", "accessRoleCreated": "Função criada",
"accessRoleCreatedDescription": "A função foi criada com sucesso.", "accessRoleCreatedDescription": "A função foi criada com sucesso.",
"accessRoleErrorCreate": "Falha ao criar função", "accessRoleErrorCreate": "Falha ao criar função",
"accessRoleErrorCreateDescription": "Ocorreu um erro ao criar a função.", "accessRoleErrorCreateDescription": "Ocorreu um erro ao criar a função.",
"accessRoleUpdateSubmit": "Atualizar Função", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Função atualizada", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "A função foi atualizada com sucesso.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Aprovação processada", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Definir decisão de solicitação de aprovação para aprovada.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Definir decisão de solicitação de aprovação para negada.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Falha ao atualizar papel", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Ocorreu um erro ao atualizar a função.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Não foi possível processar a aprovação", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Ocorreu um erro ao processar a aprovação.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Nova função é necessária", "accessRoleErrorNewRequired": "Nova função é necessária",
"accessRoleErrorRemove": "Falha ao remover função", "accessRoleErrorRemove": "Falha ao remover função",
"accessRoleErrorRemoveDescription": "Ocorreu um erro ao remover a função.", "accessRoleErrorRemoveDescription": "Ocorreu um erro ao remover a função.",
"accessRoleName": "Nome da Função", "accessRoleName": "Nome da Função",
"accessRoleQuestionRemove": "Você está prestes a apagar o papel `{name}. Você não pode desfazer esta ação.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Remover Função", "accessRoleRemove": "Remover Função",
"accessRoleRemoveDescription": "Remover uma função da organização", "accessRoleRemoveDescription": "Remover uma função da organização",
"accessRoleRemoveSubmit": "Remover Função", "accessRoleRemoveSubmit": "Remover Função",
@@ -903,7 +903,7 @@
"inviteAlready": "Parece que já foi convidado!", "inviteAlready": "Parece que já foi convidado!",
"inviteAlreadyDescription": "Para aceitar o convite, deve iniciar sessão ou criar uma conta.", "inviteAlreadyDescription": "Para aceitar o convite, deve iniciar sessão ou criar uma conta.",
"signupQuestion": "Já tem uma conta?", "signupQuestion": "Já tem uma conta?",
"login": "Iniciar sessão", "login": "Log In",
"resourceNotFound": "Recurso Não Encontrado", "resourceNotFound": "Recurso Não Encontrado",
"resourceNotFoundDescription": "O recurso que está a tentar aceder não existe.", "resourceNotFoundDescription": "O recurso que está a tentar aceder não existe.",
"pincodeRequirementsLength": "O PIN deve ter exatamente 6 dígitos", "pincodeRequirementsLength": "O PIN deve ter exatamente 6 dígitos",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Esta organização exige que você altere sua senha a cada {maxDays} dias.", "passwordExpiryDescription": "Esta organização exige que você altere sua senha a cada {maxDays} dias.",
"changePasswordNow": "Alterar a senha agora", "changePasswordNow": "Alterar a senha agora",
"pincodeAuth": "Código do Autenticador", "pincodeAuth": "Código do Autenticador",
"pincodeSubmit2": "Enviar código", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Solicitar Redefinição", "passwordResetSubmit": "Solicitar Redefinição",
"passwordResetAlreadyHaveCode": "Inserir Código", "passwordResetAlreadyHaveCode": "Inserir Código",
"passwordResetSmtpRequired": "Por favor, contate o administrador", "passwordResetSmtpRequired": "Por favor, contate o administrador",
"passwordResetSmtpRequiredDescription": "É necessário um código de redefinição de senha para redefinir sua senha. Por favor, contate o administrador para assistência.", "passwordResetSmtpRequiredDescription": "É necessário um código de redefinição de senha para redefinir sua senha. Por favor, contate o administrador para assistência.",
"passwordBack": "Voltar à Palavra-passe", "passwordBack": "Voltar à Palavra-passe",
"loginBack": "Voltar para a página principal de acesso", "loginBack": "Go back to main login page",
"signup": "Registar", "signup": "Registar",
"loginStart": "Inicie sessão para começar", "loginStart": "Inicie sessão para começar",
"idpOidcTokenValidating": "A validar token OIDC", "idpOidcTokenValidating": "A validar token OIDC",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Atualizar Organização IDP", "actionUpdateIdpOrg": "Atualizar Organização IDP",
"actionCreateClient": "Criar Cliente", "actionCreateClient": "Criar Cliente",
"actionDeleteClient": "Excluir Cliente", "actionDeleteClient": "Excluir Cliente",
"actionArchiveClient": "Arquivar Cliente", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Desarquivar Cliente", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Bloco do Cliente", "actionBlockClient": "Block Client",
"actionUnblockClient": "Desbloquear Cliente", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Atualizar Cliente", "actionUpdateClient": "Atualizar Cliente",
"actionListClients": "Listar Clientes", "actionListClients": "Listar Clientes",
"actionGetClient": "Obter Cliente", "actionGetClient": "Obter Cliente",
@@ -1167,14 +1167,14 @@
"searchProgress": "Pesquisar...", "searchProgress": "Pesquisar...",
"create": "Criar", "create": "Criar",
"orgs": "Organizações", "orgs": "Organizações",
"loginError": "Ocorreu um erro inesperado. Por favor, tente novamente.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "O login é necessário para seu dispositivo.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Esqueceu a sua palavra-passe?", "passwordForgot": "Esqueceu a sua palavra-passe?",
"otpAuth": "Autenticação de Dois Fatores", "otpAuth": "Autenticação de Dois Fatores",
"otpAuthDescription": "Insira o código da sua aplicação de autenticação ou um dos seus códigos de backup de uso único.", "otpAuthDescription": "Insira o código da sua aplicação de autenticação ou um dos seus códigos de backup de uso único.",
"otpAuthSubmit": "Submeter Código", "otpAuthSubmit": "Submeter Código",
"idpContinue": "Ou continuar com", "idpContinue": "Ou continuar com",
"otpAuthBack": "Voltar à Palavra-passe", "otpAuthBack": "Back to Password",
"navbar": "Menu de Navegação", "navbar": "Menu de Navegação",
"navbarDescription": "Menu de navegação principal da aplicação", "navbarDescription": "Menu de navegação principal da aplicação",
"navbarDocsLink": "Documentação", "navbarDocsLink": "Documentação",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Geral", "sidebarOverview": "Geral",
"sidebarHome": "Residencial", "sidebarHome": "Residencial",
"sidebarSites": "sites", "sidebarSites": "sites",
"sidebarApprovals": "Solicitações de aprovação", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Recursos", "sidebarResources": "Recursos",
"sidebarProxyResources": "Público", "sidebarProxyResources": "Público",
"sidebarClientResources": "Privado", "sidebarClientResources": "Privado",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Provedores de identidade", "sidebarIdentityProviders": "Provedores de identidade",
"sidebarLicense": "Tipo:", "sidebarLicense": "Tipo:",
"sidebarClients": "Clientes", "sidebarClients": "Clientes",
"sidebarUserDevices": "Dispositivos do usuário", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Máquinas", "sidebarMachineClients": "Máquinas",
"sidebarDomains": "Domínios", "sidebarDomains": "Domínios",
"sidebarGeneral": "Gerir", "sidebarGeneral": "Gerir",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Ocorreu um erro ao criar a conta de administrador do servidor.", "setupErrorCreateAdmin": "Ocorreu um erro ao criar a conta de administrador do servidor.",
"certificateStatus": "Status do Certificado", "certificateStatus": "Status do Certificado",
"loading": "Carregando", "loading": "Carregando",
"loadingAnalytics": "Carregando Analytics", "loadingAnalytics": "Loading Analytics",
"restart": "Reiniciar", "restart": "Reiniciar",
"domains": "Domínios", "domains": "Domínios",
"domainsDescription": "Criar e gerenciar domínios disponíveis na organização", "domainsDescription": "Criar e gerenciar domínios disponíveis na organização",
@@ -1339,7 +1339,7 @@
"refreshError": "Falha ao atualizar dados", "refreshError": "Falha ao atualizar dados",
"verified": "Verificado", "verified": "Verificado",
"pending": "Pendente", "pending": "Pendente",
"pendingApproval": "Aprovação pendente", "pendingApproval": "Pending Approval",
"sidebarBilling": "Faturamento", "sidebarBilling": "Faturamento",
"billing": "Faturamento", "billing": "Faturamento",
"orgBillingDescription": "Gerenciar informações e assinaturas de cobrança", "orgBillingDescription": "Gerenciar informações e assinaturas de cobrança",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Chave de segurança removida com sucesso", "securityKeyRemoveSuccess": "Chave de segurança removida com sucesso",
"securityKeyRemoveError": "Erro ao remover chave de segurança", "securityKeyRemoveError": "Erro ao remover chave de segurança",
"securityKeyLoadError": "Erro ao carregar chaves de segurança", "securityKeyLoadError": "Erro ao carregar chaves de segurança",
"securityKeyLogin": "Usar chave de segurança", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Erro ao autenticar com chave de segurança", "securityKeyAuthError": "Erro ao autenticar com chave de segurança",
"securityKeyRecommendation": "Considere registrar outra chave de segurança em um dispositivo diferente para garantir que você não fique bloqueado da sua conta.", "securityKeyRecommendation": "Considere registrar outra chave de segurança em um dispositivo diferente para garantir que você não fique bloqueado da sua conta.",
"registering": "Registrando...", "registering": "Registrando...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Intervalo Saudável", "IntervalSeconds": "Intervalo Saudável",
"timeoutSeconds": "Tempo limite (seg)", "timeoutSeconds": "Tempo limite (seg)",
"timeIsInSeconds": "O tempo está em segundos", "timeIsInSeconds": "O tempo está em segundos",
"requireDeviceApproval": "Exigir aprovação do dispositivo", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Usuários com esta função precisam de novos dispositivos aprovados por um administrador antes que eles possam se conectar e acessar recursos.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Nenhum recurso interno encontrado.", "resourcesTableNoInternalResourcesFound": "Nenhum recurso interno encontrado.",
"resourcesTableDestination": "Destino", "resourcesTableDestination": "Destino",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Endereço do Pseudônimo",
"resourcesTableAliasAddressInfo": "Este endereço faz parte da sub-rede de utilitários da organização. É usado para resolver registros de alias usando resolução de DNS interno.",
"resourcesTableClients": "Clientes", "resourcesTableClients": "Clientes",
"resourcesTableAndOnlyAccessibleInternally": "e são acessíveis apenas internamente quando conectados com um cliente.", "resourcesTableAndOnlyAccessibleInternally": "e são acessíveis apenas internamente quando conectados com um cliente.",
"resourcesTableNoTargets": "Nenhum alvo", "resourcesTableNoTargets": "Nenhum alvo",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Escolha o seu provedor de identidade para continuar", "orgAuthChooseIdpDescription": "Escolha o seu provedor de identidade para continuar",
"orgAuthNoIdpConfigured": "Esta organização não tem nenhum provedor de identidade configurado. Você pode entrar com a identidade do seu Pangolin.", "orgAuthNoIdpConfigured": "Esta organização não tem nenhum provedor de identidade configurado. Você pode entrar com a identidade do seu Pangolin.",
"orgAuthSignInWithPangolin": "Entrar com o Pangolin", "orgAuthSignInWithPangolin": "Entrar com o Pangolin",
"orgAuthSignInToOrg": "Fazer login em uma organização", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Entrada da Organização", "orgAuthSelectOrgTitle": "Entrada da Organização",
"orgAuthSelectOrgDescription": "Digite seu ID da organização para continuar", "orgAuthSelectOrgDescription": "Digite seu ID da organização para continuar",
"orgAuthOrgIdPlaceholder": "sua-organização", "orgAuthOrgIdPlaceholder": "sua-organização",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "O código deve ter 9 caracteres (ex.: A1AJ-N5JD)", "deviceCodeInvalidFormat": "O código deve ter 9 caracteres (ex.: A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Código inválido ou expirado", "deviceCodeInvalidOrExpired": "Código inválido ou expirado",
"deviceCodeVerifyFailed": "Falha ao verificar o código do dispositivo", "deviceCodeVerifyFailed": "Falha ao verificar o código do dispositivo",
"deviceCodeValidating": "Validando código do dispositivo...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Verificando autorização do dispositivo...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Sessão iniciada como", "signedInAs": "Sessão iniciada como",
"deviceCodeEnterPrompt": "Digite o código exibido no dispositivo", "deviceCodeEnterPrompt": "Digite o código exibido no dispositivo",
"continue": "Continuar", "continue": "Continuar",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Acesso a todas as organizações que sua conta tem acesso a", "deviceOrganizationsAccess": "Acesso a todas as organizações que sua conta tem acesso a",
"deviceAuthorize": "Autorizar {applicationName}", "deviceAuthorize": "Autorizar {applicationName}",
"deviceConnected": "Dispositivo Conectado!", "deviceConnected": "Dispositivo Conectado!",
"deviceAuthorizedMessage": "O dispositivo está autorizado a acessar sua conta. Por favor, retorne ao aplicativo cliente.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Nuvem do Pangolin", "pangolinCloud": "Nuvem do Pangolin",
"viewDevices": "Ver Dispositivos", "viewDevices": "Ver Dispositivos",
"viewDevicesDescription": "Gerencie seus dispositivos conectados", "viewDevicesDescription": "Gerencie seus dispositivos conectados",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Não é você? Use uma conta diferente.", "deviceLoginUseDifferentAccount": "Não é você? Use uma conta diferente.",
"deviceLoginDeviceRequestingAccessToAccount": "Um dispositivo está solicitando acesso a essa conta.", "deviceLoginDeviceRequestingAccessToAccount": "Um dispositivo está solicitando acesso a essa conta.",
"loginSelectAuthenticationMethod": "Selecione um método de autenticação para continuar.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Nenhum dado encontrado", "noData": "Nenhum dado encontrado",
"machineClients": "Clientes de máquina", "machineClients": "Clientes de máquina",
"install": "Instale", "install": "Instale",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Estamos enfrentando dificuldades técnicas no momento. Por favor, volte em breve.", "maintenanceScreenMessage": "Estamos enfrentando dificuldades técnicas no momento. Por favor, volte em breve.",
"maintenanceScreenEstimatedCompletion": "Conclusão Estimada:", "maintenanceScreenEstimatedCompletion": "Conclusão Estimada:",
"createInternalResourceDialogDestinationRequired": "Destino é obrigatório", "createInternalResourceDialogDestinationRequired": "Destino é obrigatório",
"available": "Disponível", "available": "Available",
"archived": "Arquivado", "archived": "Archived",
"noArchivedDevices": "Nenhum dispositivo arquivado encontrado", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Dispositivo arquivado", "deviceArchived": "Device archived",
"deviceArchivedDescription": "O dispositivo foi arquivado com sucesso.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Erro ao arquivar dispositivo", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Falha ao arquivar dispositivo", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Tem certeza que deseja arquivar este dispositivo?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "O dispositivo será arquivado e removido da sua lista de dispositivos ativos.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Arquivar dispositivo", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Arquivar dispositivo", "archiveDevice": "Archive Device",
"archive": "Arquivo", "archive": "Archive",
"deviceUnarchived": "Dispositivo desarquivado", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "O dispositivo foi desarquivado com sucesso.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Erro ao desarquivar dispositivo", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Falha ao desarquivar dispositivo", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Desarquivar", "unarchive": "Unarchive",
"archiveClient": "Arquivar Cliente", "archiveClient": "Archive Client",
"archiveClientQuestion": "Tem certeza que deseja arquivar este cliente?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "O cliente será arquivado e removido da sua lista de clientes ativos.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Arquivar Cliente", "archiveClientConfirm": "Archive Client",
"blockClient": "Bloco do Cliente", "blockClient": "Block Client",
"blockClientQuestion": "Tem certeza que deseja bloquear este cliente?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "O dispositivo será forçado a desconectar se estiver conectado. Você pode desbloquear o dispositivo mais tarde.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Bloco do Cliente", "blockClientConfirm": "Block Client",
"active": "ativo", "active": "Active",
"usernameOrEmail": "Usuário ou Email", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Selecione sua organização", "selectYourOrganization": "Select your organization",
"signInTo": "Iniciar sessão em", "signInTo": "Log in in to",
"signInWithPassword": "Continuar com a senha", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Nenhum método de autenticação disponível para esta organização.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Digite sua senha", "enterPassword": "Enter your password",
"enterMfaCode": "Insira o código do seu aplicativo autenticador", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Por favor, utilize sua chave de segurança para entrar.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Precisa usar uma conta diferente?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Ao clicar nos botões abaixo, você reconhece que leu, entende e concorda com os <termsOfService>Termos de Serviço</termsOfService> e a <privacyPolicy>Política de Privacidade</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Termos de Serviço", "termsOfService": "Terms of Service",
"privacyPolicy": "Política de Privacidade", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Nenhum usuário encontrado com este nome de usuário.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Verificar", "verify": "Verify",
"signIn": "Iniciar sessão", "signIn": "Sign In",
"forgotPassword": "Esqueceu a senha?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Se você já fez login antes, você pode digitar seu nome de usuário ou e-mail acima para autenticar com o provedor de identidade da sua organização. É mais fácil!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Continuar mesmo assim", "continueAnyway": "Continue anyway",
"dontShowAgain": "Não mostrar novamente", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Você sabia?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Tentando fazer login?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Você está tentando entrar através do provedor de identidade da sua organização?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Faça login ou inscreva-se com sua organização em vez disso", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Use uma Conta Diferente", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Iniciar sessão", "logIn": "Log In",
"deviceInformation": "Informações do dispositivo", "deviceInformation": "Device Information",
"deviceInformationDescription": "Informações sobre o dispositivo e o agente", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Segurança do dispositivo", "platform": "Platform",
"deviceSecurityDescription": "Informações sobre postagem de segurança", "macosVersion": "macOS Version",
"platform": "Plataforma", "windowsVersion": "Windows Version",
"macosVersion": "Versão do macOS", "iosVersion": "iOS Version",
"windowsVersion": "Versão do Windows", "androidVersion": "Android Version",
"iosVersion": "Versão para iOS", "osVersion": "OS Version",
"androidVersion": "Versão do Android", "kernelVersion": "Kernel Version",
"osVersion": "Versão do SO", "deviceModel": "Device Model",
"kernelVersion": "Versão do Kernel", "serialNumber": "Serial Number",
"deviceModel": "Modelo do dispositivo",
"serialNumber": "Número de Série",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Visto primeiro", "firstSeen": "First Seen",
"lastSeen": "Visto por último", "lastSeen": "Last Seen",
"biometricsEnabled": "Biometria habilitada", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Disco criptografado", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Firewall habilitado", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Atualizações Automáticas Habilitadas", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM disponível", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Proteção da Integridade do Sistema (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Modo Furtivo do Firewall", "block": "Block",
"linuxAppArmorEnabled": "AppArmor", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Ver informações e configurações do dispositivo", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Este dispositivo está aguardando aprovação", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Este dispositivo está bloqueado no momento. Ele não será capaz de se conectar a qualquer recurso a menos que seja desbloqueado.", "connected": "Connected",
"unblockClient": "Desbloquear Cliente", "disconnected": "Disconnected",
"unblockClientDescription": "O dispositivo foi desbloqueado", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Desarquivar Cliente", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "O dispositivo foi desarquivado", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Bloquear", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Desbloquear", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Ações do dispositivo", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Gerenciar status e acesso do dispositivo", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Este dispositivo está pendente de aprovação. Não será possível conectar-se a recursos até ser aprovado.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Conectado",
"disconnected": "Desconectado",
"approvalsEmptyStateTitle": "Aprovações do dispositivo não habilitado",
"approvalsEmptyStateDescription": "Habilitar aprovações do dispositivo para cargos que exigem aprovação do administrador antes que os usuários possam conectar novos dispositivos.",
"approvalsEmptyStateStep1Title": "Ir para Funções",
"approvalsEmptyStateStep1Description": "Navegue até as configurações dos papéis da sua organização para configurar as aprovações de dispositivo.",
"approvalsEmptyStateStep2Title": "Habilitar Aprovações do Dispositivo",
"approvalsEmptyStateStep2Description": "Editar uma função e habilitar a opção 'Exigir aprovação de dispositivos'. Usuários com essa função precisarão de aprovação de administrador para novos dispositivos.",
"approvalsEmptyStatePreviewDescription": "Pré-visualização: Quando ativado, solicitações de dispositivo pendentes aparecerão aqui para revisão",
"approvalsEmptyStateButtonText": "Gerir Funções"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Подключить любую сеть", "sitesBannerTitle": "Подключить любую сеть",
"sitesBannerDescription": "Сайт — это соединение с удаленной сетью, которое позволяет Pangolin предоставлять доступ к ресурсам, будь они общедоступными или частными, пользователям в любом месте. Установите сетевой коннектор сайта (Newt) там, где можно запустить исполняемый файл или контейнер, чтобы установить соединение.", "sitesBannerDescription": "Сайт — это соединение с удаленной сетью, которое позволяет Pangolin предоставлять доступ к ресурсам, будь они общедоступными или частными, пользователям в любом месте. Установите сетевой коннектор сайта (Newt) там, где можно запустить исполняемый файл или контейнер, чтобы установить соединение.",
"sitesBannerButtonText": "Установить сайт", "sitesBannerButtonText": "Установить сайт",
"approvalsBannerTitle": "Одобрить или запретить доступ к устройству", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Просмотрите и подтвердите или отклоните запросы на доступ к устройству от пользователей. Когда требуется подтверждение устройства, пользователи должны получить одобрение администратора, прежде чем их устройства смогут подключиться к ресурсам вашей организации.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Узнать больше", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Создать сайт", "siteCreate": "Создать сайт",
"siteCreateDescription2": "Следуйте инструкциям ниже для создания и подключения нового сайта", "siteCreateDescription2": "Следуйте инструкциям ниже для создания и подключения нового сайта",
"siteCreateDescription": "Создайте новый сайт для начала подключения ресурсов", "siteCreateDescription": "Создайте новый сайт для начала подключения ресурсов",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Поиск ролей...", "accessRolesSearch": "Поиск ролей...",
"accessRolesAdd": "Добавить роль", "accessRolesAdd": "Добавить роль",
"accessRoleDelete": "Удалить роль", "accessRoleDelete": "Удалить роль",
"accessApprovalsManage": "Управление утверждениями", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Просмотр и управление утверждениями в ожидании доступа к этой организации", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Описание", "description": "Описание",
"inviteTitle": "Открытые приглашения", "inviteTitle": "Открытые приглашения",
"inviteDescription": "Управление приглашениями для присоединения других пользователей к организации", "inviteDescription": "Управление приглашениями для присоединения других пользователей к организации",
@@ -455,18 +455,18 @@
"selectDuration": "Укажите срок действия", "selectDuration": "Укажите срок действия",
"selectResource": "Выберите ресурс", "selectResource": "Выберите ресурс",
"filterByResource": "Фильтровать по ресурсам", "filterByResource": "Фильтровать по ресурсам",
"selectApprovalState": "Выберите состояние одобрения", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Фильтр по состоянию утверждения", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Нет утверждений", "approvalListEmpty": "No approvals",
"approvalState": "Состояние одобрения", "approvalState": "Approval State",
"approve": "Одобрить", "approve": "Approve",
"approved": "Одобрено", "approved": "Approved",
"denied": "Отказано", "denied": "Denied",
"deniedApproval": "Отказано в одобрении", "deniedApproval": "Denied Approval",
"all": "Все", "all": "All",
"deny": "Запретить", "deny": "Deny",
"viewDetails": "Детали", "viewDetails": "View Details",
"requestingNewDeviceApproval": "запросил новое устройство", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Сбросить фильтры", "resetFilters": "Сбросить фильтры",
"totalBlocked": "Запросы заблокированы Панголином", "totalBlocked": "Запросы заблокированы Панголином",
"totalRequests": "Всего запросов", "totalRequests": "Всего запросов",
@@ -746,28 +746,28 @@
"countries": "Страны", "countries": "Страны",
"accessRoleCreate": "Создание роли", "accessRoleCreate": "Создание роли",
"accessRoleCreateDescription": "Создайте новую роль для группы пользователей и выдавайте им разрешения.", "accessRoleCreateDescription": "Создайте новую роль для группы пользователей и выдавайте им разрешения.",
"accessRoleEdit": "Изменить роль", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Редактировать информацию о роли.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Создать роль", "accessRoleCreateSubmit": "Создать роль",
"accessRoleCreated": "Роль создана", "accessRoleCreated": "Роль создана",
"accessRoleCreatedDescription": "Роль была успешно создана.", "accessRoleCreatedDescription": "Роль была успешно создана.",
"accessRoleErrorCreate": "Не удалось создать роль", "accessRoleErrorCreate": "Не удалось создать роль",
"accessRoleErrorCreateDescription": "Произошла ошибка при создании роли.", "accessRoleErrorCreateDescription": "Произошла ошибка при создании роли.",
"accessRoleUpdateSubmit": "Обновить роль", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Роль обновлена", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Роль была успешно обновлена.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Выполнено утверждение", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Принять решение об утверждении запроса.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Отказано в запросе об утверждении.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Не удалось обновить роль", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Произошла ошибка при обновлении роли.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Не удалось обработать подтверждение", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Произошла ошибка при обработке одобрения.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Новая роль обязательна", "accessRoleErrorNewRequired": "Новая роль обязательна",
"accessRoleErrorRemove": "Не удалось удалить роль", "accessRoleErrorRemove": "Не удалось удалить роль",
"accessRoleErrorRemoveDescription": "Произошла ошибка при удалении роли.", "accessRoleErrorRemoveDescription": "Произошла ошибка при удалении роли.",
"accessRoleName": "Название роли", "accessRoleName": "Название роли",
"accessRoleQuestionRemove": "Вы собираетесь удалить `{name}` роль. Это действие нельзя отменить.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Удалить роль", "accessRoleRemove": "Удалить роль",
"accessRoleRemoveDescription": "Удалить роль из организации", "accessRoleRemoveDescription": "Удалить роль из организации",
"accessRoleRemoveSubmit": "Удалить роль", "accessRoleRemoveSubmit": "Удалить роль",
@@ -903,7 +903,7 @@
"inviteAlready": "Похоже, вы были приглашены!", "inviteAlready": "Похоже, вы были приглашены!",
"inviteAlreadyDescription": "Чтобы принять приглашение, вы должны войти или создать учётную запись.", "inviteAlreadyDescription": "Чтобы принять приглашение, вы должны войти или создать учётную запись.",
"signupQuestion": "Уже есть учётная запись?", "signupQuestion": "Уже есть учётная запись?",
"login": "Войти", "login": "Log In",
"resourceNotFound": "Ресурс не найден", "resourceNotFound": "Ресурс не найден",
"resourceNotFoundDescription": "Ресурс, к которому вы пытаетесь получить доступ, не существует.", "resourceNotFoundDescription": "Ресурс, к которому вы пытаетесь получить доступ, не существует.",
"pincodeRequirementsLength": "PIN должен состоять ровно из 6 цифр", "pincodeRequirementsLength": "PIN должен состоять ровно из 6 цифр",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Эта организация требует смены пароля каждые {maxDays} дней.", "passwordExpiryDescription": "Эта организация требует смены пароля каждые {maxDays} дней.",
"changePasswordNow": "Изменить пароль сейчас", "changePasswordNow": "Изменить пароль сейчас",
"pincodeAuth": "Код аутентификатора", "pincodeAuth": "Код аутентификатора",
"pincodeSubmit2": "Отправить код", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Запросить сброс", "passwordResetSubmit": "Запросить сброс",
"passwordResetAlreadyHaveCode": "Введите код", "passwordResetAlreadyHaveCode": "Введите код",
"passwordResetSmtpRequired": "Пожалуйста, обратитесь к администратору", "passwordResetSmtpRequired": "Пожалуйста, обратитесь к администратору",
"passwordResetSmtpRequiredDescription": "Для сброса пароля необходим код сброса пароля. Обратитесь к администратору за помощью.", "passwordResetSmtpRequiredDescription": "Для сброса пароля необходим код сброса пароля. Обратитесь к администратору за помощью.",
"passwordBack": "Назад к паролю", "passwordBack": "Назад к паролю",
"loginBack": "Вернуться на главную страницу входа", "loginBack": "Go back to main login page",
"signup": "Регистрация", "signup": "Регистрация",
"loginStart": "Войдите для начала работы", "loginStart": "Войдите для начала работы",
"idpOidcTokenValidating": "Проверка OIDC токена", "idpOidcTokenValidating": "Проверка OIDC токена",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Обновить организацию IDP", "actionUpdateIdpOrg": "Обновить организацию IDP",
"actionCreateClient": "Создать Клиента", "actionCreateClient": "Создать Клиента",
"actionDeleteClient": "Удалить Клиента", "actionDeleteClient": "Удалить Клиента",
"actionArchiveClient": "Архивировать клиента", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "Разархивировать клиента", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "Блокировать клиента", "actionBlockClient": "Block Client",
"actionUnblockClient": "Разблокировать клиента", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Обновить Клиента", "actionUpdateClient": "Обновить Клиента",
"actionListClients": "Список Клиентов", "actionListClients": "Список Клиентов",
"actionGetClient": "Получить Клиента", "actionGetClient": "Получить Клиента",
@@ -1167,14 +1167,14 @@
"searchProgress": "Поиск...", "searchProgress": "Поиск...",
"create": "Создать", "create": "Создать",
"orgs": "Организации", "orgs": "Организации",
"loginError": "Произошла непредвиденная ошибка. Пожалуйста, попробуйте еще раз.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Логин необходим для вашего устройства.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Забыли пароль?", "passwordForgot": "Забыли пароль?",
"otpAuth": "Двухфакторная аутентификация", "otpAuth": "Двухфакторная аутентификация",
"otpAuthDescription": "Введите код из вашего приложения-аутентификатора или один из ваших одноразовых резервных кодов.", "otpAuthDescription": "Введите код из вашего приложения-аутентификатора или один из ваших одноразовых резервных кодов.",
"otpAuthSubmit": "Отправить код", "otpAuthSubmit": "Отправить код",
"idpContinue": "Или продолжить с", "idpContinue": "Или продолжить с",
"otpAuthBack": "Назад к паролю", "otpAuthBack": "Back to Password",
"navbar": "Навигационное меню", "navbar": "Навигационное меню",
"navbarDescription": "Главное навигационное меню приложения", "navbarDescription": "Главное навигационное меню приложения",
"navbarDocsLink": "Документация", "navbarDocsLink": "Документация",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Обзор", "sidebarOverview": "Обзор",
"sidebarHome": "Главная", "sidebarHome": "Главная",
"sidebarSites": "Сайты", "sidebarSites": "Сайты",
"sidebarApprovals": "Запросы на утверждение", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Ресурсы", "sidebarResources": "Ресурсы",
"sidebarProxyResources": "Публичный", "sidebarProxyResources": "Публичный",
"sidebarClientResources": "Приватный", "sidebarClientResources": "Приватный",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Поставщики удостоверений", "sidebarIdentityProviders": "Поставщики удостоверений",
"sidebarLicense": "Лицензия", "sidebarLicense": "Лицензия",
"sidebarClients": "Клиенты", "sidebarClients": "Клиенты",
"sidebarUserDevices": "Устройства пользователя", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Машины", "sidebarMachineClients": "Машины",
"sidebarDomains": "Домены", "sidebarDomains": "Домены",
"sidebarGeneral": "Управление", "sidebarGeneral": "Управление",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Произошла ошибка при создании учётной записи администратора сервера.", "setupErrorCreateAdmin": "Произошла ошибка при создании учётной записи администратора сервера.",
"certificateStatus": "Статус сертификата", "certificateStatus": "Статус сертификата",
"loading": "Загрузка", "loading": "Загрузка",
"loadingAnalytics": "Загрузка аналитики", "loadingAnalytics": "Loading Analytics",
"restart": "Перезагрузка", "restart": "Перезагрузка",
"domains": "Домены", "domains": "Домены",
"domainsDescription": "Создание и управление доменами, доступными в организации", "domainsDescription": "Создание и управление доменами, доступными в организации",
@@ -1339,7 +1339,7 @@
"refreshError": "Не удалось обновить данные", "refreshError": "Не удалось обновить данные",
"verified": "Подтверждено", "verified": "Подтверждено",
"pending": "В ожидании", "pending": "В ожидании",
"pendingApproval": "Ожидает утверждения", "pendingApproval": "Pending Approval",
"sidebarBilling": "Выставление счетов", "sidebarBilling": "Выставление счетов",
"billing": "Выставление счетов", "billing": "Выставление счетов",
"orgBillingDescription": "Управление платежной информацией и подписками", "orgBillingDescription": "Управление платежной информацией и подписками",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Ключ безопасности успешно удален", "securityKeyRemoveSuccess": "Ключ безопасности успешно удален",
"securityKeyRemoveError": "Не удалось удалить ключ безопасности", "securityKeyRemoveError": "Не удалось удалить ключ безопасности",
"securityKeyLoadError": "Не удалось загрузить ключи безопасности", "securityKeyLoadError": "Не удалось загрузить ключи безопасности",
"securityKeyLogin": "Использовать ключ безопасности", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Не удалось аутентифицироваться с ключом безопасности", "securityKeyAuthError": "Не удалось аутентифицироваться с ключом безопасности",
"securityKeyRecommendation": "Зарегистрируйте резервный ключ безопасности на другом устройстве, чтобы всегда иметь доступ к вашему аккаунту.", "securityKeyRecommendation": "Зарегистрируйте резервный ключ безопасности на другом устройстве, чтобы всегда иметь доступ к вашему аккаунту.",
"registering": "Регистрация...", "registering": "Регистрация...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Интервал здоровых состояний", "IntervalSeconds": "Интервал здоровых состояний",
"timeoutSeconds": "Таймаут (сек)", "timeoutSeconds": "Таймаут (сек)",
"timeIsInSeconds": "Время указано в секундах", "timeIsInSeconds": "Время указано в секундах",
"requireDeviceApproval": "Требовать подтверждения устройства", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Пользователям с этой ролью нужны новые устройства, одобренные администратором, прежде чем они смогут подключаться и получать доступ к ресурсам.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"retryAttempts": "Количество попыток повторного запроса", "retryAttempts": "Количество попыток повторного запроса",
"expectedResponseCodes": "Ожидаемые коды ответов", "expectedResponseCodes": "Ожидаемые коды ответов",
"expectedResponseCodesDescription": "HTTP-код состояния, указывающий на здоровое состояние. Если оставить пустым, 200-300 считается здоровым.", "expectedResponseCodesDescription": "HTTP-код состояния, указывающий на здоровое состояние. Если оставить пустым, 200-300 считается здоровым.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Внутренних ресурсов не найдено.", "resourcesTableNoInternalResourcesFound": "Внутренних ресурсов не найдено.",
"resourcesTableDestination": "Пункт назначения", "resourcesTableDestination": "Пункт назначения",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Псевдоним адреса",
"resourcesTableAliasAddressInfo": "Этот адрес является частью вспомогательной подсети организации. Он используется для разрешения псевдонимов с использованием внутреннего разрешения DNS.",
"resourcesTableClients": "Клиенты", "resourcesTableClients": "Клиенты",
"resourcesTableAndOnlyAccessibleInternally": "и доступны только внутренне при подключении с клиентом.", "resourcesTableAndOnlyAccessibleInternally": "и доступны только внутренне при подключении с клиентом.",
"resourcesTableNoTargets": "Нет ярлыков", "resourcesTableNoTargets": "Нет ярлыков",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Выберите своего поставщика удостоверений личности для продолжения", "orgAuthChooseIdpDescription": "Выберите своего поставщика удостоверений личности для продолжения",
"orgAuthNoIdpConfigured": "Эта организация не имеет настроенных поставщиков идентификационных данных. Вместо этого вы можете войти в свой Pangolin.", "orgAuthNoIdpConfigured": "Эта организация не имеет настроенных поставщиков идентификационных данных. Вместо этого вы можете войти в свой Pangolin.",
"orgAuthSignInWithPangolin": "Войти через Pangolin", "orgAuthSignInWithPangolin": "Войти через Pangolin",
"orgAuthSignInToOrg": "Войти в организацию", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Вход в организацию", "orgAuthSelectOrgTitle": "Вход в организацию",
"orgAuthSelectOrgDescription": "Введите ID вашей организации, чтобы продолжить", "orgAuthSelectOrgDescription": "Введите ID вашей организации, чтобы продолжить",
"orgAuthOrgIdPlaceholder": "ваша-организация", "orgAuthOrgIdPlaceholder": "ваша-организация",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Код должен быть 9 символов (например, A1AJ-N5JD)", "deviceCodeInvalidFormat": "Код должен быть 9 символов (например, A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Неверный или просроченный код", "deviceCodeInvalidOrExpired": "Неверный или просроченный код",
"deviceCodeVerifyFailed": "Не удалось проверить код устройства", "deviceCodeVerifyFailed": "Не удалось проверить код устройства",
"deviceCodeValidating": "Проверка кода устройства...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Проверка авторизации устройства...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Вы вошли как", "signedInAs": "Вы вошли как",
"deviceCodeEnterPrompt": "Введите код, отображаемый на устройстве", "deviceCodeEnterPrompt": "Введите код, отображаемый на устройстве",
"continue": "Продолжить", "continue": "Продолжить",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Доступ ко всем организациям, к которым ваш аккаунт имеет доступ", "deviceOrganizationsAccess": "Доступ ко всем организациям, к которым ваш аккаунт имеет доступ",
"deviceAuthorize": "Авторизовать {applicationName}", "deviceAuthorize": "Авторизовать {applicationName}",
"deviceConnected": "Устройство подключено!", "deviceConnected": "Устройство подключено!",
"deviceAuthorizedMessage": "Устройство авторизовано для доступа к вашей учетной записи. Вернитесь в клиентское приложение.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Облако Панголина", "pangolinCloud": "Облако Панголина",
"viewDevices": "Просмотр устройств", "viewDevices": "Просмотр устройств",
"viewDevicesDescription": "Управление подключенными устройствами", "viewDevicesDescription": "Управление подключенными устройствами",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "Не вы? Используйте другую учетную запись.", "deviceLoginUseDifferentAccount": "Не вы? Используйте другую учетную запись.",
"deviceLoginDeviceRequestingAccessToAccount": "Устройство запрашивает доступ к этой учетной записи.", "deviceLoginDeviceRequestingAccessToAccount": "Устройство запрашивает доступ к этой учетной записи.",
"loginSelectAuthenticationMethod": "Выберите метод аутентификации для продолжения.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Нет данных", "noData": "Нет данных",
"machineClients": "Машинные клиенты", "machineClients": "Машинные клиенты",
"install": "Установить", "install": "Установить",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "В настоящее время мы испытываем технические трудности. Пожалуйста, зайдите позже.", "maintenanceScreenMessage": "В настоящее время мы испытываем технические трудности. Пожалуйста, зайдите позже.",
"maintenanceScreenEstimatedCompletion": "Предполагаемое завершение:", "maintenanceScreenEstimatedCompletion": "Предполагаемое завершение:",
"createInternalResourceDialogDestinationRequired": "Укажите адрес назначения. Это может быть имя хоста или IP-адрес.", "createInternalResourceDialogDestinationRequired": "Укажите адрес назначения. Это может быть имя хоста или IP-адрес.",
"available": "Доступно", "available": "Available",
"archived": "Архивировано", "archived": "Archived",
"noArchivedDevices": "Архивные устройства не найдены", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Устройство архивировано", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Устройство успешно архивировано.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Ошибка архивирования устройства", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Не удалось архивировать устройство", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Вы уверены, что хотите архивировать это устройство?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Устройство будет архивировано и удалено из вашего списка активных устройств.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Архивировать устройство", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Архивировать устройство", "archiveDevice": "Archive Device",
"archive": "Архивировать", "archive": "Archive",
"deviceUnarchived": "Устройство разархивировано", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Устройство было успешно разархивировано.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Ошибка разархивирования устройства", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Не удалось распаковать устройство", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Разархивировать", "unarchive": "Unarchive",
"archiveClient": "Архивировать клиента", "archiveClient": "Archive Client",
"archiveClientQuestion": "Вы уверены, что хотите архивировать этого клиента?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "Клиент будет архивирован и удален из вашего активного списка клиентов.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "Архивировать клиента", "archiveClientConfirm": "Archive Client",
"blockClient": "Блокировать клиента", "blockClient": "Block Client",
"blockClientQuestion": "Вы уверены, что хотите заблокировать этого клиента?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Устройство будет вынуждено отключиться, если подключено в данный момент. Вы можете разблокировать устройство позже.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "Блокировать клиента", "blockClientConfirm": "Block Client",
"active": "Активный", "active": "Active",
"usernameOrEmail": "Имя пользователя или Email", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Выберите вашу организацию", "selectYourOrganization": "Select your organization",
"signInTo": "Войти в", "signInTo": "Log in in to",
"signInWithPassword": "Продолжить с паролем", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Методы аутентификации для этой организации недоступны.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Введите ваш пароль", "enterPassword": "Enter your password",
"enterMfaCode": "Введите код из вашего приложения-аутентификатора", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Пожалуйста, используйте ваш защитный ключ для входа.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Нужно использовать другой аккаунт?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Нажимая на кнопки ниже, вы подтверждаете, что прочитали, поняли и согласны с <termsOfService>Условиями использования</termsOfService> и <privacyPolicy>Политикой конфиденциальности</privacyPolicy>.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Условия предоставления услуг", "termsOfService": "Terms of Service",
"privacyPolicy": "Политика конфиденциальности", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Пользователь с таким именем пользователя не найден.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Подтвердить", "verify": "Verify",
"signIn": "Войти", "signIn": "Sign In",
"forgotPassword": "Забыли пароль?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Если вы вошли в систему ранее, вы можете ввести имя пользователя или адрес электронной почты, чтобы войти в систему с поставщиком идентификации вашей организации. Это проще!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Все равно продолжить", "continueAnyway": "Continue anyway",
"dontShowAgain": "Больше не показывать", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Знаете ли вы?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Пытаетесь войти?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Вы пытаетесь войти через оператора идентификации вашей организации?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Войдите или зарегистрируйтесь через вашу организацию", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Использовать другую учетную запись", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Войти", "logIn": "Log In",
"deviceInformation": "Информация об устройстве", "deviceInformation": "Device Information",
"deviceInformationDescription": "Информация о устройстве и агенте", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Безопасность устройства", "platform": "Platform",
"deviceSecurityDescription": "Информация о позе безопасности устройства", "macosVersion": "macOS Version",
"platform": "Платформа", "windowsVersion": "Windows Version",
"macosVersion": "Версия macOS", "iosVersion": "iOS Version",
"windowsVersion": "Версия Windows", "androidVersion": "Android Version",
"iosVersion": "Версия iOS", "osVersion": "OS Version",
"androidVersion": "Версия Android", "kernelVersion": "Kernel Version",
"osVersion": "Версия ОС", "deviceModel": "Device Model",
"kernelVersion": "Версия ядра", "serialNumber": "Serial Number",
"deviceModel": "Модель устройства",
"serialNumber": "Серийный номер",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "Первый раз виден", "firstSeen": "First Seen",
"lastSeen": "Последнее посещение", "lastSeen": "Last Seen",
"biometricsEnabled": "Включены биометрические данные", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Диск зашифрован", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Брандмауэр включен", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Автоматические обновления включены", "unblockClient": "Unblock Client",
"tpmAvailable": "Доступно TPM", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Защита целостности системы (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Стилс-режим брандмауэра", "block": "Block",
"linuxAppArmorEnabled": "Броня", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Просмотр информации и настроек устройства", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Это устройство ожидает одобрения", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Это устройство заблокировано. Оно не сможет подключаться к ресурсам, если не разблокировано.", "connected": "Connected",
"unblockClient": "Разблокировать клиента", "disconnected": "Disconnected",
"unblockClientDescription": "Устройство разблокировано", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "Разархивировать клиента", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Устройство было разархивировано", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Блок", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Разблокировать", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Действия устройства", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Управление статусом устройства и доступом", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Это устройство ожидает одобрения. Он не сможет подключиться к ресурсам до утверждения.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Подключено",
"disconnected": "Отключено",
"approvalsEmptyStateTitle": "Утверждения устройства не включены",
"approvalsEmptyStateDescription": "Включите одобрение ролей для того, чтобы пользователи могли подключать новые устройства.",
"approvalsEmptyStateStep1Title": "Перейти к ролям",
"approvalsEmptyStateStep1Description": "Перейдите в настройки ролей вашей организации для настройки утверждений устройств.",
"approvalsEmptyStateStep2Title": "Включить утверждения устройства",
"approvalsEmptyStateStep2Description": "Редактировать роль и включить опцию 'Требовать утверждения устройств'. Пользователям с этой ролью потребуется подтверждение администратора для новых устройств.",
"approvalsEmptyStatePreviewDescription": "Предпросмотр: Если включено, ожидающие запросы на устройство появятся здесь для проверки",
"approvalsEmptyStateButtonText": "Управление ролями"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "Herhangi Bir Ağa Bağlan", "sitesBannerTitle": "Herhangi Bir Ağa Bağlan",
"sitesBannerDescription": "Bir site, Pangolin'in kullanıcılara, halka açık veya özel kaynaklara, her yerden erişim sağlamak için uzak bir ağa bağlantı sunmasıdır. Site ağı bağlantısını (Newt) çalıştırabileceğiniz her yere kurarak bağlantıyı kurunuz.", "sitesBannerDescription": "Bir site, Pangolin'in kullanıcılara, halka açık veya özel kaynaklara, her yerden erişim sağlamak için uzak bir ağa bağlantı sunmasıdır. Site ağı bağlantısını (Newt) çalıştırabileceğiniz her yere kurarak bağlantıyı kurunuz.",
"sitesBannerButtonText": "Site Kur", "sitesBannerButtonText": "Site Kur",
"approvalsBannerTitle": "Cihaz Erişimini Onayla veya Reddet", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "Kullanıcılardan gelen cihaz erişim isteklerini gözden geçirin ve onaylayın veya reddedin. Cihaz onaylarının gerekli olduğu durumlarda, kullanıcıların cihazlarının kuruluşunuzun kaynaklarına bağlanabilmesi için yönetici onayı alması gerekecektir.", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "Daha fazla bilgi", "approvalsBannerButtonText": "Learn More",
"siteCreate": "Site Oluştur", "siteCreate": "Site Oluştur",
"siteCreateDescription2": "Yeni bir site oluşturup bağlanmak için aşağıdaki adımları izleyin", "siteCreateDescription2": "Yeni bir site oluşturup bağlanmak için aşağıdaki adımları izleyin",
"siteCreateDescription": "Kaynaklarınızı bağlamaya başlamak için yeni bir site oluşturun", "siteCreateDescription": "Kaynaklarınızı bağlamaya başlamak için yeni bir site oluşturun",
@@ -260,8 +260,8 @@
"accessRolesSearch": "Rolleri ara...", "accessRolesSearch": "Rolleri ara...",
"accessRolesAdd": "Rol Ekle", "accessRolesAdd": "Rol Ekle",
"accessRoleDelete": "Rolü Sil", "accessRoleDelete": "Rolü Sil",
"accessApprovalsManage": "Onayları Yönet", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "Bu kuruluşa erişim için bekleyen onayları görüntüleyin ve yönetin", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "Açıklama", "description": "Açıklama",
"inviteTitle": "Açık Davetiyeler", "inviteTitle": "Açık Davetiyeler",
"inviteDescription": "Organizasyona katılmak için diğer kullanıcılar için davetleri yönetin", "inviteDescription": "Organizasyona katılmak için diğer kullanıcılar için davetleri yönetin",
@@ -455,18 +455,18 @@
"selectDuration": "Süreyi seçin", "selectDuration": "Süreyi seçin",
"selectResource": "Kaynak Seçin", "selectResource": "Kaynak Seçin",
"filterByResource": "Kaynağa Göre Filtrele", "filterByResource": "Kaynağa Göre Filtrele",
"selectApprovalState": "Onay Durumunu Seçin", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "Onay Durumuna Göre Filtrele", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "Onay yok", "approvalListEmpty": "No approvals",
"approvalState": "Onay Durumu", "approvalState": "Approval State",
"approve": "Onayla", "approve": "Approve",
"approved": "Onaylandı", "approved": "Approved",
"denied": "Reddedildi", "denied": "Denied",
"deniedApproval": "Reddedilen Onay", "deniedApproval": "Denied Approval",
"all": "Tümü", "all": "All",
"deny": "Reddet", "deny": "Deny",
"viewDetails": "Ayrıntıları Gör", "viewDetails": "View Details",
"requestingNewDeviceApproval": "yeni bir cihaz talep etti", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "Filtreleri Sıfırla", "resetFilters": "Filtreleri Sıfırla",
"totalBlocked": "Pangolin Tarafından Engellenen İstekler", "totalBlocked": "Pangolin Tarafından Engellenen İstekler",
"totalRequests": "Toplam İstekler", "totalRequests": "Toplam İstekler",
@@ -746,28 +746,28 @@
"countries": "Ülkeler", "countries": "Ülkeler",
"accessRoleCreate": "Rol Oluştur", "accessRoleCreate": "Rol Oluştur",
"accessRoleCreateDescription": "Kullanıcıları gruplamak ve izinlerini yönetmek için yeni bir rol oluşturun.", "accessRoleCreateDescription": "Kullanıcıları gruplamak ve izinlerini yönetmek için yeni bir rol oluşturun.",
"accessRoleEdit": "Rol Düzenle", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "Rol bilgilerini düzenleyin.", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "Rol Oluştur", "accessRoleCreateSubmit": "Rol Oluştur",
"accessRoleCreated": "Rol oluşturuldu", "accessRoleCreated": "Rol oluşturuldu",
"accessRoleCreatedDescription": "Rol başarıyla oluşturuldu.", "accessRoleCreatedDescription": "Rol başarıyla oluşturuldu.",
"accessRoleErrorCreate": "Rol oluşturulamadı", "accessRoleErrorCreate": "Rol oluşturulamadı",
"accessRoleErrorCreateDescription": "Rol oluşturulurken bir hata oluştu.", "accessRoleErrorCreateDescription": "Rol oluşturulurken bir hata oluştu.",
"accessRoleUpdateSubmit": "Rolü Güncelle", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "Rol güncellendi", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "Rol başarıyla güncellendi.", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "Onay işlendi", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "Onay İsteği kararını onaylandı olarak ayarlayın.", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "Onay İsteği kararını reddedildi olarak ayarlayın.", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "Rol güncellenemedi", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "Rol güncellenirken bir hata oluştu.", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "Onay işlenemedi", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "Onay işlenirken bir hata oluştu.", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "Yeni rol gerekli", "accessRoleErrorNewRequired": "Yeni rol gerekli",
"accessRoleErrorRemove": "Rol kaldırılamadı", "accessRoleErrorRemove": "Rol kaldırılamadı",
"accessRoleErrorRemoveDescription": "Rol kaldırılırken bir hata oluştu.", "accessRoleErrorRemoveDescription": "Rol kaldırılırken bir hata oluştu.",
"accessRoleName": "Rol Adı", "accessRoleName": "Rol Adı",
"accessRoleQuestionRemove": "{name} rolünü silmek üzeresiniz. Bu eylemi geri alamazsınız.", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "Rolü Kaldır", "accessRoleRemove": "Rolü Kaldır",
"accessRoleRemoveDescription": "Kuruluştan bir rol kaldır", "accessRoleRemoveDescription": "Kuruluştan bir rol kaldır",
"accessRoleRemoveSubmit": "Rolü Kaldır", "accessRoleRemoveSubmit": "Rolü Kaldır",
@@ -903,7 +903,7 @@
"inviteAlready": "Davetiye gönderilmiş gibi görünüyor!", "inviteAlready": "Davetiye gönderilmiş gibi görünüyor!",
"inviteAlreadyDescription": "Daveti kabul etmek için giriş yapmalı veya bir hesap oluşturmalısınız.", "inviteAlreadyDescription": "Daveti kabul etmek için giriş yapmalı veya bir hesap oluşturmalısınız.",
"signupQuestion": "Zaten bir hesabınız var mı?", "signupQuestion": "Zaten bir hesabınız var mı?",
"login": "Giriş Yap", "login": "Log In",
"resourceNotFound": "No resources found", "resourceNotFound": "No resources found",
"resourceNotFoundDescription": "Erişmeye çalıştığınız kaynak mevcut değil.", "resourceNotFoundDescription": "Erişmeye çalıştığınız kaynak mevcut değil.",
"pincodeRequirementsLength": "PIN kesinlikle 6 haneli olmalıdır", "pincodeRequirementsLength": "PIN kesinlikle 6 haneli olmalıdır",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "Bu kuruluş, parolanızı {maxDays} günde bir değiştirmenizi gerektirir.", "passwordExpiryDescription": "Bu kuruluş, parolanızı {maxDays} günde bir değiştirmenizi gerektirir.",
"changePasswordNow": "Şifrenizi Şimdi Değiştirin", "changePasswordNow": "Şifrenizi Şimdi Değiştirin",
"pincodeAuth": "Kimlik Doğrulama Kodu", "pincodeAuth": "Kimlik Doğrulama Kodu",
"pincodeSubmit2": "Kodu Gönder", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "Sıfırlama İsteği", "passwordResetSubmit": "Sıfırlama İsteği",
"passwordResetAlreadyHaveCode": "Kodu Girin", "passwordResetAlreadyHaveCode": "Kodu Girin",
"passwordResetSmtpRequired": "Yönetici ile iletişime geçin", "passwordResetSmtpRequired": "Yönetici ile iletişime geçin",
"passwordResetSmtpRequiredDescription": "Parolanızı sıfırlamak için bir parola sıfırlama kodu gereklidir. Yardım için yönetici ile iletişime geçin.", "passwordResetSmtpRequiredDescription": "Parolanızı sıfırlamak için bir parola sıfırlama kodu gereklidir. Yardım için yönetici ile iletişime geçin.",
"passwordBack": "Şifreye Geri Dön", "passwordBack": "Şifreye Geri Dön",
"loginBack": "Ana oturum açma sayfasına geri dön", "loginBack": "Go back to main login page",
"signup": "Kaydol", "signup": "Kaydol",
"loginStart": "Başlamak için giriş yapın", "loginStart": "Başlamak için giriş yapın",
"idpOidcTokenValidating": "OIDC token'ı doğrulanıyor", "idpOidcTokenValidating": "OIDC token'ı doğrulanıyor",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "Kimlik Sağlayıcı Organizasyonu Güncelle", "actionUpdateIdpOrg": "Kimlik Sağlayıcı Organizasyonu Güncelle",
"actionCreateClient": "Müşteri Oluştur", "actionCreateClient": "Müşteri Oluştur",
"actionDeleteClient": "Müşteri Sil", "actionDeleteClient": "Müşteri Sil",
"actionArchiveClient": "İstemci Arşivle", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "İstemci Arşivini Kaldır", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "İstemci Engelle", "actionBlockClient": "Block Client",
"actionUnblockClient": "İstemci Engelini Kaldır", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "Müşteri Güncelle", "actionUpdateClient": "Müşteri Güncelle",
"actionListClients": "Müşterileri Listele", "actionListClients": "Müşterileri Listele",
"actionGetClient": "Müşteriyi Al", "actionGetClient": "Müşteriyi Al",
@@ -1167,14 +1167,14 @@
"searchProgress": "Ara...", "searchProgress": "Ara...",
"create": "Oluştur", "create": "Oluştur",
"orgs": "Organizasyonlar", "orgs": "Organizasyonlar",
"loginError": "Beklenmeyen bir hata oluştu. Lütfen tekrar deneyin.", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "Cihazınız için oturum açmanız gerekiyor.", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "Şifrenizi mi unuttunuz?", "passwordForgot": "Şifrenizi mi unuttunuz?",
"otpAuth": "İki Faktörlü Kimlik Doğrulama", "otpAuth": "İki Faktörlü Kimlik Doğrulama",
"otpAuthDescription": "Authenticator uygulamanızdan veya tek kullanımlık yedek kodlarınızdan birini girin.", "otpAuthDescription": "Authenticator uygulamanızdan veya tek kullanımlık yedek kodlarınızdan birini girin.",
"otpAuthSubmit": "Kodu Gönder", "otpAuthSubmit": "Kodu Gönder",
"idpContinue": "Veya devam et:", "idpContinue": "Veya devam et:",
"otpAuthBack": "Şifreye Geri Dön", "otpAuthBack": "Back to Password",
"navbar": "Navigasyon Menüsü", "navbar": "Navigasyon Menüsü",
"navbarDescription": "Uygulamanın ana navigasyon menüsü", "navbarDescription": "Uygulamanın ana navigasyon menüsü",
"navbarDocsLink": "Dokümantasyon", "navbarDocsLink": "Dokümantasyon",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "Genel Bakış", "sidebarOverview": "Genel Bakış",
"sidebarHome": "Ana Sayfa", "sidebarHome": "Ana Sayfa",
"sidebarSites": "Siteler", "sidebarSites": "Siteler",
"sidebarApprovals": "Onay Talepleri", "sidebarApprovals": "Approval Requests",
"sidebarResources": "Kaynaklar", "sidebarResources": "Kaynaklar",
"sidebarProxyResources": "Herkese Açık", "sidebarProxyResources": "Herkese Açık",
"sidebarClientResources": "Özel", "sidebarClientResources": "Özel",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "Kimlik Sağlayıcılar", "sidebarIdentityProviders": "Kimlik Sağlayıcılar",
"sidebarLicense": "Lisans", "sidebarLicense": "Lisans",
"sidebarClients": "İstemciler", "sidebarClients": "İstemciler",
"sidebarUserDevices": "Kullanıcı Cihazları", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "Makineler", "sidebarMachineClients": "Makineler",
"sidebarDomains": "Alan Adları", "sidebarDomains": "Alan Adları",
"sidebarGeneral": "Yönet", "sidebarGeneral": "Yönet",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "Sunucu yönetici hesabı oluşturulurken bir hata oluştu.", "setupErrorCreateAdmin": "Sunucu yönetici hesabı oluşturulurken bir hata oluştu.",
"certificateStatus": "Sertifika Durumu", "certificateStatus": "Sertifika Durumu",
"loading": "Yükleniyor", "loading": "Yükleniyor",
"loadingAnalytics": "Analiz Yükleniyor", "loadingAnalytics": "Loading Analytics",
"restart": "Yeniden Başlat", "restart": "Yeniden Başlat",
"domains": "Alan Adları", "domains": "Alan Adları",
"domainsDescription": "Organizasyonda kullanılabilir alan adlarını oluşturun ve yönetin", "domainsDescription": "Organizasyonda kullanılabilir alan adlarını oluşturun ve yönetin",
@@ -1339,7 +1339,7 @@
"refreshError": "Veriler yenilenemedi", "refreshError": "Veriler yenilenemedi",
"verified": "Doğrulandı", "verified": "Doğrulandı",
"pending": "Beklemede", "pending": "Beklemede",
"pendingApproval": "Bekleyen Onay", "pendingApproval": "Pending Approval",
"sidebarBilling": "Faturalama", "sidebarBilling": "Faturalama",
"billing": "Faturalama", "billing": "Faturalama",
"orgBillingDescription": "Fatura bilgilerinizi ve aboneliklerinizi yönetin", "orgBillingDescription": "Fatura bilgilerinizi ve aboneliklerinizi yönetin",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "Güvenlik anahtarı başarıyla kaldırıldı", "securityKeyRemoveSuccess": "Güvenlik anahtarı başarıyla kaldırıldı",
"securityKeyRemoveError": "Güvenlik anahtarı kaldırılırken hata oluştu", "securityKeyRemoveError": "Güvenlik anahtarı kaldırılırken hata oluştu",
"securityKeyLoadError": "Güvenlik anahtarları yüklenirken hata oluştu", "securityKeyLoadError": "Güvenlik anahtarları yüklenirken hata oluştu",
"securityKeyLogin": "Güvenlik Anahtarı Kullan", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "Güvenlik anahtarı ile kimlik doğrulama başarısız oldu", "securityKeyAuthError": "Güvenlik anahtarı ile kimlik doğrulama başarısız oldu",
"securityKeyRecommendation": "Hesabınızdan kilitlenmediğinizden emin olmak için farklı bir cihazda başka bir güvenlik anahtarı kaydetmeyi düşünün.", "securityKeyRecommendation": "Hesabınızdan kilitlenmediğinizden emin olmak için farklı bir cihazda başka bir güvenlik anahtarı kaydetmeyi düşünün.",
"registering": "Kaydediliyor...", "registering": "Kaydediliyor...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "Sağlıklı Aralık", "IntervalSeconds": "Sağlıklı Aralık",
"timeoutSeconds": "Zaman Aşımı (saniye)", "timeoutSeconds": "Zaman Aşımı (saniye)",
"timeIsInSeconds": "Zaman saniye cinsindendir", "timeIsInSeconds": "Zaman saniye cinsindendir",
"requireDeviceApproval": "Cihaz Onaylarını Gerektir", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "Bu role sahip kullanıcıların yeni cihazlarının bağlanabilmesi ve kaynaklara erişebilmesi için bir yönetici tarafından onaylanması gerekiyor.", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"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.",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "Hiçbir dahili kaynak bulunamadı.", "resourcesTableNoInternalResourcesFound": "Hiçbir dahili kaynak bulunamadı.",
"resourcesTableDestination": "Hedef", "resourcesTableDestination": "Hedef",
"resourcesTableAlias": "Takma Ad", "resourcesTableAlias": "Takma Ad",
"resourcesTableAliasAddress": "Alias Adresi",
"resourcesTableAliasAddressInfo": "Bu adres, kuruluşun yardımcı ağ alt bantının bir parçasıdır. Alias kayıtlarını çözümlemek için dahili DNS çözümlemesi kullanılır.",
"resourcesTableClients": "İstemciler", "resourcesTableClients": "İstemciler",
"resourcesTableAndOnlyAccessibleInternally": "veyalnızca bir istemci ile bağlandığında dahili olarak erişilebilir.", "resourcesTableAndOnlyAccessibleInternally": "veyalnızca bir istemci ile bağlandığında dahili olarak erişilebilir.",
"resourcesTableNoTargets": "Hedef yok", "resourcesTableNoTargets": "Hedef yok",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "Devam etmek için kimlik sağlayıcınızı seçin", "orgAuthChooseIdpDescription": "Devam etmek için kimlik sağlayıcınızı seçin",
"orgAuthNoIdpConfigured": "Bu kuruluşta yapılandırılmış kimlik sağlayıcı yok. Bunun yerine Pangolin kimliğinizle giriş yapabilirsiniz.", "orgAuthNoIdpConfigured": "Bu kuruluşta yapılandırılmış kimlik sağlayıcı yok. Bunun yerine Pangolin kimliğinizle giriş yapabilirsiniz.",
"orgAuthSignInWithPangolin": "Pangolin ile Giriş Yap", "orgAuthSignInWithPangolin": "Pangolin ile Giriş Yap",
"orgAuthSignInToOrg": "Bir kuruluşa giriş yapın", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "Kuruluş Giriş", "orgAuthSelectOrgTitle": "Kuruluş Giriş",
"orgAuthSelectOrgDescription": "Devam etmek için kuruluş kimliğinizi girin", "orgAuthSelectOrgDescription": "Devam etmek için kuruluş kimliğinizi girin",
"orgAuthOrgIdPlaceholder": "kuruluşunuz", "orgAuthOrgIdPlaceholder": "kuruluşunuz",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "Kod 9 karakter olmalı (ör. A1AJ-N5JD)", "deviceCodeInvalidFormat": "Kod 9 karakter olmalı (ör. A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "Geçersiz veya süresi dolmuş kod", "deviceCodeInvalidOrExpired": "Geçersiz veya süresi dolmuş kod",
"deviceCodeVerifyFailed": "Cihaz kodu doğrulanamadı", "deviceCodeVerifyFailed": "Cihaz kodu doğrulanamadı",
"deviceCodeValidating": "Cihaz kodu doğrulanıyor...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "Cihaz yetkilendirme doğrulanıyor...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "Olarak giriş yapıldı", "signedInAs": "Olarak giriş yapıldı",
"deviceCodeEnterPrompt": "Cihazda gösterilen kodu girin", "deviceCodeEnterPrompt": "Cihazda gösterilen kodu girin",
"continue": "Devam Et", "continue": "Devam Et",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "Hesabınızın erişim hakkına sahip olduğu tüm organizasyonlara erişim", "deviceOrganizationsAccess": "Hesabınızın erişim hakkına sahip olduğu tüm organizasyonlara erişim",
"deviceAuthorize": "{uygulamaAdi} yetkilendir", "deviceAuthorize": "{uygulamaAdi} yetkilendir",
"deviceConnected": "Cihaz Bağlandı!", "deviceConnected": "Cihaz Bağlandı!",
"deviceAuthorizedMessage": "Cihaz hesabınıza erişim yetkisine sahiptir. Lütfen istemci uygulamasına geri dönün.", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "Pangolin Cloud", "pangolinCloud": "Pangolin Cloud",
"viewDevices": "Cihazları Görüntüle", "viewDevices": "Cihazları Görüntüle",
"viewDevicesDescription": "Bağlantılı cihazlarınızı yönetin", "viewDevicesDescription": "Bağlantılı cihazlarınızı yönetin",
@@ -2348,7 +2346,7 @@
"identifier": "Tanımlayıcı", "identifier": "Tanımlayıcı",
"deviceLoginUseDifferentAccount": "Siz değil misiniz? Farklı bir hesap kullanın.", "deviceLoginUseDifferentAccount": "Siz değil misiniz? Farklı bir hesap kullanın.",
"deviceLoginDeviceRequestingAccessToAccount": "Bir cihaz bu hesaba erişim talep ediyor.", "deviceLoginDeviceRequestingAccessToAccount": "Bir cihaz bu hesaba erişim talep ediyor.",
"loginSelectAuthenticationMethod": "Devam etmek için bir kimlik doğrulama yöntemi seçin.", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "Veri Yok", "noData": "Veri Yok",
"machineClients": "Makine İstemcileri", "machineClients": "Makine İstemcileri",
"install": "Yükle", "install": "Yükle",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "Şu anda teknik zorluklar yaşıyoruz. Lütfen yakında tekrar kontrol edin.", "maintenanceScreenMessage": "Şu anda teknik zorluklar yaşıyoruz. Lütfen yakında tekrar kontrol edin.",
"maintenanceScreenEstimatedCompletion": "Tahmini Tamamlama:", "maintenanceScreenEstimatedCompletion": "Tahmini Tamamlama:",
"createInternalResourceDialogDestinationRequired": "Hedef gereklidir", "createInternalResourceDialogDestinationRequired": "Hedef gereklidir",
"available": "Mevcut", "available": "Available",
"archived": "Arşivlenmiş", "archived": "Archived",
"noArchivedDevices": "Arşivlenmiş cihaz bulunamadı", "noArchivedDevices": "No archived devices found",
"deviceArchived": "Cihaz arşivlendi", "deviceArchived": "Device archived",
"deviceArchivedDescription": "Cihaz başarıyla arşivlendi.", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "Cihaz arşivleme hatası", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "Cihaz arşivlenemedi", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "Bu cihazı arşivlemek istediğinizden emin misiniz?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "Cihaz arşivlenecek ve aktif cihazlar listenizden kaldırılacak.", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "Cihaz Arşivle", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "Cihaz Arşivle", "archiveDevice": "Archive Device",
"archive": "Arşivle", "archive": "Archive",
"deviceUnarchived": "Cihaz arşivden çıkarıldı", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "Cihaz başarıyla arşivden çıkarıldı.", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "Cihaz arşivden çıkartılamadı", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "Cihaz arşivden çıkarılamadı", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "Arşivden Çıkart", "unarchive": "Unarchive",
"archiveClient": "İstemci Arşivle", "archiveClient": "Archive Client",
"archiveClientQuestion": "Bu istemciyi arşivlemek istediğinizden emin misiniz?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "İstemci arşivlenecek ve aktif istemciler listenizden çıkarılacak.", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "İstemci Arşivle", "archiveClientConfirm": "Archive Client",
"blockClient": "İstemci Engelle", "blockClient": "Block Client",
"blockClientQuestion": "Bu istemciyi engellemek istediğinizden emin misiniz?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "Cihaz şu anda bağlıysa bağlantısı kesilecek. Cihazı daha sonra engelini kaldırabilirsiniz.", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "İstemci Engelle", "blockClientConfirm": "Block Client",
"active": "Aktif", "active": "Active",
"usernameOrEmail": "Kullanıcı adı veya E-posta", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "Kuruluşunuzu seçin", "selectYourOrganization": "Select your organization",
"signInTo": "Giriş yapın", "signInTo": "Log in in to",
"signInWithPassword": "Şifre ile Devam Et", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "Bu kuruluş için kullanılabilir kimlik doğrulama yöntemleri yok.", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "Şifrenizi girin", "enterPassword": "Enter your password",
"enterMfaCode": "Authenticator uygulamanızdan kodu girin", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "Giriş yapmak için güvenlik anahtarınızı kullanın.", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "Farklı bir hesap kullanmanız mı gerekiyor?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "Aşağıdaki butonlara tıklayarak, <termsOfService>Hizmet Şartları</termsOfService> ve <privacyPolicy>Gizlilik Politikası</privacyPolicy> metinlerini okuduğunuzu ve anladığınızı kabul etmektesiniz.", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "Hizmet Şartları", "termsOfService": "Terms of Service",
"privacyPolicy": "Gizlilik Politikası", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "Bu kullanıcı adıyla eşleşen kullanıcı bulunamadı.", "userNotFoundWithUsername": "No user found with that username.",
"verify": "Doğrula", "verify": "Verify",
"signIn": "Giriş Yap", "signIn": "Sign In",
"forgotPassword": "Şifreni mi unuttun?", "forgotPassword": "Forgot password?",
"orgSignInTip": "Daha önce giriş yaptıysanız, yukarıda kullanıcı adınızı veya e-posta adresinizi girerek kuruluşunuzun kimlik sağlayıcısıyla kimlik doğrulaması yapabilirsiniz. Daha kolay!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "Yine de devam et", "continueAnyway": "Continue anyway",
"dontShowAgain": "Tekrar gösterme", "dontShowAgain": "Don't show again",
"orgSignInNotice": "Biliyor muydunuz?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "Giriş yapmaya mı çalışıyorsunuz?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "Kuruluşunuzun kimlik sağlayıcısı aracılığıyla giriş yapmaya mı çalışıyorsunuz?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "Bunun yerine kuruluşunuzla giriş yapın veya kaydolun", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "Farklı Bir Hesap Kullan", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "Giriş Yap", "logIn": "Log In",
"deviceInformation": "Cihaz Bilgisi", "deviceInformation": "Device Information",
"deviceInformationDescription": "Cihaz ve temsilci hakkında bilgi", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "Cihaz Güvenliği",
"deviceSecurityDescription": "Cihaz güvenliği durumu bilgisi",
"platform": "Platform", "platform": "Platform",
"macosVersion": "macOS Sürümü", "macosVersion": "macOS Version",
"windowsVersion": "Windows Sürümü", "windowsVersion": "Windows Version",
"iosVersion": "iOS Sürümü", "iosVersion": "iOS Version",
"androidVersion": "Android Sürümü", "androidVersion": "Android Version",
"osVersion": "İşletim Sistemi Sürümü", "osVersion": "OS Version",
"kernelVersion": "Çekirdek Sürümü", "kernelVersion": "Kernel Version",
"deviceModel": "Cihaz Modeli", "deviceModel": "Device Model",
"serialNumber": "Seri Numarası", "serialNumber": "Serial Number",
"hostname": "Ana Makine Adı", "hostname": "Hostname",
"firstSeen": "İlk Görüldü", "firstSeen": "First Seen",
"lastSeen": "Son Görüldü", "lastSeen": "Last Seen",
"biometricsEnabled": "Biyometri Etkin", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "Disk Şifrelenmiş", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "Güvenlik Duvarı Etkin", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "Otomatik Güncellemeler Etkin", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM Mevcut", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "Sistem Bütünlüğü Koruması (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "Güvenlik Duvarı Gizlilik Modu", "block": "Block",
"linuxAppArmorEnabled": "AppArmor", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "Cihaz bilgilerini ve ayarlarını görüntüleyin", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "Bu cihaz onay bekliyor", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "Bu cihaz şu anda engellidir. Engeli kaldırılmadığı sürece hiçbir kaynağa bağlanamayacaktır.", "connected": "Connected",
"unblockClient": "İstemci Engeli Kaldır", "disconnected": "Disconnected",
"unblockClientDescription": "Cihazın engeli kaldırıldı", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "İstemci Arşivini Kaldır", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "Cihaz arşivden çıkarıldı", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "Engelle", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "Engelini Kaldır", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "Cihaz İşlemleri", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "Cihaz durumu ve erişimini yönetin", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "Bu cihaz onay bekliyor. Onaylanana kadar kaynaklara bağlanamayacak.", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "Bağlandı",
"disconnected": "Bağlantı Kesildi",
"approvalsEmptyStateTitle": "Cihaz Onayları Etkin Değil",
"approvalsEmptyStateDescription": "Kullanıcıların yeni cihazlara bağlanabilmeleri için yönetici onayı gerektiren rol cihaz onaylarını etkinleştirin.",
"approvalsEmptyStateStep1Title": "Rollere Git",
"approvalsEmptyStateStep1Description": "Cihaz onaylarını yapılandırmak için kuruluşunuzun rol ayarlarına gidin.",
"approvalsEmptyStateStep2Title": "Cihaz Onaylarını Etkinleştir",
"approvalsEmptyStateStep2Description": "Bir rolü düzenleyin ve 'Cihaz Onaylarını Gerektir' seçeneğini etkinleştirin. Bu role sahip kullanıcıların yeni cihazlar için yönetici onayına ihtiyacı olacaktır.",
"approvalsEmptyStatePreviewDescription": "Önizleme: Etkinleştirildiğinde, bekleyen cihaz talepleri incelenmek üzere burada görünecektir.",
"approvalsEmptyStateButtonText": "Rolleri Yönet"
} }
+138 -152
View File
@@ -56,9 +56,9 @@
"sitesBannerTitle": "连接任何网络", "sitesBannerTitle": "连接任何网络",
"sitesBannerDescription": "站点是连接到远程网络的链接,允许Pangolin为用户提供资源访问,无论是公共还是私人。可以在任何可以运行二进制文件或容器的地方安装站点网络连接器(Newt)以建立连接。", "sitesBannerDescription": "站点是连接到远程网络的链接,允许Pangolin为用户提供资源访问,无论是公共还是私人。可以在任何可以运行二进制文件或容器的地方安装站点网络连接器(Newt)以建立连接。",
"sitesBannerButtonText": "安装站点", "sitesBannerButtonText": "安装站点",
"approvalsBannerTitle": "批准或拒绝设备访问", "approvalsBannerTitle": "Approve or Deny Device Access",
"approvalsBannerDescription": "审核、批准或拒绝用户的设备访问请求。 当需要设备批准时,用户必须先获得管理员批准,然后他们的设备才能连接到您的组织资源。", "approvalsBannerDescription": "Review and approve or deny device access requests from users. When device approvals are required, users must get admin approval before their devices can connect to your organization's resources.",
"approvalsBannerButtonText": "了解更多", "approvalsBannerButtonText": "Learn More",
"siteCreate": "创建站点", "siteCreate": "创建站点",
"siteCreateDescription2": "按照下面的步骤创建和连接一个新站点", "siteCreateDescription2": "按照下面的步骤创建和连接一个新站点",
"siteCreateDescription": "创建一个新站点开始连接资源", "siteCreateDescription": "创建一个新站点开始连接资源",
@@ -260,8 +260,8 @@
"accessRolesSearch": "搜索角色...", "accessRolesSearch": "搜索角色...",
"accessRolesAdd": "添加角色", "accessRolesAdd": "添加角色",
"accessRoleDelete": "删除角色", "accessRoleDelete": "删除角色",
"accessApprovalsManage": "管理批准", "accessApprovalsManage": "Manage Approvals",
"accessApprovalsDescription": "查看和管理待审批的组织访问权限", "accessApprovalsDescription": "View and manage pending approvals for access to this organization",
"description": "描述", "description": "描述",
"inviteTitle": "打开邀请", "inviteTitle": "打开邀请",
"inviteDescription": "管理其他用户加入机构的邀请", "inviteDescription": "管理其他用户加入机构的邀请",
@@ -455,18 +455,18 @@
"selectDuration": "选择持续时间", "selectDuration": "选择持续时间",
"selectResource": "选择资源", "selectResource": "选择资源",
"filterByResource": "按资源过滤", "filterByResource": "按资源过滤",
"selectApprovalState": "选择审批状态", "selectApprovalState": "Select Approval State",
"filterByApprovalState": "按批准状态过滤", "filterByApprovalState": "Filter By Approval State",
"approvalListEmpty": "无批准", "approvalListEmpty": "No approvals",
"approvalState": "审批状态", "approvalState": "Approval State",
"approve": "批准", "approve": "Approve",
"approved": "已批准", "approved": "Approved",
"denied": "被拒绝", "denied": "Denied",
"deniedApproval": "拒绝批准", "deniedApproval": "Denied Approval",
"all": "所有", "all": "All",
"deny": "拒绝", "deny": "Deny",
"viewDetails": "查看详情", "viewDetails": "View Details",
"requestingNewDeviceApproval": "请求了一个新设备", "requestingNewDeviceApproval": "requested a new device",
"resetFilters": "重置过滤器", "resetFilters": "重置过滤器",
"totalBlocked": "被Pangolin阻止的请求", "totalBlocked": "被Pangolin阻止的请求",
"totalRequests": "总请求", "totalRequests": "总请求",
@@ -746,28 +746,28 @@
"countries": "国家", "countries": "国家",
"accessRoleCreate": "创建角色", "accessRoleCreate": "创建角色",
"accessRoleCreateDescription": "创建一个新角色来分组用户并管理他们的权限。", "accessRoleCreateDescription": "创建一个新角色来分组用户并管理他们的权限。",
"accessRoleEdit": "编辑角色", "accessRoleEdit": "Edit Role",
"accessRoleEditDescription": "编辑角色信息。", "accessRoleEditDescription": "Edit role information.",
"accessRoleCreateSubmit": "创建角色", "accessRoleCreateSubmit": "创建角色",
"accessRoleCreated": "角色已创建", "accessRoleCreated": "角色已创建",
"accessRoleCreatedDescription": "角色已成功创建。", "accessRoleCreatedDescription": "角色已成功创建。",
"accessRoleErrorCreate": "创建角色失败", "accessRoleErrorCreate": "创建角色失败",
"accessRoleErrorCreateDescription": "创建角色时出错。", "accessRoleErrorCreateDescription": "创建角色时出错。",
"accessRoleUpdateSubmit": "更新角色", "accessRoleUpdateSubmit": "Update Role",
"accessRoleUpdated": "角色已更新", "accessRoleUpdated": "Role updated",
"accessRoleUpdatedDescription": "角色已成功更新。", "accessRoleUpdatedDescription": "The role has been successfully updated.",
"accessApprovalUpdated": "审批已处理", "accessApprovalUpdated": "Approval processed",
"accessApprovalApprovedDescription": "将审批请求决定设置为已批准。", "accessApprovalApprovedDescription": "Set Approval Request decision to approved.",
"accessApprovalDeniedDescription": "设置审批请求决定被拒绝。", "accessApprovalDeniedDescription": "Set Approval Request decision to denied.",
"accessRoleErrorUpdate": "更新角色失败", "accessRoleErrorUpdate": "Failed to update role",
"accessRoleErrorUpdateDescription": "更新角色时出错。", "accessRoleErrorUpdateDescription": "An error occurred while updating the role.",
"accessApprovalErrorUpdate": "处理审核失败", "accessApprovalErrorUpdate": "Failed to process approval",
"accessApprovalErrorUpdateDescription": "处理批准时出错。", "accessApprovalErrorUpdateDescription": "An error occurred while processing the approval.",
"accessRoleErrorNewRequired": "需要新角色", "accessRoleErrorNewRequired": "需要新角色",
"accessRoleErrorRemove": "删除角色失败", "accessRoleErrorRemove": "删除角色失败",
"accessRoleErrorRemoveDescription": "删除角色时出错。", "accessRoleErrorRemoveDescription": "删除角色时出错。",
"accessRoleName": "角色名称", "accessRoleName": "角色名称",
"accessRoleQuestionRemove": "您即将删除 `{name}` 角色。此操作无法撤销。", "accessRoleQuestionRemove": "You're about to delete the `{name}` role. You cannot undo this action.",
"accessRoleRemove": "删除角色", "accessRoleRemove": "删除角色",
"accessRoleRemoveDescription": "从组织中删除角色", "accessRoleRemoveDescription": "从组织中删除角色",
"accessRoleRemoveSubmit": "删除角色", "accessRoleRemoveSubmit": "删除角色",
@@ -903,7 +903,7 @@
"inviteAlready": "看起来您已被邀请!", "inviteAlready": "看起来您已被邀请!",
"inviteAlreadyDescription": "要接受邀请,您必须登录或创建一个帐户。", "inviteAlreadyDescription": "要接受邀请,您必须登录或创建一个帐户。",
"signupQuestion": "已经有一个帐户?", "signupQuestion": "已经有一个帐户?",
"login": "登录", "login": "Log In",
"resourceNotFound": "找不到资源", "resourceNotFound": "找不到资源",
"resourceNotFoundDescription": "您要访问的资源不存在。", "resourceNotFoundDescription": "您要访问的资源不存在。",
"pincodeRequirementsLength": "PIN码必须是6位数字", "pincodeRequirementsLength": "PIN码必须是6位数字",
@@ -983,13 +983,13 @@
"passwordExpiryDescription": "该机构要求您每 {maxDays} 天更改一次密码。", "passwordExpiryDescription": "该机构要求您每 {maxDays} 天更改一次密码。",
"changePasswordNow": "现在更改密码", "changePasswordNow": "现在更改密码",
"pincodeAuth": "验证器代码", "pincodeAuth": "验证器代码",
"pincodeSubmit2": "提交代码", "pincodeSubmit2": "Submit code",
"passwordResetSubmit": "请求重置", "passwordResetSubmit": "请求重置",
"passwordResetAlreadyHaveCode": "输入代码", "passwordResetAlreadyHaveCode": "输入代码",
"passwordResetSmtpRequired": "请联系您的管理员", "passwordResetSmtpRequired": "请联系您的管理员",
"passwordResetSmtpRequiredDescription": "需要密码重置密码。请联系您的管理员寻求帮助。", "passwordResetSmtpRequiredDescription": "需要密码重置密码。请联系您的管理员寻求帮助。",
"passwordBack": "回到密码", "passwordBack": "回到密码",
"loginBack": "返回主登录页面", "loginBack": "Go back to main login page",
"signup": "注册", "signup": "注册",
"loginStart": "登录以开始", "loginStart": "登录以开始",
"idpOidcTokenValidating": "正在验证 OIDC 令牌", "idpOidcTokenValidating": "正在验证 OIDC 令牌",
@@ -1147,10 +1147,10 @@
"actionUpdateIdpOrg": "更新 IDP组织", "actionUpdateIdpOrg": "更新 IDP组织",
"actionCreateClient": "创建客户端", "actionCreateClient": "创建客户端",
"actionDeleteClient": "删除客户端", "actionDeleteClient": "删除客户端",
"actionArchiveClient": "归档客户端", "actionArchiveClient": "Archive Client",
"actionUnarchiveClient": "取消归档客户端", "actionUnarchiveClient": "Unarchive Client",
"actionBlockClient": "屏蔽客户端", "actionBlockClient": "Block Client",
"actionUnblockClient": "解除屏蔽客户端", "actionUnblockClient": "Unblock Client",
"actionUpdateClient": "更新客户端", "actionUpdateClient": "更新客户端",
"actionListClients": "列出客户端", "actionListClients": "列出客户端",
"actionGetClient": "获取客户端", "actionGetClient": "获取客户端",
@@ -1167,14 +1167,14 @@
"searchProgress": "搜索中...", "searchProgress": "搜索中...",
"create": "创建", "create": "创建",
"orgs": "组织", "orgs": "组织",
"loginError": "发生意外错误。请重试。", "loginError": "An unexpected error occurred. Please try again.",
"loginRequiredForDevice": "您的设备需要登录。", "loginRequiredForDevice": "Login is required for your device.",
"passwordForgot": "忘记密码?", "passwordForgot": "忘记密码?",
"otpAuth": "两步验证", "otpAuth": "两步验证",
"otpAuthDescription": "从您的身份验证程序中输入代码或您的单次备份代码。", "otpAuthDescription": "从您的身份验证程序中输入代码或您的单次备份代码。",
"otpAuthSubmit": "提交代码", "otpAuthSubmit": "提交代码",
"idpContinue": "或者继续", "idpContinue": "或者继续",
"otpAuthBack": "回到密码", "otpAuthBack": "Back to Password",
"navbar": "导航菜单", "navbar": "导航菜单",
"navbarDescription": "应用程序的主导航菜单", "navbarDescription": "应用程序的主导航菜单",
"navbarDocsLink": "文件", "navbarDocsLink": "文件",
@@ -1222,7 +1222,7 @@
"sidebarOverview": "概览", "sidebarOverview": "概览",
"sidebarHome": "首页", "sidebarHome": "首页",
"sidebarSites": "站点", "sidebarSites": "站点",
"sidebarApprovals": "审批请求", "sidebarApprovals": "Approval Requests",
"sidebarResources": "资源", "sidebarResources": "资源",
"sidebarProxyResources": "公开的", "sidebarProxyResources": "公开的",
"sidebarClientResources": "非公开的", "sidebarClientResources": "非公开的",
@@ -1239,7 +1239,7 @@
"sidebarIdentityProviders": "身份提供商", "sidebarIdentityProviders": "身份提供商",
"sidebarLicense": "证书", "sidebarLicense": "证书",
"sidebarClients": "客户端", "sidebarClients": "客户端",
"sidebarUserDevices": "用户设备", "sidebarUserDevices": "User Devices",
"sidebarMachineClients": "机", "sidebarMachineClients": "机",
"sidebarDomains": "域", "sidebarDomains": "域",
"sidebarGeneral": "管理", "sidebarGeneral": "管理",
@@ -1311,7 +1311,7 @@
"setupErrorCreateAdmin": "创建服务器管理员账户时发生错误。", "setupErrorCreateAdmin": "创建服务器管理员账户时发生错误。",
"certificateStatus": "证书状态", "certificateStatus": "证书状态",
"loading": "加载中", "loading": "加载中",
"loadingAnalytics": "加载分析", "loadingAnalytics": "Loading Analytics",
"restart": "重启", "restart": "重启",
"domains": "域", "domains": "域",
"domainsDescription": "创建和管理组织中可用的域", "domainsDescription": "创建和管理组织中可用的域",
@@ -1339,7 +1339,7 @@
"refreshError": "刷新数据失败", "refreshError": "刷新数据失败",
"verified": "已验证", "verified": "已验证",
"pending": "待定", "pending": "待定",
"pendingApproval": "等待批准", "pendingApproval": "Pending Approval",
"sidebarBilling": "计费", "sidebarBilling": "计费",
"billing": "计费", "billing": "计费",
"orgBillingDescription": "管理账单信息和订阅", "orgBillingDescription": "管理账单信息和订阅",
@@ -1456,7 +1456,7 @@
"securityKeyRemoveSuccess": "安全密钥删除成功", "securityKeyRemoveSuccess": "安全密钥删除成功",
"securityKeyRemoveError": "删除安全密钥失败", "securityKeyRemoveError": "删除安全密钥失败",
"securityKeyLoadError": "加载安全密钥失败", "securityKeyLoadError": "加载安全密钥失败",
"securityKeyLogin": "使用安全密钥", "securityKeyLogin": "Use Security Key",
"securityKeyAuthError": "使用安全密钥认证失败", "securityKeyAuthError": "使用安全密钥认证失败",
"securityKeyRecommendation": "考虑在其他设备上注册另一个安全密钥,以确保不会被锁定在您的账户之外。", "securityKeyRecommendation": "考虑在其他设备上注册另一个安全密钥,以确保不会被锁定在您的账户之外。",
"registering": "注册中...", "registering": "注册中...",
@@ -1583,8 +1583,8 @@
"IntervalSeconds": "正常间隔", "IntervalSeconds": "正常间隔",
"timeoutSeconds": "超时(秒)", "timeoutSeconds": "超时(秒)",
"timeIsInSeconds": "时间以秒为单位", "timeIsInSeconds": "时间以秒为单位",
"requireDeviceApproval": "需要设备批准", "requireDeviceApproval": "Require Device Approvals",
"requireDeviceApprovalDescription": "具有此角色的用户需要管理员批准的新设备才能连接和访问资源。", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
"retryAttempts": "重试次数", "retryAttempts": "重试次数",
"expectedResponseCodes": "期望响应代码", "expectedResponseCodes": "期望响应代码",
"expectedResponseCodesDescription": "HTTP 状态码表示健康状态。如留空,200-300 被视为健康。", "expectedResponseCodesDescription": "HTTP 状态码表示健康状态。如留空,200-300 被视为健康。",
@@ -1625,8 +1625,6 @@
"resourcesTableNoInternalResourcesFound": "未找到内部资源。", "resourcesTableNoInternalResourcesFound": "未找到内部资源。",
"resourcesTableDestination": "目标", "resourcesTableDestination": "目标",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "别名地址",
"resourcesTableAliasAddressInfo": "此地址是组织实用子网的一部分。它用来使用内部DNS解析来解析别名记录。",
"resourcesTableClients": "客户端", "resourcesTableClients": "客户端",
"resourcesTableAndOnlyAccessibleInternally": "且仅在与客户端连接时可内部访问。", "resourcesTableAndOnlyAccessibleInternally": "且仅在与客户端连接时可内部访问。",
"resourcesTableNoTargets": "没有目标", "resourcesTableNoTargets": "没有目标",
@@ -1916,7 +1914,7 @@
"orgAuthChooseIdpDescription": "选择您的身份提供商以继续", "orgAuthChooseIdpDescription": "选择您的身份提供商以继续",
"orgAuthNoIdpConfigured": "此机构没有配置任何身份提供者。您可以使用您的 Pangolin 身份登录。", "orgAuthNoIdpConfigured": "此机构没有配置任何身份提供者。您可以使用您的 Pangolin 身份登录。",
"orgAuthSignInWithPangolin": "使用 Pangolin 登录", "orgAuthSignInWithPangolin": "使用 Pangolin 登录",
"orgAuthSignInToOrg": "登录到组织", "orgAuthSignInToOrg": "Sign in to an organization",
"orgAuthSelectOrgTitle": "组织登录", "orgAuthSelectOrgTitle": "组织登录",
"orgAuthSelectOrgDescription": "输入您的组织ID以继续", "orgAuthSelectOrgDescription": "输入您的组织ID以继续",
"orgAuthOrgIdPlaceholder": "您的组织", "orgAuthOrgIdPlaceholder": "您的组织",
@@ -2272,8 +2270,8 @@
"deviceCodeInvalidFormat": "代码必须是9个字符(如A1AJ-N5JD)", "deviceCodeInvalidFormat": "代码必须是9个字符(如A1AJ-N5JD)",
"deviceCodeInvalidOrExpired": "无效或过期的代码", "deviceCodeInvalidOrExpired": "无效或过期的代码",
"deviceCodeVerifyFailed": "验证设备代码失败", "deviceCodeVerifyFailed": "验证设备代码失败",
"deviceCodeValidating": "正在验证设备代码...", "deviceCodeValidating": "Validating device code...",
"deviceCodeVerifying": "正在验证设备授权...", "deviceCodeVerifying": "Verifying device authorization...",
"signedInAs": "登录为", "signedInAs": "登录为",
"deviceCodeEnterPrompt": "输入设备上显示的代码", "deviceCodeEnterPrompt": "输入设备上显示的代码",
"continue": "继续", "continue": "继续",
@@ -2286,7 +2284,7 @@
"deviceOrganizationsAccess": "访问您的帐户拥有访问权限的所有组织", "deviceOrganizationsAccess": "访问您的帐户拥有访问权限的所有组织",
"deviceAuthorize": "授权{applicationName}", "deviceAuthorize": "授权{applicationName}",
"deviceConnected": "设备已连接!", "deviceConnected": "设备已连接!",
"deviceAuthorizedMessage": "设备被授权访问您的帐户。请返回客户端应用程序。", "deviceAuthorizedMessage": "Device is authorized to access your account. Please return to the client application.",
"pangolinCloud": "邦戈林云", "pangolinCloud": "邦戈林云",
"viewDevices": "查看设备", "viewDevices": "查看设备",
"viewDevicesDescription": "管理您已连接的设备", "viewDevicesDescription": "管理您已连接的设备",
@@ -2348,7 +2346,7 @@
"identifier": "Identifier", "identifier": "Identifier",
"deviceLoginUseDifferentAccount": "不是你?使用一个不同的帐户。", "deviceLoginUseDifferentAccount": "不是你?使用一个不同的帐户。",
"deviceLoginDeviceRequestingAccessToAccount": "设备正在请求访问此帐户。", "deviceLoginDeviceRequestingAccessToAccount": "设备正在请求访问此帐户。",
"loginSelectAuthenticationMethod": "选择要继续的身份验证方法。", "loginSelectAuthenticationMethod": "Select an authentication method to continue.",
"noData": "无数据", "noData": "无数据",
"machineClients": "机器客户端", "machineClients": "机器客户端",
"install": "安装", "install": "安装",
@@ -2438,103 +2436,91 @@
"maintenanceScreenMessage": "我们目前遇到技术问题。 请稍后再回来查看。", "maintenanceScreenMessage": "我们目前遇到技术问题。 请稍后再回来查看。",
"maintenanceScreenEstimatedCompletion": "预计完成时间:", "maintenanceScreenEstimatedCompletion": "预计完成时间:",
"createInternalResourceDialogDestinationRequired": "需要目标地址", "createInternalResourceDialogDestinationRequired": "需要目标地址",
"available": "可用", "available": "Available",
"archived": "已存档", "archived": "Archived",
"noArchivedDevices": "未找到存档设备", "noArchivedDevices": "No archived devices found",
"deviceArchived": "设备已存档", "deviceArchived": "Device archived",
"deviceArchivedDescription": "设备已成功归档。", "deviceArchivedDescription": "The device has been successfully archived.",
"errorArchivingDevice": "错误存档设备", "errorArchivingDevice": "Error archiving device",
"failedToArchiveDevice": "归档设备失败", "failedToArchiveDevice": "Failed to archive device",
"deviceQuestionArchive": "您确定要存档此设备吗?", "deviceQuestionArchive": "Are you sure you want to archive this device?",
"deviceMessageArchive": "设备将被存档并从活动设备列表中删除。", "deviceMessageArchive": "The device will be archived and removed from your active devices list.",
"deviceArchiveConfirm": "归档设备", "deviceArchiveConfirm": "Archive Device",
"archiveDevice": "归档设备", "archiveDevice": "Archive Device",
"archive": "存档", "archive": "Archive",
"deviceUnarchived": "设备未存档", "deviceUnarchived": "Device unarchived",
"deviceUnarchivedDescription": "设备已成功解除归档。", "deviceUnarchivedDescription": "The device has been successfully unarchived.",
"errorUnarchivingDevice": "卸载设备时出错", "errorUnarchivingDevice": "Error unarchiving device",
"failedToUnarchiveDevice": "取消归档设备失败", "failedToUnarchiveDevice": "Failed to unarchive device",
"unarchive": "取消存档", "unarchive": "Unarchive",
"archiveClient": "归档客户端", "archiveClient": "Archive Client",
"archiveClientQuestion": "您确定要存档此客户端吗?", "archiveClientQuestion": "Are you sure you want to archive this client?",
"archiveClientMessage": "客户端将被存档并从您活跃的客户端列表中删除。", "archiveClientMessage": "The client will be archived and removed from your active clients list.",
"archiveClientConfirm": "归档客户端", "archiveClientConfirm": "Archive Client",
"blockClient": "屏蔽客户端", "blockClient": "Block Client",
"blockClientQuestion": "您确定要屏蔽此客户端?", "blockClientQuestion": "Are you sure you want to block this client?",
"blockClientMessage": "如果当前连接,设备将被迫断开连接。您可以稍后取消屏蔽设备。", "blockClientMessage": "The device will be forced to disconnect if currently connected. You can unblock the device later.",
"blockClientConfirm": "屏蔽客户端", "blockClientConfirm": "Block Client",
"active": "已启用", "active": "Active",
"usernameOrEmail": "用户名或电子邮件", "usernameOrEmail": "Username or Email",
"selectYourOrganization": "选择您的组织", "selectYourOrganization": "Select your organization",
"signInTo": "登录到", "signInTo": "Log in in to",
"signInWithPassword": "使用密码继续", "signInWithPassword": "Continue with Password",
"noAuthMethodsAvailable": "该组织没有可用的身份验证方法。", "noAuthMethodsAvailable": "No authentication methods available for this organization.",
"enterPassword": "输入您的密码", "enterPassword": "Enter your password",
"enterMfaCode": "从您的身份验证程序中输入代码", "enterMfaCode": "Enter the code from your authenticator app",
"securityKeyRequired": "请使用您的安全密钥登录。", "securityKeyRequired": "Please use your security key to sign in.",
"needToUseAnotherAccount": "需要使用不同的帐户?", "needToUseAnotherAccount": "Need to use a different account?",
"loginLegalDisclaimer": "点击下面的按钮,您确认您已经阅读了,理解, 并同意 <termsOfService>服务条款</termsOfService> <privacyPolicy>隐私政策</privacyPolicy>", "loginLegalDisclaimer": "By clicking the buttons below, you acknowledge you have read, understand, and agree to the <termsOfService>Terms of Service</termsOfService> and <privacyPolicy>Privacy Policy</privacyPolicy>.",
"termsOfService": "服务条款", "termsOfService": "Terms of Service",
"privacyPolicy": "隐私政策", "privacyPolicy": "Privacy Policy",
"userNotFoundWithUsername": "找不到该用户名。", "userNotFoundWithUsername": "No user found with that username.",
"verify": "验证", "verify": "Verify",
"signIn": "登录", "signIn": "Sign In",
"forgotPassword": "忘记密码?", "forgotPassword": "Forgot password?",
"orgSignInTip": "如果您以前已经登录,您可以在上面输入您的用户名或电子邮件来验证您的组织身份提供者。这很容易!", "orgSignInTip": "If you've logged in before, you can enter your username or email above to authenticate with your organization's identity provider instead. It's easier!",
"continueAnyway": "仍然继续", "continueAnyway": "Continue anyway",
"dontShowAgain": "不再显示", "dontShowAgain": "Don't show again",
"orgSignInNotice": "您知道吗?", "orgSignInNotice": "Did you know?",
"signupOrgNotice": "试图登录?", "signupOrgNotice": "Trying to sign in?",
"signupOrgTip": "您是否试图通过您的组织的身份提供者登录?", "signupOrgTip": "Are you trying to sign in through your organization's identity provider?",
"signupOrgLink": "使用您的组织登录或注册", "signupOrgLink": "Sign in or sign up with your organization instead",
"verifyEmailLogInWithDifferentAccount": "使用不同的帐户", "verifyEmailLogInWithDifferentAccount": "Use a Different Account",
"logIn": "登录", "logIn": "Log In",
"deviceInformation": "设备信息", "deviceInformation": "Device Information",
"deviceInformationDescription": "关于设备和代理的信息", "deviceInformationDescription": "Information about the device and agent",
"deviceSecurity": "设备安全", "platform": "Platform",
"deviceSecurityDescription": "设备安全态势信息", "macosVersion": "macOS Version",
"platform": "平台", "windowsVersion": "Windows Version",
"macosVersion": "macOS 版本", "iosVersion": "iOS Version",
"windowsVersion": "Windows 版本", "androidVersion": "Android Version",
"iosVersion": "iOS 版本", "osVersion": "OS Version",
"androidVersion": "Android 版本", "kernelVersion": "Kernel Version",
"osVersion": "操作系统版本", "deviceModel": "Device Model",
"kernelVersion": "内核版本", "serialNumber": "Serial Number",
"deviceModel": "设备模型",
"serialNumber": "序列号",
"hostname": "Hostname", "hostname": "Hostname",
"firstSeen": "第一次查看", "firstSeen": "First Seen",
"lastSeen": "上次查看时间", "lastSeen": "Last Seen",
"biometricsEnabled": "生物计已启用", "deviceSettingsDescription": "View device information and settings",
"diskEncrypted": "磁盘加密", "devicePendingApprovalDescription": "This device is waiting for approval",
"firewallEnabled": "防火墙已启用", "deviceBlockedDescription": "This device is currently blocked. It won't be able to connect to any resources unless unblocked.",
"autoUpdatesEnabled": "启用自动更新", "unblockClient": "Unblock Client",
"tpmAvailable": "TPM 可用", "unblockClientDescription": "The device has been unblocked",
"macosSipEnabled": "系统完整性保护 (SIP)", "unarchiveClient": "Unarchive Client",
"macosGatekeeperEnabled": "Gatekeeper", "unarchiveClientDescription": "The device has been unarchived",
"macosFirewallStealthMode": "防火墙隐形模式", "block": "Block",
"linuxAppArmorEnabled": "AppArmor", "unblock": "Unblock",
"linuxSELinuxEnabled": "SELinux", "deviceActions": "Device Actions",
"deviceSettingsDescription": "查看设备信息和设置", "deviceActionsDescription": "Manage device status and access",
"devicePendingApprovalDescription": "此设备正在等待批准", "devicePendingApprovalBannerDescription": "This device is pending approval. It won't be able to connect to resources until approved.",
"deviceBlockedDescription": "此设备目前已被屏蔽。除非解除屏蔽,否则无法连接到任何资源。", "connected": "Connected",
"unblockClient": "解除屏蔽客户端", "disconnected": "Disconnected",
"unblockClientDescription": "设备已解除阻止", "approvalsEmptyStateTitle": "Device Approvals Not Enabled",
"unarchiveClient": "取消归档客户端", "approvalsEmptyStateDescription": "Enable device approvals for roles to require admin approval before users can connect new devices.",
"unarchiveClientDescription": "设备已被取消存档", "approvalsEmptyStateStep1Title": "Go to Roles",
"block": "封禁", "approvalsEmptyStateStep1Description": "Navigate to your organization's roles settings to configure device approvals.",
"unblock": "取消屏蔽", "approvalsEmptyStateStep2Title": "Enable Device Approvals",
"deviceActions": "设备操作", "approvalsEmptyStateStep2Description": "Edit a role and enable the 'Require Device Approvals' option. Users with this role will need admin approval for new devices.",
"deviceActionsDescription": "管理设备状态和访问权限", "approvalsEmptyStatePreviewDescription": "Preview: When enabled, pending device requests will appear here for review",
"devicePendingApprovalBannerDescription": "此设备正在等待批准。在批准之前,它将无法连接到资源。", "approvalsEmptyStateButtonText": "Manage Roles"
"connected": "已连接",
"disconnected": "断开连接",
"approvalsEmptyStateTitle": "设备批准未启用",
"approvalsEmptyStateDescription": "在用户连接新设备之前,允许设备批准角色,需要管理员批准。",
"approvalsEmptyStateStep1Title": "转到角色",
"approvalsEmptyStateStep1Description": "导航到您组织的角色设置来配置设备批准。",
"approvalsEmptyStateStep2Title": "启用设备批准",
"approvalsEmptyStateStep2Description": "编辑角色并启用“需要设备审批”选项。具有此角色的用户需要管理员批准新设备。",
"approvalsEmptyStatePreviewDescription": "预览:如果启用,待处理设备请求将出现在这里供审核",
"approvalsEmptyStateButtonText": "管理角色"
} }
+2095 -2392
View File
File diff suppressed because it is too large Load Diff
+920 -856
View File
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -3,7 +3,7 @@
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "Identity-aware VPN and proxy for remote access to anything, anywhere and Dashboard UI", "description": "Tunneled Reverse Proxy Management Server with Identity and Access Control and Dashboard UI",
"homepage": "https://github.com/fosrl/pangolin", "homepage": "https://github.com/fosrl/pangolin",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -33,9 +33,9 @@
"format": "prettier --write ." "format": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"@asteasolutions/zod-to-openapi": "8.4.0", "@asteasolutions/zod-to-openapi": "8.2.0",
"@aws-sdk/client-s3": "3.971.0", "@aws-sdk/client-s3": "3.955.0",
"@faker-js/faker": "10.2.0", "@faker-js/faker": "10.1.0",
"@headlessui/react": "2.2.9", "@headlessui/react": "2.2.9",
"@hookform/resolvers": "5.2.2", "@hookform/resolvers": "5.2.2",
"@monaco-editor/react": "4.7.0", "@monaco-editor/react": "4.7.0",
@@ -92,7 +92,7 @@
"http-errors": "2.0.1", "http-errors": "2.0.1",
"i": "0.3.7", "i": "0.3.7",
"input-otp": "1.4.2", "input-otp": "1.4.2",
"ioredis": "5.9.2", "ioredis": "5.8.2",
"jmespath": "0.16.0", "jmespath": "0.16.0",
"js-yaml": "4.1.1", "js-yaml": "4.1.1",
"jsonwebtoken": "9.0.3", "jsonwebtoken": "9.0.3",
@@ -100,7 +100,7 @@
"maxmind": "5.0.1", "maxmind": "5.0.1",
"moment": "2.30.1", "moment": "2.30.1",
"next": "15.5.9", "next": "15.5.9",
"next-intl": "4.7.0", "next-intl": "4.6.1",
"next-themes": "0.4.6", "next-themes": "0.4.6",
"nextjs-toploader": "3.9.17", "nextjs-toploader": "3.9.17",
"node-cache": "5.1.2", "node-cache": "5.1.2",
@@ -109,21 +109,21 @@
"npm": "11.7.0", "npm": "11.7.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"oslo": "1.2.1", "oslo": "1.2.1",
"pg": "8.17.1", "pg": "8.16.3",
"posthog-node": "5.23.0", "posthog-node": "5.17.4",
"qrcode.react": "4.2.0", "qrcode.react": "4.2.0",
"react": "19.2.3", "react": "19.2.3",
"react-day-picker": "9.13.0", "react-day-picker": "9.13.0",
"react-dom": "19.2.3", "react-dom": "19.2.3",
"react-easy-sort": "1.8.0", "react-easy-sort": "1.8.0",
"react-hook-form": "7.71.1", "react-hook-form": "7.68.0",
"react-icons": "5.5.0", "react-icons": "5.5.0",
"rebuild": "0.1.2", "rebuild": "0.1.2",
"recharts": "2.15.4", "recharts": "2.15.4",
"reodotdev": "1.0.0", "reodotdev": "1.0.0",
"resend": "6.8.0", "resend": "6.6.0",
"semver": "7.7.3", "semver": "7.7.3",
"stripe": "20.2.0", "stripe": "20.1.0",
"swagger-ui-express": "5.0.1", "swagger-ui-express": "5.0.1",
"tailwind-merge": "3.4.0", "tailwind-merge": "3.4.0",
"topojson-client": "3.1.0", "topojson-client": "3.1.0",
@@ -133,10 +133,10 @@
"visionscarto-world-atlas": "1.0.0", "visionscarto-world-atlas": "1.0.0",
"winston": "3.19.0", "winston": "3.19.0",
"winston-daily-rotate-file": "5.0.0", "winston-daily-rotate-file": "5.0.0",
"ws": "8.19.0", "ws": "8.18.3",
"yaml": "2.8.2", "yaml": "2.8.2",
"yargs": "18.0.0", "yargs": "18.0.0",
"zod": "4.3.5", "zod": "4.2.1",
"zod-validation-error": "5.0.0" "zod-validation-error": "5.0.0"
}, },
"devDependencies": { "devDependencies": {
@@ -170,12 +170,12 @@
"esbuild": "0.27.2", "esbuild": "0.27.2",
"esbuild-node-externals": "1.20.1", "esbuild-node-externals": "1.20.1",
"postcss": "8.5.6", "postcss": "8.5.6",
"prettier": "3.8.0", "prettier": "3.7.4",
"react-email": "5.2.5", "react-email": "5.0.7",
"tailwindcss": "4.1.18", "tailwindcss": "4.1.18",
"tsc-alias": "1.8.16", "tsc-alias": "1.8.16",
"tsx": "4.21.0", "tsx": "4.21.0",
"typescript": "5.9.3", "typescript": "5.9.3",
"typescript-eslint": "8.53.1" "typescript-eslint": "8.49.0"
} }
} }
+1 -7
View File
@@ -78,10 +78,6 @@ export enum ActionsEnum {
updateSiteResource = "updateSiteResource", updateSiteResource = "updateSiteResource",
createClient = "createClient", createClient = "createClient",
deleteClient = "deleteClient", deleteClient = "deleteClient",
archiveClient = "archiveClient",
unarchiveClient = "unarchiveClient",
blockClient = "blockClient",
unblockClient = "unblockClient",
updateClient = "updateClient", updateClient = "updateClient",
listClients = "listClients", listClients = "listClients",
getClient = "getClient", getClient = "getClient",
@@ -129,9 +125,7 @@ export enum ActionsEnum {
getBlueprint = "getBlueprint", getBlueprint = "getBlueprint",
applyBlueprint = "applyBlueprint", applyBlueprint = "applyBlueprint",
viewLogs = "viewLogs", viewLogs = "viewLogs",
exportLogs = "exportLogs", exportLogs = "exportLogs"
listApprovals = "listApprovals",
updateApprovals = "updateApprovals"
} }
export async function checkUserActionPermission( export async function checkUserActionPermission(
-150
View File
@@ -1,150 +0,0 @@
{
"iPad1,1": "iPad",
"iPad2,1": "iPad 2",
"iPad2,2": "iPad 2",
"iPad2,3": "iPad 2",
"iPad2,4": "iPad 2",
"iPad3,1": "iPad 3rd Gen",
"iPad3,3": "iPad 3rd Gen",
"iPad3,2": "iPad 3rd Gen",
"iPad3,4": "iPad 4th Gen",
"iPad3,5": "iPad 4th Gen",
"iPad3,6": "iPad 4th Gen",
"iPad6,11": "iPad 9.7 5th Gen",
"iPad6,12": "iPad 9.7 5th Gen",
"iPad7,5": "iPad 9.7 6th Gen",
"iPad7,6": "iPad 9.7 6th Gen",
"iPad7,11": "iPad 10.2 7th Gen",
"iPad7,12": "iPad 10.2 7th Gen",
"iPad11,6": "iPad 10.2 8th Gen",
"iPad11,7": "iPad 10.2 8th Gen",
"iPad12,1": "iPad 10.2 9th Gen",
"iPad12,2": "iPad 10.2 9th Gen",
"iPad13,18": "iPad 10.9 10th Gen",
"iPad13,19": "iPad 10.9 10th Gen",
"iPad4,1": "iPad Air",
"iPad4,2": "iPad Air",
"iPad4,3": "iPad Air",
"iPad5,3": "iPad Air 2",
"iPad5,4": "iPad Air 2",
"iPad11,3": "iPad Air 3rd Gen",
"iPad11,4": "iPad Air 3rd Gen",
"iPad13,1": "iPad Air 4th Gen",
"iPad13,2": "iPad Air 4th Gen",
"iPad13,16": "iPad Air 5th Gen",
"iPad13,17": "iPad Air 5th Gen",
"iPad14,8": "iPad Air M2 11",
"iPad14,9": "iPad Air M2 11",
"iPad14,10": "iPad Air M2 13",
"iPad14,11": "iPad Air M2 13",
"iPad2,5": "iPad mini",
"iPad2,6": "iPad mini",
"iPad2,7": "iPad mini",
"iPad4,4": "iPad mini 2",
"iPad4,5": "iPad mini 2",
"iPad4,6": "iPad mini 2",
"iPad4,7": "iPad mini 3",
"iPad4,8": "iPad mini 3",
"iPad4,9": "iPad mini 3",
"iPad5,1": "iPad mini 4",
"iPad5,2": "iPad mini 4",
"iPad11,1": "iPad mini 5th Gen",
"iPad11,2": "iPad mini 5th Gen",
"iPad14,1": "iPad mini 6th Gen",
"iPad14,2": "iPad mini 6th Gen",
"iPad6,7": "iPad Pro 12.9",
"iPad6,8": "iPad Pro 12.9",
"iPad6,3": "iPad Pro 9.7",
"iPad6,4": "iPad Pro 9.7",
"iPad7,3": "iPad Pro 10.5",
"iPad7,4": "iPad Pro 10.5",
"iPad7,1": "iPad Pro 12.9",
"iPad7,2": "iPad Pro 12.9",
"iPad8,1": "iPad Pro 11",
"iPad8,2": "iPad Pro 11",
"iPad8,3": "iPad Pro 11",
"iPad8,4": "iPad Pro 11",
"iPad8,5": "iPad Pro 12.9",
"iPad8,6": "iPad Pro 12.9",
"iPad8,7": "iPad Pro 12.9",
"iPad8,8": "iPad Pro 12.9",
"iPad8,9": "iPad Pro 11",
"iPad8,10": "iPad Pro 11",
"iPad8,11": "iPad Pro 12.9",
"iPad8,12": "iPad Pro 12.9",
"iPad13,4": "iPad Pro 11",
"iPad13,5": "iPad Pro 11",
"iPad13,6": "iPad Pro 11",
"iPad13,7": "iPad Pro 11",
"iPad13,8": "iPad Pro 12.9",
"iPad13,9": "iPad Pro 12.9",
"iPad13,10": "iPad Pro 12.9",
"iPad13,11": "iPad Pro 12.9",
"iPad14,3": "iPad Pro 11",
"iPad14,4": "iPad Pro 11",
"iPad14,5": "iPad Pro 12.9",
"iPad14,6": "iPad Pro 12.9",
"iPad16,3": "iPad Pro M4 11",
"iPad16,4": "iPad Pro M4 11",
"iPad16,5": "iPad Pro M4 13",
"iPad16,6": "iPad Pro M4 13",
"iPhone1,1": "iPhone",
"iPhone1,2": "iPhone 3G",
"iPhone2,1": "iPhone 3GS",
"iPhone3,1": "iPhone 4",
"iPhone3,2": "iPhone 4",
"iPhone3,3": "iPhone 4",
"iPhone4,1": "iPhone 4S",
"iPhone5,1": "iPhone 5",
"iPhone5,2": "iPhone 5",
"iPhone5,3": "iPhone 5c",
"iPhone5,4": "iPhone 5c",
"iPhone6,1": "iPhone 5s",
"iPhone6,2": "iPhone 5s",
"iPhone7,2": "iPhone 6",
"iPhone7,1": "iPhone 6 Plus",
"iPhone8,1": "iPhone 6s",
"iPhone8,2": "iPhone 6s Plus",
"iPhone8,4": "iPhone SE",
"iPhone9,1": "iPhone 7",
"iPhone9,3": "iPhone 7",
"iPhone9,2": "iPhone 7 Plus",
"iPhone9,4": "iPhone 7 Plus",
"iPhone10,1": "iPhone 8",
"iPhone10,4": "iPhone 8",
"iPhone10,2": "iPhone 8 Plus",
"iPhone10,5": "iPhone 8 Plus",
"iPhone10,3": "iPhone X",
"iPhone10,6": "iPhone X",
"iPhone11,2": "iPhone Xs",
"iPhone11,6": "iPhone Xs Max",
"iPhone11,8": "iPhone XR",
"iPhone12,1": "iPhone 11",
"iPhone12,3": "iPhone 11 Pro",
"iPhone12,5": "iPhone 11 Pro Max",
"iPhone12,8": "iPhone SE",
"iPhone13,1": "iPhone 12 mini",
"iPhone13,2": "iPhone 12",
"iPhone13,3": "iPhone 12 Pro",
"iPhone13,4": "iPhone 12 Pro Max",
"iPhone14,4": "iPhone 13 mini",
"iPhone14,5": "iPhone 13",
"iPhone14,2": "iPhone 13 Pro",
"iPhone14,3": "iPhone 13 Pro Max",
"iPhone14,6": "iPhone SE",
"iPhone14,7": "iPhone 14",
"iPhone14,8": "iPhone 14 Plus",
"iPhone15,2": "iPhone 14 Pro",
"iPhone15,3": "iPhone 14 Pro Max",
"iPhone15,4": "iPhone 15",
"iPhone15,5": "iPhone 15 Plus",
"iPhone16,1": "iPhone 15 Pro",
"iPhone16,2": "iPhone 15 Pro Max",
"iPod1,1": "iPod touch Original",
"iPod2,1": "iPod touch 2nd",
"iPod3,1": "iPod touch 3rd Gen",
"iPod4,1": "iPod touch 4th",
"iPod5,1": "iPod touch 5th",
"iPod7,1": "iPod touch 6th Gen",
"iPod9,1": "iPod touch 7th Gen"
}
-201
View File
@@ -1,201 +0,0 @@
{
"PowerMac4,4": "eMac",
"PowerMac6,4": "eMac",
"PowerBook2,1": "iBook",
"PowerBook2,2": "iBook",
"PowerBook4,1": "iBook",
"PowerBook4,2": "iBook",
"PowerBook4,3": "iBook",
"PowerBook6,3": "iBook",
"PowerBook6,5": "iBook",
"PowerBook6,7": "iBook",
"iMac,1": "iMac",
"PowerMac2,1": "iMac",
"PowerMac2,2": "iMac",
"PowerMac4,1": "iMac",
"PowerMac4,2": "iMac",
"PowerMac4,5": "iMac",
"PowerMac6,1": "iMac",
"PowerMac6,3*": "iMac",
"PowerMac6,3": "iMac",
"PowerMac8,1": "iMac",
"PowerMac8,2": "iMac",
"PowerMac12,1": "iMac",
"iMac4,1": "iMac",
"iMac4,2": "iMac",
"iMac5,2": "iMac",
"iMac5,1": "iMac",
"iMac6,1": "iMac",
"iMac7,1": "iMac",
"iMac8,1": "iMac",
"iMac9,1": "iMac",
"iMac10,1": "iMac",
"iMac11,1": "iMac",
"iMac11,2": "iMac",
"iMac11,3": "iMac",
"iMac12,1": "iMac",
"iMac12,2": "iMac",
"iMac13,1": "iMac",
"iMac13,2": "iMac",
"iMac14,1": "iMac",
"iMac14,3": "iMac",
"iMac14,2": "iMac",
"iMac14,4": "iMac",
"iMac15,1": "iMac",
"iMac16,1": "iMac",
"iMac16,2": "iMac",
"iMac17,1": "iMac",
"iMac18,1": "iMac",
"iMac18,2": "iMac",
"iMac18,3": "iMac",
"iMac19,2": "iMac",
"iMac19,1": "iMac",
"iMac20,1": "iMac",
"iMac20,2": "iMac",
"iMac21,2": "iMac",
"iMac21,1": "iMac",
"iMacPro1,1": "iMac Pro",
"PowerMac10,1": "Mac mini",
"PowerMac10,2": "Mac mini",
"Macmini1,1": "Mac mini",
"Macmini2,1": "Mac mini",
"Macmini3,1": "Mac mini",
"Macmini4,1": "Mac mini",
"Macmini5,1": "Mac mini",
"Macmini5,2": "Mac mini",
"Macmini5,3": "Mac mini",
"Macmini6,1": "Mac mini",
"Macmini6,2": "Mac mini",
"Macmini7,1": "Mac mini",
"Macmini8,1": "Mac mini",
"ADP3,2": "Mac mini",
"Macmini9,1": "Mac mini",
"Mac14,3": "Mac mini",
"Mac14,12": "Mac mini",
"MacPro1,1*": "Mac Pro",
"MacPro2,1": "Mac Pro",
"MacPro3,1": "Mac Pro",
"MacPro4,1": "Mac Pro",
"MacPro5,1": "Mac Pro",
"MacPro6,1": "Mac Pro",
"MacPro7,1": "Mac Pro",
"N/A*": "Power Macintosh",
"PowerMac1,1": "Power Macintosh",
"PowerMac3,1": "Power Macintosh",
"PowerMac3,3": "Power Macintosh",
"PowerMac3,4": "Power Macintosh",
"PowerMac3,5": "Power Macintosh",
"PowerMac3,6": "Power Macintosh",
"Mac13,1": "Mac Studio",
"Mac13,2": "Mac Studio",
"MacBook1,1": "MacBook",
"MacBook2,1": "MacBook",
"MacBook3,1": "MacBook",
"MacBook4,1": "MacBook",
"MacBook5,1": "MacBook",
"MacBook5,2": "MacBook",
"MacBook6,1": "MacBook",
"MacBook7,1": "MacBook",
"MacBook8,1": "MacBook",
"MacBook9,1": "MacBook",
"MacBook10,1": "MacBook",
"MacBookAir1,1": "MacBook Air",
"MacBookAir2,1": "MacBook Air",
"MacBookAir3,1": "MacBook Air",
"MacBookAir3,2": "MacBook Air",
"MacBookAir4,1": "MacBook Air",
"MacBookAir4,2": "MacBook Air",
"MacBookAir5,1": "MacBook Air",
"MacBookAir5,2": "MacBook Air",
"MacBookAir6,1": "MacBook Air",
"MacBookAir6,2": "MacBook Air",
"MacBookAir7,1": "MacBook Air",
"MacBookAir7,2": "MacBook Air",
"MacBookAir8,1": "MacBook Air",
"MacBookAir8,2": "MacBook Air",
"MacBookAir9,1": "MacBook Air",
"MacBookAir10,1": "MacBook Air",
"Mac14,2": "MacBook Air",
"MacBookPro1,1": "MacBook Pro",
"MacBookPro1,2": "MacBook Pro",
"MacBookPro2,2": "MacBook Pro",
"MacBookPro2,1": "MacBook Pro",
"MacBookPro3,1": "MacBook Pro",
"MacBookPro4,1": "MacBook Pro",
"MacBookPro5,1": "MacBook Pro",
"MacBookPro5,2": "MacBook Pro",
"MacBookPro5,5": "MacBook Pro",
"MacBookPro5,4": "MacBook Pro",
"MacBookPro5,3": "MacBook Pro",
"MacBookPro7,1": "MacBook Pro",
"MacBookPro6,2": "MacBook Pro",
"MacBookPro6,1": "MacBook Pro",
"MacBookPro8,1": "MacBook Pro",
"MacBookPro8,2": "MacBook Pro",
"MacBookPro8,3": "MacBook Pro",
"MacBookPro9,2": "MacBook Pro",
"MacBookPro9,1": "MacBook Pro",
"MacBookPro10,1": "MacBook Pro",
"MacBookPro10,2": "MacBook Pro",
"MacBookPro11,1": "MacBook Pro",
"MacBookPro11,2": "MacBook Pro",
"MacBookPro11,3": "MacBook Pro",
"MacBookPro12,1": "MacBook Pro",
"MacBookPro11,4": "MacBook Pro",
"MacBookPro11,5": "MacBook Pro",
"MacBookPro13,1": "MacBook Pro",
"MacBookPro13,2": "MacBook Pro",
"MacBookPro13,3": "MacBook Pro",
"MacBookPro14,1": "MacBook Pro",
"MacBookPro14,2": "MacBook Pro",
"MacBookPro14,3": "MacBook Pro",
"MacBookPro15,2": "MacBook Pro",
"MacBookPro15,1": "MacBook Pro",
"MacBookPro15,3": "MacBook Pro",
"MacBookPro15,4": "MacBook Pro",
"MacBookPro16,1": "MacBook Pro",
"MacBookPro16,3": "MacBook Pro",
"MacBookPro16,2": "MacBook Pro",
"MacBookPro16,4": "MacBook Pro",
"MacBookPro17,1": "MacBook Pro",
"MacBookPro18,3": "MacBook Pro",
"MacBookPro18,4": "MacBook Pro",
"MacBookPro18,1": "MacBook Pro",
"MacBookPro18,2": "MacBook Pro",
"Mac14,7": "MacBook Pro",
"Mac14,9": "MacBook Pro",
"Mac14,5": "MacBook Pro",
"Mac14,10": "MacBook Pro",
"Mac14,6": "MacBook Pro",
"PowerMac1,2": "Power Macintosh",
"PowerMac5,1": "Power Macintosh",
"PowerMac7,2": "Power Macintosh",
"PowerMac7,3": "Power Macintosh",
"PowerMac9,1": "Power Macintosh",
"PowerMac11,2": "Power Macintosh",
"PowerBook1,1": "PowerBook",
"PowerBook3,1": "PowerBook",
"PowerBook3,2": "PowerBook",
"PowerBook3,3": "PowerBook",
"PowerBook3,4": "PowerBook",
"PowerBook3,5": "PowerBook",
"PowerBook6,1": "PowerBook",
"PowerBook5,1": "PowerBook",
"PowerBook6,2": "PowerBook",
"PowerBook5,2": "PowerBook",
"PowerBook5,3": "PowerBook",
"PowerBook6,4": "PowerBook",
"PowerBook5,4": "PowerBook",
"PowerBook5,5": "PowerBook",
"PowerBook6,8": "PowerBook",
"PowerBook5,6": "PowerBook",
"PowerBook5,7": "PowerBook",
"PowerBook5,8": "PowerBook",
"PowerBook5,9": "PowerBook",
"RackMac1,1": "Xserve",
"RackMac1,2": "Xserve",
"RackMac3,1": "Xserve",
"Xserve1,1": "Xserve",
"Xserve2,1": "Xserve",
"Xserve3,1": "Xserve"
}
-44
View File
@@ -16,24 +16,6 @@ if (!dev) {
} }
export const names = JSON.parse(readFileSync(file, "utf-8")); export const names = JSON.parse(readFileSync(file, "utf-8"));
// Load iOS and Mac model mappings
let iosModelsFile: string;
let macModelsFile: string;
if (!dev) {
iosModelsFile = join(__DIRNAME, "ios_models.json");
macModelsFile = join(__DIRNAME, "mac_models.json");
} else {
iosModelsFile = join("server/db/ios_models.json");
macModelsFile = join("server/db/mac_models.json");
}
const iosModels: Record<string, string> = JSON.parse(
readFileSync(iosModelsFile, "utf-8")
);
const macModels: Record<string, string> = JSON.parse(
readFileSync(macModelsFile, "utf-8")
);
export async function getUniqueClientName(orgId: string): Promise<string> { export async function getUniqueClientName(orgId: string): Promise<string> {
let loops = 0; let loops = 0;
while (true) { while (true) {
@@ -177,29 +159,3 @@ export function generateName(): string {
// clean out any non-alphanumeric characters except for dashes // clean out any non-alphanumeric characters except for dashes
return name.replace(/[^a-z0-9-]/g, ""); return name.replace(/[^a-z0-9-]/g, "");
} }
export function getMacDeviceName(macIdentifier?: string | null): string | null {
if (macIdentifier && macModels[macIdentifier]) {
return macModels[macIdentifier];
}
return null;
}
export function getIosDeviceName(iosIdentifier?: string | null): string | null {
if (iosIdentifier && iosModels[iosIdentifier]) {
return iosModels[iosIdentifier];
}
return null;
}
export function getUserDeviceName(
model: string | null,
fallBack: string | null
): string {
return (
getMacDeviceName(model) ||
getIosDeviceName(model) ||
fallBack ||
"Unknown Device"
);
}
+2 -37
View File
@@ -10,15 +10,7 @@ import {
index index
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import { InferSelectModel } from "drizzle-orm"; import { InferSelectModel } from "drizzle-orm";
import { import { domains, orgs, targets, users, exitNodes, sessions } from "./schema";
domains,
orgs,
targets,
users,
exitNodes,
sessions,
clients
} from "./schema";
export const certificates = pgTable("certificates", { export const certificates = pgTable("certificates", {
certId: serial("certId").primaryKey(), certId: serial("certId").primaryKey(),
@@ -214,7 +206,7 @@ export const loginPageOrg = pgTable("loginPageOrg", {
export const loginPageBranding = pgTable("loginPageBranding", { export const loginPageBranding = pgTable("loginPageBranding", {
loginPageBrandingId: serial("loginPageBrandingId").primaryKey(), loginPageBrandingId: serial("loginPageBrandingId").primaryKey(),
logoUrl: text("logoUrl"), logoUrl: text("logoUrl").notNull(),
logoWidth: integer("logoWidth").notNull(), logoWidth: integer("logoWidth").notNull(),
logoHeight: integer("logoHeight").notNull(), logoHeight: integer("logoHeight").notNull(),
primaryColor: text("primaryColor"), primaryColor: text("primaryColor"),
@@ -297,33 +289,6 @@ export const accessAuditLog = pgTable(
] ]
); );
export const approvals = pgTable("approvals", {
approvalId: serial("approvalId").primaryKey(),
timestamp: integer("timestamp").notNull(), // this is EPOCH time in seconds
orgId: varchar("orgId")
.references(() => orgs.orgId, {
onDelete: "cascade"
})
.notNull(),
clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade"
}), // clients reference user devices (in this case)
userId: varchar("userId")
.references(() => users.userId, {
// optionally tied to a user and in this case delete when the user deletes
onDelete: "cascade"
})
.notNull(),
decision: varchar("decision")
.$type<"approved" | "denied" | "pending">()
.default("pending")
.notNull(),
type: varchar("type")
.$type<"user_device" /*| 'proxy' // for later */>()
.notNull()
});
export type Approval = InferSelectModel<typeof approvals>;
export type Limit = InferSelectModel<typeof limits>; export type Limit = InferSelectModel<typeof limits>;
export type Account = InferSelectModel<typeof account>; export type Account = InferSelectModel<typeof account>;
export type Certificate = InferSelectModel<typeof certificates>; export type Certificate = InferSelectModel<typeof certificates>;
+4 -132
View File
@@ -365,8 +365,7 @@ export const roles = pgTable("roles", {
.notNull(), .notNull(),
isAdmin: boolean("isAdmin"), isAdmin: boolean("isAdmin"),
name: varchar("name").notNull(), name: varchar("name").notNull(),
description: varchar("description"), description: varchar("description")
requireDeviceApproval: boolean("requireDeviceApproval").default(false)
}); });
export const roleActions = pgTable("roleActions", { export const roleActions = pgTable("roleActions", {
@@ -592,8 +591,7 @@ export const idp = pgTable("idp", {
type: varchar("type").notNull(), type: varchar("type").notNull(),
defaultRoleMapping: varchar("defaultRoleMapping"), defaultRoleMapping: varchar("defaultRoleMapping"),
defaultOrgMapping: varchar("defaultOrgMapping"), defaultOrgMapping: varchar("defaultOrgMapping"),
autoProvision: boolean("autoProvision").notNull().default(false), autoProvision: boolean("autoProvision").notNull().default(false)
tags: text("tags")
}); });
export const idpOidcConfig = pgTable("idpOidcConfig", { export const idpOidcConfig = pgTable("idpOidcConfig", {
@@ -690,12 +688,7 @@ export const clients = pgTable("clients", {
online: boolean("online").notNull().default(false), online: boolean("online").notNull().default(false),
// endpoint: varchar("endpoint"), // endpoint: varchar("endpoint"),
lastHolePunch: integer("lastHolePunch"), lastHolePunch: integer("lastHolePunch"),
maxConnections: integer("maxConnections"), maxConnections: integer("maxConnections")
archived: boolean("archived").notNull().default(false),
blocked: boolean("blocked").notNull().default(false),
approvalState: varchar("approvalState").$type<
"pending" | "approved" | "denied"
>()
}); });
export const clientSitesAssociationsCache = pgTable( export const clientSitesAssociationsCache = pgTable(
@@ -719,16 +712,6 @@ export const clientSiteResourcesAssociationsCache = pgTable(
} }
); );
export const clientPostureSnapshots = pgTable("clientPostureSnapshots", {
snapshotId: serial("snapshotId").primaryKey(),
clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade"
}),
collectedAt: integer("collectedAt").notNull()
});
export const olms = pgTable("olms", { export const olms = pgTable("olms", {
olmId: varchar("id").primaryKey(), olmId: varchar("id").primaryKey(),
secretHash: varchar("secretHash").notNull(), secretHash: varchar("secretHash").notNull(),
@@ -743,118 +726,7 @@ export const olms = pgTable("olms", {
userId: text("userId").references(() => users.userId, { userId: text("userId").references(() => users.userId, {
// optionally tied to a user and in this case delete when the user deletes // optionally tied to a user and in this case delete when the user deletes
onDelete: "cascade" onDelete: "cascade"
}), })
archived: boolean("archived").notNull().default(false)
});
export const currentFingerprint = pgTable("currentFingerprint", {
fingerprintId: serial("id").primaryKey(),
olmId: text("olmId")
.references(() => olms.olmId, { onDelete: "cascade" })
.notNull(),
firstSeen: integer("firstSeen").notNull(),
lastSeen: integer("lastSeen").notNull(),
lastCollectedAt: integer("lastCollectedAt").notNull(),
username: text("username"),
hostname: text("hostname"),
platform: text("platform"),
osVersion: text("osVersion"),
kernelVersion: text("kernelVersion"),
arch: text("arch"),
deviceModel: text("deviceModel"),
serialNumber: text("serialNumber"),
platformFingerprint: varchar("platformFingerprint"),
// Platform-agnostic checks
biometricsEnabled: boolean("biometricsEnabled").notNull().default(false),
diskEncrypted: boolean("diskEncrypted").notNull().default(false),
firewallEnabled: boolean("firewallEnabled").notNull().default(false),
autoUpdatesEnabled: boolean("autoUpdatesEnabled").notNull().default(false),
tpmAvailable: boolean("tpmAvailable").notNull().default(false),
// Windows-specific posture check information
windowsAntivirusEnabled: boolean("windowsAntivirusEnabled")
.notNull()
.default(false),
// macOS-specific posture check information
macosSipEnabled: boolean("macosSipEnabled").notNull().default(false),
macosGatekeeperEnabled: boolean("macosGatekeeperEnabled")
.notNull()
.default(false),
macosFirewallStealthMode: boolean("macosFirewallStealthMode")
.notNull()
.default(false),
// Linux-specific posture check information
linuxAppArmorEnabled: boolean("linuxAppArmorEnabled")
.notNull()
.default(false),
linuxSELinuxEnabled: boolean("linuxSELinuxEnabled").notNull().default(false)
});
export const fingerprintSnapshots = pgTable("fingerprintSnapshots", {
snapshotId: serial("id").primaryKey(),
fingerprintId: integer("fingerprintId").references(
() => currentFingerprint.fingerprintId,
{
onDelete: "set null"
}
),
username: text("username"),
hostname: text("hostname"),
platform: text("platform"),
osVersion: text("osVersion"),
kernelVersion: text("kernelVersion"),
arch: text("arch"),
deviceModel: text("deviceModel"),
serialNumber: text("serialNumber"),
platformFingerprint: varchar("platformFingerprint"),
// Platform-agnostic checks
biometricsEnabled: boolean("biometricsEnabled").notNull().default(false),
diskEncrypted: boolean("diskEncrypted").notNull().default(false),
firewallEnabled: boolean("firewallEnabled").notNull().default(false),
autoUpdatesEnabled: boolean("autoUpdatesEnabled").notNull().default(false),
tpmAvailable: boolean("tpmAvailable").notNull().default(false),
// Windows-specific posture check information
windowsAntivirusEnabled: boolean("windowsAntivirusEnabled")
.notNull()
.default(false),
// macOS-specific posture check information
macosSipEnabled: boolean("macosSipEnabled").notNull().default(false),
macosGatekeeperEnabled: boolean("macosGatekeeperEnabled")
.notNull()
.default(false),
macosFirewallStealthMode: boolean("macosFirewallStealthMode")
.notNull()
.default(false),
// Linux-specific posture check information
linuxAppArmorEnabled: boolean("linuxAppArmorEnabled")
.notNull()
.default(false),
linuxSELinuxEnabled: boolean("linuxSELinuxEnabled")
.notNull()
.default(false),
hash: text("hash").notNull(),
collectedAt: integer("collectedAt").notNull()
}); });
export const olmSessions = pgTable("clientSession", { export const olmSessions = pgTable("clientSession", {
+2 -10
View File
@@ -1,4 +1,4 @@
import { db, loginPage, LoginPage, loginPageOrg, Org, orgs, roles } from "@server/db"; import { db, loginPage, LoginPage, loginPageOrg, Org, orgs } from "@server/db";
import { import {
Resource, Resource,
ResourcePassword, ResourcePassword,
@@ -108,17 +108,9 @@ export async function getUserSessionWithUser(
*/ */
export async function getUserOrgRole(userId: string, orgId: string) { export async function getUserOrgRole(userId: string, orgId: string) {
const userOrgRole = await db const userOrgRole = await db
.select({ .select()
userId: userOrgs.userId,
orgId: userOrgs.orgId,
roleId: userOrgs.roleId,
isOwner: userOrgs.isOwner,
autoProvisioned: userOrgs.autoProvisioned,
roleName: roles.name
})
.from(userOrgs) .from(userOrgs)
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId))) .where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
.leftJoin(roles, eq(userOrgs.roleId, roles.roleId))
.limit(1); .limit(1);
return userOrgRole.length > 0 ? userOrgRole[0] : null; return userOrgRole.length > 0 ? userOrgRole[0] : null;
+2 -27
View File
@@ -6,7 +6,7 @@ import {
sqliteTable, sqliteTable,
text text
} from "drizzle-orm/sqlite-core"; } from "drizzle-orm/sqlite-core";
import { clients, domains, exitNodes, orgs, sessions, users } from "./schema"; import { domains, exitNodes, orgs, sessions, users } from "./schema";
export const certificates = sqliteTable("certificates", { export const certificates = sqliteTable("certificates", {
certId: integer("certId").primaryKey({ autoIncrement: true }), certId: integer("certId").primaryKey({ autoIncrement: true }),
@@ -206,7 +206,7 @@ export const loginPageBranding = sqliteTable("loginPageBranding", {
loginPageBrandingId: integer("loginPageBrandingId").primaryKey({ loginPageBrandingId: integer("loginPageBrandingId").primaryKey({
autoIncrement: true autoIncrement: true
}), }),
logoUrl: text("logoUrl"), logoUrl: text("logoUrl").notNull(),
logoWidth: integer("logoWidth").notNull(), logoWidth: integer("logoWidth").notNull(),
logoHeight: integer("logoHeight").notNull(), logoHeight: integer("logoHeight").notNull(),
primaryColor: text("primaryColor"), primaryColor: text("primaryColor"),
@@ -289,31 +289,6 @@ export const accessAuditLog = sqliteTable(
] ]
); );
export const approvals = sqliteTable("approvals", {
approvalId: integer("approvalId").primaryKey({ autoIncrement: true }),
timestamp: integer("timestamp").notNull(), // this is EPOCH time in seconds
orgId: text("orgId")
.references(() => orgs.orgId, {
onDelete: "cascade"
})
.notNull(),
clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade"
}), // olms reference user devices clients
userId: text("userId").references(() => users.userId, {
// optionally tied to a user and in this case delete when the user deletes
onDelete: "cascade"
}),
decision: text("decision")
.$type<"approved" | "denied" | "pending">()
.default("pending")
.notNull(),
type: text("type")
.$type<"user_device" /*| 'proxy' // for later */>()
.notNull()
});
export type Approval = InferSelectModel<typeof approvals>;
export type Limit = InferSelectModel<typeof limits>; export type Limit = InferSelectModel<typeof limits>;
export type Account = InferSelectModel<typeof account>; export type Account = InferSelectModel<typeof account>;
export type Certificate = InferSelectModel<typeof certificates>; export type Certificate = InferSelectModel<typeof certificates>;
+4 -168
View File
@@ -255,9 +255,7 @@ export const siteResources = sqliteTable("siteResources", {
aliasAddress: text("aliasAddress"), aliasAddress: text("aliasAddress"),
tcpPortRangeString: text("tcpPortRangeString").notNull().default("*"), tcpPortRangeString: text("tcpPortRangeString").notNull().default("*"),
udpPortRangeString: text("udpPortRangeString").notNull().default("*"), udpPortRangeString: text("udpPortRangeString").notNull().default("*"),
disableIcmp: integer("disableIcmp", { mode: "boolean" }) disableIcmp: integer("disableIcmp", { mode: "boolean" }).notNull().default(false)
.notNull()
.default(false)
}); });
export const clientSiteResources = sqliteTable("clientSiteResources", { export const clientSiteResources = sqliteTable("clientSiteResources", {
@@ -385,12 +383,7 @@ export const clients = sqliteTable("clients", {
type: text("type").notNull(), // "olm" type: text("type").notNull(), // "olm"
online: integer("online", { mode: "boolean" }).notNull().default(false), online: integer("online", { mode: "boolean" }).notNull().default(false),
// endpoint: text("endpoint"), // endpoint: text("endpoint"),
lastHolePunch: integer("lastHolePunch"), lastHolePunch: integer("lastHolePunch")
archived: integer("archived", { mode: "boolean" }).notNull().default(false),
blocked: integer("blocked", { mode: "boolean" }).notNull().default(false),
approvalState: text("approvalState").$type<
"pending" | "approved" | "denied"
>()
}); });
export const clientSitesAssociationsCache = sqliteTable( export const clientSitesAssociationsCache = sqliteTable(
@@ -430,160 +423,7 @@ export const olms = sqliteTable("olms", {
userId: text("userId").references(() => users.userId, { userId: text("userId").references(() => users.userId, {
// optionally tied to a user and in this case delete when the user deletes // optionally tied to a user and in this case delete when the user deletes
onDelete: "cascade" onDelete: "cascade"
}),
archived: integer("archived", { mode: "boolean" }).notNull().default(false)
});
export const currentFingerprint = sqliteTable("currentFingerprint", {
fingerprintId: integer("id").primaryKey({ autoIncrement: true }),
olmId: text("olmId")
.references(() => olms.olmId, { onDelete: "cascade" })
.notNull(),
firstSeen: integer("firstSeen").notNull(),
lastSeen: integer("lastSeen").notNull(),
lastCollectedAt: integer("lastCollectedAt").notNull(),
username: text("username"),
hostname: text("hostname"),
platform: text("platform"),
osVersion: text("osVersion"),
kernelVersion: text("kernelVersion"),
arch: text("arch"),
deviceModel: text("deviceModel"),
serialNumber: text("serialNumber"),
platformFingerprint: text("platformFingerprint"),
// Platform-agnostic checks
biometricsEnabled: integer("biometricsEnabled", { mode: "boolean" })
.notNull()
.default(false),
diskEncrypted: integer("diskEncrypted", { mode: "boolean" })
.notNull()
.default(false),
firewallEnabled: integer("firewallEnabled", { mode: "boolean" })
.notNull()
.default(false),
autoUpdatesEnabled: integer("autoUpdatesEnabled", { mode: "boolean" })
.notNull()
.default(false),
tpmAvailable: integer("tpmAvailable", { mode: "boolean" })
.notNull()
.default(false),
// Windows-specific posture check information
windowsAntivirusEnabled: integer("windowsAntivirusEnabled", {
mode: "boolean"
}) })
.notNull()
.default(false),
// macOS-specific posture check information
macosSipEnabled: integer("macosSipEnabled", { mode: "boolean" })
.notNull()
.default(false),
macosGatekeeperEnabled: integer("macosGatekeeperEnabled", {
mode: "boolean"
})
.notNull()
.default(false),
macosFirewallStealthMode: integer("macosFirewallStealthMode", {
mode: "boolean"
})
.notNull()
.default(false),
// Linux-specific posture check information
linuxAppArmorEnabled: integer("linuxAppArmorEnabled", { mode: "boolean" })
.notNull()
.default(false),
linuxSELinuxEnabled: integer("linuxSELinuxEnabled", {
mode: "boolean"
})
.notNull()
.default(false)
});
export const fingerprintSnapshots = sqliteTable("fingerprintSnapshots", {
snapshotId: integer("id").primaryKey({ autoIncrement: true }),
fingerprintId: integer("fingerprintId").references(
() => currentFingerprint.fingerprintId,
{
onDelete: "set null"
}
),
username: text("username"),
hostname: text("hostname"),
platform: text("platform"),
osVersion: text("osVersion"),
kernelVersion: text("kernelVersion"),
arch: text("arch"),
deviceModel: text("deviceModel"),
serialNumber: text("serialNumber"),
platformFingerprint: text("platformFingerprint"),
// Platform-agnostic checks
biometricsEnabled: integer("biometricsEnabled", { mode: "boolean" })
.notNull()
.default(false),
diskEncrypted: integer("diskEncrypted", { mode: "boolean" })
.notNull()
.default(false),
firewallEnabled: integer("firewallEnabled", { mode: "boolean" })
.notNull()
.default(false),
autoUpdatesEnabled: integer("autoUpdatesEnabled", { mode: "boolean" })
.notNull()
.default(false),
tpmAvailable: integer("tpmAvailable", { mode: "boolean" })
.notNull()
.default(false),
// Windows-specific posture check information
windowsAntivirusEnabled: integer("windowsAntivirusEnabled", {
mode: "boolean"
})
.notNull()
.default(false),
// macOS-specific posture check information
macosSipEnabled: integer("macosSipEnabled", { mode: "boolean" })
.notNull()
.default(false),
macosGatekeeperEnabled: integer("macosGatekeeperEnabled", {
mode: "boolean"
})
.notNull()
.default(false),
macosFirewallStealthMode: integer("macosFirewallStealthMode", {
mode: "boolean"
})
.notNull()
.default(false),
// Linux-specific posture check information
linuxAppArmorEnabled: integer("linuxAppArmorEnabled", { mode: "boolean" })
.notNull()
.default(false),
linuxSELinuxEnabled: integer("linuxSELinuxEnabled", {
mode: "boolean"
})
.notNull()
.default(false),
hash: text("hash").notNull(),
collectedAt: integer("collectedAt").notNull()
}); });
export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", { export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", {
@@ -675,10 +515,7 @@ export const roles = sqliteTable("roles", {
.notNull(), .notNull(),
isAdmin: integer("isAdmin", { mode: "boolean" }), isAdmin: integer("isAdmin", { mode: "boolean" }),
name: text("name").notNull(), name: text("name").notNull(),
description: text("description"), description: text("description")
requireDeviceApproval: integer("requireDeviceApproval", {
mode: "boolean"
}).default(false)
}); });
export const roleActions = sqliteTable("roleActions", { export const roleActions = sqliteTable("roleActions", {
@@ -937,8 +774,7 @@ export const idp = sqliteTable("idp", {
mode: "boolean" mode: "boolean"
}) })
.notNull() .notNull()
.default(false), .default(false)
tags: text("tags")
}); });
// Identity Provider OAuth Configuration // Identity Provider OAuth Configuration
+15 -10
View File
@@ -31,7 +31,7 @@ import { pickPort } from "@server/routers/target/helpers";
import { resourcePassword } from "@server/db"; import { resourcePassword } from "@server/db";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators"; import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed"; import { isLicensedOrSubscribed } from "../isLicencedOrSubscribed";
import { build } from "@server/build"; import { build } from "@server/build";
export type ProxyResourcesResults = { export type ProxyResourcesResults = {
@@ -213,7 +213,11 @@ export async function updateProxyResources(
// Update existing resource // Update existing resource
const isLicensed = await isLicensedOrSubscribed(orgId); const isLicensed = await isLicensedOrSubscribed(orgId);
if (!isLicensed) { if (build == "enterprise" && !isLicensed) {
logger.warn(
"Server is not licensed! Clearing set maintenance screen values"
);
// null the maintenance mode fields if not licensed
resourceData.maintenance = undefined; resourceData.maintenance = undefined;
} }
@@ -583,15 +587,13 @@ export async function updateProxyResources(
// Sync rules // Sync rules
for (const [index, rule] of resourceData.rules?.entries() || []) { for (const [index, rule] of resourceData.rules?.entries() || []) {
const intendedPriority = rule.priority ?? index + 1;
const existingRule = existingRules[index]; const existingRule = existingRules[index];
if (existingRule) { if (existingRule) {
if ( if (
existingRule.action !== getRuleAction(rule.action) || existingRule.action !== getRuleAction(rule.action) ||
existingRule.match !== rule.match.toUpperCase() || existingRule.match !== rule.match.toUpperCase() ||
existingRule.value !== existingRule.value !==
getRuleValue(rule.match.toUpperCase(), rule.value) || getRuleValue(rule.match.toUpperCase(), rule.value)
existingRule.priority !== intendedPriority
) { ) {
validateRule(rule); validateRule(rule);
await trx await trx
@@ -602,8 +604,7 @@ export async function updateProxyResources(
value: getRuleValue( value: getRuleValue(
rule.match.toUpperCase(), rule.match.toUpperCase(),
rule.value rule.value
), )
priority: intendedPriority
}) })
.where( .where(
eq(resourceRules.ruleId, existingRule.ruleId) eq(resourceRules.ruleId, existingRule.ruleId)
@@ -619,7 +620,7 @@ export async function updateProxyResources(
rule.match.toUpperCase(), rule.match.toUpperCase(),
rule.value rule.value
), ),
priority: intendedPriority priority: index + 1 // start priorities at 1
}); });
} }
} }
@@ -649,7 +650,11 @@ export async function updateProxyResources(
} }
const isLicensed = await isLicensedOrSubscribed(orgId); const isLicensed = await isLicensedOrSubscribed(orgId);
if (!isLicensed) { if (build == "enterprise" && !isLicensed) {
logger.warn(
"Server is not licensed! Clearing set maintenance screen values"
);
// null the maintenance mode fields if not licensed
resourceData.maintenance = undefined; resourceData.maintenance = undefined;
} }
@@ -804,7 +809,7 @@ export async function updateProxyResources(
action: getRuleAction(rule.action), action: getRuleAction(rule.action),
match: rule.match.toUpperCase(), match: rule.match.toUpperCase(),
value: getRuleValue(rule.match.toUpperCase(), rule.value), value: getRuleValue(rule.match.toUpperCase(), rule.value),
priority: rule.priority ?? index + 1 priority: index + 1 // start priorities at 1
}); });
} }
+3 -37
View File
@@ -78,8 +78,7 @@ export const RuleSchema = z
.object({ .object({
action: z.enum(["allow", "deny", "pass"]), action: z.enum(["allow", "deny", "pass"]),
match: z.enum(["cidr", "path", "ip", "country", "asn"]), match: z.enum(["cidr", "path", "ip", "country", "asn"]),
value: z.string(), value: z.string()
priority: z.int().optional()
}) })
.refine( .refine(
(rule) => { (rule) => {
@@ -269,39 +268,6 @@ export const ResourceSchema = z
path: ["auth"], path: ["auth"],
error: "When protocol is 'tcp' or 'udp', 'auth' must not be provided" error: "When protocol is 'tcp' or 'udp', 'auth' must not be provided"
} }
)
.refine(
(resource) => {
// Skip validation for targets-only resources
if (isTargetsOnlyResource(resource)) {
return true;
}
// Skip validation if no rules are defined
if (!resource.rules || resource.rules.length === 0) return true;
const finalPriorities: number[] = [];
let priorityCounter = 1;
// Gather priorities, assigning auto-priorities where needed
// following the logic from the backend implementation where
// empty priorities are auto-assigned a value of 1 + index of rule
for (const rule of resource.rules) {
if (rule.priority !== undefined) {
finalPriorities.push(rule.priority);
} else {
finalPriorities.push(priorityCounter);
}
priorityCounter++;
}
// Validate for duplicate priorities
return finalPriorities.length === new Set(finalPriorities).size;
},
{
path: ["rules"],
message:
"Rules have conflicting or invalid priorities (must be unique, including auto-assigned ones)"
}
); );
export function isTargetsOnlyResource(resource: any): boolean { export function isTargetsOnlyResource(resource: any): boolean {
@@ -324,8 +290,8 @@ export const ClientResourceSchema = z
alias: z alias: z
.string() .string()
.regex( .regex(
/^(?:[a-zA-Z0-9*?](?:[a-zA-Z0-9*?-]{0,61}[a-zA-Z0-9*?])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/, /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/,
"Alias must be a fully qualified domain name with optional wildcards (e.g., example.com, *.example.com, host-0?.example.internal)" "Alias must be a fully qualified domain name (e.g., example.com)"
) )
.optional(), .optional(),
roles: z roles: z
+18 -50
View File
@@ -1,25 +1,21 @@
import { listExitNodes } from "#dynamic/lib/exitNodes";
import { build } from "@server/build";
import { import {
approvals,
clients, clients,
db, db,
olms, olms,
orgs, orgs,
roleClients, roleClients,
roles, roles,
Transaction,
userClients, userClients,
userOrgs userOrgs,
Transaction
} from "@server/db"; } from "@server/db";
import { getUniqueClientName } from "@server/db/names"; import { eq, and, notInArray } from "drizzle-orm";
import { listExitNodes } from "#dynamic/lib/exitNodes";
import { getNextAvailableClientSubnet } from "@server/lib/ip"; import { getNextAvailableClientSubnet } from "@server/lib/ip";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
import logger from "@server/logger"; import logger from "@server/logger";
import { sendTerminateClient } from "@server/routers/client/terminate";
import { and, eq, notInArray, type InferInsertModel } from "drizzle-orm";
import { rebuildClientAssociationsFromClient } from "./rebuildClientAssociations"; import { rebuildClientAssociationsFromClient } from "./rebuildClientAssociations";
import { OlmErrorCodes } from "@server/routers/olm/error"; import { sendTerminateClient } from "@server/routers/client/terminate";
import { getUniqueClientName } from "@server/db/names";
export async function calculateUserClientsForOrgs( export async function calculateUserClientsForOrgs(
userId: string, userId: string,
@@ -42,15 +38,13 @@ export async function calculateUserClientsForOrgs(
const allUserOrgs = await transaction const allUserOrgs = await transaction
.select() .select()
.from(userOrgs) .from(userOrgs)
.innerJoin(roles, eq(roles.roleId, userOrgs.roleId))
.where(eq(userOrgs.userId, userId)); .where(eq(userOrgs.userId, userId));
const userOrgIds = allUserOrgs.map(({ userOrgs: uo }) => uo.orgId); const userOrgIds = allUserOrgs.map((uo) => uo.orgId);
// For each OLM, ensure there's a client in each org the user is in // For each OLM, ensure there's a client in each org the user is in
for (const olm of userOlms) { for (const olm of userOlms) {
for (const userRoleOrg of allUserOrgs) { for (const userOrg of allUserOrgs) {
const { userOrgs: userOrg, roles: role } = userRoleOrg;
const orgId = userOrg.orgId; const orgId = userOrg.orgId;
const [org] = await transaction const [org] = await transaction
@@ -188,46 +182,21 @@ export async function calculateUserClientsForOrgs(
const niceId = await getUniqueClientName(orgId); const niceId = await getUniqueClientName(orgId);
const isOrgLicensed = await isLicensedOrSubscribed(
userOrg.orgId
);
const requireApproval =
build !== "oss" &&
isOrgLicensed &&
role.requireDeviceApproval;
const newClientData: InferInsertModel<typeof clients> = {
userId,
orgId: userOrg.orgId,
exitNodeId: randomExitNode.exitNodeId,
name: olm.name || "User Client",
subnet: updatedSubnet,
olmId: olm.olmId,
type: "olm",
niceId,
approvalState: requireApproval ? "pending" : null
};
// Create the client // Create the client
const [newClient] = await transaction const [newClient] = await transaction
.insert(clients) .insert(clients)
.values(newClientData) .values({
userId,
orgId: userOrg.orgId,
exitNodeId: randomExitNode.exitNodeId,
name: olm.name || "User Client",
subnet: updatedSubnet,
olmId: olm.olmId,
type: "olm",
niceId
})
.returning(); .returning();
// create approval request
if (requireApproval) {
await transaction
.insert(approvals)
.values({
timestamp: Math.floor(new Date().getTime() / 1000),
orgId: userOrg.orgId,
clientId: newClient.clientId,
userId,
type: "user_device"
})
.returning();
}
await rebuildClientAssociationsFromClient( await rebuildClientAssociationsFromClient(
newClient, newClient,
transaction transaction
@@ -306,7 +275,6 @@ async function cleanupOrphanedClients(
if (deletedClient.olmId) { if (deletedClient.olmId) {
await sendTerminateClient( await sendTerminateClient(
deletedClient.clientId, deletedClient.clientId,
OlmErrorCodes.TERMINATED_DELETED,
deletedClient.olmId deletedClient.olmId
); );
} }
-4
View File
@@ -3,7 +3,6 @@ import { cleanUpOldLogs as cleanUpOldAccessLogs } from "#dynamic/lib/logAccessAu
import { cleanUpOldLogs as cleanUpOldActionLogs } from "#dynamic/middlewares/logActionAudit"; import { cleanUpOldLogs as cleanUpOldActionLogs } from "#dynamic/middlewares/logActionAudit";
import { cleanUpOldLogs as cleanUpOldRequestLogs } from "@server/routers/badger/logRequestAudit"; import { cleanUpOldLogs as cleanUpOldRequestLogs } from "@server/routers/badger/logRequestAudit";
import { gt, or } from "drizzle-orm"; import { gt, or } from "drizzle-orm";
import { cleanUpOldFingerprintSnapshots } from "@server/routers/olm/fingerprintingUtils";
export function initLogCleanupInterval() { export function initLogCleanupInterval() {
return setInterval( return setInterval(
@@ -27,7 +26,6 @@ export function initLogCleanupInterval() {
) )
); );
// TODO: handle when there are multiple nodes doing this clearing using redis
for (const org of orgsToClean) { for (const org of orgsToClean) {
const { const {
orgId, orgId,
@@ -57,8 +55,6 @@ export function initLogCleanupInterval() {
); );
} }
} }
await cleanUpOldFingerprintSnapshots(365);
}, },
3 * 60 * 60 * 1000 3 * 60 * 60 * 1000
); // every 3 hours ); // every 3 hours
+1 -1
View File
@@ -2,7 +2,7 @@ import path from "path";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
// This is a placeholder value replaced by the build process // This is a placeholder value replaced by the build process
export const APP_VERSION = "1.15.0"; export const APP_VERSION = "1.14.0";
export const __FILENAME = fileURLToPath(import.meta.url); export const __FILENAME = fileURLToPath(import.meta.url);
export const __DIRNAME = path.dirname(__FILENAME); export const __DIRNAME = path.dirname(__FILENAME);
+16 -2
View File
@@ -1,3 +1,17 @@
import { build } from "@server/build";
import license from "#dynamic/license/license";
import { getOrgTierData } from "#dynamic/lib/billing";
import { TierId } from "@server/lib/billing/tiers";
export async function isLicensedOrSubscribed(orgId: string): Promise<boolean> { export async function isLicensedOrSubscribed(orgId: string): Promise<boolean> {
return false; if (build === "enterprise") {
} return await license.isUnlocked();
}
if (build === "saas") {
const { tier } = await getOrgTierData(orgId);
return tier === TierId.STANDARD;
}
return true;
}
-1
View File
@@ -13,4 +13,3 @@ export * from "./verifyApiKeyIsRoot";
export * from "./verifyApiKeyApiKeyAccess"; export * from "./verifyApiKeyApiKeyAccess";
export * from "./verifyApiKeyClientAccess"; export * from "./verifyApiKeyClientAccess";
export * from "./verifyApiKeySiteResourceAccess"; export * from "./verifyApiKeySiteResourceAccess";
export * from "./verifyApiKeyIdpAccess";
@@ -1,88 +0,0 @@
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { idp, idpOrg, apiKeyOrg } from "@server/db";
import { and, eq } from "drizzle-orm";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
export async function verifyApiKeyIdpAccess(
req: Request,
res: Response,
next: NextFunction
) {
try {
const apiKey = req.apiKey;
const idpId = req.params.idpId || req.body.idpId || req.query.idpId;
const orgId = req.params.orgId;
if (!apiKey) {
return next(
createHttpError(HttpCode.UNAUTHORIZED, "Key not authenticated")
);
}
if (!orgId) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Invalid organization ID")
);
}
if (!idpId) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Invalid IDP ID")
);
}
if (apiKey.isRoot) {
// Root keys can access any IDP in any org
return next();
}
const [idpRes] = await db
.select()
.from(idp)
.innerJoin(idpOrg, eq(idp.idpId, idpOrg.idpId))
.where(and(eq(idp.idpId, idpId), eq(idpOrg.orgId, orgId)))
.limit(1);
if (!idpRes || !idpRes.idp || !idpRes.idpOrg) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`IdP with ID ${idpId} not found for organization ${orgId}`
)
);
}
if (!req.apiKeyOrg) {
const apiKeyOrgRes = await db
.select()
.from(apiKeyOrg)
.where(
and(
eq(apiKeyOrg.apiKeyId, apiKey.apiKeyId),
eq(apiKeyOrg.orgId, idpRes.idpOrg.orgId)
)
);
req.apiKeyOrg = apiKeyOrgRes[0];
}
if (!req.apiKeyOrg) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Key does not have access to this organization"
)
);
}
return next();
} catch (error) {
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Error verifying IDP access"
)
);
}
}
-4
View File
@@ -139,10 +139,6 @@ export class PrivateConfig {
process.env.USE_PANGOLIN_DNS = process.env.USE_PANGOLIN_DNS =
this.rawPrivateConfig.flags.use_pangolin_dns.toString(); this.rawPrivateConfig.flags.use_pangolin_dns.toString();
} }
if (this.rawPrivateConfig.flags.use_org_only_idp) {
process.env.USE_ORG_ONLY_IDP =
this.rawPrivateConfig.flags.use_org_only_idp.toString();
}
} }
public getRawPrivateConfig() { public getRawPrivateConfig() {
@@ -50,14 +50,10 @@ export async function sendToExitNode(
); );
} }
return sendToClient( return sendToClient(remoteExitNode.remoteExitNodeId, {
remoteExitNode.remoteExitNodeId, type: request.remoteType,
{ data: request.data
type: request.remoteType, });
data: request.data
},
{ incrementConfigVersion: true }
);
} else { } else {
let hostname = exitNode.reachableAt; let hostname = exitNode.reachableAt;
+1 -1
View File
@@ -288,7 +288,7 @@ export function selectBestExitNode(
const validNodes = pingResults.filter((n) => !n.error && n.weight > 0); const validNodes = pingResults.filter((n) => !n.error && n.weight > 0);
if (validNodes.length === 0) { if (validNodes.length === 0) {
logger.debug("No valid exit nodes available"); logger.error("No valid exit nodes available");
return null; return null;
} }
@@ -1,30 +0,0 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
import { build } from "@server/build";
import license from "#private/license/license";
import { getOrgTierData } from "#private/lib/billing";
import { TierId } from "@server/lib/billing/tiers";
export async function isLicensedOrSubscribed(orgId: string): Promise<boolean> {
if (build === "enterprise") {
return await license.isUnlocked();
}
if (build === "saas") {
const { tier } = await getOrgTierData(orgId);
return tier === TierId.STANDARD;
}
return false;
}
+41 -61
View File
@@ -24,9 +24,7 @@ export class LockManager {
*/ */
async acquireLock( async acquireLock(
lockKey: string, lockKey: string,
ttlMs: number = 30000, ttlMs: number = 30000
maxRetries: number = 3,
retryDelayMs: number = 100
): Promise<boolean> { ): Promise<boolean> {
if (!redis || !redis.status || redis.status !== "ready") { if (!redis || !redis.status || redis.status !== "ready") {
return true; return true;
@@ -37,67 +35,49 @@ export class LockManager {
}:${Date.now()}`; }:${Date.now()}`;
const redisKey = `lock:${lockKey}`; const redisKey = `lock:${lockKey}`;
for (let attempt = 0; attempt < maxRetries; attempt++) { try {
try { // Use SET with NX (only set if not exists) and PX (expire in milliseconds)
// Use SET with NX (only set if not exists) and PX (expire in milliseconds) // This is atomic and handles both setting and expiration
// This is atomic and handles both setting and expiration const result = await redis.set(
const result = await redis.set( redisKey,
redisKey, lockValue,
lockValue, "PX",
"PX", ttlMs,
ttlMs, "NX"
"NX" );
if (result === "OK") {
logger.debug(
`Lock acquired: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
}`
); );
return true;
if (result === "OK") {
logger.debug(
`Lock acquired: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
}`
);
return true;
}
// Check if the existing lock is from this worker (reentrant behavior)
const existingValue = await redis.get(redisKey);
if (
existingValue &&
existingValue.startsWith(
`${config.getRawConfig().gerbil.exit_node_name}:`
)
) {
// Extend the lock TTL since it's the same worker
await redis.pexpire(redisKey, ttlMs);
logger.debug(
`Lock extended: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
}`
);
return true;
}
// If this isn't our last attempt, wait before retrying with exponential backoff
if (attempt < maxRetries - 1) {
const delay = retryDelayMs * Math.pow(2, attempt);
logger.debug(
`Lock ${lockKey} not available, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`
);
await new Promise((resolve) => setTimeout(resolve, delay));
}
} catch (error) {
logger.error(`Failed to acquire lock ${lockKey} (attempt ${attempt + 1}/${maxRetries}):`, error);
// On error, still retry if we have attempts left
if (attempt < maxRetries - 1) {
const delay = retryDelayMs * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
}
} }
}
logger.debug( // Check if the existing lock is from this worker (reentrant behavior)
`Failed to acquire lock ${lockKey} after ${maxRetries} attempts` const existingValue = await redis.get(redisKey);
); if (
return false; existingValue &&
existingValue.startsWith(
`${config.getRawConfig().gerbil.exit_node_name}:`
)
) {
// Extend the lock TTL since it's the same worker
await redis.pexpire(redisKey, ttlMs);
logger.debug(
`Lock extended: ${lockKey} by ${
config.getRawConfig().gerbil.exit_node_name
}`
);
return true;
}
return false;
} catch (error) {
logger.error(`Failed to acquire lock ${lockKey}:`, error);
return false;
}
} }
/** /**
+1 -2
View File
@@ -83,8 +83,7 @@ export const privateConfigSchema = z.object({
flags: z flags: z
.object({ .object({
enable_redis: z.boolean().optional().default(false), enable_redis: z.boolean().optional().default(false),
use_pangolin_dns: z.boolean().optional().default(false), use_pangolin_dns: z.boolean().optional().default(false)
use_org_only_idp: z.boolean().optional().default(false)
}) })
.optional() .optional()
.prefault({}), .prefault({}),
-14
View File
@@ -573,20 +573,6 @@ class RedisManager {
} }
} }
public async incr(key: string): Promise<number> {
if (!this.isRedisEnabled() || !this.writeClient) return 0;
try {
return await this.executeWithRetry(
() => this.writeClient!.incr(key),
"Redis INCR"
);
} catch (error) {
logger.error("Redis INCR error:", error);
return 0;
}
}
public async sadd(key: string, member: string): Promise<boolean> { public async sadd(key: string, member: string): Promise<boolean> {
if (!this.isRedisEnabled() || !this.writeClient) return false; if (!this.isRedisEnabled() || !this.writeClient) return false;
@@ -456,11 +456,11 @@ export async function getTraefikConfig(
// ); // );
} else if (resource.maintenanceModeType === "automatic") { } else if (resource.maintenanceModeType === "automatic") {
showMaintenancePage = !hasHealthyServers; showMaintenancePage = !hasHealthyServers;
// if (showMaintenancePage) { if (showMaintenancePage) {
// logger.warn( logger.warn(
// `Resource ${resource.name} (${fullDomain}) has no healthy servers - showing maintenance page (AUTOMATIC mode)` `Resource ${resource.name} (${fullDomain}) has no healthy servers - showing maintenance page (AUTOMATIC mode)`
// ); );
// } }
} }
} }
@@ -27,18 +27,7 @@ export async function verifyValidSubscription(
return next(); return next();
} }
const orgId = req.params.orgId || req.body.orgId || req.query.orgId || req.userOrgId; const tier = await getOrgTierData(req.params.orgId);
if (!orgId) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"Organization ID is required to verify subscription"
)
);
}
const tier = await getOrgTierData(orgId);
if (!tier.active) { if (!tier.active) {
return next( return next(
@@ -1,110 +0,0 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { z } from "zod";
import { fromError } from "zod-validation-error";
import type { Request, Response, NextFunction } from "express";
import { approvals, db, type Approval } from "@server/db";
import { eq, sql, and } from "drizzle-orm";
import response from "@server/lib/response";
const paramsSchema = z.strictObject({
orgId: z.string()
});
const querySchema = z.strictObject({
approvalState: z
.enum(["pending", "approved", "denied", "all"])
.optional()
.default("all")
.catch("all")
});
export type CountApprovalsResponse = {
count: number;
};
export async function countApprovals(
req: Request,
res: Response,
next: NextFunction
) {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const parsedQuery = querySchema.safeParse(req.query);
if (!parsedQuery.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedQuery.error).toString()
)
);
}
const { approvalState } = parsedQuery.data;
const { orgId } = parsedParams.data;
let state: Array<Approval["decision"]> = [];
switch (approvalState) {
case "pending":
state = ["pending"];
break;
case "approved":
state = ["approved"];
break;
case "denied":
state = ["denied"];
break;
default:
state = ["approved", "denied", "pending"];
}
const [{ count }] = await db
.select({ count: sql<number>`count(*)` })
.from(approvals)
.where(
and(
eq(approvals.orgId, orgId),
sql`${approvals.decision} in ${state}`
)
);
return response<CountApprovalsResponse>(res, {
data: {
count
},
success: true,
error: false,
message: "Approval count retrieved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
-16
View File
@@ -1,16 +0,0 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
export * from "./listApprovals";
export * from "./processPendingApproval";
export * from "./countApprovals";
@@ -1,269 +0,0 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { z } from "zod";
import { fromError } from "zod-validation-error";
import type { Request, Response, NextFunction } from "express";
import { build } from "@server/build";
import { getOrgTierData } from "#private/lib/billing";
import { TierId } from "@server/lib/billing/tiers";
import {
approvals,
clients,
db,
users,
olms,
currentFingerprint,
type Approval
} from "@server/db";
import { eq, isNull, sql, not, and, desc } from "drizzle-orm";
import response from "@server/lib/response";
import { getUserDeviceName } from "@server/db/names";
const paramsSchema = z.strictObject({
orgId: z.string()
});
const querySchema = z.strictObject({
limit: z
.string()
.optional()
.default("1000")
.transform(Number)
.pipe(z.int().nonnegative()),
offset: z
.string()
.optional()
.default("0")
.transform(Number)
.pipe(z.int().nonnegative()),
approvalState: z
.enum(["pending", "approved", "denied", "all"])
.optional()
.default("all")
.catch("all"),
clientId: z
.string()
.optional()
.transform((val) => (val ? Number(val) : undefined))
.pipe(z.number().int().positive().optional())
});
async function queryApprovals(
orgId: string,
limit: number,
offset: number,
approvalState: z.infer<typeof querySchema>["approvalState"],
clientId?: number
) {
let state: Array<Approval["decision"]> = [];
switch (approvalState) {
case "pending":
state = ["pending"];
break;
case "approved":
state = ["approved"];
break;
case "denied":
state = ["denied"];
break;
default:
state = ["approved", "denied", "pending"];
}
const res = await db
.select({
approvalId: approvals.approvalId,
orgId: approvals.orgId,
clientId: approvals.clientId,
decision: approvals.decision,
type: approvals.type,
user: {
name: users.name,
userId: users.userId,
username: users.username,
email: users.email
},
clientName: clients.name,
niceId: clients.niceId,
deviceModel: currentFingerprint.deviceModel,
fingerprintPlatform: currentFingerprint.platform,
fingerprintOsVersion: currentFingerprint.osVersion,
fingerprintKernelVersion: currentFingerprint.kernelVersion,
fingerprintArch: currentFingerprint.arch,
fingerprintSerialNumber: currentFingerprint.serialNumber,
fingerprintUsername: currentFingerprint.username,
fingerprintHostname: currentFingerprint.hostname
})
.from(approvals)
.innerJoin(users, and(eq(approvals.userId, users.userId)))
.leftJoin(
clients,
and(
eq(approvals.clientId, clients.clientId),
not(isNull(clients.userId)) // only user devices
)
)
.leftJoin(olms, eq(clients.clientId, olms.clientId))
.leftJoin(currentFingerprint, eq(olms.olmId, currentFingerprint.olmId))
.where(
and(
eq(approvals.orgId, orgId),
sql`${approvals.decision} in ${state}`,
...(clientId ? [eq(approvals.clientId, clientId)] : [])
)
)
.orderBy(
sql`CASE ${approvals.decision} WHEN 'pending' THEN 0 ELSE 1 END`,
desc(approvals.timestamp)
)
.limit(limit)
.offset(offset);
// Process results to format device names and build fingerprint objects
return res.map((approval) => {
const model = approval.deviceModel || null;
const deviceName = approval.clientName
? getUserDeviceName(model, approval.clientName)
: null;
// Build fingerprint object if any fingerprint data exists
const hasFingerprintData =
approval.fingerprintPlatform ||
approval.fingerprintOsVersion ||
approval.fingerprintKernelVersion ||
approval.fingerprintArch ||
approval.fingerprintSerialNumber ||
approval.fingerprintUsername ||
approval.fingerprintHostname ||
approval.deviceModel;
const fingerprint = hasFingerprintData
? {
platform: approval.fingerprintPlatform || null,
osVersion: approval.fingerprintOsVersion || null,
kernelVersion: approval.fingerprintKernelVersion || null,
arch: approval.fingerprintArch || null,
deviceModel: approval.deviceModel || null,
serialNumber: approval.fingerprintSerialNumber || null,
username: approval.fingerprintUsername || null,
hostname: approval.fingerprintHostname || null
}
: null;
const {
clientName,
deviceModel,
fingerprintPlatform,
fingerprintOsVersion,
fingerprintKernelVersion,
fingerprintArch,
fingerprintSerialNumber,
fingerprintUsername,
fingerprintHostname,
...rest
} = approval;
return {
...rest,
deviceName,
fingerprint,
niceId: approval.niceId || null
};
});
}
export type ListApprovalsResponse = {
approvals: NonNullable<Awaited<ReturnType<typeof queryApprovals>>>;
pagination: { total: number; limit: number; offset: number };
};
export async function listApprovals(
req: Request,
res: Response,
next: NextFunction
) {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const parsedQuery = querySchema.safeParse(req.query);
if (!parsedQuery.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedQuery.error).toString()
)
);
}
const { limit, offset, approvalState, clientId } = parsedQuery.data;
const { orgId } = parsedParams.data;
if (build === "saas") {
const { tier } = await getOrgTierData(orgId);
const subscribed = tier === TierId.STANDARD;
if (!subscribed) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"This organization's current plan does not support this feature."
)
);
}
}
const approvalsList = await queryApprovals(
orgId.toString(),
limit,
offset,
approvalState,
clientId
);
const [{ count }] = await db
.select({ count: sql<number>`count(*)` })
.from(approvals);
return response<ListApprovalsResponse>(res, {
data: {
approvals: approvalsList,
pagination: {
total: count,
limit,
offset
}
},
success: true,
error: false,
message: "Approvals retrieved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
@@ -1,142 +0,0 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import { z } from "zod";
import { fromError } from "zod-validation-error";
import { build } from "@server/build";
import { approvals, clients, db, orgs, type Approval } from "@server/db";
import { getOrgTierData } from "#private/lib/billing";
import { TierId } from "@server/lib/billing/tiers";
import response from "@server/lib/response";
import { and, eq, type InferInsertModel } from "drizzle-orm";
import type { NextFunction, Request, Response } from "express";
const paramsSchema = z.strictObject({
orgId: z.string(),
approvalId: z.string().transform(Number).pipe(z.int().positive())
});
const bodySchema = z.strictObject({
decision: z.enum(["approved", "denied"])
});
export type ProcessApprovalResponse = Approval;
export async function processPendingApproval(
req: Request,
res: Response,
next: NextFunction
) {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const parsedBody = bodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const { orgId, approvalId } = parsedParams.data;
if (build === "saas") {
const { tier } = await getOrgTierData(orgId);
const subscribed = tier === TierId.STANDARD;
if (!subscribed) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"This organization's current plan does not support this feature."
)
);
}
}
const updateData = parsedBody.data;
const approval = await db
.select()
.from(approvals)
.where(
and(
eq(approvals.approvalId, approvalId),
eq(approvals.decision, "pending")
)
)
.innerJoin(orgs, eq(approvals.orgId, approvals.orgId))
.limit(1);
if (approval.length === 0) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Pending Approval with ID ${approvalId} not found`
)
);
}
const [updatedApproval] = await db
.update(approvals)
.set(updateData)
.where(eq(approvals.approvalId, approvalId))
.returning();
// Update user device approval state too
if (
updatedApproval.type === "user_device" &&
updatedApproval.clientId
) {
const updateDataBody: Partial<InferInsertModel<typeof clients>> = {
approvalState: updateData.decision
};
if (updateData.decision === "denied") {
updateDataBody.blocked = true;
}
await db
.update(clients)
.set(updateDataBody)
.where(eq(clients.clientId, updatedApproval.clientId));
}
return response(res, {
data: updatedApproval,
success: true,
error: false,
message: "Approval updated successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
+2 -28
View File
@@ -24,7 +24,6 @@ import * as generateLicense from "./generatedLicense";
import * as logs from "#private/routers/auditLogs"; import * as logs from "#private/routers/auditLogs";
import * as misc from "#private/routers/misc"; import * as misc from "#private/routers/misc";
import * as reKey from "#private/routers/re-key"; import * as reKey from "#private/routers/re-key";
import * as approval from "#private/routers/approvals";
import { import {
verifyOrgAccess, verifyOrgAccess,
@@ -312,31 +311,6 @@ authenticated.get(
loginPage.getLoginPage loginPage.getLoginPage
); );
authenticated.get(
"/org/:orgId/approvals",
verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listApprovals),
logActionAudit(ActionsEnum.listApprovals),
approval.listApprovals
);
authenticated.get(
"/org/:orgId/approvals/count",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listApprovals),
approval.countApprovals
);
authenticated.put(
"/org/:orgId/approvals/:approvalId",
verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.updateApprovals),
logActionAudit(ActionsEnum.updateApprovals),
approval.processPendingApproval
);
authenticated.get( authenticated.get(
"/org/:orgId/login-page-branding", "/org/:orgId/login-page-branding",
verifyValidLicense, verifyValidLicense,
@@ -462,18 +436,18 @@ authenticated.get(
authenticated.post( authenticated.post(
"/re-key/:clientId/regenerate-client-secret", "/re-key/:clientId/regenerate-client-secret",
verifyClientAccess, // this is first to set the org id
verifyValidLicense, verifyValidLicense,
verifyValidSubscription, verifyValidSubscription,
verifyClientAccess,
verifyUserHasAction(ActionsEnum.reGenerateSecret), verifyUserHasAction(ActionsEnum.reGenerateSecret),
reKey.reGenerateClientSecret reKey.reGenerateClientSecret
); );
authenticated.post( authenticated.post(
"/re-key/:siteId/regenerate-site-secret", "/re-key/:siteId/regenerate-site-secret",
verifySiteAccess, // this is first to set the org id
verifyValidLicense, verifyValidLicense,
verifyValidSubscription, verifyValidSubscription,
verifySiteAccess,
verifyUserHasAction(ActionsEnum.reGenerateSecret), verifyUserHasAction(ActionsEnum.reGenerateSecret),
reKey.reGenerateSiteSecret reKey.reGenerateSiteSecret
); );
+1 -50
View File
@@ -18,8 +18,7 @@ import * as logs from "#private/routers/auditLogs";
import { import {
verifyApiKeyHasAction, verifyApiKeyHasAction,
verifyApiKeyIsRoot, verifyApiKeyIsRoot,
verifyApiKeyOrgAccess, verifyApiKeyOrgAccess
verifyApiKeyIdpAccess
} from "@server/middlewares"; } from "@server/middlewares";
import { import {
verifyValidSubscription, verifyValidSubscription,
@@ -32,8 +31,6 @@ import {
authenticated as a authenticated as a
} from "@server/routers/integration"; } from "@server/routers/integration";
import { logActionAudit } from "#private/middlewares"; import { logActionAudit } from "#private/middlewares";
import config from "#private/lib/config";
import { build } from "@server/build";
export const unauthenticated = ua; export const unauthenticated = ua;
export const authenticated = a; export const authenticated = a;
@@ -91,49 +88,3 @@ authenticated.get(
logActionAudit(ActionsEnum.exportLogs), logActionAudit(ActionsEnum.exportLogs),
logs.exportAccessAuditLogs logs.exportAccessAuditLogs
); );
authenticated.put(
"/org/:orgId/idp/oidc",
verifyValidLicense,
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createIdp),
logActionAudit(ActionsEnum.createIdp),
orgIdp.createOrgOidcIdp
);
authenticated.post(
"/org/:orgId/idp/:idpId/oidc",
verifyValidLicense,
verifyApiKeyOrgAccess,
verifyApiKeyIdpAccess,
verifyApiKeyHasAction(ActionsEnum.updateIdp),
logActionAudit(ActionsEnum.updateIdp),
orgIdp.updateOrgOidcIdp
);
authenticated.delete(
"/org/:orgId/idp/:idpId",
verifyValidLicense,
verifyApiKeyOrgAccess,
verifyApiKeyIdpAccess,
verifyApiKeyHasAction(ActionsEnum.deleteIdp),
logActionAudit(ActionsEnum.deleteIdp),
orgIdp.deleteOrgIdp
);
authenticated.get(
"/org/:orgId/idp/:idpId",
verifyValidLicense,
verifyApiKeyOrgAccess,
verifyApiKeyIdpAccess,
verifyApiKeyHasAction(ActionsEnum.getIdp),
orgIdp.getOrgIdp
);
authenticated.get(
"/org/:orgId/idp",
verifyValidLicense,
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.listIdps),
orgIdp.listOrgIdps
);
@@ -29,9 +29,11 @@ import { getOrgTierData } from "#private/lib/billing";
import { TierId } from "@server/lib/billing/tiers"; import { TierId } from "@server/lib/billing/tiers";
import { build } from "@server/build"; import { build } from "@server/build";
const paramsSchema = z.strictObject({ const paramsSchema = z
orgId: z.string() .object({
}); orgId: z.string()
})
.strict();
export async function getLoginPageBranding( export async function getLoginPageBranding(
req: Request, req: Request,
@@ -28,36 +28,13 @@ import { eq, InferInsertModel } from "drizzle-orm";
import { getOrgTierData } from "#private/lib/billing"; import { getOrgTierData } from "#private/lib/billing";
import { TierId } from "@server/lib/billing/tiers"; import { TierId } from "@server/lib/billing/tiers";
import { build } from "@server/build"; import { build } from "@server/build";
import config from "@server/private/lib/config";
const paramsSchema = z.strictObject({ const paramsSchema = z.strictObject({
orgId: z.string() orgId: z.string()
}); });
const bodySchema = z.strictObject({ const bodySchema = z.strictObject({
logoUrl: z logoUrl: z.url(),
.union([
z.string().length(0),
z.url().refine(
async (url) => {
try {
const response = await fetch(url);
return (
response.status === 200 &&
(
response.headers.get("content-type") ?? ""
).startsWith("image/")
);
} catch (error) {
return false;
}
},
{
error: "Invalid logo URL, must be a valid image URL"
}
)
])
.optional(),
logoWidth: z.coerce.number<number>().min(1), logoWidth: z.coerce.number<number>().min(1),
logoHeight: z.coerce.number<number>().min(1), logoHeight: z.coerce.number<number>().min(1),
resourceTitle: z.string(), resourceTitle: z.string(),
@@ -117,14 +94,8 @@ export async function upsertLoginPageBranding(
typeof loginPageBranding typeof loginPageBranding
>; >;
if ((updateData.logoUrl ?? "").trim().length === 0) { if (build !== "saas") {
updateData.logoUrl = undefined; // org branding settings are only considered in the saas build
}
if (
build !== "saas" &&
!config.getRawPrivateConfig().flags.use_org_only_idp
) {
const { orgTitle, orgSubtitle, ...rest } = updateData; const { orgTitle, orgSubtitle, ...rest } = updateData;
updateData = rest; updateData = rest;
} }
@@ -43,27 +43,25 @@ const bodySchema = z.strictObject({
scopes: z.string().nonempty(), scopes: z.string().nonempty(),
autoProvision: z.boolean().optional(), autoProvision: z.boolean().optional(),
variant: z.enum(["oidc", "google", "azure"]).optional().default("oidc"), variant: z.enum(["oidc", "google", "azure"]).optional().default("oidc"),
roleMapping: z.string().optional(), roleMapping: z.string().optional()
tags: z.string().optional()
}); });
registry.registerPath({ // registry.registerPath({
method: "put", // method: "put",
path: "/org/{orgId}/idp/oidc", // path: "/idp/oidc",
description: "Create an OIDC IdP for a specific organization.", // description: "Create an OIDC IdP.",
tags: [OpenAPITags.Idp, OpenAPITags.Org], // tags: [OpenAPITags.Idp],
request: { // request: {
params: paramsSchema, // body: {
body: { // content: {
content: { // "application/json": {
"application/json": { // schema: bodySchema
schema: bodySchema // }
} // }
} // }
} // },
}, // responses: {}
responses: {} // });
});
export async function createOrgOidcIdp( export async function createOrgOidcIdp(
req: Request, req: Request,
@@ -105,8 +103,7 @@ export async function createOrgOidcIdp(
name, name,
autoProvision, autoProvision,
variant, variant,
roleMapping, roleMapping
tags
} = parsedBody.data; } = parsedBody.data;
if (build === "saas") { if (build === "saas") {
@@ -134,8 +131,7 @@ export async function createOrgOidcIdp(
.values({ .values({
name, name,
autoProvision, autoProvision,
type: "oidc", type: "oidc"
tags
}) })
.returning(); .returning();
@@ -32,9 +32,9 @@ const paramsSchema = z
registry.registerPath({ registry.registerPath({
method: "delete", method: "delete",
path: "/org/{orgId}/idp/{idpId}", path: "/idp/{idpId}",
description: "Delete IDP for a specific organization.", description: "Delete IDP.",
tags: [OpenAPITags.Idp, OpenAPITags.Org], tags: [OpenAPITags.Idp],
request: { request: {
params: paramsSchema params: paramsSchema
}, },
+10 -10
View File
@@ -48,16 +48,16 @@ async function query(idpId: number, orgId: string) {
return res; return res;
} }
registry.registerPath({ // registry.registerPath({
method: "get", // method: "get",
path: "/org/:orgId/idp/:idpId", // path: "/idp/{idpId}",
description: "Get an IDP by its IDP ID for a specific organization.", // description: "Get an IDP by its IDP ID.",
tags: [OpenAPITags.Idp, OpenAPITags.Org], // tags: [OpenAPITags.Idp],
request: { // request: {
params: paramsSchema // params: paramsSchema
}, // },
responses: {} // responses: {}
}); // });
export async function getOrgIdp( export async function getOrgIdp(
req: Request, req: Request,
+11 -13
View File
@@ -50,8 +50,7 @@ async function query(orgId: string, limit: number, offset: number) {
orgId: idpOrg.orgId, orgId: idpOrg.orgId,
name: idp.name, name: idp.name,
type: idp.type, type: idp.type,
variant: idpOidcConfig.variant, variant: idpOidcConfig.variant
tags: idp.tags
}) })
.from(idpOrg) .from(idpOrg)
.where(eq(idpOrg.orgId, orgId)) .where(eq(idpOrg.orgId, orgId))
@@ -63,17 +62,16 @@ async function query(orgId: string, limit: number, offset: number) {
return res; return res;
} }
registry.registerPath({ // registry.registerPath({
method: "get", // method: "get",
path: "/org/{orgId}/idp", // path: "/idp",
description: "List all IDP for a specific organization.", // description: "List all IDP in the system.",
tags: [OpenAPITags.Idp, OpenAPITags.Org], // tags: [OpenAPITags.Idp],
request: { // request: {
query: querySchema, // query: querySchema
params: paramsSchema // },
}, // responses: {}
responses: {} // });
});
export async function listOrgIdps( export async function listOrgIdps(
req: Request, req: Request,
@@ -46,31 +46,30 @@ const bodySchema = z.strictObject({
namePath: z.string().optional(), namePath: z.string().optional(),
scopes: z.string().optional(), scopes: z.string().optional(),
autoProvision: z.boolean().optional(), autoProvision: z.boolean().optional(),
roleMapping: z.string().optional(), roleMapping: z.string().optional()
tags: z.string().optional()
}); });
export type UpdateOrgIdpResponse = { export type UpdateOrgIdpResponse = {
idpId: number; idpId: number;
}; };
registry.registerPath({ // registry.registerPath({
method: "post", // method: "post",
path: "/org/{orgId}/idp/{idpId}/oidc", // path: "/idp/{idpId}/oidc",
description: "Update an OIDC IdP for a specific organization.", // description: "Update an OIDC IdP.",
tags: [OpenAPITags.Idp, OpenAPITags.Org], // tags: [OpenAPITags.Idp],
request: { // request: {
params: paramsSchema, // params: paramsSchema,
body: { // body: {
content: { // content: {
"application/json": { // "application/json": {
schema: bodySchema // schema: bodySchema
} // }
} // }
} // }
}, // },
responses: {} // responses: {}
}); // });
export async function updateOrgOidcIdp( export async function updateOrgOidcIdp(
req: Request, req: Request,
@@ -110,8 +109,7 @@ export async function updateOrgOidcIdp(
namePath, namePath,
name, name,
autoProvision, autoProvision,
roleMapping, roleMapping
tags
} = parsedBody.data; } = parsedBody.data;
if (build === "saas") { if (build === "saas") {
@@ -169,8 +167,7 @@ export async function updateOrgOidcIdp(
await db.transaction(async (trx) => { await db.transaction(async (trx) => {
const idpData = { const idpData = {
name, name,
autoProvision, autoProvision
tags
}; };
// only update if at least one key is not undefined // only update if at least one key is not undefined
@@ -24,8 +24,6 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
import { disconnectClient, sendToClient } from "#private/routers/ws"; import { disconnectClient, sendToClient } from "#private/routers/ws";
import { OlmErrorCodes, sendOlmError } from "@server/routers/olm/error";
import { sendTerminateClient } from "@server/routers/client/terminate";
const reGenerateSecretParamsSchema = z.strictObject({ const reGenerateSecretParamsSchema = z.strictObject({
clientId: z.string().transform(Number).pipe(z.int().positive()) clientId: z.string().transform(Number).pipe(z.int().positive())
@@ -119,12 +117,12 @@ export async function reGenerateClientSecret(
// Only disconnect if explicitly requested // Only disconnect if explicitly requested
if (disconnect) { if (disconnect) {
const payload = {
type: `olm/terminate`,
data: {}
};
// Don't await this to prevent blocking the response // Don't await this to prevent blocking the response
sendTerminateClient( sendToClient(existingOlms[0].olmId, payload).catch((error) => {
clientId,
OlmErrorCodes.TERMINATED_REKEYED,
existingOlms[0].olmId
).catch((error) => {
logger.error( logger.error(
"Failed to send termination message to olm:", "Failed to send termination message to olm:",
error error
+23 -164
View File
@@ -43,8 +43,7 @@ import {
WSMessage, WSMessage,
TokenPayload, TokenPayload,
WebSocketRequest, WebSocketRequest,
RedisMessage, RedisMessage
SendMessageOptions
} from "@server/routers/ws"; } from "@server/routers/ws";
import { validateSessionToken } from "@server/auth/sessions/app"; import { validateSessionToken } from "@server/auth/sessions/app";
@@ -119,21 +118,12 @@ const processMessage = async (
if (response.broadcast) { if (response.broadcast) {
await broadcastToAllExcept( await broadcastToAllExcept(
response.message, response.message,
response.excludeSender ? clientId : undefined, response.excludeSender ? clientId : undefined
response.options
); );
} else if (response.targetClientId) { } else if (response.targetClientId) {
await sendToClient( await sendToClient(response.targetClientId, response.message);
response.targetClientId,
response.message,
response.options
);
} else { } else {
await sendToClient( ws.send(JSON.stringify(response.message));
clientId,
response.message,
response.options
);
} }
} }
} catch (error) { } catch (error) {
@@ -182,9 +172,6 @@ const REDIS_CHANNEL = "websocket_messages";
// Client tracking map (local to this node) // Client tracking map (local to this node)
const connectedClients: Map<string, AuthenticatedWebSocket[]> = new Map(); const connectedClients: Map<string, AuthenticatedWebSocket[]> = new Map();
// Config version tracking map (local to this node, resets on server restart)
const clientConfigVersions: Map<string, number> = new Map();
// Recovery tracking // Recovery tracking
let isRedisRecoveryInProgress = false; let isRedisRecoveryInProgress = false;
@@ -195,8 +182,6 @@ const getClientMapKey = (clientId: string) => clientId;
const getConnectionsKey = (clientId: string) => `ws:connections:${clientId}`; const getConnectionsKey = (clientId: string) => `ws:connections:${clientId}`;
const getNodeConnectionsKey = (nodeId: string, clientId: string) => const getNodeConnectionsKey = (nodeId: string, clientId: string) =>
`ws:node:${nodeId}:${clientId}`; `ws:node:${nodeId}:${clientId}`;
const getConfigVersionKey = (clientId: string) =>
`ws:configVersion:${clientId}`;
// Initialize Redis subscription for cross-node messaging // Initialize Redis subscription for cross-node messaging
const initializeRedisSubscription = async (): Promise<void> => { const initializeRedisSubscription = async (): Promise<void> => {
@@ -319,45 +304,6 @@ const addClient = async (
existingClients.push(ws); existingClients.push(ws);
connectedClients.set(mapKey, existingClients); connectedClients.set(mapKey, existingClients);
// Get or initialize config version
let configVersion = 0;
// Check Redis first if enabled
if (redisManager.isRedisEnabled()) {
try {
const redisVersion = await redisManager.get(getConfigVersionKey(clientId));
if (redisVersion !== null) {
configVersion = parseInt(redisVersion, 10);
// Sync to local cache
clientConfigVersions.set(clientId, configVersion);
} else if (!clientConfigVersions.has(clientId)) {
// No version in Redis or local cache, initialize to 0
await redisManager.set(getConfigVersionKey(clientId), "0");
clientConfigVersions.set(clientId, 0);
} else {
// Use local cache version and sync to Redis
configVersion = clientConfigVersions.get(clientId) || 0;
await redisManager.set(getConfigVersionKey(clientId), configVersion.toString());
}
} catch (error) {
logger.error("Failed to get/set config version in Redis:", error);
// Fall back to local cache
if (!clientConfigVersions.has(clientId)) {
clientConfigVersions.set(clientId, 0);
}
configVersion = clientConfigVersions.get(clientId) || 0;
}
} else {
// Redis not enabled, use local cache only
if (!clientConfigVersions.has(clientId)) {
clientConfigVersions.set(clientId, 0);
}
configVersion = clientConfigVersions.get(clientId) || 0;
}
// Set config version on websocket
ws.configVersion = configVersion;
// Add to Redis tracking if enabled // Add to Redis tracking if enabled
if (redisManager.isRedisEnabled()) { if (redisManager.isRedisEnabled()) {
try { try {
@@ -376,7 +322,7 @@ const addClient = async (
} }
logger.info( logger.info(
`Client added to tracking - ${clientType.toUpperCase()} ID: ${clientId}, Connection ID: ${connectionId}, Total connections: ${existingClients.length}, Config version: ${configVersion}` `Client added to tracking - ${clientType.toUpperCase()} ID: ${clientId}, Connection ID: ${connectionId}, Total connections: ${existingClients.length}`
); );
}; };
@@ -431,133 +377,53 @@ const removeClient = async (
} }
}; };
// Helper to get the current config version for a client
const getClientConfigVersion = async (clientId: string): Promise<number | undefined> => {
// Try Redis first if available
if (redisManager.isRedisEnabled()) {
try {
const redisVersion = await redisManager.get(
getConfigVersionKey(clientId)
);
if (redisVersion !== null) {
const version = parseInt(redisVersion, 10);
// Sync local cache with Redis
clientConfigVersions.set(clientId, version);
return version;
}
} catch (error) {
logger.error("Failed to get config version from Redis:", error);
}
}
// Fall back to local cache
return clientConfigVersions.get(clientId);
};
// Helper to increment and get the new config version for a client
const incrementClientConfigVersion = async (
clientId: string
): Promise<number> => {
let newVersion: number;
if (redisManager.isRedisEnabled()) {
try {
// Use Redis INCR for atomic increment across nodes
newVersion = await redisManager.incr(getConfigVersionKey(clientId));
// Sync local cache
clientConfigVersions.set(clientId, newVersion);
return newVersion;
} catch (error) {
logger.error("Failed to increment config version in Redis:", error);
// Fall through to local increment
}
}
// Local increment
const currentVersion = clientConfigVersions.get(clientId) || 0;
newVersion = currentVersion + 1;
clientConfigVersions.set(clientId, newVersion);
return newVersion;
};
// Local message sending (within this node) // Local message sending (within this node)
const sendToClientLocal = async ( const sendToClientLocal = async (
clientId: string, clientId: string,
message: WSMessage, message: WSMessage
options: SendMessageOptions = {}
): Promise<boolean> => { ): Promise<boolean> => {
const mapKey = getClientMapKey(clientId); const mapKey = getClientMapKey(clientId);
const clients = connectedClients.get(mapKey); const clients = connectedClients.get(mapKey);
if (!clients || clients.length === 0) { if (!clients || clients.length === 0) {
return false; return false;
} }
const messageString = JSON.stringify(message);
// Handle config version
const configVersion = await getClientConfigVersion(clientId);
// Add config version to message
const messageWithVersion = {
...message,
configVersion
};
const messageString = JSON.stringify(messageWithVersion);
clients.forEach((client) => { clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) { if (client.readyState === WebSocket.OPEN) {
client.send(messageString); client.send(messageString);
} }
}); });
logger.debug(
`sendToClient: Message type ${message.type} sent to clientId ${clientId}`
);
return true; return true;
}; };
const broadcastToAllExceptLocal = async ( const broadcastToAllExceptLocal = async (
message: WSMessage, message: WSMessage,
excludeClientId?: string, excludeClientId?: string
options: SendMessageOptions = {}
): Promise<void> => { ): Promise<void> => {
for (const [mapKey, clients] of connectedClients.entries()) { connectedClients.forEach((clients, mapKey) => {
const [type, id] = mapKey.split(":"); const [type, id] = mapKey.split(":");
const clientId = mapKey; // mapKey is the clientId if (!(excludeClientId && id === excludeClientId)) {
if (!(excludeClientId && clientId === excludeClientId)) {
// Handle config version per client
let configVersion = await getClientConfigVersion(clientId);
if (options.incrementConfigVersion) {
configVersion = await incrementClientConfigVersion(clientId);
}
// Add config version to message
const messageWithVersion = {
...message,
configVersion
};
clients.forEach((client) => { clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) { if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(messageWithVersion)); client.send(JSON.stringify(message));
} }
}); });
} }
} });
}; };
// Cross-node message sending (via Redis) // Cross-node message sending (via Redis)
const sendToClient = async ( const sendToClient = async (
clientId: string, clientId: string,
message: WSMessage, message: WSMessage
options: SendMessageOptions = {}
): Promise<boolean> => { ): Promise<boolean> => {
let configVersion = await getClientConfigVersion(clientId);
if (options.incrementConfigVersion) {
configVersion = await incrementClientConfigVersion(clientId);
}
logger.debug(
`sendToClient: Message type ${message.type} sent to clientId ${clientId} (new configVersion: ${configVersion})`
);
// Try to send locally first // Try to send locally first
const localSent = await sendToClientLocal(clientId, message, options); const localSent = await sendToClientLocal(clientId, message);
// Only send via Redis if the client is not connected locally and Redis is enabled // Only send via Redis if the client is not connected locally and Redis is enabled
if (!localSent && redisManager.isRedisEnabled()) { if (!localSent && redisManager.isRedisEnabled()) {
@@ -565,10 +431,7 @@ const sendToClient = async (
const redisMessage: RedisMessage = { const redisMessage: RedisMessage = {
type: "direct", type: "direct",
targetClientId: clientId, targetClientId: clientId,
message: { message,
...message,
configVersion
},
fromNodeId: NODE_ID fromNodeId: NODE_ID
}; };
@@ -595,22 +458,19 @@ const sendToClient = async (
const broadcastToAllExcept = async ( const broadcastToAllExcept = async (
message: WSMessage, message: WSMessage,
excludeClientId?: string, excludeClientId?: string
options: SendMessageOptions = {}
): Promise<void> => { ): Promise<void> => {
// Broadcast locally // Broadcast locally
await broadcastToAllExceptLocal(message, excludeClientId, options); await broadcastToAllExceptLocal(message, excludeClientId);
// If Redis is enabled, also broadcast via Redis pub/sub to other nodes // If Redis is enabled, also broadcast via Redis pub/sub to other nodes
// Note: For broadcasts, we include the options so remote nodes can handle versioning
if (redisManager.isRedisEnabled()) { if (redisManager.isRedisEnabled()) {
try { try {
const redisMessage: RedisMessage = { const redisMessage: RedisMessage = {
type: "broadcast", type: "broadcast",
excludeClientId, excludeClientId,
message, message,
fromNodeId: NODE_ID, fromNodeId: NODE_ID
options
}; };
await redisManager.publish( await redisManager.publish(
@@ -1076,6 +936,5 @@ export {
getActiveNodes, getActiveNodes,
disconnectClient, disconnectClient,
NODE_ID, NODE_ID,
cleanup, cleanup
getClientConfigVersion
}; };
-1
View File
@@ -17,4 +17,3 @@ export * from "./securityKey";
export * from "./startDeviceWebAuth"; export * from "./startDeviceWebAuth";
export * from "./verifyDeviceWebAuth"; export * from "./verifyDeviceWebAuth";
export * from "./pollDeviceWebAuth"; export * from "./pollDeviceWebAuth";
export * from "./lookupUser";
-224
View File
@@ -1,224 +0,0 @@
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import {
users,
userOrgs,
orgs,
idpOrg,
idp,
idpOidcConfig
} from "@server/db";
import { eq, or, sql, and, isNotNull, inArray } from "drizzle-orm";
import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
import { UserType } from "@server/types/UserTypes";
const lookupBodySchema = z.strictObject({
identifier: z.string().min(1).toLowerCase()
});
export type LookupUserResponse = {
found: boolean;
identifier: string;
accounts: Array<{
userId: string;
email: string | null;
username: string;
hasInternalAuth: boolean;
orgs: Array<{
orgId: string;
orgName: string;
idps: Array<{
idpId: number;
name: string;
variant: string | null;
}>;
hasInternalAuth: boolean;
}>;
}>;
};
// registry.registerPath({
// method: "post",
// path: "/auth/lookup-user",
// description: "Lookup user accounts by username or email and return available authentication methods.",
// tags: [OpenAPITags.Auth],
// request: {
// body: lookupBodySchema
// },
// responses: {}
// });
export async function lookupUser(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = lookupBodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const { identifier } = parsedBody.data;
// Query users matching identifier (case-insensitive)
// Match by username OR email
const matchingUsers = await db
.select({
userId: users.userId,
email: users.email,
username: users.username,
type: users.type,
passwordHash: users.passwordHash,
idpId: users.idpId
})
.from(users)
.where(
or(
sql`LOWER(${users.username}) = ${identifier}`,
sql`LOWER(${users.email}) = ${identifier}`
)
);
if (!matchingUsers || matchingUsers.length === 0) {
return response<LookupUserResponse>(res, {
data: {
found: false,
identifier,
accounts: []
},
success: true,
error: false,
message: "No accounts found",
status: HttpCode.OK
});
}
// Get unique user IDs
const userIds = [...new Set(matchingUsers.map((u) => u.userId))];
// Get all org memberships for these users
const orgMemberships = await db
.select({
userId: userOrgs.userId,
orgId: userOrgs.orgId,
orgName: orgs.name
})
.from(userOrgs)
.innerJoin(orgs, eq(orgs.orgId, userOrgs.orgId))
.where(inArray(userOrgs.userId, userIds));
// Get unique org IDs
const orgIds = [...new Set(orgMemberships.map((m) => m.orgId))];
// Get all IdPs for these orgs
const orgIdps =
orgIds.length > 0
? await db
.select({
orgId: idpOrg.orgId,
idpId: idp.idpId,
idpName: idp.name,
variant: idpOidcConfig.variant
})
.from(idpOrg)
.innerJoin(idp, eq(idp.idpId, idpOrg.idpId))
.innerJoin(
idpOidcConfig,
eq(idpOidcConfig.idpId, idp.idpId)
)
.where(inArray(idpOrg.orgId, orgIds))
: [];
// Build response structure
const accounts: LookupUserResponse["accounts"] = [];
for (const user of matchingUsers) {
const hasInternalAuth =
user.type === UserType.Internal && user.passwordHash !== null;
// Get orgs for this user
const userOrgMemberships = orgMemberships.filter(
(m) => m.userId === user.userId
);
// Deduplicate orgs (user might have multiple memberships in same org)
const uniqueOrgs = new Map<string, typeof userOrgMemberships[0]>();
for (const membership of userOrgMemberships) {
if (!uniqueOrgs.has(membership.orgId)) {
uniqueOrgs.set(membership.orgId, membership);
}
}
const orgsData = Array.from(uniqueOrgs.values()).map((membership) => {
// Get IdPs for this org where the user (with the exact identifier) is authenticated via that IdP
// Only show IdPs where the user's idpId matches
// Internal users don't have an idpId, so they won't see any IdPs
const orgIdpsList = orgIdps
.filter((idp) => {
if (idp.orgId !== membership.orgId) {
return false;
}
// Only show IdPs where the user (with exact identifier) is authenticated via that IdP
// This means user.idpId must match idp.idpId
if (user.idpId !== null && user.idpId === idp.idpId) {
return true;
}
return false;
})
.map((idp) => ({
idpId: idp.idpId,
name: idp.idpName,
variant: idp.variant
}));
// Check if user has internal auth for this org
// User has internal auth if they have an internal account type
const orgHasInternalAuth = hasInternalAuth;
return {
orgId: membership.orgId,
orgName: membership.orgName,
idps: orgIdpsList,
hasInternalAuth: orgHasInternalAuth
};
});
accounts.push({
userId: user.userId,
email: user.email,
username: user.username,
hasInternalAuth,
orgs: orgsData
});
}
return response<LookupUserResponse>(res, {
data: {
found: true,
identifier,
accounts
},
success: true,
error: false,
message: "User lookup completed",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
+1 -7
View File
@@ -10,7 +10,6 @@ import { eq, and, gt } from "drizzle-orm";
import { encodeHexLowerCase } from "@oslojs/encoding"; import { encodeHexLowerCase } from "@oslojs/encoding";
import { sha256 } from "@oslojs/crypto/sha2"; import { sha256 } from "@oslojs/crypto/sha2";
import { unauthorized } from "@server/auth/unauthorizedResponse"; import { unauthorized } from "@server/auth/unauthorizedResponse";
import { getIosDeviceName, getMacDeviceName } from "@server/db/names";
const bodySchema = z const bodySchema = z
.object({ .object({
@@ -121,11 +120,6 @@ export async function verifyDeviceWebAuth(
); );
} }
const deviceName =
getMacDeviceName(deviceCode.deviceName) ||
getIosDeviceName(deviceCode.deviceName) ||
deviceCode.deviceName;
// If verify is false, just return metadata without verifying // If verify is false, just return metadata without verifying
if (!verify) { if (!verify) {
return response<VerifyDeviceWebAuthResponse>(res, { return response<VerifyDeviceWebAuthResponse>(res, {
@@ -135,7 +129,7 @@ export async function verifyDeviceWebAuth(
metadata: { metadata: {
ip: deviceCode.ip, ip: deviceCode.ip,
city: deviceCode.city, city: deviceCode.city,
deviceName: deviceName, deviceName: deviceCode.deviceName,
applicationName: deviceCode.applicationName, applicationName: deviceCode.applicationName,
createdAt: deviceCode.createdAt createdAt: deviceCode.createdAt
} }
+3 -31
View File
@@ -49,43 +49,27 @@ const auditLogBuffer: Array<{
const BATCH_SIZE = 100; // Write to DB every 100 logs const BATCH_SIZE = 100; // Write to DB every 100 logs
const BATCH_INTERVAL_MS = 5000; // Or every 5 seconds, whichever comes first const BATCH_INTERVAL_MS = 5000; // Or every 5 seconds, whichever comes first
const MAX_BUFFER_SIZE = 10000; // Prevent unbounded memory growth
let flushTimer: NodeJS.Timeout | null = null; let flushTimer: NodeJS.Timeout | null = null;
let isFlushInProgress = false;
/** /**
* Flush buffered logs to database * Flush buffered logs to database
*/ */
async function flushAuditLogs() { async function flushAuditLogs() {
if (auditLogBuffer.length === 0 || isFlushInProgress) { if (auditLogBuffer.length === 0) {
return; return;
} }
isFlushInProgress = true;
// Take all current logs and clear buffer // Take all current logs and clear buffer
const logsToWrite = auditLogBuffer.splice(0, auditLogBuffer.length); const logsToWrite = auditLogBuffer.splice(0, auditLogBuffer.length);
try { try {
// Batch insert logs in groups of 25 to avoid overwhelming the database // Batch insert all logs at once
const BATCH_DB_SIZE = 25; await db.insert(requestAuditLog).values(logsToWrite);
for (let i = 0; i < logsToWrite.length; i += BATCH_DB_SIZE) {
const batch = logsToWrite.slice(i, i + BATCH_DB_SIZE);
await db.insert(requestAuditLog).values(batch);
}
logger.debug(`Flushed ${logsToWrite.length} audit logs to database`); logger.debug(`Flushed ${logsToWrite.length} audit logs to database`);
} catch (error) { } catch (error) {
logger.error("Error flushing audit logs:", error); logger.error("Error flushing audit logs:", error);
// On error, we lose these logs - consider a fallback strategy if needed // On error, we lose these logs - consider a fallback strategy if needed
// (e.g., write to file, or put back in buffer with retry limit) // (e.g., write to file, or put back in buffer with retry limit)
} finally {
isFlushInProgress = false;
// If buffer filled up while we were flushing, flush again
if (auditLogBuffer.length >= BATCH_SIZE) {
flushAuditLogs().catch((err) =>
logger.error("Error in follow-up flush:", err)
);
}
} }
} }
@@ -111,10 +95,6 @@ export async function shutdownAuditLogger() {
clearTimeout(flushTimer); clearTimeout(flushTimer);
flushTimer = null; flushTimer = null;
} }
// Force flush even if one is in progress by waiting and retrying
while (isFlushInProgress) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
await flushAuditLogs(); await flushAuditLogs();
} }
@@ -232,14 +212,6 @@ export async function logRequestAudit(
? stripPortFromHost(body.requestIp) ? stripPortFromHost(body.requestIp)
: undefined; : undefined;
// Prevent unbounded buffer growth - drop oldest entries if buffer is too large
if (auditLogBuffer.length >= MAX_BUFFER_SIZE) {
const dropped = auditLogBuffer.splice(0, BATCH_SIZE);
logger.warn(
`Audit log buffer exceeded max size (${MAX_BUFFER_SIZE}), dropped ${dropped.length} oldest entries`
);
}
// Add to buffer instead of writing directly to DB // Add to buffer instead of writing directly to DB
auditLogBuffer.push({ auditLogBuffer.push({
timestamp, timestamp,
+10 -21
View File
@@ -942,7 +942,7 @@ async function isUserAllowedToAccessResource(
username: user.username, username: user.username,
email: user.email, email: user.email,
name: user.name, name: user.name,
role: userOrgRole.roleName role: user.role
}; };
} }
@@ -956,7 +956,7 @@ async function isUserAllowedToAccessResource(
username: user.username, username: user.username,
email: user.email, email: user.email,
name: user.name, name: user.name,
role: userOrgRole.roleName role: user.role
}; };
} }
@@ -1035,25 +1035,14 @@ export function isPathAllowed(pattern: string, path: string): boolean {
logger.debug(`Normalized pattern parts: [${patternParts.join(", ")}]`); logger.debug(`Normalized pattern parts: [${patternParts.join(", ")}]`);
logger.debug(`Normalized path parts: [${pathParts.join(", ")}]`); logger.debug(`Normalized path parts: [${pathParts.join(", ")}]`);
// Maximum recursion depth to prevent stack overflow and memory issues
const MAX_RECURSION_DEPTH = 100;
// Recursive function to try different wildcard matches // Recursive function to try different wildcard matches
function matchSegments(patternIndex: number, pathIndex: number, depth: number = 0): boolean { function matchSegments(patternIndex: number, pathIndex: number): boolean {
// Check recursion depth limit const indent = " ".repeat(pathIndex); // Indent based on recursion depth
if (depth > MAX_RECURSION_DEPTH) {
logger.warn(
`Path matching exceeded maximum recursion depth (${MAX_RECURSION_DEPTH}) for pattern "${pattern}" and path "${path}"`
);
return false;
}
const indent = " ".repeat(depth); // Indent based on recursion depth
const currentPatternPart = patternParts[patternIndex]; const currentPatternPart = patternParts[patternIndex];
const currentPathPart = pathParts[pathIndex]; const currentPathPart = pathParts[pathIndex];
logger.debug( logger.debug(
`${indent}Checking patternIndex=${patternIndex} (${currentPatternPart || "END"}) vs pathIndex=${pathIndex} (${currentPathPart || "END"}) [depth=${depth}]` `${indent}Checking patternIndex=${patternIndex} (${currentPatternPart || "END"}) vs pathIndex=${pathIndex} (${currentPathPart || "END"})`
); );
// If we've consumed all pattern parts, we should have consumed all path parts // If we've consumed all pattern parts, we should have consumed all path parts
@@ -1086,7 +1075,7 @@ export function isPathAllowed(pattern: string, path: string): boolean {
logger.debug( logger.debug(
`${indent}Trying to skip wildcard (consume 0 segments)` `${indent}Trying to skip wildcard (consume 0 segments)`
); );
if (matchSegments(patternIndex + 1, pathIndex, depth + 1)) { if (matchSegments(patternIndex + 1, pathIndex)) {
logger.debug( logger.debug(
`${indent}Successfully matched by skipping wildcard` `${indent}Successfully matched by skipping wildcard`
); );
@@ -1097,7 +1086,7 @@ export function isPathAllowed(pattern: string, path: string): boolean {
logger.debug( logger.debug(
`${indent}Trying to consume segment "${currentPathPart}" for wildcard` `${indent}Trying to consume segment "${currentPathPart}" for wildcard`
); );
if (matchSegments(patternIndex, pathIndex + 1, depth + 1)) { if (matchSegments(patternIndex, pathIndex + 1)) {
logger.debug( logger.debug(
`${indent}Successfully matched by consuming segment for wildcard` `${indent}Successfully matched by consuming segment for wildcard`
); );
@@ -1125,7 +1114,7 @@ export function isPathAllowed(pattern: string, path: string): boolean {
logger.debug( logger.debug(
`${indent}Segment with wildcard matches: "${currentPatternPart}" matches "${currentPathPart}"` `${indent}Segment with wildcard matches: "${currentPatternPart}" matches "${currentPathPart}"`
); );
return matchSegments(patternIndex + 1, pathIndex + 1, depth + 1); return matchSegments(patternIndex + 1, pathIndex + 1);
} }
logger.debug( logger.debug(
@@ -1146,10 +1135,10 @@ export function isPathAllowed(pattern: string, path: string): boolean {
`${indent}Segments match: "${currentPatternPart}" = "${currentPathPart}"` `${indent}Segments match: "${currentPatternPart}" = "${currentPathPart}"`
); );
// Move to next segments in both pattern and path // Move to next segments in both pattern and path
return matchSegments(patternIndex + 1, pathIndex + 1, depth + 1); return matchSegments(patternIndex + 1, pathIndex + 1);
} }
const result = matchSegments(0, 0, 0); const result = matchSegments(0, 0);
logger.debug(`Final result: ${result}`); logger.debug(`Final result: ${result}`);
return result; return result;
} }
@@ -26,8 +26,7 @@ const applyBlueprintSchema = z
message: `Invalid YAML: ${error instanceof Error ? error.message : "Unknown error"}` message: `Invalid YAML: ${error instanceof Error ? error.message : "Unknown error"}`
}); });
} }
}), })
source: z.enum(["API", "UI", "CLI"]).optional()
}) })
.strict(); .strict();
@@ -85,7 +84,7 @@ export async function applyYAMLBlueprint(
); );
} }
const { blueprint: contents, name, source = "UI" } = parsedBody.data; const { blueprint: contents, name } = parsedBody.data;
logger.debug(`Received blueprint:`, contents); logger.debug(`Received blueprint:`, contents);
@@ -108,7 +107,7 @@ export async function applyYAMLBlueprint(
blueprint = await applyBlueprint({ blueprint = await applyBlueprint({
orgId, orgId,
name, name,
source, source: "UI",
configData: parsedConfig configData: parsedConfig
}); });
} catch (err) { } catch (err) {
+1 -1
View File
@@ -1,6 +1,6 @@
import type { Blueprint } from "@server/db"; import type { Blueprint } from "@server/db";
export type BlueprintSource = "API" | "UI" | "NEWT" | "CLI"; export type BlueprintSource = "API" | "UI" | "NEWT";
export type BlueprintData = Omit<Blueprint, "source"> & { export type BlueprintData = Omit<Blueprint, "source"> & {
source: BlueprintSource; source: BlueprintSource;
-101
View File
@@ -1,101 +0,0 @@
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { clients } from "@server/db";
import { eq } from "drizzle-orm";
import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
import { rebuildClientAssociationsFromClient } from "@server/lib/rebuildClientAssociations";
import { sendTerminateClient } from "./terminate";
import { OlmErrorCodes } from "../olm/error";
const archiveClientSchema = z.strictObject({
clientId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",
path: "/client/{clientId}/archive",
description: "Archive a client by its client ID.",
tags: [OpenAPITags.Client],
request: {
params: archiveClientSchema
},
responses: {}
});
export async function archiveClient(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = archiveClientSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { clientId } = parsedParams.data;
// Check if client exists
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Client with ID ${clientId} not found`
)
);
}
if (client.archived) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
`Client with ID ${clientId} is already archived`
)
);
}
await db.transaction(async (trx) => {
// Archive the client
await trx
.update(clients)
.set({ archived: true })
.where(eq(clients.clientId, clientId));
// Rebuild associations to clean up related data
await rebuildClientAssociationsFromClient(client, trx);
});
return response(res, {
data: null,
success: true,
error: false,
message: "Client archived successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to archive client"
)
);
}
}
-102
View File
@@ -1,102 +0,0 @@
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { clients } from "@server/db";
import { eq } from "drizzle-orm";
import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
import { sendTerminateClient } from "./terminate";
import { OlmErrorCodes } from "../olm/error";
const blockClientSchema = z.strictObject({
clientId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",
path: "/client/{clientId}/block",
description: "Block a client by its client ID.",
tags: [OpenAPITags.Client],
request: {
params: blockClientSchema
},
responses: {}
});
export async function blockClient(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = blockClientSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { clientId } = parsedParams.data;
// Check if client exists
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Client with ID ${clientId} not found`
)
);
}
if (client.blocked) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
`Client with ID ${clientId} is already blocked`
)
);
}
await db.transaction(async (trx) => {
// Block the client
await trx
.update(clients)
.set({ blocked: true, approvalState: "denied" })
.where(eq(clients.clientId, clientId));
// Send terminate signal if there's an associated OLM and it's connected
if (client.olmId && client.online) {
await sendTerminateClient(client.clientId, OlmErrorCodes.TERMINATED_BLOCKED, client.olmId);
}
});
return response(res, {
data: null,
success: true,
error: false,
message: "Client blocked successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to block client"
)
);
}
}
+2 -4
View File
@@ -11,7 +11,6 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { rebuildClientAssociationsFromClient } from "@server/lib/rebuildClientAssociations"; import { rebuildClientAssociationsFromClient } from "@server/lib/rebuildClientAssociations";
import { sendTerminateClient } from "./terminate"; import { sendTerminateClient } from "./terminate";
import { OlmErrorCodes } from "../olm/error";
const deleteClientSchema = z.strictObject({ const deleteClientSchema = z.strictObject({
clientId: z.string().transform(Number).pipe(z.int().positive()) clientId: z.string().transform(Number).pipe(z.int().positive())
@@ -61,12 +60,11 @@ export async function deleteClient(
); );
} }
// Only allow deletion of machine clients (clients without userId)
if (client.userId) { if (client.userId) {
return next( return next(
createHttpError( createHttpError(
HttpCode.BAD_REQUEST, HttpCode.BAD_REQUEST,
`Cannot delete a user client. User clients must be archived instead.` `Cannot delete a user client with this endpoint`
) )
); );
} }
@@ -92,7 +90,7 @@ export async function deleteClient(
await rebuildClientAssociationsFromClient(deletedClient, trx); await rebuildClientAssociationsFromClient(deletedClient, trx);
if (olm) { if (olm) {
await sendTerminateClient(deletedClient.clientId, OlmErrorCodes.TERMINATED_DELETED, olm.olmId); // the olmId needs to be provided because it cant look it up after deletion await sendTerminateClient(deletedClient.clientId, olm.olmId); // the olmId needs to be provided because it cant look it up after deletion
} }
}); });
+2 -218
View File
@@ -1,7 +1,7 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
import { z } from "zod"; import { z } from "zod";
import { db, olms } from "@server/db"; import { db, olms } from "@server/db";
import { clients, currentFingerprint } from "@server/db"; import { clients } from "@server/db";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
import response from "@server/lib/response"; import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
@@ -10,9 +10,6 @@ import logger from "@server/logger";
import stoi from "@server/lib/stoi"; import stoi from "@server/lib/stoi";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { getUserDeviceName } from "@server/db/names";
import { build } from "@server/build";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
const getClientSchema = z.strictObject({ const getClientSchema = z.strictObject({
clientId: z clientId: z
@@ -32,10 +29,6 @@ async function query(clientId?: number, niceId?: string, orgId?: string) {
.from(clients) .from(clients)
.where(eq(clients.clientId, clientId)) .where(eq(clients.clientId, clientId))
.leftJoin(olms, eq(clients.clientId, olms.clientId)) .leftJoin(olms, eq(clients.clientId, olms.clientId))
.leftJoin(
currentFingerprint,
eq(olms.olmId, currentFingerprint.olmId)
)
.limit(1); .limit(1);
return res; return res;
} else if (niceId && orgId) { } else if (niceId && orgId) {
@@ -44,182 +37,15 @@ async function query(clientId?: number, niceId?: string, orgId?: string) {
.from(clients) .from(clients)
.where(and(eq(clients.niceId, niceId), eq(clients.orgId, orgId))) .where(and(eq(clients.niceId, niceId), eq(clients.orgId, orgId)))
.leftJoin(olms, eq(clients.clientId, olms.clientId)) .leftJoin(olms, eq(clients.clientId, olms.clientId))
.leftJoin(
currentFingerprint,
eq(olms.olmId, currentFingerprint.olmId)
)
.limit(1); .limit(1);
return res; return res;
} }
} }
type PostureData = {
biometricsEnabled?: boolean | null;
diskEncrypted?: boolean | null;
firewallEnabled?: boolean | null;
autoUpdatesEnabled?: boolean | null;
tpmAvailable?: boolean | null;
windowsAntivirusEnabled?: boolean | null;
macosSipEnabled?: boolean | null;
macosGatekeeperEnabled?: boolean | null;
macosFirewallStealthMode?: boolean | null;
linuxAppArmorEnabled?: boolean | null;
linuxSELinuxEnabled?: boolean | null;
};
function getPlatformPostureData(
platform: string | null | undefined,
fingerprint: typeof currentFingerprint.$inferSelect | null
): PostureData | null {
if (!fingerprint) return null;
const normalizedPlatform = platform?.toLowerCase() || "unknown";
const posture: PostureData = {};
// Windows: Hard drive encryption, Firewall, Auto updates, TPM availability, Windows Antivirus status
if (normalizedPlatform === "windows") {
if (
fingerprint.diskEncrypted !== null &&
fingerprint.diskEncrypted !== undefined
) {
posture.diskEncrypted = fingerprint.diskEncrypted;
}
if (
fingerprint.firewallEnabled !== null &&
fingerprint.firewallEnabled !== undefined
) {
posture.firewallEnabled = fingerprint.firewallEnabled;
}
if (
fingerprint.tpmAvailable !== null &&
fingerprint.tpmAvailable !== undefined
) {
posture.tpmAvailable = fingerprint.tpmAvailable;
}
if (
fingerprint.windowsAntivirusEnabled !== null &&
fingerprint.windowsAntivirusEnabled !== undefined
) {
posture.windowsAntivirusEnabled =
fingerprint.windowsAntivirusEnabled;
}
}
// macOS: Hard drive encryption, Biometric configuration, Firewall, System Integrity Protection (SIP), Gatekeeper, Firewall stealth mode
else if (normalizedPlatform === "macos") {
if (
fingerprint.diskEncrypted !== null &&
fingerprint.diskEncrypted !== undefined
) {
posture.diskEncrypted = fingerprint.diskEncrypted;
}
if (
fingerprint.biometricsEnabled !== null &&
fingerprint.biometricsEnabled !== undefined
) {
posture.biometricsEnabled = fingerprint.biometricsEnabled;
}
if (
fingerprint.firewallEnabled !== null &&
fingerprint.firewallEnabled !== undefined
) {
posture.firewallEnabled = fingerprint.firewallEnabled;
}
if (
fingerprint.macosSipEnabled !== null &&
fingerprint.macosSipEnabled !== undefined
) {
posture.macosSipEnabled = fingerprint.macosSipEnabled;
}
if (
fingerprint.macosGatekeeperEnabled !== null &&
fingerprint.macosGatekeeperEnabled !== undefined
) {
posture.macosGatekeeperEnabled = fingerprint.macosGatekeeperEnabled;
}
if (
fingerprint.macosFirewallStealthMode !== null &&
fingerprint.macosFirewallStealthMode !== undefined
) {
posture.macosFirewallStealthMode =
fingerprint.macosFirewallStealthMode;
}
if (
fingerprint.autoUpdatesEnabled !== null &&
fingerprint.autoUpdatesEnabled !== undefined
) {
posture.autoUpdatesEnabled = fingerprint.autoUpdatesEnabled;
}
}
// Linux: Hard drive encryption, Firewall, AppArmor, SELinux, TPM availability
else if (normalizedPlatform === "linux") {
if (
fingerprint.diskEncrypted !== null &&
fingerprint.diskEncrypted !== undefined
) {
posture.diskEncrypted = fingerprint.diskEncrypted;
}
if (
fingerprint.firewallEnabled !== null &&
fingerprint.firewallEnabled !== undefined
) {
posture.firewallEnabled = fingerprint.firewallEnabled;
}
if (
fingerprint.linuxAppArmorEnabled !== null &&
fingerprint.linuxAppArmorEnabled !== undefined
) {
posture.linuxAppArmorEnabled = fingerprint.linuxAppArmorEnabled;
}
if (
fingerprint.linuxSELinuxEnabled !== null &&
fingerprint.linuxSELinuxEnabled !== undefined
) {
posture.linuxSELinuxEnabled = fingerprint.linuxSELinuxEnabled;
}
if (
fingerprint.tpmAvailable !== null &&
fingerprint.tpmAvailable !== undefined
) {
posture.tpmAvailable = fingerprint.tpmAvailable;
}
}
// iOS: Biometric configuration
else if (normalizedPlatform === "ios") {
// none supported yet
}
// Android: Screen lock, Biometric configuration, Hard drive encryption
else if (normalizedPlatform === "android") {
if (
fingerprint.diskEncrypted !== null &&
fingerprint.diskEncrypted !== undefined
) {
posture.diskEncrypted = fingerprint.diskEncrypted;
}
}
// Only return if we have at least one posture field
return Object.keys(posture).length > 0 ? posture : null;
}
export type GetClientResponse = NonNullable< export type GetClientResponse = NonNullable<
Awaited<ReturnType<typeof query>> Awaited<ReturnType<typeof query>>
>["clients"] & { >["clients"] & {
olmId: string | null; olmId: string | null;
agent: string | null;
olmVersion: string | null;
fingerprint: {
username: string | null;
hostname: string | null;
platform: string | null;
osVersion: string | null;
kernelVersion: string | null;
arch: string | null;
deviceModel: string | null;
serialNumber: string | null;
firstSeen: number | null;
lastSeen: number | null;
} | null;
posture: PostureData | null;
}; };
registry.registerPath({ registry.registerPath({
@@ -279,51 +105,9 @@ export async function getClient(
); );
} }
// Replace name with device name if OLM exists
let clientName = client.clients.name;
if (client.olms) {
const model = client.currentFingerprint?.deviceModel || null;
clientName = getUserDeviceName(model, client.clients.name);
}
// Build fingerprint data if available
const fingerprintData = client.currentFingerprint
? {
username: client.currentFingerprint.username || null,
hostname: client.currentFingerprint.hostname || null,
platform: client.currentFingerprint.platform || null,
osVersion: client.currentFingerprint.osVersion || null,
kernelVersion:
client.currentFingerprint.kernelVersion || null,
arch: client.currentFingerprint.arch || null,
deviceModel: client.currentFingerprint.deviceModel || null,
serialNumber: client.currentFingerprint.serialNumber || null,
firstSeen: client.currentFingerprint.firstSeen || null,
lastSeen: client.currentFingerprint.lastSeen || null
}
: null;
// Build posture data if available (platform-specific)
// Only return posture data if org is licensed/subscribed
let postureData: PostureData | null = null;
const isOrgLicensed = await isLicensedOrSubscribed(
client.clients.orgId
);
if (isOrgLicensed) {
postureData = getPlatformPostureData(
client.currentFingerprint?.platform || null,
client.currentFingerprint
);
}
const data: GetClientResponse = { const data: GetClientResponse = {
...client.clients, ...client.clients,
name: clientName, olmId: client.olms ? client.olms.olmId : null
olmId: client.olms ? client.olms.olmId : null,
agent: client.olms?.agent || null,
olmVersion: client.olms?.version || null,
fingerprint: fingerprintData,
posture: postureData
}; };
return response<GetClientResponse>(res, { return response<GetClientResponse>(res, {
-4
View File
@@ -1,10 +1,6 @@
export * from "./pickClientDefaults"; export * from "./pickClientDefaults";
export * from "./createClient"; export * from "./createClient";
export * from "./deleteClient"; export * from "./deleteClient";
export * from "./archiveClient";
export * from "./unarchiveClient";
export * from "./blockClient";
export * from "./unblockClient";
export * from "./listClients"; export * from "./listClients";
export * from "./updateClient"; export * from "./updateClient";
export * from "./getClient"; export * from "./getClient";
+19 -37
View File
@@ -5,8 +5,7 @@ import {
roleClients, roleClients,
sites, sites,
userClients, userClients,
clientSitesAssociationsCache, clientSitesAssociationsCache
currentFingerprint
} from "@server/db"; } from "@server/db";
import logger from "@server/logger"; import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
@@ -28,7 +27,6 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import NodeCache from "node-cache"; import NodeCache from "node-cache";
import semver from "semver"; import semver from "semver";
import { getUserDeviceName } from "@server/db/names";
const olmVersionCache = new NodeCache({ stdTTL: 3600 }); const olmVersionCache = new NodeCache({ stdTTL: 3600 });
@@ -138,25 +136,12 @@ function queryClients(
username: users.username, username: users.username,
userEmail: users.email, userEmail: users.email,
niceId: clients.niceId, niceId: clients.niceId,
agent: olms.agent, agent: olms.agent
approvalState: clients.approvalState,
olmArchived: olms.archived,
archived: clients.archived,
blocked: clients.blocked,
deviceModel: currentFingerprint.deviceModel,
fingerprintPlatform: currentFingerprint.platform,
fingerprintOsVersion: currentFingerprint.osVersion,
fingerprintKernelVersion: currentFingerprint.kernelVersion,
fingerprintArch: currentFingerprint.arch,
fingerprintSerialNumber: currentFingerprint.serialNumber,
fingerprintUsername: currentFingerprint.username,
fingerprintHostname: currentFingerprint.hostname
}) })
.from(clients) .from(clients)
.leftJoin(orgs, eq(clients.orgId, orgs.orgId)) .leftJoin(orgs, eq(clients.orgId, orgs.orgId))
.leftJoin(olms, eq(clients.clientId, olms.clientId)) .leftJoin(olms, eq(clients.clientId, olms.clientId))
.leftJoin(users, eq(clients.userId, users.userId)) .leftJoin(users, eq(clients.userId, users.userId))
.leftJoin(currentFingerprint, eq(olms.olmId, currentFingerprint.olmId))
.where(and(...conditions)); .where(and(...conditions));
} }
@@ -175,19 +160,21 @@ async function getSiteAssociations(clientIds: number[]) {
.where(inArray(clientSitesAssociationsCache.clientId, clientIds)); .where(inArray(clientSitesAssociationsCache.clientId, clientIds));
} }
type ClientWithSites = Awaited<ReturnType<typeof queryClients>>[0] & { type OlmWithUpdateAvailable = Awaited<ReturnType<typeof queryClients>>[0] & {
sites: Array<{
siteId: number;
siteName: string | null;
siteNiceId: string | null;
}>;
olmUpdateAvailable?: boolean; olmUpdateAvailable?: boolean;
}; };
type OlmWithUpdateAvailable = ClientWithSites;
export type ListClientsResponse = { export type ListClientsResponse = {
clients: Array<ClientWithSites>; clients: Array<
Awaited<ReturnType<typeof queryClients>>[0] & {
sites: Array<{
siteId: number;
siteName: string | null;
siteNiceId: string | null;
}>;
olmUpdateAvailable?: boolean;
}
>;
pagination: { total: number; limit: number; offset: number }; pagination: { total: number; limit: number; offset: number };
}; };
@@ -317,16 +304,11 @@ export async function listClients(
> >
); );
// Merge clients with their site associations and replace name with device name // Merge clients with their site associations
const clientsWithSites = clientsList.map((client) => { const clientsWithSites = clientsList.map((client) => ({
const model = client.deviceModel || null; ...client,
const newName = getUserDeviceName(model, client.name); sites: sitesByClient[client.clientId] || []
return { }));
...client,
name: newName,
sites: sitesByClient[client.clientId] || []
};
});
const latestOlVersionPromise = getLatestOlmVersion(); const latestOlVersionPromise = getLatestOlmVersion();
@@ -365,7 +347,7 @@ export async function listClients(
return response<ListClientsResponse>(res, { return response<ListClientsResponse>(res, {
data: { data: {
clients: olmsWithUpdates, clients: clientsWithSites,
pagination: { pagination: {
total: totalCount, total: totalCount,
limit, limit,
+6 -6
View File
@@ -28,7 +28,7 @@ export async function addTargets(newtId: string, targets: SubnetProxyTarget[]) {
await sendToClient(newtId, { await sendToClient(newtId, {
type: `newt/wg/targets/add`, type: `newt/wg/targets/add`,
data: batches[i] data: batches[i]
}, { incrementConfigVersion: true }); });
} }
} }
@@ -44,7 +44,7 @@ export async function removeTargets(
await sendToClient(newtId, { await sendToClient(newtId, {
type: `newt/wg/targets/remove`, type: `newt/wg/targets/remove`,
data: batches[i] data: batches[i]
},{ incrementConfigVersion: true }); });
} }
} }
@@ -69,7 +69,7 @@ export async function updateTargets(
oldTargets: oldBatches[i] || [], oldTargets: oldBatches[i] || [],
newTargets: newBatches[i] || [] newTargets: newBatches[i] || []
} }
}, { incrementConfigVersion: true }).catch((error) => { }).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
@@ -101,7 +101,7 @@ export async function addPeerData(
remoteSubnets: remoteSubnets, remoteSubnets: remoteSubnets,
aliases: aliases aliases: aliases
} }
}, { incrementConfigVersion: true }).catch((error) => { }).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
@@ -132,7 +132,7 @@ export async function removePeerData(
remoteSubnets: remoteSubnets, remoteSubnets: remoteSubnets,
aliases: aliases aliases: aliases
} }
}, { incrementConfigVersion: true }).catch((error) => { }).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
@@ -173,7 +173,7 @@ export async function updatePeerData(
...remoteSubnets, ...remoteSubnets,
...aliases ...aliases
} }
}, { incrementConfigVersion: true }).catch((error) => { }).catch((error) => {
logger.warn(`Error sending message:`, error); logger.warn(`Error sending message:`, error);
}); });
} }
+1 -6
View File
@@ -1,11 +1,9 @@
import { sendToClient } from "#dynamic/routers/ws"; import { sendToClient } from "#dynamic/routers/ws";
import { db, olms } from "@server/db"; import { db, olms } from "@server/db";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { OlmErrorCodes } from "../olm/error";
export async function sendTerminateClient( export async function sendTerminateClient(
clientId: number, clientId: number,
error: (typeof OlmErrorCodes)[keyof typeof OlmErrorCodes],
olmId?: string | null olmId?: string | null
) { ) {
if (!olmId) { if (!olmId) {
@@ -22,9 +20,6 @@ export async function sendTerminateClient(
await sendToClient(olmId, { await sendToClient(olmId, {
type: `olm/terminate`, type: `olm/terminate`,
data: { data: {}
code: error.code,
message: error.message
}
}); });
} }
-93
View File
@@ -1,93 +0,0 @@
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { clients } from "@server/db";
import { eq } from "drizzle-orm";
import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const unarchiveClientSchema = z.strictObject({
clientId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",
path: "/client/{clientId}/unarchive",
description: "Unarchive a client by its client ID.",
tags: [OpenAPITags.Client],
request: {
params: unarchiveClientSchema
},
responses: {}
});
export async function unarchiveClient(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = unarchiveClientSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { clientId } = parsedParams.data;
// Check if client exists
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Client with ID ${clientId} not found`
)
);
}
if (!client.archived) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
`Client with ID ${clientId} is not archived`
)
);
}
// Unarchive the client
await db
.update(clients)
.set({ archived: false })
.where(eq(clients.clientId, clientId));
return response(res, {
data: null,
success: true,
error: false,
message: "Client unarchived successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to unarchive client"
)
);
}
}
-93
View File
@@ -1,93 +0,0 @@
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
import { clients } from "@server/db";
import { eq } from "drizzle-orm";
import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const unblockClientSchema = z.strictObject({
clientId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",
path: "/client/{clientId}/unblock",
description: "Unblock a client by its client ID.",
tags: [OpenAPITags.Client],
request: {
params: unblockClientSchema
},
responses: {}
});
export async function unblockClient(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = unblockClientSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { clientId } = parsedParams.data;
// Check if client exists
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Client with ID ${clientId} not found`
)
);
}
if (!client.blocked) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
`Client with ID ${clientId} is not blocked`
)
);
}
// Unblock the client
await db
.update(clients)
.set({ blocked: false, approvalState: null })
.where(eq(clients.clientId, clientId));
return response(res, {
data: null,
success: true,
error: false,
message: "Client unblocked successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to unblock client"
)
);
}
}

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