Compare commits

...

375 Commits

Author SHA1 Message Date
Owen Schwartz 3c3f068500 New translations en-us.json (French)
[ci skip]
2026-07-20 12:55:32 -04:00
Owen Schwartz 8eac2f811b New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-20 12:55:29 -04:00
Owen Schwartz 55ad2b1009 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-20 12:55:27 -04:00
Owen Schwartz 6cf4e1c1b7 New translations en-us.json (Turkish)
[ci skip]
2026-07-20 12:55:25 -04:00
Owen Schwartz 36a46fcca7 New translations en-us.json (Russian)
[ci skip]
2026-07-20 12:55:23 -04:00
Owen Schwartz 4b8412cbcd New translations en-us.json (Portuguese)
[ci skip]
2026-07-20 12:55:20 -04:00
Owen Schwartz c36aaafd69 New translations en-us.json (Polish)
[ci skip]
2026-07-20 12:55:18 -04:00
Owen Schwartz 1e988e542f New translations en-us.json (Dutch)
[ci skip]
2026-07-20 12:55:16 -04:00
Owen Schwartz a245d55272 New translations en-us.json (Korean)
[ci skip]
2026-07-20 12:55:13 -04:00
Owen Schwartz c180d06b0a New translations en-us.json (Italian)
[ci skip]
2026-07-20 12:55:11 -04:00
Owen Schwartz bca8dfa4bc New translations en-us.json (German)
[ci skip]
2026-07-20 12:55:08 -04:00
Owen Schwartz b1543aaefe New translations en-us.json (Danish)
[ci skip]
2026-07-20 12:55:06 -04:00
Owen Schwartz 26fe554793 New translations en-us.json (Czech)
[ci skip]
2026-07-20 12:55:04 -04:00
Owen Schwartz f0247ccd76 New translations en-us.json (Bulgarian)
[ci skip]
2026-07-20 12:55:02 -04:00
Owen Schwartz a00add2976 New translations en-us.json (Spanish)
[ci skip]
2026-07-20 12:55:00 -04:00
Owen Schwartz a062c721c7 New translations en-us.json (French)
[ci skip]
2026-07-18 16:34:56 -04:00
Owen Schwartz 5803304023 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-18 16:34:54 -04:00
Owen Schwartz cbcb7304a0 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-18 16:34:52 -04:00
Owen Schwartz e17b921cd7 New translations en-us.json (Turkish)
[ci skip]
2026-07-18 16:34:51 -04:00
Owen Schwartz 0165fca7d4 New translations en-us.json (Russian)
[ci skip]
2026-07-18 16:34:49 -04:00
Owen Schwartz ef225884fb New translations en-us.json (Portuguese)
[ci skip]
2026-07-18 16:34:47 -04:00
Owen Schwartz c15afa3950 New translations en-us.json (Polish)
[ci skip]
2026-07-18 16:34:45 -04:00
Owen Schwartz b7ca6d2f09 New translations en-us.json (Dutch)
[ci skip]
2026-07-18 16:34:43 -04:00
Owen Schwartz 99340e8e17 New translations en-us.json (Korean)
[ci skip]
2026-07-18 16:34:41 -04:00
Owen Schwartz 9bda88ca51 New translations en-us.json (Italian)
[ci skip]
2026-07-18 16:34:40 -04:00
Owen Schwartz 4758e0f737 New translations en-us.json (German)
[ci skip]
2026-07-18 16:34:38 -04:00
Owen Schwartz 0f14623f1a New translations en-us.json (Danish)
[ci skip]
2026-07-18 16:34:36 -04:00
Owen Schwartz e3537b8d99 New translations en-us.json (Czech)
[ci skip]
2026-07-18 16:34:34 -04:00
Owen Schwartz af8463a141 New translations en-us.json (Bulgarian)
[ci skip]
2026-07-18 16:34:32 -04:00
Owen Schwartz da58a42003 New translations en-us.json (Spanish)
[ci skip]
2026-07-18 16:34:31 -04:00
Owen Schwartz 452a2b3dd3 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-17 16:13:28 -04:00
Owen Schwartz ace90e99d1 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-17 16:13:26 -04:00
Owen Schwartz efe53a2294 New translations en-us.json (Turkish)
[ci skip]
2026-07-17 16:13:24 -04:00
Owen Schwartz 5c39c98e3a New translations en-us.json (Russian)
[ci skip]
2026-07-17 16:13:23 -04:00
Owen Schwartz 9b9fc5caa1 New translations en-us.json (Portuguese)
[ci skip]
2026-07-17 16:13:21 -04:00
Owen Schwartz ef09b62bf3 New translations en-us.json (Polish)
[ci skip]
2026-07-17 16:13:19 -04:00
Owen Schwartz 9a269d515f New translations en-us.json (Dutch)
[ci skip]
2026-07-17 16:13:17 -04:00
Owen Schwartz 891dbdc6d8 New translations en-us.json (Korean)
[ci skip]
2026-07-17 16:13:15 -04:00
Owen Schwartz d90850e99d New translations en-us.json (Italian)
[ci skip]
2026-07-17 16:13:13 -04:00
Owen Schwartz d363416769 New translations en-us.json (German)
[ci skip]
2026-07-17 16:13:11 -04:00
Owen Schwartz f115ddd2b2 New translations en-us.json (Danish)
[ci skip]
2026-07-17 16:13:09 -04:00
Owen Schwartz 754837b36d New translations en-us.json (Czech)
[ci skip]
2026-07-17 16:13:07 -04:00
Owen Schwartz 0e67c31908 New translations en-us.json (Bulgarian)
[ci skip]
2026-07-17 16:13:05 -04:00
Owen Schwartz b7511e912d New translations en-us.json (Spanish)
[ci skip]
2026-07-17 16:13:03 -04:00
Owen 02d2e09709 Merge branch 'local-connection' into dev 2026-07-17 14:07:30 -04:00
miloschwartz 6e8283957c update remote node routes to support access token updates 2026-07-17 14:06:35 -04:00
miloschwartz bb9b94a983 add persistent session and users to access tokens 2026-07-17 13:39:09 -04:00
Owen 36f807ddbc Merge branch 'dev' into local-connection 2026-07-17 11:15:51 -04:00
miloschwartz cb31546c6b fix spelling in installer 2026-07-17 10:15:11 -04:00
miloschwartz 2d48adc9f9 use proxy for logout on org auth page session expire 2026-07-16 22:06:59 -04:00
Owen Schwartz ca279ee3e0 Merge pull request #3452 from fosrl/crowdin_dev
New Crowdin updates
2026-07-16 21:37:08 -04:00
Owen Schwartz a5808200f0 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-16 21:34:54 -04:00
Owen Schwartz aa9de4d2ac New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-16 21:34:52 -04:00
Owen Schwartz 50821e972d New translations en-us.json (Turkish)
[ci skip]
2026-07-16 21:34:50 -04:00
Owen Schwartz e5b9dfee66 New translations en-us.json (Russian)
[ci skip]
2026-07-16 21:34:48 -04:00
Owen Schwartz 8e09070bc1 New translations en-us.json (Portuguese)
[ci skip]
2026-07-16 21:34:46 -04:00
Owen Schwartz 3d9c413bbb New translations en-us.json (Polish)
[ci skip]
2026-07-16 21:34:45 -04:00
Owen Schwartz 86670c1d60 New translations en-us.json (Dutch)
[ci skip]
2026-07-16 21:34:43 -04:00
Owen Schwartz 5f2ee77a73 New translations en-us.json (Korean)
[ci skip]
2026-07-16 21:34:41 -04:00
Owen Schwartz 714e3a8fb1 New translations en-us.json (Italian)
[ci skip]
2026-07-16 21:34:40 -04:00
Owen Schwartz 672555f051 New translations en-us.json (German)
[ci skip]
2026-07-16 21:34:38 -04:00
Owen Schwartz 7853f2b096 New translations en-us.json (Danish)
[ci skip]
2026-07-16 21:34:36 -04:00
Owen Schwartz 61a7dda29a New translations en-us.json (Czech)
[ci skip]
2026-07-16 21:34:35 -04:00
Owen Schwartz f9bcb25eaa New translations en-us.json (Bulgarian)
[ci skip]
2026-07-16 21:34:33 -04:00
Owen Schwartz 6df804ab32 New translations en-us.json (Spanish)
[ci skip]
2026-07-16 21:34:31 -04:00
Owen Schwartz 9e50735800 New translations en-us.json (French)
[ci skip]
2026-07-16 21:34:29 -04:00
miloschwartz a30119f5e8 encode email in url param 2026-07-16 21:28:36 -04:00
miloschwartz 3c9f0946d2 add site provisioning keys to integration api 2026-07-16 17:56:31 -04:00
Owen 21861a6dcd Merge branch 'local-connection' of github.com:fosrl/pangolin into local-connection 2026-07-16 17:25:58 -04:00
Owen 6135f2b727 Local endpoints from the get config 2026-07-16 17:25:51 -04:00
Owen 3a616cc804 Add handlers 2026-07-16 17:25:51 -04:00
Owen d5eb67a8fc Send localEndpoints on sites to olm 2026-07-16 17:25:51 -04:00
Owen 3ac7ef23ae Save the local endpoints 2026-07-16 17:25:51 -04:00
Owen 08c5ec2be7 Add new column 2026-07-16 17:25:51 -04:00
Owen a88b79e066 Add timezone offset to fix bad display 2026-07-16 16:09:35 -04:00
Owen a48ef77ee5 Merge branch 'dev' of github.com:fosrl/pangolin into dev 2026-07-16 15:49:52 -04:00
Owen 55f3807491 Enforce uniqueness of aliases in blueprints 2026-07-16 15:10:38 -04:00
Owen dbfb8e83e8 Local endpoints from the get config 2026-07-16 14:43:45 -04:00
Owen 515afc14a5 Add handlers 2026-07-16 11:23:53 -04:00
Owen 903e8c0fa1 Send localEndpoints on sites to olm 2026-07-16 10:47:24 -04:00
Owen 7f9c760380 Save the local endpoints 2026-07-16 09:59:11 -04:00
Owen 530a1a5350 Add new column 2026-07-16 09:59:07 -04:00
miloschwartz 3fb36c1434 add missing translation 2026-07-15 22:03:28 -04:00
Owen Schwartz 29f91e8276 Merge pull request #3449 from fosrl/crowdin_dev
New Crowdin updates
2026-07-15 20:54:40 -04:00
Owen Schwartz 4d9e38d022 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-15 20:54:17 -04:00
Owen Schwartz d7d31b78f0 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-15 20:54:15 -04:00
Owen Schwartz e8ed8fc7e9 New translations en-us.json (Turkish)
[ci skip]
2026-07-15 20:54:13 -04:00
Owen Schwartz 5ee406c92e New translations en-us.json (Russian)
[ci skip]
2026-07-15 20:54:12 -04:00
Owen Schwartz 89f4f4ba6f New translations en-us.json (Portuguese)
[ci skip]
2026-07-15 20:54:10 -04:00
Owen Schwartz 4e5fd2f2b0 New translations en-us.json (French)
[ci skip]
2026-07-15 20:54:08 -04:00
Owen Schwartz 22a5743817 New translations en-us.json (Polish)
[ci skip]
2026-07-15 20:54:06 -04:00
Owen Schwartz 40e05f903a New translations en-us.json (Dutch)
[ci skip]
2026-07-15 20:54:04 -04:00
Owen Schwartz 6c1e1bc0ca New translations en-us.json (Korean)
[ci skip]
2026-07-15 20:54:02 -04:00
Owen Schwartz cebbf9ca65 New translations en-us.json (Italian)
[ci skip]
2026-07-15 20:54:00 -04:00
Owen Schwartz e6646e5833 New translations en-us.json (German)
[ci skip]
2026-07-15 20:53:59 -04:00
Owen Schwartz 00f7510195 New translations en-us.json (Danish)
[ci skip]
2026-07-15 20:53:57 -04:00
Owen Schwartz 8d1f5e1096 New translations en-us.json (Czech)
[ci skip]
2026-07-15 20:53:55 -04:00
Owen Schwartz e497fcc3b9 New translations en-us.json (Bulgarian)
[ci skip]
2026-07-15 20:53:53 -04:00
Owen Schwartz a7010b2788 New translations en-us.json (Spanish)
[ci skip]
2026-07-15 20:53:51 -04:00
Owen abf58a70ee Merge branch 'provisioning-resources' into dev 2026-07-15 20:45:39 -04:00
Owen d4c602cf91 Update the counts when deleting resources 2026-07-15 17:22:12 -04:00
miloschwartz d1b0bbb6d9 update translations 2026-07-15 16:05:53 -04:00
miloschwartz ae0be3a4bc add resources overview column to pending sites table 2026-07-12 17:53:57 -04:00
miloschwartz a8f3f71021 add reject endpoint 2026-07-12 17:48:48 -04:00
miloschwartz 933ca71c16 add approve site endpoint 2026-07-12 17:16:08 -04:00
miloschwartz 591cb9cdc1 dont use strict query params in list alises 2026-07-10 18:05:16 -04:00
miloschwartz 34b18bdb53 only show approved resources in launcher 2026-07-10 17:24:10 -04:00
miloschwartz 7d475f5e91 filter out pending resources 2026-07-10 17:18:33 -04:00
miloschwartz 39c35fa539 reorganize components nad hooks for consistency 2026-07-10 17:05:45 -04:00
Milo Schwartz bada1fdb97 Merge pull request #3394 from fosrl/feat/remember-last-idp-on-smart-login-form
feat: Remember last used idp in login forms
2026-07-10 16:34:22 -04:00
miloschwartz d9303f87c8 set last used cookie in smart login lookup 2026-07-10 16:34:02 -04:00
Owen e1bc0b7efd Make sure the enabled gets set to false 2026-07-10 15:36:05 -04:00
Owen 5ef068c8dc Set the resource from the site 2026-07-10 15:31:37 -04:00
miloschwartz 14680df160 suse tiermatrix in server component susbcribed check 2026-07-10 15:23:09 -04:00
Owen 94c01a23a9 Merge branch 'private-resource-enable' into provisioning-resources 2026-07-10 15:17:06 -04:00
Owen 609fb357bb Support enable in the blueprints 2026-07-10 15:16:50 -04:00
Owen cf9a17cc2e Add status filter 2026-07-10 15:04:28 -04:00
Owen 538b57941c Makes sure patch works
z#
2026-07-10 11:32:27 -04:00
Owen f4bee6406a Support partial updates 2026-07-10 10:11:47 -04:00
Owen 0b2693a317 Add toggle to the ui for enabled 2026-07-10 09:59:11 -04:00
Owen 3be2d928f6 Filter out disabled 2026-07-09 21:42:59 -04:00
miloschwartz d38f9ac2bb update readme 2026-07-09 21:32:35 -04:00
Owen 8d018fe47d Clean up 2026-07-09 21:28:48 -04:00
Fred KISSIE 34d5c9535d ♻️ delete last used IDP coookie when logging in with email/password on smart login form 2026-07-10 03:22:28 +02:00
Fred KISSIE dc60ef712f Merge branch 'dev' into feat/remember-last-idp-on-smart-login-form 2026-07-10 02:38:38 +02:00
Owen dc7eb630c3 Add missing action 2026-07-09 11:16:15 -04:00
Owen Schwartz bbcd352817 Merge pull request #3420 from fosrl/crowdin_dev
New Crowdin updates
2026-07-09 10:35:21 -04:00
Owen Schwartz 21d9199978 New translations en-us.json (French)
[ci skip]
2026-07-09 10:34:31 -04:00
Owen Schwartz 3e7b9d7bff New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-09 10:34:29 -04:00
Owen Schwartz 54acdbe282 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-09 10:34:27 -04:00
Owen Schwartz 11bbd028fc New translations en-us.json (Turkish)
[ci skip]
2026-07-09 10:34:24 -04:00
Owen Schwartz 7ae99731f4 New translations en-us.json (Russian)
[ci skip]
2026-07-09 10:34:22 -04:00
Owen Schwartz 17b4fd9a44 New translations en-us.json (Portuguese)
[ci skip]
2026-07-09 10:34:20 -04:00
Owen Schwartz caa398ae54 New translations en-us.json (Polish)
[ci skip]
2026-07-09 10:34:18 -04:00
Owen Schwartz 035e324e5a New translations en-us.json (Dutch)
[ci skip]
2026-07-09 10:34:16 -04:00
Owen Schwartz 272a5737b0 New translations en-us.json (Korean)
[ci skip]
2026-07-09 10:34:14 -04:00
Owen Schwartz be50fd4586 New translations en-us.json (Italian)
[ci skip]
2026-07-09 10:34:12 -04:00
Owen Schwartz 8301511efe New translations en-us.json (German)
[ci skip]
2026-07-09 10:34:10 -04:00
Owen Schwartz c527ce6562 New translations en-us.json (Danish)
[ci skip]
2026-07-09 10:34:08 -04:00
Owen Schwartz 80bee900aa New translations en-us.json (Czech)
[ci skip]
2026-07-09 10:34:06 -04:00
Owen Schwartz 54209c2390 New translations en-us.json (Bulgarian)
[ci skip]
2026-07-09 10:34:04 -04:00
Owen Schwartz 3b0ee8d9d4 New translations en-us.json (Spanish)
[ci skip]
2026-07-09 10:34:02 -04:00
miloschwartz 7a0a877dc0 fix create private resource ports default to blocked 2026-07-09 10:28:06 -04:00
Owen b6ed762724 Sort before inserting 2026-07-09 10:18:41 -04:00
Owen Schwartz d1d58cf455 Merge pull request #3418 from fosrl/crowdin_dev
New Crowdin updates
2026-07-09 10:00:30 -04:00
Owen Schwartz e22f30c694 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-09 09:59:33 -04:00
Owen Schwartz d71c112959 New translations en-us.json (Turkish)
[ci skip]
2026-07-09 09:59:30 -04:00
Owen Schwartz 199e960f6d New translations en-us.json (Portuguese)
[ci skip]
2026-07-09 09:59:26 -04:00
Owen Schwartz 843b9a0b16 New translations en-us.json (Dutch)
[ci skip]
2026-07-09 09:59:23 -04:00
Owen Schwartz b9aedc65fe New translations en-us.json (Italian)
[ci skip]
2026-07-09 09:59:20 -04:00
Owen Schwartz 11f5cfd4f8 New translations en-us.json (German)
[ci skip]
2026-07-09 09:59:18 -04:00
Owen Schwartz 2ff2e32e9c New translations en-us.json (Danish)
[ci skip]
2026-07-09 09:59:16 -04:00
Owen Schwartz facb1e4cdf New translations en-us.json (Spanish)
[ci skip]
2026-07-09 09:59:11 -04:00
Owen 6d129c0738 Fix #3099 2026-07-08 21:44:20 -04:00
Owen 67a3d226f5 Add session creation 2026-07-08 21:17:40 -04:00
Owen 19a3773880 Update ironrdp
Ref #3272
2026-07-08 16:23:53 -04:00
Owen Schwartz 8eab3b1ee2 Merge pull request #3409 from fosrl/crowdin_dev
New Crowdin updates
2026-07-08 14:00:41 -04:00
Owen Schwartz 30b46ebb6e New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-08 13:59:57 -04:00
Owen Schwartz 91d5f89ab9 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-08 13:59:55 -04:00
Owen Schwartz 703050f949 New translations en-us.json (Turkish)
[ci skip]
2026-07-08 13:59:53 -04:00
Owen Schwartz 97af17a993 New translations en-us.json (Russian)
[ci skip]
2026-07-08 13:59:51 -04:00
Owen Schwartz 09a8c457ac New translations en-us.json (Portuguese)
[ci skip]
2026-07-08 13:59:49 -04:00
Owen Schwartz 80317aca83 New translations en-us.json (Polish)
[ci skip]
2026-07-08 13:59:47 -04:00
Owen Schwartz bd10519598 New translations en-us.json (Dutch)
[ci skip]
2026-07-08 13:59:45 -04:00
Owen Schwartz 15c7c47b3c New translations en-us.json (Korean)
[ci skip]
2026-07-08 13:59:43 -04:00
Owen Schwartz 0a7e8c3cc2 New translations en-us.json (Italian)
[ci skip]
2026-07-08 13:59:42 -04:00
Owen Schwartz fc2668fca8 New translations en-us.json (German)
[ci skip]
2026-07-08 13:59:40 -04:00
Owen Schwartz 8f2c20a2bc New translations en-us.json (Danish)
[ci skip]
2026-07-08 13:59:38 -04:00
Owen Schwartz 462ae7ee8c New translations en-us.json (Czech)
[ci skip]
2026-07-08 13:59:36 -04:00
Owen Schwartz 808abd2038 New translations en-us.json (Bulgarian)
[ci skip]
2026-07-08 13:59:34 -04:00
Owen Schwartz 3de25e51ff New translations en-us.json (Spanish)
[ci skip]
2026-07-08 13:59:32 -04:00
Owen Schwartz ef25a9dbe0 New translations en-us.json (French)
[ci skip]
2026-07-08 13:59:30 -04:00
miloschwartz e21c3afb13 fix restart site styling 2026-07-08 12:32:29 -04:00
Milo Schwartz cb7962c25d Merge pull request #3200 from Adityakk9031/#3001
fix: redirect lost after Pangolin auth session timeout (#3001)
2026-07-08 12:30:39 -04:00
miloschwartz f667ee4feb fix api reference 2026-07-08 12:29:23 -04:00
miloschwartz 810119e4ee Merge branch 'dev' into #3001 2026-07-08 12:10:13 -04:00
miloschwartz d082de3d88 command palette tweaks 2026-07-07 21:55:15 -04:00
Milo Schwartz 1e7863ce4f Merge pull request #3342 from Fredkiss3/feat/geoip-country-is-not-rule
feat: add country `is not` rule in resource policies
2026-07-07 21:18:43 -04:00
Milo Schwartz a942871f3d Merge pull request #3263 from Fredkiss3/feat/command-bar
feat: Command Palette for searching accross the dashboard
2026-07-07 21:17:39 -04:00
Fred KISSIE 2fe85ebda2 ♻️ set last IDP to null if login with email + password 2026-07-08 03:11:12 +02:00
Milo Schwartz da1205d38e Merge pull request #3407 from fosrl/fix/non-semver-version-error
fix: invalid version causing crashes in the frontend
2026-07-07 21:09:05 -04:00
Fred KISSIE 92775a51ca 🐛 fix invalid semver version causing crashes in frontend 2026-07-08 01:44:28 +02:00
Fred KISSIE ea60aa701e 🐛 fix sitetable page crashing because of invalid version 2026-07-08 01:39:52 +02:00
Fred KISSIE b1f7ee02b0 🐛 fix imports 2026-07-08 00:58:03 +02:00
Fred KISSIE affa3bbb6a Merge branch 'dev' into feat/command-bar 2026-07-08 00:33:28 +02:00
miloschwartz dbb1e7b274 dont show non sso resoruces 2026-07-07 18:10:12 -04:00
miloschwartz b2d1a66279 bump version 2026-07-07 17:08:49 -04:00
miloschwartz 202466792c fix search icon alignment 2026-07-07 16:34:37 -04:00
miloschwartz 4dcf684868 add 1.20.0 migration 2026-07-07 16:04:41 -04:00
miloschwartz 2b8f50af6f add missing api key perms to permissions selector 2026-07-07 15:23:41 -04:00
Owen a8c255ef71 Fix type issue 2026-07-07 15:21:23 -04:00
miloschwartz d9608bd408 improve role required feedback on user 2026-07-07 15:17:29 -04:00
Owen be193731c1 Reorder labels columns 2026-07-07 15:15:00 -04:00
Owen 0c3edc7560 Further remove labels 2026-07-07 15:12:14 -04:00
miloschwartz 813a3f07dc Merge branch 'dev' into private-resource-page 2026-07-07 15:07:35 -04:00
Owen 417438c209 Remove feature flags from labels 2026-07-07 15:04:41 -04:00
miloschwartz beaa5735ce move cert to info box and add network access to create wizard 2026-07-07 14:51:15 -04:00
Owen 83de8576bf Add ? to support undefined 2026-07-07 10:59:01 -04:00
Owen e9d424eb80 Move jit mode to a config param
Ref #3262
2026-07-07 10:41:12 -04:00
Owen 8cceed91cf Make feilds optional 2026-07-07 09:02:25 -04:00
Owen 633159fb77 Email whitelist should respect policies 2026-07-07 08:37:20 -04:00
miloschwartz 4c8bd4db0a includen on sso resources in launcher 2026-07-06 22:00:35 -04:00
miloschwartz d742300e82 add mising tooltips to collapsed sidebar 2026-07-06 21:52:22 -04:00
miloschwartz a521db91a2 migrate private resources to page 2026-07-06 21:48:29 -04:00
Owen d4549f1c33 log error 2026-07-06 14:44:30 -04:00
Owen 71da22328c Quiet logs 2026-07-06 14:44:30 -04:00
miloschwartz 0b5b732a48 Merge branch 'resource-launcher-compact' into dev 2026-07-06 14:19:58 -04:00
miloschwartz a82bae8f93 add resource info to side panel 2026-07-06 12:45:07 -04:00
Owen e59176149b Disable jit
Fixes #3262
2026-07-06 11:01:40 -04:00
Owen 2c3151da9b Fix #3374 2026-07-03 17:36:06 -04:00
Owen f60b8795ad Fix #3383 2026-07-03 17:26:49 -04:00
Owen 4054976388 Fix #3395 2026-07-03 17:15:48 -04:00
Fred KISSIE 11c30b8b27 Merge branch 'dev' into feat/geoip-country-is-not-rule 2026-07-03 22:50:56 +02:00
Fred KISSIE 3d13e9105c 🏷️ fix types 2026-07-03 22:33:58 +02:00
Fred KISSIE 289be30e6b show last used login idp in smart login form 2026-07-03 22:33:51 +02:00
Owen 390c822bb4 Fix issue with overlapping site resources not sending 2026-07-03 16:13:50 -04:00
Fred KISSIE a74c0c227c 🌐 text 2026-07-03 21:05:53 +02:00
Fred KISSIE 05bf77da29 ♻️ remove cache on verifySession calls as it's already wrapped in cache 2026-07-03 21:05:47 +02:00
Fred KISSIE bb4deb1ae9 remember last used idp in dashboard login form 2026-07-03 21:05:16 +02:00
Owen 2bfc1901a6 Dont check the subnet because we dont use it 2026-07-03 14:38:01 -04:00
Owen 5da186b528 Quiet warning messages 2026-07-03 11:58:00 -04:00
Owen 600a96c13b Update rate limit to 10 2026-07-03 11:52:59 -04:00
Owen e4e0da3723 Add not exists check 2026-07-03 11:24:53 -04:00
miloschwartz 4087d7fb6b remove text from refresh button 2026-07-03 11:18:06 -04:00
miloschwartz 9edb86fd73 add invalidate launcher cache on refresh 2026-07-03 10:30:41 -04:00
Owen 440ebfe08e Clarify error messages 2026-07-03 10:26:13 -04:00
Owen b399d2a291 Add some retry and database confict mitigation 2026-07-03 10:23:32 -04:00
miloschwartz 811119a9a6 reduce filter dropdown page size 2026-07-03 10:13:58 -04:00
miloschwartz b53f80d317 use column for default view 2026-07-03 09:59:49 -04:00
Owen 1b1fba60f1 Make sure to retry rebuilds 2026-07-03 09:02:08 -04:00
miloschwartz a89509c8bd add more caching 2026-07-02 23:32:16 -04:00
miloschwartz f0546eb622 add save default view 2026-07-02 22:27:51 -04:00
miloschwartz 12f9ac94fd allow grouping when filter applied 2026-07-02 22:07:30 -04:00
miloschwartz 1717a99cee add compact mode for large orgs 2026-07-02 21:53:52 -04:00
Owen b93d26f09f Fix reading from replicas 2026-07-02 21:46:53 -04:00
Owen fc54ad49b5 Fix trial showing 2026-07-02 21:46:44 -04:00
Owen f87e136f6b Unique subnets for exit nodes 2026-07-02 20:54:59 -04:00
Owen 1bf3d2cdd6 Add back the sync with semver 2026-07-02 12:10:20 -04:00
Owen 5fc5a3ebca Adjust spacing 2026-07-02 11:49:49 -04:00
Owen e40f325703 Add new limits to the billing page 2026-07-02 10:55:46 -04:00
Owen 8f377a4fb2 Dont run on cloud 2026-07-01 22:07:33 -04:00
Owen Schwartz 3699f8f9cb Merge pull request #3380 from fosrl/resource-launcher
improve pagination
2026-07-01 21:47:14 -04:00
Owen 5a2388a1e6 Fix imports 2026-07-01 21:43:51 -04:00
Owen 86e6ebc8af Comment out sync again for now 2026-07-01 21:40:08 -04:00
miloschwartz 005f050a81 improve pagination 2026-07-01 21:36:23 -04:00
Owen Schwartz c82678852e Merge pull request #3377 from fosrl/crowdin_dev
New Crowdin updates
2026-07-01 21:30:26 -04:00
Owen Schwartz 2e3ab10f5e New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-07-01 21:28:16 -04:00
Owen Schwartz 4985ed02d3 New translations en-us.json (Chinese Simplified)
[ci skip]
2026-07-01 21:28:14 -04:00
Owen Schwartz a2fea7f714 New translations en-us.json (Turkish)
[ci skip]
2026-07-01 21:28:12 -04:00
Owen Schwartz ddba2aff21 New translations en-us.json (Russian)
[ci skip]
2026-07-01 21:28:11 -04:00
Owen Schwartz da9e668fb8 New translations en-us.json (Portuguese)
[ci skip]
2026-07-01 21:28:09 -04:00
Owen Schwartz 9c2d14d8c6 New translations en-us.json (Polish)
[ci skip]
2026-07-01 21:28:07 -04:00
Owen Schwartz c383e74df4 New translations en-us.json (Dutch)
[ci skip]
2026-07-01 21:28:05 -04:00
Owen Schwartz 40101f8bb0 New translations en-us.json (Korean)
[ci skip]
2026-07-01 21:28:03 -04:00
Owen Schwartz b20ed9efa9 New translations en-us.json (Italian)
[ci skip]
2026-07-01 21:28:02 -04:00
Owen Schwartz 56266e3b62 New translations en-us.json (German)
[ci skip]
2026-07-01 21:28:00 -04:00
Owen Schwartz 47eff8c948 New translations en-us.json (Danish)
[ci skip]
2026-07-01 21:27:58 -04:00
Owen Schwartz 15f36096ef New translations en-us.json (Czech)
[ci skip]
2026-07-01 21:27:57 -04:00
Owen Schwartz 064252586d New translations en-us.json (Bulgarian)
[ci skip]
2026-07-01 21:27:55 -04:00
Owen Schwartz 6181d46a1e New translations en-us.json (Spanish)
[ci skip]
2026-07-01 21:27:53 -04:00
Owen Schwartz 9747731668 New translations en-us.json (French)
[ci skip]
2026-07-01 21:27:51 -04:00
Owen Schwartz 2a478eef6f Merge pull request #3375 from fosrl/resource-launcher
Resource launcher
2026-07-01 21:19:19 -04:00
Owen 4ab101f8a9 Fix lock 2026-07-01 21:13:40 -04:00
miloschwartz e35878ee55 add caching 2026-07-01 19:59:38 -04:00
Owen 807613f28c Move rate limit up 2026-07-01 17:30:07 -04:00
miloschwartz 663244fa3a support labels in list alises 2026-07-01 16:17:27 -04:00
Owen bcc128aeb6 Fix ping function 2026-07-01 15:47:24 -04:00
Owen ba33cb9895 Increment config version for this 2026-07-01 15:44:08 -04:00
Owen 69e7fedcfc Add the remote exit node info 2026-07-01 15:28:26 -04:00
miloschwartz 023110b341 update en-us 2026-07-01 15:18:49 -04:00
miloschwartz 7fb95e1726 restore script 2026-07-01 15:15:43 -04:00
miloschwartz db0a7cc1ce fix toolbar responsiveness and disable side panel 2026-07-01 15:14:29 -04:00
Owen 61fc2e5ea7 Fix restartSite import 2026-07-01 14:48:36 -04:00
miloschwartz 0871a211ec open side panel on click 2026-07-01 14:30:43 -04:00
miloschwartz 5a1d5cb66e redirect to settings if org admin 2026-07-01 14:06:33 -04:00
miloschwartz 5a7ca5b542 add refresh button 2026-07-01 12:38:45 -04:00
miloschwartz 87e1a509ce show sites and labels for non admins 2026-07-01 12:17:36 -04:00
miloschwartz 75f481bc3d improve search bar debounce behavior 2026-07-01 11:53:11 -04:00
miloschwartz 97cdb2eb5a use proper label filter selector 2026-07-01 11:46:20 -04:00
miloschwartz 297fd2caf3 standardize permissions in api 2026-07-01 11:26:14 -04:00
miloschwartz 22dd4220fe fix ordering of buttons 2026-07-01 11:09:26 -04:00
Owen 108cb6216c Add migration to fix policy delete issues
Ref #3257
2026-07-01 10:39:41 -04:00
Owen e3ef592778 Adjust language 2026-07-01 10:39:41 -04:00
miloschwartz 3c37e10638 add mobile overflow menu 2026-07-01 10:11:17 -04:00
miloschwartz 561f75b6b1 improve responsiveness 2026-07-01 10:03:06 -04:00
Owen Schwartz e98bcb83ac Merge pull request #3371 from jaisinha77777/fix/oss-listexitnodes-siteid-signature
Fix OSS build break: add siteId param to OSS listExitNodes
2026-07-01 08:44:12 -04:00
Owen Schwartz 80284863bb Merge pull request #3369 from jaisinha77777/fix/private-resources-delete-error-toast
Fix broken toast on private resource delete failure
2026-07-01 08:43:50 -04:00
miloschwartz bc759c5c9e improve mobile responsiveness 2026-06-30 22:11:25 -04:00
miloschwartz f4854a3a74 include exit node endpoint in tcp/udp resources 2026-06-30 21:54:27 -04:00
miloschwartz 376dd465b3 show no site category 2026-06-30 21:49:08 -04:00
jaisinha77777 296439fd67 Fix OSS build break: add siteId param to OSS listExitNodes
listExitNodes is resolved via the #dynamic path alias, which maps to
server/lib in the OSS build and server/private/lib in enterprise/saas.
Commit 9c18936b added a 4th siteId argument to the shared caller
(handleNewtPingRequestMessage) and to the enterprise implementation, but
not to the OSS one, so under the OSS tsconfig the call fails:

  handleNewtPingRequestMessage.ts: error TS2554: Expected 1-3 arguments,
  but got 4.

This breaks 'npx tsc --noEmit' for the OSS build (the CI 'Test with tsc'
step runs it after set:oss). Add siteId?: number to the OSS signature
for parity. It is unused in OSS since that build has no remote exit
nodes to label-filter; accepting it keeps the two #dynamic
implementations interface-compatible.
2026-07-01 07:17:03 +05:30
jaisinha77777 31f675f38c Fix broken toast on private resource delete failure
The delete-error handler in PrivateResourcesTable referenced two i18n
keys that do not exist in the message catalog:

- console.error used "resourceErrorDelete" (the catalog key is
  "resourceErrorDelte"), logging a raw key instead of the message.
- the toast description passed "v" to formatAxiosError, so a failed
  delete showed the user a bogus fallback title.

Point both at the existing "resourceErrorDelte" key, matching the
delete handlers in PublicResourcesTable and ResourcePoliciesTable. No
catalog/translation changes, so nothing changes for Crowdin.
2026-07-01 07:04:54 +05:30
miloschwartz 9f68be2a9b add empty state 2026-06-30 21:18:46 -04:00
miloschwartz fed4ec42c4 add server side fetching 2026-06-30 21:15:03 -04:00
miloschwartz f0efa4203b basic functionality 2026-06-30 21:03:19 -04:00
Owen cfbbdedaf5 rework ui 2026-06-30 17:44:35 -04:00
Owen 686789ee4c Properly translate 2026-06-30 15:37:42 -04:00
Owen 3fda190ff6 Merge branch 'backhaul' into dev 2026-06-30 15:21:11 -04:00
Owen 0033f40f4d Fix typo preventing subscription cancelation 2026-06-30 15:06:35 -04:00
Owen af95052706 Update schema for tracking valid domains 2026-06-30 13:53:44 -04:00
Owen 9bb2d6cdc8 Prompt for the username on vnc 2026-06-30 12:16:58 -04:00
Owen 29563a13a4 Add indexes on the niceId and orgId 2026-06-30 09:49:53 -04:00
Owen b41c1f5b27 Add restart button 2026-06-29 21:10:49 -04:00
Owen e5652cdb8a Dont enable admin routes 2026-06-29 20:45:38 -04:00
Owen 7c2ea153c5 Use regional cache for rate limiting 2026-06-29 18:33:03 -04:00
Owen ccabddc225 Add logging for access for new public resources 2026-06-29 18:05:29 -04:00
Owen 42d98fa83b Comment back in the sync command 2026-06-29 16:34:10 -04:00
Owen 2f2b7f43c1 Add usage tracking to blueprints 2026-06-29 16:13:12 -04:00
Owen 528bbeca26 Implement usage tracking on resources, clients 2026-06-29 15:39:30 -04:00
Owen d60c15b0ae Fix typo 2026-06-29 15:24:16 -04:00
Owen ff89a64453 Rename to limit id 2026-06-29 15:22:35 -04:00
Owen 4718c489d3 Add concurrency guard calculateUserClientsForOrgs 2026-06-29 15:02:41 -04:00
Owen d5d99a4804 Add org rebuild rate limit 2026-06-29 14:59:05 -04:00
Fred KISSIE 8d29602929 🏷️ fix types 2026-06-29 18:06:03 +02:00
Owen 9c18936be7 Filter the nodes based on the preference labels 2026-06-29 11:40:25 -04:00
Owen cf07cceb5d Fix bad col in pg 2026-06-29 11:31:34 -04:00
Owen faee9e6330 Merge branch 'main' into dev 2026-06-29 11:29:12 -04:00
miloschwartz 31725eb3cc display resource type in info card 2026-06-29 10:45:38 -04:00
miloschwartz 04d4e298e8 fix spacing on endpoint field on site 2026-06-29 10:42:25 -04:00
Owen c9cc9581b1 Add batch update 2026-06-26 23:24:14 -04:00
Fred KISSIE 6c2a8bf6de 💄 Show the selected country in policy access rules country is not rule match 2026-06-27 02:12:09 +02:00
Fred KISSIE 697be01411 Merge branch 'dev' into feat/geoip-country-is-not-rule 2026-06-27 02:05:02 +02:00
Owen eac7c67dcc Send down remote subnets 2026-06-26 18:09:56 -04:00
Owen 633d9031af Add labels input 2026-06-26 18:02:20 -04:00
Owen 05dc558c4a Add basic resources input on the remote node 2026-06-26 18:01:24 -04:00
Fred KISSIE 1bd6f240cc ♻️ add Country is not rule to verifySession 2026-06-26 23:18:46 +02:00
miloschwartz 7506c0420d properly pass org policy error message in olm register 2026-06-26 17:11:32 -04:00
Owen Schwartz 5572822c4a Merge pull request #3351 from fosrl/copilot/fix-rest-ruleid-changing
fix: preserve rule IDs when saving policy rules via the GUI
2026-06-26 15:05:31 -04:00
Owen ea3f1c341b Move hashing outside of transaction 2026-06-26 14:40:39 -04:00
Owen 35dffe71cb Make error statement debug 2026-06-26 14:40:31 -04:00
copilot-swe-agent[bot] 5428bf4ed0 fix: preserve rule IDs when saving policy rules through the GUI
The `setResourcePolicyRules` endpoint was deleting all existing rules and
re-inserting them on every save, causing all ruleIDs to change.

Backend: Accept an optional `ruleId` per rule in the request body and
perform an upsert — update existing rules (matched by ruleId), insert
new ones (no ruleId), and delete only rules absent from the incoming list.

Frontend: Include `ruleId` in the rules payload for existing (non-new)
rules so the backend can match and preserve them.
2026-06-26 14:37:34 +00:00
copilot-swe-agent[bot] 9a89579e08 Initial plan 2026-06-26 14:33:35 +00:00
Owen Schwartz 784588cebc Merge pull request #3350 from fosrl/dev
Make sure the rebuild actually executes
2026-06-26 09:28:12 -04:00
Owen 2e628fe0e4 Make sure the rebuild actually executes 2026-06-26 09:26:43 -04:00
Owen Schwartz 7590e8d8a1 Merge pull request #3345 from fosrl/dev
Show utility subnet on org
2026-06-25 13:05:32 -07:00
Owen 053ff1e799 Add utility subnet 2026-06-25 15:39:04 -04:00
Fred KISSIE 278375f7be 🚧 More country is not rule 2026-06-25 21:26:13 +02:00
Owen Schwartz c5ffca499e Merge pull request #3330 from fosrl/dev
1.19.3
2026-06-25 11:54:25 -07:00
Fred KISSIE 65c383520b 💄 adjust match type column width 2026-06-25 20:49:55 +02:00
Owen Schwartz 9ae54f445d Merge pull request #3343 from fosrl/crowdin_dev
New Crowdin updates
2026-06-25 11:45:14 -07:00
Owen Schwartz 8183d19400 New translations en-us.json (Norwegian Bokmal)
[ci skip]
2026-06-25 11:44:44 -07:00
Owen Schwartz 7425daad3f New translations en-us.json (Chinese Simplified)
[ci skip]
2026-06-25 11:44:43 -07:00
Owen Schwartz 39d61a35eb New translations en-us.json (Turkish)
[ci skip]
2026-06-25 11:44:41 -07:00
Owen Schwartz f3fe11c136 New translations en-us.json (Russian)
[ci skip]
2026-06-25 11:44:39 -07:00
Owen Schwartz 66b1b385a3 New translations en-us.json (Portuguese)
[ci skip]
2026-06-25 11:44:37 -07:00
Owen Schwartz 822a07d48e New translations en-us.json (Polish)
[ci skip]
2026-06-25 11:44:35 -07:00
Owen Schwartz 3c13b1ea15 New translations en-us.json (Dutch)
[ci skip]
2026-06-25 11:44:33 -07:00
Owen Schwartz fee635b861 New translations en-us.json (Korean)
[ci skip]
2026-06-25 11:44:31 -07:00
Owen Schwartz 7e4dea918a New translations en-us.json (Italian)
[ci skip]
2026-06-25 11:44:29 -07:00
Owen Schwartz 56187d61d5 New translations en-us.json (German)
[ci skip]
2026-06-25 11:44:27 -07:00
Owen Schwartz 36460d4cc0 New translations en-us.json (Danish)
[ci skip]
2026-06-25 11:44:25 -07:00
Owen Schwartz 88a9b92dc3 New translations en-us.json (Czech)
[ci skip]
2026-06-25 11:44:23 -07:00
Owen Schwartz dd26518d6f New translations en-us.json (Bulgarian)
[ci skip]
2026-06-25 11:44:21 -07:00
Owen Schwartz 60339706bb New translations en-us.json (Spanish)
[ci skip]
2026-06-25 11:44:19 -07:00
Owen Schwartz 4b1b3d3d5b New translations en-us.json (French)
[ci skip]
2026-06-25 11:44:17 -07:00
Owen cf21bacd9c Merge branch 'main' into dev 2026-06-25 14:30:05 -04:00
Fred KISSIE e54bd25516 🚧 add country is not rule 2026-06-25 20:28:57 +02:00
Owen Schwartz 80d257b94b Merge pull request #3336 from mr1beast/main
New translations en-us.json (Danish)
2026-06-25 11:24:56 -07:00
Owen Schwartz e0d0c5dcbf Merge pull request #3331 from Fredkiss3/feat/geoip-tag-in-tables
feat: Show GeoIp country flags in site & rules page
2026-06-25 11:23:42 -07:00
Fred KISSIE 0f02d1bc02 ♻️ remove deprecated ISO CS country code 2026-06-25 18:01:25 +02:00
mr1beast a48032adb3 New translations en-us.json (Danish)
New translations en-us.json (Danish)
2026-06-24 21:25:57 +00:00
Fred KISSIE bb7729df00 💄 show geoip flag in policy access rule tab 2026-06-23 23:45:59 +02:00
Fred KISSIE e104489257 💄 Show GeoIp flag in site details page 2026-06-23 23:28:46 +02:00
Fred KISSIE 8f0e17774f 💄 Update command bar 2026-06-22 21:22:55 +02:00
Fred KISSIE 2ab5540085 ♻️ add command palette trigger on the header 2026-06-19 18:08:36 +02:00
Fred KISSIE 4e7328a1cc ♻️ refactor private resource page 2026-06-16 22:29:03 +02:00
Fred KISSIE 6380079239 Command palette with search & actions 2026-06-16 22:28:31 +02:00
Fred KISSIE b6aba13d3a ♻️ rename query, add query 2026-06-16 22:28:04 +02:00
Fred KISSIE c0a9db92ef 💄 update command bar UI 2026-06-16 19:28:22 +02:00
Fred KISSIE 3bc5ab2136 🚧 wip 2026-06-13 00:48:32 +02:00
Fred KISSIE ce77268c82 🚧 wip: block top position of command palette 2026-06-13 00:47:36 +02:00
Fred KISSIE abc0a41d9e ♻️ reorganize command bar items 2026-06-13 00:27:39 +02:00
Fred KISSIE a68b57067c 🚧 wip: Use command bar nav items 2026-06-12 23:51:05 +02:00
Fred KISSIE 444d293a29 🚧 WIP: copy command bar from existing PR 2026-06-11 23:46:11 +02:00
Aditya kumar singh 35d16ac683 fix: redirect lost after Pangolin auth session timeout (#3001) 2026-06-01 15:53:10 +05:30
371 changed files with 31501 additions and 7092 deletions
+5
View File
@@ -0,0 +1,5 @@
---
alwaysApply: true
---
Don't write or edit migrations in `server/setup` unless specificall instructed to do so.
+39 -3
View File
@@ -41,7 +41,7 @@
</strong> </strong>
</p> </p>
Pangolin is an open-source, identity-based remote access platform built on WireGuard® that enables secure, seamless connectivity to private and public resources. Pangolin combines reverse proxy and VPN capabilities into one platform, providing browser-based access to web applications and client-based access to any private resources with NAT traversal, all with granular access controls. Pangolin is an open-source, identity-based remote access platform built on WireGuard® that enables secure connectivity to infrastructure anywhere. It combines reverse-proxy and VPN capabilities into one platform, providing browser-based access to web applications and client-based access to private resources with NAT traversal, all with granular access control.
## Installation ## Installation
@@ -63,11 +63,26 @@ Pangolin is an open-source, identity-based remote access platform built on WireG
Pangolin's site connectors provide gateways into networks so you can access any networked resources. Sites use outbound tunnels and intelligent NAT traversal to make networks behind restrictive firewalls available for authorized access without public IPs or open ports. Easily deploy a site as a binary or container on any platform. Pangolin's site connectors provide gateways into networks so you can access any networked resources. Sites use outbound tunnels and intelligent NAT traversal to make networks behind restrictive firewalls available for authorized access without public IPs or open ports. Easily deploy a site as a binary or container on any platform.
* Lightweight user-space connector runs anywhere
* Punches through any firewall
* Doesn't require open ports or a public IP
* Strict network segmentation
* WireGuard-based
* Get alerts when a device or network resource goes down
<img src="public/screenshots/sites.png" alt="Sites" width="100%" /> <img src="public/screenshots/sites.png" alt="Sites" width="100%" />
### Browser-based reverse proxy access ### Browser-based reverse proxy access
Expose web applications through identity and context-aware tunneled reverse proxies. Users access applications through any web browser with authentication and granular access control without installing a client. Pangolin handles routing, load balancing, health checking, and automatic SSL certificates without exposing your network directly to the internet. Expose HTTPS web applications and connect to VNC, RDP, and SSH entirely in the browser through identity and context-aware tunneled reverse proxies. Users access resources with authentication and granular access control without installing a client. Pangolin handles routing, load balancing, health checking, and automatic SSL certificates without exposing your network directly to the internet.
* Expose a web panel anywhere
* Access via any web browser
* Single sign-on across all resources
* HTTPS resources
* Remote desktop in the browser with VNC and RDP
* In-browser SSH terminal with privileged access management (PAM)
* PIN codes, passcodes, email OTP, geoblocking, allow-lists, and more
<img src="public/clip.gif" alt="Reverse proxy access" width="100%" /> <img src="public/clip.gif" alt="Reverse proxy access" width="100%" />
@@ -75,14 +90,35 @@ Expose web applications through identity and context-aware tunneled reverse prox
Access private resources like SSH servers, databases, RDP, and entire network ranges through Pangolin clients. Intelligent NAT traversal enables connections even through restrictive firewalls, while DNS aliases provide friendly names and fast connections to resources across all your sites. Add redundancy by routing traffic through multiple connectors in your network. Access private resources like SSH servers, databases, RDP, and entire network ranges through Pangolin clients. Intelligent NAT traversal enables connections even through restrictive firewalls, while DNS aliases provide friendly names and fast connections to resources across all your sites. Add redundancy by routing traffic through multiple connectors in your network.
* Peer-to-peer with intelligent NAT traversal
* Hosts/IPs and port ranges
* Network ranges/CIDRs
* Friendly DNS aliases for network addresses
* Privileged access management (PAM) with SSH resources
* Private HTTPS resources only accessible on the private network
<img src="public/screenshots/private-resources.png" alt="Private resources" width="100%" /> <img src="public/screenshots/private-resources.png" alt="Private resources" width="100%" />
### Give users and roles access to resources ### Give users and roles access to resources
Use Pangolin's built in users or bring your own identity provider and set up role based access control (RBAC). Grant users access to specific resources, not entire networks. Unlike traditional VPNs that expose full network access, Pangolin's zero-trust model ensures users can only reach the applications, services, and routes you explicitly define. Use Pangolin's built-in users or bring your own identity provider and set up role-based access control (RBAC). Grant users access to specific resources, not entire networks. Unlike traditional VPNs that expose full network access, Pangolin's zero-trust model ensures users can only reach the applications, services, and routes you explicitly define.
* Bring your existing identity provider (IdP) or use Pangolin identities
* Sync users and roles from your IdP
* User- and role-based access control
* Full network audit and access logs
<img src="public/screenshots/users.png" alt="Users from identity provider with roles" width="100%" /> <img src="public/screenshots/users.png" alt="Users from identity provider with roles" width="100%" />
### Find and launch resources from a personalized home page
Give users a landing page to quickly find and open the resources they can access. Resources are grouped by site or label, searchable, and filterable, with grid or list views. Saved views capture filters, grouping, and layout as personal or organization-wide defaults.
* Single place for admins and non-admins to see accessible resources
* Create reusable views for common access patterns
<img src="public/screenshots/resource-launcher.png" alt="Resource Launcher" width="100%" />
## Download Clients ## Download Clients
Download the Pangolin client for your platform: Download the Pangolin client for your platform:
+1 -1
View File
@@ -76,7 +76,7 @@ var redisFlag *bool
func main() { func main() {
crowdsecFlag := flag.Bool("crowdsec", false, "Enable the CrowdSec installation prompt") crowdsecFlag := flag.Bool("crowdsec", false, "Enable the CrowdSec installation prompt")
redisFlag = flag.Bool("redis", false, "Install Redis as cacheing solution. Required for HA. Not required for the Enterprise version.") redisFlag = flag.Bool("redis", false, "Install Redis as caching solution. Required for HA. Not required for the Enterprise version.")
flag.Parse() flag.Parse()
// print a banner about prerequisites - opening port 80, 443, 51820, and 21820 on the VPS and firewall and pointing your domain to the VPS IP with a records. Docs are at http://localhost:3000/Getting%20Started/dns-networking // print a banner about prerequisites - opening port 80, 443, 51820, and 21820 on the VPS and firewall and pointing your domain to the VPS IP with a records. Docs are at http://localhost:3000/Getting%20Started/dns-networking
+249 -21
View File
@@ -66,9 +66,15 @@
"local": "Локална", "local": "Локална",
"edit": "Редактиране", "edit": "Редактиране",
"siteConfirmDelete": "Потвърждение на изтриване на сайта", "siteConfirmDelete": "Потвърждение на изтриване на сайта",
"siteConfirmDeleteAndResources": "Потвърдете изтриването на сайта и ресурсите",
"siteDelete": "Изтриване на сайта", "siteDelete": "Изтриване на сайта",
"siteDeleteAndResources": "Изтриване на сайта и ресурсите",
"siteMessageRemove": "След премахване, сайтът вече няма да бъде достъпен. Всички цели, свързани със сайта, също ще бъдат премахнати.", "siteMessageRemove": "След премахване, сайтът вече няма да бъде достъпен. Всички цели, свързани със сайта, също ще бъдат премахнати.",
"siteMessageRemoveAndResources": "Това ще изтрие окончателно всички публични и частни ресурси, свързани с този сайт, дори ако ресурсът е асоцииран и с други сайтове.",
"siteQuestionRemove": "Сигурни ли сте, че искате да премахнете сайта от организацията?", "siteQuestionRemove": "Сигурни ли сте, че искате да премахнете сайта от организацията?",
"siteQuestionRemoveAndResources": "Наистина ли желаете да изтриете този сайт и всички свързани ресурси?",
"sitesTableDeleteSite": "Изтриване на сайта",
"sitesTableDeleteSiteAndResources": "Изтриване на сайта и ресурсите",
"siteManageSites": "Управление на сайтове", "siteManageSites": "Управление на сайтове",
"siteDescription": "Създайте и управлявайте сайтове, за да осигурите свързаност със частни мрежи", "siteDescription": "Създайте и управлявайте сайтове, за да осигурите свързаност със частни мрежи",
"sitesBannerTitle": "Свържете се с мрежа.", "sitesBannerTitle": "Свържете се с мрежа.",
@@ -117,6 +123,16 @@
"siteUpdated": "Сайтът е обновен", "siteUpdated": "Сайтът е обновен",
"siteUpdatedDescription": "Сайтът е актуализиран.", "siteUpdatedDescription": "Сайтът е актуализиран.",
"siteGeneralDescription": "Конфигурирайте общи настройки за този сайт", "siteGeneralDescription": "Конфигурирайте общи настройки за този сайт",
"siteRestartTitle": "Рестартирайте Сайта",
"siteRestartDescription": "Рестартирайте WireGuard тунела за този сайт. Това ще прекъсне връзката за кратко.",
"siteRestartBody": "Използвайте това, ако тунелът на сайта не функционира правилно и искате да принудите повторно свързване без да рестартирате хоста.",
"siteRestartButton": "Рестартирайте Сайта",
"siteRestartDialogMessage": "Сигурни ли сте, че искате да рестартирате WireGuard тунела за <b>{name}</b>? Сайтът ще изгуби връзка за кратко.",
"siteRestartWarning": "Сайтът ще се изключи за кратко, докато тунелът се рестартира.",
"siteRestarted": "Сайтът е рестартиран",
"siteRestartedDescription": "WireGuard тунелът е рестартиран.",
"siteErrorRestart": "Неуспешно рестартиране на сайта",
"siteErrorRestartDescription": "Възникна грешка при рестартирането на сайта.",
"siteSettingDescription": "Конфигурирайте настройките на сайта", "siteSettingDescription": "Конфигурирайте настройките на сайта",
"siteResourcesTab": "Ресурси", "siteResourcesTab": "Ресурси",
"siteResourcesNoneOnSite": "Този сайт все още няма публични или частни ресурси.", "siteResourcesNoneOnSite": "Този сайт все още няма публични или частни ресурси.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Потвърдете изтриването на споделима връзка", "shareDeleteConfirm": "Потвърдете изтриването на споделима връзка",
"shareQuestionRemove": "Сигурни ли сте, че искате да изтриете тази споделена връзка?", "shareQuestionRemove": "Сигурни ли сте, че искате да изтриете тази споделена връзка?",
"shareMessageRemove": "След изтриване връзката вече няма да работи и всеки, който я използва, ще загуби достъп до ресурса.", "shareMessageRemove": "След изтриване връзката вече няма да работи и всеки, който я използва, ще загуби достъп до ресурса.",
"shareTokenDescription": "Достъпният токен може да бъде предаван по два начина: като параметър или в хедърите на заявките. Те трябва да бъдат предавани от клиента при всяка заявка за удостоверен достъп.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Достъп Токен", "accessToken": "Достъп Токен",
"usageExamples": "Примери за използване", "usageExamples": "Примери за използване",
"tokenId": "Токен ID", "tokenId": "Токен ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Заглавие (по избор)", "shareTitleOptional": "Заглавие (по избор)",
"sharePathOptional": "Път (по избор)", "sharePathOptional": "Път (по избор)",
"sharePathDescription": "След удостоверяване, линкът ще препрати потребителите на този път.", "sharePathDescription": "След удостоверяване, линкът ще препрати потребителите на този път.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Изтече", "expireIn": "Изтече",
"neverExpire": "Никога не изтича", "neverExpire": "Никога не изтича",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Времето на изтичане е колко дълго връзката ще бъде използваема и ще предоставя достъп до ресурса. След това време, връзката няма да работи и потребителите, които са я използвали, ще загубят достъп до ресурса.", "shareExpireDescription": "Времето на изтичане е колко дълго връзката ще бъде използваема и ще предоставя достъп до ресурса. След това време, връзката няма да работи и потребителите, които са я използвали, ще загубят достъп до ресурса.",
"shareSeeOnce": "Ще можете да видите този линк само веднъж. Уверете се, че го копирате.", "shareSeeOnce": "Ще можете да видите този линк само веднъж. Уверете се, че го копирате.",
"shareAccessHint": "Всеки с тази връзка може да има достъп до ресурса. Споделяйте я с внимание.", "shareAccessHint": "Всеки с тази връзка може да има достъп до ресурса. Споделяйте я с внимание.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Получавайте заявки чрез суров TCP/UDP с използване на портен номер. Изисква се сайтовете да се свързват към отдалечен възел.", "resourceRawDescriptionCloud": "Получавайте заявки чрез суров TCP/UDP с използване на портен номер. Изисква се сайтовете да се свързват към отдалечен възел.",
"resourceCreate": "Създайте ресурс", "resourceCreate": "Създайте ресурс",
"resourceCreateDescription": "Следвайте стъпките по-долу, за да създадете нов ресурс", "resourceCreateDescription": "Следвайте стъпките по-долу, за да създадете нов ресурс",
"resourcePublicCreate": "Създаване на публичен ресурс",
"resourcePublicCreateDescription": "Следвайте стъпките по-долу, за да създадете нов обществен ресурс, достъпен чрез уеб браузър",
"resourceCreateGeneralDescription": "Конфигуриране на основните настройки на ресурса, включително име и тип", "resourceCreateGeneralDescription": "Конфигуриране на основните настройки на ресурса, включително име и тип",
"resourceSeeAll": "Вижте всички ресурси", "resourceSeeAll": "Вижте всички ресурси",
"resourceCreateGeneral": "Основни параметри", "resourceCreateGeneral": "Основни параметри",
@@ -431,8 +455,14 @@
"provisioningManage": "Осигуряване", "provisioningManage": "Осигуряване",
"provisioningDescription": "Управление на ключовете за осигуряване и преглед на чаканещите сайтове за одобрение.", "provisioningDescription": "Управление на ключовете за осигуряване и преглед на чаканещите сайтове за одобрение.",
"pendingSites": "Чаканещи сайтове", "pendingSites": "Чаканещи сайтове",
"siteApproveSuccess": "Сайтът е одобрен успешно", "siteApproveSuccess": "Сайтът и свързаните ресурси са одобрени успешно",
"siteApproveError": "Грешка при одобряването на сайта", "siteApproveError": "Грешка при одобряването на сайта",
"siteReject": "Отказ на сайт",
"siteQuestionReject": "Сигурни ли сте, че искате да откажете този сайт?",
"siteMessageReject": "Това ще изтрие окончателно сайта и всички свързани ресурси, които все още са на изчакване.",
"siteConfirmReject": "Потвърдете отказ на сайт",
"siteRejectSuccess": "Сайтът беше успешно отхвърлен",
"siteRejectError": "Грешка при отхвърляне на сайта",
"provisioningKeys": "Ключове за осигуряване", "provisioningKeys": "Ключове за осигуряване",
"searchProvisioningKeys": "Търсене на ключове за осигуряване...", "searchProvisioningKeys": "Търсене на ключове за осигуряване...",
"provisioningKeysAdd": "Генериране на ключ за осигуряване", "provisioningKeysAdd": "Генериране на ключ за осигуряване",
@@ -448,8 +478,8 @@
"provisioningKeysSave": "Запазете ключа за осигуряване", "provisioningKeysSave": "Запазете ключа за осигуряване",
"provisioningKeysSaveDescription": "Ще можете да видите това само веднъж. Копирайте го на сигурно място.", "provisioningKeysSaveDescription": "Ще можете да видите това само веднъж. Копирайте го на сигурно място.",
"provisioningKeysErrorCreate": "Грешка при създаване на ключ за осигуряване", "provisioningKeysErrorCreate": "Грешка при създаване на ключ за осигуряване",
"provisioningKeysList": "Нов ключ за осигуряване", "provisioningKeysList": "Нов ключ за разпределяне",
"provisioningKeysMaxBatchSize": "Максимален размер на пакет", "provisioningKeysMaxBatchSize": "Максимален размер на пакета",
"provisioningKeysUnlimitedBatchSize": "Неограничен размер на партида (без лимит)", "provisioningKeysUnlimitedBatchSize": "Неограничен размер на партида (без лимит)",
"provisioningKeysMaxBatchUnlimited": "Неограничено", "provisioningKeysMaxBatchUnlimited": "Неограничено",
"provisioningKeysMaxBatchSizeInvalid": "Въведете валиден максимален размер на партида (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Въведете валиден максимален размер на партида (11,000,000).",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Никога", "provisioningKeysNeverUsed": "Никога",
"provisioningKeysEdit": "Редактиране на ключ за осигуряване", "provisioningKeysEdit": "Редактиране на ключ за осигуряване",
"provisioningKeysEditDescription": "Актуализирайте максималния размер на партида и времето на изтичане за този ключ.", "provisioningKeysEditDescription": "Актуализирайте максималния размер на партида и времето на изтичане за този ключ.",
"provisioningKeysApproveNewSites": "Одобрете нови сайтове", "provisioningKeysApproveNewSites": "Одобряване на нови сайтове",
"provisioningKeysApproveNewSitesDescription": "Автоматично одобряване на сайтове, които се регистрират с този ключ.", "provisioningKeysApproveNewSitesDescription": "Автоматично одобряване на сайтове, които се регистрират с този ключ.",
"provisioningKeysUpdateError": "Грешка при актуализирането на ключа за осигуряване", "provisioningKeysUpdateError": "Грешка при актуализирането на ключа за осигуряване",
"provisioningKeysUpdated": "Ключът за осигуряване е актуализиран", "provisioningKeysUpdated": "Ключът за осигуряване е актуализиран",
@@ -597,7 +627,8 @@
"idpNameInternal": "Вътрешен", "idpNameInternal": "Вътрешен",
"emailInvalid": "Невалиден имейл адрес", "emailInvalid": "Невалиден имейл адрес",
"inviteValidityDuration": "Моля, изберете продължителност", "inviteValidityDuration": "Моля, изберете продължителност",
"accessRoleSelectPlease": "Моля, изберете роля", "accessRoleSelectPlease": "Потребителят трябва да принадлежи към поне една роля.",
"accessRoleRequired": "Ролята е задължителна",
"removeOwnAdminRoleConfirmTitle": "Премахване на административния ви достъп?", "removeOwnAdminRoleConfirmTitle": "Премахване на административния ви достъп?",
"removeOwnAdminRoleConfirmDescription": "След записване няма да имате повече администраторски права в тази организация. Друг администратор може да възстанови достъпа, ако е необходимо.", "removeOwnAdminRoleConfirmDescription": "След записване няма да имате повече администраторски права в тази организация. Друг администратор може да възстанови достъпа, ако е необходимо.",
"removeOwnAdminRoleConfirmButton": "Премахнете административния ми достъп", "removeOwnAdminRoleConfirmButton": "Премахнете административния ми достъп",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Базово удостоверяване чрез заглавие", "policyAuthHeaderAuthTitle": "Базово удостоверяване чрез заглавие",
"policyAuthHeaderAuthDescription": "Валидирайте собствено HTTP заглавие и стойност при всяка заявка", "policyAuthHeaderAuthDescription": "Валидирайте собствено HTTP заглавие и стойност при всяка заявка",
"policyAuthHeaderAuthSummary": "Конфигурирано заглавие", "policyAuthHeaderAuthSummary": "Конфигурирано заглавие",
"policyAuthHeaderName": "Име на заглавието", "policyAuthHeaderName": "Потребителско име",
"policyAuthHeaderValue": "Очаквана стойност", "policyAuthHeaderValue": "Парола",
"policyAuthSetPasscode": "Задайте парола", "policyAuthSetPasscode": "Задайте парола",
"policyAuthSetPincode": "Задайте ПИН код", "policyAuthSetPincode": "Задайте ПИН код",
"policyAuthSetEmailWhitelist": "Задайте списък с имейли", "policyAuthSetEmailWhitelist": "Задайте списък с имейли",
@@ -903,7 +934,7 @@
"newtVersion": "Версия", "newtVersion": "Версия",
"architecture": "Архитектура", "architecture": "Архитектура",
"sites": "Сайтове", "sites": "Сайтове",
"siteWgAnyClients": "Използвайте клиент на WireGuard, за да се свържете. Ще трябва да използвате вътрешните ресурси чрез IP адреса на връстника.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Съвместим с всички WireGuard клиенти", "siteWgCompatibleAllClients": "Съвместим с всички WireGuard клиенти",
"siteWgManualConfigurationRequired": "Необходима е ръчна конфигурация", "siteWgManualConfigurationRequired": "Необходима е ръчна конфигурация",
"userErrorNotAdminOrOwner": "Потребителят не е администратор или собственик", "userErrorNotAdminOrOwner": "Потребителят не е администратор или собственик",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Създаване на Организационна Потребител", "createOrgUser": "Създаване на Организационна Потребител",
"actionUpdateOrg": "Актуализиране на организацията", "actionUpdateOrg": "Актуализиране на организацията",
"actionRemoveInvitation": "Премахване на поканата.", "actionRemoveInvitation": "Премахване на поканата.",
"actionRemoveUserRole": "Премахване на роля на потребител",
"actionUpdateUser": "Актуализиране на потребител", "actionUpdateUser": "Актуализиране на потребител",
"actionGetUser": "Получаване на потребител", "actionGetUser": "Получаване на потребител",
"actionGetOrgUser": "Вземете потребител на организация", "actionGetOrgUser": "Вземете потребител на организация",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Приложи Чернова", "actionApplyBlueprint": "Приложи Чернова",
"actionListBlueprints": "Списък с планове.", "actionListBlueprints": "Списък с планове.",
"actionGetBlueprint": "Вземи план.", "actionGetBlueprint": "Вземи план.",
"actionCreateOrgWideLauncherView": "Създайте Изглед на Стартирача за Цялата Организация",
"setupToken": "Конфигурация на токен", "setupToken": "Конфигурация на токен",
"setupTokenDescription": "Въведете конфигурационния токен от сървърната конзола.", "setupTokenDescription": "Въведете конфигурационния токен от сървърната конзола.",
"setupTokenRequired": "Необходим е конфигурационен токен", "setupTokenRequired": "Необходим е конфигурационен токен",
"actionUpdateSite": "Актуализиране на сайт", "actionUpdateSite": "Актуализиране на сайт",
"actionApproveSite": "Одобряване на сайт",
"actionRejectSite": "Отказ на сайт",
"actionResetSiteBandwidth": "Нулиране на честотната лента на организацията", "actionResetSiteBandwidth": "Нулиране на честотната лента на организацията",
"actionListSiteRoles": "Изброяване на позволените роли за сайта", "actionListSiteRoles": "Изброяване на позволените роли за сайта",
"actionCreateResource": "Създаване на ресурс", "actionCreateResource": "Създаване на ресурс",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Задайте ПИН код на ресурса", "actionSetResourcePincode": "Задайте ПИН код на ресурса",
"actionSetResourceEmailWhitelist": "Задайте списък на одобрените имейл адреси за ресурса", "actionSetResourceEmailWhitelist": "Задайте списък на одобрените имейл адреси за ресурса",
"actionGetResourceEmailWhitelist": "Вземете списък на одобрените имейл адреси за ресурса", "actionGetResourceEmailWhitelist": "Вземете списък на одобрените имейл адреси за ресурса",
"actionGetResourcePolicy": "Получете политика за ресурси",
"actionUpdateResourcePolicy": "Актуализирайте политика за ресурси",
"actionSetResourcePolicyUsers": "Задайте потребители на ресурсна политика",
"actionSetResourcePolicyRoles": "Задайте роли на ресурсна политика",
"actionSetResourcePolicyPassword": "Задайте парола на ресурсна политика",
"actionSetResourcePolicyPincode": "Задайте ПИН код на ресурсна политика",
"actionSetResourcePolicyHeaderAuth": "Задайте автентикация на ресурсна политика",
"actionSetResourcePolicyWhitelist": "Задайте бял списък на имейли за ресурси",
"actionSetResourcePolicyRules": "Задайте правила за ресурси",
"actionCreateTarget": "Създайте цел", "actionCreateTarget": "Създайте цел",
"actionDeleteTarget": "Изтрийте цел", "actionDeleteTarget": "Изтрийте цел",
"actionGetTarget": "Вземете цел", "actionGetTarget": "Вземете цел",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Генериране на токен за достъп", "actionGenerateAccessToken": "Генериране на токен за достъп",
"actionDeleteAccessToken": "Изтриване на токен за достъп", "actionDeleteAccessToken": "Изтриване на токен за достъп",
"actionListAccessTokens": "Изброяване на токени за достъп", "actionListAccessTokens": "Изброяване на токени за достъп",
"actionCreateResourceSessionToken": "Създаване на токен за сесия на ресурс",
"actionCreateResourceRule": "Създаване на правило за ресурс", "actionCreateResourceRule": "Създаване на правило за ресурс",
"actionDeleteResourceRule": "Изтрийте правило за ресурс", "actionDeleteResourceRule": "Изтрийте правило за ресурс",
"actionListResourceRules": "Изброяване на правила за ресурс", "actionListResourceRules": "Изброяване на правила за ресурс",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Списък с покани", "actionListInvitations": "Списък с покани",
"actionExportLogs": "Експортиране на дневници", "actionExportLogs": "Експортиране на дневници",
"actionViewLogs": "Преглед на дневници", "actionViewLogs": "Преглед на дневници",
"actionCreateSiteProvisioningKey": "Създаване на ключ за предоставяне на сайт",
"actionListSiteProvisioningKeys": "Списък на ключовете за предоставяне на сайт",
"actionUpdateSiteProvisioningKey": "Актуализиране на ключ за предоставяне на сайт",
"actionDeleteSiteProvisioningKey": "Изтриване на ключ за предоставяне на сайт",
"noneSelected": "Нищо не е избрано", "noneSelected": "Нищо не е избрано",
"orgNotFound2": "Няма намерени организации.", "orgNotFound2": "Няма намерени организации.",
"search": "Търси…", "search": "Търси…",
@@ -1486,10 +1535,35 @@
"otpAuthDescription": "Въведете кода от приложението за удостоверяване или един от вашите резервни кодове за еднократна употреба.", "otpAuthDescription": "Въведете кода от приложението за удостоверяване или един от вашите резервни кодове за еднократна употреба.",
"otpAuthSubmit": "Изпрати код", "otpAuthSubmit": "Изпрати код",
"idpContinue": "Или продължете със", "idpContinue": "Или продължете със",
"idpLastUsed": "Последно използвано",
"otpAuthBack": "Назад към парола", "otpAuthBack": "Назад към парола",
"navbar": "Навигационно меню", "navbar": "Навигационно меню",
"navbarDescription": "Главно навигационно меню за приложението", "navbarDescription": "Главно навигационно меню за приложението",
"navbarDocsLink": "Документация", "navbarDocsLink": "Документация",
"commandPaletteTitle": "Командна палитра",
"commandPaletteDescription": "Търсене на страници, организации, ресурси и действия",
"commandPaletteSearchPlaceholder": "Търсете страници, ресурси, действия...",
"commandPaletteNoResults": "Няма намерени резултати.",
"commandPaletteSearching": "Търсене...",
"commandPaletteNavigation": "Навигация",
"commandPaletteOrganizations": "Организации",
"commandPaletteSites": "Сайтове",
"commandPaletteResources": "Ресурси",
"commandPaletteUsers": "Потребители",
"commandPaletteClients": "Машинни клиенти",
"commandPaletteActions": "Действия",
"commandPaletteCreateSite": "Създаване на сайт",
"commandPaletteCreateProxyResource": "Създаване на обществен ресурс",
"commandPaletteCreatePrivateResource": "Създаване на частен ресурс",
"commandPaletteCreateUser": "Създаване на потребител",
"commandPaletteCreateApiKey": "Създаване на API ключ",
"commandPaletteCreateMachineClient": "Създаване на машинен клиент",
"commandPaletteCreateAlertRule": "Създаване на правила за известия",
"commandPaletteCreateIdentityProvider": "Създаване на доставчик на идентичност",
"commandPaletteToggleTheme": "Смяна на темата",
"commandPaletteChooseOrganization": "Изберете организация",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Не може да се активира 2FA", "otpErrorEnable": "Не може да се активира 2FA",
"otpErrorEnableDescription": "Възникна грешка при активиране на 2FA", "otpErrorEnableDescription": "Възникна грешка при активиране на 2FA",
"otpSetupCheckCode": "Моля, въведете 6-цифрен код", "otpSetupCheckCode": "Моля, въведете 6-цифрен код",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Управление", "sidebarManagement": "Управление",
"sidebarBillingAndLicenses": "Фактуриране & Лицензи", "sidebarBillingAndLicenses": "Фактуриране & Лицензи",
"sidebarLogsAnalytics": "Анализи", "sidebarLogsAnalytics": "Анализи",
"commandSites": "Сайтове",
"commandActionModeInfo": "Напишете \">\" за да отворите режим на действия",
"commandResources": "Ресурси",
"commandProxyResources": "Обществени ресурси",
"commandClientResources": "Частни ресурси",
"commandClients": "Клиенти",
"commandUserDevices": "Потребителски устройства",
"commandMachineClients": "Машинни клиенти",
"commandDomains": "Домейни",
"commandRemoteExitNodes": "Отдалечени възли",
"commandTeam": "Екип",
"commandUsers": "Потребители",
"commandRoles": "Роли",
"commandInvitations": "Покани",
"commandPolicies": "Споделени политики",
"commandResourcePolicies": "Политики за обществени ресурси",
"commandIdentityProviders": "Доставчици на идентичност",
"commandApprovals": "Заявки за потвърждение",
"commandShareableLinks": "Споделени връзки",
"commandOrganization": "Организация",
"commandLogsAndAnalytics": "Логове и Анализи",
"commandLogsAnalytics": "Анализи",
"commandLogsRequest": "HTTP заявки за логове",
"commandLogsAccess": "Логове за достъп",
"commandLogsAction": "Логове на администратори",
"commandLogsConnection": "Логове на връзките",
"commandLogsStreaming": "Течения на събития",
"commandManagement": "Управление",
"commandAlerting": "Предупреждение",
"commandProvisioning": "Осигуряване",
"commandBluePrints": "Планове",
"commandApiKeys": "API ключове",
"commandBillingAndLicenses": "Фактуриране и лицензи",
"commandBilling": "Фактуриране",
"commandEnterpriseLicenses": "Лицензи",
"commandSettings": "Настройки",
"commandLauncher": "Стартиращо устройство",
"commandResourceLauncher": "Стартер на ресурси",
"commandSearchResults": "Резултати от търсенето",
"alertingTitle": "Извеждане на предупреждения", "alertingTitle": "Извеждане на предупреждения",
"alertingDescription": "Определете източници, тригери и действия за уведомления", "alertingDescription": "Определете източници, тригери и действия за уведомления",
"alertingRules": "Правила за предупреждение", "alertingRules": "Правила за предупреждение",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Поддомейн: {subdomain}", "domainPickerSubdomain": "Поддомейн: {subdomain}",
"domainPickerNamespace": "Име на пространство: {namespace}", "domainPickerNamespace": "Име на пространство: {namespace}",
"domainPickerShowMore": "Покажи повече", "domainPickerShowMore": "Покажи повече",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Избор на регион", "regionSelectorTitle": "Избор на регион",
"domainPickerRemoteExitNodeWarning": "Предоставените домейни не се поддържат, когато сайтовете се свързват към отдалечени крайни възли. За да бъдат ресурсите налични на отдалечени възли, използвайте персонализиран домейн вместо това.", "domainPickerRemoteExitNodeWarning": "Предоставените домейни не се поддържат, когато сайтовете се свързват към отдалечени крайни възли. За да бъдат ресурсите налични на отдалечени възли, използвайте персонализиран домейн вместо това.",
"regionSelectorInfo": "Изборът на регион ни помага да предоставим по-добра производителност за вашето местоположение. Не е необходимо да сте в същия регион като сървъра.", "regionSelectorInfo": "Изборът на регион ни помага да предоставим по-добра производителност за вашето местоположение. Не е необходимо да сте в същия регион като сървъра.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Домейни", "billingDomains": "Домейни",
"billingOrganizations": "Организации", "billingOrganizations": "Организации",
"billingRemoteExitNodes": "Дистанционни възли", "billingRemoteExitNodes": "Дистанционни възли",
"billingPublicResources": "Обществени ресурси",
"billingPrivateResources": "Частни ресурси",
"billingMachineClients": "Машинни клиенти",
"billingNoLimitConfigured": "Няма конфигуриран лимит", "billingNoLimitConfigured": "Няма конфигуриран лимит",
"billingEstimatedPeriod": "Очакван период на фактуриране", "billingEstimatedPeriod": "Очакван период на фактуриране",
"billingIncludedUsage": "Включено използване", "billingIncludedUsage": "Включено използване",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Колко потребители можете да използвате", "billingUsersInfo": "Колко потребители можете да използвате",
"billingDomainInfo": "Колко домейни можете да използвате", "billingDomainInfo": "Колко домейни можете да използвате",
"billingRemoteExitNodesInfo": "Колко дистанционни възли можете да използвате", "billingRemoteExitNodesInfo": "Колко дистанционни възли можете да използвате",
"billingPublicResourcesInfo": "Колко публични ресурси можете да използвате",
"billingPrivateResourcesInfo": "Колко частни ресурси можете да използвате",
"billingMachineClientsInfo": "Колко машинни клиенти можете да използвате",
"billingLicenseKeys": "Лицензионни ключове", "billingLicenseKeys": "Лицензионни ключове",
"billingLicenseKeysDescription": "Управлявайте вашите абонаменти за лицензионни ключове", "billingLicenseKeysDescription": "Управлявайте вашите абонаменти за лицензионни ключове",
"billingLicenseSubscription": "Абонамент за лиценз", "billingLicenseSubscription": "Абонамент за лиценз",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Мрежа", "subnetPlaceholder": "Мрежа",
"addressDescription": "Вътрешният адрес на клиента. Трябва да пада в подмрежата на организацията.", "addressDescription": "Вътрешният адрес на клиента. Трябва да пада в подмрежата на организацията.",
"selectSites": "Избор на сайтове", "selectSites": "Избор на сайтове",
"selectLabels": "Изберете етикети",
"sitesDescription": "Клиентът ще има връзка с избраните сайтове", "sitesDescription": "Клиентът ще има връзка с избраните сайтове",
"clientInstallOlm": "Инсталиране на Olm", "clientInstallOlm": "Инсталиране на Olm",
"clientInstallOlmDescription": "Конфигурирайте Olm да работи на вашата система", "clientInstallOlmDescription": "Конфигурирайте Olm да работи на вашата система",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Публичен", "resourcesTableProxyResources": "Публичен",
"resourcesTableClientResources": "Частен", "resourcesTableClientResources": "Частен",
"resourcesTableNoProxyResourcesFound": "Не са намерени ресурсни проксита.", "resourcesTableNoProxyResourcesFound": "Не са намерени ресурсни проксита.",
"resourcesTableNoInternalResourcesFound": "Не са намерени вътрешни ресурси.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Дестинация", "resourcesTableDestination": "Дестинация",
"resourcesTableAlias": "Псевдоним", "resourcesTableAlias": "Псевдоним",
"resourcesTableAliasAddress": "Адрес на псевдоним.", "resourcesTableAliasAddress": "Адрес на псевдоним.",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Отмяна", "editInternalResourceDialogCancel": "Отмяна",
"editInternalResourceDialogSaveResource": "Запазване на ресурс", "editInternalResourceDialogSaveResource": "Запазване на ресурс",
"editInternalResourceDialogSuccess": "Успех", "editInternalResourceDialogSuccess": "Успех",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Вътрешният ресурс успешно актуализиран", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Грешка", "editInternalResourceDialogError": "Грешка",
"editInternalResourceDialogFailedToUpdateInternalResource": "Неуспешно актуализиране на вътрешен ресурс", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Името е задължително", "editInternalResourceDialogNameRequired": "Името е задължително",
"editInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа", "editInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
"editInternalResourceDialogProxyPortMin": "Прокси портът трябва да бъде поне 1", "editInternalResourceDialogProxyPortMin": "Прокси портът трябва да бъде поне 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Псевдоним", "editInternalResourceDialogAlias": "Псевдоним",
"editInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.", "editInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.",
"createInternalResourceDialogNoSitesAvailable": "Няма достъпни сайтове", "createInternalResourceDialogNoSitesAvailable": "Няма достъпни сайтове",
"createInternalResourceDialogNoSitesAvailableDescription": "Трябва да имате поне един сайт на Newt с конфигурирана мрежа, за да създадете вътрешни ресурси.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Затвори", "createInternalResourceDialogClose": "Затвори",
"createInternalResourceDialogCreateClientResource": "Създаване на частен ресурс", "createInternalResourceDialogCreateClientResource": "Създаване на частен ресурс",
"createInternalResourceDialogCreateClientResourceDescription": "Създайте нов ресурс, който ще бъде достъпен само за клиенти, свързани към организацията", "createInternalResourceDialogCreateClientResourceDescription": "Създайте нов ресурс, който ще бъде достъпен само за клиенти, свързани към организацията",
"privateResourceGeneralDescription": "Конфигурирайте името, идентификатора и другите общи настройки на ресурса.",
"privateResourceCreatePageSeeAll": "Вижте всички частни ресурси",
"privateResourceAllowIcmpPing": "Разрешете ICMP Ping",
"privateResourceNetworkAccess": "Достъп до мрежата",
"privateResourceNetworkAccessDescription": "Контролирайте достъпа до TCP/UDP портовете и дали ICMP пинг е разрешен за този ресурс.",
"hostSettings": "Настройки на хоста",
"cidrSettings": "Настройки на CIDR",
"createInternalResourceDialogResourceProperties": "Свойства на ресурса", "createInternalResourceDialogResourceProperties": "Свойства на ресурса",
"createInternalResourceDialogName": "Име", "createInternalResourceDialogName": "Име",
"createInternalResourceDialogSite": "Сайт", "createInternalResourceDialogSite": "Сайт",
"selectSite": "Изберете сайт...", "selectSite": "Изберете сайт...",
"multiSitesSelectorSitesCount": "{count, plural, one {# сайт} other {# сайтове}}", "multiSitesSelectorSitesCount": "{count, plural, one {# сайт} other {# сайтове}}",
"labelsSelectorLabelsCount": "{count, plural, one {# етикет} other {# етикета}}",
"noSitesFound": "Не са намерени сайтове.", "noSitesFound": "Не са намерени сайтове.",
"createInternalResourceDialogProtocol": "Протокол", "createInternalResourceDialogProtocol": "Протокол",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Отмяна", "createInternalResourceDialogCancel": "Отмяна",
"createInternalResourceDialogCreateResource": "Създаване на ресурс", "createInternalResourceDialogCreateResource": "Създаване на ресурс",
"createInternalResourceDialogSuccess": "Успех", "createInternalResourceDialogSuccess": "Успех",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Вътрешният ресурс създаден успешно", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Грешка", "createInternalResourceDialogError": "Грешка",
"createInternalResourceDialogFailedToCreateInternalResource": "Неуспешно създаване на вътрешен ресурс", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Името е задължително", "createInternalResourceDialogNameRequired": "Името е задължително",
"createInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа", "createInternalResourceDialogNameMaxLength": "Името трябва да е по-малко от 255 символа",
"createInternalResourceDialogPleaseSelectSite": "Моля, изберете сайт", "createInternalResourceDialogPleaseSelectSite": "Моля, изберете сайт",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "CIDR диапазонът на ресурса в мрежата на сайта.", "createInternalResourceDialogDestinationCidrDescription": "CIDR диапазонът на ресурса в мрежата на сайта.",
"createInternalResourceDialogAlias": "Псевдоним", "createInternalResourceDialogAlias": "Псевдоним",
"createInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.", "createInternalResourceDialogAliasDescription": "По избор вътрешен DNS псевдоним за този ресурс.",
"internalResourceAliasLocalWarning": "Синоними с окончание .local могат да причинят проблеми с резолюцията поради mDNS в някои мрежи.",
"internalResourceDownstreamSchemeRequired": "Методът е задължителен за HTTP ресурси", "internalResourceDownstreamSchemeRequired": "Методът е задължителен за HTTP ресурси",
"internalResourceHttpPortRequired": "Портът към целта е задължителен за HTTP ресурси", "internalResourceHttpPortRequired": "Портът към целта е задължителен за HTTP ресурси",
"siteConfiguration": "Конфигурация", "siteConfiguration": "Конфигурация",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Отдалечени възли", "sidebarRemoteExitNodes": "Отдалечени възли",
"remoteExitNodeId": "ID.", "remoteExitNodeId": "ID.",
"remoteExitNodeSecretKey": "Секретен ключ.", "remoteExitNodeSecretKey": "Секретен ключ.",
"remoteExitNodeNetworkingTitle": "Настройки на Мрежата",
"remoteExitNodeNetworkingDescription": "Настройте как този отдалечен край маршрутизира трафика и кои сайтове предпочитат да се свържат чрез него. Усъвършенствани функции за използване при конфигурации на бекаул мрежи.",
"remoteExitNodeNetworkingSave": "Запазване на Настройките",
"remoteExitNodeNetworkingSaveSuccessTitle": "Настройките на мрежата са успешно запазени",
"remoteExitNodeNetworkingSaveSuccessDescription": "Настройките на мрежата бяха успешно обновени.",
"remoteExitNodeNetworkingSaveError": "Неуспешно запазване на мрежовите настройки",
"remoteExitNodeNetworkingSubnetsTitle": "Отдалечени Подмрежи",
"remoteExitNodeNetworkingSubnetsDescription": "Определете CIDR диапазоните, които този отдалечен край ще маршрутизира трафика към. Въведете валиден CIDR (e.g. <code>10.0.0.0/8</code>) и натиснете Enter, за да добавите.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Добавете CIDR диапазон (напр. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Неуспешно зареждане на подмрежи",
"remoteExitNodeNetworkingLabelsTitle": "Етикети за Предпочитания",
"remoteExitNodeNetworkingLabelsDescription": "Сайтове с тези етикети ще бъдат принудени да се свържат чрез този отдалечен край.",
"remoteExitNodeNetworkingLabelsButtonText": "Изберете етикети...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Търсене на етикети...",
"remoteExitNodeNetworkingLabelsLoadError": "Неуспешно зареждане на етикети",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Създаване на отдалечен възел.", "title": "Създаване на отдалечен възел.",
"description": "Създайте нов самохостнал отдалечен ретранслатор и прокси сървърен възел.", "description": "Създайте нов самохостнал отдалечен ретранслатор и прокси сървърен възел.",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Няма налични възли за тази организация. Първо създайте възел, за да използвате местни сайтове.", "noRemoteExitNodesAvailableDescription": "Няма налични възли за тази организация. Първо създайте възел, за да използвате местни сайтове.",
"exitNode": "Изходен възел", "exitNode": "Изходен възел",
"country": "Държава", "country": "Държава",
"countryIsNot": "Държавата не е",
"rulesMatchCountry": "Понастоящем на базата на изходния IP", "rulesMatchCountry": "Понастоящем на базата на изходния IP",
"region": "Регион", "region": "Регион",
"selectRegion": "Изберете регион", "selectRegion": "Изберете регион",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC доставчик", "idpGoogleDescription": "Google OAuth2/OIDC доставчик",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC доставчик", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC доставчик",
"subnet": "Подмрежа", "subnet": "Подмрежа",
"utilitySubnet": "Мрежа на Помощни Подмрежи",
"subnetDescription": "Подмрежата за конфигурацията на мрежата на тази организация.", "subnetDescription": "Подмрежата за конфигурацията на мрежата на тази организация.",
"customDomain": "Персонализиран домейн.", "customDomain": "Персонализиран домейн.",
"authPage": "Страници за автентификация.", "authPage": "Страници за автентификация.",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Необходима е настройка на двуфакторно удостоверяване. Моля, влезте отново чрез {dashboardUrl}/auth/login, за да завършите тази стъпка. След това, върнете се тук.", "twoFactorSetupRequired": "Необходима е настройка на двуфакторно удостоверяване. Моля, влезте отново чрез {dashboardUrl}/auth/login, за да завършите тази стъпка. След това, върнете се тук.",
"additionalSecurityRequired": "Необходима е допълнителна сигурност", "additionalSecurityRequired": "Необходима е допълнителна сигурност",
"organizationRequiresAdditionalSteps": "Тази организация изисква допълнителни стъпки за сигурност, за да получите достъп до ресурсите.", "organizationRequiresAdditionalSteps": "Тази организация изисква допълнителни стъпки за сигурност, за да получите достъп до ресурсите.",
"sessionExpired": "Сесията е изтекла",
"sessionExpiredReauthRequired": "Вашата сесия изтече според политиката за сигурност на вашата организация. Моля, повторете автентификацията, за да продължите.",
"reauthenticate": "Повторно автентифициране",
"completeTheseSteps": "Завършете тези стъпки", "completeTheseSteps": "Завършете тези стъпки",
"enableTwoFactorAuthentication": "Активирайте двуфакторното удостоверяване", "enableTwoFactorAuthentication": "Активирайте двуфакторното удостоверяване",
"completeSecuritySteps": "Завършете стъпките за сигурност", "completeSecuritySteps": "Завършете стъпките за сигурност",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Източен адрес", "sourceAddress": "Източен адрес",
"destinationAddress": "Адрес на дестинация", "destinationAddress": "Адрес на дестинация",
"duration": "Продължителност", "duration": "Продължителност",
"licenseRequiredToUse": "Изисква се лиценз за <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> за използване на тази функция. <bookADemoLink>Резервирайте демонстрация или пробен POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> е необходим за използване на тази функция. Тази функция също е налична в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Резервирайте демонстрация или пробен POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Решавач на сертификати", "certResolver": "Решавач на сертификати",
"certResolverDescription": "Изберете решавач на сертификати за използване за този ресурс.", "certResolverDescription": "Изберете решавач на сертификати за използване за този ресурс.",
"selectCertResolver": "Изберете решавач на сертификати", "selectCertResolver": "Изберете решавач на сертификати",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Липсва идентификатор на организация или домейн", "orgOrDomainIdMissing": "Липсва идентификатор на организация или домейн",
"loadingDNSRecords": "Зареждане на DNS записи...", "loadingDNSRecords": "Зареждане на DNS записи...",
"olmUpdateAvailableInfo": "Налична е актуализирана версия на Olm. Моля, актуализирайте до най-новата версия за най-добро преживяване.", "olmUpdateAvailableInfo": "Налична е актуализирана версия на Olm. Моля, актуализирайте до най-новата версия за най-добро преживяване.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "На разположение е обновена версия. Моля, обновете до най-новата версия за най-добър опит.",
"client": "Клиент", "client": "Клиент",
"proxyProtocol": "Настройки на прокси протокол", "proxyProtocol": "Настройки на прокси протокол",
"proxyProtocolDescription": "Конфигурирайте Proxy Protocol, за да запазите IP адресите на клиентите за TCP услуги.", "proxyProtocolDescription": "Конфигурирайте Proxy Protocol, за да запазите IP адресите на клиентите за TCP услуги.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Добавяне на потребители.", "editInternalResourceDialogAddUsers": "Добавяне на потребители.",
"editInternalResourceDialogAddClients": "Добавяне на клиенти.", "editInternalResourceDialogAddClients": "Добавяне на клиенти.",
"editInternalResourceDialogDestinationLabel": "Дестинация.", "editInternalResourceDialogDestinationLabel": "Дестинация.",
"editInternalResourceDialogDestinationDescription": "Посочете адреса дестинация за вътрешния ресурс. Това може да бъде име на хост, IP адрес или CIDR обхват в зависимост от избрания режим. По избор настройте вътрешен DNS алиас за по-лесно идентифициране.", "editInternalResourceDialogDestinationDescription": "Конфигурирайте как клиентите да достигнат до този ресурс.",
"internalResourceFormMultiSiteRoutingHelp": "Избирайки няколко сайта, се осигурява сигурен път и пренасочване при висока достъпност.", "internalResourceFormMultiSiteRoutingHelp": "Избирайки няколко сайта, се осигурява сигурен път и пренасочване при висока достъпност.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Научете повече", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Научете повече",
"editInternalResourceDialogPortRestrictionsDescription": "Ограничете достъпа до конкретни TCP/UDP портове или позволете/блокирайте всички портове.", "editInternalResourceDialogPortRestrictionsDescription": "Ограничете достъпа до конкретни TCP/UDP портове или позволете/блокирайте всички портове.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Бял списък на имейли", "memberPortalEmailWhitelist": "Бял списък на имейли",
"memberPortalResourceDisabled": "Ресурсът е деактивиран", "memberPortalResourceDisabled": "Ресурсът е деактивиран",
"memberPortalShowingResources": "Показва {start}-{end} от {total} ресурси", "memberPortalShowingResources": "Показва {start}-{end} от {total} ресурси",
"resourceLauncherTitle": "Стартер за Ресурси",
"resourceSidebarLauncherTitle": "Стартирано устройство",
"resourceLauncherDescription": "Вижте всички налични ресурси и ги стартирайте от един централен център",
"resourceLauncherSearchPlaceholder": "Търсете вашите ресурси...",
"resourceLauncherDefaultView": "По Подразбиране",
"resourceLauncherSaveView": "Запазете Изгледа",
"resourceLauncherSaveToCurrentView": "Запазете в Текущ Изглед",
"resourceLauncherSaveDefaultPersonal": "Запази за мен",
"resourceLauncherResetView": "Нулирайте Изгледа",
"resourceLauncherResetSystemDefault": "Възстанови към системните настройки",
"resourceLauncherSystemDefaultRestored": "Системните настройки са възстановени",
"resourceLauncherSystemDefaultRestoredDescription": "По подразбиране изгледът е възстановен към оригиналните настройки.",
"resourceLauncherSaveAsNewView": "Запазете като Нов Изглед",
"resourceLauncherSaveAsNewViewDescription": "Дайте име на този изглед, за да запазите текущите си филтри и оформление.",
"resourceLauncherSaveForEveryone": "Запазете за Всеки",
"resourceLauncherSaveForEveryoneDescription": "Споделете този изглед с всички членове на организацията. Когато е изключено, изгледът е видим само за вас.",
"resourceLauncherMakePersonal": "Направи Личен",
"resourceLauncherFilter": "Филтър",
"resourceLauncherFilterWithCount": "Филтър, {count} приложени",
"resourceLauncherSort": "Сортиране",
"resourceLauncherSortAscending": "Сортиране възходящо",
"resourceLauncherSortDescending": "Сортиране низходящо",
"resourceLauncherSettings": "Настройки",
"resourceLauncherGroupBy": "Групирай По",
"resourceLauncherGroupBySite": "Сайт",
"resourceLauncherGroupByLabel": "Етикет",
"resourceLauncherGroupByNone": "Няма",
"resourceLauncherLayout": "Оформление",
"resourceLauncherLayoutGrid": "Мрежа",
"resourceLauncherLayoutList": "Списък",
"resourceLauncherShowLabels": "Показване на Етикети",
"resourceLauncherShowSiteTags": "Показване на Тагове на Сайт",
"resourceLauncherShowRecents": "Показване на Последни",
"resourceLauncherDeleteView": "Изтриване на Изглед",
"resourceLauncherDeleteViewTitle": "Изтриване на изглед",
"resourceLauncherDeleteViewQuestion": "Сигурни ли сте, че искате да изтриете този изглед на стартиращото устройство?",
"resourceLauncherDeleteViewConfirm": "Изтриване на изглед",
"resourceLauncherViewAsAdmin": "Вижте като Админ",
"resourceLauncherResourceDetailsDescription": "Информация и статус на връзката за този ресурс.",
"resourceLauncherResourceDetails": "Детайли за ресурса",
"resourceLauncherAuthMethodsDescription": "Методи на автентикация, активирани за този ресурс.",
"resourceLauncherPrivateClientRequired": "Свържете се с клиент на вашето устройство, за да получите частен достъп до този ресурс.",
"resourceLauncherPrivateClientRequiredTitle": "Изисква се връзка с клиента",
"resourceLauncherDownloadClient": "Изтеглете клиент",
"resourceLauncherFailedToLoadDetails": "Не може да се зареди информацията за ресурса. Може вече да нямате достъп до този ресурс.",
"resourceLauncherNoPortRestrictions": "Няма ограничения за порт",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Без Етикет",
"resourceLauncherNoSite": "Няма Сайт",
"resourceLauncherNoResourcesInGroup": "Няма ресурси в тази група",
"resourceLauncherEmptyStateTitle": "Няма Налични Ресурси",
"resourceLauncherEmptyStateDescription": "Все още нямате достъп до никакви ресурси. Свържете се с вашия администратор, за да поискате достъп.",
"resourceLauncherEmptyStateNoResultsTitle": "Няма Намерени Ресурси",
"resourceLauncherEmptyStateNoResultsDescription": "Никакви ресурси не съвпадат с текущото ви търсене или филтри. Опитайте да ги коригирате, за да намерите това, което търсите.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Никакви ресурси не съвпадат с \"{query}\". Опитайте да коригирате търсенето или да изтриете филтри, за да видите всички ресурси.",
"resourceLauncherSearchFirstTitle": "Търсете или филтрирайте за да разгледате",
"resourceLauncherSearchFirstDescription": "Имате достъп до много ресурси. Използвайте търсене или филтър по сайт или етикет, за да намерите това, от което се нуждаете.",
"resourceLauncherSiteGroupingDisabled": "Групирането по сайт не е налично при този мащаб. Филтрирайте по сайт, за да групирате по-малък набор.",
"resourceLauncherLabelGroupingDisabled": "Групирането по етикет не е налично при този мащаб.",
"resourceLauncherCompactModeHint": "Показване на опростен списък за по-бързо разглеждане. Използвайте търсене или филтри за да стесните резултатите.",
"resourceLauncherCompactGroupingHint": "Прилагайте филтри за сайт или етикет, за да активирате групирането.",
"resourceLauncherCopiedToClipboard": "Копирано в клипборда",
"resourceLauncherCopiedAccessDescription": "Достъпът до ресурса е копиран на вашия клипборд.",
"resourceLauncherViewNamePlaceholder": "Име на Изгледа",
"resourceLauncherViewNameLabel": "Име на Изгледа",
"resourceLauncherViewSaved": "Изгледът е запазен",
"resourceLauncherViewSavedDescription": "Вашият изглед на стартер е запазен.",
"resourceLauncherViewSaveFailed": "Неуспешно запазване на изгледа",
"resourceLauncherViewSaveFailedDescription": "Не можеше да се запази изгледът на стартер. Моля, опитайте отново.",
"resourceLauncherViewDeleted": "Изгледът е изтрит",
"resourceLauncherViewDeletedDescription": "Изгледът на стартер е изтрит.",
"resourceLauncherViewDeleteFailed": "Неуспешно изтриване на изгледа",
"resourceLauncherViewDeleteFailedDescription": "Не можахте да изтриете изгледа на стартер. Моля, опитайте отново.",
"memberPortalPrevious": "Предишен", "memberPortalPrevious": "Предишен",
"memberPortalNext": "Следващ", "memberPortalNext": "Следващ",
"httpSettings": "HTTP настройки", "httpSettings": "HTTP настройки",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----НАЧАЛО НА OPENSSH ЧАСТЕН КЛЮЧ-----", "sshPrivateKeyPlaceholder": "-----НАЧАЛО НА OPENSSH ЧАСТЕН КЛЮЧ-----",
"sshPrivateKeyRequired": "Изисква се частен ключ", "sshPrivateKeyRequired": "Изисква се частен ключ",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Въведете вашата VNC парола за свързване", "vncSignInDescription": "Въведете VNC данните си за връзка",
"vncUsernameOptional": "Потребителско име (по избор)",
"vncPasswordOptional": "Парола (по избор)", "vncPasswordOptional": "Парола (по избор)",
"vncNoResourceTarget": "Не е налична цел за ресурса", "vncNoResourceTarget": "Не е налична цел за ресурса",
"vncFailedToLoadNovnc": "Неуспешно зареждане на noVNC", "vncFailedToLoadNovnc": "Неуспешно зареждане на noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Качването неуспешно", "rdpUploadFailed": "Качването неуспешно",
"rdpUnicodeKeyboardMode": "Режим на unicode клавиатура", "rdpUnicodeKeyboardMode": "Режим на unicode клавиатура",
"sessionToolbarShow": "Показване на лентата с инструменти", "sessionToolbarShow": "Показване на лентата с инструменти",
"sessionToolbarHide": "Скриване на лентата с инструменти" "sessionToolbarHide": "Скриване на лентата с инструменти",
"actionUpdateSiteApprovals": "Обновяване на одобренията на сайта"
} }
+248 -20
View File
@@ -66,9 +66,15 @@
"local": "Místní", "local": "Místní",
"edit": "Upravit", "edit": "Upravit",
"siteConfirmDelete": "Potvrdit odstranění lokality", "siteConfirmDelete": "Potvrdit odstranění lokality",
"siteConfirmDeleteAndResources": "Potvrdit odstranění lokality a zdrojů",
"siteDelete": "Odstranění lokality", "siteDelete": "Odstranění lokality",
"siteDeleteAndResources": "Odstranit lokalitu a zdroje",
"siteMessageRemove": "Po odstranění webu již nebude přístupný. Všechny cíle spojené s webem budou také odstraněny.", "siteMessageRemove": "Po odstranění webu již nebude přístupný. Všechny cíle spojené s webem budou také odstraněny.",
"siteMessageRemoveAndResources": "Toto trvale odstraní všechny veřejné a soukromé zdroje spojené s touto lokalitou, i když je zdroj také přiřazen k jiným lokalitám.",
"siteQuestionRemove": "Jste si jisti, že chcete odstranit tuto stránku z organizace?", "siteQuestionRemove": "Jste si jisti, že chcete odstranit tuto stránku z organizace?",
"siteQuestionRemoveAndResources": "Opravdu chcete odstranit tuto lokalitu a všechny přidružené zdroje?",
"sitesTableDeleteSite": "Odstranění lokality",
"sitesTableDeleteSiteAndResources": "Odstranit lokalitu a zdroje",
"siteManageSites": "Správa lokalit", "siteManageSites": "Správa lokalit",
"siteDescription": "Vytvořte a spravujte stránky pro povolení připojení k soukromým sítím", "siteDescription": "Vytvořte a spravujte stránky pro povolení připojení k soukromým sítím",
"sitesBannerTitle": "Připojit jakoukoli síť", "sitesBannerTitle": "Připojit jakoukoli síť",
@@ -117,6 +123,16 @@
"siteUpdated": "Lokalita upravena", "siteUpdated": "Lokalita upravena",
"siteUpdatedDescription": "Lokalita byla upravena.", "siteUpdatedDescription": "Lokalita byla upravena.",
"siteGeneralDescription": "Upravte obecná nastavení pro tuto lokalitu", "siteGeneralDescription": "Upravte obecná nastavení pro tuto lokalitu",
"siteRestartTitle": "Restartovat lokalitu",
"siteRestartDescription": "Restartujte tunel WireGuard pro tuto lokalitu. To krátce přeruší konektivitu.",
"siteRestartBody": "Použijte to, pokud tunel lokality nefunguje správně a chcete vynutit opětovné připojení bez restartování hostitele.",
"siteRestartButton": "Restartovat lokalitu",
"siteRestartDialogMessage": "Opravdu chcete restartovat WireGuard tunel pro <b>{name}</b>? Lokalita krátce ztratí konektivitu.",
"siteRestartWarning": "Lokalita bude krátce odpojena, zatímco se tunel restartuje.",
"siteRestarted": "Lokalita restartována",
"siteRestartedDescription": "Tunel WireGuard byl restartován.",
"siteErrorRestart": "Nepodařilo se restartovat lokalitu",
"siteErrorRestartDescription": "Při restartování lokality došlo k chybě.",
"siteSettingDescription": "Konfigurace nastavení na webu", "siteSettingDescription": "Konfigurace nastavení na webu",
"siteResourcesTab": "Zdroje", "siteResourcesTab": "Zdroje",
"siteResourcesNoneOnSite": "Tento web zatím nemá veřejné ani soukromé zdroje.", "siteResourcesNoneOnSite": "Tento web zatím nemá veřejné ani soukromé zdroje.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Potvrdit odstranění sdílného odkazu", "shareDeleteConfirm": "Potvrdit odstranění sdílného odkazu",
"shareQuestionRemove": "Jste si jisti, že chcete smazat tento odkaz ke sdílení?", "shareQuestionRemove": "Jste si jisti, že chcete smazat tento odkaz ke sdílení?",
"shareMessageRemove": "Jakmile bude smazán, odkaz přestane fungovat a všichni, kdo jej používají, ztratí přístup k prostředku.", "shareMessageRemove": "Jakmile bude smazán, odkaz přestane fungovat a všichni, kdo jej používají, ztratí přístup k prostředku.",
"shareTokenDescription": "Přístupový token může být předán dvěma způsoby: jako parametr dotazu nebo v záhlaví požadavku. Tyto údaje musí být předány klientovi na každé žádosti o ověřený přístup.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Přístupový token", "accessToken": "Přístupový token",
"usageExamples": "Příklady použití", "usageExamples": "Příklady použití",
"tokenId": "ID tokenu", "tokenId": "ID tokenu",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Název (volitelné)", "shareTitleOptional": "Název (volitelné)",
"sharePathOptional": "Cesta (volitelně)", "sharePathOptional": "Cesta (volitelně)",
"sharePathDescription": "Odkaz přesměruje uživatele na tuto cestu po autentikaci.", "sharePathDescription": "Odkaz přesměruje uživatele na tuto cestu po autentikaci.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Platnost vyprší za", "expireIn": "Platnost vyprší za",
"neverExpire": "Nikdy nevyprší", "neverExpire": "Nikdy nevyprší",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Doba platnosti určuje, jak dlouho bude odkaz použitelný a bude poskytovat přístup ke zdroji. Po této době odkaz již nebude fungovat a uživatelé kteří tento odkaz používali ztratí přístup ke zdroji.", "shareExpireDescription": "Doba platnosti určuje, jak dlouho bude odkaz použitelný a bude poskytovat přístup ke zdroji. Po této době odkaz již nebude fungovat a uživatelé kteří tento odkaz používali ztratí přístup ke zdroji.",
"shareSeeOnce": "Tento odkaz uvidíte pouze jednou. Nezapomeňte jej zkopírovat.", "shareSeeOnce": "Tento odkaz uvidíte pouze jednou. Nezapomeňte jej zkopírovat.",
"shareAccessHint": "Kdokoli s tímto odkazem může přistupovat ke zdroji. Sdílejte jej s rozvahou.", "shareAccessHint": "Kdokoli s tímto odkazem může přistupovat ke zdroji. Sdílejte jej s rozvahou.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy požadavky na syrové TCP/UDP pomocí čísla portu. Vyžaduje připojení stránek ke vzdálenému uzlu.", "resourceRawDescriptionCloud": "Proxy požadavky na syrové TCP/UDP pomocí čísla portu. Vyžaduje připojení stránek ke vzdálenému uzlu.",
"resourceCreate": "Vytvořit zdroj", "resourceCreate": "Vytvořit zdroj",
"resourceCreateDescription": "Postupujte podle níže uvedených kroků, abyste vytvořili a připojili nový zdroj", "resourceCreateDescription": "Postupujte podle níže uvedených kroků, abyste vytvořili a připojili nový zdroj",
"resourcePublicCreate": "Vytvořit veřejný zdroj",
"resourcePublicCreateDescription": "Postupujte podle kroků níže pro vytvoření nového veřejného zdroje přístupného přes webový prohlížeč",
"resourceCreateGeneralDescription": "Konfigurace základních nastavení zdroje včetně názvu a typu", "resourceCreateGeneralDescription": "Konfigurace základních nastavení zdroje včetně názvu a typu",
"resourceSeeAll": "Zobrazit všechny zdroje", "resourceSeeAll": "Zobrazit všechny zdroje",
"resourceCreateGeneral": "Obecné", "resourceCreateGeneral": "Obecné",
@@ -431,8 +455,14 @@
"provisioningManage": "Zajištění", "provisioningManage": "Zajištění",
"provisioningDescription": "Spravovat klíče pro nastavení a zkontrolovat čekající stránky čekající na schválení.", "provisioningDescription": "Spravovat klíče pro nastavení a zkontrolovat čekající stránky čekající na schválení.",
"pendingSites": "Nevyřízené weby", "pendingSites": "Nevyřízené weby",
"siteApproveSuccess": "Web byl úspěšně schválen", "siteApproveSuccess": "Stránka a přidružené zdroje byly úspěšně schváleny",
"siteApproveError": "Chyba při schvalování webu", "siteApproveError": "Chyba při schvalování webu",
"siteReject": "Odmítnout stránku",
"siteQuestionReject": "Opravdu chcete tuto stránku odmítnout?",
"siteMessageReject": "Toto trvale odstraní stránku a všechny přidružené zdroje, které jsou stále nevyřízené.",
"siteConfirmReject": "Potvrdit odmítnutí stránky",
"siteRejectSuccess": "Stránka byla úspěšně odmítnuta",
"siteRejectError": "Chyba při odmítání stránky",
"provisioningKeys": "Poskytovací klíče", "provisioningKeys": "Poskytovací klíče",
"searchProvisioningKeys": "Hledat klíče k zajišťování...", "searchProvisioningKeys": "Hledat klíče k zajišťování...",
"provisioningKeysAdd": "Generovat zajišťovací klíč", "provisioningKeysAdd": "Generovat zajišťovací klíč",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Uložit konfigurační klíč", "provisioningKeysSave": "Uložit konfigurační klíč",
"provisioningKeysSaveDescription": "Toto můžete vidět pouze jednou. Zkopírujte ho na bezpečné místo.", "provisioningKeysSaveDescription": "Toto můžete vidět pouze jednou. Zkopírujte ho na bezpečné místo.",
"provisioningKeysErrorCreate": "Chyba při vytváření doplňovacího klíče", "provisioningKeysErrorCreate": "Chyba při vytváření doplňovacího klíče",
"provisioningKeysList": "Nový klíč pro poskytování informací", "provisioningKeysList": "Nový provisioning klíč",
"provisioningKeysMaxBatchSize": "Maximální velikost dávky", "provisioningKeysMaxBatchSize": "Maximální velikost dávky",
"provisioningKeysUnlimitedBatchSize": "Neomezená velikost šarže (bez omezení)", "provisioningKeysUnlimitedBatchSize": "Neomezená velikost šarže (bez omezení)",
"provisioningKeysMaxBatchUnlimited": "Bez omezení", "provisioningKeysMaxBatchUnlimited": "Bez omezení",
"provisioningKeysMaxBatchSizeInvalid": "Zadejte platnou maximální velikost šarže (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Zadejte platnou maximální velikost šarže (11,000,000).",
"provisioningKeysValidUntil": "Platné do", "provisioningKeysValidUntil": "Platná do",
"provisioningKeysValidUntilHint": "Ponechte prázdné, pokud vyprší platnost.", "provisioningKeysValidUntilHint": "Ponechte prázdné, pokud vyprší platnost.",
"provisioningKeysValidUntilInvalid": "Zadejte platné datum a čas.", "provisioningKeysValidUntilInvalid": "Zadejte platné datum a čas.",
"provisioningKeysNumUsed": "Časy použití", "provisioningKeysNumUsed": "Časy použití",
@@ -597,7 +627,8 @@
"idpNameInternal": "Interní", "idpNameInternal": "Interní",
"emailInvalid": "Neplatná e-mailová adresa", "emailInvalid": "Neplatná e-mailová adresa",
"inviteValidityDuration": "Zvolte prosím dobu trvání", "inviteValidityDuration": "Zvolte prosím dobu trvání",
"accessRoleSelectPlease": "Vyberte prosím roli", "accessRoleSelectPlease": "Uživatel musí patřit minimálně do jedné role.",
"accessRoleRequired": "Role je vyžadována",
"removeOwnAdminRoleConfirmTitle": "Odebrat přístup správce?", "removeOwnAdminRoleConfirmTitle": "Odebrat přístup správce?",
"removeOwnAdminRoleConfirmDescription": "Po uložení již nebudete mít oprávnění správce v této organizaci. Další administrátor vám může přístup obnovit, pokud bude potřeba.", "removeOwnAdminRoleConfirmDescription": "Po uložení již nebudete mít oprávnění správce v této organizaci. Další administrátor vám může přístup obnovit, pokud bude potřeba.",
"removeOwnAdminRoleConfirmButton": "Odebrat mé administrátorské oprávnění", "removeOwnAdminRoleConfirmButton": "Odebrat mé administrátorské oprávnění",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Základní Ověření Záhlaví", "policyAuthHeaderAuthTitle": "Základní Ověření Záhlaví",
"policyAuthHeaderAuthDescription": "Ověřit vlastní HTTP hlavičku názvu a hodnoty při každém požadavku", "policyAuthHeaderAuthDescription": "Ověřit vlastní HTTP hlavičku názvu a hodnoty při každém požadavku",
"policyAuthHeaderAuthSummary": "Nastaveno hlavička", "policyAuthHeaderAuthSummary": "Nastaveno hlavička",
"policyAuthHeaderName": "Název hlavičky", "policyAuthHeaderName": "Uživatelské jméno",
"policyAuthHeaderValue": "Očekávaná hodnota", "policyAuthHeaderValue": "Heslo",
"policyAuthSetPasscode": "Nastavit přístupový kód", "policyAuthSetPasscode": "Nastavit přístupový kód",
"policyAuthSetPincode": "Nastavit PIN kód", "policyAuthSetPincode": "Nastavit PIN kód",
"policyAuthSetEmailWhitelist": "Nastavit e-mailový whitelist", "policyAuthSetEmailWhitelist": "Nastavit e-mailový whitelist",
@@ -903,7 +934,7 @@
"newtVersion": "Verze", "newtVersion": "Verze",
"architecture": "Architektura", "architecture": "Architektura",
"sites": "Stránky", "sites": "Stránky",
"siteWgAnyClients": "K připojení použijte jakéhokoli klienta WireGuard. Budete muset řešit interní zdroje pomocí klientské IP adresy.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Kompatibilní se všemi klienty aplikace WireGuard", "siteWgCompatibleAllClients": "Kompatibilní se všemi klienty aplikace WireGuard",
"siteWgManualConfigurationRequired": "Je vyžadována ruční konfigurace", "siteWgManualConfigurationRequired": "Je vyžadována ruční konfigurace",
"userErrorNotAdminOrOwner": "Uživatel není administrátor nebo vlastník", "userErrorNotAdminOrOwner": "Uživatel není administrátor nebo vlastník",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Vytvořit Org uživatele", "createOrgUser": "Vytvořit Org uživatele",
"actionUpdateOrg": "Aktualizovat organizaci", "actionUpdateOrg": "Aktualizovat organizaci",
"actionRemoveInvitation": "Odstranit pozvání", "actionRemoveInvitation": "Odstranit pozvání",
"actionRemoveUserRole": "Odstranit uživatelskou roli",
"actionUpdateUser": "Aktualizovat uživatele", "actionUpdateUser": "Aktualizovat uživatele",
"actionGetUser": "Získat uživatele", "actionGetUser": "Získat uživatele",
"actionGetOrgUser": "Získat uživatele organizace", "actionGetOrgUser": "Získat uživatele organizace",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Použít plán", "actionApplyBlueprint": "Použít plán",
"actionListBlueprints": "Seznam šablon", "actionListBlueprints": "Seznam šablon",
"actionGetBlueprint": "Získat šablonu", "actionGetBlueprint": "Získat šablonu",
"actionCreateOrgWideLauncherView": "Vytvořit organizační pohled",
"setupToken": "Nastavit token", "setupToken": "Nastavit token",
"setupTokenDescription": "Zadejte nastavovací token z konzole serveru.", "setupTokenDescription": "Zadejte nastavovací token z konzole serveru.",
"setupTokenRequired": "Je vyžadován token nastavení", "setupTokenRequired": "Je vyžadován token nastavení",
"actionUpdateSite": "Aktualizovat stránku", "actionUpdateSite": "Aktualizovat stránku",
"actionApproveSite": "Schválit stránku",
"actionRejectSite": "Odmítnout stránku",
"actionResetSiteBandwidth": "Resetovat šířku pásma organizace", "actionResetSiteBandwidth": "Resetovat šířku pásma organizace",
"actionListSiteRoles": "Seznam povolených rolí webu", "actionListSiteRoles": "Seznam povolených rolí webu",
"actionCreateResource": "Vytvořit zdroj", "actionCreateResource": "Vytvořit zdroj",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Nastavit zdrojový kód", "actionSetResourcePincode": "Nastavit zdrojový kód",
"actionSetResourceEmailWhitelist": "Nastavit seznam povolených dokumentů", "actionSetResourceEmailWhitelist": "Nastavit seznam povolených dokumentů",
"actionGetResourceEmailWhitelist": "Získat seznam povolených dokumentů", "actionGetResourceEmailWhitelist": "Získat seznam povolených dokumentů",
"actionGetResourcePolicy": "Získat zásady zdroje",
"actionUpdateResourcePolicy": "Aktualizovat zásady zdroje",
"actionSetResourcePolicyUsers": "Nastavte uživatele pro zásady zdroje",
"actionSetResourcePolicyRoles": "Nastavte role pro zásady zdroje",
"actionSetResourcePolicyPassword": "Nastavte heslo pro zásady zdroje",
"actionSetResourcePolicyPincode": "Nastavit PIN kód Zásady zdroje",
"actionSetResourcePolicyHeaderAuth": "Nastavit autentizaci hlavičky zásady zdroje",
"actionSetResourcePolicyWhitelist": "Nastavit seznam povolených e-mailů v zásadě zdroje",
"actionSetResourcePolicyRules": "Nastavit pravidla zásady zdroje",
"actionCreateTarget": "Create Target", "actionCreateTarget": "Create Target",
"actionDeleteTarget": "Odstranit cíl", "actionDeleteTarget": "Odstranit cíl",
"actionGetTarget": "Získat cíl", "actionGetTarget": "Získat cíl",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Generovat přístupový token", "actionGenerateAccessToken": "Generovat přístupový token",
"actionDeleteAccessToken": "Odstranit přístupový token", "actionDeleteAccessToken": "Odstranit přístupový token",
"actionListAccessTokens": "Seznam přístupových tokenů", "actionListAccessTokens": "Seznam přístupových tokenů",
"actionCreateResourceSessionToken": "Vytvořit token relace prostředku",
"actionCreateResourceRule": "Vytvořit pravidlo pro zdroj", "actionCreateResourceRule": "Vytvořit pravidlo pro zdroj",
"actionDeleteResourceRule": "Odstranit pravidlo pro dokument", "actionDeleteResourceRule": "Odstranit pravidlo pro dokument",
"actionListResourceRules": "Seznam pravidel zdrojů", "actionListResourceRules": "Seznam pravidel zdrojů",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Seznam pozvánek", "actionListInvitations": "Seznam pozvánek",
"actionExportLogs": "Exportovat protokoly", "actionExportLogs": "Exportovat protokoly",
"actionViewLogs": "Zobrazit logy", "actionViewLogs": "Zobrazit logy",
"actionCreateSiteProvisioningKey": "Vytvořit klíč pro zřízení webu",
"actionListSiteProvisioningKeys": "Seznam klíčů pro zřízení webu",
"actionUpdateSiteProvisioningKey": "Aktualizovat klíč pro zřízení webu",
"actionDeleteSiteProvisioningKey": "Smazat klíč pro zřízení webu",
"noneSelected": "Není vybráno", "noneSelected": "Není vybráno",
"orgNotFound2": "Nebyly nalezeny žádné organizace.", "orgNotFound2": "Nebyly nalezeny žádné organizace.",
"search": "Vyhledávání…", "search": "Vyhledávání…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Naposled použito",
"otpAuthBack": "Zpět na heslo", "otpAuthBack": "Zpět na heslo",
"navbar": "Navigation Menu", "navbar": "Navigation Menu",
"navbarDescription": "Hlavní navigační menu aplikace", "navbarDescription": "Hlavní navigační menu aplikace",
"navbarDocsLink": "Dokumentace", "navbarDocsLink": "Dokumentace",
"commandPaletteTitle": "Paleta příkazů",
"commandPaletteDescription": "Vyhledávejte stránky, organizace, zdroje a akce",
"commandPaletteSearchPlaceholder": "Hledat stránky, zdroje, akce...",
"commandPaletteNoResults": "Nebyly nalezeny žádné výsledky.",
"commandPaletteSearching": "Hledání...",
"commandPaletteNavigation": "Navigace",
"commandPaletteOrganizations": "Organizace",
"commandPaletteSites": "Lokality",
"commandPaletteResources": "Zdroje",
"commandPaletteUsers": "Uživatelé",
"commandPaletteClients": "Strojoví klienti",
"commandPaletteActions": "Akce",
"commandPaletteCreateSite": "Vytvořit lokalitu",
"commandPaletteCreateProxyResource": "Vytvořit veřejný zdroj",
"commandPaletteCreatePrivateResource": "Vytvořit privátní zdroj",
"commandPaletteCreateUser": "Vytvořit uživatele",
"commandPaletteCreateApiKey": "Vytvořit API klíč",
"commandPaletteCreateMachineClient": "Vytvořit strojového klienta",
"commandPaletteCreateAlertRule": "Vytvořit pravidlo upozornění",
"commandPaletteCreateIdentityProvider": "Vytvořit poskytovatele identity",
"commandPaletteToggleTheme": "Přepnout téma",
"commandPaletteChooseOrganization": "Vybrat organizaci",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "2FA nelze povolit", "otpErrorEnable": "2FA nelze povolit",
"otpErrorEnableDescription": "Došlo k chybě při povolování 2FA", "otpErrorEnableDescription": "Došlo k chybě při povolování 2FA",
"otpSetupCheckCode": "Zadejte 6místný kód", "otpSetupCheckCode": "Zadejte 6místný kód",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Správa", "sidebarManagement": "Správa",
"sidebarBillingAndLicenses": "Fakturace a licence", "sidebarBillingAndLicenses": "Fakturace a licence",
"sidebarLogsAnalytics": "Analytici", "sidebarLogsAnalytics": "Analytici",
"commandSites": "Lokality",
"commandActionModeInfo": "Napište \">\" pro otevření režimu akcí",
"commandResources": "Zdroje",
"commandProxyResources": "Veřejné zdroje",
"commandClientResources": "Privátní zdroje",
"commandClients": "Klienti",
"commandUserDevices": "Uživatelská zařízení",
"commandMachineClients": "Strojoví klienti",
"commandDomains": "Domény",
"commandRemoteExitNodes": "Vzdálené uzly",
"commandTeam": "Tým",
"commandUsers": "Uživatelé",
"commandRoles": "Role",
"commandInvitations": "Pozvánky",
"commandPolicies": "Sdílené zásady",
"commandResourcePolicies": "Zásady veřejných zdrojů",
"commandIdentityProviders": "Poskytovatelé identity",
"commandApprovals": "Žádosti o schválení",
"commandShareableLinks": "Sdílené odkazy",
"commandOrganization": "Organizace",
"commandLogsAndAnalytics": "Protokoly a analytika",
"commandLogsAnalytics": "Analytika",
"commandLogsRequest": "Protokoly požadavků na HTTP",
"commandLogsAccess": "Protokoly autentizace",
"commandLogsAction": "Protokoly akcí administrátora",
"commandLogsConnection": "Protokoly připojení",
"commandLogsStreaming": "Streamování událostí",
"commandManagement": "Řízení",
"commandAlerting": "Upozorňování",
"commandProvisioning": "Zajištění",
"commandBluePrints": "Blueprinty",
"commandApiKeys": "API klíče",
"commandBillingAndLicenses": "Účty a licence",
"commandBilling": "Účty",
"commandEnterpriseLicenses": "Licence",
"commandSettings": "Nastavení",
"commandLauncher": "Spouštěč",
"commandResourceLauncher": "Spouštěč zdrojů",
"commandSearchResults": "Výsledky hledání",
"alertingTitle": "Upozornění", "alertingTitle": "Upozornění",
"alertingDescription": "Definujte zdroje, spouštěče a akce pro oznámení", "alertingDescription": "Definujte zdroje, spouštěče a akce pro oznámení",
"alertingRules": "Pravidla upozornění", "alertingRules": "Pravidla upozornění",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Subdoména: {subdomain}", "domainPickerSubdomain": "Subdoména: {subdomain}",
"domainPickerNamespace": "Jmenný prostor: {namespace}", "domainPickerNamespace": "Jmenný prostor: {namespace}",
"domainPickerShowMore": "Zobrazit více", "domainPickerShowMore": "Zobrazit více",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Vybrat region", "regionSelectorTitle": "Vybrat region",
"domainPickerRemoteExitNodeWarning": "Poskytnuté domény nejsou podporovány, když se stránky připojují k vzdáleným výstupním uzlům. Pro dostupné zdroje na vzdálených uzlech použijte vlastní doménu.", "domainPickerRemoteExitNodeWarning": "Poskytnuté domény nejsou podporovány, když se stránky připojují k vzdáleným výstupním uzlům. Pro dostupné zdroje na vzdálených uzlech použijte vlastní doménu.",
"regionSelectorInfo": "Výběr regionu nám pomáhá poskytovat lepší výkon pro vaši polohu. Nemusíte být ve stejném regionu jako váš server.", "regionSelectorInfo": "Výběr regionu nám pomáhá poskytovat lepší výkon pro vaši polohu. Nemusíte být ve stejném regionu jako váš server.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domény", "billingDomains": "Domény",
"billingOrganizations": "Tělo", "billingOrganizations": "Tělo",
"billingRemoteExitNodes": "Vzdálené uzly", "billingRemoteExitNodes": "Vzdálené uzly",
"billingPublicResources": "Veřejné zdroje",
"billingPrivateResources": "Soukromé zdroje",
"billingMachineClients": "Strojní klienti",
"billingNoLimitConfigured": "Žádný limit nenastaven", "billingNoLimitConfigured": "Žádný limit nenastaven",
"billingEstimatedPeriod": "Odhadované období fakturace", "billingEstimatedPeriod": "Odhadované období fakturace",
"billingIncludedUsage": "Zahrnuto využití", "billingIncludedUsage": "Zahrnuto využití",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Kolik uživatelů můžete použít", "billingUsersInfo": "Kolik uživatelů můžete použít",
"billingDomainInfo": "Kolik domén můžete použít", "billingDomainInfo": "Kolik domén můžete použít",
"billingRemoteExitNodesInfo": "Kolik vzdálených uzlů můžete použít", "billingRemoteExitNodesInfo": "Kolik vzdálených uzlů můžete použít",
"billingPublicResourcesInfo": "Kolik veřejných zdrojů můžete využít",
"billingPrivateResourcesInfo": "Kolik soukromých zdrojů můžete využít",
"billingMachineClientsInfo": "Kolik strojních klientů můžete využít",
"billingLicenseKeys": "Licenční klíče", "billingLicenseKeys": "Licenční klíče",
"billingLicenseKeysDescription": "Spravovat předplatné licenčního klíče", "billingLicenseKeysDescription": "Spravovat předplatné licenčního klíče",
"billingLicenseSubscription": "Předplatné licence", "billingLicenseSubscription": "Předplatné licence",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Podsíť", "subnetPlaceholder": "Podsíť",
"addressDescription": "Interní adresa klienta. Musí spadat do podsítě organizace.", "addressDescription": "Interní adresa klienta. Musí spadat do podsítě organizace.",
"selectSites": "Vyberte stránky", "selectSites": "Vyberte stránky",
"selectLabels": "Vyberte názvy",
"sitesDescription": "Klient bude mít připojení k vybraným webům", "sitesDescription": "Klient bude mít připojení k vybraným webům",
"clientInstallOlm": "Nainstalovat Olm", "clientInstallOlm": "Nainstalovat Olm",
"clientInstallOlmDescription": "Stáhněte si Olm běžící ve vašem systému", "clientInstallOlmDescription": "Stáhněte si Olm běžící ve vašem systému",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Veřejnost", "resourcesTableProxyResources": "Veřejnost",
"resourcesTableClientResources": "Soukromé", "resourcesTableClientResources": "Soukromé",
"resourcesTableNoProxyResourcesFound": "Nebyly nalezeny žádné zdroje proxy", "resourcesTableNoProxyResourcesFound": "Nebyly nalezeny žádné zdroje proxy",
"resourcesTableNoInternalResourcesFound": "Nebyly nalezeny žádné vnitřní zdroje.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Místo určení", "resourcesTableDestination": "Místo určení",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Adresa aliasu", "resourcesTableAliasAddress": "Adresa aliasu",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Zrušit", "editInternalResourceDialogCancel": "Zrušit",
"editInternalResourceDialogSaveResource": "Uložit dokument", "editInternalResourceDialogSaveResource": "Uložit dokument",
"editInternalResourceDialogSuccess": "Úspěšně", "editInternalResourceDialogSuccess": "Úspěšně",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interní zdroj byl úspěšně aktualizován", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Chyba", "editInternalResourceDialogError": "Chyba",
"editInternalResourceDialogFailedToUpdateInternalResource": "Aktualizace interního zdroje se nezdařila", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Název je povinný", "editInternalResourceDialogNameRequired": "Název je povinný",
"editInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků", "editInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
"editInternalResourceDialogProxyPortMin": "Port proxy serveru musí být alespoň 1", "editInternalResourceDialogProxyPortMin": "Port proxy serveru musí být alespoň 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.", "editInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.",
"createInternalResourceDialogNoSitesAvailable": "Nejsou k dispozici žádné weby", "createInternalResourceDialogNoSitesAvailable": "Nejsou k dispozici žádné weby",
"createInternalResourceDialogNoSitesAvailableDescription": "Musíte mít alespoň jeden Newt web s podsítí nakonfigurovanou pro vytvoření vnitřních zdrojů.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Zavřít", "createInternalResourceDialogClose": "Zavřít",
"createInternalResourceDialogCreateClientResource": "Vytvořit soukromý zdroj", "createInternalResourceDialogCreateClientResource": "Vytvořit soukromý zdroj",
"createInternalResourceDialogCreateClientResourceDescription": "Vytvořte nový zdroj, který bude přístupný pouze klientům připojeným k organizaci", "createInternalResourceDialogCreateClientResourceDescription": "Vytvořte nový zdroj, který bude přístupný pouze klientům připojeným k organizaci",
"privateResourceGeneralDescription": "Nastavte název, identifikátor a další obecná nastavení zdroje.",
"privateResourceCreatePageSeeAll": "Zobrazit všechny privátní zdroje",
"privateResourceAllowIcmpPing": "Povolit ICMP ping",
"privateResourceNetworkAccess": "Přístup k síti",
"privateResourceNetworkAccessDescription": "Ovládejte přístup k TCP/UDP portům a zda je pro tento zdroj povolen ICMP ping.",
"hostSettings": "Nastavení hostitele",
"cidrSettings": "Nastavení CIDR",
"createInternalResourceDialogResourceProperties": "Vlastnosti zdroje", "createInternalResourceDialogResourceProperties": "Vlastnosti zdroje",
"createInternalResourceDialogName": "Jméno", "createInternalResourceDialogName": "Jméno",
"createInternalResourceDialogSite": "Lokalita", "createInternalResourceDialogSite": "Lokalita",
"selectSite": "Vybrat lokalitu...", "selectSite": "Vybrat lokalitu...",
"multiSitesSelectorSitesCount": "{count, plural, one {# web} few {# weby} many {# webů} other {# weby}}", "multiSitesSelectorSitesCount": "{count, plural, one {# web} few {# weby} many {# webů} other {# weby}}",
"labelsSelectorLabelsCount": "{count, plural, one {# název} few {# názvy} many {# názvů} other {# názvů}}",
"noSitesFound": "Nebyly nalezeny žádné lokality.", "noSitesFound": "Nebyly nalezeny žádné lokality.",
"createInternalResourceDialogProtocol": "Protokol", "createInternalResourceDialogProtocol": "Protokol",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Zrušit", "createInternalResourceDialogCancel": "Zrušit",
"createInternalResourceDialogCreateResource": "Vytvořit zdroj", "createInternalResourceDialogCreateResource": "Vytvořit zdroj",
"createInternalResourceDialogSuccess": "Úspěšně", "createInternalResourceDialogSuccess": "Úspěšně",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interní zdroj byl úspěšně vytvořen", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Chyba", "createInternalResourceDialogError": "Chyba",
"createInternalResourceDialogFailedToCreateInternalResource": "Nepodařilo se vytvořit interní zdroj", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Název je povinný", "createInternalResourceDialogNameRequired": "Název je povinný",
"createInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků", "createInternalResourceDialogNameMaxLength": "Název musí mít méně než 255 znaků",
"createInternalResourceDialogPleaseSelectSite": "Vyberte prosím web", "createInternalResourceDialogPleaseSelectSite": "Vyberte prosím web",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "Rozsah zdrojů CIDR v síti webu.", "createInternalResourceDialogDestinationCidrDescription": "Rozsah zdrojů CIDR v síti webu.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.", "createInternalResourceDialogAliasDescription": "Volitelný interní DNS alias pro tento dokument.",
"internalResourceAliasLocalWarning": "Aliasy končící na .local mohou způsobit problémy s vyřešením díky mDNS v některých sítích.",
"internalResourceDownstreamSchemeRequired": "HTTP metoda je vyžadována pro HTTP zdroje", "internalResourceDownstreamSchemeRequired": "HTTP metoda je vyžadována pro HTTP zdroje",
"internalResourceHttpPortRequired": "Přípoječný port je nutný pro HTTP zdroj", "internalResourceHttpPortRequired": "Přípoječný port je nutný pro HTTP zdroj",
"siteConfiguration": "Konfigurace", "siteConfiguration": "Konfigurace",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Vzdálené uzly", "sidebarRemoteExitNodes": "Vzdálené uzly",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Tajný klíč", "remoteExitNodeSecretKey": "Tajný klíč",
"remoteExitNodeNetworkingTitle": "Nastavení sítě",
"remoteExitNodeNetworkingDescription": "Nastavte, jak tento vzdálený výstupní uzel směruje provoz a které lokality se mají připojit přes něj. Pokročilé funkce pro použití s konfiguracemi zpětné sítě.",
"remoteExitNodeNetworkingSave": "Uložit nastavení",
"remoteExitNodeNetworkingSaveSuccessTitle": "Nastavení sítě bylo úspěšně uloženo",
"remoteExitNodeNetworkingSaveSuccessDescription": "Nastavení sítě bylo úspěšně aktualizováno.",
"remoteExitNodeNetworkingSaveError": "Nepodařilo se uložit nastavení sítě",
"remoteExitNodeNetworkingSubnetsTitle": "Dálkové podsítě",
"remoteExitNodeNetworkingSubnetsDescription": "Definujte rozsahy CIDR, ke kterým tento vzdálený výstupní uzel bude směrovat provoz. Zadejte platné CIDR (např. <code>10.0.0.0/8</code>) a stiskněte Enter pro přidání.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Přidejte rozsah CIDR (např. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Nepodařilo se načíst podsítě",
"remoteExitNodeNetworkingLabelsTitle": "Názvy preferencí",
"remoteExitNodeNetworkingLabelsDescription": "Weby s těmito názvy budou nuceny připojit se tímto vzdáleným výstupním uzlem.",
"remoteExitNodeNetworkingLabelsButtonText": "Vyberte názvy...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Hledat názvy...",
"remoteExitNodeNetworkingLabelsLoadError": "Nepodařilo se načíst názvy",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Vytvořit vzdálený uzel", "title": "Vytvořit vzdálený uzel",
"description": "Vytvořte nový vlastní hostovaný vzdálený relační a proxy server uzel", "description": "Vytvořte nový vlastní hostovaný vzdálený relační a proxy server uzel",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Pro tuto organizaci nejsou k dispozici žádné uzly. Nejprve vytvořte uzel pro použití lokálních stránek.", "noRemoteExitNodesAvailableDescription": "Pro tuto organizaci nejsou k dispozici žádné uzly. Nejprve vytvořte uzel pro použití lokálních stránek.",
"exitNode": "Ukončit uzel", "exitNode": "Ukončit uzel",
"country": "L 343, 22.12.2009, s. 1).", "country": "L 343, 22.12.2009, s. 1).",
"countryIsNot": "Země není",
"rulesMatchCountry": "Aktuálně založené na zdrojové IP adrese", "rulesMatchCountry": "Aktuálně založené na zdrojové IP adrese",
"region": "Oblasti", "region": "Oblasti",
"selectRegion": "Vyberte region", "selectRegion": "Vyberte region",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Poskytovatel Google OAuth2/OIDC", "idpGoogleDescription": "Poskytovatel Google OAuth2/OIDC",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Podsíť", "subnet": "Podsíť",
"utilitySubnet": "Nástrojová podsíť",
"subnetDescription": "Podsíť pro konfiguraci sítě této organizace.", "subnetDescription": "Podsíť pro konfiguraci sítě této organizace.",
"customDomain": "Vlastní doména", "customDomain": "Vlastní doména",
"authPage": "Autentizační stránky", "authPage": "Autentizační stránky",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Je vyžadováno nastavení dvoufaktorového ověřování. Přihlaste se znovu pomocí {dashboardUrl}/autentizace/přihlášení dokončí tento krok. Poté se vraťte zde.", "twoFactorSetupRequired": "Je vyžadováno nastavení dvoufaktorového ověřování. Přihlaste se znovu pomocí {dashboardUrl}/autentizace/přihlášení dokončí tento krok. Poté se vraťte zde.",
"additionalSecurityRequired": "Vyžadováno další zabezpečení", "additionalSecurityRequired": "Vyžadováno další zabezpečení",
"organizationRequiresAdditionalSteps": "Tato organizace vyžaduje další bezpečnostní kroky, než budete moci přistupovat ke zdrojům.", "organizationRequiresAdditionalSteps": "Tato organizace vyžaduje další bezpečnostní kroky, než budete moci přistupovat ke zdrojům.",
"sessionExpired": "Session vypršela",
"sessionExpiredReauthRequired": "Vaše session vypršela podle bezpečnostní politiky organizace. Prosím, znovu se přihlaste, abyste mohli pokračovat.",
"reauthenticate": "Znovu autentizovat",
"completeTheseSteps": "Dokončete tyto kroky", "completeTheseSteps": "Dokončete tyto kroky",
"enableTwoFactorAuthentication": "Povolit dvoufaktorové ověření", "enableTwoFactorAuthentication": "Povolit dvoufaktorové ověření",
"completeSecuritySteps": "Dokončit bezpečnostní kroky", "completeSecuritySteps": "Dokončit bezpečnostní kroky",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Zdrojová adresa", "sourceAddress": "Zdrojová adresa",
"destinationAddress": "Cílová adresa", "destinationAddress": "Cílová adresa",
"duration": "Doba trvání", "duration": "Doba trvání",
"licenseRequiredToUse": "Pro použití této funkce je vyžadována licence <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> nebo <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> . <bookADemoLink>Zarezervujte si demo nebo POC zkušební verzi</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> je vyžadována pro použití této funkce. Tato funkce je také k dispozici v <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Rezervujte si demo nebo POC zkušební verzi</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Oddělovač certifikátů", "certResolver": "Oddělovač certifikátů",
"certResolverDescription": "Vyberte řešitele certifikátů pro tento dokument.", "certResolverDescription": "Vyberte řešitele certifikátů pro tento dokument.",
"selectCertResolver": "Vyberte řešič certifikátů", "selectCertResolver": "Vyberte řešič certifikátů",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Chybí ID organizace nebo domény", "orgOrDomainIdMissing": "Chybí ID organizace nebo domény",
"loadingDNSRecords": "Načítání DNS záznamů...", "loadingDNSRecords": "Načítání DNS záznamů...",
"olmUpdateAvailableInfo": "Je k dispozici aktualizovaná verze Olm. Pro nejlepší zážitek prosím aktualizujte na nejnovější verzi.", "olmUpdateAvailableInfo": "Je k dispozici aktualizovaná verze Olm. Pro nejlepší zážitek prosím aktualizujte na nejnovější verzi.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Je k dispozici aktualizovaná verze. Aktualizujte prosím na nejnovější verzi pro nejlepší zážitek.",
"client": "Zákazník", "client": "Zákazník",
"proxyProtocol": "Nastavení proxy protokolu", "proxyProtocol": "Nastavení proxy protokolu",
"proxyProtocolDescription": "Konfigurace Proxy protokolu pro zachování klientských IP adres pro služby TCP.", "proxyProtocolDescription": "Konfigurace Proxy protokolu pro zachování klientských IP adres pro služby TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Přidat uživatele", "editInternalResourceDialogAddUsers": "Přidat uživatele",
"editInternalResourceDialogAddClients": "Přidat klienty", "editInternalResourceDialogAddClients": "Přidat klienty",
"editInternalResourceDialogDestinationLabel": "Cíl", "editInternalResourceDialogDestinationLabel": "Cíl",
"editInternalResourceDialogDestinationDescription": "Určete cílovou adresu pro interní prostředek. Může se jednat o hostname, IP adresu, nebo rozsah CIDR v závislosti na vybraném režimu. Volitelně nastavte interní DNS alias pro snazší identifikaci.", "editInternalResourceDialogDestinationDescription": "Nakonfigurujte, jak klienti dosáhnou tohoto zdroje.",
"internalResourceFormMultiSiteRoutingHelp": "Výběrem více webů se povolí odolné směrování a přepojení pro vysokou dostupnost.", "internalResourceFormMultiSiteRoutingHelp": "Výběrem více webů se povolí odolné směrování a přepojení pro vysokou dostupnost.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Zjistit více", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Zjistit více",
"editInternalResourceDialogPortRestrictionsDescription": "Omezte přístup na specifické TCP/UDP porty nebo povolte/blokujte všechny porty.", "editInternalResourceDialogPortRestrictionsDescription": "Omezte přístup na specifické TCP/UDP porty nebo povolte/blokujte všechny porty.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Seznam povolených emailů", "memberPortalEmailWhitelist": "Seznam povolených emailů",
"memberPortalResourceDisabled": "Zdroj je zakázán", "memberPortalResourceDisabled": "Zdroj je zakázán",
"memberPortalShowingResources": "Zobrazeny {start}-{end} z {total} zdrojů", "memberPortalShowingResources": "Zobrazeny {start}-{end} z {total} zdrojů",
"resourceLauncherTitle": "Spouštěč zdrojů",
"resourceSidebarLauncherTitle": "Spouštěč",
"resourceLauncherDescription": "Prohlédněte si všechny dostupné zdroje a spusťte je z jednoho centrálního hubu",
"resourceLauncherSearchPlaceholder": "Prohledejte vaše zdroje...",
"resourceLauncherDefaultView": "Výchozí",
"resourceLauncherSaveView": "Uložit pohled",
"resourceLauncherSaveToCurrentView": "Uložit do aktuálního pohledu",
"resourceLauncherSaveDefaultPersonal": "Uložit pro mě",
"resourceLauncherResetView": "Obnovit pohled",
"resourceLauncherResetSystemDefault": "Obnovit na systémové nastavení",
"resourceLauncherSystemDefaultRestored": "Systémové nastavení bylo obnoveno",
"resourceLauncherSystemDefaultRestoredDescription": "Výchozí zobrazení bylo resetováno na původní nastavení.",
"resourceLauncherSaveAsNewView": "Uložit jako nový pohled",
"resourceLauncherSaveAsNewViewDescription": "Uložte tento pohled k uloženému filtrování a rozvržení.",
"resourceLauncherSaveForEveryone": "Uložit pro všechny",
"resourceLauncherSaveForEveryoneDescription": "Sdílejte tento pohled se všemi členy organizace. Pokud není zaškrtnuto, pohled je viditelný pouze vám.",
"resourceLauncherMakePersonal": "Udělat osobní",
"resourceLauncherFilter": "Filtr",
"resourceLauncherFilterWithCount": "Filtr, {count} aplikováno",
"resourceLauncherSort": "Řadit",
"resourceLauncherSortAscending": "Řadit vzestupně",
"resourceLauncherSortDescending": "Řadit sestupně",
"resourceLauncherSettings": "Nastavení",
"resourceLauncherGroupBy": "Seskupit podle",
"resourceLauncherGroupBySite": "Lokalita",
"resourceLauncherGroupByLabel": "Název",
"resourceLauncherGroupByNone": "Žádný",
"resourceLauncherLayout": "Rozvržení",
"resourceLauncherLayoutGrid": "Mřížka",
"resourceLauncherLayoutList": "Seznam",
"resourceLauncherShowLabels": "Zobrazit název",
"resourceLauncherShowSiteTags": "Zobrazit značky lokality",
"resourceLauncherShowRecents": "Zobrazit nedávné",
"resourceLauncherDeleteView": "Smazat pohled",
"resourceLauncherDeleteViewTitle": "Odstranění zobrazení",
"resourceLauncherDeleteViewQuestion": "Opravdu chcete smazat toto zobrazení launcheru?",
"resourceLauncherDeleteViewConfirm": "Odstranění zobrazení",
"resourceLauncherViewAsAdmin": "Zobrazit jako administrátor",
"resourceLauncherResourceDetailsDescription": "Informace o připojení a stavu pro tento zdroj.",
"resourceLauncherResourceDetails": "Podrobnosti o zdroji",
"resourceLauncherAuthMethodsDescription": "Povolené metody autentizace pro tento zdroj.",
"resourceLauncherPrivateClientRequired": "Připojte se s klientem na vašem zařízení, abyste měli k tomuto zdroji soukromý přístup.",
"resourceLauncherPrivateClientRequiredTitle": "K připojení klienta vyžadováno",
"resourceLauncherDownloadClient": "Stáhnout klienta",
"resourceLauncherFailedToLoadDetails": "Nemohu načíst podrobnosti o zdroji. K tomuto zdroji možná již nemáte přístup.",
"resourceLauncherNoPortRestrictions": "Žádná omezení portu",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Bez nálepky",
"resourceLauncherNoSite": "Žádná lokalita",
"resourceLauncherNoResourcesInGroup": "V této skupině nejsou žádné zdroje",
"resourceLauncherEmptyStateTitle": "Žádné dostupné zdroje",
"resourceLauncherEmptyStateDescription": "Zatím nemáte přístup k žádným zdrojům. Kontaktujte svého administrátora, abyste požádali o přístup.",
"resourceLauncherEmptyStateNoResultsTitle": "Nebyl nalezen žádný zdroj",
"resourceLauncherEmptyStateNoResultsDescription": "Žádný zdroj neodpovídá vašemu aktuálnímu vyhledávání nebo filtrům. Zkuste je upravit, abyste našli to, co hledáte.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Žádné zdroje neodpovídají \"{query}\". Zkuste upravit vyhledávání nebo vymazat filtry, abyste viděli všechny zdroje.",
"resourceLauncherSearchFirstTitle": "Hledat nebo filtrovat k procházení",
"resourceLauncherSearchFirstDescription": "Máte přístup k mnoha zdrojům. Použijte vyhledávání nebo filtr podle místa či štítku k nalezení toho, co potřebujete.",
"resourceLauncherSiteGroupingDisabled": "Na této úrovni není možné seskupení podle místa. Pro skupinování menší sady se použije filtr podle místa.",
"resourceLauncherLabelGroupingDisabled": "Na této úrovni není možné seskupení podle štítku.",
"resourceLauncherCompactModeHint": "Zobrazování zjednodušeného seznamu pro rychlejší procházení. K upřesnění výsledků použijte vyhledávání nebo filtry.",
"resourceLauncherCompactGroupingHint": "Aplikujte filtry místa nebo štítku, abyste povolili seskupování.",
"resourceLauncherCopiedToClipboard": "Zkopírováno do schránky",
"resourceLauncherCopiedAccessDescription": "Přístup ke zdroji byl zkopírován do vaší schránky.",
"resourceLauncherViewNamePlaceholder": "Název pohledu",
"resourceLauncherViewNameLabel": "Název pohledu",
"resourceLauncherViewSaved": "Pohled uložen",
"resourceLauncherViewSavedDescription": "Váš spouštěcí pohled byl uložen.",
"resourceLauncherViewSaveFailed": "Nepodařilo se uložit pohled",
"resourceLauncherViewSaveFailedDescription": "Nepodařilo se uložit spouštěcí pohled. Prosím zkuste to znovu.",
"resourceLauncherViewDeleted": "Pohled smazán",
"resourceLauncherViewDeletedDescription": "Spouštěcí pohled byl smazán.",
"resourceLauncherViewDeleteFailed": "Nepodařilo se smazat pohled",
"resourceLauncherViewDeleteFailedDescription": "Nepodařilo se smazat spouštěcí pohled. Prosím zkuste to znovu.",
"memberPortalPrevious": "Předchozí", "memberPortalPrevious": "Předchozí",
"memberPortalNext": "Následující", "memberPortalNext": "Následující",
"httpSettings": "Nastavení HTTP", "httpSettings": "Nastavení HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----ZAČÁTEK SOUKROMÉHO KLÍČE OPENSSH-----", "sshPrivateKeyPlaceholder": "-----ZAČÁTEK SOUKROMÉHO KLÍČE OPENSSH-----",
"sshPrivateKeyRequired": "Je vyžadován soukromý klíč", "sshPrivateKeyRequired": "Je vyžadován soukromý klíč",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Zadejte své heslo VNC pro připojení", "vncSignInDescription": "Zadejte své VNC přihlašovací údaje pro připojení",
"vncUsernameOptional": "Uživatelské jméno (nepovinné)",
"vncPasswordOptional": "Heslo (nepovinné)", "vncPasswordOptional": "Heslo (nepovinné)",
"vncNoResourceTarget": "Není k dispozici žádný cíl zdroje", "vncNoResourceTarget": "Není k dispozici žádný cíl zdroje",
"vncFailedToLoadNovnc": "Nepodařilo se načíst noVNC", "vncFailedToLoadNovnc": "Nepodařilo se načíst noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Nahrání selhalo", "rdpUploadFailed": "Nahrání selhalo",
"rdpUnicodeKeyboardMode": "Režim Unicode klávesnice", "rdpUnicodeKeyboardMode": "Režim Unicode klávesnice",
"sessionToolbarShow": "Zobrazit panel nástrojů", "sessionToolbarShow": "Zobrazit panel nástrojů",
"sessionToolbarHide": "Skrýt panel nástrojů" "sessionToolbarHide": "Skrýt panel nástrojů",
"actionUpdateSiteApprovals": "Aktualizovat schválení webu"
} }
+3829
View File
File diff suppressed because it is too large Load Diff
+248 -20
View File
@@ -66,9 +66,15 @@
"local": "Lokal", "local": "Lokal",
"edit": "Bearbeiten", "edit": "Bearbeiten",
"siteConfirmDelete": "Löschen des Standorts bestätigen", "siteConfirmDelete": "Löschen des Standorts bestätigen",
"siteConfirmDeleteAndResources": "Löschen von Standort und Ressourcen bestätigen",
"siteDelete": "Standort löschen", "siteDelete": "Standort löschen",
"siteDeleteAndResources": "Standort und Ressourcen löschen",
"siteMessageRemove": "Sobald der Standort entfernt ist, wird er nicht mehr zugänglich sein. Alle mit dem Standort verbundenen Ziele werden ebenfalls entfernt.", "siteMessageRemove": "Sobald der Standort entfernt ist, wird er nicht mehr zugänglich sein. Alle mit dem Standort verbundenen Ziele werden ebenfalls entfernt.",
"siteMessageRemoveAndResources": "Dies wird dauerhaft alle öffentlichen und privaten Ressourcen, die mit diesem Standort verknüpft sind, löschen, selbst wenn eine Ressource auch mit anderen Standorten verbunden ist.",
"siteQuestionRemove": "Sind Sie sicher, dass Sie den Standort aus der Organisation entfernen möchten?", "siteQuestionRemove": "Sind Sie sicher, dass Sie den Standort aus der Organisation entfernen möchten?",
"siteQuestionRemoveAndResources": "Sind Sie sicher, dass Sie diesen Standort und alle zugehörigen Ressourcen löschen möchten?",
"sitesTableDeleteSite": "Standort löschen",
"sitesTableDeleteSiteAndResources": "Standort und Ressourcen löschen",
"siteManageSites": "Standorte verwalten", "siteManageSites": "Standorte verwalten",
"siteDescription": "Erstellen und Verwalten von Standorten, um die Verbindung zu privaten Netzwerken zu ermöglichen", "siteDescription": "Erstellen und Verwalten von Standorten, um die Verbindung zu privaten Netzwerken zu ermöglichen",
"sitesBannerTitle": "Verbinde ein beliebiges Netzwerk", "sitesBannerTitle": "Verbinde ein beliebiges Netzwerk",
@@ -117,6 +123,16 @@
"siteUpdated": "Standort aktualisiert", "siteUpdated": "Standort aktualisiert",
"siteUpdatedDescription": "Der Standort wurde aktualisiert.", "siteUpdatedDescription": "Der Standort wurde aktualisiert.",
"siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren", "siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren",
"siteRestartTitle": "Standort neu starten",
"siteRestartDescription": "Starten Sie den WireGuard-Tunnel für diesen Standort neu. Dies wird die Konnektivität kurzzeitig unterbrechen.",
"siteRestartBody": "Verwenden Sie dies, wenn der Standort-Tunnel nicht ordnungsgemäß funktioniert und Sie eine erneute Verbindung erzwingen möchten, ohne den Host neu zu starten.",
"siteRestartButton": "Standort neu starten",
"siteRestartDialogMessage": "Sind Sie sicher, dass Sie den WireGuard-Tunnel für <b>{name}</b> neu starten möchten? Der Standort wird kurzzeitig die Konnektivität verlieren.",
"siteRestartWarning": "Der Standort wird kurzzeitig getrennt, während der Tunnel neu gestartet wird.",
"siteRestarted": "Standort neu gestartet",
"siteRestartedDescription": "Der WireGuard-Tunnel wurde neu gestartet.",
"siteErrorRestart": "Fehler beim Neustart des Standorts",
"siteErrorRestartDescription": "Ein Fehler ist aufgetreten, während der Standort neu gestartet wurde.",
"siteSettingDescription": "Standorteinstellungen konfigurieren", "siteSettingDescription": "Standorteinstellungen konfigurieren",
"siteResourcesTab": "Ressourcen", "siteResourcesTab": "Ressourcen",
"siteResourcesNoneOnSite": "Dieser Standort hat noch keine öffentlichen oder privaten Ressourcen", "siteResourcesNoneOnSite": "Dieser Standort hat noch keine öffentlichen oder privaten Ressourcen",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Löschung des Freigabelinks bestätigen", "shareDeleteConfirm": "Löschung des Freigabelinks bestätigen",
"shareQuestionRemove": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?", "shareQuestionRemove": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?",
"shareMessageRemove": "Nach dem Löschen funktioniert der Link nicht mehr, und jeder, der ihn nutzt, verliert den Zugriff auf die Ressource.", "shareMessageRemove": "Nach dem Löschen funktioniert der Link nicht mehr, und jeder, der ihn nutzt, verliert den Zugriff auf die Ressource.",
"shareTokenDescription": "Das Zugriffstoken kann auf zwei Arten übergeben werden: als Abfrageparameter oder in den Request-Headern. Diese müssen vom Client auf jeder Anfrage für authentifizierten Zugriff weitergegeben werden.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Zugriffstoken", "accessToken": "Zugriffstoken",
"usageExamples": "Nutzungsbeispiele", "usageExamples": "Nutzungsbeispiele",
"tokenId": "Token-ID", "tokenId": "Token-ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Titel (optional)", "shareTitleOptional": "Titel (optional)",
"sharePathOptional": "Pfad (optional)", "sharePathOptional": "Pfad (optional)",
"sharePathDescription": "Der Link leitet Benutzer nach der Authentifizierung zu diesem Pfad weiter.", "sharePathDescription": "Der Link leitet Benutzer nach der Authentifizierung zu diesem Pfad weiter.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Läuft ab in", "expireIn": "Läuft ab in",
"neverExpire": "Läuft nie ab", "neverExpire": "Läuft nie ab",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Ablaufzeit ist, wie lange der Link verwendet werden kann und bietet Zugriff auf die Ressource. Nach dieser Zeit wird der Link nicht mehr funktionieren und Benutzer, die diesen Link benutzt haben, verlieren den Zugriff auf die Ressource.", "shareExpireDescription": "Ablaufzeit ist, wie lange der Link verwendet werden kann und bietet Zugriff auf die Ressource. Nach dieser Zeit wird der Link nicht mehr funktionieren und Benutzer, die diesen Link benutzt haben, verlieren den Zugriff auf die Ressource.",
"shareSeeOnce": "Sie können diesen Link nur einmal sehen. Bitte kopieren Sie ihn.", "shareSeeOnce": "Sie können diesen Link nur einmal sehen. Bitte kopieren Sie ihn.",
"shareAccessHint": "Jeder mit diesem Link kann auf die Ressource zugreifen. Teilen Sie sie mit Vorsicht.", "shareAccessHint": "Jeder mit diesem Link kann auf die Ressource zugreifen. Teilen Sie sie mit Vorsicht.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy-Anfragen über rohe TCP/UDP mit Portnummer. Benötigt Sites, um sich mit einem entfernten Knoten zu verbinden.", "resourceRawDescriptionCloud": "Proxy-Anfragen über rohe TCP/UDP mit Portnummer. Benötigt Sites, um sich mit einem entfernten Knoten zu verbinden.",
"resourceCreate": "Ressource erstellen", "resourceCreate": "Ressource erstellen",
"resourceCreateDescription": "Folgen Sie den Schritten unten, um eine neue Ressource zu erstellen", "resourceCreateDescription": "Folgen Sie den Schritten unten, um eine neue Ressource zu erstellen",
"resourcePublicCreate": "Öffentliche Ressource erstellen",
"resourcePublicCreateDescription": "Befolgen Sie die unten aufgeführten Schritte, um eine neue öffentliche Ressource zu erstellen, auf die über einen Webbrowser zugegriffen werden kann",
"resourceCreateGeneralDescription": "Konfigurieren Sie die Grundeinstellungen der Ressource, einschließlich Name und Typ", "resourceCreateGeneralDescription": "Konfigurieren Sie die Grundeinstellungen der Ressource, einschließlich Name und Typ",
"resourceSeeAll": "Alle Ressourcen anzeigen", "resourceSeeAll": "Alle Ressourcen anzeigen",
"resourceCreateGeneral": "Allgemein", "resourceCreateGeneral": "Allgemein",
@@ -431,8 +455,14 @@
"provisioningManage": "Bereitstellung", "provisioningManage": "Bereitstellung",
"provisioningDescription": "Bereitstellungsschlüssel verwalten und ausstehende Standorte prüfen, die noch auf Genehmigung warten.", "provisioningDescription": "Bereitstellungsschlüssel verwalten und ausstehende Standorte prüfen, die noch auf Genehmigung warten.",
"pendingSites": "Ausstehende Standorte", "pendingSites": "Ausstehende Standorte",
"siteApproveSuccess": "Standort erfolgreich freigegeben", "siteApproveSuccess": "Site und zugehörige Ressourcen erfolgreich genehmigt",
"siteApproveError": "Fehler beim Genehmigen des Standorts", "siteApproveError": "Fehler beim Genehmigen des Standorts",
"siteReject": "Site ablehnen",
"siteQuestionReject": "Sind Sie sicher, dass Sie diese Site ablehnen möchten?",
"siteMessageReject": "Dies wird die Site und alle damit verbundenen, noch ausstehenden Ressourcen dauerhaft löschen.",
"siteConfirmReject": "Ablehnung der Site bestätigen",
"siteRejectSuccess": "Site erfolgreich abgelehnt",
"siteRejectError": "Fehler beim Ablehnen der Site",
"provisioningKeys": "Bereitstellungsschlüssel", "provisioningKeys": "Bereitstellungsschlüssel",
"searchProvisioningKeys": "Bereitstellungsschlüssel suchen...", "searchProvisioningKeys": "Bereitstellungsschlüssel suchen...",
"provisioningKeysAdd": "Bereitstellungsschlüssel generieren", "provisioningKeysAdd": "Bereitstellungsschlüssel generieren",
@@ -449,7 +479,7 @@
"provisioningKeysSaveDescription": "Sie können dies nur einmal sehen. Kopieren Sie es an einen sicheren Ort.", "provisioningKeysSaveDescription": "Sie können dies nur einmal sehen. Kopieren Sie es an einen sicheren Ort.",
"provisioningKeysErrorCreate": "Fehler beim Erstellen des Bereitstellungsschlüssels", "provisioningKeysErrorCreate": "Fehler beim Erstellen des Bereitstellungsschlüssels",
"provisioningKeysList": "Neuer Bereitstellungsschlüssel", "provisioningKeysList": "Neuer Bereitstellungsschlüssel",
"provisioningKeysMaxBatchSize": "Max. Batch-Größe", "provisioningKeysMaxBatchSize": "Maximale Batch-Größe",
"provisioningKeysUnlimitedBatchSize": "Unbegrenzte Batch-Größe (kein Limit)", "provisioningKeysUnlimitedBatchSize": "Unbegrenzte Batch-Größe (kein Limit)",
"provisioningKeysMaxBatchUnlimited": "Unbegrenzt", "provisioningKeysMaxBatchUnlimited": "Unbegrenzt",
"provisioningKeysMaxBatchSizeInvalid": "Geben Sie eine gültige maximale Batchgröße ein (11.000.000).", "provisioningKeysMaxBatchSizeInvalid": "Geben Sie eine gültige maximale Batchgröße ein (11.000.000).",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Nie", "provisioningKeysNeverUsed": "Nie",
"provisioningKeysEdit": "Bereitstellungsschlüssel bearbeiten", "provisioningKeysEdit": "Bereitstellungsschlüssel bearbeiten",
"provisioningKeysEditDescription": "Aktualisieren Sie die maximale Batch-Größe und Ablaufzeit für diesen Schlüssel.", "provisioningKeysEditDescription": "Aktualisieren Sie die maximale Batch-Größe und Ablaufzeit für diesen Schlüssel.",
"provisioningKeysApproveNewSites": "Neuen Standort genehmigen", "provisioningKeysApproveNewSites": "Neue Sites genehmigen",
"provisioningKeysApproveNewSitesDescription": "Sites, die sich mit diesem Schlüssel registrieren, automatisch freigeben.", "provisioningKeysApproveNewSitesDescription": "Sites, die sich mit diesem Schlüssel registrieren, automatisch freigeben.",
"provisioningKeysUpdateError": "Fehler beim Aktualisieren des Bereitstellungsschlüssels", "provisioningKeysUpdateError": "Fehler beim Aktualisieren des Bereitstellungsschlüssels",
"provisioningKeysUpdated": "Bereitstellungsschlüssel aktualisiert", "provisioningKeysUpdated": "Bereitstellungsschlüssel aktualisiert",
@@ -597,7 +627,8 @@
"idpNameInternal": "Intern", "idpNameInternal": "Intern",
"emailInvalid": "Ungültige E-Mail-Adresse", "emailInvalid": "Ungültige E-Mail-Adresse",
"inviteValidityDuration": "Bitte wählen Sie eine Dauer", "inviteValidityDuration": "Bitte wählen Sie eine Dauer",
"accessRoleSelectPlease": "Bitte wählen Sie eine Rolle", "accessRoleSelectPlease": "Ein Benutzer muss mindestens einer Rolle zugeordnet sein.",
"accessRoleRequired": "Rolle erforderlich",
"removeOwnAdminRoleConfirmTitle": "Möchten Sie Ihren Administratorzugriff entfernen?", "removeOwnAdminRoleConfirmTitle": "Möchten Sie Ihren Administratorzugriff entfernen?",
"removeOwnAdminRoleConfirmDescription": "Nach dem Speichern haben Sie keine Administratorrechte mehr in dieser Organisation. Ein anderer Administrator kann den Zugriff bei Bedarf wiederherstellen.", "removeOwnAdminRoleConfirmDescription": "Nach dem Speichern haben Sie keine Administratorrechte mehr in dieser Organisation. Ein anderer Administrator kann den Zugriff bei Bedarf wiederherstellen.",
"removeOwnAdminRoleConfirmButton": "Meinen Administratorzugriff entfernen", "removeOwnAdminRoleConfirmButton": "Meinen Administratorzugriff entfernen",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Grundlegende Header-Authentifizierung", "policyAuthHeaderAuthTitle": "Grundlegende Header-Authentifizierung",
"policyAuthHeaderAuthDescription": "Überprüfen Sie einen benutzerdefinierten HTTP-Headernamen und -wert bei jeder Anfrage", "policyAuthHeaderAuthDescription": "Überprüfen Sie einen benutzerdefinierten HTTP-Headernamen und -wert bei jeder Anfrage",
"policyAuthHeaderAuthSummary": "Header konfiguriert", "policyAuthHeaderAuthSummary": "Header konfiguriert",
"policyAuthHeaderName": "Header-Name", "policyAuthHeaderName": "Benutzername",
"policyAuthHeaderValue": "Erwarteter Wert", "policyAuthHeaderValue": "Passwort",
"policyAuthSetPasscode": "Passcode setzen", "policyAuthSetPasscode": "Passcode setzen",
"policyAuthSetPincode": "PIN-Code festlegen", "policyAuthSetPincode": "PIN-Code festlegen",
"policyAuthSetEmailWhitelist": "E-Mail-Whitelist festlegen", "policyAuthSetEmailWhitelist": "E-Mail-Whitelist festlegen",
@@ -903,7 +934,7 @@
"newtVersion": "Version", "newtVersion": "Version",
"architecture": "Architektur", "architecture": "Architektur",
"sites": "Standorte", "sites": "Standorte",
"siteWgAnyClients": "Verwenden Sie jeden WireGuard-Client um sich zu verbinden. Sie müssen interne Ressourcen über die Peer-IP ansprechen.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Kompatibel mit allen WireGuard-Clients", "siteWgCompatibleAllClients": "Kompatibel mit allen WireGuard-Clients",
"siteWgManualConfigurationRequired": "Manuelle Konfiguration erforderlich", "siteWgManualConfigurationRequired": "Manuelle Konfiguration erforderlich",
"userErrorNotAdminOrOwner": "Benutzer ist kein Administrator oder Eigentümer", "userErrorNotAdminOrOwner": "Benutzer ist kein Administrator oder Eigentümer",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Org Benutzer erstellen", "createOrgUser": "Org Benutzer erstellen",
"actionUpdateOrg": "Organisation aktualisieren", "actionUpdateOrg": "Organisation aktualisieren",
"actionRemoveInvitation": "Einladung entfernen", "actionRemoveInvitation": "Einladung entfernen",
"actionRemoveUserRole": "Benutzerrolle entfernen",
"actionUpdateUser": "Benutzer aktualisieren", "actionUpdateUser": "Benutzer aktualisieren",
"actionGetUser": "Benutzer abrufen", "actionGetUser": "Benutzer abrufen",
"actionGetOrgUser": "Organisationsbenutzer abrufen", "actionGetOrgUser": "Organisationsbenutzer abrufen",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Blueprint anwenden", "actionApplyBlueprint": "Blueprint anwenden",
"actionListBlueprints": "Blaupausen anzeigen", "actionListBlueprints": "Blaupausen anzeigen",
"actionGetBlueprint": "Erhalte Blaupause", "actionGetBlueprint": "Erhalte Blaupause",
"actionCreateOrgWideLauncherView": "Organisationen-Weiter-Startansicht erstellen",
"setupToken": "Setup-Token", "setupToken": "Setup-Token",
"setupTokenDescription": "Geben Sie das Setup-Token von der Serverkonsole ein.", "setupTokenDescription": "Geben Sie das Setup-Token von der Serverkonsole ein.",
"setupTokenRequired": "Setup-Token ist erforderlich", "setupTokenRequired": "Setup-Token ist erforderlich",
"actionUpdateSite": "Standorte aktualisieren", "actionUpdateSite": "Standorte aktualisieren",
"actionApproveSite": "Site genehmigen",
"actionRejectSite": "Site ablehnen",
"actionResetSiteBandwidth": "Organisations-Bandbreite zurücksetzen", "actionResetSiteBandwidth": "Organisations-Bandbreite zurücksetzen",
"actionListSiteRoles": "Erlaubte Standort-Rollen auflisten", "actionListSiteRoles": "Erlaubte Standort-Rollen auflisten",
"actionCreateResource": "Ressource erstellen", "actionCreateResource": "Ressource erstellen",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Ressourcen-PIN festlegen", "actionSetResourcePincode": "Ressourcen-PIN festlegen",
"actionSetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist festlegen", "actionSetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist festlegen",
"actionGetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist abrufen", "actionGetResourceEmailWhitelist": "Ressourcen-E-Mail-Whitelist abrufen",
"actionGetResourcePolicy": "Ressourcenrichtlinie abrufen",
"actionUpdateResourcePolicy": "Ressourcenrichtlinie aktualisieren",
"actionSetResourcePolicyUsers": "Ressourcenrichtlinienbenutzer festlegen",
"actionSetResourcePolicyRoles": "Rollen der Ressourcenrichtlinie festlegen",
"actionSetResourcePolicyPassword": "Passwort der Ressourcenrichtlinie festlegen",
"actionSetResourcePolicyPincode": "Ressourcenrichtlinie-PIN festlegen",
"actionSetResourcePolicyHeaderAuth": "Ressourcenrichtlinie für Header-Authentifizierung festlegen",
"actionSetResourcePolicyWhitelist": "E-Mail-Whitelist der Ressourcenrichtlinie festlegen",
"actionSetResourcePolicyRules": "Ressourcenrichtlinienregeln festlegen",
"actionCreateTarget": "Ziel erstellen", "actionCreateTarget": "Ziel erstellen",
"actionDeleteTarget": "Ziel löschen", "actionDeleteTarget": "Ziel löschen",
"actionGetTarget": "Ziel abrufen", "actionGetTarget": "Ziel abrufen",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Zugriffstoken generieren", "actionGenerateAccessToken": "Zugriffstoken generieren",
"actionDeleteAccessToken": "Zugriffstoken löschen", "actionDeleteAccessToken": "Zugriffstoken löschen",
"actionListAccessTokens": "Zugriffstoken auflisten", "actionListAccessTokens": "Zugriffstoken auflisten",
"actionCreateResourceSessionToken": "Ressourcensitzungstoken erstellen",
"actionCreateResourceRule": "Ressourcenregel erstellen", "actionCreateResourceRule": "Ressourcenregel erstellen",
"actionDeleteResourceRule": "Ressourcenregel löschen", "actionDeleteResourceRule": "Ressourcenregel löschen",
"actionListResourceRules": "Ressourcenregeln auflisten", "actionListResourceRules": "Ressourcenregeln auflisten",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Einladungen auflisten", "actionListInvitations": "Einladungen auflisten",
"actionExportLogs": "Logs exportieren", "actionExportLogs": "Logs exportieren",
"actionViewLogs": "Logs anzeigen", "actionViewLogs": "Logs anzeigen",
"actionCreateSiteProvisioningKey": "Bereitstellungsschlüssel für Standort erstellen",
"actionListSiteProvisioningKeys": "Liste der Bereitstellungsschlüssel für Standorte",
"actionUpdateSiteProvisioningKey": "Bereitstellungsschlüssel für Standort aktualisieren",
"actionDeleteSiteProvisioningKey": "Bereitstellungsschlüssel für Standort löschen",
"noneSelected": "Keine ausgewählt", "noneSelected": "Keine ausgewählt",
"orgNotFound2": "Keine Organisationen gefunden.", "orgNotFound2": "Keine Organisationen gefunden.",
"search": "Suche…", "search": "Suche…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Zuletzt verwendet",
"otpAuthBack": "Zurück zum Passwort", "otpAuthBack": "Zurück zum Passwort",
"navbar": "Navigationsmenü", "navbar": "Navigationsmenü",
"navbarDescription": "Hauptnavigationsmenü für die Anwendung", "navbarDescription": "Hauptnavigationsmenü für die Anwendung",
"navbarDocsLink": "Dokumentation", "navbarDocsLink": "Dokumentation",
"commandPaletteTitle": "Befehlsfeld",
"commandPaletteDescription": "Nach Seiten, Organisationen, Ressourcen und Aktionen suchen",
"commandPaletteSearchPlaceholder": "Seiten, Ressourcen, Aktionen suchen...",
"commandPaletteNoResults": "Keine Ergebnisse gefunden.",
"commandPaletteSearching": "Suche...",
"commandPaletteNavigation": "Navigation",
"commandPaletteOrganizations": "Organisationen",
"commandPaletteSites": "Seiten",
"commandPaletteResources": "Ressourcen",
"commandPaletteUsers": "Benutzer",
"commandPaletteClients": "Maschinen-Clients",
"commandPaletteActions": "Aktionen",
"commandPaletteCreateSite": "Seite erstellen",
"commandPaletteCreateProxyResource": "Öffentliche Ressource erstellen",
"commandPaletteCreatePrivateResource": "Private Ressource erstellen",
"commandPaletteCreateUser": "Benutzer erstellen",
"commandPaletteCreateApiKey": "API-Schlüssel erstellen",
"commandPaletteCreateMachineClient": "Maschinen-Client erstellen",
"commandPaletteCreateAlertRule": "Alarmregel erstellen",
"commandPaletteCreateIdentityProvider": "Identitätsanbieter erstellen",
"commandPaletteToggleTheme": "Thema umschalten",
"commandPaletteChooseOrganization": "Organisation auswählen",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Strg K",
"otpErrorEnable": "2FA konnte nicht aktiviert werden", "otpErrorEnable": "2FA konnte nicht aktiviert werden",
"otpErrorEnableDescription": "Beim Aktivieren der 2FA ist ein Fehler aufgetreten", "otpErrorEnableDescription": "Beim Aktivieren der 2FA ist ein Fehler aufgetreten",
"otpSetupCheckCode": "Bitte geben Sie einen 6-stelligen Code ein", "otpSetupCheckCode": "Bitte geben Sie einen 6-stelligen Code ein",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Management", "sidebarManagement": "Management",
"sidebarBillingAndLicenses": "Abrechnung & Lizenzen", "sidebarBillingAndLicenses": "Abrechnung & Lizenzen",
"sidebarLogsAnalytics": "Analytik", "sidebarLogsAnalytics": "Analytik",
"commandSites": "Seiten",
"commandActionModeInfo": "Geben Sie \">\" ein, um den Aktionsmodus zu öffnen",
"commandResources": "Ressourcen",
"commandProxyResources": "Öffentliche Ressourcen",
"commandClientResources": "Private Ressourcen",
"commandClients": "Clients",
"commandUserDevices": "Benutzergeräte",
"commandMachineClients": "Maschinen-Clients",
"commandDomains": "Domänen",
"commandRemoteExitNodes": "Fernknoten",
"commandTeam": "Team",
"commandUsers": "Benutzer",
"commandRoles": "Rollen",
"commandInvitations": "Einladungen",
"commandPolicies": "Geteilte Richtlinien",
"commandResourcePolicies": "Öffentliche Ressourcenrichtlinien",
"commandIdentityProviders": "Identitätsanbieter",
"commandApprovals": "Genehmigungsanfragen",
"commandShareableLinks": "Teilbare Links",
"commandOrganization": "Organisation",
"commandLogsAndAnalytics": "Logs & Analysen",
"commandLogsAnalytics": "Analysen",
"commandLogsRequest": "HTTP-Anforderungsprotokolle",
"commandLogsAccess": "Zugriffsprotokolle",
"commandLogsAction": "Administrator-Aktionsprotokolle",
"commandLogsConnection": "Netzwerkprotokolle",
"commandLogsStreaming": "Ereignis-Streaming",
"commandManagement": "Verwaltung",
"commandAlerting": "Alarmierung",
"commandProvisioning": "Bereitstellung",
"commandBluePrints": "Blaupausen",
"commandApiKeys": "API-Schlüssel",
"commandBillingAndLicenses": "Abrechnung & Lizenzen",
"commandBilling": "Abrechnung",
"commandEnterpriseLicenses": "Lizenzen",
"commandSettings": "Einstellungen",
"commandLauncher": "Launcher",
"commandResourceLauncher": "Ressourcen-Launcher",
"commandSearchResults": "Suchergebnisse",
"alertingTitle": "Benachrichtigung", "alertingTitle": "Benachrichtigung",
"alertingDescription": "Quellen, Auslöser und Aktionen für Benachrichtigungen festlegen", "alertingDescription": "Quellen, Auslöser und Aktionen für Benachrichtigungen festlegen",
"alertingRules": "Benachrichtigungsregeln", "alertingRules": "Benachrichtigungsregeln",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Subdomain: {subdomain}", "domainPickerSubdomain": "Subdomain: {subdomain}",
"domainPickerNamespace": "Namespace: {namespace}", "domainPickerNamespace": "Namespace: {namespace}",
"domainPickerShowMore": "Mehr anzeigen", "domainPickerShowMore": "Mehr anzeigen",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Region auswählen", "regionSelectorTitle": "Region auswählen",
"domainPickerRemoteExitNodeWarning": "Angegebene Domains werden nicht unterstützt, wenn sich Websites mit externen Exit-Knoten verbinden. Damit Ressourcen auf entfernten Knoten verfügbar sind, verwenden Sie stattdessen eine eigene Domain.", "domainPickerRemoteExitNodeWarning": "Angegebene Domains werden nicht unterstützt, wenn sich Websites mit externen Exit-Knoten verbinden. Damit Ressourcen auf entfernten Knoten verfügbar sind, verwenden Sie stattdessen eine eigene Domain.",
"regionSelectorInfo": "Das Auswählen einer Region hilft uns, eine bessere Leistung für Ihren Standort bereitzustellen. Sie müssen sich nicht in derselben Region wie Ihr Server befinden.", "regionSelectorInfo": "Das Auswählen einer Region hilft uns, eine bessere Leistung für Ihren Standort bereitzustellen. Sie müssen sich nicht in derselben Region wie Ihr Server befinden.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domänen", "billingDomains": "Domänen",
"billingOrganizations": "Orden", "billingOrganizations": "Orden",
"billingRemoteExitNodes": "Entfernte Knoten", "billingRemoteExitNodes": "Entfernte Knoten",
"billingPublicResources": "Öffentliche Ressourcen",
"billingPrivateResources": "Private Ressourcen",
"billingMachineClients": "Maschinen-Clients",
"billingNoLimitConfigured": "Kein Limit konfiguriert", "billingNoLimitConfigured": "Kein Limit konfiguriert",
"billingEstimatedPeriod": "Geschätzter Abrechnungszeitraum", "billingEstimatedPeriod": "Geschätzter Abrechnungszeitraum",
"billingIncludedUsage": "Inklusive Nutzung", "billingIncludedUsage": "Inklusive Nutzung",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Wie viele Benutzer Sie verwenden können", "billingUsersInfo": "Wie viele Benutzer Sie verwenden können",
"billingDomainInfo": "Wie viele Domains Sie verwenden können", "billingDomainInfo": "Wie viele Domains Sie verwenden können",
"billingRemoteExitNodesInfo": "Wie viele entfernte Knoten Sie verwenden können", "billingRemoteExitNodesInfo": "Wie viele entfernte Knoten Sie verwenden können",
"billingPublicResourcesInfo": "Wie viele öffentliche Ressourcen Sie nutzen können",
"billingPrivateResourcesInfo": "Wie viele private Ressourcen Sie nutzen können",
"billingMachineClientsInfo": "Wie viele Maschinen-Clients Sie nutzen können",
"billingLicenseKeys": "Lizenzschlüssel", "billingLicenseKeys": "Lizenzschlüssel",
"billingLicenseKeysDescription": "Verwalten Sie Ihre Lizenzschlüssel Abonnements", "billingLicenseKeysDescription": "Verwalten Sie Ihre Lizenzschlüssel Abonnements",
"billingLicenseSubscription": "Lizenzabonnement", "billingLicenseSubscription": "Lizenzabonnement",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Subnetz", "subnetPlaceholder": "Subnetz",
"addressDescription": "Die interne Adresse des Clients. Muss in das Subnetz der Organisation fallen.", "addressDescription": "Die interne Adresse des Clients. Muss in das Subnetz der Organisation fallen.",
"selectSites": "Standorte auswählen", "selectSites": "Standorte auswählen",
"selectLabels": "Etiketten auswählen",
"sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.", "sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.",
"clientInstallOlm": "Olm installieren", "clientInstallOlm": "Olm installieren",
"clientInstallOlmDescription": "Olm auf Ihrem System zum Laufen bringen", "clientInstallOlmDescription": "Olm auf Ihrem System zum Laufen bringen",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Öffentlich", "resourcesTableProxyResources": "Öffentlich",
"resourcesTableClientResources": "Privat", "resourcesTableClientResources": "Privat",
"resourcesTableNoProxyResourcesFound": "Keine Proxy-Ressourcen gefunden.", "resourcesTableNoProxyResourcesFound": "Keine Proxy-Ressourcen gefunden.",
"resourcesTableNoInternalResourcesFound": "Keine internen Ressourcen gefunden.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Ziel", "resourcesTableDestination": "Ziel",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias-Adresse", "resourcesTableAliasAddress": "Alias-Adresse",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Abbrechen", "editInternalResourceDialogCancel": "Abbrechen",
"editInternalResourceDialogSaveResource": "Ressource speichern", "editInternalResourceDialogSaveResource": "Ressource speichern",
"editInternalResourceDialogSuccess": "Erfolg", "editInternalResourceDialogSuccess": "Erfolg",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne Ressource erfolgreich aktualisiert", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Fehler", "editInternalResourceDialogError": "Fehler",
"editInternalResourceDialogFailedToUpdateInternalResource": "Interne Ressource konnte nicht aktualisiert werden", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Name ist erforderlich", "editInternalResourceDialogNameRequired": "Name ist erforderlich",
"editInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein", "editInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
"editInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein", "editInternalResourceDialogProxyPortMin": "Proxy-Port muss mindestens 1 sein",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.", "editInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.",
"createInternalResourceDialogNoSitesAvailable": "Kein Standort verfügbar", "createInternalResourceDialogNoSitesAvailable": "Kein Standort verfügbar",
"createInternalResourceDialogNoSitesAvailableDescription": "Sie müssen mindestens ein Newt-Standort mit einem konfigurierten Subnetz haben, um interne Ressourcen zu erstellen.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Schließen", "createInternalResourceDialogClose": "Schließen",
"createInternalResourceDialogCreateClientResource": "Private Ressource erstellen", "createInternalResourceDialogCreateClientResource": "Private Ressource erstellen",
"createInternalResourceDialogCreateClientResourceDescription": "Erstelle eine neue Ressource, die nur für Clients zugänglich ist, die mit der Organisation verbunden sind", "createInternalResourceDialogCreateClientResourceDescription": "Erstelle eine neue Ressource, die nur für Clients zugänglich ist, die mit der Organisation verbunden sind",
"privateResourceGeneralDescription": "Konfigurieren Sie den Namen, die Kennung und andere allgemeine Ressourceneinstellungen.",
"privateResourceCreatePageSeeAll": "Alle privaten Ressourcen anzeigen",
"privateResourceAllowIcmpPing": "ICMP-Ping zulassen",
"privateResourceNetworkAccess": "Netzwerkzugriff",
"privateResourceNetworkAccessDescription": "TCP/UDP-Portzugriff kontrollieren und ICMP-Ping für diese Ressource zulassen.",
"hostSettings": "Host-Einstellungen",
"cidrSettings": "CIDR-Einstellungen",
"createInternalResourceDialogResourceProperties": "Ressourceneigenschaften", "createInternalResourceDialogResourceProperties": "Ressourceneigenschaften",
"createInternalResourceDialogName": "Name", "createInternalResourceDialogName": "Name",
"createInternalResourceDialogSite": "Standort", "createInternalResourceDialogSite": "Standort",
"selectSite": "Standort auswählen...", "selectSite": "Standort auswählen...",
"multiSitesSelectorSitesCount": "{count, plural, one {# Standort} other {# Standorte}}", "multiSitesSelectorSitesCount": "{count, plural, one {# Standort} other {# Standorte}}",
"labelsSelectorLabelsCount": "{count, plural, one {# Etikett} other {# Etiketten}}",
"noSitesFound": "Keine Standorte gefunden.", "noSitesFound": "Keine Standorte gefunden.",
"createInternalResourceDialogProtocol": "Protokoll", "createInternalResourceDialogProtocol": "Protokoll",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Abbrechen", "createInternalResourceDialogCancel": "Abbrechen",
"createInternalResourceDialogCreateResource": "Ressource erstellen", "createInternalResourceDialogCreateResource": "Ressource erstellen",
"createInternalResourceDialogSuccess": "Erfolg", "createInternalResourceDialogSuccess": "Erfolg",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne Ressource erfolgreich erstellt", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Fehler", "createInternalResourceDialogError": "Fehler",
"createInternalResourceDialogFailedToCreateInternalResource": "Interne Ressource konnte nicht erstellt werden", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Name ist erforderlich", "createInternalResourceDialogNameRequired": "Name ist erforderlich",
"createInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein", "createInternalResourceDialogNameMaxLength": "Der Name darf nicht länger als 255 Zeichen sein",
"createInternalResourceDialogPleaseSelectSite": "Bitte wählen Sie einen Standort aus", "createInternalResourceDialogPleaseSelectSite": "Bitte wählen Sie einen Standort aus",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "Der CIDR-Bereich der Ressource im Netzwerk der Website.", "createInternalResourceDialogDestinationCidrDescription": "Der CIDR-Bereich der Ressource im Netzwerk der Website.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.", "createInternalResourceDialogAliasDescription": "Ein optionaler interner DNS-Alias für diese Ressource.",
"internalResourceAliasLocalWarning": "Aliasse, die auf .local enden, können aufgrund von mDNS in einigen Netzwerken zu Auflösungsproblemen führen.",
"internalResourceDownstreamSchemeRequired": "Schema ist für HTTP-Ressourcen erforderlich", "internalResourceDownstreamSchemeRequired": "Schema ist für HTTP-Ressourcen erforderlich",
"internalResourceHttpPortRequired": "Zielport ist für HTTP-Ressourcen erforderlich", "internalResourceHttpPortRequired": "Zielport ist für HTTP-Ressourcen erforderlich",
"siteConfiguration": "Konfiguration", "siteConfiguration": "Konfiguration",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Entfernte Knoten", "sidebarRemoteExitNodes": "Entfernte Knoten",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Geheimnis", "remoteExitNodeSecretKey": "Geheimnis",
"remoteExitNodeNetworkingTitle": "Netzwerkeinstellungen",
"remoteExitNodeNetworkingDescription": "Konfigurieren Sie, wie dieser Remote Exit Node den Datenverkehr leitet und welche Standorte bevorzugt über ihn verbinden. Erweiterte Funktionen zur Verwendung mit Backhaul-Netzwerkkonfigurationen.",
"remoteExitNodeNetworkingSave": "Einstellungen speichern",
"remoteExitNodeNetworkingSaveSuccessTitle": "Netzwerkeinstellungen gespeichert",
"remoteExitNodeNetworkingSaveSuccessDescription": "Netzwerkeinstellungen wurden erfolgreich aktualisiert.",
"remoteExitNodeNetworkingSaveError": "Fehler beim Speichern der Netzwerkeinstellungen",
"remoteExitNodeNetworkingSubnetsTitle": "Remote-Subnetze",
"remoteExitNodeNetworkingSubnetsDescription": "Definieren Sie die CIDR-Bereiche, an die dieser Remote Exit Node den Datenverkehr weiterleitet. Geben Sie einen gültigen CIDR (z. B. <code>10.0.0.0/8</code>) ein und drücken Sie die Eingabetaste, um hinzuzufügen.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Fügen Sie einen CIDR-Bereich hinzu (z.B. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Fehler beim Laden der Subnetze",
"remoteExitNodeNetworkingLabelsTitle": "Präferenzetiketten",
"remoteExitNodeNetworkingLabelsDescription": "Standorte mit diesen Etiketten werden gezwungen, über diesen Remote Exit Node zu verbinden.",
"remoteExitNodeNetworkingLabelsButtonText": "Etiketten auswählen...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Etiketten suchen...",
"remoteExitNodeNetworkingLabelsLoadError": "Fehler beim Laden der Etiketten",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Erstelle Remote Node", "title": "Erstelle Remote Node",
"description": "Erstelle einen neues selbst gehostetes Relay und ihre Proxyserver Nodes", "description": "Erstelle einen neues selbst gehostetes Relay und ihre Proxyserver Nodes",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Für diese Organisation sind keine Knoten verfügbar. Erstellen Sie zuerst einen Knoten, um lokale Standorte zu verwenden.", "noRemoteExitNodesAvailableDescription": "Für diese Organisation sind keine Knoten verfügbar. Erstellen Sie zuerst einen Knoten, um lokale Standorte zu verwenden.",
"exitNode": "Exit-Node", "exitNode": "Exit-Node",
"country": "Land", "country": "Land",
"countryIsNot": "Land ist nicht",
"rulesMatchCountry": "Derzeit basierend auf der Quell-IP", "rulesMatchCountry": "Derzeit basierend auf der Quell-IP",
"region": "Region", "region": "Region",
"selectRegion": "Region wählen...", "selectRegion": "Region wählen...",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC Provider", "idpGoogleDescription": "Google OAuth2/OIDC Provider",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Subnetz", "subnet": "Subnetz",
"utilitySubnet": "Nutzsubnetz",
"subnetDescription": "Das Subnetz für die Netzwerkkonfiguration dieser Organisation.", "subnetDescription": "Das Subnetz für die Netzwerkkonfiguration dieser Organisation.",
"customDomain": "Eigene Domain", "customDomain": "Eigene Domain",
"authPage": "Authentifizierungs-Seiten", "authPage": "Authentifizierungs-Seiten",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Die Zwei-Faktor-Authentifizierung ist erforderlich. Bitte melden Sie sich erneut über {dashboardUrl}/auth/login an. Dann kommen Sie hierher zurück.", "twoFactorSetupRequired": "Die Zwei-Faktor-Authentifizierung ist erforderlich. Bitte melden Sie sich erneut über {dashboardUrl}/auth/login an. Dann kommen Sie hierher zurück.",
"additionalSecurityRequired": "Zusätzliche Sicherheit erforderlich", "additionalSecurityRequired": "Zusätzliche Sicherheit erforderlich",
"organizationRequiresAdditionalSteps": "Diese Organisation erfordert zusätzliche Sicherheitsschritte, bevor Sie auf Ressourcen zugreifen können.", "organizationRequiresAdditionalSteps": "Diese Organisation erfordert zusätzliche Sicherheitsschritte, bevor Sie auf Ressourcen zugreifen können.",
"sessionExpired": "Sitzung abgelaufen",
"sessionExpiredReauthRequired": "Ihre Sitzung ist gemäß der Sicherheitsrichtlinie Ihrer Organisation abgelaufen. Bitte authentifizieren Sie sich erneut, um fortzufahren.",
"reauthenticate": "Neu anmelden",
"completeTheseSteps": "Schließe diese Schritte ab", "completeTheseSteps": "Schließe diese Schritte ab",
"enableTwoFactorAuthentication": "Zwei-Faktor-Authentifizierung aktivieren", "enableTwoFactorAuthentication": "Zwei-Faktor-Authentifizierung aktivieren",
"completeSecuritySteps": "Schließe Sicherheitsschritte ab", "completeSecuritySteps": "Schließe Sicherheitsschritte ab",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Quelladresse", "sourceAddress": "Quelladresse",
"destinationAddress": "Zieladresse", "destinationAddress": "Zieladresse",
"duration": "Dauer", "duration": "Dauer",
"licenseRequiredToUse": "Eine <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> Lizenz oder <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> wird benötigt, um diese Funktion nutzen zu können. <bookADemoLink>Buchen Sie eine Demo oder POC Testversion</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "Die <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> wird benötigt, um diese Funktion nutzen zu können. Diese Funktion ist auch in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>verfügbar. <bookADemoLink>Buchen Sie eine Demo oder POC Testversion</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Zertifikatsauflöser", "certResolver": "Zertifikatsauflöser",
"certResolverDescription": "Wählen Sie den Zertifikatslöser aus, der für diese Ressource verwendet werden soll.", "certResolverDescription": "Wählen Sie den Zertifikatslöser aus, der für diese Ressource verwendet werden soll.",
"selectCertResolver": "Zertifikatsauflöser auswählen", "selectCertResolver": "Zertifikatsauflöser auswählen",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Organisation oder Domänen-ID fehlt", "orgOrDomainIdMissing": "Organisation oder Domänen-ID fehlt",
"loadingDNSRecords": "Lade DNS-Einträge...", "loadingDNSRecords": "Lade DNS-Einträge...",
"olmUpdateAvailableInfo": "Eine aktualisierte Version von Olm ist verfügbar. Bitte aktualisieren Sie auf die neueste Version für die beste Erfahrung.", "olmUpdateAvailableInfo": "Eine aktualisierte Version von Olm ist verfügbar. Bitte aktualisieren Sie auf die neueste Version für die beste Erfahrung.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Eine aktualisierte Version ist verfügbar. Bitte aktualisieren Sie auf die neueste Version für das beste Erlebnis.",
"client": "Client", "client": "Client",
"proxyProtocol": "Proxy-Protokoll-Einstellungen", "proxyProtocol": "Proxy-Protokoll-Einstellungen",
"proxyProtocolDescription": "Konfigurieren Sie das Proxy-Protokoll, um die IP-Adressen des Clients für TCP-Dienste zu erhalten.", "proxyProtocolDescription": "Konfigurieren Sie das Proxy-Protokoll, um die IP-Adressen des Clients für TCP-Dienste zu erhalten.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Nutzer hinzufügen", "editInternalResourceDialogAddUsers": "Nutzer hinzufügen",
"editInternalResourceDialogAddClients": "Clients hinzufügen", "editInternalResourceDialogAddClients": "Clients hinzufügen",
"editInternalResourceDialogDestinationLabel": "Ziel", "editInternalResourceDialogDestinationLabel": "Ziel",
"editInternalResourceDialogDestinationDescription": "Geben Sie die Zieladresse für die interne Ressource an. Dies kann ein Hostname, eine IP-Adresse oder ein CIDR-Bereich sein, abhängig vom gewählten Modus. Legen Sie optional einen internen DNS-Alias für eine vereinfachte Identifizierung fest.", "editInternalResourceDialogDestinationDescription": "Konfigurieren Sie, wie Clients diese Ressource erreichen.",
"internalResourceFormMultiSiteRoutingHelp": "Durch die Auswahl mehrerer Seiten wird ein ausfallsicheres Routing und Failover für hohe Verfügbarkeit ermöglicht.", "internalResourceFormMultiSiteRoutingHelp": "Durch die Auswahl mehrerer Seiten wird ein ausfallsicheres Routing und Failover für hohe Verfügbarkeit ermöglicht.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Mehr erfahren", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Mehr erfahren",
"editInternalResourceDialogPortRestrictionsDescription": "Den Zugriff auf bestimmte TCP/UDP-Ports beschränken oder alle Ports erlauben/blockieren.", "editInternalResourceDialogPortRestrictionsDescription": "Den Zugriff auf bestimmte TCP/UDP-Ports beschränken oder alle Ports erlauben/blockieren.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "E-Mail-Whitelist", "memberPortalEmailWhitelist": "E-Mail-Whitelist",
"memberPortalResourceDisabled": "Ressource deaktiviert", "memberPortalResourceDisabled": "Ressource deaktiviert",
"memberPortalShowingResources": "Zeige {start}-{end} von {total} Ressourcen", "memberPortalShowingResources": "Zeige {start}-{end} von {total} Ressourcen",
"resourceLauncherTitle": "Ressourcenstarter",
"resourceSidebarLauncherTitle": "Launcher",
"resourceLauncherDescription": "Alle verfügbaren Ressourcen anzeigen und von einem zentralen Hub aus starten",
"resourceLauncherSearchPlaceholder": "Suche deine Ressourcen...",
"resourceLauncherDefaultView": "Standard",
"resourceLauncherSaveView": "Ansicht speichern",
"resourceLauncherSaveToCurrentView": "In aktueller Ansicht speichern",
"resourceLauncherSaveDefaultPersonal": "Für mich speichern",
"resourceLauncherResetView": "Ansicht zurücksetzen",
"resourceLauncherResetSystemDefault": "Auf Systemeinstellung zurücksetzen",
"resourceLauncherSystemDefaultRestored": "Systemstandard wurde wiederhergestellt",
"resourceLauncherSystemDefaultRestoredDescription": "Die Standardansicht wurde auf die ursprünglichen Einstellungen zurückgesetzt.",
"resourceLauncherSaveAsNewView": "Als neue Ansicht speichern",
"resourceLauncherSaveAsNewViewDescription": "Geben Sie dieser Ansicht einen Namen, um Ihre aktuellen Filter und das Layout zu speichern.",
"resourceLauncherSaveForEveryone": "Für alle speichern",
"resourceLauncherSaveForEveryoneDescription": "Teilen Sie diese Ansicht mit allen Organisationsmitgliedern. Wenn nicht aktiviert, ist die Ansicht nur für Sie sichtbar.",
"resourceLauncherMakePersonal": "Persönlich machen",
"resourceLauncherFilter": "Filter",
"resourceLauncherFilterWithCount": "Filter, {count} angewendet",
"resourceLauncherSort": "Sortieren",
"resourceLauncherSortAscending": "Aufsteigend sortieren",
"resourceLauncherSortDescending": "Absteigend sortieren",
"resourceLauncherSettings": "Einstellungen",
"resourceLauncherGroupBy": "Gruppieren nach",
"resourceLauncherGroupBySite": "Standort",
"resourceLauncherGroupByLabel": "Etikett",
"resourceLauncherGroupByNone": "Keine",
"resourceLauncherLayout": "Layout",
"resourceLauncherLayoutGrid": "Raster",
"resourceLauncherLayoutList": "Liste",
"resourceLauncherShowLabels": "Etiketten anzeigen",
"resourceLauncherShowSiteTags": "Standort-Tags anzeigen",
"resourceLauncherShowRecents": "Kürzlich anzeigen",
"resourceLauncherDeleteView": "Ansicht löschen",
"resourceLauncherDeleteViewTitle": "Ansicht löschen",
"resourceLauncherDeleteViewQuestion": "Sind Sie sicher, dass Sie diese Launcher-Ansicht löschen möchten?",
"resourceLauncherDeleteViewConfirm": "Ansicht löschen",
"resourceLauncherViewAsAdmin": "Ansicht als Administrator anzeigen",
"resourceLauncherResourceDetailsDescription": "Verbindungsinformationen und Status für diese Ressource.",
"resourceLauncherResourceDetails": "Ressourcendetails",
"resourceLauncherAuthMethodsDescription": "Aktivierte Authentifizierungsmethoden für diese Ressource.",
"resourceLauncherPrivateClientRequired": "Verbinde dich mit einem Client auf deinem Gerät, um privat auf diese Ressource zuzugreifen.",
"resourceLauncherPrivateClientRequiredTitle": "Client-Verbindung erforderlich",
"resourceLauncherDownloadClient": "Client herunterladen",
"resourceLauncherFailedToLoadDetails": "Ressourcendetails konnten nicht geladen werden. Möglicherweise haben Sie keinen Zugriff mehr auf diese Ressource.",
"resourceLauncherNoPortRestrictions": "Keine Portbeschränkungen",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Nicht etikettiert",
"resourceLauncherNoSite": "Kein Standort",
"resourceLauncherNoResourcesInGroup": "Keine Ressourcen in dieser Gruppe",
"resourceLauncherEmptyStateTitle": "Keine Ressourcen verfügbar",
"resourceLauncherEmptyStateDescription": "Sie haben noch keinen Zugriff auf Ressourcen. Kontaktieren Sie Ihren Administrator, um Zugriff anzufordern.",
"resourceLauncherEmptyStateNoResultsTitle": "Keine Ressourcen gefunden",
"resourceLauncherEmptyStateNoResultsDescription": "Keine Ressourcen entsprechen Ihrer aktuellen Suche oder den Filtern. Versuchen Sie, diese anzupassen, um zu finden, wonach Sie suchen.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Keine Ressourcen entsprechen \"{query}\". Versuchen Sie, Ihre Suche anzupassen oder die Filter zu löschen, um alle Ressourcen anzuzeigen.",
"resourceLauncherSearchFirstTitle": "Suchen oder Filtern zum Durchsuchen",
"resourceLauncherSearchFirstDescription": "Sie haben Zugriff auf viele Ressourcen. Verwenden Sie die Suche oder filtern Sie nach Websites oder Labels, um das zu finden, was Sie brauchen.",
"resourceLauncherSiteGroupingDisabled": "Website-Gruppierung ist in diesem Maßstab nicht verfügbar. Filtern Sie nach Standort, um eine kleinere Gruppe zu bilden.",
"resourceLauncherLabelGroupingDisabled": "Label-Gruppierung ist in diesem Maßstab nicht verfügbar.",
"resourceLauncherCompactModeHint": "Vereinfachte Liste für schnelleres Durchsuchen anzeigen. Verwenden Sie Suche oder Filter, um die Ergebnisse einzugrenzen.",
"resourceLauncherCompactGroupingHint": "Treffen Sie Standort- oder Labelfilter an, um Gruppierungen zu aktivieren.",
"resourceLauncherCopiedToClipboard": "In die Zwischenablage kopiert",
"resourceLauncherCopiedAccessDescription": "Der Ressourcenzugriff wurde in Ihre Zwischenablage kopiert.",
"resourceLauncherViewNamePlaceholder": "Ansichtsname",
"resourceLauncherViewNameLabel": "Ansichtsname",
"resourceLauncherViewSaved": "Ansicht gespeichert",
"resourceLauncherViewSavedDescription": "Ihre Startansicht wurde gespeichert.",
"resourceLauncherViewSaveFailed": "Fehler beim Speichern der Ansicht",
"resourceLauncherViewSaveFailedDescription": "Die Startansicht konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.",
"resourceLauncherViewDeleted": "Ansicht gelöscht",
"resourceLauncherViewDeletedDescription": "Die Startansicht wurde gelöscht.",
"resourceLauncherViewDeleteFailed": "Fehler beim Löschen der Ansicht",
"resourceLauncherViewDeleteFailedDescription": "Die Startansicht konnte nicht gelöscht werden. Bitte versuchen Sie es erneut.",
"memberPortalPrevious": "Vorherige", "memberPortalPrevious": "Vorherige",
"memberPortalNext": "Nächste", "memberPortalNext": "Nächste",
"httpSettings": "HTTP-Einstellungen", "httpSettings": "HTTP-Einstellungen",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "Privater Schlüssel ist erforderlich", "sshPrivateKeyRequired": "Privater Schlüssel ist erforderlich",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Geben Sie Ihr VNC-Passwort ein, um sich zu verbinden", "vncSignInDescription": "Geben Sie Ihre VNC-Zugangsdaten ein, um sich zu verbinden",
"vncUsernameOptional": "Benutzername (optional)",
"vncPasswordOptional": "Passwort (optional)", "vncPasswordOptional": "Passwort (optional)",
"vncNoResourceTarget": "Kein Ressourcen-Ziel verfügbar", "vncNoResourceTarget": "Kein Ressourcen-Ziel verfügbar",
"vncFailedToLoadNovnc": "Fehler beim Laden von noVNC", "vncFailedToLoadNovnc": "Fehler beim Laden von noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Upload fehlgeschlagen", "rdpUploadFailed": "Upload fehlgeschlagen",
"rdpUnicodeKeyboardMode": "Unicode-Tastaturmodus", "rdpUnicodeKeyboardMode": "Unicode-Tastaturmodus",
"sessionToolbarShow": "Werkzeugleiste zeigen", "sessionToolbarShow": "Werkzeugleiste zeigen",
"sessionToolbarHide": "Werkzeugleiste ausblenden" "sessionToolbarHide": "Werkzeugleiste ausblenden",
"actionUpdateSiteApprovals": "Standortgenehmigungen aktualisieren"
} }
+232 -14
View File
@@ -123,6 +123,16 @@
"siteUpdated": "Site updated", "siteUpdated": "Site updated",
"siteUpdatedDescription": "The site has been updated.", "siteUpdatedDescription": "The site has been updated.",
"siteGeneralDescription": "Configure the general settings for this site", "siteGeneralDescription": "Configure the general settings for this site",
"siteRestartTitle": "Restart Site",
"siteRestartDescription": "Restart the WireGuard tunnel for this site. This will briefly interrupt connectivity.",
"siteRestartBody": "Use this if the site tunnel is not functioning correctly and you want to force a reconnect without restarting the host.",
"siteRestartButton": "Restart Site",
"siteRestartDialogMessage": "Are you sure you want to restart the WireGuard tunnel for <b>{name}</b>? The site will briefly lose connectivity.",
"siteRestartWarning": "The site will briefly disconnect while the tunnel restarts.",
"siteRestarted": "Site restarted",
"siteRestartedDescription": "The WireGuard tunnel has been restarted.",
"siteErrorRestart": "Failed to restart site",
"siteErrorRestartDescription": "An error occurred while restarting the site.",
"siteSettingDescription": "Configure the settings on the site", "siteSettingDescription": "Configure the settings on the site",
"siteResourcesTab": "Resources", "siteResourcesTab": "Resources",
"siteResourcesNoneOnSite": "This site has no public or private resources yet.", "siteResourcesNoneOnSite": "This site has no public or private resources yet.",
@@ -168,7 +178,7 @@
"shareDeleteConfirm": "Confirm Delete Shareable Link", "shareDeleteConfirm": "Confirm Delete Shareable Link",
"shareQuestionRemove": "Are you sure you want to delete this share link?", "shareQuestionRemove": "Are you sure you want to delete this share link?",
"shareMessageRemove": "Once deleted, the link will no longer work and anyone using it will lose access to the resource.", "shareMessageRemove": "Once deleted, the link will no longer work and anyone using it will lose access to the resource.",
"shareTokenDescription": "The access token can be passed in two ways: as a query parameter or in the request headers. These must be passed from the client on every request for authenticated access.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Access Token", "accessToken": "Access Token",
"usageExamples": "Usage Examples", "usageExamples": "Usage Examples",
"tokenId": "Token ID", "tokenId": "Token ID",
@@ -186,8 +196,14 @@
"shareTitleOptional": "Title (optional)", "shareTitleOptional": "Title (optional)",
"sharePathOptional": "Path (optional)", "sharePathOptional": "Path (optional)",
"sharePathDescription": "The link will redirect users to this path after authentication.", "sharePathDescription": "The link will redirect users to this path after authentication.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Expire In", "expireIn": "Expire In",
"neverExpire": "Never expire", "neverExpire": "Never expire",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Expiration time is how long the link will be usable and provide access to the resource. After this time, the link will no longer work, and users who used this link will lose access to the resource.", "shareExpireDescription": "Expiration time is how long the link will be usable and provide access to the resource. After this time, the link will no longer work, and users who used this link will lose access to the resource.",
"shareSeeOnce": "You will only be able to see this link once. Make sure to copy it.", "shareSeeOnce": "You will only be able to see this link once. Make sure to copy it.",
"shareAccessHint": "Anyone with this link can access the resource. Share it with care.", "shareAccessHint": "Anyone with this link can access the resource. Share it with care.",
@@ -256,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy requests over raw TCP/UDP using a port number. Requires sites to connect to a remote node.", "resourceRawDescriptionCloud": "Proxy requests over raw TCP/UDP using a port number. Requires sites to connect to a remote node.",
"resourceCreate": "Create Resource", "resourceCreate": "Create Resource",
"resourceCreateDescription": "Follow the steps below to create a new resource", "resourceCreateDescription": "Follow the steps below to create a new resource",
"resourcePublicCreate": "Create Public Resource",
"resourcePublicCreateDescription": "Follow the steps below to create a new public resource that is accessible through a web browser",
"resourceCreateGeneralDescription": "Configure the basic resource settings including the name and the type", "resourceCreateGeneralDescription": "Configure the basic resource settings including the name and the type",
"resourceSeeAll": "See All Resources", "resourceSeeAll": "See All Resources",
"resourceCreateGeneral": "General", "resourceCreateGeneral": "General",
@@ -437,8 +455,14 @@
"provisioningManage": "Provisioning", "provisioningManage": "Provisioning",
"provisioningDescription": "Manage provisioning keys and review pending sites awaiting approval.", "provisioningDescription": "Manage provisioning keys and review pending sites awaiting approval.",
"pendingSites": "Pending Sites", "pendingSites": "Pending Sites",
"siteApproveSuccess": "Site approved successfully", "siteApproveSuccess": "Site and associated resources approved successfully",
"siteApproveError": "Error approving site", "siteApproveError": "Error approving site",
"siteReject": "Reject Site",
"siteQuestionReject": "Are you sure you want to reject this site?",
"siteMessageReject": "This will permanently delete the site and any associated resources that are still pending.",
"siteConfirmReject": "Confirm Reject Site",
"siteRejectSuccess": "Site rejected successfully",
"siteRejectError": "Error rejecting site",
"provisioningKeys": "Provisioning Keys", "provisioningKeys": "Provisioning Keys",
"searchProvisioningKeys": "Search provisioning keys...", "searchProvisioningKeys": "Search provisioning keys...",
"provisioningKeysAdd": "Generate Provisioning Key", "provisioningKeysAdd": "Generate Provisioning Key",
@@ -454,12 +478,12 @@
"provisioningKeysSave": "Save the provisioning key", "provisioningKeysSave": "Save the provisioning key",
"provisioningKeysSaveDescription": "You will only be able to see this once. Copy it to a secure place.", "provisioningKeysSaveDescription": "You will only be able to see this once. Copy it to a secure place.",
"provisioningKeysErrorCreate": "Error creating provisioning key", "provisioningKeysErrorCreate": "Error creating provisioning key",
"provisioningKeysList": "New provisioning key", "provisioningKeysList": "New Provisioning Key",
"provisioningKeysMaxBatchSize": "Max batch size", "provisioningKeysMaxBatchSize": "Max Batch Size",
"provisioningKeysUnlimitedBatchSize": "Unlimited batch size (no limit)", "provisioningKeysUnlimitedBatchSize": "Unlimited batch size (no limit)",
"provisioningKeysMaxBatchUnlimited": "Unlimited", "provisioningKeysMaxBatchUnlimited": "Unlimited",
"provisioningKeysMaxBatchSizeInvalid": "Enter a valid max batch size (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Enter a valid max batch size (11,000,000).",
"provisioningKeysValidUntil": "Valid until", "provisioningKeysValidUntil": "Valid Until",
"provisioningKeysValidUntilHint": "Leave empty for no expiration.", "provisioningKeysValidUntilHint": "Leave empty for no expiration.",
"provisioningKeysValidUntilInvalid": "Enter a valid date and time.", "provisioningKeysValidUntilInvalid": "Enter a valid date and time.",
"provisioningKeysNumUsed": "Times used", "provisioningKeysNumUsed": "Times used",
@@ -468,7 +492,7 @@
"provisioningKeysNeverUsed": "Never", "provisioningKeysNeverUsed": "Never",
"provisioningKeysEdit": "Edit Provisioning Key", "provisioningKeysEdit": "Edit Provisioning Key",
"provisioningKeysEditDescription": "Update the max batch size and expiration time for this key.", "provisioningKeysEditDescription": "Update the max batch size and expiration time for this key.",
"provisioningKeysApproveNewSites": "Approve new sites", "provisioningKeysApproveNewSites": "Approve New Sites",
"provisioningKeysApproveNewSitesDescription": "Automatically approve sites that register with this key.", "provisioningKeysApproveNewSitesDescription": "Automatically approve sites that register with this key.",
"provisioningKeysUpdateError": "Error updating provisioning key", "provisioningKeysUpdateError": "Error updating provisioning key",
"provisioningKeysUpdated": "Provisioning key updated", "provisioningKeysUpdated": "Provisioning key updated",
@@ -603,7 +627,8 @@
"idpNameInternal": "Internal", "idpNameInternal": "Internal",
"emailInvalid": "Invalid email address", "emailInvalid": "Invalid email address",
"inviteValidityDuration": "Please select a duration", "inviteValidityDuration": "Please select a duration",
"accessRoleSelectPlease": "Please select a role", "accessRoleSelectPlease": "A user must belong to at least one role.",
"accessRoleRequired": "Role required",
"removeOwnAdminRoleConfirmTitle": "Remove your administrator access?", "removeOwnAdminRoleConfirmTitle": "Remove your administrator access?",
"removeOwnAdminRoleConfirmDescription": "You will no longer have administrator permissions in this organization after saving. Another administrator can restore access if needed.", "removeOwnAdminRoleConfirmDescription": "You will no longer have administrator permissions in this organization after saving. Another administrator can restore access if needed.",
"removeOwnAdminRoleConfirmButton": "Remove My Administrator Access", "removeOwnAdminRoleConfirmButton": "Remove My Administrator Access",
@@ -854,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Basic Header Auth", "policyAuthHeaderAuthTitle": "Basic Header Auth",
"policyAuthHeaderAuthDescription": "Validate a custom HTTP header name and value on each request", "policyAuthHeaderAuthDescription": "Validate a custom HTTP header name and value on each request",
"policyAuthHeaderAuthSummary": "Header configured", "policyAuthHeaderAuthSummary": "Header configured",
"policyAuthHeaderName": "Header name", "policyAuthHeaderName": "Username",
"policyAuthHeaderValue": "Expected value", "policyAuthHeaderValue": "Password",
"policyAuthSetPasscode": "Set Passcode", "policyAuthSetPasscode": "Set Passcode",
"policyAuthSetPincode": "Set PIN Code", "policyAuthSetPincode": "Set PIN Code",
"policyAuthSetEmailWhitelist": "Set Email Whitelist", "policyAuthSetEmailWhitelist": "Set Email Whitelist",
@@ -1384,6 +1409,7 @@
"createOrgUser": "Create Org User", "createOrgUser": "Create Org User",
"actionUpdateOrg": "Update Organization", "actionUpdateOrg": "Update Organization",
"actionRemoveInvitation": "Remove Invitation", "actionRemoveInvitation": "Remove Invitation",
"actionRemoveUserRole": "Remove User Role",
"actionUpdateUser": "Update User", "actionUpdateUser": "Update User",
"actionGetUser": "Get User", "actionGetUser": "Get User",
"actionGetOrgUser": "Get Organization User", "actionGetOrgUser": "Get Organization User",
@@ -1401,10 +1427,13 @@
"actionApplyBlueprint": "Apply Blueprint", "actionApplyBlueprint": "Apply Blueprint",
"actionListBlueprints": "List Blueprints", "actionListBlueprints": "List Blueprints",
"actionGetBlueprint": "Get Blueprint", "actionGetBlueprint": "Get Blueprint",
"actionCreateOrgWideLauncherView": "Create Org-Wide Launcher View",
"setupToken": "Setup Token", "setupToken": "Setup Token",
"setupTokenDescription": "Enter the setup token from the server console.", "setupTokenDescription": "Enter the setup token from the server console.",
"setupTokenRequired": "Setup token is required", "setupTokenRequired": "Setup token is required",
"actionUpdateSite": "Update Site", "actionUpdateSite": "Update Site",
"actionApproveSite": "Approve Site",
"actionRejectSite": "Reject Site",
"actionResetSiteBandwidth": "Reset Organization Bandwidth", "actionResetSiteBandwidth": "Reset Organization Bandwidth",
"actionListSiteRoles": "List Allowed Site Roles", "actionListSiteRoles": "List Allowed Site Roles",
"actionCreateResource": "Create Resource", "actionCreateResource": "Create Resource",
@@ -1420,6 +1449,15 @@
"actionSetResourcePincode": "Set Resource Pincode", "actionSetResourcePincode": "Set Resource Pincode",
"actionSetResourceEmailWhitelist": "Set Resource Email Whitelist", "actionSetResourceEmailWhitelist": "Set Resource Email Whitelist",
"actionGetResourceEmailWhitelist": "Get Resource Email Whitelist", "actionGetResourceEmailWhitelist": "Get Resource Email Whitelist",
"actionGetResourcePolicy": "Get Resource Policy",
"actionUpdateResourcePolicy": "Update Resource Policy",
"actionSetResourcePolicyUsers": "Set Resource Policy Users",
"actionSetResourcePolicyRoles": "Set Resource Policy Roles",
"actionSetResourcePolicyPassword": "Set Resource Policy Password",
"actionSetResourcePolicyPincode": "Set Resource Policy Pincode",
"actionSetResourcePolicyHeaderAuth": "Set Resource Policy Header Authentication",
"actionSetResourcePolicyWhitelist": "Set Resource Policy Email Whitelist",
"actionSetResourcePolicyRules": "Set Resource Policy Rules",
"actionCreateTarget": "Create Target", "actionCreateTarget": "Create Target",
"actionDeleteTarget": "Delete Target", "actionDeleteTarget": "Delete Target",
"actionGetTarget": "Get Target", "actionGetTarget": "Get Target",
@@ -1439,6 +1477,7 @@
"actionGenerateAccessToken": "Generate Access Token", "actionGenerateAccessToken": "Generate Access Token",
"actionDeleteAccessToken": "Delete Access Token", "actionDeleteAccessToken": "Delete Access Token",
"actionListAccessTokens": "List Access Tokens", "actionListAccessTokens": "List Access Tokens",
"actionCreateResourceSessionToken": "Create Resource Session Token",
"actionCreateResourceRule": "Create Resource Rule", "actionCreateResourceRule": "Create Resource Rule",
"actionDeleteResourceRule": "Delete Resource Rule", "actionDeleteResourceRule": "Delete Resource Rule",
"actionListResourceRules": "List Resource Rules", "actionListResourceRules": "List Resource Rules",
@@ -1478,6 +1517,10 @@
"actionListInvitations": "List Invitations", "actionListInvitations": "List Invitations",
"actionExportLogs": "Export Logs", "actionExportLogs": "Export Logs",
"actionViewLogs": "View Logs", "actionViewLogs": "View Logs",
"actionCreateSiteProvisioningKey": "Create Site Provisioning Key",
"actionListSiteProvisioningKeys": "List Site Provisioning Keys",
"actionUpdateSiteProvisioningKey": "Update Site Provisioning Key",
"actionDeleteSiteProvisioningKey": "Delete Site Provisioning Key",
"noneSelected": "None selected", "noneSelected": "None selected",
"orgNotFound2": "No organizations found.", "orgNotFound2": "No organizations found.",
"search": "Search…", "search": "Search…",
@@ -1492,10 +1535,35 @@
"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",
"idpLastUsed": "Last Used",
"otpAuthBack": "Back to Password", "otpAuthBack": "Back to Password",
"navbar": "Navigation Menu", "navbar": "Navigation Menu",
"navbarDescription": "Main navigation menu for the application", "navbarDescription": "Main navigation menu for the application",
"navbarDocsLink": "Documentation", "navbarDocsLink": "Documentation",
"commandPaletteTitle": "Command Palette",
"commandPaletteDescription": "Search for pages, organizations, resources, and actions",
"commandPaletteSearchPlaceholder": "Search pages, resources, actions...",
"commandPaletteNoResults": "No results found.",
"commandPaletteSearching": "Searching...",
"commandPaletteNavigation": "Navigation",
"commandPaletteOrganizations": "Organizations",
"commandPaletteSites": "Sites",
"commandPaletteResources": "Resources",
"commandPaletteUsers": "Users",
"commandPaletteClients": "Machine Clients",
"commandPaletteActions": "Actions",
"commandPaletteCreateSite": "Create Site",
"commandPaletteCreateProxyResource": "Create Public Resource",
"commandPaletteCreatePrivateResource": "Create Private Resource",
"commandPaletteCreateUser": "Create User",
"commandPaletteCreateApiKey": "Create API Key",
"commandPaletteCreateMachineClient": "Create Machine Client",
"commandPaletteCreateAlertRule": "Create Alert Rule",
"commandPaletteCreateIdentityProvider": "Create Identity Provider",
"commandPaletteToggleTheme": "Toggle Theme",
"commandPaletteChooseOrganization": "Choose Organization",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Unable to enable 2FA", "otpErrorEnable": "Unable to enable 2FA",
"otpErrorEnableDescription": "An error occurred while enabling 2FA", "otpErrorEnableDescription": "An error occurred while enabling 2FA",
"otpSetupCheckCode": "Please enter a 6-digit code", "otpSetupCheckCode": "Please enter a 6-digit code",
@@ -1573,6 +1641,45 @@
"sidebarManagement": "Management", "sidebarManagement": "Management",
"sidebarBillingAndLicenses": "Billing & Licenses", "sidebarBillingAndLicenses": "Billing & Licenses",
"sidebarLogsAnalytics": "Analytics", "sidebarLogsAnalytics": "Analytics",
"commandSites": "Sites",
"commandActionModeInfo": "Type \">\" To Open Action Mode",
"commandResources": "Resources",
"commandProxyResources": "Public Resources",
"commandClientResources": "Private Resources",
"commandClients": "Clients",
"commandUserDevices": "User Devices",
"commandMachineClients": "Machine Clients",
"commandDomains": "Domains",
"commandRemoteExitNodes": "Remote Nodes",
"commandTeam": "Team",
"commandUsers": "Users",
"commandRoles": "Roles",
"commandInvitations": "Invitations",
"commandPolicies": "Shared Policies",
"commandResourcePolicies": "Public Resources Policies",
"commandIdentityProviders": "Identity Providers",
"commandApprovals": "Approval Requests",
"commandShareableLinks": "Shareable Links",
"commandOrganization": "Organization",
"commandLogsAndAnalytics": "Logs & Analytics",
"commandLogsAnalytics": "Analytics",
"commandLogsRequest": "HTTP Request Logs",
"commandLogsAccess": "Authentication Logs",
"commandLogsAction": "Admin Action Logs",
"commandLogsConnection": "Network Logs",
"commandLogsStreaming": "Event Streaming",
"commandManagement": "Management",
"commandAlerting": "Alerting",
"commandProvisioning": "Provisioning",
"commandBluePrints": "Blueprints",
"commandApiKeys": "API Keys",
"commandBillingAndLicenses": "Billing & Licenses",
"commandBilling": "Billing",
"commandEnterpriseLicenses": "Licenses",
"commandSettings": "Settings",
"commandLauncher": "Launcher",
"commandResourceLauncher": "Resource Launcher",
"commandSearchResults": "Search Results",
"alertingTitle": "Alerting", "alertingTitle": "Alerting",
"alertingDescription": "Define sources, triggers, and actions for notifications", "alertingDescription": "Define sources, triggers, and actions for notifications",
"alertingRules": "Alert rules", "alertingRules": "Alert rules",
@@ -1904,6 +2011,9 @@
"billingDomains": "Domains", "billingDomains": "Domains",
"billingOrganizations": "Orgs", "billingOrganizations": "Orgs",
"billingRemoteExitNodes": "Remote Nodes", "billingRemoteExitNodes": "Remote Nodes",
"billingPublicResources": "Public Resources",
"billingPrivateResources": "Private Resources",
"billingMachineClients": "Machine Clients",
"billingNoLimitConfigured": "No limit configured", "billingNoLimitConfigured": "No limit configured",
"billingEstimatedPeriod": "Estimated Billing Period", "billingEstimatedPeriod": "Estimated Billing Period",
"billingIncludedUsage": "Included Usage", "billingIncludedUsage": "Included Usage",
@@ -1932,6 +2042,9 @@
"billingUsersInfo": "How many users you can use", "billingUsersInfo": "How many users you can use",
"billingDomainInfo": "How many domains you can use", "billingDomainInfo": "How many domains you can use",
"billingRemoteExitNodesInfo": "How many remote nodes you can use", "billingRemoteExitNodesInfo": "How many remote nodes you can use",
"billingPublicResourcesInfo": "How many public resources you can use",
"billingPrivateResourcesInfo": "How many private resources you can use",
"billingMachineClientsInfo": "How many machine clients you can use",
"billingLicenseKeys": "License Keys", "billingLicenseKeys": "License Keys",
"billingLicenseKeysDescription": "Manage your license key subscriptions", "billingLicenseKeysDescription": "Manage your license key subscriptions",
"billingLicenseSubscription": "License Subscription", "billingLicenseSubscription": "License Subscription",
@@ -2077,6 +2190,7 @@
"subnetPlaceholder": "Subnet", "subnetPlaceholder": "Subnet",
"addressDescription": "The internal address of the client. Must fall within the organization's subnet.", "addressDescription": "The internal address of the client. Must fall within the organization's subnet.",
"selectSites": "Select sites", "selectSites": "Select sites",
"selectLabels": "Select labels",
"sitesDescription": "The client will have connectivity to the selected sites", "sitesDescription": "The client will have connectivity to the selected sites",
"clientInstallOlm": "Install Machine Client", "clientInstallOlm": "Install Machine Client",
"clientInstallOlmDescription": "Install the machine client for your system", "clientInstallOlmDescription": "Install the machine client for your system",
@@ -2299,11 +2413,19 @@
"createInternalResourceDialogClose": "Close", "createInternalResourceDialogClose": "Close",
"createInternalResourceDialogCreateClientResource": "Create Private Resource", "createInternalResourceDialogCreateClientResource": "Create Private Resource",
"createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will only be accessible to clients connected to the organization", "createInternalResourceDialogCreateClientResourceDescription": "Create a new resource that will only be accessible to clients connected to the organization",
"privateResourceGeneralDescription": "Configure the name, identifier, and other general resource settings.",
"privateResourceCreatePageSeeAll": "See All Private Resources",
"privateResourceAllowIcmpPing": "Allow ICMP Ping",
"privateResourceNetworkAccess": "Network Access",
"privateResourceNetworkAccessDescription": "Control TCP/UDP port access and whether ICMP ping is allowed for this resource.",
"hostSettings": "Host Settings",
"cidrSettings": "CIDR Settings",
"createInternalResourceDialogResourceProperties": "Resource Properties", "createInternalResourceDialogResourceProperties": "Resource Properties",
"createInternalResourceDialogName": "Name", "createInternalResourceDialogName": "Name",
"createInternalResourceDialogSite": "Site", "createInternalResourceDialogSite": "Site",
"selectSite": "Select site...", "selectSite": "Select site...",
"multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}", "multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}",
"labelsSelectorLabelsCount": "{count, plural, one {# label} other {# labels}}",
"noSitesFound": "No sites found.", "noSitesFound": "No sites found.",
"createInternalResourceDialogProtocol": "Protocol", "createInternalResourceDialogProtocol": "Protocol",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2378,6 +2500,21 @@
"sidebarRemoteExitNodes": "Remote Nodes", "sidebarRemoteExitNodes": "Remote Nodes",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Secret", "remoteExitNodeSecretKey": "Secret",
"remoteExitNodeNetworkingTitle": "Network Settings",
"remoteExitNodeNetworkingDescription": "Configure how this remote exit node routes traffic and which sites prefer to connect through it. Advanced features to be used with backhaul networking configurations.",
"remoteExitNodeNetworkingSave": "Save Settings",
"remoteExitNodeNetworkingSaveSuccessTitle": "Network settings saved",
"remoteExitNodeNetworkingSaveSuccessDescription": "Network settings have been updated successfully.",
"remoteExitNodeNetworkingSaveError": "Failed to save network settings",
"remoteExitNodeNetworkingSubnetsTitle": "Remote Subnets",
"remoteExitNodeNetworkingSubnetsDescription": "Define the CIDR ranges that this remote exit node will route traffic to. Type a valid CIDR (e.g. <code>10.0.0.0/8</code>) and press Enter to add.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Add a CIDR range (e.g. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Failed to load subnets",
"remoteExitNodeNetworkingLabelsTitle": "Preference Labels",
"remoteExitNodeNetworkingLabelsDescription": "Sites with these labels will be enforced to connect through this remote exit node.",
"remoteExitNodeNetworkingLabelsButtonText": "Select labels...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Search labels...",
"remoteExitNodeNetworkingLabelsLoadError": "Failed to load labels",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Create Remote Node", "title": "Create Remote Node",
"description": "Create a new self-hosted remote relay and proxy server node", "description": "Create a new self-hosted remote relay and proxy server node",
@@ -2431,6 +2568,7 @@
"noRemoteExitNodesAvailableDescription": "No nodes are available for this organization. Create a node first to use local sites.", "noRemoteExitNodesAvailableDescription": "No nodes are available for this organization. Create a node first to use local sites.",
"exitNode": "Exit Node", "exitNode": "Exit Node",
"country": "Country", "country": "Country",
"countryIsNot": "Country Is Not",
"rulesMatchCountry": "Currently based on source IP", "rulesMatchCountry": "Currently based on source IP",
"region": "Region", "region": "Region",
"selectRegion": "Select region", "selectRegion": "Select region",
@@ -2556,6 +2694,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC provider", "idpGoogleDescription": "Google OAuth2/OIDC provider",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Subnet", "subnet": "Subnet",
"utilitySubnet": "Utility Subnet",
"subnetDescription": "The subnet for this organization's network configuration.", "subnetDescription": "The subnet for this organization's network configuration.",
"customDomain": "Custom Domain", "customDomain": "Custom Domain",
"authPage": "Authentication Pages", "authPage": "Authentication Pages",
@@ -2639,6 +2778,9 @@
"twoFactorSetupRequired": "Two-factor authentication setup is required. Please log in again via {dashboardUrl}/auth/login complete this step. Then, come back here.", "twoFactorSetupRequired": "Two-factor authentication setup is required. Please log in again via {dashboardUrl}/auth/login complete this step. Then, come back here.",
"additionalSecurityRequired": "Additional Security Required", "additionalSecurityRequired": "Additional Security Required",
"organizationRequiresAdditionalSteps": "This organization requires additional security steps before you can access resources.", "organizationRequiresAdditionalSteps": "This organization requires additional security steps before you can access resources.",
"sessionExpired": "Session Expired",
"sessionExpiredReauthRequired": "Your session has expired per your organization's security policy. Please re-authenticate to continue.",
"reauthenticate": "Re-authenticate",
"completeTheseSteps": "Complete these steps", "completeTheseSteps": "Complete these steps",
"enableTwoFactorAuthentication": "Enable two-factor authentication", "enableTwoFactorAuthentication": "Enable two-factor authentication",
"completeSecuritySteps": "Complete Security Steps", "completeSecuritySteps": "Complete Security Steps",
@@ -2953,8 +3095,8 @@
"sourceAddress": "Source Address", "sourceAddress": "Source Address",
"destinationAddress": "Destination Address", "destinationAddress": "Destination Address",
"duration": "Duration", "duration": "Duration",
"licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Certificate Resolver", "certResolver": "Certificate Resolver",
"certResolverDescription": "Select the certificate resolver to use for this resource.", "certResolverDescription": "Select the certificate resolver to use for this resource.",
"selectCertResolver": "Select Certificate Resolver", "selectCertResolver": "Select Certificate Resolver",
@@ -3148,7 +3290,7 @@
"editInternalResourceDialogAddUsers": "Add Users", "editInternalResourceDialogAddUsers": "Add Users",
"editInternalResourceDialogAddClients": "Add Clients", "editInternalResourceDialogAddClients": "Add Clients",
"editInternalResourceDialogDestinationLabel": "Destination", "editInternalResourceDialogDestinationLabel": "Destination",
"editInternalResourceDialogDestinationDescription": "Choose where this resource runs and how clients reach it. Selecting multiple sites will create a high availability resource that can be accessed from any of the selected sites.", "editInternalResourceDialogDestinationDescription": "Configure how clients reach this resource.",
"internalResourceFormMultiSiteRoutingHelp": "Selecting multiple sites enables resilient routing and failover for high availability.", "internalResourceFormMultiSiteRoutingHelp": "Selecting multiple sites enables resilient routing and failover for high availability.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Learn more", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Learn more",
"editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.", "editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.",
@@ -3541,6 +3683,80 @@
"memberPortalEmailWhitelist": "Email Whitelist", "memberPortalEmailWhitelist": "Email Whitelist",
"memberPortalResourceDisabled": "Resource Disabled", "memberPortalResourceDisabled": "Resource Disabled",
"memberPortalShowingResources": "Showing {start}-{end} of {total} resources", "memberPortalShowingResources": "Showing {start}-{end} of {total} resources",
"resourceLauncherTitle": "Resource Launcher",
"resourceSidebarLauncherTitle": "Launcher",
"resourceLauncherDescription": "View all available resources and launch them from one central hub",
"resourceLauncherSearchPlaceholder": "Search your resources...",
"resourceLauncherDefaultView": "Default",
"resourceLauncherSaveView": "Save View",
"resourceLauncherSaveToCurrentView": "Save to Current View",
"resourceLauncherSaveDefaultPersonal": "Save for Me",
"resourceLauncherResetView": "Reset View",
"resourceLauncherResetSystemDefault": "Reset to System Default",
"resourceLauncherSystemDefaultRestored": "System default restored",
"resourceLauncherSystemDefaultRestoredDescription": "The default view has been reset to the original settings.",
"resourceLauncherSaveAsNewView": "Save as New View",
"resourceLauncherSaveAsNewViewDescription": "Give this view a name to save your current filters and layout.",
"resourceLauncherSaveForEveryone": "Save for Everyone",
"resourceLauncherSaveForEveryoneDescription": "Share this view with all organization members. When unchecked, the view is only visible to you.",
"resourceLauncherMakePersonal": "Make Personal",
"resourceLauncherFilter": "Filter",
"resourceLauncherFilterWithCount": "Filter, {count} applied",
"resourceLauncherSort": "Sort",
"resourceLauncherSortAscending": "Sort ascending",
"resourceLauncherSortDescending": "Sort descending",
"resourceLauncherSettings": "Settings",
"resourceLauncherGroupBy": "Group By",
"resourceLauncherGroupBySite": "Site",
"resourceLauncherGroupByLabel": "Label",
"resourceLauncherGroupByNone": "None",
"resourceLauncherLayout": "Layout",
"resourceLauncherLayoutGrid": "Grid",
"resourceLauncherLayoutList": "List",
"resourceLauncherShowLabels": "Show Labels",
"resourceLauncherShowSiteTags": "Show Site Tags",
"resourceLauncherShowRecents": "Show Recents",
"resourceLauncherDeleteView": "Delete View",
"resourceLauncherDeleteViewTitle": "Delete View",
"resourceLauncherDeleteViewQuestion": "Are you sure you want to delete this launcher view?",
"resourceLauncherDeleteViewConfirm": "Delete View",
"resourceLauncherViewAsAdmin": "View as Admin",
"resourceLauncherResourceDetailsDescription": "Connection information and status for this resource.",
"resourceLauncherResourceDetails": "Resource Details",
"resourceLauncherAuthMethodsDescription": "Authentication methods enabled for this resource.",
"resourceLauncherPrivateClientRequired": "Connect with a client on your device to access this resource privately.",
"resourceLauncherPrivateClientRequiredTitle": "Client Connection Required",
"resourceLauncherDownloadClient": "Download client",
"resourceLauncherFailedToLoadDetails": "Could not load resource details. You may no longer have access to this resource.",
"resourceLauncherNoPortRestrictions": "No port restrictions",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Unlabeled",
"resourceLauncherNoSite": "No Site",
"resourceLauncherNoResourcesInGroup": "No resources in this group",
"resourceLauncherEmptyStateTitle": "No Resources Available",
"resourceLauncherEmptyStateDescription": "You don't have access to any resources yet. Contact your administrator to request access.",
"resourceLauncherEmptyStateNoResultsTitle": "No Resources Found",
"resourceLauncherEmptyStateNoResultsDescription": "No resources match your current search or filters. Try adjusting them to find what you are looking for.",
"resourceLauncherEmptyStateNoResultsWithQuery": "No resources match \"{query}\". Try adjusting your search or clearing filters to see all resources.",
"resourceLauncherSearchFirstTitle": "Search or Filter to Browse",
"resourceLauncherSearchFirstDescription": "You have access to many resources. Use search or filter by site or label to find what you need.",
"resourceLauncherSiteGroupingDisabled": "Site grouping is unavailable at this scale. Filter by site to group a smaller set.",
"resourceLauncherLabelGroupingDisabled": "Label grouping is unavailable at this scale.",
"resourceLauncherCompactModeHint": "Showing a simplified list for faster browsing. Use search or filters to narrow results.",
"resourceLauncherCompactGroupingHint": "Apply site or label filters to enable grouping.",
"resourceLauncherCopiedToClipboard": "Copied to clipboard",
"resourceLauncherCopiedAccessDescription": "Resource access has been copied to your clipboard.",
"resourceLauncherViewNamePlaceholder": "View name",
"resourceLauncherViewNameLabel": "View Name",
"resourceLauncherViewSaved": "View saved",
"resourceLauncherViewSavedDescription": "Your launcher view has been saved.",
"resourceLauncherViewSaveFailed": "Failed to save view",
"resourceLauncherViewSaveFailedDescription": "Could not save the launcher view. Please try again.",
"resourceLauncherViewDeleted": "View deleted",
"resourceLauncherViewDeletedDescription": "The launcher view has been deleted.",
"resourceLauncherViewDeleteFailed": "Failed to delete view",
"resourceLauncherViewDeleteFailedDescription": "Could not delete the launcher view. Please try again.",
"memberPortalPrevious": "Previous", "memberPortalPrevious": "Previous",
"memberPortalNext": "Next", "memberPortalNext": "Next",
"httpSettings": "HTTP Settings", "httpSettings": "HTTP Settings",
@@ -3576,7 +3792,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "Private key is required", "sshPrivateKeyRequired": "Private key is required",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Enter your VNC password to connect", "vncSignInDescription": "Enter your VNC credentials to connect",
"vncUsernameOptional": "Username (optional)",
"vncPasswordOptional": "Password (optional)", "vncPasswordOptional": "Password (optional)",
"vncNoResourceTarget": "No resource target is available", "vncNoResourceTarget": "No resource target is available",
"vncFailedToLoadNovnc": "Failed to load noVNC", "vncFailedToLoadNovnc": "Failed to load noVNC",
@@ -3604,5 +3821,6 @@
"rdpUploadFailed": "Upload failed", "rdpUploadFailed": "Upload failed",
"rdpUnicodeKeyboardMode": "Unicode keyboard mode", "rdpUnicodeKeyboardMode": "Unicode keyboard mode",
"sessionToolbarShow": "Show toolbar", "sessionToolbarShow": "Show toolbar",
"sessionToolbarHide": "Hide toolbar" "sessionToolbarHide": "Hide toolbar",
"actionUpdateSiteApprovals": "Update Site Approvals"
} }
+250 -22
View File
@@ -66,9 +66,15 @@
"local": "Local", "local": "Local",
"edit": "Editar", "edit": "Editar",
"siteConfirmDelete": "Confirmar Borrar Sitio", "siteConfirmDelete": "Confirmar Borrar Sitio",
"siteConfirmDeleteAndResources": "Confirmar eliminación del sitio y recursos",
"siteDelete": "Eliminar sitio", "siteDelete": "Eliminar sitio",
"siteDeleteAndResources": "Eliminar sitio y recursos",
"siteMessageRemove": "Una vez eliminado, el sitio ya no será accesible. Todos los objetivos asociados con el sitio también serán eliminados.", "siteMessageRemove": "Una vez eliminado, el sitio ya no será accesible. Todos los objetivos asociados con el sitio también serán eliminados.",
"siteMessageRemoveAndResources": "Esto eliminará permanentemente todos los recursos públicos y privados vinculados a este sitio, incluso si un recurso también está asociado con otros sitios.",
"siteQuestionRemove": "¿Está seguro que desea eliminar el sitio de la organización?", "siteQuestionRemove": "¿Está seguro que desea eliminar el sitio de la organización?",
"siteQuestionRemoveAndResources": "¿Está seguro de que desea eliminar este sitio y todos los recursos asociados?",
"sitesTableDeleteSite": "Eliminar sitio",
"sitesTableDeleteSiteAndResources": "Eliminar sitio y recursos",
"siteManageSites": "Administrar Sitios", "siteManageSites": "Administrar Sitios",
"siteDescription": "Crear y administrar sitios para permitir la conectividad a redes privadas", "siteDescription": "Crear y administrar sitios para permitir la conectividad a redes privadas",
"sitesBannerTitle": "Conectar cualquier red", "sitesBannerTitle": "Conectar cualquier red",
@@ -117,6 +123,16 @@
"siteUpdated": "Sitio actualizado", "siteUpdated": "Sitio actualizado",
"siteUpdatedDescription": "El sitio ha sido actualizado.", "siteUpdatedDescription": "El sitio ha sido actualizado.",
"siteGeneralDescription": "Configurar la configuración general de este sitio", "siteGeneralDescription": "Configurar la configuración general de este sitio",
"siteRestartTitle": "Reiniciar Sitio",
"siteRestartDescription": "Reinicia el túnel WireGuard para este sitio. Esto interrumpirá brevemente la conectividad.",
"siteRestartBody": "Utiliza esto si el túnel del sitio no está funcionando correctamente y quieres forzar una reconexión sin reiniciar el host.",
"siteRestartButton": "Reiniciar Sitio",
"siteRestartDialogMessage": "¿Estás seguro de que deseas reiniciar el túnel WireGuard para <b>{name}</b>? El sitio perderá conectividad brevemente.",
"siteRestartWarning": "El sitio se desconectará brevemente mientras se reinicia el túnel.",
"siteRestarted": "Sitio reiniciado",
"siteRestartedDescription": "El túnel WireGuard ha sido reiniciado.",
"siteErrorRestart": "Error al reiniciar el sitio",
"siteErrorRestartDescription": "Se ha producido un error al reiniciar el sitio.",
"siteSettingDescription": "Configurar los ajustes en el sitio", "siteSettingDescription": "Configurar los ajustes en el sitio",
"siteResourcesTab": "Recursos", "siteResourcesTab": "Recursos",
"siteResourcesNoneOnSite": "Este sitio aún no tiene recursos públicos o privados.", "siteResourcesNoneOnSite": "Este sitio aún no tiene recursos públicos o privados.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Confirmar Eliminación de Enlace Compartible", "shareDeleteConfirm": "Confirmar Eliminación de Enlace Compartible",
"shareQuestionRemove": "¿Está seguro de que desea borrar este enlace compartido?", "shareQuestionRemove": "¿Está seguro de que desea borrar este enlace compartido?",
"shareMessageRemove": "Una vez borrado, el enlace dejará de funcionar y cualquier persona que lo use perderá acceso al recurso.", "shareMessageRemove": "Una vez borrado, el enlace dejará de funcionar y cualquier persona que lo use perderá acceso al recurso.",
"shareTokenDescription": "El token de acceso puede ser pasado de dos maneras: como parámetro de consulta o en las cabeceras de solicitud. Estos deben ser pasados del cliente en cada solicitud de acceso autenticado.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Token de acceso", "accessToken": "Token de acceso",
"usageExamples": "Ejemplos de uso", "usageExamples": "Ejemplos de uso",
"tokenId": "ID de token", "tokenId": "ID de token",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Título (opcional)", "shareTitleOptional": "Título (opcional)",
"sharePathOptional": "Ruta (opcional)", "sharePathOptional": "Ruta (opcional)",
"sharePathDescription": "El enlace redirigirá a los usuarios a esta ruta tras la autenticación.", "sharePathDescription": "El enlace redirigirá a los usuarios a esta ruta tras la autenticación.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Caduca en", "expireIn": "Caduca en",
"neverExpire": "Nunca expirar", "neverExpire": "Nunca expirar",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "El tiempo de caducidad es cuánto tiempo el enlace será utilizable y proporcionará acceso al recurso. Después de este tiempo, el enlace ya no funcionará, y los usuarios que usaron este enlace perderán el acceso al recurso.", "shareExpireDescription": "El tiempo de caducidad es cuánto tiempo el enlace será utilizable y proporcionará acceso al recurso. Después de este tiempo, el enlace ya no funcionará, y los usuarios que usaron este enlace perderán el acceso al recurso.",
"shareSeeOnce": "Sólo podrás ver este enlace una vez. Asegúrate de copiarlo.", "shareSeeOnce": "Sólo podrás ver este enlace una vez. Asegúrate de copiarlo.",
"shareAccessHint": "Cualquiera con este enlace puede acceder al recurso. Compártelo con cuidado.", "shareAccessHint": "Cualquiera con este enlace puede acceder al recurso. Compártelo con cuidado.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Las peticiones de proxy sobre TCP/UDP crudas usando un número de puerto. Requiere que los sitios se conecten a un nodo remoto.", "resourceRawDescriptionCloud": "Las peticiones de proxy sobre TCP/UDP crudas usando un número de puerto. Requiere que los sitios se conecten a un nodo remoto.",
"resourceCreate": "Crear Recurso", "resourceCreate": "Crear Recurso",
"resourceCreateDescription": "Siga los siguientes pasos para crear un nuevo recurso", "resourceCreateDescription": "Siga los siguientes pasos para crear un nuevo recurso",
"resourcePublicCreate": "Crear recurso público",
"resourcePublicCreateDescription": "Siga los pasos a continuación para crear un nuevo recurso público accesible a través de un navegador web",
"resourceCreateGeneralDescription": "Configurar la configuración básica del recurso, incluido el nombre y el tipo", "resourceCreateGeneralDescription": "Configurar la configuración básica del recurso, incluido el nombre y el tipo",
"resourceSeeAll": "Ver todos los recursos", "resourceSeeAll": "Ver todos los recursos",
"resourceCreateGeneral": "General", "resourceCreateGeneral": "General",
@@ -431,8 +455,14 @@
"provisioningManage": "Aprovisionamiento", "provisioningManage": "Aprovisionamiento",
"provisioningDescription": "Administrar las claves de aprovisionamiento y revisar los sitios pendientes de aprobación.", "provisioningDescription": "Administrar las claves de aprovisionamiento y revisar los sitios pendientes de aprobación.",
"pendingSites": "Sitios pendientes", "pendingSites": "Sitios pendientes",
"siteApproveSuccess": "Sitio aprobado con éxito", "siteApproveSuccess": "Sitio y recursos asociados aprobados correctamente",
"siteApproveError": "Error al aprobar el sitio", "siteApproveError": "Error al aprobar el sitio",
"siteReject": "Rechazar Sitio",
"siteQuestionReject": "¿Está seguro de que desea rechazar este sitio?",
"siteMessageReject": "Esto eliminará permanentemente el sitio y cualquier recurso asociado que aún esté pendiente.",
"siteConfirmReject": "Confirmar Rechazo del Sitio",
"siteRejectSuccess": "Sitio rechazado correctamente",
"siteRejectError": "Error al rechazar el sitio",
"provisioningKeys": "Claves de aprovisionamiento", "provisioningKeys": "Claves de aprovisionamiento",
"searchProvisioningKeys": "Buscar claves de suministro...", "searchProvisioningKeys": "Buscar claves de suministro...",
"provisioningKeysAdd": "Generar clave de aprovisionamiento", "provisioningKeysAdd": "Generar clave de aprovisionamiento",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Guardar la clave de aprovisionamiento", "provisioningKeysSave": "Guardar la clave de aprovisionamiento",
"provisioningKeysSaveDescription": "Sólo podrás verlo una vez. Copítalo a un lugar seguro.", "provisioningKeysSaveDescription": "Sólo podrás verlo una vez. Copítalo a un lugar seguro.",
"provisioningKeysErrorCreate": "Error al crear la clave de provisioning", "provisioningKeysErrorCreate": "Error al crear la clave de provisioning",
"provisioningKeysList": "Nueva clave de aprovisionamiento", "provisioningKeysList": "Nueva Clave de Provisión",
"provisioningKeysMaxBatchSize": "Tamaño máximo de lote", "provisioningKeysMaxBatchSize": "Tamaño Máximo del Lote",
"provisioningKeysUnlimitedBatchSize": "Tamaño ilimitado del lote (sin límite)", "provisioningKeysUnlimitedBatchSize": "Tamaño ilimitado del lote (sin límite)",
"provisioningKeysMaxBatchUnlimited": "Ilimitado", "provisioningKeysMaxBatchUnlimited": "Ilimitado",
"provisioningKeysMaxBatchSizeInvalid": "Introduzca un tamaño máximo de lote válido (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Introduzca un tamaño máximo de lote válido (11,000,000).",
"provisioningKeysValidUntil": "Válido hasta", "provisioningKeysValidUntil": "Válido Hasta",
"provisioningKeysValidUntilHint": "Dejar vacío para no expirar.", "provisioningKeysValidUntilHint": "Dejar vacío para no expirar.",
"provisioningKeysValidUntilInvalid": "Introduzca una fecha y hora válidas.", "provisioningKeysValidUntilInvalid": "Introduzca una fecha y hora válidas.",
"provisioningKeysNumUsed": "Tiempos usados", "provisioningKeysNumUsed": "Tiempos usados",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Nunca", "provisioningKeysNeverUsed": "Nunca",
"provisioningKeysEdit": "Editar clave de aprovisionamiento", "provisioningKeysEdit": "Editar clave de aprovisionamiento",
"provisioningKeysEditDescription": "Actualizar el tamaño máximo de lote y el tiempo de caducidad para esta clave.", "provisioningKeysEditDescription": "Actualizar el tamaño máximo de lote y el tiempo de caducidad para esta clave.",
"provisioningKeysApproveNewSites": "Aprobar nuevos sitios", "provisioningKeysApproveNewSites": "Aprobar Nuevos Sitios",
"provisioningKeysApproveNewSitesDescription": "Aprobar automáticamente los sitios que se registran con esta clave.", "provisioningKeysApproveNewSitesDescription": "Aprobar automáticamente los sitios que se registran con esta clave.",
"provisioningKeysUpdateError": "Error al actualizar la clave de aprovisionamiento", "provisioningKeysUpdateError": "Error al actualizar la clave de aprovisionamiento",
"provisioningKeysUpdated": "Clave de aprovisionamiento actualizada", "provisioningKeysUpdated": "Clave de aprovisionamiento actualizada",
@@ -597,7 +627,8 @@
"idpNameInternal": "Interno", "idpNameInternal": "Interno",
"emailInvalid": "Dirección de correo inválida", "emailInvalid": "Dirección de correo inválida",
"inviteValidityDuration": "Por favor, seleccione una duración", "inviteValidityDuration": "Por favor, seleccione una duración",
"accessRoleSelectPlease": "Por favor, seleccione un rol", "accessRoleSelectPlease": "Un usuario debe pertenecer al menos a un rol.",
"accessRoleRequired": "Rol requerido",
"removeOwnAdminRoleConfirmTitle": "¿Eliminar su acceso de administrador?", "removeOwnAdminRoleConfirmTitle": "¿Eliminar su acceso de administrador?",
"removeOwnAdminRoleConfirmDescription": "Ya no tendrá permisos de administrador en esta organización después de guardar. Otro administrador puede restaurar el acceso si es necesario.", "removeOwnAdminRoleConfirmDescription": "Ya no tendrá permisos de administrador en esta organización después de guardar. Otro administrador puede restaurar el acceso si es necesario.",
"removeOwnAdminRoleConfirmButton": "Eliminar Mi Acceso de Administrador", "removeOwnAdminRoleConfirmButton": "Eliminar Mi Acceso de Administrador",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Autenticación Básica del Encabezado", "policyAuthHeaderAuthTitle": "Autenticación Básica del Encabezado",
"policyAuthHeaderAuthDescription": "Valida un nombre y valor de encabezado HTTP personalizado en cada petición", "policyAuthHeaderAuthDescription": "Valida un nombre y valor de encabezado HTTP personalizado en cada petición",
"policyAuthHeaderAuthSummary": "Encabezado configurado", "policyAuthHeaderAuthSummary": "Encabezado configurado",
"policyAuthHeaderName": "Nombre del encabezado", "policyAuthHeaderName": "Usuario",
"policyAuthHeaderValue": "Valor esperado", "policyAuthHeaderValue": "Contraseña",
"policyAuthSetPasscode": "Establecer Código de Acceso", "policyAuthSetPasscode": "Establecer Código de Acceso",
"policyAuthSetPincode": "Establecer Código PIN", "policyAuthSetPincode": "Establecer Código PIN",
"policyAuthSetEmailWhitelist": "Establecer Lista Blanca de Correo", "policyAuthSetEmailWhitelist": "Establecer Lista Blanca de Correo",
@@ -903,7 +934,7 @@
"newtVersion": "Versión", "newtVersion": "Versión",
"architecture": "Arquitectura", "architecture": "Arquitectura",
"sites": "Sitios", "sites": "Sitios",
"siteWgAnyClients": "Usa cualquier cliente de Wirex para conectarte. Tendrás que dirigirte a los recursos internos usando la IP de compañeros.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Compatible con todos los clientes de Wirex Guard", "siteWgCompatibleAllClients": "Compatible con todos los clientes de Wirex Guard",
"siteWgManualConfigurationRequired": "Configuración manual requerida", "siteWgManualConfigurationRequired": "Configuración manual requerida",
"userErrorNotAdminOrOwner": "El usuario no es un administrador o propietario", "userErrorNotAdminOrOwner": "El usuario no es un administrador o propietario",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Crear usuario Org", "createOrgUser": "Crear usuario Org",
"actionUpdateOrg": "Actualizar organización", "actionUpdateOrg": "Actualizar organización",
"actionRemoveInvitation": "Eliminar invitación", "actionRemoveInvitation": "Eliminar invitación",
"actionRemoveUserRole": "Quitar Rol de Usuario",
"actionUpdateUser": "Actualizar usuario", "actionUpdateUser": "Actualizar usuario",
"actionGetUser": "Obtener usuario", "actionGetUser": "Obtener usuario",
"actionGetOrgUser": "Obtener usuario de la organización", "actionGetOrgUser": "Obtener usuario de la organización",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Aplicar plano", "actionApplyBlueprint": "Aplicar plano",
"actionListBlueprints": "Listar blueprints", "actionListBlueprints": "Listar blueprints",
"actionGetBlueprint": "Obtener blueprint", "actionGetBlueprint": "Obtener blueprint",
"actionCreateOrgWideLauncherView": "Crear Vista de Lanzador para toda la Organización",
"setupToken": "Configuración de token", "setupToken": "Configuración de token",
"setupTokenDescription": "Ingrese el token de configuración desde la consola del servidor.", "setupTokenDescription": "Ingrese el token de configuración desde la consola del servidor.",
"setupTokenRequired": "Se requiere el token de configuración", "setupTokenRequired": "Se requiere el token de configuración",
"actionUpdateSite": "Actualizar sitio", "actionUpdateSite": "Actualizar sitio",
"actionApproveSite": "Aprobar Sitio",
"actionRejectSite": "Rechazar Sitio",
"actionResetSiteBandwidth": "Restablecer ancho de banda de la organización", "actionResetSiteBandwidth": "Restablecer ancho de banda de la organización",
"actionListSiteRoles": "Lista de roles permitidos del sitio", "actionListSiteRoles": "Lista de roles permitidos del sitio",
"actionCreateResource": "Crear Recurso", "actionCreateResource": "Crear Recurso",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Establecer Pincode del recurso", "actionSetResourcePincode": "Establecer Pincode del recurso",
"actionSetResourceEmailWhitelist": "Establecer lista blanca de correo de recursos", "actionSetResourceEmailWhitelist": "Establecer lista blanca de correo de recursos",
"actionGetResourceEmailWhitelist": "Obtener correo electrónico de recursos", "actionGetResourceEmailWhitelist": "Obtener correo electrónico de recursos",
"actionGetResourcePolicy": "Obtener política de recursos",
"actionUpdateResourcePolicy": "Actualizar política de recursos",
"actionSetResourcePolicyUsers": "Definir política de recursos para usuarios",
"actionSetResourcePolicyRoles": "Definir roles de política de recursos",
"actionSetResourcePolicyPassword": "Definir contraseña de política de recursos",
"actionSetResourcePolicyPincode": "Definir Pincode de política de recursos",
"actionSetResourcePolicyHeaderAuth": "Definir autenticación de encabezado de política de recursos",
"actionSetResourcePolicyWhitelist": "Definir lista blanca de correos de política de recursos",
"actionSetResourcePolicyRules": "Definir reglas de política de recursos",
"actionCreateTarget": "Crear destino", "actionCreateTarget": "Crear destino",
"actionDeleteTarget": "Eliminar destino", "actionDeleteTarget": "Eliminar destino",
"actionGetTarget": "Obtener objetivo", "actionGetTarget": "Obtener objetivo",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Generar token de acceso", "actionGenerateAccessToken": "Generar token de acceso",
"actionDeleteAccessToken": "Eliminar token de acceso", "actionDeleteAccessToken": "Eliminar token de acceso",
"actionListAccessTokens": "Lista de Tokens de Acceso", "actionListAccessTokens": "Lista de Tokens de Acceso",
"actionCreateResourceSessionToken": "Crear Token de Sesión de Recurso",
"actionCreateResourceRule": "Crear Regla de Recursos", "actionCreateResourceRule": "Crear Regla de Recursos",
"actionDeleteResourceRule": "Eliminar Regla de Recurso", "actionDeleteResourceRule": "Eliminar Regla de Recurso",
"actionListResourceRules": "Lista de Reglas de Recursos", "actionListResourceRules": "Lista de Reglas de Recursos",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Listar invitaciones", "actionListInvitations": "Listar invitaciones",
"actionExportLogs": "Exportar registros", "actionExportLogs": "Exportar registros",
"actionViewLogs": "Ver registros", "actionViewLogs": "Ver registros",
"actionCreateSiteProvisioningKey": "Crear clave de aprovisionamiento del sitio",
"actionListSiteProvisioningKeys": "Listado de claves de aprovisionamiento del sitio",
"actionUpdateSiteProvisioningKey": "Actualizar clave de aprovisionamiento del sitio",
"actionDeleteSiteProvisioningKey": "Eliminar clave de aprovisionamiento del sitio",
"noneSelected": "Ninguno seleccionado", "noneSelected": "Ninguno seleccionado",
"orgNotFound2": "No se encontraron organizaciones.", "orgNotFound2": "No se encontraron organizaciones.",
"search": "Buscar…", "search": "Buscar…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Último Uso",
"otpAuthBack": "Volver a la contraseña", "otpAuthBack": "Volver a la contraseña",
"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",
"commandPaletteTitle": "Paleta de Comandos",
"commandPaletteDescription": "Buscar páginas, organizaciones, recursos y acciones",
"commandPaletteSearchPlaceholder": "Buscar páginas, recursos, acciones...",
"commandPaletteNoResults": "No se han encontrado resultados.",
"commandPaletteSearching": "Buscando...",
"commandPaletteNavigation": "Navegación",
"commandPaletteOrganizations": "Organizaciones",
"commandPaletteSites": "Sitios",
"commandPaletteResources": "Recursos",
"commandPaletteUsers": "Usuarios",
"commandPaletteClients": "Clientes de Máquina",
"commandPaletteActions": "Acciones",
"commandPaletteCreateSite": "Crear Sitio",
"commandPaletteCreateProxyResource": "Crear recurso público",
"commandPaletteCreatePrivateResource": "Crear recurso privado",
"commandPaletteCreateUser": "Crear Usuario",
"commandPaletteCreateApiKey": "Crear Clave API",
"commandPaletteCreateMachineClient": "Crear Cliente de Máquina",
"commandPaletteCreateAlertRule": "Crear Regla de Alerta",
"commandPaletteCreateIdentityProvider": "Crear proveedor de identidad",
"commandPaletteToggleTheme": "Cambiar tema",
"commandPaletteChooseOrganization": "Elegir organización",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "No se puede habilitar 2FA", "otpErrorEnable": "No se puede habilitar 2FA",
"otpErrorEnableDescription": "Se ha producido un error al habilitar 2FA", "otpErrorEnableDescription": "Se ha producido un error al habilitar 2FA",
"otpSetupCheckCode": "Por favor, introduzca un código de 6 dígitos", "otpSetupCheckCode": "Por favor, introduzca un código de 6 dígitos",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Gestión", "sidebarManagement": "Gestión",
"sidebarBillingAndLicenses": "Facturación y licencias", "sidebarBillingAndLicenses": "Facturación y licencias",
"sidebarLogsAnalytics": "Analíticas", "sidebarLogsAnalytics": "Analíticas",
"commandSites": "Sitios",
"commandActionModeInfo": "Escriba \">\" Para abrir el modo de acción",
"commandResources": "Recursos",
"commandProxyResources": "Recursos Públicos",
"commandClientResources": "Recursos Privados",
"commandClients": "Clientes",
"commandUserDevices": "Dispositivos de Usuario",
"commandMachineClients": "Clientes de Máquina",
"commandDomains": "Dominios",
"commandRemoteExitNodes": "Nodos Remotos",
"commandTeam": "Equipo",
"commandUsers": "Usuarios",
"commandRoles": "Roles",
"commandInvitations": "Invitaciones",
"commandPolicies": "Políticas Compartidas",
"commandResourcePolicies": "Políticas de Recursos Públicos",
"commandIdentityProviders": "Proveedores de identidad",
"commandApprovals": "Solicitudes de Aprobación",
"commandShareableLinks": "Enlaces compartibles",
"commandOrganization": "Organización",
"commandLogsAndAnalytics": "Registros y Análisis",
"commandLogsAnalytics": "Análisis",
"commandLogsRequest": "Registros de Solicitud HTTP",
"commandLogsAccess": "Registros de acceso",
"commandLogsAction": "Registros de acción de administrador",
"commandLogsConnection": "Registros de conexión",
"commandLogsStreaming": "Transmisión de Eventos",
"commandManagement": "Gestión",
"commandAlerting": "Alertas",
"commandProvisioning": "Aprovisionamiento",
"commandBluePrints": "Planos",
"commandApiKeys": "Claves API",
"commandBillingAndLicenses": "Facturación y Licencias",
"commandBilling": "Facturación",
"commandEnterpriseLicenses": "Licencias",
"commandSettings": "Ajustes",
"commandLauncher": "Lanzador",
"commandResourceLauncher": "Lanzador de Recursos",
"commandSearchResults": "Resultados de búsqueda",
"alertingTitle": "Alertas", "alertingTitle": "Alertas",
"alertingDescription": "Definir fuentes, disparadores y acciones para notificaciones", "alertingDescription": "Definir fuentes, disparadores y acciones para notificaciones",
"alertingRules": "Reglas de alerta", "alertingRules": "Reglas de alerta",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Subdominio: {subdomain}", "domainPickerSubdomain": "Subdominio: {subdomain}",
"domainPickerNamespace": "Espacio de nombres: {namespace}", "domainPickerNamespace": "Espacio de nombres: {namespace}",
"domainPickerShowMore": "Mostrar más", "domainPickerShowMore": "Mostrar más",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Seleccionar Región", "regionSelectorTitle": "Seleccionar Región",
"domainPickerRemoteExitNodeWarning": "Los dominios suministrados no son compatibles cuando los sitios se conectan a nodos de salida remotos. Para que los recursos estén disponibles en nodos remotos, utilice un dominio personalizado en su lugar.", "domainPickerRemoteExitNodeWarning": "Los dominios suministrados no son compatibles cuando los sitios se conectan a nodos de salida remotos. Para que los recursos estén disponibles en nodos remotos, utilice un dominio personalizado en su lugar.",
"regionSelectorInfo": "Seleccionar una región nos ayuda a brindar un mejor rendimiento para tu ubicación. No tienes que estar en la misma región que tu servidor.", "regionSelectorInfo": "Seleccionar una región nos ayuda a brindar un mejor rendimiento para tu ubicación. No tienes que estar en la misma región que tu servidor.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Dominios", "billingDomains": "Dominios",
"billingOrganizations": "Orgánico", "billingOrganizations": "Orgánico",
"billingRemoteExitNodes": "Nodos remotos", "billingRemoteExitNodes": "Nodos remotos",
"billingPublicResources": "Recursos Públicos",
"billingPrivateResources": "Recursos Privados",
"billingMachineClients": "Clientes de Máquina",
"billingNoLimitConfigured": "No se ha configurado ningún límite", "billingNoLimitConfigured": "No se ha configurado ningún límite",
"billingEstimatedPeriod": "Período de facturación estimado", "billingEstimatedPeriod": "Período de facturación estimado",
"billingIncludedUsage": "Uso incluido", "billingIncludedUsage": "Uso incluido",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Cuántos usuarios puedes usar", "billingUsersInfo": "Cuántos usuarios puedes usar",
"billingDomainInfo": "Cuántos dominios puedes usar", "billingDomainInfo": "Cuántos dominios puedes usar",
"billingRemoteExitNodesInfo": "Cuántos nodos remotos puedes usar", "billingRemoteExitNodesInfo": "Cuántos nodos remotos puedes usar",
"billingPublicResourcesInfo": "Cuántos recursos públicos puedes usar",
"billingPrivateResourcesInfo": "Cuántos recursos privados puedes usar",
"billingMachineClientsInfo": "Cuántos clientes de máquina puedes usar",
"billingLicenseKeys": "Claves de licencia", "billingLicenseKeys": "Claves de licencia",
"billingLicenseKeysDescription": "Administrar las suscripciones de su clave de licencia", "billingLicenseKeysDescription": "Administrar las suscripciones de su clave de licencia",
"billingLicenseSubscription": "Suscripción de licencia", "billingLicenseSubscription": "Suscripción de licencia",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Subred", "subnetPlaceholder": "Subred",
"addressDescription": "La dirección interna del cliente. Debe estar dentro de la subred de la organización.", "addressDescription": "La dirección interna del cliente. Debe estar dentro de la subred de la organización.",
"selectSites": "Seleccionar sitios", "selectSites": "Seleccionar sitios",
"selectLabels": "Seleccionar etiquetas",
"sitesDescription": "El cliente tendrá conectividad con los sitios seleccionados", "sitesDescription": "El cliente tendrá conectividad con los sitios seleccionados",
"clientInstallOlm": "Instalar Olm", "clientInstallOlm": "Instalar Olm",
"clientInstallOlmDescription": "Obtén Olm funcionando en tu sistema", "clientInstallOlmDescription": "Obtén Olm funcionando en tu sistema",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Público", "resourcesTableProxyResources": "Público",
"resourcesTableClientResources": "Privado", "resourcesTableClientResources": "Privado",
"resourcesTableNoProxyResourcesFound": "No se encontraron recursos de proxy.", "resourcesTableNoProxyResourcesFound": "No se encontraron recursos de proxy.",
"resourcesTableNoInternalResourcesFound": "No se encontraron recursos internos.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Destino", "resourcesTableDestination": "Destino",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Dirección del alias", "resourcesTableAliasAddress": "Dirección del alias",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Cancelar", "editInternalResourceDialogCancel": "Cancelar",
"editInternalResourceDialogSaveResource": "Guardar recurso", "editInternalResourceDialogSaveResource": "Guardar recurso",
"editInternalResourceDialogSuccess": "Éxito", "editInternalResourceDialogSuccess": "Éxito",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno actualizado con éxito", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Error", "editInternalResourceDialogError": "Error",
"editInternalResourceDialogFailedToUpdateInternalResource": "Error al actualizar el recurso interno", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "El nombre es requerido", "editInternalResourceDialogNameRequired": "El nombre es requerido",
"editInternalResourceDialogNameMaxLength": "El nombre no debe tener más de 255 caracteres", "editInternalResourceDialogNameMaxLength": "El nombre no debe tener más de 255 caracteres",
"editInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1", "editInternalResourceDialogProxyPortMin": "El puerto del proxy debe ser al menos 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.", "editInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.",
"createInternalResourceDialogNoSitesAvailable": "No hay sitios disponibles", "createInternalResourceDialogNoSitesAvailable": "No hay sitios disponibles",
"createInternalResourceDialogNoSitesAvailableDescription": "Necesita tener al menos un sitio de Newt con una subred configurada para crear recursos internos.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Cerrar", "createInternalResourceDialogClose": "Cerrar",
"createInternalResourceDialogCreateClientResource": "Crear recurso privado", "createInternalResourceDialogCreateClientResource": "Crear recurso privado",
"createInternalResourceDialogCreateClientResourceDescription": "Crear un nuevo recurso que sólo será accesible a los clientes conectados a la organización", "createInternalResourceDialogCreateClientResourceDescription": "Crear un nuevo recurso que sólo será accesible a los clientes conectados a la organización",
"privateResourceGeneralDescription": "Configura el nombre, identificador y otros ajustes generales del recurso.",
"privateResourceCreatePageSeeAll": "Ver todos los recursos privados",
"privateResourceAllowIcmpPing": "Permitir ping ICMP",
"privateResourceNetworkAccess": "Acceso de red",
"privateResourceNetworkAccessDescription": "Controlar el acceso a puertos TCP/UDP y si se permite ping ICMP para este recurso.",
"hostSettings": "Configuraciones del anfitrión",
"cidrSettings": "Configuraciones CIDR",
"createInternalResourceDialogResourceProperties": "Propiedades del recurso", "createInternalResourceDialogResourceProperties": "Propiedades del recurso",
"createInternalResourceDialogName": "Nombre", "createInternalResourceDialogName": "Nombre",
"createInternalResourceDialogSite": "Sitio", "createInternalResourceDialogSite": "Sitio",
"selectSite": "Seleccionar sitio...", "selectSite": "Seleccionar sitio...",
"multiSitesSelectorSitesCount": "{count, plural, one {# sitio} other {# sitios}}", "multiSitesSelectorSitesCount": "{count, plural, one {# sitio} other {# sitios}}",
"labelsSelectorLabelsCount": "{count, plural, one {# etiqueta} other {# etiquetas}}",
"noSitesFound": "Sitios no encontrados.", "noSitesFound": "Sitios no encontrados.",
"createInternalResourceDialogProtocol": "Protocolo", "createInternalResourceDialogProtocol": "Protocolo",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Cancelar", "createInternalResourceDialogCancel": "Cancelar",
"createInternalResourceDialogCreateResource": "Crear recurso", "createInternalResourceDialogCreateResource": "Crear recurso",
"createInternalResourceDialogSuccess": "Éxito", "createInternalResourceDialogSuccess": "Éxito",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno creado con éxito", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Error", "createInternalResourceDialogError": "Error",
"createInternalResourceDialogFailedToCreateInternalResource": "Error al crear recurso interno", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "El nombre es requerido", "createInternalResourceDialogNameRequired": "El nombre es requerido",
"createInternalResourceDialogNameMaxLength": "El nombre debe ser menor de 255 caracteres", "createInternalResourceDialogNameMaxLength": "El nombre debe ser menor de 255 caracteres",
"createInternalResourceDialogPleaseSelectSite": "Por favor seleccione un sitio", "createInternalResourceDialogPleaseSelectSite": "Por favor seleccione un sitio",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "El rango CIDR del recurso en la red del sitio.", "createInternalResourceDialogDestinationCidrDescription": "El rango CIDR del recurso en la red del sitio.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.", "createInternalResourceDialogAliasDescription": "Un alias DNS interno opcional para este recurso.",
"internalResourceAliasLocalWarning": "Los alias que terminan en .local pueden causar problemas de resolución debido a mDNS en algunas redes.",
"internalResourceDownstreamSchemeRequired": "Se requiere el método para recursos HTTP", "internalResourceDownstreamSchemeRequired": "Se requiere el método para recursos HTTP",
"internalResourceHttpPortRequired": "Se requiere el puerto de destino para recursos HTTP", "internalResourceHttpPortRequired": "Se requiere el puerto de destino para recursos HTTP",
"siteConfiguration": "Configuración", "siteConfiguration": "Configuración",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Nodos remotos", "sidebarRemoteExitNodes": "Nodos remotos",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Secreto", "remoteExitNodeSecretKey": "Secreto",
"remoteExitNodeNetworkingTitle": "Ajustes de Red",
"remoteExitNodeNetworkingDescription": "Configura cómo este nodo de salida remoto dirige el tráfico y qué sitios prefieren conectarse a través de él. Características avanzadas para usar con configuraciones de red de retroceso.",
"remoteExitNodeNetworkingSave": "Guardar Ajustes",
"remoteExitNodeNetworkingSaveSuccessTitle": "Ajustes de red guardados",
"remoteExitNodeNetworkingSaveSuccessDescription": "Los ajustes de red han sido actualizados exitosamente.",
"remoteExitNodeNetworkingSaveError": "Error al guardar los ajustes de red",
"remoteExitNodeNetworkingSubnetsTitle": "Subredes Remotas",
"remoteExitNodeNetworkingSubnetsDescription": "Define los rangos CIDR a los que este nodo de salida remoto dirigirá el tráfico. Escribe un CIDR válido (e.g. <code>10.0.0.0/8</code>) y presiona Enter para añadir.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Añadir un rango CIDR (e.g. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Error al cargar las subredes",
"remoteExitNodeNetworkingLabelsTitle": "Etiquetas de Preferencias",
"remoteExitNodeNetworkingLabelsDescription": "Los sitios con estas etiquetas se verán obligados a conectarse a través de este nodo de salida remoto.",
"remoteExitNodeNetworkingLabelsButtonText": "Seleccionar etiquetas...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Buscar etiquetas...",
"remoteExitNodeNetworkingLabelsLoadError": "Error al cargar las etiquetas",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Crear nodo remoto", "title": "Crear nodo remoto",
"description": "Crea un nuevo nodo de retransmisión y proxy server autogestionado", "description": "Crea un nuevo nodo de retransmisión y proxy server autogestionado",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "No hay nodos disponibles para esta organización. Crea un nodo primero para usar sitios locales.", "noRemoteExitNodesAvailableDescription": "No hay nodos disponibles para esta organización. Crea un nodo primero para usar sitios locales.",
"exitNode": "Nodo de Salida", "exitNode": "Nodo de Salida",
"country": "País", "country": "País",
"countryIsNot": "El país no es",
"rulesMatchCountry": "Actualmente basado en IP de origen", "rulesMatchCountry": "Actualmente basado en IP de origen",
"region": "Región", "region": "Región",
"selectRegion": "Seleccionar región", "selectRegion": "Seleccionar región",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Proveedor OAuth2/OIDC de Google", "idpGoogleDescription": "Proveedor OAuth2/OIDC de Google",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Subred", "subnet": "Subred",
"utilitySubnet": "Subred de Utilidad",
"subnetDescription": "La subred para la configuración de red de esta organización.", "subnetDescription": "La subred para la configuración de red de esta organización.",
"customDomain": "Dominio personalizado", "customDomain": "Dominio personalizado",
"authPage": "Páginas de autenticación", "authPage": "Páginas de autenticación",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "La configuración de autenticación de doble factor es requerida. Por favor, inicia sesión de nuevo a través de {dashboardUrl}/auth/login completa este paso. Luego, vuelve aquí.", "twoFactorSetupRequired": "La configuración de autenticación de doble factor es requerida. Por favor, inicia sesión de nuevo a través de {dashboardUrl}/auth/login completa este paso. Luego, vuelve aquí.",
"additionalSecurityRequired": "Seguridad adicional requerida", "additionalSecurityRequired": "Seguridad adicional requerida",
"organizationRequiresAdditionalSteps": "Esta organización requiere pasos de seguridad adicionales antes de poder acceder a los recursos.", "organizationRequiresAdditionalSteps": "Esta organización requiere pasos de seguridad adicionales antes de poder acceder a los recursos.",
"sessionExpired": "Sesión Expirada",
"sessionExpiredReauthRequired": "Su sesión ha expirado según la política de seguridad de su organización. Por favor, vuelva a autenticarse para continuar.",
"reauthenticate": "Volver a autenticar",
"completeTheseSteps": "Completa estos pasos", "completeTheseSteps": "Completa estos pasos",
"enableTwoFactorAuthentication": "Habilitar autenticación de doble factor", "enableTwoFactorAuthentication": "Habilitar autenticación de doble factor",
"completeSecuritySteps": "Pasos de seguridad completos", "completeSecuritySteps": "Pasos de seguridad completos",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Dirección de origen", "sourceAddress": "Dirección de origen",
"destinationAddress": "Dirección de destino", "destinationAddress": "Dirección de destino",
"duration": "Duración", "duration": "Duración",
"licenseRequiredToUse": "Se requiere una licencia <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> o <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> para usar esta función. <bookADemoLink>Reserve una demostración o prueba POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "La <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> es necesaria para utilizar esta función. Esta función también está disponible en <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Reserva una demostración o prueba POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Resolver certificado", "certResolver": "Resolver certificado",
"certResolverDescription": "Seleccione la resolución de certificados a utilizar para este recurso.", "certResolverDescription": "Seleccione la resolución de certificados a utilizar para este recurso.",
"selectCertResolver": "Seleccionar Resolver Certificado", "selectCertResolver": "Seleccionar Resolver Certificado",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Falta el ID de organización o dominio", "orgOrDomainIdMissing": "Falta el ID de organización o dominio",
"loadingDNSRecords": "Cargando registros DNS...", "loadingDNSRecords": "Cargando registros DNS...",
"olmUpdateAvailableInfo": "Una versión actualizada de Olm está disponible. Por favor, actualice a la última versión para obtener la mejor experiencia.", "olmUpdateAvailableInfo": "Una versión actualizada de Olm está disponible. Por favor, actualice a la última versión para obtener la mejor experiencia.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Hay una versión actualizada disponible. Actualice a la última versión para obtener la mejor experiencia.",
"client": "Cliente", "client": "Cliente",
"proxyProtocol": "Configuración del Protocolo Proxy", "proxyProtocol": "Configuración del Protocolo Proxy",
"proxyProtocolDescription": "Configurar el protocolo de proxy para preservar las direcciones IP del cliente para los servicios TCP.", "proxyProtocolDescription": "Configurar el protocolo de proxy para preservar las direcciones IP del cliente para los servicios TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Agregar usuarios", "editInternalResourceDialogAddUsers": "Agregar usuarios",
"editInternalResourceDialogAddClients": "Agregar clientes", "editInternalResourceDialogAddClients": "Agregar clientes",
"editInternalResourceDialogDestinationLabel": "Destino", "editInternalResourceDialogDestinationLabel": "Destino",
"editInternalResourceDialogDestinationDescription": "Especifique la dirección de destino para el recurso interno. Puede ser un nombre de host, dirección IP o rango CIDR dependiendo del modo seleccionado. Opcionalmente establezca un alias DNS interno para una identificación más fácil.", "editInternalResourceDialogDestinationDescription": "Configura cómo los clientes acceden a este recurso.",
"internalResourceFormMultiSiteRoutingHelp": "Seleccionar múltiples sitios habilita el enrutamiento resistente y la conmutación por error para alta disponibilidad.", "internalResourceFormMultiSiteRoutingHelp": "Seleccionar múltiples sitios habilita el enrutamiento resistente y la conmutación por error para alta disponibilidad.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Más información", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Más información",
"editInternalResourceDialogPortRestrictionsDescription": "Restringir el acceso a puertos TCP/UDP específicos o permitir/bloquear todos los puertos.", "editInternalResourceDialogPortRestrictionsDescription": "Restringir el acceso a puertos TCP/UDP específicos o permitir/bloquear todos los puertos.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Lista Blanca de Correo", "memberPortalEmailWhitelist": "Lista Blanca de Correo",
"memberPortalResourceDisabled": "Recurso Deshabilitado", "memberPortalResourceDisabled": "Recurso Deshabilitado",
"memberPortalShowingResources": "Mostrando {start}-{end} de {total} recursos", "memberPortalShowingResources": "Mostrando {start}-{end} de {total} recursos",
"resourceLauncherTitle": "Lanzador de Recursos",
"resourceSidebarLauncherTitle": "Lanzador",
"resourceLauncherDescription": "Ver todos los recursos disponibles y lanzarlos desde un único centro",
"resourceLauncherSearchPlaceholder": "Buscar tus recursos...",
"resourceLauncherDefaultView": "Predeterminado",
"resourceLauncherSaveView": "Guardar Vista",
"resourceLauncherSaveToCurrentView": "Guardar en la Vista Actual",
"resourceLauncherSaveDefaultPersonal": "Guardar para mí",
"resourceLauncherResetView": "Restablecer Vista",
"resourceLauncherResetSystemDefault": "Restaurar a la configuración predeterminada del sistema",
"resourceLauncherSystemDefaultRestored": "Configuración del sistema restaurada",
"resourceLauncherSystemDefaultRestoredDescription": "La vista predeterminada se ha restablecido a la configuración original.",
"resourceLauncherSaveAsNewView": "Guardar como Nueva Vista",
"resourceLauncherSaveAsNewViewDescription": "Ponle un nombre a esta vista para guardar tus filtros y diseño actuales.",
"resourceLauncherSaveForEveryone": "Guardar para Todos",
"resourceLauncherSaveForEveryoneDescription": "Comparte esta vista con todos los miembros de la organización. Si está desmarcado, la vista solo es visible para ti.",
"resourceLauncherMakePersonal": "Hacer Personal",
"resourceLauncherFilter": "Filtro",
"resourceLauncherFilterWithCount": "Filtro, {count} aplicado",
"resourceLauncherSort": "Ordenar",
"resourceLauncherSortAscending": "Ordenar Ascendente",
"resourceLauncherSortDescending": "Ordenar Descendente",
"resourceLauncherSettings": "Ajustes",
"resourceLauncherGroupBy": "Agrupar Por",
"resourceLauncherGroupBySite": "Sitio",
"resourceLauncherGroupByLabel": "Etiqueta",
"resourceLauncherGroupByNone": "Ninguna",
"resourceLauncherLayout": "Disposición",
"resourceLauncherLayoutGrid": "Cuadrícula",
"resourceLauncherLayoutList": "Lista",
"resourceLauncherShowLabels": "Mostrar Etiquetas",
"resourceLauncherShowSiteTags": "Mostrar Etiquetas del Sitio",
"resourceLauncherShowRecents": "Mostrar Recientes",
"resourceLauncherDeleteView": "Eliminar Vista",
"resourceLauncherDeleteViewTitle": "Eliminar Vista",
"resourceLauncherDeleteViewQuestion": "¿Está seguro de que desea eliminar esta vista de lanzador?",
"resourceLauncherDeleteViewConfirm": "Eliminar Vista",
"resourceLauncherViewAsAdmin": "Ver como Administrador",
"resourceLauncherResourceDetailsDescription": "Información de conexión y estado de este recurso.",
"resourceLauncherResourceDetails": "Detalles del recurso",
"resourceLauncherAuthMethodsDescription": "Métodos de autenticación habilitados para este recurso.",
"resourceLauncherPrivateClientRequired": "Conéctese con un cliente en su dispositivo para acceder a este recurso en privado.",
"resourceLauncherPrivateClientRequiredTitle": "Se requiere conexión del cliente",
"resourceLauncherDownloadClient": "Descargar cliente",
"resourceLauncherFailedToLoadDetails": "No se pudieron cargar los detalles del recurso. Es posible que ya no tengas acceso a este recurso.",
"resourceLauncherNoPortRestrictions": "Sin restricciones de puertos",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Sin Etiqueta",
"resourceLauncherNoSite": "Sin Sitio",
"resourceLauncherNoResourcesInGroup": "No hay recursos en este grupo",
"resourceLauncherEmptyStateTitle": "No hay Recursos Disponibles",
"resourceLauncherEmptyStateDescription": "Todavía no tienes acceso a ningún recurso. Contacta a tu administrador para solicitar acceso.",
"resourceLauncherEmptyStateNoResultsTitle": "No se Encontraron Recursos",
"resourceLauncherEmptyStateNoResultsDescription": "No hay recursos que coincidan con tu búsqueda o filtros actuales. Intenta ajustarlos para encontrar lo que buscas.",
"resourceLauncherEmptyStateNoResultsWithQuery": "No hay recursos que coincidan con \"{query}\". Intenta ajustar tu búsqueda o borrar filtros para ver todos los recursos.",
"resourceLauncherSearchFirstTitle": "Buscar o filtrar para navegar",
"resourceLauncherSearchFirstDescription": "Tiene acceso a muchos recursos. Use la búsqueda o filtre por sitio o etiqueta para encontrar lo que necesita.",
"resourceLauncherSiteGroupingDisabled": "La agrupación por sitios no está disponible en esta escala. Filtre por sitio para agrupar un conjunto más pequeño.",
"resourceLauncherLabelGroupingDisabled": "La agrupación por etiquetas no está disponible en esta escala.",
"resourceLauncherCompactModeHint": "Mostrando una lista simplificada para una navegación más rápida. Use la búsqueda o los filtros para limitar los resultados.",
"resourceLauncherCompactGroupingHint": "Aplique filtros de sitio o etiqueta para habilitar la agrupación.",
"resourceLauncherCopiedToClipboard": "Copiado al portapapeles",
"resourceLauncherCopiedAccessDescription": "El acceso al recurso ha sido copiado a tu portapapeles.",
"resourceLauncherViewNamePlaceholder": "Nombre de la Vista",
"resourceLauncherViewNameLabel": "Nombre de la Vista",
"resourceLauncherViewSaved": "Vista guardada",
"resourceLauncherViewSavedDescription": "Tu vista del lanzador ha sido guardada.",
"resourceLauncherViewSaveFailed": "Error al guardar la vista",
"resourceLauncherViewSaveFailedDescription": "No se pudo guardar la vista del lanzador. Por favor, intenta de nuevo.",
"resourceLauncherViewDeleted": "Vista eliminada",
"resourceLauncherViewDeletedDescription": "La vista del lanzador ha sido eliminada.",
"resourceLauncherViewDeleteFailed": "Error al eliminar la vista",
"resourceLauncherViewDeleteFailedDescription": "No se pudo eliminar la vista del lanzador. Por favor, intenta de nuevo.",
"memberPortalPrevious": "Anterior", "memberPortalPrevious": "Anterior",
"memberPortalNext": "Siguiente", "memberPortalNext": "Siguiente",
"httpSettings": "Configuración HTTP", "httpSettings": "Configuración HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----COMIENZO DE LA CLAVE PRIVADA OPENSSH-----", "sshPrivateKeyPlaceholder": "-----COMIENZO DE LA CLAVE PRIVADA OPENSSH-----",
"sshPrivateKeyRequired": "Se requiere clave privada", "sshPrivateKeyRequired": "Se requiere clave privada",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Introduce tu contraseña VNC para conectar", "vncSignInDescription": "Introduce tus credenciales VNC para conectarte",
"vncUsernameOptional": "Nombre de usuario (opcional)",
"vncPasswordOptional": "Contraseña (opcional)", "vncPasswordOptional": "Contraseña (opcional)",
"vncNoResourceTarget": "No hay objetivo de recurso disponible", "vncNoResourceTarget": "No hay objetivo de recurso disponible",
"vncFailedToLoadNovnc": "Error al cargar noVNC", "vncFailedToLoadNovnc": "Error al cargar noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Error de subida", "rdpUploadFailed": "Error de subida",
"rdpUnicodeKeyboardMode": "Modo teclado Unicode", "rdpUnicodeKeyboardMode": "Modo teclado Unicode",
"sessionToolbarShow": "Mostrar barra de herramientas", "sessionToolbarShow": "Mostrar barra de herramientas",
"sessionToolbarHide": "Ocultar barra de herramientas" "sessionToolbarHide": "Ocultar barra de herramientas",
"actionUpdateSiteApprovals": "Actualizar aprobaciones del sitio"
} }
+248 -20
View File
@@ -66,9 +66,15 @@
"local": "Locale", "local": "Locale",
"edit": "Modifier", "edit": "Modifier",
"siteConfirmDelete": "Confirmer la suppression du nœud", "siteConfirmDelete": "Confirmer la suppression du nœud",
"siteConfirmDeleteAndResources": "Confirmer la suppression du site et des ressources",
"siteDelete": "Supprimer le nœud", "siteDelete": "Supprimer le nœud",
"siteDeleteAndResources": "Supprimer le site et les ressources",
"siteMessageRemove": "Une fois supprimé, le nœud ne sera plus accessible. Toutes les cibles associées au nœud seront également supprimées.", "siteMessageRemove": "Une fois supprimé, le nœud ne sera plus accessible. Toutes les cibles associées au nœud seront également supprimées.",
"siteMessageRemoveAndResources": "Cela supprimera définitivement toutes les ressources publiques et privées liées à ce site, même si une ressource est également associée à d'autres sites.",
"siteQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce nœud de l'organisation ?", "siteQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce nœud de l'organisation ?",
"siteQuestionRemoveAndResources": "Êtes-vous sûr de vouloir supprimer ce site et toutes les ressources associées?",
"sitesTableDeleteSite": "Supprimer le site",
"sitesTableDeleteSiteAndResources": "Supprimer le site et les ressources",
"siteManageSites": "Gérer les nœuds", "siteManageSites": "Gérer les nœuds",
"siteDescription": "Créer et gérer des sites pour activer la connectivité aux réseaux privés", "siteDescription": "Créer et gérer des sites pour activer la connectivité aux réseaux privés",
"sitesBannerTitle": "Se connecter à n'importe quel réseau", "sitesBannerTitle": "Se connecter à n'importe quel réseau",
@@ -117,6 +123,16 @@
"siteUpdated": "Nœud mis à jour", "siteUpdated": "Nœud mis à jour",
"siteUpdatedDescription": "Le nœud a été mis à jour.", "siteUpdatedDescription": "Le nœud a été mis à jour.",
"siteGeneralDescription": "Configurer les paramètres par défaut de ce nœud", "siteGeneralDescription": "Configurer les paramètres par défaut de ce nœud",
"siteRestartTitle": "Redémarrer Site",
"siteRestartDescription": "Redémarrer le tunnel WireGuard pour ce site. Cela interrompra brièvement la connectivité.",
"siteRestartBody": "Utilisez cela si le tunnel du site ne fonctionne pas correctement et que vous souhaitez forcer une reconnexion sans redémarrer l'hôte.",
"siteRestartButton": "Redémarrer Site",
"siteRestartDialogMessage": "Êtes-vous sûr de vouloir redémarrer le tunnel WireGuard pour <b>{name}</b>? Le site perdra brièvement sa connectivité.",
"siteRestartWarning": "Le site sera brièvement déconnecté pendant le redémarrage du tunnel.",
"siteRestarted": "Site redémarré",
"siteRestartedDescription": "Le tunnel WireGuard a été redémarré.",
"siteErrorRestart": "Échec du redémarrage du site",
"siteErrorRestartDescription": "Une erreur s'est produite lors du redémarrage du site.",
"siteSettingDescription": "Configurer les paramètres du site", "siteSettingDescription": "Configurer les paramètres du site",
"siteResourcesTab": "Ressources", "siteResourcesTab": "Ressources",
"siteResourcesNoneOnSite": "Ce site n'a pas encore de ressources publiques ou privées.", "siteResourcesNoneOnSite": "Ce site n'a pas encore de ressources publiques ou privées.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Confirmer la suppression du lien partageable", "shareDeleteConfirm": "Confirmer la suppression du lien partageable",
"shareQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?", "shareQuestionRemove": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?",
"shareMessageRemove": "Une fois supprimé, le lien ne fonctionnera plus et toute personne l'utilisant perdra l'accès à la ressource.", "shareMessageRemove": "Une fois supprimé, le lien ne fonctionnera plus et toute personne l'utilisant perdra l'accès à la ressource.",
"shareTokenDescription": "Le jeton d'accès peut être passé de deux façons : en tant que paramètre de requête ou dans les en-têtes de la requête. Elles doivent être transmises par le client à chaque demande d'accès authentifié.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Jeton d'accès", "accessToken": "Jeton d'accès",
"usageExamples": "Exemples d'utilisation", "usageExamples": "Exemples d'utilisation",
"tokenId": "ID du jeton", "tokenId": "ID du jeton",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Titre (facultatif)", "shareTitleOptional": "Titre (facultatif)",
"sharePathOptional": "Chemin (optionnel)", "sharePathOptional": "Chemin (optionnel)",
"sharePathDescription": "Le lien redirigera les utilisateurs vers ce chemin après l'authentification.", "sharePathDescription": "Le lien redirigera les utilisateurs vers ce chemin après l'authentification.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Expire dans", "expireIn": "Expire dans",
"neverExpire": "N'expire jamais", "neverExpire": "N'expire jamais",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Le délai d'expiration correspond à la période pendant laquelle le lien sera utilisable et permettra d'accéder à la ressource. Passé ce délai, le lien ne fonctionnera plus et les utilisateurs qui l'ont utilisé perdront l'accès à la ressource.", "shareExpireDescription": "Le délai d'expiration correspond à la période pendant laquelle le lien sera utilisable et permettra d'accéder à la ressource. Passé ce délai, le lien ne fonctionnera plus et les utilisateurs qui l'ont utilisé perdront l'accès à la ressource.",
"shareSeeOnce": "Vous ne pourrez voir ce lien qu'une seule fois. N'oubliez pas de le copier.", "shareSeeOnce": "Vous ne pourrez voir ce lien qu'une seule fois. N'oubliez pas de le copier.",
"shareAccessHint": "N'importe qui avec ce lien peut accéder à la ressource. Partagez-le avec précaution.", "shareAccessHint": "N'importe qui avec ce lien peut accéder à la ressource. Partagez-le avec précaution.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Requêtes de proxy sur TCP/UDP brute en utilisant un numéro de port. Nécessite des sites pour se connecter à un noeud distant.", "resourceRawDescriptionCloud": "Requêtes de proxy sur TCP/UDP brute en utilisant un numéro de port. Nécessite des sites pour se connecter à un noeud distant.",
"resourceCreate": "Créer une ressource", "resourceCreate": "Créer une ressource",
"resourceCreateDescription": "Suivez les étapes ci-dessous pour créer une nouvelle ressource", "resourceCreateDescription": "Suivez les étapes ci-dessous pour créer une nouvelle ressource",
"resourcePublicCreate": "Créer une ressource publique",
"resourcePublicCreateDescription": "Suivez les étapes ci-dessous pour créer une nouvelle ressource publique accessible via un navigateur web",
"resourceCreateGeneralDescription": "Configurer les paramètres de ressource de base, y compris le nom et le type", "resourceCreateGeneralDescription": "Configurer les paramètres de ressource de base, y compris le nom et le type",
"resourceSeeAll": "Voir toutes les ressources", "resourceSeeAll": "Voir toutes les ressources",
"resourceCreateGeneral": "Général", "resourceCreateGeneral": "Général",
@@ -431,8 +455,14 @@
"provisioningManage": "Mise en place", "provisioningManage": "Mise en place",
"provisioningDescription": "Gérer les clés de provisioning et examiner les sites en attente d'approbation.", "provisioningDescription": "Gérer les clés de provisioning et examiner les sites en attente d'approbation.",
"pendingSites": "Sites en attente", "pendingSites": "Sites en attente",
"siteApproveSuccess": "Site approuvé avec succès", "siteApproveSuccess": "Site et ressources associées approuvés avec succès",
"siteApproveError": "Erreur lors de l'approbation du site", "siteApproveError": "Erreur lors de l'approbation du site",
"siteReject": "Rejeter le site",
"siteQuestionReject": "Êtes-vous sûr de vouloir rejeter ce site ?",
"siteMessageReject": "Cela supprimera définitivement le site et toutes les ressources associées qui sont encore en attente.",
"siteConfirmReject": "Confirmer le rejet du site",
"siteRejectSuccess": "Site rejeté avec succès",
"siteRejectError": "Erreur lors du rejet du site",
"provisioningKeys": "Clés de provisionnement", "provisioningKeys": "Clés de provisionnement",
"searchProvisioningKeys": "Recherche des clés de provision...", "searchProvisioningKeys": "Recherche des clés de provision...",
"provisioningKeysAdd": "Générer une clé de provisioning", "provisioningKeysAdd": "Générer une clé de provisioning",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Enregistrer la clé de provisioning", "provisioningKeysSave": "Enregistrer la clé de provisioning",
"provisioningKeysSaveDescription": "Vous ne pourrez voir cela qu'une seule fois. Copiez-le dans un endroit sécurisé.", "provisioningKeysSaveDescription": "Vous ne pourrez voir cela qu'une seule fois. Copiez-le dans un endroit sécurisé.",
"provisioningKeysErrorCreate": "Erreur lors de la création de la clé de provisioning", "provisioningKeysErrorCreate": "Erreur lors de la création de la clé de provisioning",
"provisioningKeysList": "Nouvelle clé de provisioning", "provisioningKeysList": "Nouvelle clé d'approvisionnement",
"provisioningKeysMaxBatchSize": "Taille maximale du lot", "provisioningKeysMaxBatchSize": "Taille maximale du lot",
"provisioningKeysUnlimitedBatchSize": "Taille de lot illimitée (sans limite)", "provisioningKeysUnlimitedBatchSize": "Taille de lot illimitée (sans limite)",
"provisioningKeysMaxBatchUnlimited": "Illimité", "provisioningKeysMaxBatchUnlimited": "Illimité",
"provisioningKeysMaxBatchSizeInvalid": "Entrez une taille de lot maximale valide (11 000 000).", "provisioningKeysMaxBatchSizeInvalid": "Entrez une taille de lot maximale valide (11 000 000).",
"provisioningKeysValidUntil": "Valable jusqu'au", "provisioningKeysValidUntil": "Valable jusqu'à",
"provisioningKeysValidUntilHint": "Laisser vide pour ne pas expirer.", "provisioningKeysValidUntilHint": "Laisser vide pour ne pas expirer.",
"provisioningKeysValidUntilInvalid": "Entrez une date et une heure valides.", "provisioningKeysValidUntilInvalid": "Entrez une date et une heure valides.",
"provisioningKeysNumUsed": "Nombre de fois utilisées", "provisioningKeysNumUsed": "Nombre de fois utilisées",
@@ -597,7 +627,8 @@
"idpNameInternal": "Interne", "idpNameInternal": "Interne",
"emailInvalid": "Adresse e-mail invalide", "emailInvalid": "Adresse e-mail invalide",
"inviteValidityDuration": "Veuillez sélectionner une durée", "inviteValidityDuration": "Veuillez sélectionner une durée",
"accessRoleSelectPlease": "Veuillez sélectionner un rôle", "accessRoleSelectPlease": "Un utilisateur doit appartenir à au moins un rôle.",
"accessRoleRequired": "Rôle requis",
"removeOwnAdminRoleConfirmTitle": "Retirer votre accès administrateur ?", "removeOwnAdminRoleConfirmTitle": "Retirer votre accès administrateur ?",
"removeOwnAdminRoleConfirmDescription": "Vous n'aurez plus de droits d'administrateur dans cette organisation après avoir enregistré. Un autre administrateur pourra restaurer cet accès si nécessaire.", "removeOwnAdminRoleConfirmDescription": "Vous n'aurez plus de droits d'administrateur dans cette organisation après avoir enregistré. Un autre administrateur pourra restaurer cet accès si nécessaire.",
"removeOwnAdminRoleConfirmButton": "Retirer mon accès administrateur", "removeOwnAdminRoleConfirmButton": "Retirer mon accès administrateur",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Authentification de l'en-tête de base", "policyAuthHeaderAuthTitle": "Authentification de l'en-tête de base",
"policyAuthHeaderAuthDescription": "Validez un nom et une valeur d'en-tête HTTP personnalisé à chaque requête", "policyAuthHeaderAuthDescription": "Validez un nom et une valeur d'en-tête HTTP personnalisé à chaque requête",
"policyAuthHeaderAuthSummary": "En-tête configuré", "policyAuthHeaderAuthSummary": "En-tête configuré",
"policyAuthHeaderName": "Nom de l'en-tête", "policyAuthHeaderName": "Nom d'utilisateur",
"policyAuthHeaderValue": "Valeur attendue", "policyAuthHeaderValue": "Mot de passe",
"policyAuthSetPasscode": "Définir le code confidentiel", "policyAuthSetPasscode": "Définir le code confidentiel",
"policyAuthSetPincode": "Définir le code PIN", "policyAuthSetPincode": "Définir le code PIN",
"policyAuthSetEmailWhitelist": "Définir la liste blanche des e-mails", "policyAuthSetEmailWhitelist": "Définir la liste blanche des e-mails",
@@ -903,7 +934,7 @@
"newtVersion": "Version", "newtVersion": "Version",
"architecture": "Architecture", "architecture": "Architecture",
"sites": "Nœuds", "sites": "Nœuds",
"siteWgAnyClients": "Utilisez n'importe quel client WireGuard pour vous connecter. Vous devrez adresser des ressources internes en utilisant l'adresse IP du pair.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Compatible avec tous les clients WireGuard", "siteWgCompatibleAllClients": "Compatible avec tous les clients WireGuard",
"siteWgManualConfigurationRequired": "Configuration manuelle requise", "siteWgManualConfigurationRequired": "Configuration manuelle requise",
"userErrorNotAdminOrOwner": "L'utilisateur n'est pas un administrateur ou un propriétaire", "userErrorNotAdminOrOwner": "L'utilisateur n'est pas un administrateur ou un propriétaire",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Créer un utilisateur Org", "createOrgUser": "Créer un utilisateur Org",
"actionUpdateOrg": "Mettre à jour l'organisation", "actionUpdateOrg": "Mettre à jour l'organisation",
"actionRemoveInvitation": "Supprimer l'invitation", "actionRemoveInvitation": "Supprimer l'invitation",
"actionRemoveUserRole": "Supprimer le rôle d'utilisateur",
"actionUpdateUser": "Mettre à jour l'utilisateur", "actionUpdateUser": "Mettre à jour l'utilisateur",
"actionGetUser": "Obtenir l'utilisateur", "actionGetUser": "Obtenir l'utilisateur",
"actionGetOrgUser": "Obtenir l'utilisateur de l'organisation", "actionGetOrgUser": "Obtenir l'utilisateur de l'organisation",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Appliquer la Config", "actionApplyBlueprint": "Appliquer la Config",
"actionListBlueprints": "Lister les plans", "actionListBlueprints": "Lister les plans",
"actionGetBlueprint": "Obtenez un plan", "actionGetBlueprint": "Obtenez un plan",
"actionCreateOrgWideLauncherView": "Créer une vue de lancement au niveau de l'organisation",
"setupToken": "Jeton de configuration", "setupToken": "Jeton de configuration",
"setupTokenDescription": "Entrez le jeton de configuration depuis la console du serveur.", "setupTokenDescription": "Entrez le jeton de configuration depuis la console du serveur.",
"setupTokenRequired": "Le jeton de configuration est requis.", "setupTokenRequired": "Le jeton de configuration est requis.",
"actionUpdateSite": "Mettre à jour un site", "actionUpdateSite": "Mettre à jour un site",
"actionApproveSite": "Approuver le site",
"actionRejectSite": "Rejeter le site",
"actionResetSiteBandwidth": "Réinitialiser la bande passante de l'organisation", "actionResetSiteBandwidth": "Réinitialiser la bande passante de l'organisation",
"actionListSiteRoles": "Lister les rôles autorisés du site", "actionListSiteRoles": "Lister les rôles autorisés du site",
"actionCreateResource": "Créer une ressource", "actionCreateResource": "Créer une ressource",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Définir le code PIN de la ressource", "actionSetResourcePincode": "Définir le code PIN de la ressource",
"actionSetResourceEmailWhitelist": "Définir la liste blanche des emails de la ressource", "actionSetResourceEmailWhitelist": "Définir la liste blanche des emails de la ressource",
"actionGetResourceEmailWhitelist": "Obtenir la liste blanche des emails de la ressource", "actionGetResourceEmailWhitelist": "Obtenir la liste blanche des emails de la ressource",
"actionGetResourcePolicy": "Obtenir une politique de ressources",
"actionUpdateResourcePolicy": "Mettre à jour la politique de ressources",
"actionSetResourcePolicyUsers": "Définir les utilisateurs de la politique de ressources",
"actionSetResourcePolicyRoles": "Définir les rôles de la politique de ressources",
"actionSetResourcePolicyPassword": "Définir le mot de passe de la politique de ressources",
"actionSetResourcePolicyPincode": "Définir le code PIN de la politique de ressources",
"actionSetResourcePolicyHeaderAuth": "Définir l'authentification des en-têtes de la politique de ressources",
"actionSetResourcePolicyWhitelist": "Définir la liste blanche des emails de la politique de ressources",
"actionSetResourcePolicyRules": "Définir les règles de la politique de ressources",
"actionCreateTarget": "Créer une cible", "actionCreateTarget": "Créer une cible",
"actionDeleteTarget": "Supprimer une cible", "actionDeleteTarget": "Supprimer une cible",
"actionGetTarget": "Obtenir une cible", "actionGetTarget": "Obtenir une cible",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Générer un jeton d'accès", "actionGenerateAccessToken": "Générer un jeton d'accès",
"actionDeleteAccessToken": "Supprimer un jeton d'accès", "actionDeleteAccessToken": "Supprimer un jeton d'accès",
"actionListAccessTokens": "Lister les jetons d'accès", "actionListAccessTokens": "Lister les jetons d'accès",
"actionCreateResourceSessionToken": "Créer un jeton de session de ressource",
"actionCreateResourceRule": "Créer une règle de ressource", "actionCreateResourceRule": "Créer une règle de ressource",
"actionDeleteResourceRule": "Supprimer une règle de ressource", "actionDeleteResourceRule": "Supprimer une règle de ressource",
"actionListResourceRules": "Lister les règles de ressource", "actionListResourceRules": "Lister les règles de ressource",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Lister les invitations", "actionListInvitations": "Lister les invitations",
"actionExportLogs": "Exporter les journaux", "actionExportLogs": "Exporter les journaux",
"actionViewLogs": "Voir les logs", "actionViewLogs": "Voir les logs",
"actionCreateSiteProvisioningKey": "Créer une clé de provisionnement de site",
"actionListSiteProvisioningKeys": "Lister les clés de provisionnement de site",
"actionUpdateSiteProvisioningKey": "Mettre à jour la clé de provisionnement de site",
"actionDeleteSiteProvisioningKey": "Supprimer la clé de provisionnement de site",
"noneSelected": "Aucune sélection", "noneSelected": "Aucune sélection",
"orgNotFound2": "Aucune organisation trouvée.", "orgNotFound2": "Aucune organisation trouvée.",
"search": "Rechercher…", "search": "Rechercher…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Dernière utilisation",
"otpAuthBack": "Retour au mot de passe", "otpAuthBack": "Retour au mot de passe",
"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",
"commandPaletteTitle": "Palette de commandes",
"commandPaletteDescription": "Rechercher des pages, organisations, ressources et actions",
"commandPaletteSearchPlaceholder": "Rechercher des pages, ressources, actions...",
"commandPaletteNoResults": "Aucun résultat trouvé.",
"commandPaletteSearching": "Recherche en cours...",
"commandPaletteNavigation": "Navigation",
"commandPaletteOrganizations": "Organisations",
"commandPaletteSites": "Sites",
"commandPaletteResources": "Ressource",
"commandPaletteUsers": "Utilisateurs",
"commandPaletteClients": "Liste des clients",
"commandPaletteActions": "Actions",
"commandPaletteCreateSite": "Créer un site",
"commandPaletteCreateProxyResource": "Créer une ressource publique",
"commandPaletteCreatePrivateResource": "Créer une ressource privée",
"commandPaletteCreateUser": "Créer un utilisateur",
"commandPaletteCreateApiKey": "Créer une clé API",
"commandPaletteCreateMachineClient": "Créer un client machine",
"commandPaletteCreateAlertRule": "Créer une règle d'alerte",
"commandPaletteCreateIdentityProvider": "Créer un fournisseur d'identité",
"commandPaletteToggleTheme": "Changer de thème",
"commandPaletteChooseOrganization": "Choisir une organisation",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Impossible d'activer l'A2F", "otpErrorEnable": "Impossible d'activer l'A2F",
"otpErrorEnableDescription": "Une erreur s'est produite lors de l'activation de l'A2F", "otpErrorEnableDescription": "Une erreur s'est produite lors de l'activation de l'A2F",
"otpSetupCheckCode": "Veuillez entrer un code à 6 chiffres", "otpSetupCheckCode": "Veuillez entrer un code à 6 chiffres",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Gestion", "sidebarManagement": "Gestion",
"sidebarBillingAndLicenses": "Facturation & Licences", "sidebarBillingAndLicenses": "Facturation & Licences",
"sidebarLogsAnalytics": "Analyses", "sidebarLogsAnalytics": "Analyses",
"commandSites": "Nœuds",
"commandActionModeInfo": "Tapez \">\" Pour ouvrir le mode action",
"commandResources": "Ressource",
"commandProxyResources": "Ressources publiques",
"commandClientResources": "Ressources privées",
"commandClients": "Clients",
"commandUserDevices": "Appareils utilisateur",
"commandMachineClients": "Clients machine",
"commandDomains": "Domaines",
"commandRemoteExitNodes": "Nœuds distants",
"commandTeam": "Équipe",
"commandUsers": "Utilisateurs",
"commandRoles": "Rôles",
"commandInvitations": "Invitations",
"commandPolicies": "Politiques partagées",
"commandResourcePolicies": "Politiques de ressources publiques",
"commandIdentityProviders": "Fournisseurs d'identité",
"commandApprovals": "Demandes d'approbation",
"commandShareableLinks": "Liens partageables",
"commandOrganization": "Organisation",
"commandLogsAndAnalytics": "Journaux & Analyses",
"commandLogsAnalytics": "Analyses",
"commandLogsRequest": "Journaux des requêtes HTTP",
"commandLogsAccess": "Journaux d'authentification",
"commandLogsAction": "Journaux des actions administratives",
"commandLogsConnection": "Journaux de connexion",
"commandLogsStreaming": "Diffusion d'événements",
"commandManagement": "Gestion",
"commandAlerting": "Alerte",
"commandProvisioning": "Provisionnement",
"commandBluePrints": "Configs",
"commandApiKeys": "Clés d'API",
"commandBillingAndLicenses": "Facturation & Licences",
"commandBilling": "Facturation",
"commandEnterpriseLicenses": "Licence",
"commandSettings": "Réglages",
"commandLauncher": "Lanceur",
"commandResourceLauncher": "Lanceur de ressources",
"commandSearchResults": "Résultats de recherche",
"alertingTitle": "Alertes", "alertingTitle": "Alertes",
"alertingDescription": "Définissez des sources, des déclencheurs et des actions pour les notifications", "alertingDescription": "Définissez des sources, des déclencheurs et des actions pour les notifications",
"alertingRules": "Règles d'alerte", "alertingRules": "Règles d'alerte",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Sous-domaine : {subdomain}", "domainPickerSubdomain": "Sous-domaine : {subdomain}",
"domainPickerNamespace": "Espace de noms : {namespace}", "domainPickerNamespace": "Espace de noms : {namespace}",
"domainPickerShowMore": "Afficher plus", "domainPickerShowMore": "Afficher plus",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Sélectionner Région", "regionSelectorTitle": "Sélectionner Région",
"domainPickerRemoteExitNodeWarning": "Les domaines fournis ne sont pas pris en charge lorsque les sites se connectent à des nœuds de sortie distants. Pour que les ressources soient disponibles sur des nœuds distants, utilisez un domaine personnalisé à la place.", "domainPickerRemoteExitNodeWarning": "Les domaines fournis ne sont pas pris en charge lorsque les sites se connectent à des nœuds de sortie distants. Pour que les ressources soient disponibles sur des nœuds distants, utilisez un domaine personnalisé à la place.",
"regionSelectorInfo": "Sélectionner une région nous aide à offrir de meilleures performances pour votre localisation. Vous n'avez pas besoin d'être dans la même région que votre serveur.", "regionSelectorInfo": "Sélectionner une région nous aide à offrir de meilleures performances pour votre localisation. Vous n'avez pas besoin d'être dans la même région que votre serveur.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domaines", "billingDomains": "Domaines",
"billingOrganizations": "Organes", "billingOrganizations": "Organes",
"billingRemoteExitNodes": "Nœuds distants", "billingRemoteExitNodes": "Nœuds distants",
"billingPublicResources": "Ressources publiques",
"billingPrivateResources": "Ressources privées",
"billingMachineClients": "Clients machine",
"billingNoLimitConfigured": "Aucune limite configurée", "billingNoLimitConfigured": "Aucune limite configurée",
"billingEstimatedPeriod": "Période de facturation estimée", "billingEstimatedPeriod": "Période de facturation estimée",
"billingIncludedUsage": "Utilisation incluse", "billingIncludedUsage": "Utilisation incluse",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Combien d'utilisateurs vous pouvez utiliser", "billingUsersInfo": "Combien d'utilisateurs vous pouvez utiliser",
"billingDomainInfo": "Combien de domaines vous pouvez utiliser", "billingDomainInfo": "Combien de domaines vous pouvez utiliser",
"billingRemoteExitNodesInfo": "Combien de nœuds distants vous pouvez utiliser", "billingRemoteExitNodesInfo": "Combien de nœuds distants vous pouvez utiliser",
"billingPublicResourcesInfo": "Combien de ressources publiques pouvez-vous utiliser",
"billingPrivateResourcesInfo": "Combien de ressources privées pouvez-vous utiliser",
"billingMachineClientsInfo": "Combien de clients machine pouvez-vous utiliser",
"billingLicenseKeys": "Clés de licence", "billingLicenseKeys": "Clés de licence",
"billingLicenseKeysDescription": "Gérer vos abonnements à la clé de licence", "billingLicenseKeysDescription": "Gérer vos abonnements à la clé de licence",
"billingLicenseSubscription": "Abonnement à la licence", "billingLicenseSubscription": "Abonnement à la licence",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Sous-réseau", "subnetPlaceholder": "Sous-réseau",
"addressDescription": "L'adresse interne du client. Doit être dans le sous-réseau de l'organisation.", "addressDescription": "L'adresse interne du client. Doit être dans le sous-réseau de l'organisation.",
"selectSites": "Sélectionner des sites", "selectSites": "Sélectionner des sites",
"selectLabels": "Sélectionner des étiquettes",
"sitesDescription": "Le client aura une connectivité vers les sites sélectionnés", "sitesDescription": "Le client aura une connectivité vers les sites sélectionnés",
"clientInstallOlm": "Installer Olm", "clientInstallOlm": "Installer Olm",
"clientInstallOlmDescription": "Faites fonctionner Olm sur votre système", "clientInstallOlmDescription": "Faites fonctionner Olm sur votre système",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Publique", "resourcesTableProxyResources": "Publique",
"resourcesTableClientResources": "Privé", "resourcesTableClientResources": "Privé",
"resourcesTableNoProxyResourcesFound": "Aucune ressource proxy trouvée.", "resourcesTableNoProxyResourcesFound": "Aucune ressource proxy trouvée.",
"resourcesTableNoInternalResourcesFound": "Aucune ressource interne trouvée.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Destination", "resourcesTableDestination": "Destination",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Adresse de l'alias", "resourcesTableAliasAddress": "Adresse de l'alias",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Abandonner", "editInternalResourceDialogCancel": "Abandonner",
"editInternalResourceDialogSaveResource": "Enregistrer la ressource", "editInternalResourceDialogSaveResource": "Enregistrer la ressource",
"editInternalResourceDialogSuccess": "Succès", "editInternalResourceDialogSuccess": "Succès",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Ressource interne mise à jour avec succès", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Erreur", "editInternalResourceDialogError": "Erreur",
"editInternalResourceDialogFailedToUpdateInternalResource": "Échec de la mise à jour de la ressource interne", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Le nom est requis", "editInternalResourceDialogNameRequired": "Le nom est requis",
"editInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères", "editInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
"editInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1", "editInternalResourceDialogProxyPortMin": "Le port proxy doit être d'au moins 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.", "editInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.",
"createInternalResourceDialogNoSitesAvailable": "Aucun site disponible", "createInternalResourceDialogNoSitesAvailable": "Aucun site disponible",
"createInternalResourceDialogNoSitesAvailableDescription": "Vous devez avoir au moins un site Newt avec un sous-réseau configuré pour créer des ressources internes.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Fermer", "createInternalResourceDialogClose": "Fermer",
"createInternalResourceDialogCreateClientResource": "Créer une ressource privée", "createInternalResourceDialogCreateClientResource": "Créer une ressource privée",
"createInternalResourceDialogCreateClientResourceDescription": "Créer une nouvelle ressource qui ne sera accessible qu'aux clients connectés à l'organisation", "createInternalResourceDialogCreateClientResourceDescription": "Créer une nouvelle ressource qui ne sera accessible qu'aux clients connectés à l'organisation",
"privateResourceGeneralDescription": "Configurez le nom, l'identifiant et d'autres paramètres généraux de la ressource.",
"privateResourceCreatePageSeeAll": "Voir toutes les ressources privées",
"privateResourceAllowIcmpPing": "Autoriser le ping ICMP",
"privateResourceNetworkAccess": "Accès au réseau",
"privateResourceNetworkAccessDescription": "Contrôler l'accès aux ports TCP/UDP et si le ping ICMP est autorisé pour cette ressource.",
"hostSettings": "Paramètres de l'hôte",
"cidrSettings": "Paramètres CIDR",
"createInternalResourceDialogResourceProperties": "Propriétés de la ressource", "createInternalResourceDialogResourceProperties": "Propriétés de la ressource",
"createInternalResourceDialogName": "Nom", "createInternalResourceDialogName": "Nom",
"createInternalResourceDialogSite": "Site", "createInternalResourceDialogSite": "Site",
"selectSite": "Sélectionner un site...", "selectSite": "Sélectionner un site...",
"multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}", "multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}",
"labelsSelectorLabelsCount": "{count, plural, one {# étiquette} other {# étiquettes}}",
"noSitesFound": "Aucun site trouvé.", "noSitesFound": "Aucun site trouvé.",
"createInternalResourceDialogProtocol": "Protocole", "createInternalResourceDialogProtocol": "Protocole",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Abandonner", "createInternalResourceDialogCancel": "Abandonner",
"createInternalResourceDialogCreateResource": "Créer une ressource", "createInternalResourceDialogCreateResource": "Créer une ressource",
"createInternalResourceDialogSuccess": "Succès", "createInternalResourceDialogSuccess": "Succès",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Ressource interne créée avec succès", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Erreur", "createInternalResourceDialogError": "Erreur",
"createInternalResourceDialogFailedToCreateInternalResource": "Échec de la création de la ressource interne", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Le nom est requis", "createInternalResourceDialogNameRequired": "Le nom est requis",
"createInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères", "createInternalResourceDialogNameMaxLength": "Le nom doit être inférieur à 255 caractères",
"createInternalResourceDialogPleaseSelectSite": "Veuillez sélectionner un site", "createInternalResourceDialogPleaseSelectSite": "Veuillez sélectionner un site",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "La gamme CIDR de la ressource sur le réseau du site.", "createInternalResourceDialogDestinationCidrDescription": "La gamme CIDR de la ressource sur le réseau du site.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.", "createInternalResourceDialogAliasDescription": "Un alias DNS interne optionnel pour cette ressource.",
"internalResourceAliasLocalWarning": "Les alias se terminant par .local peuvent causer des problèmes de résolution dus au mDNS sur certains réseaux.",
"internalResourceDownstreamSchemeRequired": "Un schéma est requis pour les ressources HTTP", "internalResourceDownstreamSchemeRequired": "Un schéma est requis pour les ressources HTTP",
"internalResourceHttpPortRequired": "Le port de destination est requis pour les ressources HTTP", "internalResourceHttpPortRequired": "Le port de destination est requis pour les ressources HTTP",
"siteConfiguration": "Configuration", "siteConfiguration": "Configuration",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Nœuds distants", "sidebarRemoteExitNodes": "Nœuds distants",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Clé secrète", "remoteExitNodeSecretKey": "Clé secrète",
"remoteExitNodeNetworkingTitle": "Paramètres du réseau",
"remoteExitNodeNetworkingDescription": "Configurez comment ce nœud de sortie distant acheminera le trafic et quels sites préfèrent se connecter via ce dernier. Fonctions avancées à utiliser avec les configurations réseau de retour.",
"remoteExitNodeNetworkingSave": "Enregistrer les paramètres",
"remoteExitNodeNetworkingSaveSuccessTitle": "Paramètres du réseau enregistrés",
"remoteExitNodeNetworkingSaveSuccessDescription": "Les paramètres du réseau ont été mis à jour avec succès.",
"remoteExitNodeNetworkingSaveError": "Échec de l'enregistrement des paramètres du réseau",
"remoteExitNodeNetworkingSubnetsTitle": "Sous-réseaux distants",
"remoteExitNodeNetworkingSubnetsDescription": "Définissez les plages CIDR que ce nœud de sortie distant acheminera. Saisissez un CIDR valide (par exemple <code>10.0.0.0/8</code>) et appuyez sur Entrée pour ajouter.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Ajouter une plage CIDR (par exemple 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Échec du chargement des sous-réseaux",
"remoteExitNodeNetworkingLabelsTitle": "Étiquettes de préférences",
"remoteExitNodeNetworkingLabelsDescription": "Les sites avec ces étiquettes devront se connecter via ce nœud de sortie distant.",
"remoteExitNodeNetworkingLabelsButtonText": "Sélectionner des étiquettes...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Chercher des étiquettes...",
"remoteExitNodeNetworkingLabelsLoadError": "Échec du chargement des étiquettes",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Créer un nœud distant", "title": "Créer un nœud distant",
"description": "Créez un nouveau nœud de relais et de serveur proxy distant auto-hébergé", "description": "Créez un nouveau nœud de relais et de serveur proxy distant auto-hébergé",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Aucun noeud n'est disponible pour cette organisation. Créez d'abord un noeud pour utiliser des sites locaux.", "noRemoteExitNodesAvailableDescription": "Aucun noeud n'est disponible pour cette organisation. Créez d'abord un noeud pour utiliser des sites locaux.",
"exitNode": "Nœud de sortie", "exitNode": "Nœud de sortie",
"country": "Pays", "country": "Pays",
"countryIsNot": "Le pays n'est pas",
"rulesMatchCountry": "Actuellement basé sur l'IP source", "rulesMatchCountry": "Actuellement basé sur l'IP source",
"region": "Région", "region": "Région",
"selectRegion": "Sélectionner une région", "selectRegion": "Sélectionner une région",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Fournisseur Google OAuth2/OIDC", "idpGoogleDescription": "Fournisseur Google OAuth2/OIDC",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Sous-réseau", "subnet": "Sous-réseau",
"utilitySubnet": "Routeur utilitaire",
"subnetDescription": "Le sous-réseau de la configuration réseau de cette organisation.", "subnetDescription": "Le sous-réseau de la configuration réseau de cette organisation.",
"customDomain": "Domaine personnalisé", "customDomain": "Domaine personnalisé",
"authPage": "Pages d'authentification", "authPage": "Pages d'authentification",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "La configuration d'authentification à deux facteurs est requise. Veuillez vous reconnecter via {dashboardUrl}/auth/login terminé cette étape. Puis revenez ici.", "twoFactorSetupRequired": "La configuration d'authentification à deux facteurs est requise. Veuillez vous reconnecter via {dashboardUrl}/auth/login terminé cette étape. Puis revenez ici.",
"additionalSecurityRequired": "Sécurité supplémentaire requise", "additionalSecurityRequired": "Sécurité supplémentaire requise",
"organizationRequiresAdditionalSteps": "Cette organisation nécessite des étapes de sécurité supplémentaires avant de pouvoir accéder aux ressources.", "organizationRequiresAdditionalSteps": "Cette organisation nécessite des étapes de sécurité supplémentaires avant de pouvoir accéder aux ressources.",
"sessionExpired": "Session expirée",
"sessionExpiredReauthRequired": "Votre session a expiré selon la politique de sécurité de votre organisation. Veuillez vous ré-authentifier pour continuer.",
"reauthenticate": "Se ré-authentifier",
"completeTheseSteps": "Compléter ces étapes", "completeTheseSteps": "Compléter ces étapes",
"enableTwoFactorAuthentication": "Activer l'authentification à deux facteurs", "enableTwoFactorAuthentication": "Activer l'authentification à deux facteurs",
"completeSecuritySteps": "Compléter les étapes de sécurité", "completeSecuritySteps": "Compléter les étapes de sécurité",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Adresse source", "sourceAddress": "Adresse source",
"destinationAddress": "Adresse de destination", "destinationAddress": "Adresse de destination",
"duration": "Durée", "duration": "Durée",
"licenseRequiredToUse": "Une <enterpriseLicenseLink>licence Enterprise Edition</enterpriseLicenseLink> ou <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> est requise pour utiliser cette fonctionnalité. <bookADemoLink>Réservez une démonstration ou une évaluation de POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "La version <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> est requise pour utiliser cette fonctionnalité. Cette fonctionnalité est également disponible dans <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Réservez une démo ou un essai POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Résolveur de certificat", "certResolver": "Résolveur de certificat",
"certResolverDescription": "Sélectionnez le solveur de certificat à utiliser pour cette ressource.", "certResolverDescription": "Sélectionnez le solveur de certificat à utiliser pour cette ressource.",
"selectCertResolver": "Sélectionnez le résolveur de certificat", "selectCertResolver": "Sélectionnez le résolveur de certificat",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "L'organisation ou l'identifiant de domaine est manquant", "orgOrDomainIdMissing": "L'organisation ou l'identifiant de domaine est manquant",
"loadingDNSRecords": "Chargement des enregistrements DNS...", "loadingDNSRecords": "Chargement des enregistrements DNS...",
"olmUpdateAvailableInfo": "Une version mise à jour de Olm est disponible. Veuillez mettre à jour vers la dernière version pour la meilleure expérience.", "olmUpdateAvailableInfo": "Une version mise à jour de Olm est disponible. Veuillez mettre à jour vers la dernière version pour la meilleure expérience.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Une version mise à jour est disponible. Veuillez mettre à jour vers la dernière version pour une meilleure expérience.",
"client": "Client", "client": "Client",
"proxyProtocol": "Paramètres du protocole proxy", "proxyProtocol": "Paramètres du protocole proxy",
"proxyProtocolDescription": "Configurer le protocole Proxy pour préserver les adresses IP du client pour les services TCP.", "proxyProtocolDescription": "Configurer le protocole Proxy pour préserver les adresses IP du client pour les services TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Ajouter des utilisateurs", "editInternalResourceDialogAddUsers": "Ajouter des utilisateurs",
"editInternalResourceDialogAddClients": "Ajouter des clients", "editInternalResourceDialogAddClients": "Ajouter des clients",
"editInternalResourceDialogDestinationLabel": "Destination", "editInternalResourceDialogDestinationLabel": "Destination",
"editInternalResourceDialogDestinationDescription": "Indiquez l'adresse de destination pour la ressource interne. Cela peut être un nom d'hôte, une adresse IP ou une plage CIDR selon le mode sélectionné. Définissez éventuellement un alias DNS interne pour une identification plus facile.", "editInternalResourceDialogDestinationDescription": "Configurez comment les clients accèdent à cette ressource.",
"internalResourceFormMultiSiteRoutingHelp": "La sélection de plusieurs sites permet un routage résilient et un basculement pour une haute disponibilité.", "internalResourceFormMultiSiteRoutingHelp": "La sélection de plusieurs sites permet un routage résilient et un basculement pour une haute disponibilité.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "En savoir plus", "internalResourceFormMultiSiteRoutingHelpLearnMore": "En savoir plus",
"editInternalResourceDialogPortRestrictionsDescription": "Restreindre l'accès à des ports TCP/UDP spécifiques ou autoriser/bloquer tous les ports.", "editInternalResourceDialogPortRestrictionsDescription": "Restreindre l'accès à des ports TCP/UDP spécifiques ou autoriser/bloquer tous les ports.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Liste blanche des e-mails", "memberPortalEmailWhitelist": "Liste blanche des e-mails",
"memberPortalResourceDisabled": "Ressource désactivée", "memberPortalResourceDisabled": "Ressource désactivée",
"memberPortalShowingResources": "Affichage de {start}-{end} sur {total} ressources", "memberPortalShowingResources": "Affichage de {start}-{end} sur {total} ressources",
"resourceLauncherTitle": "Lanceur de ressources",
"resourceSidebarLauncherTitle": "Lanceur",
"resourceLauncherDescription": "Afficher toutes les ressources disponibles et les lancer depuis un hub central",
"resourceLauncherSearchPlaceholder": "Chercher vos ressources...",
"resourceLauncherDefaultView": "Par défaut",
"resourceLauncherSaveView": "Enregistrer la vue",
"resourceLauncherSaveToCurrentView": "Enregistrer dans la vue actuelle",
"resourceLauncherSaveDefaultPersonal": "Sauvegarder pour moi",
"resourceLauncherResetView": "Réinitialiser la vue",
"resourceLauncherResetSystemDefault": "Réinitialiser aux paramètres système par défaut",
"resourceLauncherSystemDefaultRestored": "Paramètre système par défaut restauré",
"resourceLauncherSystemDefaultRestoredDescription": "La vue par défaut a été réinitialisée aux paramètres d'origine.",
"resourceLauncherSaveAsNewView": "Enregistrer comme nouvelle vue",
"resourceLauncherSaveAsNewViewDescription": "Donnez un nom à cette vue pour enregistrer vos filtres et mise en page actuels.",
"resourceLauncherSaveForEveryone": "Enregistrer pour tout le monde",
"resourceLauncherSaveForEveryoneDescription": "Partagez cette vue avec tous les membres de l'organisation. Lorsque décochée, la vue est visible uniquement par vous.",
"resourceLauncherMakePersonal": "Rendre personnel",
"resourceLauncherFilter": "Filtrer",
"resourceLauncherFilterWithCount": "Filtrer, {count} appliqué",
"resourceLauncherSort": "Trier",
"resourceLauncherSortAscending": "Trier par ordre croissant",
"resourceLauncherSortDescending": "Trier par ordre décroissant",
"resourceLauncherSettings": "Réglages",
"resourceLauncherGroupBy": "Grouper par",
"resourceLauncherGroupBySite": "Nœud",
"resourceLauncherGroupByLabel": "Étiquette",
"resourceLauncherGroupByNone": "Aucun",
"resourceLauncherLayout": "Mise en page",
"resourceLauncherLayoutGrid": "Grille",
"resourceLauncherLayoutList": "Liste",
"resourceLauncherShowLabels": "Afficher les étiquettes",
"resourceLauncherShowSiteTags": "Afficher les tags de site",
"resourceLauncherShowRecents": "Afficher les récents",
"resourceLauncherDeleteView": "Supprimer la vue",
"resourceLauncherDeleteViewTitle": "Supprimer la vue",
"resourceLauncherDeleteViewQuestion": "Êtes-vous sûr de vouloir supprimer cette vue de lancement ?",
"resourceLauncherDeleteViewConfirm": "Supprimer la vue",
"resourceLauncherViewAsAdmin": "Voir en tant qu'admin",
"resourceLauncherResourceDetailsDescription": "Informations de connexion et statut pour cette ressource.",
"resourceLauncherResourceDetails": "Détails de la ressource",
"resourceLauncherAuthMethodsDescription": "Méthodes d'authentification activées pour cette ressource.",
"resourceLauncherPrivateClientRequired": "Connectez-vous avec un client sur votre appareil pour accéder à cette ressource en privé.",
"resourceLauncherPrivateClientRequiredTitle": "Connexion client requise",
"resourceLauncherDownloadClient": "Télécharger le client",
"resourceLauncherFailedToLoadDetails": "Impossible de charger les détails de la ressource. Vous n'avez peut-être plus accès à cette ressource.",
"resourceLauncherNoPortRestrictions": "Aucune restriction de port",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Non étiqueté",
"resourceLauncherNoSite": "Aucun nœud",
"resourceLauncherNoResourcesInGroup": "Aucune ressource dans ce groupe",
"resourceLauncherEmptyStateTitle": "Aucune ressource disponible",
"resourceLauncherEmptyStateDescription": "Vous n'avez pas encore accès à des ressources. Contactez votre administrateur pour demander l'accès.",
"resourceLauncherEmptyStateNoResultsTitle": "Aucune ressource trouvée",
"resourceLauncherEmptyStateNoResultsDescription": "Aucune ressource ne correspond à votre recherche ou filtre actuel. Essayez de les ajuster pour trouver ce que vous cherchez.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Aucune ressource ne correspond à \"{query}\". Essayez d'ajuster votre recherche ou de supprimer les filtres pour voir toutes les ressources.",
"resourceLauncherSearchFirstTitle": "Rechercher ou filtrer pour parcourir",
"resourceLauncherSearchFirstDescription": "Vous avez accès à de nombreuses ressources. Utilisez la recherche ou filtrez par site ou étiquette pour trouver ce dont vous avez besoin.",
"resourceLauncherSiteGroupingDisabled": "Le regroupement par site n'est pas disponible à cette échelle. Filtrez par site pour regrouper un ensemble plus restreint.",
"resourceLauncherLabelGroupingDisabled": "Le regroupement par étiquette n'est pas disponible à cette échelle.",
"resourceLauncherCompactModeHint": "Affichage d'une liste simplifiée pour une navigation plus rapide. Utilisez la recherche ou les filtres pour affiner les résultats.",
"resourceLauncherCompactGroupingHint": "Appliquer des filtres par site ou étiquette pour activer le regroupement.",
"resourceLauncherCopiedToClipboard": "Copié dans le presse-papiers",
"resourceLauncherCopiedAccessDescription": "L'accès à la ressource a été copié dans votre presse-papiers.",
"resourceLauncherViewNamePlaceholder": "Nom de la vue",
"resourceLauncherViewNameLabel": "Nom de la vue",
"resourceLauncherViewSaved": "Vue enregistrée",
"resourceLauncherViewSavedDescription": "Votre vue de lancement a été enregistrée.",
"resourceLauncherViewSaveFailed": "Échec de l'enregistrement de la vue",
"resourceLauncherViewSaveFailedDescription": "Impossible d'enregistrer la vue de lancement. Veuillez réessayer.",
"resourceLauncherViewDeleted": "Vue supprimée",
"resourceLauncherViewDeletedDescription": "La vue de lancement a été supprimée.",
"resourceLauncherViewDeleteFailed": "Impossible de supprimer la vue",
"resourceLauncherViewDeleteFailedDescription": "Impossible de supprimer la vue de lancement. Veuillez réessayer.",
"memberPortalPrevious": "Précédent", "memberPortalPrevious": "Précédent",
"memberPortalNext": "Suivant", "memberPortalNext": "Suivant",
"httpSettings": "Paramètres HTTP", "httpSettings": "Paramètres HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "Une clé privée est requise", "sshPrivateKeyRequired": "Une clé privée est requise",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Entrez votre mot de passe VNC pour vous connecter", "vncSignInDescription": "Entrez vos identifiants VNC pour vous connecter",
"vncUsernameOptional": "Nom d'utilisateur (optionnel)",
"vncPasswordOptional": "Mot de passe (facultatif)", "vncPasswordOptional": "Mot de passe (facultatif)",
"vncNoResourceTarget": "Aucune cible de ressource disponible", "vncNoResourceTarget": "Aucune cible de ressource disponible",
"vncFailedToLoadNovnc": "Échec du chargement de noVNC", "vncFailedToLoadNovnc": "Échec du chargement de noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Échec du téléchargement", "rdpUploadFailed": "Échec du téléchargement",
"rdpUnicodeKeyboardMode": "Mode clavier Unicode", "rdpUnicodeKeyboardMode": "Mode clavier Unicode",
"sessionToolbarShow": "Afficher la barre d'outils", "sessionToolbarShow": "Afficher la barre d'outils",
"sessionToolbarHide": "Masquer la barre d'outils" "sessionToolbarHide": "Masquer la barre d'outils",
"actionUpdateSiteApprovals": "Mettre à jour les approbations de site"
} }
+250 -22
View File
@@ -66,9 +66,15 @@
"local": "Locale", "local": "Locale",
"edit": "Modifica", "edit": "Modifica",
"siteConfirmDelete": "Conferma Eliminazione Sito", "siteConfirmDelete": "Conferma Eliminazione Sito",
"siteConfirmDeleteAndResources": "Conferma Eliminazione Sito e Risorse",
"siteDelete": "Elimina Sito", "siteDelete": "Elimina Sito",
"siteDeleteAndResources": "Elimina Sito e Risorse",
"siteMessageRemove": "Una volta rimosso il sito non sarà più accessibile. Tutti gli oggetti associati al sito verranno rimossi.", "siteMessageRemove": "Una volta rimosso il sito non sarà più accessibile. Tutti gli oggetti associati al sito verranno rimossi.",
"siteMessageRemoveAndResources": "Questo eliminerà permanentemente tutte le risorse pubbliche e private collegate a questo sito, anche se una risorsa è anche associata ad altri siti.",
"siteQuestionRemove": "Sei sicuro di voler rimuovere il sito dall'organizzazione?", "siteQuestionRemove": "Sei sicuro di voler rimuovere il sito dall'organizzazione?",
"siteQuestionRemoveAndResources": "Sei sicuro di voler eliminare questo sito e tutte le risorse associate?",
"sitesTableDeleteSite": "Elimina Sito",
"sitesTableDeleteSiteAndResources": "Elimina Sito e Risorse",
"siteManageSites": "Gestisci Siti", "siteManageSites": "Gestisci Siti",
"siteDescription": "Creare e gestire siti per abilitare la connettività a reti private", "siteDescription": "Creare e gestire siti per abilitare la connettività a reti private",
"sitesBannerTitle": "Connetti Qualsiasi Rete", "sitesBannerTitle": "Connetti Qualsiasi Rete",
@@ -117,6 +123,16 @@
"siteUpdated": "Sito aggiornato", "siteUpdated": "Sito aggiornato",
"siteUpdatedDescription": "Il sito è stato aggiornato.", "siteUpdatedDescription": "Il sito è stato aggiornato.",
"siteGeneralDescription": "Configura le impostazioni generali per questo sito", "siteGeneralDescription": "Configura le impostazioni generali per questo sito",
"siteRestartTitle": "Riavvia Sito",
"siteRestartDescription": "Riavvia il tunnel WireGuard per questo sito. Questo interromperà brevemente la connettività.",
"siteRestartBody": "Usalo se il tunnel del sito non funziona correttamente e vuoi forzare un riconnessione senza riavviare l'host.",
"siteRestartButton": "Riavvia Sito",
"siteRestartDialogMessage": "Sei sicuro di voler riavviare il tunnel WireGuard per <b>{name}</b>? Il sito perderà brevemente la connettività.",
"siteRestartWarning": "Il sito si disconnette brevemente mentre il tunnel si riavvia.",
"siteRestarted": "Sito riavviato",
"siteRestartedDescription": "Il tunnel WireGuard è stato riavviato.",
"siteErrorRestart": "Impossibile riavviare il sito",
"siteErrorRestartDescription": "Si è verificato un errore durante il riavvio del sito.",
"siteSettingDescription": "Configura le impostazioni del sito", "siteSettingDescription": "Configura le impostazioni del sito",
"siteResourcesTab": "Risorse", "siteResourcesTab": "Risorse",
"siteResourcesNoneOnSite": "Questo sito non ha ancora risorse pubbliche o private.", "siteResourcesNoneOnSite": "Questo sito non ha ancora risorse pubbliche o private.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Conferma Eliminazione Collegamento Condivisibile", "shareDeleteConfirm": "Conferma Eliminazione Collegamento Condivisibile",
"shareQuestionRemove": "Sei sicuro di voler eliminare questo link di condivisione?", "shareQuestionRemove": "Sei sicuro di voler eliminare questo link di condivisione?",
"shareMessageRemove": "Una volta eliminato, il link non funzionerà più e chiunque lo utilizzi perderà l'accesso alla risorsa.", "shareMessageRemove": "Una volta eliminato, il link non funzionerà più e chiunque lo utilizzi perderà l'accesso alla risorsa.",
"shareTokenDescription": "Il token di accesso può essere passato in due modi: come parametro di interrogazione o nelle intestazioni della richiesta. Questi devono essere passati dal client su ogni richiesta di accesso autenticato.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Token Di Accesso", "accessToken": "Token Di Accesso",
"usageExamples": "Esempi Di Utilizzo", "usageExamples": "Esempi Di Utilizzo",
"tokenId": "ID del Token", "tokenId": "ID del Token",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Titolo (facoltativo)", "shareTitleOptional": "Titolo (facoltativo)",
"sharePathOptional": "Percorso (opzionale)", "sharePathOptional": "Percorso (opzionale)",
"sharePathDescription": "Il link reindirizzerà gli utenti a questo percorso dopo l'autenticazione.", "sharePathDescription": "Il link reindirizzerà gli utenti a questo percorso dopo l'autenticazione.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Scadenza In", "expireIn": "Scadenza In",
"neverExpire": "Nessuna scadenza", "neverExpire": "Nessuna scadenza",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Il tempo di scadenza indica per quanto tempo il link sarà utilizzabile e fornirà accesso alla risorsa. Dopo questo tempo, il link non funzionerà più e gli utenti che hanno utilizzato questo link perderanno l'accesso alla risorsa.", "shareExpireDescription": "Il tempo di scadenza indica per quanto tempo il link sarà utilizzabile e fornirà accesso alla risorsa. Dopo questo tempo, il link non funzionerà più e gli utenti che hanno utilizzato questo link perderanno l'accesso alla risorsa.",
"shareSeeOnce": "Potrai vedere questo link solo una volta. Assicurati di copiarlo.", "shareSeeOnce": "Potrai vedere questo link solo una volta. Assicurati di copiarlo.",
"shareAccessHint": "Chiunque abbia questo link può accedere alla risorsa. Condividilo con cura.", "shareAccessHint": "Chiunque abbia questo link può accedere alla risorsa. Condividilo con cura.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Richiesta proxy su TCP/UDP grezzo utilizzando un numero di porta. Richiede siti per connettersi a un nodo remoto.", "resourceRawDescriptionCloud": "Richiesta proxy su TCP/UDP grezzo utilizzando un numero di porta. Richiede siti per connettersi a un nodo remoto.",
"resourceCreate": "Crea Risorsa", "resourceCreate": "Crea Risorsa",
"resourceCreateDescription": "Segui i passaggi seguenti per creare una nuova risorsa", "resourceCreateDescription": "Segui i passaggi seguenti per creare una nuova risorsa",
"resourcePublicCreate": "Crea Risorsa Pubblica",
"resourcePublicCreateDescription": "Segui i passaggi seguenti per creare una nuova risorsa pubblica accessibile tramite un browser web",
"resourceCreateGeneralDescription": "Configura le impostazioni generali delle risorse, inclusi il nome e il tipo", "resourceCreateGeneralDescription": "Configura le impostazioni generali delle risorse, inclusi il nome e il tipo",
"resourceSeeAll": "Vedi Tutte Le Risorse", "resourceSeeAll": "Vedi Tutte Le Risorse",
"resourceCreateGeneral": "Generale", "resourceCreateGeneral": "Generale",
@@ -431,8 +455,14 @@
"provisioningManage": "Accantonamento", "provisioningManage": "Accantonamento",
"provisioningDescription": "Gestire le chiavi di provisioning e rivedere i siti in attesa di approvazione.", "provisioningDescription": "Gestire le chiavi di provisioning e rivedere i siti in attesa di approvazione.",
"pendingSites": "Siti In Attesa", "pendingSites": "Siti In Attesa",
"siteApproveSuccess": "Sito approvato con successo", "siteApproveSuccess": "Sito e risorse associate approvate con successo",
"siteApproveError": "Errore nell'approvazione del sito", "siteApproveError": "Errore nell'approvazione del sito",
"siteReject": "Rifiuta Sito",
"siteQuestionReject": "Sei sicuro di voler rifiutare questo sito?",
"siteMessageReject": "Questo eliminerà permanentemente il sito e tutte le risorse associate ancora in sospeso.",
"siteConfirmReject": "Conferma Rifiuto Sito",
"siteRejectSuccess": "Sito rifiutato con successo",
"siteRejectError": "Errore nel rifiutare il sito",
"provisioningKeys": "Chiavi Di Provvedimento", "provisioningKeys": "Chiavi Di Provvedimento",
"searchProvisioningKeys": "Cerca le chiavi di provisioning...", "searchProvisioningKeys": "Cerca le chiavi di provisioning...",
"provisioningKeysAdd": "Genera Chiave di provisioning", "provisioningKeysAdd": "Genera Chiave di provisioning",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Salva la chiave di provisioning", "provisioningKeysSave": "Salva la chiave di provisioning",
"provisioningKeysSaveDescription": "Sarai in grado di vedere solo una volta. Copiarlo in un posto sicuro.", "provisioningKeysSaveDescription": "Sarai in grado di vedere solo una volta. Copiarlo in un posto sicuro.",
"provisioningKeysErrorCreate": "Errore nella creazione della chiave di provisioning", "provisioningKeysErrorCreate": "Errore nella creazione della chiave di provisioning",
"provisioningKeysList": "Nuova chiave di provisioning", "provisioningKeysList": "Nuova Chiave di Provisioning",
"provisioningKeysMaxBatchSize": "Dimensione massima batch", "provisioningKeysMaxBatchSize": "Dimensione Massima Batch",
"provisioningKeysUnlimitedBatchSize": "Dimensione illimitata del batch (nessun limite)", "provisioningKeysUnlimitedBatchSize": "Dimensione illimitata del batch (nessun limite)",
"provisioningKeysMaxBatchUnlimited": "Illimitato", "provisioningKeysMaxBatchUnlimited": "Illimitato",
"provisioningKeysMaxBatchSizeInvalid": "Inserisci una dimensione massima valida del batch (11.000.000).", "provisioningKeysMaxBatchSizeInvalid": "Inserisci una dimensione massima valida del batch (11.000.000).",
"provisioningKeysValidUntil": "Valido fino al", "provisioningKeysValidUntil": "Valido Fino a",
"provisioningKeysValidUntilHint": "Lasciare vuoto per nessuna scadenza.", "provisioningKeysValidUntilHint": "Lasciare vuoto per nessuna scadenza.",
"provisioningKeysValidUntilInvalid": "Inserisci una data e ora valide.", "provisioningKeysValidUntilInvalid": "Inserisci una data e ora valide.",
"provisioningKeysNumUsed": "Volte usate", "provisioningKeysNumUsed": "Volte usate",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Mai", "provisioningKeysNeverUsed": "Mai",
"provisioningKeysEdit": "Modifica Chiave di provisioning", "provisioningKeysEdit": "Modifica Chiave di provisioning",
"provisioningKeysEditDescription": "Aggiorna la dimensione massima del batch e il tempo di scadenza per questa chiave.", "provisioningKeysEditDescription": "Aggiorna la dimensione massima del batch e il tempo di scadenza per questa chiave.",
"provisioningKeysApproveNewSites": "Approva nuovi siti", "provisioningKeysApproveNewSites": "Approva Nuovi Siti",
"provisioningKeysApproveNewSitesDescription": "Approvare automaticamente i siti che si registrano con questa chiave.", "provisioningKeysApproveNewSitesDescription": "Approvare automaticamente i siti che si registrano con questa chiave.",
"provisioningKeysUpdateError": "Errore nell'aggiornamento della chiave di provisioning", "provisioningKeysUpdateError": "Errore nell'aggiornamento della chiave di provisioning",
"provisioningKeysUpdated": "Chiave di provisioning aggiornata", "provisioningKeysUpdated": "Chiave di provisioning aggiornata",
@@ -597,7 +627,8 @@
"idpNameInternal": "Interno", "idpNameInternal": "Interno",
"emailInvalid": "Indirizzo email non valido", "emailInvalid": "Indirizzo email non valido",
"inviteValidityDuration": "Seleziona una durata", "inviteValidityDuration": "Seleziona una durata",
"accessRoleSelectPlease": "Seleziona un ruolo", "accessRoleSelectPlease": "Un utente deve appartenere ad almeno un ruolo.",
"accessRoleRequired": "Ruolo richiesto",
"removeOwnAdminRoleConfirmTitle": "Rimuovere il tuo accesso amministrativo?", "removeOwnAdminRoleConfirmTitle": "Rimuovere il tuo accesso amministrativo?",
"removeOwnAdminRoleConfirmDescription": "Non avrai più i permessi di amministratore in questa organizzazione dopo il salvataggio. Un altro amministratore può ripristinare l'accesso se necessario.", "removeOwnAdminRoleConfirmDescription": "Non avrai più i permessi di amministratore in questa organizzazione dopo il salvataggio. Un altro amministratore può ripristinare l'accesso se necessario.",
"removeOwnAdminRoleConfirmButton": "Rimuovere il Mio Accesso Amministrativo", "removeOwnAdminRoleConfirmButton": "Rimuovere il Mio Accesso Amministrativo",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Autenticazione Header Base", "policyAuthHeaderAuthTitle": "Autenticazione Header Base",
"policyAuthHeaderAuthDescription": "Convalida un nome e un valore di intestazione HTTP personalizzato su ogni richiesta", "policyAuthHeaderAuthDescription": "Convalida un nome e un valore di intestazione HTTP personalizzato su ogni richiesta",
"policyAuthHeaderAuthSummary": "Intestazione configurata", "policyAuthHeaderAuthSummary": "Intestazione configurata",
"policyAuthHeaderName": "Nome dell'intestazione", "policyAuthHeaderName": "Nome utente",
"policyAuthHeaderValue": "Valore atteso", "policyAuthHeaderValue": "Password",
"policyAuthSetPasscode": "Imposta Codice di Accesso", "policyAuthSetPasscode": "Imposta Codice di Accesso",
"policyAuthSetPincode": "Imposta Codice PIN", "policyAuthSetPincode": "Imposta Codice PIN",
"policyAuthSetEmailWhitelist": "Imposta Lista Autorizzazioni Email", "policyAuthSetEmailWhitelist": "Imposta Lista Autorizzazioni Email",
@@ -903,7 +934,7 @@
"newtVersion": "Versione", "newtVersion": "Versione",
"architecture": "Architettura", "architecture": "Architettura",
"sites": "Siti", "sites": "Siti",
"siteWgAnyClients": "Usa qualsiasi client WireGuard per connetterti. Dovrai indirizzare le risorse interne utilizzando l'IP del peer.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Compatibile con tutti i client WireGuard", "siteWgCompatibleAllClients": "Compatibile con tutti i client WireGuard",
"siteWgManualConfigurationRequired": "Configurazione manuale richiesta", "siteWgManualConfigurationRequired": "Configurazione manuale richiesta",
"userErrorNotAdminOrOwner": "L'utente non è un amministratore o proprietario", "userErrorNotAdminOrOwner": "L'utente non è un amministratore o proprietario",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Crea Utente Org", "createOrgUser": "Crea Utente Org",
"actionUpdateOrg": "Aggiorna Organizzazione", "actionUpdateOrg": "Aggiorna Organizzazione",
"actionRemoveInvitation": "Rimuovi Invito", "actionRemoveInvitation": "Rimuovi Invito",
"actionRemoveUserRole": "Rimuovi Ruolo Utente",
"actionUpdateUser": "Aggiorna Utente", "actionUpdateUser": "Aggiorna Utente",
"actionGetUser": "Ottieni Utente", "actionGetUser": "Ottieni Utente",
"actionGetOrgUser": "Ottieni Utente Organizzazione", "actionGetOrgUser": "Ottieni Utente Organizzazione",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Applica Progetto", "actionApplyBlueprint": "Applica Progetto",
"actionListBlueprints": "Elenco Blueprints", "actionListBlueprints": "Elenco Blueprints",
"actionGetBlueprint": "Ottieni Blueprint", "actionGetBlueprint": "Ottieni Blueprint",
"actionCreateOrgWideLauncherView": "Crea Visualizzazione Lanscia Org-Wide",
"setupToken": "Configura Token", "setupToken": "Configura Token",
"setupTokenDescription": "Inserisci il token di configurazione dalla console del server.", "setupTokenDescription": "Inserisci il token di configurazione dalla console del server.",
"setupTokenRequired": "Il token di configurazione è richiesto", "setupTokenRequired": "Il token di configurazione è richiesto",
"actionUpdateSite": "Aggiorna Sito", "actionUpdateSite": "Aggiorna Sito",
"actionApproveSite": "Approva Sito",
"actionRejectSite": "Rifiuta Sito",
"actionResetSiteBandwidth": "Reimposta Larghezza Banda Dell'Organizzazione", "actionResetSiteBandwidth": "Reimposta Larghezza Banda Dell'Organizzazione",
"actionListSiteRoles": "Elenca Ruoli Sito Consentiti", "actionListSiteRoles": "Elenca Ruoli Sito Consentiti",
"actionCreateResource": "Crea Risorsa", "actionCreateResource": "Crea Risorsa",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Imposta Codice PIN Risorsa", "actionSetResourcePincode": "Imposta Codice PIN Risorsa",
"actionSetResourceEmailWhitelist": "Imposta Lista Autorizzazioni Email Risorsa", "actionSetResourceEmailWhitelist": "Imposta Lista Autorizzazioni Email Risorsa",
"actionGetResourceEmailWhitelist": "Ottieni Lista Autorizzazioni Email Risorsa", "actionGetResourceEmailWhitelist": "Ottieni Lista Autorizzazioni Email Risorsa",
"actionGetResourcePolicy": "Ottieni la Politica della Risorsa",
"actionUpdateResourcePolicy": "Aggiorna la Politica della Risorsa",
"actionSetResourcePolicyUsers": "Imposta Utenti della Politica Risorsa",
"actionSetResourcePolicyRoles": "Imposta Ruoli della Politica Risorsa",
"actionSetResourcePolicyPassword": "Imposta Password della Politica Risorsa",
"actionSetResourcePolicyPincode": "Imposta Codice PIN della Politica Risorsa",
"actionSetResourcePolicyHeaderAuth": "Imposta Autenticazione Header della Politica Risorsa",
"actionSetResourcePolicyWhitelist": "Imposta Lista Autorizzazioni Email della Politica Risorsa",
"actionSetResourcePolicyRules": "Imposta Regole della Politica Risorsa",
"actionCreateTarget": "Crea Target", "actionCreateTarget": "Crea Target",
"actionDeleteTarget": "Elimina Target", "actionDeleteTarget": "Elimina Target",
"actionGetTarget": "Ottieni Target", "actionGetTarget": "Ottieni Target",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Genera Token di Accesso", "actionGenerateAccessToken": "Genera Token di Accesso",
"actionDeleteAccessToken": "Elimina Token di Accesso", "actionDeleteAccessToken": "Elimina Token di Accesso",
"actionListAccessTokens": "Elenca Token di Accesso", "actionListAccessTokens": "Elenca Token di Accesso",
"actionCreateResourceSessionToken": "Crea Token di Sessione della Risorsa",
"actionCreateResourceRule": "Crea Regola Risorsa", "actionCreateResourceRule": "Crea Regola Risorsa",
"actionDeleteResourceRule": "Elimina Regola Risorsa", "actionDeleteResourceRule": "Elimina Regola Risorsa",
"actionListResourceRules": "Elenca Regole Risorsa", "actionListResourceRules": "Elenca Regole Risorsa",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Elenco Inviti", "actionListInvitations": "Elenco Inviti",
"actionExportLogs": "Esporta Log", "actionExportLogs": "Esporta Log",
"actionViewLogs": "Visualizza Log", "actionViewLogs": "Visualizza Log",
"actionCreateSiteProvisioningKey": "Crea Chiave di Provisioning del Sito",
"actionListSiteProvisioningKeys": "Elenca Chiavi di Provisioning del Sito",
"actionUpdateSiteProvisioningKey": "Aggiorna Chiave di Provisioning del Sito",
"actionDeleteSiteProvisioningKey": "Elimina Chiave di Provisioning del Sito",
"noneSelected": "Nessuna selezione", "noneSelected": "Nessuna selezione",
"orgNotFound2": "Nessuna organizzazione trovata.", "orgNotFound2": "Nessuna organizzazione trovata.",
"search": "Cerca…", "search": "Cerca…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Ultimo Utilizzo",
"otpAuthBack": "Torna alla Password", "otpAuthBack": "Torna alla 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",
"commandPaletteTitle": "Tavolozza dei Comandi",
"commandPaletteDescription": "Cerca pagine, organizzazioni, risorse e azioni",
"commandPaletteSearchPlaceholder": "Cerca pagine, risorse, azioni...",
"commandPaletteNoResults": "Nessun risultato trovato.",
"commandPaletteSearching": "Ricerca...",
"commandPaletteNavigation": "Navigazione",
"commandPaletteOrganizations": "Organizzazioni",
"commandPaletteSites": "Siti",
"commandPaletteResources": "Risorse",
"commandPaletteUsers": "Utenti",
"commandPaletteClients": "Client Macchina",
"commandPaletteActions": "Azioni",
"commandPaletteCreateSite": "Crea Sito",
"commandPaletteCreateProxyResource": "Crea Risorsa Pubblica",
"commandPaletteCreatePrivateResource": "Crea Risorsa Privata",
"commandPaletteCreateUser": "Crea Utente",
"commandPaletteCreateApiKey": "Crea Chiave API",
"commandPaletteCreateMachineClient": "Crea Client Macchina",
"commandPaletteCreateAlertRule": "Crea Regola di Avviso",
"commandPaletteCreateIdentityProvider": "Crea Provider di Identità",
"commandPaletteToggleTheme": "Attiva/Disattiva Tema",
"commandPaletteChooseOrganization": "Scegli Organizzazione",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Impossibile abilitare 2FA", "otpErrorEnable": "Impossibile abilitare 2FA",
"otpErrorEnableDescription": "Si è verificato un errore durante l'abilitazione di 2FA", "otpErrorEnableDescription": "Si è verificato un errore durante l'abilitazione di 2FA",
"otpSetupCheckCode": "Inserisci un codice a 6 cifre", "otpSetupCheckCode": "Inserisci un codice a 6 cifre",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Gestione", "sidebarManagement": "Gestione",
"sidebarBillingAndLicenses": "Fatturazione E Licenze", "sidebarBillingAndLicenses": "Fatturazione E Licenze",
"sidebarLogsAnalytics": "Analisi", "sidebarLogsAnalytics": "Analisi",
"commandSites": "Siti",
"commandActionModeInfo": "Digita \">\" Per Aprire la Modalità Azione",
"commandResources": "Risorse",
"commandProxyResources": "Risorse Pubbliche",
"commandClientResources": "Risorse Private",
"commandClients": "Client",
"commandUserDevices": "Dispositivi Utente",
"commandMachineClients": "Client Macchina",
"commandDomains": "Domini",
"commandRemoteExitNodes": "Nodi Remoti",
"commandTeam": "Squadra",
"commandUsers": "Utenti",
"commandRoles": "Ruoli",
"commandInvitations": "Inviti",
"commandPolicies": "Politiche Condivise",
"commandResourcePolicies": "Politiche delle Risorse Pubbliche",
"commandIdentityProviders": "Fornitori di Identità",
"commandApprovals": "Richieste di Approvazione",
"commandShareableLinks": "Link Condivisibili",
"commandOrganization": "Organizzazione",
"commandLogsAndAnalytics": "Log & Analisi",
"commandLogsAnalytics": "Analisi",
"commandLogsRequest": "Log di Richieste HTTP",
"commandLogsAccess": "Log di Autenticazione",
"commandLogsAction": "Log delle Azioni Amministrative",
"commandLogsConnection": "Log di Connessione",
"commandLogsStreaming": "Streaming di Eventi",
"commandManagement": "Gestione",
"commandAlerting": "Avvisi",
"commandProvisioning": "Provisioning",
"commandBluePrints": "Modelli",
"commandApiKeys": "Chiavi API",
"commandBillingAndLicenses": "Fatturazione & Licenze",
"commandBilling": "Fatturazione",
"commandEnterpriseLicenses": "Licenze",
"commandSettings": "Impostazioni",
"commandLauncher": "Avvio",
"commandResourceLauncher": "Launcher delle Risorse",
"commandSearchResults": "Risultati della Ricerca",
"alertingTitle": "Allerta", "alertingTitle": "Allerta",
"alertingDescription": "Definisci fonti, trigger e azioni per le notifiche", "alertingDescription": "Definisci fonti, trigger e azioni per le notifiche",
"alertingRules": "Regole di allerta", "alertingRules": "Regole di allerta",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Sottodominio: {subdomain}", "domainPickerSubdomain": "Sottodominio: {subdomain}",
"domainPickerNamespace": "Namespace: {namespace}", "domainPickerNamespace": "Namespace: {namespace}",
"domainPickerShowMore": "Mostra Altro", "domainPickerShowMore": "Mostra Altro",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Seleziona regione", "regionSelectorTitle": "Seleziona regione",
"domainPickerRemoteExitNodeWarning": "I domini forniti non sono supportati quando i siti si connettono a nodi di uscita remoti. Affinché le risorse siano disponibili su nodi remoti, utilizza invece un dominio personalizzato.", "domainPickerRemoteExitNodeWarning": "I domini forniti non sono supportati quando i siti si connettono a nodi di uscita remoti. Affinché le risorse siano disponibili su nodi remoti, utilizza invece un dominio personalizzato.",
"regionSelectorInfo": "Selezionare una regione ci aiuta a fornire migliori performance per la tua posizione. Non devi necessariamente essere nella stessa regione del tuo server.", "regionSelectorInfo": "Selezionare una regione ci aiuta a fornire migliori performance per la tua posizione. Non devi necessariamente essere nella stessa regione del tuo server.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domini", "billingDomains": "Domini",
"billingOrganizations": "Organi", "billingOrganizations": "Organi",
"billingRemoteExitNodes": "Nodi Remoti", "billingRemoteExitNodes": "Nodi Remoti",
"billingPublicResources": "Risorse Pubbliche",
"billingPrivateResources": "Risorse Private",
"billingMachineClients": "Client Macchina",
"billingNoLimitConfigured": "Nessun limite configurato", "billingNoLimitConfigured": "Nessun limite configurato",
"billingEstimatedPeriod": "Periodo di Fatturazione Stimato", "billingEstimatedPeriod": "Periodo di Fatturazione Stimato",
"billingIncludedUsage": "Utilizzo Incluso", "billingIncludedUsage": "Utilizzo Incluso",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Quanti utenti puoi usare", "billingUsersInfo": "Quanti utenti puoi usare",
"billingDomainInfo": "Quanti domini puoi usare", "billingDomainInfo": "Quanti domini puoi usare",
"billingRemoteExitNodesInfo": "Quanti nodi remoti puoi usare", "billingRemoteExitNodesInfo": "Quanti nodi remoti puoi usare",
"billingPublicResourcesInfo": "Quante risorse pubbliche puoi utilizzare",
"billingPrivateResourcesInfo": "Quante risorse private puoi utilizzare",
"billingMachineClientsInfo": "Quanti client macchina puoi utilizzare",
"billingLicenseKeys": "Chiavi di Licenza", "billingLicenseKeys": "Chiavi di Licenza",
"billingLicenseKeysDescription": "Gestisci le sottoscrizioni alla chiave di licenza", "billingLicenseKeysDescription": "Gestisci le sottoscrizioni alla chiave di licenza",
"billingLicenseSubscription": "Abbonamento Licenza", "billingLicenseSubscription": "Abbonamento Licenza",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Sottorete", "subnetPlaceholder": "Sottorete",
"addressDescription": "L'indirizzo interno del client. Deve rientrare nella sottorete dell'organizzazione.", "addressDescription": "L'indirizzo interno del client. Deve rientrare nella sottorete dell'organizzazione.",
"selectSites": "Seleziona siti", "selectSites": "Seleziona siti",
"selectLabels": "Seleziona etichette",
"sitesDescription": "Il cliente avrà connettività ai siti selezionati", "sitesDescription": "Il cliente avrà connettività ai siti selezionati",
"clientInstallOlm": "Installa Olm", "clientInstallOlm": "Installa Olm",
"clientInstallOlmDescription": "Avvia Olm sul tuo sistema", "clientInstallOlmDescription": "Avvia Olm sul tuo sistema",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Pubblico", "resourcesTableProxyResources": "Pubblico",
"resourcesTableClientResources": "Privato", "resourcesTableClientResources": "Privato",
"resourcesTableNoProxyResourcesFound": "Nessuna risorsa proxy trovata.", "resourcesTableNoProxyResourcesFound": "Nessuna risorsa proxy trovata.",
"resourcesTableNoInternalResourcesFound": "Nessuna risorsa interna trovata.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Destinazione", "resourcesTableDestination": "Destinazione",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Indirizzo Alias", "resourcesTableAliasAddress": "Indirizzo Alias",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Annulla", "editInternalResourceDialogCancel": "Annulla",
"editInternalResourceDialogSaveResource": "Salva Risorsa", "editInternalResourceDialogSaveResource": "Salva Risorsa",
"editInternalResourceDialogSuccess": "Successo", "editInternalResourceDialogSuccess": "Successo",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Risorsa interna aggiornata con successo", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Errore", "editInternalResourceDialogError": "Errore",
"editInternalResourceDialogFailedToUpdateInternalResource": "Impossibile aggiornare la risorsa interna", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Il nome è obbligatorio", "editInternalResourceDialogNameRequired": "Il nome è obbligatorio",
"editInternalResourceDialogNameMaxLength": "Il nome deve essere inferiore a 255 caratteri", "editInternalResourceDialogNameMaxLength": "Il nome deve essere inferiore a 255 caratteri",
"editInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1", "editInternalResourceDialogProxyPortMin": "La porta proxy deve essere almeno 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.", "editInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.",
"createInternalResourceDialogNoSitesAvailable": "Nessun Sito Disponibile", "createInternalResourceDialogNoSitesAvailable": "Nessun Sito Disponibile",
"createInternalResourceDialogNoSitesAvailableDescription": "Devi avere almeno un sito Newt con una subnet configurata per creare risorse interne.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Chiudi", "createInternalResourceDialogClose": "Chiudi",
"createInternalResourceDialogCreateClientResource": "Crea Risorsa Privata", "createInternalResourceDialogCreateClientResource": "Crea Risorsa Privata",
"createInternalResourceDialogCreateClientResourceDescription": "Crea una nuova risorsa che sarà accessibile solo ai client connessi all'organizzazione", "createInternalResourceDialogCreateClientResourceDescription": "Crea una nuova risorsa che sarà accessibile solo ai client connessi all'organizzazione",
"privateResourceGeneralDescription": "Configura il nome, l'identificativo e altre impostazioni generali delle risorse.",
"privateResourceCreatePageSeeAll": "Vedi Tutte le Risorse Private",
"privateResourceAllowIcmpPing": "Consenti ICMP Ping",
"privateResourceNetworkAccess": "Accesso alla Rete",
"privateResourceNetworkAccessDescription": "Controlla l'accesso alle porte TCP/UDP e se ICMP ping è consentito per questa risorsa.",
"hostSettings": "Impostazioni dell'Host",
"cidrSettings": "Impostazioni CIDR",
"createInternalResourceDialogResourceProperties": "Proprietà della Risorsa", "createInternalResourceDialogResourceProperties": "Proprietà della Risorsa",
"createInternalResourceDialogName": "Nome", "createInternalResourceDialogName": "Nome",
"createInternalResourceDialogSite": "Sito", "createInternalResourceDialogSite": "Sito",
"selectSite": "Seleziona sito...", "selectSite": "Seleziona sito...",
"multiSitesSelectorSitesCount": "{count, plural, one {# sito} other {# siti}}", "multiSitesSelectorSitesCount": "{count, plural, one {# sito} other {# siti}}",
"labelsSelectorLabelsCount": "{count, plural, one {# etichetta} other {# etichette}}",
"noSitesFound": "Nessun sito trovato.", "noSitesFound": "Nessun sito trovato.",
"createInternalResourceDialogProtocol": "Protocollo", "createInternalResourceDialogProtocol": "Protocollo",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Annulla", "createInternalResourceDialogCancel": "Annulla",
"createInternalResourceDialogCreateResource": "Crea Risorsa", "createInternalResourceDialogCreateResource": "Crea Risorsa",
"createInternalResourceDialogSuccess": "Successo", "createInternalResourceDialogSuccess": "Successo",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Risorsa interna creata con successo", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Errore", "createInternalResourceDialogError": "Errore",
"createInternalResourceDialogFailedToCreateInternalResource": "Impossibile creare la risorsa interna", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Il nome è obbligatorio", "createInternalResourceDialogNameRequired": "Il nome è obbligatorio",
"createInternalResourceDialogNameMaxLength": "Il nome non deve superare i 255 caratteri", "createInternalResourceDialogNameMaxLength": "Il nome non deve superare i 255 caratteri",
"createInternalResourceDialogPleaseSelectSite": "Si prega di selezionare un sito", "createInternalResourceDialogPleaseSelectSite": "Si prega di selezionare un sito",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "La gamma CIDR della risorsa sulla rete del sito.", "createInternalResourceDialogDestinationCidrDescription": "La gamma CIDR della risorsa sulla rete del sito.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.", "createInternalResourceDialogAliasDescription": "Un alias DNS interno opzionale per questa risorsa.",
"internalResourceAliasLocalWarning": "Gli alias che terminano in .local possono causare problemi di risoluzione a causa di mDNS su alcune reti.",
"internalResourceDownstreamSchemeRequired": "Il metodo è richiesto per risorse HTTP", "internalResourceDownstreamSchemeRequired": "Il metodo è richiesto per risorse HTTP",
"internalResourceHttpPortRequired": "Porta di destinazione richiesta per risorse HTTP", "internalResourceHttpPortRequired": "Porta di destinazione richiesta per risorse HTTP",
"siteConfiguration": "Configurazione", "siteConfiguration": "Configurazione",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Nodi Remoti", "sidebarRemoteExitNodes": "Nodi Remoti",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Segreto", "remoteExitNodeSecretKey": "Segreto",
"remoteExitNodeNetworkingTitle": "Impostazioni di Rete",
"remoteExitNodeNetworkingDescription": "Configura come questo nodo di uscita remoto indirizza il traffico e quali siti preferiscono connettersi tramite esso. Caratteristiche avanzate da utilizzare con le configurazioni di rete backhaul.",
"remoteExitNodeNetworkingSave": "Salva Impostazioni",
"remoteExitNodeNetworkingSaveSuccessTitle": "Impostazioni di rete salvate",
"remoteExitNodeNetworkingSaveSuccessDescription": "Le impostazioni di rete sono state aggiornate con successo.",
"remoteExitNodeNetworkingSaveError": "Impossibile salvare le impostazioni di rete",
"remoteExitNodeNetworkingSubnetsTitle": "Sottoreti Remote",
"remoteExitNodeNetworkingSubnetsDescription": "Definisci gli intervalli CIDR che questo nodo di uscita remota inoltrerà il traffico. Digita un CIDR valido (ad esempio <code>10.0.0.0/8</code>) e premi Invio per aggiungerlo.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Aggiungi un intervallo CIDR (ad esempio 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Caricamento sottoreti fallito",
"remoteExitNodeNetworkingLabelsTitle": "Etichette Preferenze",
"remoteExitNodeNetworkingLabelsDescription": "I siti con queste etichette saranno collegati attraverso questo nodo di uscita remoto.",
"remoteExitNodeNetworkingLabelsButtonText": "Seleziona etichette...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Cerca etichette...",
"remoteExitNodeNetworkingLabelsLoadError": "Caricamento etichette fallito",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Crea Nodo Remoto", "title": "Crea Nodo Remoto",
"description": "Crea un nuovo nodo server proxy e relay remoto ospitato in proprio", "description": "Crea un nuovo nodo server proxy e relay remoto ospitato in proprio",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Non ci sono nodi disponibili per questa organizzazione. Crea un nodo prima per usare i siti locali.", "noRemoteExitNodesAvailableDescription": "Non ci sono nodi disponibili per questa organizzazione. Crea un nodo prima per usare i siti locali.",
"exitNode": "Nodo di Uscita", "exitNode": "Nodo di Uscita",
"country": "Paese", "country": "Paese",
"countryIsNot": "Paese Non È",
"rulesMatchCountry": "Attualmente basato sull'IP di origine", "rulesMatchCountry": "Attualmente basato sull'IP di origine",
"region": "Regione", "region": "Regione",
"selectRegion": "Seleziona regione", "selectRegion": "Seleziona regione",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC provider", "idpGoogleDescription": "Google OAuth2/OIDC provider",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Sottorete", "subnet": "Sottorete",
"utilitySubnet": "Sottorete di utilità",
"subnetDescription": "La sottorete per la configurazione di rete di questa organizzazione.", "subnetDescription": "La sottorete per la configurazione di rete di questa organizzazione.",
"customDomain": "Dominio Personalizzato", "customDomain": "Dominio Personalizzato",
"authPage": "Pagine di Autenticazione", "authPage": "Pagine di Autenticazione",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "È richiesta la configurazione di autenticazione a due fattori. Effettua nuovamente l'accesso tramite {dashboardUrl}/auth/login completa questo passaggio. Quindi, torna qui.", "twoFactorSetupRequired": "È richiesta la configurazione di autenticazione a due fattori. Effettua nuovamente l'accesso tramite {dashboardUrl}/auth/login completa questo passaggio. Quindi, torna qui.",
"additionalSecurityRequired": "Necessaria Sicurezza Aggiuntiva", "additionalSecurityRequired": "Necessaria Sicurezza Aggiuntiva",
"organizationRequiresAdditionalSteps": "Questa organizzazione richiede ulteriori passi di sicurezza prima di poter accedere alle risorse.", "organizationRequiresAdditionalSteps": "Questa organizzazione richiede ulteriori passi di sicurezza prima di poter accedere alle risorse.",
"sessionExpired": "Sessione Scaduta",
"sessionExpiredReauthRequired": "La tua sessione è scaduta in conformità con la politica di sicurezza della tua organizzazione. Effettua nuovamente l'autenticazione per continuare.",
"reauthenticate": "Riautenticazione",
"completeTheseSteps": "Completa questi passaggi", "completeTheseSteps": "Completa questi passaggi",
"enableTwoFactorAuthentication": "Abilita autenticazione a due fattori", "enableTwoFactorAuthentication": "Abilita autenticazione a due fattori",
"completeSecuritySteps": "Passi Di Sicurezza Completa", "completeSecuritySteps": "Passi Di Sicurezza Completa",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Indirizzo Di Origine", "sourceAddress": "Indirizzo Di Origine",
"destinationAddress": "Indirizzo Di Destinazione", "destinationAddress": "Indirizzo Di Destinazione",
"duration": "Durata", "duration": "Durata",
"licenseRequiredToUse": "Per utilizzare questa funzione è necessaria una licenza <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> o <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> . <bookADemoLink>Prenota una demo o una prova POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "L' <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> è necessaria per utilizzare questa funzione. Questa funzione è disponibile anche in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Prenota una demo o una prova POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Risolutore Di Certificato", "certResolver": "Risolutore Di Certificato",
"certResolverDescription": "Selezionare il risolutore di certificati da usare per questa risorsa.", "certResolverDescription": "Selezionare il risolutore di certificati da usare per questa risorsa.",
"selectCertResolver": "Seleziona Risolutore Di Certificato", "selectCertResolver": "Seleziona Risolutore Di Certificato",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Manca l'ID dell'organizzazione o del dominio", "orgOrDomainIdMissing": "Manca l'ID dell'organizzazione o del dominio",
"loadingDNSRecords": "Caricamento record DNS...", "loadingDNSRecords": "Caricamento record DNS...",
"olmUpdateAvailableInfo": "È disponibile una versione aggiornata di Olm. Si prega di aggiornare all'ultima versione per la migliore esperienza.", "olmUpdateAvailableInfo": "È disponibile una versione aggiornata di Olm. Si prega di aggiornare all'ultima versione per la migliore esperienza.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "È disponibile una versione aggiornata. Si prega di aggiornare all'ultima versione per la migliore esperienza.",
"client": "Client", "client": "Client",
"proxyProtocol": "Impostazioni Protocollo Proxy", "proxyProtocol": "Impostazioni Protocollo Proxy",
"proxyProtocolDescription": "Configurare il protocollo proxy per preservare gli indirizzi IP client per i servizi TCP.", "proxyProtocolDescription": "Configurare il protocollo proxy per preservare gli indirizzi IP client per i servizi TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Aggiungi Utenti", "editInternalResourceDialogAddUsers": "Aggiungi Utenti",
"editInternalResourceDialogAddClients": "Aggiungi Clienti", "editInternalResourceDialogAddClients": "Aggiungi Clienti",
"editInternalResourceDialogDestinationLabel": "Destinazione", "editInternalResourceDialogDestinationLabel": "Destinazione",
"editInternalResourceDialogDestinationDescription": "Specifica l'indirizzo di destinazione per la risorsa interna. Può essere un hostname, indirizzo IP o un intervallo CIDR a seconda della modalità selezionata. Opzionalmente imposta un alias DNS interno per una più facile identificazione.", "editInternalResourceDialogDestinationDescription": "Configura come i client raggiungono questa risorsa.",
"internalResourceFormMultiSiteRoutingHelp": "Selezionare più siti consente un routing resiliente e Failover per alta disponibilità.", "internalResourceFormMultiSiteRoutingHelp": "Selezionare più siti consente un routing resiliente e Failover per alta disponibilità.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Scopri di più", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Scopri di più",
"editInternalResourceDialogPortRestrictionsDescription": "Limita l'accesso a porte TCP/UDP specifiche o consenti/blocca tutte le porte.", "editInternalResourceDialogPortRestrictionsDescription": "Limita l'accesso a porte TCP/UDP specifiche o consenti/blocca tutte le porte.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Lista Autorizzazioni Email", "memberPortalEmailWhitelist": "Lista Autorizzazioni Email",
"memberPortalResourceDisabled": "Risorsa Disabilitata", "memberPortalResourceDisabled": "Risorsa Disabilitata",
"memberPortalShowingResources": "Mostrando {start}-{end} di {total} risorse", "memberPortalShowingResources": "Mostrando {start}-{end} di {total} risorse",
"resourceLauncherTitle": "Lanscia Risorse",
"resourceSidebarLauncherTitle": "Avvio",
"resourceLauncherDescription": "Visualizza tutte le risorse disponibili e avviale da un unico hub centrale",
"resourceLauncherSearchPlaceholder": "Cerca le tue risorse...",
"resourceLauncherDefaultView": "Predefinito",
"resourceLauncherSaveView": "Salva Visualizzazione",
"resourceLauncherSaveToCurrentView": "Salva alla Visualizzazione Corrente",
"resourceLauncherSaveDefaultPersonal": "Salva per Me",
"resourceLauncherResetView": "Reimposta Visualizzazione",
"resourceLauncherResetSystemDefault": "Ripristina le Impostazioni di Sistema",
"resourceLauncherSystemDefaultRestored": "Ripristinato il default di sistema",
"resourceLauncherSystemDefaultRestoredDescription": "La vista predefinita è stata reimpostata alle impostazioni originali.",
"resourceLauncherSaveAsNewView": "Salva come Nuova Visualizzazione",
"resourceLauncherSaveAsNewViewDescription": "Dai un nome a questa visualizzazione per salvare i tuoi filtri e layout attuali.",
"resourceLauncherSaveForEveryone": "Salva per Tutti",
"resourceLauncherSaveForEveryoneDescription": "Condividi questa visualizzazione con tutti i membri dell'organizzazione. Quando non è selezionata, la visualizzazione è visibile solo a te.",
"resourceLauncherMakePersonal": "Rendi Personale",
"resourceLauncherFilter": "Filtro",
"resourceLauncherFilterWithCount": "Filtro, {count} applicato/i",
"resourceLauncherSort": "Ordina",
"resourceLauncherSortAscending": "Ordina in ordine crescente",
"resourceLauncherSortDescending": "Ordina in ordine decrescente",
"resourceLauncherSettings": "Impostazioni",
"resourceLauncherGroupBy": "Raggruppa per",
"resourceLauncherGroupBySite": "Sito",
"resourceLauncherGroupByLabel": "Etichetta",
"resourceLauncherGroupByNone": "Nessuno",
"resourceLauncherLayout": "Layout",
"resourceLauncherLayoutGrid": "Griglia",
"resourceLauncherLayoutList": "Lista",
"resourceLauncherShowLabels": "Mostra Etichette",
"resourceLauncherShowSiteTags": "Mostra Tag di Sito",
"resourceLauncherShowRecents": "Mostra Recenti",
"resourceLauncherDeleteView": "Elimina Visualizzazione",
"resourceLauncherDeleteViewTitle": "Elimina Vista",
"resourceLauncherDeleteViewQuestion": "Sei sicuro di voler eliminare questa vista del launcher?",
"resourceLauncherDeleteViewConfirm": "Elimina Vista",
"resourceLauncherViewAsAdmin": "Visualizza come Admin",
"resourceLauncherResourceDetailsDescription": "Informazioni e stato della connessione per questa risorsa.",
"resourceLauncherResourceDetails": "Dettagli Risorsa",
"resourceLauncherAuthMethodsDescription": "Metodi di autenticazione abilitati per questa risorsa.",
"resourceLauncherPrivateClientRequired": "Connettiti con un client sul tuo dispositivo per accedere a questa risorsa privatamente.",
"resourceLauncherPrivateClientRequiredTitle": "Connessione Client Richiesta",
"resourceLauncherDownloadClient": "Scarica client",
"resourceLauncherFailedToLoadDetails": "Impossibile caricare i dettagli della risorsa. Potresti non avere più accesso a questa risorsa.",
"resourceLauncherNoPortRestrictions": "Nessuna restrizione di porta",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Non Etichettato",
"resourceLauncherNoSite": "Nessun Sito",
"resourceLauncherNoResourcesInGroup": "Nessuna risorsa in questo gruppo",
"resourceLauncherEmptyStateTitle": "Non ci sono risorse disponibili",
"resourceLauncherEmptyStateDescription": "Non hai ancora accesso a nessuna risorsa. Contatta il tuo amministratore per richiedere l'accesso.",
"resourceLauncherEmptyStateNoResultsTitle": "Nessuna risorsa trovata",
"resourceLauncherEmptyStateNoResultsDescription": "Nessuna risorsa corrisponde alla tua ricerca o ai tuoi filtri attuali. Prova a modificarli per trovare ciò che stai cercando.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Nessuna risorsa corrisponde a \"{query}\". Prova a modificare la tua ricerca o a cancellare i filtri per vedere tutte le risorse.",
"resourceLauncherSearchFirstTitle": "Cerca o Filtra per Navigare",
"resourceLauncherSearchFirstDescription": "Hai accesso a molte risorse. Usa la ricerca o filtra per sito o etichetta per trovare ciò di cui hai bisogno.",
"resourceLauncherSiteGroupingDisabled": "Raggruppamento per sito non disponibile su questa scala. Filtra per sito per raggruppare un set più piccolo.",
"resourceLauncherLabelGroupingDisabled": "Raggruppamento per etichetta non disponibile su questa scala.",
"resourceLauncherCompactModeHint": "Mostrando un elenco semplificato per una navigazione più veloce. Usa la ricerca o i filtri per restringere i risultati.",
"resourceLauncherCompactGroupingHint": "Applica filtri di sito o etichetta per abilitare il raggruppamento.",
"resourceLauncherCopiedToClipboard": "Copiato negli appunti",
"resourceLauncherCopiedAccessDescription": "L'accesso alla risorsa è stato copiato nei tuoi appunti.",
"resourceLauncherViewNamePlaceholder": "Nome Visualizzazione",
"resourceLauncherViewNameLabel": "Nome Visualizzazione",
"resourceLauncherViewSaved": "Visualizzazione salvata",
"resourceLauncherViewSavedDescription": "La tua visualizzazione del lanscia è stata salvata.",
"resourceLauncherViewSaveFailed": "Impossibile salvare la visualizzazione",
"resourceLauncherViewSaveFailedDescription": "Impossibile salvare la visualizzazione del lanscia. Per favore riprova.",
"resourceLauncherViewDeleted": "Visualizzazione eliminata",
"resourceLauncherViewDeletedDescription": "La visualizzazione del lanscia è stata eliminata.",
"resourceLauncherViewDeleteFailed": "Impossibile eliminare la visualizzazione",
"resourceLauncherViewDeleteFailedDescription": "Non è stato possibile eliminare la visualizzazione del lanscia. Per favore riprova.",
"memberPortalPrevious": "Precedente", "memberPortalPrevious": "Precedente",
"memberPortalNext": "Successivo", "memberPortalNext": "Successivo",
"httpSettings": "Impostazioni HTTP", "httpSettings": "Impostazioni HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "È richiesta una chiave privata", "sshPrivateKeyRequired": "È richiesta una chiave privata",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Inserisci la tua password VNC per connetterti", "vncSignInDescription": "Inserisci le tue credenziali VNC per connetterti",
"vncUsernameOptional": "Nome utente (facoltativo)",
"vncPasswordOptional": "Password (opzionale)", "vncPasswordOptional": "Password (opzionale)",
"vncNoResourceTarget": "Nessun bersaglio di risorsa disponibile", "vncNoResourceTarget": "Nessun bersaglio di risorsa disponibile",
"vncFailedToLoadNovnc": "Impossibile caricare noVNC", "vncFailedToLoadNovnc": "Impossibile caricare noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Caricamento fallito", "rdpUploadFailed": "Caricamento fallito",
"rdpUnicodeKeyboardMode": "Modalità tastiera Unicode", "rdpUnicodeKeyboardMode": "Modalità tastiera Unicode",
"sessionToolbarShow": "Mostra barra degli strumenti", "sessionToolbarShow": "Mostra barra degli strumenti",
"sessionToolbarHide": "Nascondi barra degli strumenti" "sessionToolbarHide": "Nascondi barra degli strumenti",
"actionUpdateSiteApprovals": "Aggiorna Approvazioni del Sito"
} }
+247 -19
View File
@@ -66,9 +66,15 @@
"local": "로컬", "local": "로컬",
"edit": "편집", "edit": "편집",
"siteConfirmDelete": "사이트 삭제 확인", "siteConfirmDelete": "사이트 삭제 확인",
"siteConfirmDeleteAndResources": "사이트 및 리소스 삭제 확인",
"siteDelete": "사이트 삭제", "siteDelete": "사이트 삭제",
"siteDeleteAndResources": "사이트 및 리소스 삭제",
"siteMessageRemove": "삭제되면 사이트에 더 이상 액세스할 수 없습니다. 사이트와 연결된 모든 대상도 삭제됩니다.", "siteMessageRemove": "삭제되면 사이트에 더 이상 액세스할 수 없습니다. 사이트와 연결된 모든 대상도 삭제됩니다.",
"siteMessageRemoveAndResources": "이 사이트와 연결된 모든 공용 및 개인 리소스는 다른 사이트에도 연결되어 있더라도 영구적으로 삭제됩니다.",
"siteQuestionRemove": "조직에서 사이트를 제거하시겠습니까?", "siteQuestionRemove": "조직에서 사이트를 제거하시겠습니까?",
"siteQuestionRemoveAndResources": "이 사이트와 모든 관련 리소스를 삭제하시겠습니까?",
"sitesTableDeleteSite": "사이트 삭제",
"sitesTableDeleteSiteAndResources": "사이트 및 리소스 삭제",
"siteManageSites": "사이트 관리", "siteManageSites": "사이트 관리",
"siteDescription": "프라이빗 네트워크로의 연결을 활성화하려면 사이트를 생성하고 관리하세요.", "siteDescription": "프라이빗 네트워크로의 연결을 활성화하려면 사이트를 생성하고 관리하세요.",
"sitesBannerTitle": "모든 네트워크 연결", "sitesBannerTitle": "모든 네트워크 연결",
@@ -117,6 +123,16 @@
"siteUpdated": "사이트가 업데이트되었습니다", "siteUpdated": "사이트가 업데이트되었습니다",
"siteUpdatedDescription": "사이트가 업데이트되었습니다.", "siteUpdatedDescription": "사이트가 업데이트되었습니다.",
"siteGeneralDescription": "이 사이트에 대한 일반 설정을 구성하세요.", "siteGeneralDescription": "이 사이트에 대한 일반 설정을 구성하세요.",
"siteRestartTitle": "사이트 다시 시작",
"siteRestartDescription": "이 사이트의 WireGuard 터널을 다시 시작합니다. 일시적으로 연결이 중단될 수 있습니다.",
"siteRestartBody": "사이트 터널이 제대로 작동하지 않을 경우, 호스트를 재시작하지 않고 다시 연결을 강제하려면 이 옵션을 사용하세요.",
"siteRestartButton": "사이트 다시 시작",
"siteRestartDialogMessage": "<b>{name}</b>의 WireGuard 터널을 재시작하시겠습니까? 이 작업으로 인해 사이트의 연결이 일시적으로 중단될 수 있습니다.",
"siteRestartWarning": "터널을 재시작하는 동안 사이트가 일시적으로 연결이 끊깁니다.",
"siteRestarted": "사이트가 재시작되었습니다",
"siteRestartedDescription": "WireGuard 터널이 재시작되었습니다.",
"siteErrorRestart": "사이트 재시작 실패",
"siteErrorRestartDescription": "사이트를 재시작하는 중 오류가 발생했습니다.",
"siteSettingDescription": "사이트에서 설정을 구성하세요.", "siteSettingDescription": "사이트에서 설정을 구성하세요.",
"siteResourcesTab": "리소스", "siteResourcesTab": "리소스",
"siteResourcesNoneOnSite": "이 사이트에는 아직 공용 또는 개인 리소스가 없습니다.", "siteResourcesNoneOnSite": "이 사이트에는 아직 공용 또는 개인 리소스가 없습니다.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "공유 가능한 링크 삭제 확인", "shareDeleteConfirm": "공유 가능한 링크 삭제 확인",
"shareQuestionRemove": "이 공유 링크를 삭제하시겠습니까?", "shareQuestionRemove": "이 공유 링크를 삭제하시겠습니까?",
"shareMessageRemove": "삭제되면 링크가 더 이상 작동하지 않으며, 이를 사용하는 모든 사용자는 자원에 대한 접근을 잃게 됩니다.", "shareMessageRemove": "삭제되면 링크가 더 이상 작동하지 않으며, 이를 사용하는 모든 사용자는 자원에 대한 접근을 잃게 됩니다.",
"shareTokenDescription": "액세스 토큰은 쿼리 매개변수 또는 요청 헤더의 두 가지 방법으로 전달될 수 있습니다. 이는 인증된 액세스를 위해 클라이언트에서 모든 요청마다 전달되어야 합니다.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "액세스 토큰", "accessToken": "액세스 토큰",
"usageExamples": "사용 예", "usageExamples": "사용 예",
"tokenId": "토큰 ID", "tokenId": "토큰 ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "제목 (선택 사항)", "shareTitleOptional": "제목 (선택 사항)",
"sharePathOptional": "경로 (선택 사항)", "sharePathOptional": "경로 (선택 사항)",
"sharePathDescription": "링크는 인증 후 이 경로로 사용자를 리디렉션합니다.", "sharePathDescription": "링크는 인증 후 이 경로로 사용자를 리디렉션합니다.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "만료됨", "expireIn": "만료됨",
"neverExpire": "만료되지 않음", "neverExpire": "만료되지 않음",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "만료 시간은 링크가 사용 가능하고 리소스에 접근할 수 있는 기간입니다. 이 시간이 지나면 링크는 더 이상 작동하지 않으며, 이 링크를 사용한 사용자는 리소스에 대한 접근 권한을 잃게 됩니다.", "shareExpireDescription": "만료 시간은 링크가 사용 가능하고 리소스에 접근할 수 있는 기간입니다. 이 시간이 지나면 링크는 더 이상 작동하지 않으며, 이 링크를 사용한 사용자는 리소스에 대한 접근 권한을 잃게 됩니다.",
"shareSeeOnce": "이 링크는 한 번만 볼 수 있습니다. 반드시 복사해 두세요.", "shareSeeOnce": "이 링크는 한 번만 볼 수 있습니다. 반드시 복사해 두세요.",
"shareAccessHint": "이 링크가 있는 누구나 리소스에 접근할 수 있습니다. 주의해서 공유하세요.", "shareAccessHint": "이 링크가 있는 누구나 리소스에 접근할 수 있습니다. 주의해서 공유하세요.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "포트 번호를 사용하여 원격 노드에 연결해야 합니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.", "resourceRawDescriptionCloud": "포트 번호를 사용하여 원격 노드에 연결해야 합니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.",
"resourceCreate": "리소스 생성", "resourceCreate": "리소스 생성",
"resourceCreateDescription": "아래 단계를 따라 새 리소스를 생성하세요.", "resourceCreateDescription": "아래 단계를 따라 새 리소스를 생성하세요.",
"resourcePublicCreate": "공용 리소스 생성",
"resourcePublicCreateDescription": "웹 브라우저를 통해 접근할 수 있는 새로운 공용 리소스를 생성하려면 아래 단계를 따르십시오",
"resourceCreateGeneralDescription": "이름 및 유형을 포함한 기본 리소스 설정 구성", "resourceCreateGeneralDescription": "이름 및 유형을 포함한 기본 리소스 설정 구성",
"resourceSeeAll": "모든 리소스 보기", "resourceSeeAll": "모든 리소스 보기",
"resourceCreateGeneral": "일반", "resourceCreateGeneral": "일반",
@@ -431,8 +455,14 @@
"provisioningManage": "프로비저닝", "provisioningManage": "프로비저닝",
"provisioningDescription": "프로비저닝 키를 관리하고 승인을 기다리는 사이트를 검토합니다.", "provisioningDescription": "프로비저닝 키를 관리하고 승인을 기다리는 사이트를 검토합니다.",
"pendingSites": "대기중인 사이트", "pendingSites": "대기중인 사이트",
"siteApproveSuccess": "사이트가 성공적으로 승인되었습니다", "siteApproveSuccess": "사이트 및 관련 리소스가 성공적으로 승인되었습니다",
"siteApproveError": "사이트 승인 오류", "siteApproveError": "사이트 승인 오류",
"siteReject": "사이트 거부",
"siteQuestionReject": "이 사이트를 거부하시겠습니까?",
"siteMessageReject": "이렇게 하면 펜딩 중인 사이트 및 관련 리소스가 영구적으로 삭제됩니다.",
"siteConfirmReject": "사이트 거부 확인",
"siteRejectSuccess": "사이트가 성공적으로 거부되었습니다",
"siteRejectError": "사이트 거부 오류",
"provisioningKeys": "프로비저닝 키", "provisioningKeys": "프로비저닝 키",
"searchProvisioningKeys": "프로비저닝 키 검색...", "searchProvisioningKeys": "프로비저닝 키 검색...",
"provisioningKeysAdd": "프로비저닝 키 생성", "provisioningKeysAdd": "프로비저닝 키 생성",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "절대", "provisioningKeysNeverUsed": "절대",
"provisioningKeysEdit": "프로비저닝 키 수정", "provisioningKeysEdit": "프로비저닝 키 수정",
"provisioningKeysEditDescription": "이 키의 최대 배치 크기 및 만료 시간을 업데이트하세요.", "provisioningKeysEditDescription": "이 키의 최대 배치 크기 및 만료 시간을 업데이트하세요.",
"provisioningKeysApproveNewSites": "새로운 사이트 승인", "provisioningKeysApproveNewSites": "새 사이트 승인",
"provisioningKeysApproveNewSitesDescription": "이 키를 등록하는 사이트를 자동으로 승인합니다.", "provisioningKeysApproveNewSitesDescription": "이 키를 등록하는 사이트를 자동으로 승인합니다.",
"provisioningKeysUpdateError": "프로비저닝 키 업데이트 오류", "provisioningKeysUpdateError": "프로비저닝 키 업데이트 오류",
"provisioningKeysUpdated": "프로비저닝 키가 업데이트되었습니다", "provisioningKeysUpdated": "프로비저닝 키가 업데이트되었습니다",
@@ -597,7 +627,8 @@
"idpNameInternal": "내부", "idpNameInternal": "내부",
"emailInvalid": "유효하지 않은 이메일 주소입니다.", "emailInvalid": "유효하지 않은 이메일 주소입니다.",
"inviteValidityDuration": "지속 시간을 선택하십시오.", "inviteValidityDuration": "지속 시간을 선택하십시오.",
"accessRoleSelectPlease": "역할을 선택하세요", "accessRoleSelectPlease": "사용자는 적어도 하나의 역할에 속해야 합니다.",
"accessRoleRequired": "역할 필요",
"removeOwnAdminRoleConfirmTitle": "관리자 권한을 제거하시겠습니까?", "removeOwnAdminRoleConfirmTitle": "관리자 권한을 제거하시겠습니까?",
"removeOwnAdminRoleConfirmDescription": "저장 후 이 조직에 대한 관리자 권한이 없어집니다. 필요한 경우 다른 관리자가 접근 권한을 복구할 수 있습니다.", "removeOwnAdminRoleConfirmDescription": "저장 후 이 조직에 대한 관리자 권한이 없어집니다. 필요한 경우 다른 관리자가 접근 권한을 복구할 수 있습니다.",
"removeOwnAdminRoleConfirmButton": "내 관리자 권한 제거", "removeOwnAdminRoleConfirmButton": "내 관리자 권한 제거",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "기본 헤더 인증", "policyAuthHeaderAuthTitle": "기본 헤더 인증",
"policyAuthHeaderAuthDescription": "각 요청에서 맞춤 HTTP 헤더 이름 및 값을 검증", "policyAuthHeaderAuthDescription": "각 요청에서 맞춤 HTTP 헤더 이름 및 값을 검증",
"policyAuthHeaderAuthSummary": "헤더 구성됨", "policyAuthHeaderAuthSummary": "헤더 구성됨",
"policyAuthHeaderName": "헤더 이름", "policyAuthHeaderName": "사용자 이름",
"policyAuthHeaderValue": "예상 값", "policyAuthHeaderValue": "비밀번호",
"policyAuthSetPasscode": "패스코드 설정", "policyAuthSetPasscode": "패스코드 설정",
"policyAuthSetPincode": "PIN 코드 설정", "policyAuthSetPincode": "PIN 코드 설정",
"policyAuthSetEmailWhitelist": "이메일 화이트리스트 설정", "policyAuthSetEmailWhitelist": "이메일 화이트리스트 설정",
@@ -903,7 +934,7 @@
"newtVersion": "버전", "newtVersion": "버전",
"architecture": "아키텍처", "architecture": "아키텍처",
"sites": "사이트", "sites": "사이트",
"siteWgAnyClients": "WireGuard 클라이언트를 사용하여 연결하십시오. 피어 IP를 사용하여 내부 리소스에 접근해야 합니다.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "모든 WireGuard 클라이언트와 호환", "siteWgCompatibleAllClients": "모든 WireGuard 클라이언트와 호환",
"siteWgManualConfigurationRequired": "수동 구성이 필요합니다.", "siteWgManualConfigurationRequired": "수동 구성이 필요합니다.",
"userErrorNotAdminOrOwner": "사용자는 관리자 또는 소유자가 아닙니다.", "userErrorNotAdminOrOwner": "사용자는 관리자 또는 소유자가 아닙니다.",
@@ -1378,6 +1409,7 @@
"createOrgUser": "조직 사용자 생성", "createOrgUser": "조직 사용자 생성",
"actionUpdateOrg": "조직 업데이트", "actionUpdateOrg": "조직 업데이트",
"actionRemoveInvitation": "초대 제거", "actionRemoveInvitation": "초대 제거",
"actionRemoveUserRole": "사용자 역할 제거",
"actionUpdateUser": "사용자 업데이트", "actionUpdateUser": "사용자 업데이트",
"actionGetUser": "사용자 조회", "actionGetUser": "사용자 조회",
"actionGetOrgUser": "조직 사용자 가져오기", "actionGetOrgUser": "조직 사용자 가져오기",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "청사진 적용", "actionApplyBlueprint": "청사진 적용",
"actionListBlueprints": "청사진 목록", "actionListBlueprints": "청사진 목록",
"actionGetBlueprint": "청사진 가져오기", "actionGetBlueprint": "청사진 가져오기",
"actionCreateOrgWideLauncherView": "조직 전체 런처 보기 생성",
"setupToken": "설정 토큰", "setupToken": "설정 토큰",
"setupTokenDescription": "서버 콘솔에서 설정 토큰 입력.", "setupTokenDescription": "서버 콘솔에서 설정 토큰 입력.",
"setupTokenRequired": "설정 토큰이 필요합니다", "setupTokenRequired": "설정 토큰이 필요합니다",
"actionUpdateSite": "사이트 업데이트", "actionUpdateSite": "사이트 업데이트",
"actionApproveSite": "사이트 승인",
"actionRejectSite": "사이트 거부",
"actionResetSiteBandwidth": "조직 대역폭 재설정", "actionResetSiteBandwidth": "조직 대역폭 재설정",
"actionListSiteRoles": "허용된 사이트 역할 목록", "actionListSiteRoles": "허용된 사이트 역할 목록",
"actionCreateResource": "리소스 생성", "actionCreateResource": "리소스 생성",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "리소스 핀코드 설정", "actionSetResourcePincode": "리소스 핀코드 설정",
"actionSetResourceEmailWhitelist": "리소스 이메일 화이트리스트 설정", "actionSetResourceEmailWhitelist": "리소스 이메일 화이트리스트 설정",
"actionGetResourceEmailWhitelist": "리소스 이메일 화이트리스트 가져오기", "actionGetResourceEmailWhitelist": "리소스 이메일 화이트리스트 가져오기",
"actionGetResourcePolicy": "리소스 정책 가져오기",
"actionUpdateResourcePolicy": "리소스 정책 업데이트",
"actionSetResourcePolicyUsers": "리소스 정책 사용자 설정",
"actionSetResourcePolicyRoles": "리소스 정책 역할 설정",
"actionSetResourcePolicyPassword": "리소스 정책 비밀번호 설정",
"actionSetResourcePolicyPincode": "리소스 정책 핀코드 설정",
"actionSetResourcePolicyHeaderAuth": "리소스 정책 헤더 인증 설정",
"actionSetResourcePolicyWhitelist": "리소스 정책 이메일 화이트리스트 설정",
"actionSetResourcePolicyRules": "리소스 정책 규칙 설정",
"actionCreateTarget": "대상 만들기", "actionCreateTarget": "대상 만들기",
"actionDeleteTarget": "대상 삭제", "actionDeleteTarget": "대상 삭제",
"actionGetTarget": "대상 가져오기", "actionGetTarget": "대상 가져오기",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "액세스 토큰 생성", "actionGenerateAccessToken": "액세스 토큰 생성",
"actionDeleteAccessToken": "액세스 토큰 삭제", "actionDeleteAccessToken": "액세스 토큰 삭제",
"actionListAccessTokens": "액세스 토큰 목록", "actionListAccessTokens": "액세스 토큰 목록",
"actionCreateResourceSessionToken": "리소스 세션 토큰 생성",
"actionCreateResourceRule": "리소스 규칙 생성", "actionCreateResourceRule": "리소스 규칙 생성",
"actionDeleteResourceRule": "리소스 규칙 삭제", "actionDeleteResourceRule": "리소스 규칙 삭제",
"actionListResourceRules": "리소스 규칙 목록", "actionListResourceRules": "리소스 규칙 목록",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "초대 목록", "actionListInvitations": "초대 목록",
"actionExportLogs": "로그 내보내기", "actionExportLogs": "로그 내보내기",
"actionViewLogs": "로그 보기", "actionViewLogs": "로그 보기",
"actionCreateSiteProvisioningKey": "사이트 프로비저닝 키 생성",
"actionListSiteProvisioningKeys": "사이트 프로비저닝 키 목록",
"actionUpdateSiteProvisioningKey": "사이트 프로비저닝 키 업데이트",
"actionDeleteSiteProvisioningKey": "사이트 프로비저닝 키 삭제",
"noneSelected": "선택된 항목 없음", "noneSelected": "선택된 항목 없음",
"orgNotFound2": "조직이 없습니다.", "orgNotFound2": "조직이 없습니다.",
"search": "검색…", "search": "검색…",
@@ -1486,10 +1535,35 @@
"otpAuthDescription": "인증 앱에서 코드를 입력하거나 단일 사용 백업 코드 중 하나를 입력하세요.", "otpAuthDescription": "인증 앱에서 코드를 입력하거나 단일 사용 백업 코드 중 하나를 입력하세요.",
"otpAuthSubmit": "코드 제출", "otpAuthSubmit": "코드 제출",
"idpContinue": "또는 계속 진행하십시오.", "idpContinue": "또는 계속 진행하십시오.",
"idpLastUsed": "마지막 사용",
"otpAuthBack": "비밀번호로 돌아가기", "otpAuthBack": "비밀번호로 돌아가기",
"navbar": "탐색 메뉴", "navbar": "탐색 메뉴",
"navbarDescription": "애플리케이션의 주요 탐색 메뉴", "navbarDescription": "애플리케이션의 주요 탐색 메뉴",
"navbarDocsLink": "문서", "navbarDocsLink": "문서",
"commandPaletteTitle": "명령 팔레트",
"commandPaletteDescription": "페이지, 조직, 리소스 및 작업을 검색합니다",
"commandPaletteSearchPlaceholder": "페이지, 리소스, 작업 검색...",
"commandPaletteNoResults": "결과를 찾을 수 없습니다.",
"commandPaletteSearching": "검색 중...",
"commandPaletteNavigation": "탐색",
"commandPaletteOrganizations": "조직",
"commandPaletteSites": "사이트",
"commandPaletteResources": "리소스",
"commandPaletteUsers": "사용자",
"commandPaletteClients": "머신 클라이언트",
"commandPaletteActions": "작업",
"commandPaletteCreateSite": "사이트 생성",
"commandPaletteCreateProxyResource": "공용 리소스 생성",
"commandPaletteCreatePrivateResource": "개인 리소스 생성",
"commandPaletteCreateUser": "사용자 생성",
"commandPaletteCreateApiKey": "API 키 생성",
"commandPaletteCreateMachineClient": "머신 클라이언트 생성",
"commandPaletteCreateAlertRule": "경고 규칙 생성",
"commandPaletteCreateIdentityProvider": "신원 공급자 생성",
"commandPaletteToggleTheme": "테마 전환",
"commandPaletteChooseOrganization": "조직 선택",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "2FA를 활성화할 수 없습니다.", "otpErrorEnable": "2FA를 활성화할 수 없습니다.",
"otpErrorEnableDescription": "2FA를 활성화하는 동안 오류가 발생했습니다", "otpErrorEnableDescription": "2FA를 활성화하는 동안 오류가 발생했습니다",
"otpSetupCheckCode": "6자리 코드를 입력하세요", "otpSetupCheckCode": "6자리 코드를 입력하세요",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "관리", "sidebarManagement": "관리",
"sidebarBillingAndLicenses": "결제 및 라이선스", "sidebarBillingAndLicenses": "결제 및 라이선스",
"sidebarLogsAnalytics": "분석", "sidebarLogsAnalytics": "분석",
"commandSites": "사이트",
"commandActionModeInfo": "동작 모드 열기 위해 \">\" 입력",
"commandResources": "리소스",
"commandProxyResources": "공용 리소스",
"commandClientResources": "개인 리소스",
"commandClients": "클라이언트",
"commandUserDevices": "사용자 기기",
"commandMachineClients": "머신 클라이언트",
"commandDomains": "도메인",
"commandRemoteExitNodes": "원격 노드",
"commandTeam": "팀",
"commandUsers": "사용자",
"commandRoles": "역할",
"commandInvitations": "초대",
"commandPolicies": "공유 정책",
"commandResourcePolicies": "공용 리소스 정책",
"commandIdentityProviders": "신원 공급자",
"commandApprovals": "승인 요청",
"commandShareableLinks": "공유 가능한 링크",
"commandOrganization": "조직",
"commandLogsAndAnalytics": "로그 및 분석",
"commandLogsAnalytics": "분석",
"commandLogsRequest": "HTTP 요청 로그",
"commandLogsAccess": "인증 로그",
"commandLogsAction": "관리자 작업 로그",
"commandLogsConnection": "네트워크 로그",
"commandLogsStreaming": "이벤트 스트리밍",
"commandManagement": "관리",
"commandAlerting": "경보",
"commandProvisioning": "프로비저닝",
"commandBluePrints": "블루밍",
"commandApiKeys": "API 키",
"commandBillingAndLicenses": "청구 및 라이선스",
"commandBilling": "청구",
"commandEnterpriseLicenses": "라이선스",
"commandSettings": "설정",
"commandLauncher": "런처",
"commandResourceLauncher": "리소스 런처",
"commandSearchResults": "검색 결과",
"alertingTitle": "알림", "alertingTitle": "알림",
"alertingDescription": "알림에 대한 소스, 트리거 및 작업 정의", "alertingDescription": "알림에 대한 소스, 트리거 및 작업 정의",
"alertingRules": "알림 규칙", "alertingRules": "알림 규칙",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "서브도메인: {subdomain}", "domainPickerSubdomain": "서브도메인: {subdomain}",
"domainPickerNamespace": "이름 공간: {namespace}", "domainPickerNamespace": "이름 공간: {namespace}",
"domainPickerShowMore": "더보기", "domainPickerShowMore": "더보기",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "지역 선택", "regionSelectorTitle": "지역 선택",
"domainPickerRemoteExitNodeWarning": "제공된 도메인은 원격 종료 노드에 연결된 사이트에서 지원되지 않습니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.", "domainPickerRemoteExitNodeWarning": "제공된 도메인은 원격 종료 노드에 연결된 사이트에서 지원되지 않습니다. 원격 노드에서 리소스를 사용하려면 사용자 지정 도메인을 사용하십시오.",
"regionSelectorInfo": "지역을 선택하면 위치에 따라 더 나은 성능이 제공됩니다. 서버와 같은 지역에 있을 필요는 없습니다.", "regionSelectorInfo": "지역을 선택하면 위치에 따라 더 나은 성능이 제공됩니다. 서버와 같은 지역에 있을 필요는 없습니다.",
@@ -1898,6 +2014,9 @@
"billingDomains": "도메인", "billingDomains": "도메인",
"billingOrganizations": "조직", "billingOrganizations": "조직",
"billingRemoteExitNodes": "원격 노드", "billingRemoteExitNodes": "원격 노드",
"billingPublicResources": "공용 리소스",
"billingPrivateResources": "개인 리소스",
"billingMachineClients": "머신 클라이언트",
"billingNoLimitConfigured": "구성된 한도가 없습니다.", "billingNoLimitConfigured": "구성된 한도가 없습니다.",
"billingEstimatedPeriod": "예상 청구 기간", "billingEstimatedPeriod": "예상 청구 기간",
"billingIncludedUsage": "포함 사용량", "billingIncludedUsage": "포함 사용량",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "사용할 수 있는 사용자 수", "billingUsersInfo": "사용할 수 있는 사용자 수",
"billingDomainInfo": "사용할 수 있는 도메인 수", "billingDomainInfo": "사용할 수 있는 도메인 수",
"billingRemoteExitNodesInfo": "사용할 수 있는 원격 노드 수", "billingRemoteExitNodesInfo": "사용할 수 있는 원격 노드 수",
"billingPublicResourcesInfo": "사용할 수 있는 공용 리소스 수",
"billingPrivateResourcesInfo": "사용할 수 있는 개인 리소스 수",
"billingMachineClientsInfo": "사용할 수 있는 머신 클라이언트 수",
"billingLicenseKeys": "라이센스 키", "billingLicenseKeys": "라이센스 키",
"billingLicenseKeysDescription": "라이센스 키 구독을 관리하세요", "billingLicenseKeysDescription": "라이센스 키 구독을 관리하세요",
"billingLicenseSubscription": "라이센스 구독", "billingLicenseSubscription": "라이센스 구독",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "서브넷", "subnetPlaceholder": "서브넷",
"addressDescription": "클라이언트의 내부 주소. 조직의 서브넷 내에 있어야 합니다.", "addressDescription": "클라이언트의 내부 주소. 조직의 서브넷 내에 있어야 합니다.",
"selectSites": "사이트 선택", "selectSites": "사이트 선택",
"selectLabels": "레이블 선택",
"sitesDescription": "클라이언트는 선택한 사이트에 연결됩니다.", "sitesDescription": "클라이언트는 선택한 사이트에 연결됩니다.",
"clientInstallOlm": "Olm 설치", "clientInstallOlm": "Olm 설치",
"clientInstallOlmDescription": "시스템에서 Olm을 실행하기", "clientInstallOlmDescription": "시스템에서 Olm을 실행하기",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "공유", "resourcesTableProxyResources": "공유",
"resourcesTableClientResources": "비공개", "resourcesTableClientResources": "비공개",
"resourcesTableNoProxyResourcesFound": "프록시 리소스를 찾을 수 없습니다.", "resourcesTableNoProxyResourcesFound": "프록시 리소스를 찾을 수 없습니다.",
"resourcesTableNoInternalResourcesFound": "내부 리소스를 찾을 수 없습니다.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "대상지", "resourcesTableDestination": "대상지",
"resourcesTableAlias": "별칭", "resourcesTableAlias": "별칭",
"resourcesTableAliasAddress": "별칭 주소", "resourcesTableAliasAddress": "별칭 주소",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "취소", "editInternalResourceDialogCancel": "취소",
"editInternalResourceDialogSaveResource": "리소스 저장", "editInternalResourceDialogSaveResource": "리소스 저장",
"editInternalResourceDialogSuccess": "성공", "editInternalResourceDialogSuccess": "성공",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "내부 리소스가 성공적으로 업데이트되었습니다", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "오류", "editInternalResourceDialogError": "오류",
"editInternalResourceDialogFailedToUpdateInternalResource": "내부 리소스 업데이트 실패", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "이름은 필수입니다.", "editInternalResourceDialogNameRequired": "이름은 필수입니다.",
"editInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.", "editInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
"editInternalResourceDialogProxyPortMin": "프록시 포트는 최소 1이어야 합니다.", "editInternalResourceDialogProxyPortMin": "프록시 포트는 최소 1이어야 합니다.",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "별칭", "editInternalResourceDialogAlias": "별칭",
"editInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.", "editInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.",
"createInternalResourceDialogNoSitesAvailable": "사용 가능한 사이트가 없습니다.", "createInternalResourceDialogNoSitesAvailable": "사용 가능한 사이트가 없습니다.",
"createInternalResourceDialogNoSitesAvailableDescription": "내부 리소스를 생성하려면 서브넷이 구성된 최소 하나의 Newt 사이트가 필요합니다.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "닫기", "createInternalResourceDialogClose": "닫기",
"createInternalResourceDialogCreateClientResource": "사이트 리소스 생성", "createInternalResourceDialogCreateClientResource": "사이트 리소스 생성",
"createInternalResourceDialogCreateClientResourceDescription": "선택한 사이트에 연결된 클라이언트에 접근할 새 리소스를 생성합니다", "createInternalResourceDialogCreateClientResourceDescription": "선택한 사이트에 연결된 클라이언트에 접근할 새 리소스를 생성합니다",
"privateResourceGeneralDescription": "이름, 식별자, 기타 일반 리소스 설정을 구성합니다.",
"privateResourceCreatePageSeeAll": "모든 개인 리소스 보기",
"privateResourceAllowIcmpPing": "ICMP 핑 허용",
"privateResourceNetworkAccess": "네트워크 접근",
"privateResourceNetworkAccessDescription": "이 리소스에 대한 TCP/UDP 포트 접근과 ICMP 핑이 허용되는지 여부를 제어합니다.",
"hostSettings": "호스트 설정",
"cidrSettings": "CIDR 설정",
"createInternalResourceDialogResourceProperties": "리소스 속성", "createInternalResourceDialogResourceProperties": "리소스 속성",
"createInternalResourceDialogName": "이름", "createInternalResourceDialogName": "이름",
"createInternalResourceDialogSite": "사이트", "createInternalResourceDialogSite": "사이트",
"selectSite": "사이트 선택...", "selectSite": "사이트 선택...",
"multiSitesSelectorSitesCount": "{count, plural, other {# 사이트}}", "multiSitesSelectorSitesCount": "{count, plural, other {# 사이트}}",
"labelsSelectorLabelsCount": "{count, plural, one {# 레이블} other {# 레이블}}",
"noSitesFound": "사이트를 찾을 수 없습니다.", "noSitesFound": "사이트를 찾을 수 없습니다.",
"createInternalResourceDialogProtocol": "프로토콜", "createInternalResourceDialogProtocol": "프로토콜",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "취소", "createInternalResourceDialogCancel": "취소",
"createInternalResourceDialogCreateResource": "리소스 생성", "createInternalResourceDialogCreateResource": "리소스 생성",
"createInternalResourceDialogSuccess": "성공", "createInternalResourceDialogSuccess": "성공",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "내부 리소스가 성공적으로 생성되었습니다.", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "오류", "createInternalResourceDialogError": "오류",
"createInternalResourceDialogFailedToCreateInternalResource": "내부 리소스 생성 실패", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "이름은 필수입니다.", "createInternalResourceDialogNameRequired": "이름은 필수입니다.",
"createInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.", "createInternalResourceDialogNameMaxLength": "이름은 255자 이하이어야 합니다.",
"createInternalResourceDialogPleaseSelectSite": "사이트를 선택하세요", "createInternalResourceDialogPleaseSelectSite": "사이트를 선택하세요",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "사이트 네트워크의 자원 IP 주소입니다.", "createInternalResourceDialogDestinationCidrDescription": "사이트 네트워크의 자원 IP 주소입니다.",
"createInternalResourceDialogAlias": "별칭", "createInternalResourceDialogAlias": "별칭",
"createInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.", "createInternalResourceDialogAliasDescription": "이 리소스에 대한 선택적 내부 DNS 별칭입니다.",
"internalResourceAliasLocalWarning": ".local로 끝나는 별칭은 일부 네트워크에서 mDNS로 인해 해결 문제가 발생할 수 있습니다.",
"internalResourceDownstreamSchemeRequired": "HTTP 리소스에 스킴이 필요합니다", "internalResourceDownstreamSchemeRequired": "HTTP 리소스에 스킴이 필요합니다",
"internalResourceHttpPortRequired": "HTTP 리소스에 목적지 포트가 필요합니다", "internalResourceHttpPortRequired": "HTTP 리소스에 목적지 포트가 필요합니다",
"siteConfiguration": "설정", "siteConfiguration": "설정",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "원격 노드", "sidebarRemoteExitNodes": "원격 노드",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "비밀", "remoteExitNodeSecretKey": "비밀",
"remoteExitNodeNetworkingTitle": "네트워크 설정",
"remoteExitNodeNetworkingDescription": "이 원격 출구 노드의 트래픽 라우팅 방법과 어떤 사이트가 이를 통해 연결하는지 구성합니다. 백홀 네트워킹 구성을 사용한 고급 기능입니다.",
"remoteExitNodeNetworkingSave": "설정 저장",
"remoteExitNodeNetworkingSaveSuccessTitle": "네트워크 설정이 저장되었습니다",
"remoteExitNodeNetworkingSaveSuccessDescription": "네트워크 설정이 성공적으로 업데이트되었습니다.",
"remoteExitNodeNetworkingSaveError": "네트워크 설정 저장 실패",
"remoteExitNodeNetworkingSubnetsTitle": "원격 서브넷",
"remoteExitNodeNetworkingSubnetsDescription": "이 원격 출구 노드가 트래픽을 라우팅할 CIDR 범위를 정의합니다. 유효한 CIDR을 입력하고 Enter를 눌러 추가하세요 (예: <code>10.0.0.0/8</code>).",
"remoteExitNodeNetworkingSubnetsPlaceholder": "CIDR 범위 추가 (예: 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "서브넷 로드 실패",
"remoteExitNodeNetworkingLabelsTitle": "우선순위 레이블",
"remoteExitNodeNetworkingLabelsDescription": "이 레이블이 있는 사이트는 이 원격 출구 노드를 통해 연결됩니다.",
"remoteExitNodeNetworkingLabelsButtonText": "레이블 선택...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "레이블 검색...",
"remoteExitNodeNetworkingLabelsLoadError": "레이블 로드 실패",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "원격 노드 생성", "title": "원격 노드 생성",
"description": "새로운 자체 호스팅 원격 중계 및 프록시 서버 노드를 생성하십시오.", "description": "새로운 자체 호스팅 원격 중계 및 프록시 서버 노드를 생성하십시오.",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "이 조직에 사용 가능한 노드가 없습니다. 로컬 사이트를 사용하려면 먼저 노드를 생성하세요.", "noRemoteExitNodesAvailableDescription": "이 조직에 사용 가능한 노드가 없습니다. 로컬 사이트를 사용하려면 먼저 노드를 생성하세요.",
"exitNode": "종단 노드", "exitNode": "종단 노드",
"country": "국가", "country": "국가",
"countryIsNot": "국가가 아닙니다",
"rulesMatchCountry": "현재 소스 IP를 기반으로 합니다", "rulesMatchCountry": "현재 소스 IP를 기반으로 합니다",
"region": "지역", "region": "지역",
"selectRegion": "지역 선택", "selectRegion": "지역 선택",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC 공급자", "idpGoogleDescription": "Google OAuth2/OIDC 공급자",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC 공급자", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC 공급자",
"subnet": "서브넷", "subnet": "서브넷",
"utilitySubnet": "유틸리티 서브넷",
"subnetDescription": "이 조직의 네트워크 구성에 대한 서브넷입니다.", "subnetDescription": "이 조직의 네트워크 구성에 대한 서브넷입니다.",
"customDomain": "사용자 정의 도메인", "customDomain": "사용자 정의 도메인",
"authPage": "인증 페이지", "authPage": "인증 페이지",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "이중 인증 설정이 필요합니다. 이 단계를 완료하려면 {dashboardUrl}/auth/login 통해 다시 로그인하십시오. 그런 다음 여기로 돌아오세요.", "twoFactorSetupRequired": "이중 인증 설정이 필요합니다. 이 단계를 완료하려면 {dashboardUrl}/auth/login 통해 다시 로그인하십시오. 그런 다음 여기로 돌아오세요.",
"additionalSecurityRequired": "추가 보안 필요", "additionalSecurityRequired": "추가 보안 필요",
"organizationRequiresAdditionalSteps": "이 조직은 자원에 접근하기 전에 추가 보안 단계를 요구합니다.", "organizationRequiresAdditionalSteps": "이 조직은 자원에 접근하기 전에 추가 보안 단계를 요구합니다.",
"sessionExpired": "세션 만료",
"sessionExpiredReauthRequired": "조직의 보안 정책에 따라 세션이 만료되었습니다. 계속하려면 재인증하십시오.",
"reauthenticate": "재 인증",
"completeTheseSteps": "이 단계를 완료하십시오", "completeTheseSteps": "이 단계를 완료하십시오",
"enableTwoFactorAuthentication": "이중 인증 활성화", "enableTwoFactorAuthentication": "이중 인증 활성화",
"completeSecuritySteps": "보안 단계 완료", "completeSecuritySteps": "보안 단계 완료",
@@ -2946,8 +3098,8 @@
"sourceAddress": "소스 주소", "sourceAddress": "소스 주소",
"destinationAddress": "대상 주소", "destinationAddress": "대상 주소",
"duration": "지속 시간", "duration": "지속 시간",
"licenseRequiredToUse": "이 기능을 사용하려면 <enterpriseLicenseLink>엔터프라이즈 에디션</enterpriseLicenseLink> 라이선스가 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "이 기능을 사용하려면 <enterpriseEditionLink>엔터프라이즈 에디션</enterpriseEditionLink>이(가) 필요합니다. 이 기능은 <pangolinCloudLink>판골린 클라우드</pangolinCloudLink>에서도 사용할 수 있습니다. <bookADemoLink>데모 또는 POC 체험을 예약하세요</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "인증서 해결사", "certResolver": "인증서 해결사",
"certResolverDescription": "이 리소스에 사용할 인증서 해결사를 선택하세요.", "certResolverDescription": "이 리소스에 사용할 인증서 해결사를 선택하세요.",
"selectCertResolver": "인증서 해결사 선택", "selectCertResolver": "인증서 해결사 선택",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "조직 ID 또는 도메인 ID가 누락되었습니다", "orgOrDomainIdMissing": "조직 ID 또는 도메인 ID가 누락되었습니다",
"loadingDNSRecords": "DNS 레코드를 로드하는 중...", "loadingDNSRecords": "DNS 레코드를 로드하는 중...",
"olmUpdateAvailableInfo": "올름의 새 버전이 이용 가능합니다. 최상의 경험을 위해 최신 버전으로 업데이트하세요.", "olmUpdateAvailableInfo": "올름의 새 버전이 이용 가능합니다. 최상의 경험을 위해 최신 버전으로 업데이트하세요.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "업데이트된 버전이 있습니다. 최상의 경험을 위해 최신 버전으로 업데이트하세요.",
"client": "클라이언트", "client": "클라이언트",
"proxyProtocol": "프록시 프로토콜 설정", "proxyProtocol": "프록시 프로토콜 설정",
"proxyProtocolDescription": "TCP 서비스에 대한 클라이언트 IP 주소를 유지하도록 프록시 프로토콜을 구성하세요.", "proxyProtocolDescription": "TCP 서비스에 대한 클라이언트 IP 주소를 유지하도록 프록시 프로토콜을 구성하세요.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "사용자 추가", "editInternalResourceDialogAddUsers": "사용자 추가",
"editInternalResourceDialogAddClients": "클라이언트 추가", "editInternalResourceDialogAddClients": "클라이언트 추가",
"editInternalResourceDialogDestinationLabel": "대상지", "editInternalResourceDialogDestinationLabel": "대상지",
"editInternalResourceDialogDestinationDescription": "내부 리소스의 목적지 주소를 지정하세요. 선택한 모드에 따라 이 주소는 호스트명, IP 주소, 또는 CIDR 범위가 될 수 있습니다. 더욱 쉽게 식별할 수 있도록 내부 DNS 별칭을 설정할 수 있습니다.", "editInternalResourceDialogDestinationDescription": "클라이언트가 이 리소스에 어떻게 도달하는지 구성합니다.",
"internalResourceFormMultiSiteRoutingHelp": "다중 사이트를 선택하면 높은 가용성을 위해 회복력 있는 라우팅 및 페일오버가 가능해집니다.", "internalResourceFormMultiSiteRoutingHelp": "다중 사이트를 선택하면 높은 가용성을 위해 회복력 있는 라우팅 및 페일오버가 가능해집니다.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "자세히 알아보기", "internalResourceFormMultiSiteRoutingHelpLearnMore": "자세히 알아보기",
"editInternalResourceDialogPortRestrictionsDescription": "특정 TCP/UDP 포트에 대한 접근을 제한하거나 모든 포트를 허용/차단하십시오.", "editInternalResourceDialogPortRestrictionsDescription": "특정 TCP/UDP 포트에 대한 접근을 제한하거나 모든 포트를 허용/차단하십시오.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "이메일 화이트리스트", "memberPortalEmailWhitelist": "이메일 화이트리스트",
"memberPortalResourceDisabled": "리소스 비활성화됨", "memberPortalResourceDisabled": "리소스 비활성화됨",
"memberPortalShowingResources": "{start}-{end} 중 {total}개의 리소스를 표시 중", "memberPortalShowingResources": "{start}-{end} 중 {total}개의 리소스를 표시 중",
"resourceLauncherTitle": "리소스 런처",
"resourceSidebarLauncherTitle": "런처",
"resourceLauncherDescription": "모든 사용 가능한 리소스를 보고 중앙 허브에서 실행",
"resourceLauncherSearchPlaceholder": "리소스를 검색하세요...",
"resourceLauncherDefaultView": "기본값",
"resourceLauncherSaveView": "보기를 저장",
"resourceLauncherSaveToCurrentView": "현재 보기로 저장",
"resourceLauncherSaveDefaultPersonal": "내게 저장",
"resourceLauncherResetView": "보기를 재설정",
"resourceLauncherResetSystemDefault": "시스템 기본값으로 재설정",
"resourceLauncherSystemDefaultRestored": "시스템 기본값이 복원되었습니다",
"resourceLauncherSystemDefaultRestoredDescription": "기본 보기가 원래 설정으로 재설정되었습니다.",
"resourceLauncherSaveAsNewView": "새 보기로 저장",
"resourceLauncherSaveAsNewViewDescription": "현재 필터와 레이아웃을 저장할 이름을 입력하세요.",
"resourceLauncherSaveForEveryone": "모두에게 저장",
"resourceLauncherSaveForEveryoneDescription": "이 보기를 모든 조직 구성원과 공유합니다. 체크 해제하면 해당 뷰는 사용자에게만 표시됩니다.",
"resourceLauncherMakePersonal": "개인적으로 만들기",
"resourceLauncherFilter": "필터",
"resourceLauncherFilterWithCount": "필터, {count} 적용됨",
"resourceLauncherSort": "정렬",
"resourceLauncherSortAscending": "오름차순 정렬",
"resourceLauncherSortDescending": "내림차순 정렬",
"resourceLauncherSettings": "설정",
"resourceLauncherGroupBy": "그룹화 기준",
"resourceLauncherGroupBySite": "사이트",
"resourceLauncherGroupByLabel": "레이블",
"resourceLauncherGroupByNone": "없음",
"resourceLauncherLayout": "레이아웃",
"resourceLauncherLayoutGrid": "그리드",
"resourceLauncherLayoutList": "목록",
"resourceLauncherShowLabels": "레이블 표시",
"resourceLauncherShowSiteTags": "사이트 태그 표시",
"resourceLauncherShowRecents": "최근 항목 표시",
"resourceLauncherDeleteView": "보기 삭제",
"resourceLauncherDeleteViewTitle": "뷰 삭제",
"resourceLauncherDeleteViewQuestion": "이 런처 뷰를 삭제하시겠습니까?",
"resourceLauncherDeleteViewConfirm": "뷰 삭제",
"resourceLauncherViewAsAdmin": "관리자로 보기",
"resourceLauncherResourceDetailsDescription": "이 리소스에 대한 연결 정보 및 상태입니다.",
"resourceLauncherResourceDetails": "리소스 세부 정보",
"resourceLauncherAuthMethodsDescription": "이 리소스에 활성화된 인증 방법입니다.",
"resourceLauncherPrivateClientRequired": "이 리소스에 개인적으로 접근하려면 기기에서 클라이언트로 연결하십시오.",
"resourceLauncherPrivateClientRequiredTitle": "클라이언트 연결 필요",
"resourceLauncherDownloadClient": "클라이언트 다운로드",
"resourceLauncherFailedToLoadDetails": "리소스 세부 정보를 로드할 수 없습니다. 더 이상 이 리소스에 접근할 수 없을 수 있습니다.",
"resourceLauncherNoPortRestrictions": "포트 제한 없음",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "레이블 없음",
"resourceLauncherNoSite": "사이트 없음",
"resourceLauncherNoResourcesInGroup": "이 그룹에는 리소스가 없습니다",
"resourceLauncherEmptyStateTitle": "사용 가능한 리소스 없음",
"resourceLauncherEmptyStateDescription": "아직 리소스에 대한 액세스 권한이 없습니다. 액세스를 요청하려면 관리자에게 문의하세요.",
"resourceLauncherEmptyStateNoResultsTitle": "리소스를 찾을 수 없음",
"resourceLauncherEmptyStateNoResultsDescription": "현재 검색이나 필터에 맞는 리소스가 없습니다. 필터를 조정하여 찾으려는 항목을 확인해보세요.",
"resourceLauncherEmptyStateNoResultsWithQuery": "\"{query}\"와 일치하는 리소스가 없습니다. 검색을 조정하거나 필터를 지워서 모든 리소스를 확인해보세요.",
"resourceLauncherSearchFirstTitle": "검색 또는 필터로 탐색하기",
"resourceLauncherSearchFirstDescription": "많은 리소스에 접근할 수 있습니다. 필요한 것을 찾기 위해 사이트 또는 라벨로 검색하십시오.",
"resourceLauncherSiteGroupingDisabled": "이 규모에서는 사이트 그룹화가 불가능합니다. 더 작은 그룹을 위해 사이트로 필터링하십시오.",
"resourceLauncherLabelGroupingDisabled": "이 규모에서는 라벨 그룹화가 불가능합니다.",
"resourceLauncherCompactModeHint": "더 빠른 탐색을 위해 단순화된 목록을 표시하고 있습니다. 검색하거나 필터를 사용하여 결과를 좁히십시오.",
"resourceLauncherCompactGroupingHint": "그룹핑을 활성화하려면 사이트 또는 라벨 필터를 적용하십시오.",
"resourceLauncherCopiedToClipboard": "클립보드에 복사됨",
"resourceLauncherCopiedAccessDescription": "리소스 액세스가 클립보드에 복사되었습니다.",
"resourceLauncherViewNamePlaceholder": "보기 이름",
"resourceLauncherViewNameLabel": "뷰 이름",
"resourceLauncherViewSaved": "보기 저장됨",
"resourceLauncherViewSavedDescription": "런처 뷰가 저장되었습니다.",
"resourceLauncherViewSaveFailed": "뷰 저장 실패",
"resourceLauncherViewSaveFailedDescription": "런처 뷰를 저장할 수 없습니다. 다시 시도하세요.",
"resourceLauncherViewDeleted": "보기 삭제됨",
"resourceLauncherViewDeletedDescription": "런처 뷰가 삭제되었습니다.",
"resourceLauncherViewDeleteFailed": "뷰 삭제 실패",
"resourceLauncherViewDeleteFailedDescription": "런처 뷰를 삭제할 수 없습니다. 다시 시도하세요.",
"memberPortalPrevious": "이전", "memberPortalPrevious": "이전",
"memberPortalNext": "다음", "memberPortalNext": "다음",
"httpSettings": "HTTP 설정", "httpSettings": "HTTP 설정",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "프라이빗 키가 필요합니다", "sshPrivateKeyRequired": "프라이빗 키가 필요합니다",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "연결하려면 VNC 비밀번호를 입력하세요", "vncSignInDescription": "연결하기 위해 VNC 자격 증명을 입력하세요",
"vncUsernameOptional": "사용자 이름 (선택 사항)",
"vncPasswordOptional": "비밀번호 (선택 사항)", "vncPasswordOptional": "비밀번호 (선택 사항)",
"vncNoResourceTarget": "사용할 수 있는 리소스 대상이 없습니다", "vncNoResourceTarget": "사용할 수 있는 리소스 대상이 없습니다",
"vncFailedToLoadNovnc": "noVNC 로드를 실패했습니다", "vncFailedToLoadNovnc": "noVNC 로드를 실패했습니다",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "업로드 실패", "rdpUploadFailed": "업로드 실패",
"rdpUnicodeKeyboardMode": "유니코드 키보드 모드", "rdpUnicodeKeyboardMode": "유니코드 키보드 모드",
"sessionToolbarShow": "툴바 보기", "sessionToolbarShow": "툴바 보기",
"sessionToolbarHide": "툴바 숨기기" "sessionToolbarHide": "툴바 숨기기",
"actionUpdateSiteApprovals": "사이트 승인 업데이트"
} }
+250 -22
View File
@@ -66,9 +66,15 @@
"local": "Lokal", "local": "Lokal",
"edit": "Rediger", "edit": "Rediger",
"siteConfirmDelete": "Bekreft Sletting av Område", "siteConfirmDelete": "Bekreft Sletting av Område",
"siteConfirmDeleteAndResources": "Bekreft sletting av nettsted og ressurser",
"siteDelete": "Slett Område", "siteDelete": "Slett Område",
"siteDeleteAndResources": "Slett nettsted og ressurser",
"siteMessageRemove": "Når nettstedet er fjernet, vil det ikke lenger være tilgjengelig. Alle målene for nettstedet vil også bli fjernet.", "siteMessageRemove": "Når nettstedet er fjernet, vil det ikke lenger være tilgjengelig. Alle målene for nettstedet vil også bli fjernet.",
"siteMessageRemoveAndResources": "Dette vil permanent slette alle offentlige og private ressurser tilknyttet dette nettstedet, selv om en ressurs også er tilknyttet andre nettsteder.",
"siteQuestionRemove": "Er du sikker på at du vil fjerne nettstedet fra organisasjonen?", "siteQuestionRemove": "Er du sikker på at du vil fjerne nettstedet fra organisasjonen?",
"siteQuestionRemoveAndResources": "Er du sikker på at du vil slette dette nettstedet og alle tilknyttede ressurser?",
"sitesTableDeleteSite": "Slett nettsted",
"sitesTableDeleteSiteAndResources": "Slett nettsted og ressurser",
"siteManageSites": "Administrer Områder", "siteManageSites": "Administrer Områder",
"siteDescription": "Opprette og administrere nettsteder for å aktivere tilkobling til private nettverk", "siteDescription": "Opprette og administrere nettsteder for å aktivere tilkobling til private nettverk",
"sitesBannerTitle": "Koble til alle nettverk", "sitesBannerTitle": "Koble til alle nettverk",
@@ -117,6 +123,16 @@
"siteUpdated": "Område oppdatert", "siteUpdated": "Område oppdatert",
"siteUpdatedDescription": "Området har blitt oppdatert.", "siteUpdatedDescription": "Området har blitt oppdatert.",
"siteGeneralDescription": "Konfigurer de generelle innstillingene for dette området", "siteGeneralDescription": "Konfigurer de generelle innstillingene for dette området",
"siteRestartTitle": "Start område på nytt",
"siteRestartDescription": "Start WireGuard-tunnelen for dette området på nytt. Dette vil midlertidig avbryte tilkoblingen.",
"siteRestartBody": "Bruk dette hvis områdetunnelen ikke fungerer riktig og du vil tvinge en ny tilkobling uten å starte verten på nytt.",
"siteRestartButton": "Start område på nytt",
"siteRestartDialogMessage": "Er du sikker på at du vil starte WireGuard-tunnelen for <b>{name}</b> på nytt? Området vil midlertidig miste tilkoblingen.",
"siteRestartWarning": "Området vil kobles kort fra mens tunnelen starter om.",
"siteRestarted": "Område startet på nytt",
"siteRestartedDescription": "WireGuard-tunnelen er startet på nytt.",
"siteErrorRestart": "Kan ikke starte område på nytt",
"siteErrorRestartDescription": "En feil oppstod ved omstart av området.",
"siteSettingDescription": "Konfigurere innstillingene på nettstedet", "siteSettingDescription": "Konfigurere innstillingene på nettstedet",
"siteResourcesTab": "Ressurser", "siteResourcesTab": "Ressurser",
"siteResourcesNoneOnSite": "Dette nettstedet har ingen offentlige eller private ressurser enda.", "siteResourcesNoneOnSite": "Dette nettstedet har ingen offentlige eller private ressurser enda.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Bekreft sletting av delbar lenke", "shareDeleteConfirm": "Bekreft sletting av delbar lenke",
"shareQuestionRemove": "Er du sikker på at du vil slette denne delingslenken?", "shareQuestionRemove": "Er du sikker på at du vil slette denne delingslenken?",
"shareMessageRemove": "Når slettet, vil lenken ikke lenger fungere, og alle som bruker den vil miste tilgang til ressursen.", "shareMessageRemove": "Når slettet, vil lenken ikke lenger fungere, og alle som bruker den vil miste tilgang til ressursen.",
"shareTokenDescription": "Adgangstoken kan sendes på to måter: som en spørringsparameter eller i forespørselsoverskriftene. Disse må sendes fra klienten på hver forespørsel om autentisert tilgang.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Tilgangsnøkkel", "accessToken": "Tilgangsnøkkel",
"usageExamples": "Brukseksempler", "usageExamples": "Brukseksempler",
"tokenId": "Token-ID", "tokenId": "Token-ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Tittel (valgfritt)", "shareTitleOptional": "Tittel (valgfritt)",
"sharePathOptional": "Bane (valgfritt)", "sharePathOptional": "Bane (valgfritt)",
"sharePathDescription": "Lenken vil videresende brukere til denne stien etter autentisering.", "sharePathDescription": "Lenken vil videresende brukere til denne stien etter autentisering.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Utløper om", "expireIn": "Utløper om",
"neverExpire": "Utløper aldri", "neverExpire": "Utløper aldri",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Utløpstid er hvor lenge lenken vil være brukbar og gi tilgang til ressursen. Etter denne tiden vil lenken ikke lenger fungere, og brukere som brukte denne lenken vil miste tilgangen til ressursen.", "shareExpireDescription": "Utløpstid er hvor lenge lenken vil være brukbar og gi tilgang til ressursen. Etter denne tiden vil lenken ikke lenger fungere, og brukere som brukte denne lenken vil miste tilgangen til ressursen.",
"shareSeeOnce": "Du vil bare kunne se denne linken én gang. Pass på å kopiere den.", "shareSeeOnce": "Du vil bare kunne se denne linken én gang. Pass på å kopiere den.",
"shareAccessHint": "Alle med denne lenken kan få tilgang til ressursen. Del forsiktig.", "shareAccessHint": "Alle med denne lenken kan få tilgang til ressursen. Del forsiktig.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy forespørsler om rå TCP/UDP ved hjelp av et portnummer. Krever sider for å koble til en ekstern node.", "resourceRawDescriptionCloud": "Proxy forespørsler om rå TCP/UDP ved hjelp av et portnummer. Krever sider for å koble til en ekstern node.",
"resourceCreate": "Opprett ressurs", "resourceCreate": "Opprett ressurs",
"resourceCreateDescription": "Følg trinnene nedenfor for å opprette en ny ressurs", "resourceCreateDescription": "Følg trinnene nedenfor for å opprette en ny ressurs",
"resourcePublicCreate": "Opprett offentlig ressurs",
"resourcePublicCreateDescription": "Følg trinnene nedenfor for å opprette en ny offentlig ressurs som er tilgjengelig via en nettleser",
"resourceCreateGeneralDescription": "Konfigurer de grunnleggende ressursinnstillingene inkludert navnet og typen", "resourceCreateGeneralDescription": "Konfigurer de grunnleggende ressursinnstillingene inkludert navnet og typen",
"resourceSeeAll": "Se alle ressurser", "resourceSeeAll": "Se alle ressurser",
"resourceCreateGeneral": "Generelt", "resourceCreateGeneral": "Generelt",
@@ -431,8 +455,14 @@
"provisioningManage": "Levering", "provisioningManage": "Levering",
"provisioningDescription": "Administrer foreløpig nøkler og gjennomgå ventende nettsteder som venter på godkjenning.", "provisioningDescription": "Administrer foreløpig nøkler og gjennomgå ventende nettsteder som venter på godkjenning.",
"pendingSites": "Ventende nettsteder", "pendingSites": "Ventende nettsteder",
"siteApproveSuccess": "Vellykket godkjenning av nettsted", "siteApproveSuccess": "Område og tilknyttede ressurser godkjent",
"siteApproveError": "Feil ved godkjenning av side", "siteApproveError": "Feil ved godkjenning av side",
"siteReject": "Avvis Område",
"siteQuestionReject": "Er du sikker på at du vil avvise dette området?",
"siteMessageReject": "Dette vil permanent slette området og eventuelle tilknyttede ressurser som fortsatt venter.",
"siteConfirmReject": "Bekreft Avvisning av Område",
"siteRejectSuccess": "Område avvist",
"siteRejectError": "Feil ved avvisning av området",
"provisioningKeys": "Foreløpig nøkler", "provisioningKeys": "Foreløpig nøkler",
"searchProvisioningKeys": "Søk varer i lagrings nøkler...", "searchProvisioningKeys": "Søk varer i lagrings nøkler...",
"provisioningKeysAdd": "Generer fremvisende nøkkel", "provisioningKeysAdd": "Generer fremvisende nøkkel",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Lagre den midlertidig nøkkelen", "provisioningKeysSave": "Lagre den midlertidig nøkkelen",
"provisioningKeysSaveDescription": "Du kan bare se denne én gang. Kopier det til et sikkert sted.", "provisioningKeysSaveDescription": "Du kan bare se denne én gang. Kopier det til et sikkert sted.",
"provisioningKeysErrorCreate": "Feil under oppretting av foreløpig nøkkel", "provisioningKeysErrorCreate": "Feil under oppretting av foreløpig nøkkel",
"provisioningKeysList": "Ny provisorisk nøkkel", "provisioningKeysList": "Ny Forsyningsnøkkel",
"provisioningKeysMaxBatchSize": "Maks størrelse på bunt", "provisioningKeysMaxBatchSize": "Maks Batch Størrelse",
"provisioningKeysUnlimitedBatchSize": "Ubegrenset mengde bunt (ingen begrensning)", "provisioningKeysUnlimitedBatchSize": "Ubegrenset mengde bunt (ingen begrensning)",
"provisioningKeysMaxBatchUnlimited": "Ubegrenset", "provisioningKeysMaxBatchUnlimited": "Ubegrenset",
"provisioningKeysMaxBatchSizeInvalid": "Angi en gyldig sjakkstørrelse (11 000.000).", "provisioningKeysMaxBatchSizeInvalid": "Angi en gyldig sjakkstørrelse (11 000.000).",
"provisioningKeysValidUntil": "Gyldig til", "provisioningKeysValidUntil": "Gyldig Til",
"provisioningKeysValidUntilHint": "La stå tomt for ingen utløp.", "provisioningKeysValidUntilHint": "La stå tomt for ingen utløp.",
"provisioningKeysValidUntilInvalid": "Angi en gyldig dato og klokkeslett.", "provisioningKeysValidUntilInvalid": "Angi en gyldig dato og klokkeslett.",
"provisioningKeysNumUsed": "Antall ganger brukt", "provisioningKeysNumUsed": "Antall ganger brukt",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Aldri", "provisioningKeysNeverUsed": "Aldri",
"provisioningKeysEdit": "Rediger bestemmelsesnøkkel", "provisioningKeysEdit": "Rediger bestemmelsesnøkkel",
"provisioningKeysEditDescription": "Oppdater maksimal størrelse for bunt og utløpstid for denne nøkkelen.", "provisioningKeysEditDescription": "Oppdater maksimal størrelse for bunt og utløpstid for denne nøkkelen.",
"provisioningKeysApproveNewSites": "Godkjenn nye nettsteder", "provisioningKeysApproveNewSites": "Godkjenn Nye Områder",
"provisioningKeysApproveNewSitesDescription": "Godkjenn automatisk nettsteder som registrerer deg med denne nøkkelen.", "provisioningKeysApproveNewSitesDescription": "Godkjenn automatisk nettsteder som registrerer deg med denne nøkkelen.",
"provisioningKeysUpdateError": "Feil under oppdatering av foreløpig nøkkel", "provisioningKeysUpdateError": "Feil under oppdatering av foreløpig nøkkel",
"provisioningKeysUpdated": "Foreslå nøkkel oppdatert", "provisioningKeysUpdated": "Foreslå nøkkel oppdatert",
@@ -597,7 +627,8 @@
"idpNameInternal": "Intern", "idpNameInternal": "Intern",
"emailInvalid": "Ugyldig e-postadresse", "emailInvalid": "Ugyldig e-postadresse",
"inviteValidityDuration": "Vennligst velg en varighet", "inviteValidityDuration": "Vennligst velg en varighet",
"accessRoleSelectPlease": "Vennligst velg en rolle", "accessRoleSelectPlease": "En bruker må tilhøre minst en rolle.",
"accessRoleRequired": "Rolle påkrevd",
"removeOwnAdminRoleConfirmTitle": "Fjern din administratoradgang?", "removeOwnAdminRoleConfirmTitle": "Fjern din administratoradgang?",
"removeOwnAdminRoleConfirmDescription": "Du vil ikke lenger ha administratorrettigheter i denne organisasjonen etter lagring. En annen administrator kan gjenopprette tilgang hvis nødvendig.", "removeOwnAdminRoleConfirmDescription": "Du vil ikke lenger ha administratorrettigheter i denne organisasjonen etter lagring. En annen administrator kan gjenopprette tilgang hvis nødvendig.",
"removeOwnAdminRoleConfirmButton": "Fjern min administratoradgang", "removeOwnAdminRoleConfirmButton": "Fjern min administratoradgang",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Grunnleggende Header Autentisering", "policyAuthHeaderAuthTitle": "Grunnleggende Header Autentisering",
"policyAuthHeaderAuthDescription": "Bekreft et tilpasset HTTP-headernavn og verdi ved hver forespørsel", "policyAuthHeaderAuthDescription": "Bekreft et tilpasset HTTP-headernavn og verdi ved hver forespørsel",
"policyAuthHeaderAuthSummary": "Header konfigurert", "policyAuthHeaderAuthSummary": "Header konfigurert",
"policyAuthHeaderName": "Headernavn", "policyAuthHeaderName": "Brukernavn",
"policyAuthHeaderValue": "Forventet verdi", "policyAuthHeaderValue": "Passord",
"policyAuthSetPasscode": "Angi passordkode", "policyAuthSetPasscode": "Angi passordkode",
"policyAuthSetPincode": "Sett PIN-kode", "policyAuthSetPincode": "Sett PIN-kode",
"policyAuthSetEmailWhitelist": "Angi e-post hviteliste", "policyAuthSetEmailWhitelist": "Angi e-post hviteliste",
@@ -903,7 +934,7 @@
"newtVersion": "Versjon", "newtVersion": "Versjon",
"architecture": "Arkitektur", "architecture": "Arkitektur",
"sites": "Områder", "sites": "Områder",
"siteWgAnyClients": "Bruk hvilken som helst WireGuard klient til å koble til. Du må adressere interne ressurser ved hjelp av peer IP.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Kompatibel med alle WireGuard-klienter", "siteWgCompatibleAllClients": "Kompatibel med alle WireGuard-klienter",
"siteWgManualConfigurationRequired": "Manuell konfigurasjon påkrevd", "siteWgManualConfigurationRequired": "Manuell konfigurasjon påkrevd",
"userErrorNotAdminOrOwner": "Bruker er ikke administrator eller eier", "userErrorNotAdminOrOwner": "Bruker er ikke administrator eller eier",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Opprett Org bruker", "createOrgUser": "Opprett Org bruker",
"actionUpdateOrg": "Oppdater organisasjon", "actionUpdateOrg": "Oppdater organisasjon",
"actionRemoveInvitation": "Fjern invitasjon", "actionRemoveInvitation": "Fjern invitasjon",
"actionRemoveUserRole": "Fjern Brukerrolle",
"actionUpdateUser": "Oppdater bruker", "actionUpdateUser": "Oppdater bruker",
"actionGetUser": "Hent bruker", "actionGetUser": "Hent bruker",
"actionGetOrgUser": "Hent organisasjonsbruker", "actionGetOrgUser": "Hent organisasjonsbruker",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Bruk blåkopi", "actionApplyBlueprint": "Bruk blåkopi",
"actionListBlueprints": "List opp blåkopier", "actionListBlueprints": "List opp blåkopier",
"actionGetBlueprint": "Hent blåkopi", "actionGetBlueprint": "Hent blåkopi",
"actionCreateOrgWideLauncherView": "Opprett lanseringsvisning for hele organisasjonen",
"setupToken": "Oppsetttoken", "setupToken": "Oppsetttoken",
"setupTokenDescription": "Skriv inn oppsetttoken fra serverkonsollen.", "setupTokenDescription": "Skriv inn oppsetttoken fra serverkonsollen.",
"setupTokenRequired": "Oppsetttoken er nødvendig", "setupTokenRequired": "Oppsetttoken er nødvendig",
"actionUpdateSite": "Oppdater område", "actionUpdateSite": "Oppdater område",
"actionApproveSite": "Godkjenn Område",
"actionRejectSite": "Avvis Område",
"actionResetSiteBandwidth": "Tilbakestill organisasjons-båndbredde", "actionResetSiteBandwidth": "Tilbakestill organisasjons-båndbredde",
"actionListSiteRoles": "List opp tillatte områderoller", "actionListSiteRoles": "List opp tillatte områderoller",
"actionCreateResource": "Opprett ressurs", "actionCreateResource": "Opprett ressurs",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Angi ressurspinkode", "actionSetResourcePincode": "Angi ressurspinkode",
"actionSetResourceEmailWhitelist": "Angi e-post-hviteliste for ressurs", "actionSetResourceEmailWhitelist": "Angi e-post-hviteliste for ressurs",
"actionGetResourceEmailWhitelist": "Hent e-post-hviteliste for ressurs", "actionGetResourceEmailWhitelist": "Hent e-post-hviteliste for ressurs",
"actionGetResourcePolicy": "Hent ressursregel",
"actionUpdateResourcePolicy": "Oppdater ressursregel",
"actionSetResourcePolicyUsers": "Sett ressursregel for brukere",
"actionSetResourcePolicyRoles": "Sett ressursregel for roller",
"actionSetResourcePolicyPassword": "Sett ressursregel for passord",
"actionSetResourcePolicyPincode": "Sett ressursregel for pinkode",
"actionSetResourcePolicyHeaderAuth": "Sett ressursregel for header-autentisering",
"actionSetResourcePolicyWhitelist": "Sett ressursregel for hvitlisting av e-post",
"actionSetResourcePolicyRules": "Sett ressursregel for regler",
"actionCreateTarget": "Opprett mål", "actionCreateTarget": "Opprett mål",
"actionDeleteTarget": "Slett mål", "actionDeleteTarget": "Slett mål",
"actionGetTarget": "Hent mål", "actionGetTarget": "Hent mål",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Generer tilgangstoken", "actionGenerateAccessToken": "Generer tilgangstoken",
"actionDeleteAccessToken": "Slett tilgangstoken", "actionDeleteAccessToken": "Slett tilgangstoken",
"actionListAccessTokens": "List opp tilgangstokener", "actionListAccessTokens": "List opp tilgangstokener",
"actionCreateResourceSessionToken": "Opprett ressurs økt-token",
"actionCreateResourceRule": "Opprett ressursregel", "actionCreateResourceRule": "Opprett ressursregel",
"actionDeleteResourceRule": "Slett ressursregel", "actionDeleteResourceRule": "Slett ressursregel",
"actionListResourceRules": "List opp ressursregler", "actionListResourceRules": "List opp ressursregler",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Liste invitasjoner", "actionListInvitations": "Liste invitasjoner",
"actionExportLogs": "Eksportlogger", "actionExportLogs": "Eksportlogger",
"actionViewLogs": "Vis logger", "actionViewLogs": "Vis logger",
"actionCreateSiteProvisioningKey": "Opprett Klargjøringsnøkkel for Sted",
"actionListSiteProvisioningKeys": "List Klargjøringsnøkler for Sted",
"actionUpdateSiteProvisioningKey": "Oppdater Klargjøringsnøkkel for Sted",
"actionDeleteSiteProvisioningKey": "Slett Klargjøringsnøkkel for Sted",
"noneSelected": "Ingen valgt", "noneSelected": "Ingen valgt",
"orgNotFound2": "Ingen organisasjoner funnet.", "orgNotFound2": "Ingen organisasjoner funnet.",
"search": "Søk…", "search": "Søk…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Sist brukt",
"otpAuthBack": "Tilbake til passord", "otpAuthBack": "Tilbake til passord",
"navbar": "Navigasjonsmeny", "navbar": "Navigasjonsmeny",
"navbarDescription": "Hovednavigasjonsmeny for applikasjonen", "navbarDescription": "Hovednavigasjonsmeny for applikasjonen",
"navbarDocsLink": "Dokumentasjon", "navbarDocsLink": "Dokumentasjon",
"commandPaletteTitle": "Kommando-palett",
"commandPaletteDescription": "Søk etter sider, organisasjoner, ressurser, og handlinger",
"commandPaletteSearchPlaceholder": "Søk sider, ressurser, handlinger...",
"commandPaletteNoResults": "Ingen resultater funnet.",
"commandPaletteSearching": "Søker...",
"commandPaletteNavigation": "Navigasjon",
"commandPaletteOrganizations": "Organisasjoner",
"commandPaletteSites": "Områder",
"commandPaletteResources": "Ressurser",
"commandPaletteUsers": "Brukere",
"commandPaletteClients": "Maskinklienter",
"commandPaletteActions": "Handlinger",
"commandPaletteCreateSite": "Opprett område",
"commandPaletteCreateProxyResource": "Opprett offentlig ressurs",
"commandPaletteCreatePrivateResource": "Opprett privat ressurs",
"commandPaletteCreateUser": "Opprett bruker",
"commandPaletteCreateApiKey": "Opprett API-nøkkel",
"commandPaletteCreateMachineClient": "Opprett maskinklient",
"commandPaletteCreateAlertRule": "Opprett varslingsregel",
"commandPaletteCreateIdentityProvider": "Opprett identitetsleverandør",
"commandPaletteToggleTheme": "Bytt tema",
"commandPaletteChooseOrganization": "Velg organisasjon",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Kunne ikke aktivere 2FA", "otpErrorEnable": "Kunne ikke aktivere 2FA",
"otpErrorEnableDescription": "En feil oppstod under aktivering av 2FA", "otpErrorEnableDescription": "En feil oppstod under aktivering av 2FA",
"otpSetupCheckCode": "Vennligst skriv inn en 6-sifret kode", "otpSetupCheckCode": "Vennligst skriv inn en 6-sifret kode",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Administrasjon", "sidebarManagement": "Administrasjon",
"sidebarBillingAndLicenses": "Fakturering & lisenser", "sidebarBillingAndLicenses": "Fakturering & lisenser",
"sidebarLogsAnalytics": "Analyser", "sidebarLogsAnalytics": "Analyser",
"commandSites": "Områder",
"commandActionModeInfo": "Skriv \">\" for å åpne handlingsmodus",
"commandResources": "Ressurser",
"commandProxyResources": "Offentlige ressurser",
"commandClientResources": "Private ressurser",
"commandClients": "Klienter",
"commandUserDevices": "Bruker enheter",
"commandMachineClients": "Maskinklienter",
"commandDomains": "Domener",
"commandRemoteExitNodes": "Eksterne noder",
"commandTeam": "Lag",
"commandUsers": "Brukere",
"commandRoles": "Roller",
"commandInvitations": "Invitasjoner",
"commandPolicies": "Delte regler",
"commandResourcePolicies": "Offentlige ressurser regler",
"commandIdentityProviders": "Identitetsleverandører",
"commandApprovals": "Godkjenningsforespørsler",
"commandShareableLinks": "Delbare lenker",
"commandOrganization": "Organisasjon",
"commandLogsAndAnalytics": "Logg & Analyse",
"commandLogsAnalytics": "Analyse",
"commandLogsRequest": "HTTP forespørselslogger",
"commandLogsAccess": "Logger for autentisering",
"commandLogsAction": "Handlingslogger",
"commandLogsConnection": "Loggfiler for tilkobling",
"commandLogsStreaming": "Strømming",
"commandManagement": "Administrasjon",
"commandAlerting": "Varsler",
"commandProvisioning": "Forsyning",
"commandBluePrints": "Blåkopier",
"commandApiKeys": "API-nøkler",
"commandBillingAndLicenses": "Fakturering & Lisenser",
"commandBilling": "Fakturering",
"commandEnterpriseLicenses": "Lisenser",
"commandSettings": "Innstillinger",
"commandLauncher": "Oppstarter",
"commandResourceLauncher": "Ressurs Oppstarter",
"commandSearchResults": "Søkeresultater",
"alertingTitle": "Varsling", "alertingTitle": "Varsling",
"alertingDescription": "Definer kilder, triggere og handlinger for varsler", "alertingDescription": "Definer kilder, triggere og handlinger for varsler",
"alertingRules": "Varslingsregler", "alertingRules": "Varslingsregler",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Underdomene: {subdomain}", "domainPickerSubdomain": "Underdomene: {subdomain}",
"domainPickerNamespace": "Navnerom: {namespace}", "domainPickerNamespace": "Navnerom: {namespace}",
"domainPickerShowMore": "Vis mer", "domainPickerShowMore": "Vis mer",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Velg Region", "regionSelectorTitle": "Velg Region",
"domainPickerRemoteExitNodeWarning": "Tilbudte domener støttes ikke når sider kobles til eksterne avkjøringsnoder. For ressurser som skal være tilgjengelige på eksterne noder, brukes et egendefinert domene i stedet.", "domainPickerRemoteExitNodeWarning": "Tilbudte domener støttes ikke når sider kobles til eksterne avkjøringsnoder. For ressurser som skal være tilgjengelige på eksterne noder, brukes et egendefinert domene i stedet.",
"regionSelectorInfo": "Å velge en region hjelper oss med å gi bedre ytelse for din lokasjon. Du trenger ikke være i samme region som serveren.", "regionSelectorInfo": "Å velge en region hjelper oss med å gi bedre ytelse for din lokasjon. Du trenger ikke være i samme region som serveren.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domener", "billingDomains": "Domener",
"billingOrganizations": "Orger", "billingOrganizations": "Orger",
"billingRemoteExitNodes": "Eksterne Noder", "billingRemoteExitNodes": "Eksterne Noder",
"billingPublicResources": "Offentlige ressurser",
"billingPrivateResources": "Private ressurser",
"billingMachineClients": "Maskinklienter",
"billingNoLimitConfigured": "Ingen grense konfigurert", "billingNoLimitConfigured": "Ingen grense konfigurert",
"billingEstimatedPeriod": "Estimert faktureringsperiode", "billingEstimatedPeriod": "Estimert faktureringsperiode",
"billingIncludedUsage": "Inkludert Bruk", "billingIncludedUsage": "Inkludert Bruk",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Hvor mange brukere du kan bruke", "billingUsersInfo": "Hvor mange brukere du kan bruke",
"billingDomainInfo": "Hvor mange domener du kan bruke", "billingDomainInfo": "Hvor mange domener du kan bruke",
"billingRemoteExitNodesInfo": "Hvor mange fjernnoder du kan bruke", "billingRemoteExitNodesInfo": "Hvor mange fjernnoder du kan bruke",
"billingPublicResourcesInfo": "Hvor mange offentlige ressurser du kan bruke",
"billingPrivateResourcesInfo": "Hvor mange private ressurser du kan bruke",
"billingMachineClientsInfo": "Hvor mange maskinklienter du kan bruke",
"billingLicenseKeys": "Lisensnøkler", "billingLicenseKeys": "Lisensnøkler",
"billingLicenseKeysDescription": "Administrer dine lisensnøkkelabonnementer", "billingLicenseKeysDescription": "Administrer dine lisensnøkkelabonnementer",
"billingLicenseSubscription": "Lisens abonnement", "billingLicenseSubscription": "Lisens abonnement",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Subnett", "subnetPlaceholder": "Subnett",
"addressDescription": "Den interne adressen til klienten. Må falle innenfor organisasjonens undernett.", "addressDescription": "Den interne adressen til klienten. Må falle innenfor organisasjonens undernett.",
"selectSites": "Velg områder", "selectSites": "Velg områder",
"selectLabels": "Velg etiketter",
"sitesDescription": "Klienten vil ha tilkobling til de valgte områdene", "sitesDescription": "Klienten vil ha tilkobling til de valgte områdene",
"clientInstallOlm": "Installer Olm", "clientInstallOlm": "Installer Olm",
"clientInstallOlmDescription": "Få Olm til å kjøre på systemet ditt", "clientInstallOlmDescription": "Få Olm til å kjøre på systemet ditt",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Offentlig", "resourcesTableProxyResources": "Offentlig",
"resourcesTableClientResources": "Privat", "resourcesTableClientResources": "Privat",
"resourcesTableNoProxyResourcesFound": "Ingen proxy-ressurser funnet.", "resourcesTableNoProxyResourcesFound": "Ingen proxy-ressurser funnet.",
"resourcesTableNoInternalResourcesFound": "Ingen interne ressurser funnet.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Destinasjon", "resourcesTableDestination": "Destinasjon",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias adresse", "resourcesTableAliasAddress": "Alias adresse",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Avbryt", "editInternalResourceDialogCancel": "Avbryt",
"editInternalResourceDialogSaveResource": "Lagre ressurs", "editInternalResourceDialogSaveResource": "Lagre ressurs",
"editInternalResourceDialogSuccess": "Suksess", "editInternalResourceDialogSuccess": "Suksess",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Intern ressurs oppdatert vellykket", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Feil", "editInternalResourceDialogError": "Feil",
"editInternalResourceDialogFailedToUpdateInternalResource": "Mislyktes å oppdatere intern ressurs", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Navn er påkrevd", "editInternalResourceDialogNameRequired": "Navn er påkrevd",
"editInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn", "editInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
"editInternalResourceDialogProxyPortMin": "Proxy-port må være minst 1", "editInternalResourceDialogProxyPortMin": "Proxy-port må være minst 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.", "editInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.",
"createInternalResourceDialogNoSitesAvailable": "Ingen tilgjengelige steder", "createInternalResourceDialogNoSitesAvailable": "Ingen tilgjengelige steder",
"createInternalResourceDialogNoSitesAvailableDescription": "Du må ha minst ett Newt-område med et konfigureret delnett for å lage interne ressurser.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Lukk", "createInternalResourceDialogClose": "Lukk",
"createInternalResourceDialogCreateClientResource": "Opprett privat ressurs", "createInternalResourceDialogCreateClientResource": "Opprett privat ressurs",
"createInternalResourceDialogCreateClientResourceDescription": "Opprett en ny ressurs som bare vil være tilgjengelig for kunder som er koblet til organisasjonen", "createInternalResourceDialogCreateClientResourceDescription": "Opprett en ny ressurs som bare vil være tilgjengelig for kunder som er koblet til organisasjonen",
"privateResourceGeneralDescription": "Konfigurer navnet, identifikatoren og andre generelle ressursinnstillinger.",
"privateResourceCreatePageSeeAll": "Se alle private ressurser",
"privateResourceAllowIcmpPing": "Tillat ICMP Ping",
"privateResourceNetworkAccess": "Nettverkstilgang",
"privateResourceNetworkAccessDescription": "Kontroller TCP/UDP porttilgang og om ICMP ping tillates for denne ressursen.",
"hostSettings": "Vertinnstillinger",
"cidrSettings": "CIDR-innstillinger",
"createInternalResourceDialogResourceProperties": "Ressursegenskaper", "createInternalResourceDialogResourceProperties": "Ressursegenskaper",
"createInternalResourceDialogName": "Navn", "createInternalResourceDialogName": "Navn",
"createInternalResourceDialogSite": "Område", "createInternalResourceDialogSite": "Område",
"selectSite": "Velg område...", "selectSite": "Velg område...",
"multiSitesSelectorSitesCount": "{count, plural, one {# sted} other {# steder}}", "multiSitesSelectorSitesCount": "{count, plural, one {# sted} other {# steder}}",
"labelsSelectorLabelsCount": "{count, plural, one {en etikett} other {# etiketter}}",
"noSitesFound": "Ingen områder funnet.", "noSitesFound": "Ingen områder funnet.",
"createInternalResourceDialogProtocol": "Protokoll", "createInternalResourceDialogProtocol": "Protokoll",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Avbryt", "createInternalResourceDialogCancel": "Avbryt",
"createInternalResourceDialogCreateResource": "Opprett ressurs", "createInternalResourceDialogCreateResource": "Opprett ressurs",
"createInternalResourceDialogSuccess": "Suksess", "createInternalResourceDialogSuccess": "Suksess",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Intern ressurs opprettet vellykket", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Feil", "createInternalResourceDialogError": "Feil",
"createInternalResourceDialogFailedToCreateInternalResource": "Kunne ikke opprette intern ressurs", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Navn er påkrevd", "createInternalResourceDialogNameRequired": "Navn er påkrevd",
"createInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn", "createInternalResourceDialogNameMaxLength": "Navn kan ikke være lengre enn 255 tegn",
"createInternalResourceDialogPleaseSelectSite": "Vennligst velg et område", "createInternalResourceDialogPleaseSelectSite": "Vennligst velg et område",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "CIDR-rekkevidden til ressursen på nettstedets nettverk.", "createInternalResourceDialogDestinationCidrDescription": "CIDR-rekkevidden til ressursen på nettstedets nettverk.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.", "createInternalResourceDialogAliasDescription": "Et valgfritt internt DNS-alias for denne ressursen.",
"internalResourceAliasLocalWarning": "Alias som slutter på .local kan forårsake oppløsningsproblemer på grunn av mDNS på enkelte nettverk.",
"internalResourceDownstreamSchemeRequired": "Skjema er påkrevd for HTTP-ressurser", "internalResourceDownstreamSchemeRequired": "Skjema er påkrevd for HTTP-ressurser",
"internalResourceHttpPortRequired": "Destinasjonsport er nødvendig for HTTP-ressurser", "internalResourceHttpPortRequired": "Destinasjonsport er nødvendig for HTTP-ressurser",
"siteConfiguration": "Konfigurasjon", "siteConfiguration": "Konfigurasjon",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Eksterne Noder", "sidebarRemoteExitNodes": "Eksterne Noder",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Sikkerhetsnøkkel", "remoteExitNodeSecretKey": "Sikkerhetsnøkkel",
"remoteExitNodeNetworkingTitle": "Nettverksinnstillinger",
"remoteExitNodeNetworkingDescription": "Konfigurer hvordan denne fjerne utgangsnoden ruter trafikk og hvilke områder som foretrekker å koble gjennom den. Avanserte funksjoner for å brukes med bakhalstilkoplingskonfigurasjoner.",
"remoteExitNodeNetworkingSave": "Lagre innstillinger",
"remoteExitNodeNetworkingSaveSuccessTitle": "Nettverksinnstillinger lagret",
"remoteExitNodeNetworkingSaveSuccessDescription": "Nettverksinnstillingene er oppdatert.",
"remoteExitNodeNetworkingSaveError": "Klarte ikke å lagre nettverksinnstillinger",
"remoteExitNodeNetworkingSubnetsTitle": "Fjern-subnett",
"remoteExitNodeNetworkingSubnetsDescription": "Definer CIDR-områdene som denne fjernutgangsnoden vil rute trafikk til. Skriv inn en gyldig CIDR (f.eks. <code>10.0.0.0/8</code>) og trykk Enter for å legge til.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Legg til et CIDR-område (f.eks. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Feil ved lasting av subnett",
"remoteExitNodeNetworkingLabelsTitle": "Preferanseetiketter",
"remoteExitNodeNetworkingLabelsDescription": "Områder med disse etikettene vil bli tvunget til å koble gjennom denne fjerne utgangsnoden.",
"remoteExitNodeNetworkingLabelsButtonText": "Velg etiketter...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Søk etiketter...",
"remoteExitNodeNetworkingLabelsLoadError": "Feil ved lasting av etiketter",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Opprett ekstern node", "title": "Opprett ekstern node",
"description": "Opprett en ny egendrift ekstern relé- og proxyservernode", "description": "Opprett en ny egendrift ekstern relé- og proxyservernode",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Ingen noder er tilgjengelige for denne organisasjonen. Opprett en node først for å bruke lokale nettsteder.", "noRemoteExitNodesAvailableDescription": "Ingen noder er tilgjengelige for denne organisasjonen. Opprett en node først for å bruke lokale nettsteder.",
"exitNode": "Utgangsnode", "exitNode": "Utgangsnode",
"country": "Land", "country": "Land",
"countryIsNot": "Land ikke",
"rulesMatchCountry": "For tiden basert på kilde IP", "rulesMatchCountry": "For tiden basert på kilde IP",
"region": "Fylke", "region": "Fylke",
"selectRegion": "Velg region", "selectRegion": "Velg region",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC leverandør", "idpGoogleDescription": "Google OAuth2/OIDC leverandør",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Subnett", "subnet": "Subnett",
"utilitySubnet": "Nyttesubnett",
"subnetDescription": "Undernettverket for denne organisasjonens nettverkskonfigurasjon.", "subnetDescription": "Undernettverket for denne organisasjonens nettverkskonfigurasjon.",
"customDomain": "Egendefinert domene", "customDomain": "Egendefinert domene",
"authPage": "Autentiseringssider", "authPage": "Autentiseringssider",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "To-faktor autentiseringsoppsett er nødvendig. Vennligst logg inn igjen via {dashboardUrl}/auth/login og fullfør dette steget. Kom deretter tilbake her.", "twoFactorSetupRequired": "To-faktor autentiseringsoppsett er nødvendig. Vennligst logg inn igjen via {dashboardUrl}/auth/login og fullfør dette steget. Kom deretter tilbake her.",
"additionalSecurityRequired": "Ekstra sikkerhet kreves", "additionalSecurityRequired": "Ekstra sikkerhet kreves",
"organizationRequiresAdditionalSteps": "Denne organisasjonen krever ytterligere sikkerhetstrinn før du får tilgang til ressurser.", "organizationRequiresAdditionalSteps": "Denne organisasjonen krever ytterligere sikkerhetstrinn før du får tilgang til ressurser.",
"sessionExpired": "Økt utløpt",
"sessionExpiredReauthRequired": "Økten din har utløpt i henhold til organisasjonens sikkerhetspolitikk. Vennligst autentiser på nytt for å fortsette.",
"reauthenticate": "Autentiser på nytt",
"completeTheseSteps": "Fullfør disse trinnene", "completeTheseSteps": "Fullfør disse trinnene",
"enableTwoFactorAuthentication": "Aktiver to-faktor autentisering", "enableTwoFactorAuthentication": "Aktiver to-faktor autentisering",
"completeSecuritySteps": "Fullfør sikkerhetstrinnene", "completeSecuritySteps": "Fullfør sikkerhetstrinnene",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Kilde adresse", "sourceAddress": "Kilde adresse",
"destinationAddress": "Måladresse (Automatic Translation)", "destinationAddress": "Måladresse (Automatic Translation)",
"duration": "Varighet", "duration": "Varighet",
"licenseRequiredToUse": "En <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lisens eller <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> er påkrevd for å bruke denne funksjonen. <bookADemoLink>Bestill en demo eller POC prøveversjon</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> er nødvendig for å bruke denne funksjonen. Denne funksjonen er også tilgjengelig i <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Bestill en demo eller POC studie</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Sertifikat løser", "certResolver": "Sertifikat løser",
"certResolverDescription": "Velg sertifikatløser som skal brukes for denne ressursen.", "certResolverDescription": "Velg sertifikatløser som skal brukes for denne ressursen.",
"selectCertResolver": "Velg sertifikatløser", "selectCertResolver": "Velg sertifikatløser",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "ID for organisasjon eller domene mangler", "orgOrDomainIdMissing": "ID for organisasjon eller domene mangler",
"loadingDNSRecords": "Laster DNS-poster...", "loadingDNSRecords": "Laster DNS-poster...",
"olmUpdateAvailableInfo": "En oppdatert versjon av Olm er tilgjengelig. Oppdater til den nyeste versjonen for å få den beste opplevelsen.", "olmUpdateAvailableInfo": "En oppdatert versjon av Olm er tilgjengelig. Oppdater til den nyeste versjonen for å få den beste opplevelsen.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "En oppdatert versjon er tilgjengelig. Vennligst oppdater til den nyeste versjonen for den beste opplevelsen.",
"client": "Klient", "client": "Klient",
"proxyProtocol": "Protokoll innstillinger for Protokoll", "proxyProtocol": "Protokoll innstillinger for Protokoll",
"proxyProtocolDescription": "Konfigurer Proxy-protokoll for å bevare klientens IP-adresser til TCP-tjenester.", "proxyProtocolDescription": "Konfigurer Proxy-protokoll for å bevare klientens IP-adresser til TCP-tjenester.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Legg til brukere", "editInternalResourceDialogAddUsers": "Legg til brukere",
"editInternalResourceDialogAddClients": "Legg til klienter", "editInternalResourceDialogAddClients": "Legg til klienter",
"editInternalResourceDialogDestinationLabel": "Destinasjon", "editInternalResourceDialogDestinationLabel": "Destinasjon",
"editInternalResourceDialogDestinationDescription": "Spesifiser destinasjonsadressen for den interne ressursen. Dette kan være et vertsnavn, IP-adresse eller CIDR-sjikt avhengig av valgt modus. Valgfrie oppsett av intern DNS-alias for enklere identifikasjon.", "editInternalResourceDialogDestinationDescription": "Konfigurer hvordan klienter får tilgang til denne ressursen.",
"internalResourceFormMultiSiteRoutingHelp": "Valg av flere nettsteder muliggjør motstandskraftig ruting og failover for høy tilgjengelighet.", "internalResourceFormMultiSiteRoutingHelp": "Valg av flere nettsteder muliggjør motstandskraftig ruting og failover for høy tilgjengelighet.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Lær mer", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Lær mer",
"editInternalResourceDialogPortRestrictionsDescription": "Begrens tilgang til spesifikke TCP/UDP-porter eller tillate/blokkere alle porter.", "editInternalResourceDialogPortRestrictionsDescription": "Begrens tilgang til spesifikke TCP/UDP-porter eller tillate/blokkere alle porter.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "E-post-hviteliste", "memberPortalEmailWhitelist": "E-post-hviteliste",
"memberPortalResourceDisabled": "Ressurs deaktivert", "memberPortalResourceDisabled": "Ressurs deaktivert",
"memberPortalShowingResources": "Viser {start}-{end} av {total} ressurser", "memberPortalShowingResources": "Viser {start}-{end} av {total} ressurser",
"resourceLauncherTitle": "Ressurslansering",
"resourceSidebarLauncherTitle": "Oppstarter",
"resourceLauncherDescription": "Se alle tilgjengelige ressurser og start dem fra ett sentralt sted",
"resourceLauncherSearchPlaceholder": "Søk i ressurser...",
"resourceLauncherDefaultView": "Standard",
"resourceLauncherSaveView": "Lagre visning",
"resourceLauncherSaveToCurrentView": "Lagre til nåværende visning",
"resourceLauncherSaveDefaultPersonal": "Lagre for meg",
"resourceLauncherResetView": "Tilbakestill visning",
"resourceLauncherResetSystemDefault": "Tilbakestill til systemets standard",
"resourceLauncherSystemDefaultRestored": "Systemstandard gjenopprettet",
"resourceLauncherSystemDefaultRestoredDescription": "Standardvisningen er tilbakestilt til de opprinnelige innstillingene.",
"resourceLauncherSaveAsNewView": "Lagre som ny visning",
"resourceLauncherSaveAsNewViewDescription": "Gi denne visningen et navn for å lagre dine nåværende filtre og oppsett.",
"resourceLauncherSaveForEveryone": "Lagre for alle",
"resourceLauncherSaveForEveryoneDescription": "Del denne visningen med alle organisasjonsmedlemmer. Når avkrysset, er visningen synlig bare for deg.",
"resourceLauncherMakePersonal": "Gjør personlig",
"resourceLauncherFilter": "Filter",
"resourceLauncherFilterWithCount": "Filter, {count} anvendt",
"resourceLauncherSort": "Sorter",
"resourceLauncherSortAscending": "Sorter stigende",
"resourceLauncherSortDescending": "Sorter synkende",
"resourceLauncherSettings": "Innstillinger",
"resourceLauncherGroupBy": "Grupper etter",
"resourceLauncherGroupBySite": "Område",
"resourceLauncherGroupByLabel": "Etikett",
"resourceLauncherGroupByNone": "Ingen",
"resourceLauncherLayout": "Oppsett",
"resourceLauncherLayoutGrid": "Rutenett",
"resourceLauncherLayoutList": "Liste",
"resourceLauncherShowLabels": "Vis etiketter",
"resourceLauncherShowSiteTags": "Vis områdestikkord",
"resourceLauncherShowRecents": "Vis nylige",
"resourceLauncherDeleteView": "Slett visning",
"resourceLauncherDeleteViewTitle": "Slett visning",
"resourceLauncherDeleteViewQuestion": "Er du sikker på at du vil slette denne oppstartervisningen?",
"resourceLauncherDeleteViewConfirm": "Slett visning",
"resourceLauncherViewAsAdmin": "Vis som administrator",
"resourceLauncherResourceDetailsDescription": "Tilkoblingsinformasjon og status for denne ressursen.",
"resourceLauncherResourceDetails": "Ressursdetaljer",
"resourceLauncherAuthMethodsDescription": "Godkjenningsmetoder aktivert for denne ressursen.",
"resourceLauncherPrivateClientRequired": "Koble til med en klient på enheten din for å få privat tilgang til denne ressursen.",
"resourceLauncherPrivateClientRequiredTitle": "Klienttilkobling kreves",
"resourceLauncherDownloadClient": "Last ned klient",
"resourceLauncherFailedToLoadDetails": "Kunne ikke laste ressurstetatter. Du har kanskje ikke lenger tilgang til denne ressursen.",
"resourceLauncherNoPortRestrictions": "Ingen portbegrensninger",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Umerket",
"resourceLauncherNoSite": "Ingen område",
"resourceLauncherNoResourcesInGroup": "Ingen ressurser i denne gruppen",
"resourceLauncherEmptyStateTitle": "Ingen tilgjengelige ressurser",
"resourceLauncherEmptyStateDescription": "Du har ennå ikke tilgang til noen ressurser. Kontakt administratoren din for å be om tilgang.",
"resourceLauncherEmptyStateNoResultsTitle": "Ingen ressurser funnet",
"resourceLauncherEmptyStateNoResultsDescription": "Ingen ressurser matcher dine nåværende søk eller filtre. Prøv å justere dem for å finne det du leter etter.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Ingen ressurser samsvarer med \"{query}\". Prøv å justere søket eller fjern filtrene for å se alle ressursene.",
"resourceLauncherSearchFirstTitle": "Søk eller filtrer for å bla gjennom",
"resourceLauncherSearchFirstDescription": "Du har tilgang til mange ressurser. Bruk søk eller filtrer eksplisitt etter sted eller etikett for å finne det du trenger.",
"resourceLauncherSiteGroupingDisabled": "Stedssamling er ikke tilgjengelig i denne omfanget. Filtrer etter sted for å gruppere et mindre sett.",
"resourceLauncherLabelGroupingDisabled": "Etikettsamling er ikke tilgjengelig i denne omfanget.",
"resourceLauncherCompactModeHint": "Viser en forenklet liste for raskere bla. Bruk søk eller filtrer for å innskrenke resultatene.",
"resourceLauncherCompactGroupingHint": "Bruk filter for sted eller etikett for å aktivere gruppering.",
"resourceLauncherCopiedToClipboard": "Kopiert til utklippstavlen",
"resourceLauncherCopiedAccessDescription": "Ressurstilgang er kopiert til utklippstavlen din.",
"resourceLauncherViewNamePlaceholder": "Visningsnavn",
"resourceLauncherViewNameLabel": "Visningsnavn",
"resourceLauncherViewSaved": "Visning lagret",
"resourceLauncherViewSavedDescription": "Lanseringsvisningen din er lagret.",
"resourceLauncherViewSaveFailed": "Feilet å lagre visning",
"resourceLauncherViewSaveFailedDescription": "Kunne ikke lagre lanseringsvisningen. Vennligst prøv igjen.",
"resourceLauncherViewDeleted": "Visning slettet",
"resourceLauncherViewDeletedDescription": "Lanseringsvisningen er slettet.",
"resourceLauncherViewDeleteFailed": "Klarte ikke å slette visning",
"resourceLauncherViewDeleteFailedDescription": "Kunne ikke slette lanseringsvisningen. Vennligst prøv igjen.",
"memberPortalPrevious": "Forrige", "memberPortalPrevious": "Forrige",
"memberPortalNext": "Neste", "memberPortalNext": "Neste",
"httpSettings": "HTTP Innstillinger", "httpSettings": "HTTP Innstillinger",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGYNN OPENSSH PRIVAT NØKKEL-----", "sshPrivateKeyPlaceholder": "-----BEGYNN OPENSSH PRIVAT NØKKEL-----",
"sshPrivateKeyRequired": "Privat nøkkel er påkrevd", "sshPrivateKeyRequired": "Privat nøkkel er påkrevd",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Skriv inn VNC-passordet for å koble til", "vncSignInDescription": "Skriv inn VNC-kredentialene dine for å koble til",
"vncUsernameOptional": "Brukernavn (valgfritt)",
"vncPasswordOptional": "Passord (valgfritt)", "vncPasswordOptional": "Passord (valgfritt)",
"vncNoResourceTarget": "Ingen ressursemål tilgjengelig", "vncNoResourceTarget": "Ingen ressursemål tilgjengelig",
"vncFailedToLoadNovnc": "Klarte ikke å laste noVNC", "vncFailedToLoadNovnc": "Klarte ikke å laste noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Opplastningen mislyktes", "rdpUploadFailed": "Opplastningen mislyktes",
"rdpUnicodeKeyboardMode": "Unicode tastaturmodus", "rdpUnicodeKeyboardMode": "Unicode tastaturmodus",
"sessionToolbarShow": "Vis verktøylinje", "sessionToolbarShow": "Vis verktøylinje",
"sessionToolbarHide": "Skjul verktøylinje" "sessionToolbarHide": "Skjul verktøylinje",
"actionUpdateSiteApprovals": "Oppdater Stedsgodkjenninger"
} }
+248 -20
View File
@@ -66,9 +66,15 @@
"local": "Lokaal", "local": "Lokaal",
"edit": "Bewerken", "edit": "Bewerken",
"siteConfirmDelete": "Verwijderen van site bevestigen", "siteConfirmDelete": "Verwijderen van site bevestigen",
"siteConfirmDeleteAndResources": "Bevestig Verwijderen van Site en Bronnen",
"siteDelete": "Site verwijderen", "siteDelete": "Site verwijderen",
"siteDeleteAndResources": "Site en Bronnen verwijderen",
"siteMessageRemove": "Eenmaal verwijderd zal de site niet langer toegankelijk zijn. Alle aan de site gekoppelde doelen zullen ook worden verwijderd.", "siteMessageRemove": "Eenmaal verwijderd zal de site niet langer toegankelijk zijn. Alle aan de site gekoppelde doelen zullen ook worden verwijderd.",
"siteMessageRemoveAndResources": "Dit zal permanent alle publieke en private resources gekoppeld aan deze site verwijderen, zelfs als een resource ook aan andere sites is gekoppeld.",
"siteQuestionRemove": "Weet u zeker dat u de site wilt verwijderen uit de organisatie?", "siteQuestionRemove": "Weet u zeker dat u de site wilt verwijderen uit de organisatie?",
"siteQuestionRemoveAndResources": "Weet u zeker dat u deze site en alle gekoppelde resources wilt verwijderen?",
"sitesTableDeleteSite": "Site verwijderen",
"sitesTableDeleteSiteAndResources": "Site en Bronnen verwijderen",
"siteManageSites": "Sites beheren", "siteManageSites": "Sites beheren",
"siteDescription": "Maak en beheer sites om verbinding met privénetwerken in te schakelen", "siteDescription": "Maak en beheer sites om verbinding met privénetwerken in te schakelen",
"sitesBannerTitle": "Verbind elk netwerk", "sitesBannerTitle": "Verbind elk netwerk",
@@ -117,6 +123,16 @@
"siteUpdated": "Site bijgewerkt", "siteUpdated": "Site bijgewerkt",
"siteUpdatedDescription": "De site is bijgewerkt.", "siteUpdatedDescription": "De site is bijgewerkt.",
"siteGeneralDescription": "Algemene instellingen voor deze site configureren", "siteGeneralDescription": "Algemene instellingen voor deze site configureren",
"siteRestartTitle": "Herstart Site",
"siteRestartDescription": "Herstart de WireGuard-tunnel voor deze site. Dit zal de connectiviteit kort onderbreken.",
"siteRestartBody": "Gebruik dit als de sitetunnel niet correct functioneert en je wilt een herverbinding forceren zonder de host opnieuw op te starten.",
"siteRestartButton": "Herstart Site",
"siteRestartDialogMessage": "Weet u zeker dat u de WireGuard-tunnel voor <b>{name}</b> wilt herstarten? De site zal tijdelijk geen connectiviteit hebben.",
"siteRestartWarning": "De site zal kort worden losgekoppeld terwijl de tunnel opnieuw wordt gestart.",
"siteRestarted": "Site herstart",
"siteRestartedDescription": "De WireGuard-tunnel is opnieuw gestart.",
"siteErrorRestart": "Site herstarten mislukt",
"siteErrorRestartDescription": "Er is een fout opgetreden tijdens het herstarten van de site.",
"siteSettingDescription": "Configureer de instellingen van de site", "siteSettingDescription": "Configureer de instellingen van de site",
"siteResourcesTab": "Bronnen", "siteResourcesTab": "Bronnen",
"siteResourcesNoneOnSite": "Deze site heeft nog geen openbare of privébronnen.", "siteResourcesNoneOnSite": "Deze site heeft nog geen openbare of privébronnen.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Bevestig Verwijdering Deelbare Link", "shareDeleteConfirm": "Bevestig Verwijdering Deelbare Link",
"shareQuestionRemove": "Weet u zeker dat u deze deel link wilt verwijderen?", "shareQuestionRemove": "Weet u zeker dat u deze deel link wilt verwijderen?",
"shareMessageRemove": "Zodra verwijderd, zal de link niet meer werken en zal iedereen die het gebruikt de toegang tot de bron verliezen.", "shareMessageRemove": "Zodra verwijderd, zal de link niet meer werken en zal iedereen die het gebruikt de toegang tot de bron verliezen.",
"shareTokenDescription": "De toegangstoken kan op twee manieren worden doorgegeven: als queryparameter of in de aanvraagheaders. Deze moeten worden doorgegeven van de client op elk verzoek voor geverifieerde toegang.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Toegangs-token", "accessToken": "Toegangs-token",
"usageExamples": "Voorbeelden van gebruik", "usageExamples": "Voorbeelden van gebruik",
"tokenId": "Token ID", "tokenId": "Token ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Titel (optioneel)", "shareTitleOptional": "Titel (optioneel)",
"sharePathOptional": "Pad (optioneel)", "sharePathOptional": "Pad (optioneel)",
"sharePathDescription": "De link zal gebruikers naar dit pad doorsturen na authenticatie.", "sharePathDescription": "De link zal gebruikers naar dit pad doorsturen na authenticatie.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Vervalt in", "expireIn": "Vervalt in",
"neverExpire": "Nooit verlopen", "neverExpire": "Nooit verlopen",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Vervaltijd is hoe lang de link bruikbaar is en geeft toegang tot de bron. Na deze tijd zal de link niet meer werken en zullen gebruikers die deze link hebben gebruikt de toegang tot de pagina verliezen.", "shareExpireDescription": "Vervaltijd is hoe lang de link bruikbaar is en geeft toegang tot de bron. Na deze tijd zal de link niet meer werken en zullen gebruikers die deze link hebben gebruikt de toegang tot de pagina verliezen.",
"shareSeeOnce": "U kunt deze link slechts één keer zien. Zorg ervoor dat u deze kopieert.", "shareSeeOnce": "U kunt deze link slechts één keer zien. Zorg ervoor dat u deze kopieert.",
"shareAccessHint": "Iedereen met deze link heeft toegang tot de bron. Deel deze met zorg.", "shareAccessHint": "Iedereen met deze link heeft toegang tot de bron. Deel deze met zorg.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy verzoeken over rauwe TCP/UDP met behulp van een poortnummer. Vereist sites om verbinding te maken met een remote node.", "resourceRawDescriptionCloud": "Proxy verzoeken over rauwe TCP/UDP met behulp van een poortnummer. Vereist sites om verbinding te maken met een remote node.",
"resourceCreate": "Bron maken", "resourceCreate": "Bron maken",
"resourceCreateDescription": "Volg de onderstaande stappen om een nieuwe bron te maken", "resourceCreateDescription": "Volg de onderstaande stappen om een nieuwe bron te maken",
"resourcePublicCreate": "Maak Openbare Bron",
"resourcePublicCreateDescription": "Volg de onderstaande stappen om een nieuwe openbare bron aan te maken die toegankelijk is via een webbrowser",
"resourceCreateGeneralDescription": "Configureer de basisinstellingen van de bron, inclusief de naam en het type", "resourceCreateGeneralDescription": "Configureer de basisinstellingen van de bron, inclusief de naam en het type",
"resourceSeeAll": "Alle bronnen bekijken", "resourceSeeAll": "Alle bronnen bekijken",
"resourceCreateGeneral": "Algemeen", "resourceCreateGeneral": "Algemeen",
@@ -431,8 +455,14 @@
"provisioningManage": "Provisie", "provisioningManage": "Provisie",
"provisioningDescription": "Voorzieningssleutels beheren en sites beoordelen in afwachting van goedkeuring.", "provisioningDescription": "Voorzieningssleutels beheren en sites beoordelen in afwachting van goedkeuring.",
"pendingSites": "Openstaande sites", "pendingSites": "Openstaande sites",
"siteApproveSuccess": "Site succesvol goedgekeurd", "siteApproveSuccess": "Site en bijbehorende middelen succesvol goedgekeurd",
"siteApproveError": "Fout bij goedkeuren website", "siteApproveError": "Fout bij goedkeuren website",
"siteReject": "Afwijzen Site",
"siteQuestionReject": "Weet u zeker dat u deze site wilt afwijzen?",
"siteMessageReject": "Hiermee wordt de site en alle bijbehorende middelen die nog in behandeling zijn permanent verwijderd.",
"siteConfirmReject": "Afwijzing van site bevestigen",
"siteRejectSuccess": "Site succesvol afgewezen",
"siteRejectError": "Fout bij het afwijzen van site",
"provisioningKeys": "Verhelderende sleutels", "provisioningKeys": "Verhelderende sleutels",
"searchProvisioningKeys": "Zoek provisioningsleutels ...", "searchProvisioningKeys": "Zoek provisioningsleutels ...",
"provisioningKeysAdd": "Genereer Provisioning Sleutel", "provisioningKeysAdd": "Genereer Provisioning Sleutel",
@@ -448,7 +478,7 @@
"provisioningKeysSave": "Sla de provisioning sleutel op", "provisioningKeysSave": "Sla de provisioning sleutel op",
"provisioningKeysSaveDescription": "Je kunt dit slechts één keer zien. Kopieer het naar een veilige plaats.", "provisioningKeysSaveDescription": "Je kunt dit slechts één keer zien. Kopieer het naar een veilige plaats.",
"provisioningKeysErrorCreate": "Fout bij aanmaken provisioning sleutel", "provisioningKeysErrorCreate": "Fout bij aanmaken provisioning sleutel",
"provisioningKeysList": "Nieuwe provisioning sleutel", "provisioningKeysList": "Nieuwe provisioning-sleutel",
"provisioningKeysMaxBatchSize": "Maximale batchgrootte", "provisioningKeysMaxBatchSize": "Maximale batchgrootte",
"provisioningKeysUnlimitedBatchSize": "Onbeperkte batchgrootte (geen limiet)", "provisioningKeysUnlimitedBatchSize": "Onbeperkte batchgrootte (geen limiet)",
"provisioningKeysMaxBatchUnlimited": "Onbeperkt", "provisioningKeysMaxBatchUnlimited": "Onbeperkt",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Nooit", "provisioningKeysNeverUsed": "Nooit",
"provisioningKeysEdit": "Wijzig Provisioning Sleutel", "provisioningKeysEdit": "Wijzig Provisioning Sleutel",
"provisioningKeysEditDescription": "Werk de maximale batchgrootte en verlooptijd voor deze sleutel bij.", "provisioningKeysEditDescription": "Werk de maximale batchgrootte en verlooptijd voor deze sleutel bij.",
"provisioningKeysApproveNewSites": "Goedkeuren van nieuwe sites", "provisioningKeysApproveNewSites": "Nieuwe sites goedkeuren",
"provisioningKeysApproveNewSitesDescription": "Automatisch sites goedkeuren die zich registreren met deze sleutel.", "provisioningKeysApproveNewSitesDescription": "Automatisch sites goedkeuren die zich registreren met deze sleutel.",
"provisioningKeysUpdateError": "Fout tijdens bijwerken provisioning sleutel", "provisioningKeysUpdateError": "Fout tijdens bijwerken provisioning sleutel",
"provisioningKeysUpdated": "Provisie sleutel bijgewerkt", "provisioningKeysUpdated": "Provisie sleutel bijgewerkt",
@@ -597,7 +627,8 @@
"idpNameInternal": "Intern", "idpNameInternal": "Intern",
"emailInvalid": "Ongeldig e-mailadres", "emailInvalid": "Ongeldig e-mailadres",
"inviteValidityDuration": "Selecteer een tijdsduur", "inviteValidityDuration": "Selecteer een tijdsduur",
"accessRoleSelectPlease": "Selecteer een rol", "accessRoleSelectPlease": "Een gebruiker moet tot minstens één rol behoren.",
"accessRoleRequired": "Rol vereist",
"removeOwnAdminRoleConfirmTitle": "Uw beheerderstoegang verwijderen?", "removeOwnAdminRoleConfirmTitle": "Uw beheerderstoegang verwijderen?",
"removeOwnAdminRoleConfirmDescription": "U zult na het opslaan geen beheerdersrechten meer hebben in deze organisatie. Een andere beheerder kan de toegang indien nodig herstellen.", "removeOwnAdminRoleConfirmDescription": "U zult na het opslaan geen beheerdersrechten meer hebben in deze organisatie. Een andere beheerder kan de toegang indien nodig herstellen.",
"removeOwnAdminRoleConfirmButton": "Verwijder Mijn Beheerderstoegang", "removeOwnAdminRoleConfirmButton": "Verwijder Mijn Beheerderstoegang",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Basic Header Authenticatie", "policyAuthHeaderAuthTitle": "Basic Header Authenticatie",
"policyAuthHeaderAuthDescription": "Valideer een aangepaste HTTP-headernaam en waarde bij elk verzoek", "policyAuthHeaderAuthDescription": "Valideer een aangepaste HTTP-headernaam en waarde bij elk verzoek",
"policyAuthHeaderAuthSummary": "Header geconfigureerd", "policyAuthHeaderAuthSummary": "Header geconfigureerd",
"policyAuthHeaderName": "Header naam", "policyAuthHeaderName": "Gebruikersnaam",
"policyAuthHeaderValue": "Verwachte waarde", "policyAuthHeaderValue": "Wachtwoord",
"policyAuthSetPasscode": "Stel toegangscode in", "policyAuthSetPasscode": "Stel toegangscode in",
"policyAuthSetPincode": "Stel Pincode in", "policyAuthSetPincode": "Stel Pincode in",
"policyAuthSetEmailWhitelist": "Stel E-mail Whitelist in", "policyAuthSetEmailWhitelist": "Stel E-mail Whitelist in",
@@ -903,7 +934,7 @@
"newtVersion": "Versie", "newtVersion": "Versie",
"architecture": "Architectuur", "architecture": "Architectuur",
"sites": "Sites", "sites": "Sites",
"siteWgAnyClients": "Gebruik een willekeurige WireGuard client om verbinding te maken. Je zult interne bronnen moeten aanspreken met behulp van de peer IP.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Compatibel met alle WireGuard clients", "siteWgCompatibleAllClients": "Compatibel met alle WireGuard clients",
"siteWgManualConfigurationRequired": "Handmatige configuratie vereist", "siteWgManualConfigurationRequired": "Handmatige configuratie vereist",
"userErrorNotAdminOrOwner": "Gebruiker is geen beheerder of eigenaar", "userErrorNotAdminOrOwner": "Gebruiker is geen beheerder of eigenaar",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Org gebruiker aanmaken", "createOrgUser": "Org gebruiker aanmaken",
"actionUpdateOrg": "Organisatie bijwerken", "actionUpdateOrg": "Organisatie bijwerken",
"actionRemoveInvitation": "Verwijder uitnodiging", "actionRemoveInvitation": "Verwijder uitnodiging",
"actionRemoveUserRole": "Gebruikersrol verwijderen",
"actionUpdateUser": "Gebruiker bijwerken", "actionUpdateUser": "Gebruiker bijwerken",
"actionGetUser": "Gebruiker ophalen", "actionGetUser": "Gebruiker ophalen",
"actionGetOrgUser": "Krijg organisatie-gebruiker", "actionGetOrgUser": "Krijg organisatie-gebruiker",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Blauwdruk toepassen", "actionApplyBlueprint": "Blauwdruk toepassen",
"actionListBlueprints": "Lijst blauwdrukken", "actionListBlueprints": "Lijst blauwdrukken",
"actionGetBlueprint": "Krijg Blauwdruk", "actionGetBlueprint": "Krijg Blauwdruk",
"actionCreateOrgWideLauncherView": "Maak Organisatiebrede Launcher Weergave",
"setupToken": "Instel Token", "setupToken": "Instel Token",
"setupTokenDescription": "Voer het setup-token in vanaf de serverconsole.", "setupTokenDescription": "Voer het setup-token in vanaf de serverconsole.",
"setupTokenRequired": "Setup-token is vereist", "setupTokenRequired": "Setup-token is vereist",
"actionUpdateSite": "Site bijwerken", "actionUpdateSite": "Site bijwerken",
"actionApproveSite": "Verleen site goedkeuring",
"actionRejectSite": "Afwijzen Site",
"actionResetSiteBandwidth": "Reset organisatieschandbreedte", "actionResetSiteBandwidth": "Reset organisatieschandbreedte",
"actionListSiteRoles": "Toon toegestane sitenollen", "actionListSiteRoles": "Toon toegestane sitenollen",
"actionCreateResource": "Bron maken", "actionCreateResource": "Bron maken",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Stel Resource Pincode in", "actionSetResourcePincode": "Stel Resource Pincode in",
"actionSetResourceEmailWhitelist": "Stel Resource e-mail whitelist in", "actionSetResourceEmailWhitelist": "Stel Resource e-mail whitelist in",
"actionGetResourceEmailWhitelist": "Verkrijg Resource E-mail Whitelist", "actionGetResourceEmailWhitelist": "Verkrijg Resource E-mail Whitelist",
"actionGetResourcePolicy": "Haal Bronbeleid op",
"actionUpdateResourcePolicy": "Werk Bronbeleid bij",
"actionSetResourcePolicyUsers": "Stel gebruikers van bronbeleid in",
"actionSetResourcePolicyRoles": "Stel rollen van bronbeleid in",
"actionSetResourcePolicyPassword": "Stel wachtwoord van bronbeleid in",
"actionSetResourcePolicyPincode": "Stel pincode van bronbeleid in",
"actionSetResourcePolicyHeaderAuth": "Stel hoofdveraantwoorden van bronbeleid in",
"actionSetResourcePolicyWhitelist": "Stel e-mail whitelist van bronbeleid in",
"actionSetResourcePolicyRules": "Stel regels van bronbeleid in",
"actionCreateTarget": "Doelwit aanmaken", "actionCreateTarget": "Doelwit aanmaken",
"actionDeleteTarget": "Verwijder doel", "actionDeleteTarget": "Verwijder doel",
"actionGetTarget": "Verkrijg Doel", "actionGetTarget": "Verkrijg Doel",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Genereer Toegangstoken", "actionGenerateAccessToken": "Genereer Toegangstoken",
"actionDeleteAccessToken": "Verwijder toegangstoken", "actionDeleteAccessToken": "Verwijder toegangstoken",
"actionListAccessTokens": "Lijst toegangstokens", "actionListAccessTokens": "Lijst toegangstokens",
"actionCreateResourceSessionToken": "Maak Resource Sessie Token",
"actionCreateResourceRule": "Bronregel aanmaken", "actionCreateResourceRule": "Bronregel aanmaken",
"actionDeleteResourceRule": "Verwijder Resource Regel", "actionDeleteResourceRule": "Verwijder Resource Regel",
"actionListResourceRules": "Bron regels weergeven", "actionListResourceRules": "Bron regels weergeven",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Toon uitnodigingen", "actionListInvitations": "Toon uitnodigingen",
"actionExportLogs": "Logboeken exporteren", "actionExportLogs": "Logboeken exporteren",
"actionViewLogs": "Logboeken bekijken", "actionViewLogs": "Logboeken bekijken",
"actionCreateSiteProvisioningKey": "Een sitevoorzie-ningssleutel aanmaken",
"actionListSiteProvisioningKeys": "Sitevoorzie-ningssleutels weergeven",
"actionUpdateSiteProvisioningKey": "Sitevoorzie-ningssleutel bijwerken",
"actionDeleteSiteProvisioningKey": "Sitevoorzie-ningssleutel verwijderen",
"noneSelected": "Niet geselecteerd", "noneSelected": "Niet geselecteerd",
"orgNotFound2": "Geen organisaties gevonden.", "orgNotFound2": "Geen organisaties gevonden.",
"search": "Zoeken…", "search": "Zoeken…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Laatst gebruikt",
"otpAuthBack": "Terug naar wachtwoord", "otpAuthBack": "Terug naar wachtwoord",
"navbar": "Navigatiemenu", "navbar": "Navigatiemenu",
"navbarDescription": "Hoofd navigatie menu voor de applicatie", "navbarDescription": "Hoofd navigatie menu voor de applicatie",
"navbarDocsLink": "Documentatie", "navbarDocsLink": "Documentatie",
"commandPaletteTitle": "Commandopalet",
"commandPaletteDescription": "Zoek naar pagina's, organisaties, bronnen en acties",
"commandPaletteSearchPlaceholder": "Zoek pagina's, bronnen, acties...",
"commandPaletteNoResults": "Geen resultaten gevonden.",
"commandPaletteSearching": "Zoeken...",
"commandPaletteNavigation": "Navigatie",
"commandPaletteOrganizations": "Organisaties",
"commandPaletteSites": "Sites",
"commandPaletteResources": "Bronnen",
"commandPaletteUsers": "Gebruikers",
"commandPaletteClients": "Machine klanten",
"commandPaletteActions": "Acties",
"commandPaletteCreateSite": "Site Aanmaken",
"commandPaletteCreateProxyResource": "Maak Openbare Bron",
"commandPaletteCreatePrivateResource": "Maak Privébron",
"commandPaletteCreateUser": "Gebruiker aanmaken",
"commandPaletteCreateApiKey": "API-sleutel aanmaken",
"commandPaletteCreateMachineClient": "Machineclient aanmaken",
"commandPaletteCreateAlertRule": "Alarmregel aanmaken",
"commandPaletteCreateIdentityProvider": "Identiteitsprovider aanmaken",
"commandPaletteToggleTheme": "Thema wisselen",
"commandPaletteChooseOrganization": "Kies Organisatie",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Kan 2FA niet inschakelen", "otpErrorEnable": "Kan 2FA niet inschakelen",
"otpErrorEnableDescription": "Er is een fout opgetreden tijdens het inschakelen van 2FA", "otpErrorEnableDescription": "Er is een fout opgetreden tijdens het inschakelen van 2FA",
"otpSetupCheckCode": "Voer een 6-cijferige code in", "otpSetupCheckCode": "Voer een 6-cijferige code in",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Beheer", "sidebarManagement": "Beheer",
"sidebarBillingAndLicenses": "Facturatie & Licenties", "sidebarBillingAndLicenses": "Facturatie & Licenties",
"sidebarLogsAnalytics": "Analyses", "sidebarLogsAnalytics": "Analyses",
"commandSites": "Sites",
"commandActionModeInfo": "Typ \">\" Om Actiemodus Te Openen",
"commandResources": "Bronnen",
"commandProxyResources": "Openbare Bronnen",
"commandClientResources": "Privébronnen",
"commandClients": "Clienten",
"commandUserDevices": "Apparaatgebruikers",
"commandMachineClients": "Machine klanten",
"commandDomains": "Domeinen",
"commandRemoteExitNodes": "Externe Knooppunten",
"commandTeam": "Team",
"commandUsers": "Gebruikers",
"commandRoles": "Rollen",
"commandInvitations": "Uitnodigingen",
"commandPolicies": "Gedeeld Beleid",
"commandResourcePolicies": "Openbare Bronnenbeleid",
"commandIdentityProviders": "Identiteitsproviders",
"commandApprovals": "Goedkeuring Aanvragen",
"commandShareableLinks": "Deelbare Links",
"commandOrganization": "Organisatie",
"commandLogsAndAnalytics": "Logboeken & Analytics",
"commandLogsAnalytics": "Analyse",
"commandLogsRequest": "HTTP-aanvraaglogboeken",
"commandLogsAccess": "Toegang tot logboek",
"commandLogsAction": "Actie Logboeken",
"commandLogsConnection": "Connectie Logs",
"commandLogsStreaming": "Streamen",
"commandManagement": "Beheren",
"commandAlerting": "Waarschuwingen",
"commandProvisioning": "Inrichting",
"commandBluePrints": "Blauwdrukken",
"commandApiKeys": "API sleutels",
"commandBillingAndLicenses": "Facturering & Licenties",
"commandBilling": "Facturering",
"commandEnterpriseLicenses": "Licentie",
"commandSettings": "Instellingen",
"commandLauncher": "Startprogramma",
"commandResourceLauncher": "Bron Startprogramma",
"commandSearchResults": "Zoekresultaten",
"alertingTitle": "Waarschuwingen", "alertingTitle": "Waarschuwingen",
"alertingDescription": "Definieer bronnen, triggers en acties voor meldingen", "alertingDescription": "Definieer bronnen, triggers en acties voor meldingen",
"alertingRules": "Waarschuwingsregels", "alertingRules": "Waarschuwingsregels",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Subdomein: {subdomain}", "domainPickerSubdomain": "Subdomein: {subdomain}",
"domainPickerNamespace": "Naamruimte: {namespace}", "domainPickerNamespace": "Naamruimte: {namespace}",
"domainPickerShowMore": "Meer weergeven", "domainPickerShowMore": "Meer weergeven",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Selecteer Regio", "regionSelectorTitle": "Selecteer Regio",
"domainPickerRemoteExitNodeWarning": "Opgegeven domeinen worden niet ondersteund wanneer websites verbinding maken met externe sluitnodes. Gebruik in plaats daarvan een aangepast domein. Om bronnen beschikbaar te maken op externe nodes.", "domainPickerRemoteExitNodeWarning": "Opgegeven domeinen worden niet ondersteund wanneer websites verbinding maken met externe sluitnodes. Gebruik in plaats daarvan een aangepast domein. Om bronnen beschikbaar te maken op externe nodes.",
"regionSelectorInfo": "Het selecteren van een regio helpt ons om betere prestaties te leveren voor uw locatie. U hoeft niet in dezelfde regio als uw server te zijn.", "regionSelectorInfo": "Het selecteren van een regio helpt ons om betere prestaties te leveren voor uw locatie. U hoeft niet in dezelfde regio als uw server te zijn.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domeinen", "billingDomains": "Domeinen",
"billingOrganizations": "Ordenen", "billingOrganizations": "Ordenen",
"billingRemoteExitNodes": "Externe knooppunten", "billingRemoteExitNodes": "Externe knooppunten",
"billingPublicResources": "Openbare Bronnen",
"billingPrivateResources": "Privébronnen",
"billingMachineClients": "Machine klanten",
"billingNoLimitConfigured": "Geen limiet ingesteld", "billingNoLimitConfigured": "Geen limiet ingesteld",
"billingEstimatedPeriod": "Geschatte Facturatie Periode", "billingEstimatedPeriod": "Geschatte Facturatie Periode",
"billingIncludedUsage": "Opgenomen Gebruik", "billingIncludedUsage": "Opgenomen Gebruik",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Hoeveel gebruikers je kan gebruiken", "billingUsersInfo": "Hoeveel gebruikers je kan gebruiken",
"billingDomainInfo": "Hoeveel domeinen je kunt gebruiken", "billingDomainInfo": "Hoeveel domeinen je kunt gebruiken",
"billingRemoteExitNodesInfo": "Hoeveel externe nodes je kunt gebruiken", "billingRemoteExitNodesInfo": "Hoeveel externe nodes je kunt gebruiken",
"billingPublicResourcesInfo": "Hoeveel openbare bronnen u kunt gebruiken",
"billingPrivateResourcesInfo": "Hoeveel privébronnen u kunt gebruiken",
"billingMachineClientsInfo": "Hoeveel machineclients u kunt gebruiken",
"billingLicenseKeys": "Licentie Sleutels", "billingLicenseKeys": "Licentie Sleutels",
"billingLicenseKeysDescription": "Beheer uw licentiesleutelabonnementen", "billingLicenseKeysDescription": "Beheer uw licentiesleutelabonnementen",
"billingLicenseSubscription": "Licentie abonnement", "billingLicenseSubscription": "Licentie abonnement",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Subnet", "subnetPlaceholder": "Subnet",
"addressDescription": "Het interne adres van de klant. Moet binnen het subnetwerk van de organisatie vallen.", "addressDescription": "Het interne adres van de klant. Moet binnen het subnetwerk van de organisatie vallen.",
"selectSites": "Selecteer sites", "selectSites": "Selecteer sites",
"selectLabels": "Selecteer labels",
"sitesDescription": "De client heeft connectiviteit met de geselecteerde sites", "sitesDescription": "De client heeft connectiviteit met de geselecteerde sites",
"clientInstallOlm": "Installeer Olm", "clientInstallOlm": "Installeer Olm",
"clientInstallOlmDescription": "Laat Olm draaien op uw systeem", "clientInstallOlmDescription": "Laat Olm draaien op uw systeem",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Openbaar", "resourcesTableProxyResources": "Openbaar",
"resourcesTableClientResources": "Privé", "resourcesTableClientResources": "Privé",
"resourcesTableNoProxyResourcesFound": "Geen proxybronnen gevonden.", "resourcesTableNoProxyResourcesFound": "Geen proxybronnen gevonden.",
"resourcesTableNoInternalResourcesFound": "Geen interne bronnen gevonden.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Bestemming", "resourcesTableDestination": "Bestemming",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Alias adres", "resourcesTableAliasAddress": "Alias adres",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Annuleren", "editInternalResourceDialogCancel": "Annuleren",
"editInternalResourceDialogSaveResource": "Sla bron op", "editInternalResourceDialogSaveResource": "Sla bron op",
"editInternalResourceDialogSuccess": "Succes", "editInternalResourceDialogSuccess": "Succes",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Interne bron succesvol bijgewerkt", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Fout", "editInternalResourceDialogError": "Fout",
"editInternalResourceDialogFailedToUpdateInternalResource": "Het bijwerken van de interne bron is mislukt", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Naam is verplicht", "editInternalResourceDialogNameRequired": "Naam is verplicht",
"editInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens", "editInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens",
"editInternalResourceDialogProxyPortMin": "Proxy poort moet minstens 1 zijn", "editInternalResourceDialogProxyPortMin": "Proxy poort moet minstens 1 zijn",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Een optionele interne DNS-alias voor dit document.", "editInternalResourceDialogAliasDescription": "Een optionele interne DNS-alias voor dit document.",
"createInternalResourceDialogNoSitesAvailable": "Geen sites beschikbaar", "createInternalResourceDialogNoSitesAvailable": "Geen sites beschikbaar",
"createInternalResourceDialogNoSitesAvailableDescription": "U moet ten minste één Newt-site hebben met een geconfigureerd subnet om interne bronnen aan te maken.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Sluiten", "createInternalResourceDialogClose": "Sluiten",
"createInternalResourceDialogCreateClientResource": "Privé bron maken", "createInternalResourceDialogCreateClientResource": "Privé bron maken",
"createInternalResourceDialogCreateClientResourceDescription": "Maak een nieuwe bron aan die alleen toegankelijk is voor klanten die verbonden zijn met de organisatie", "createInternalResourceDialogCreateClientResourceDescription": "Maak een nieuwe bron aan die alleen toegankelijk is voor klanten die verbonden zijn met de organisatie",
"privateResourceGeneralDescription": "Configureer de naam, identificatie en andere algemene resource-instellingen.",
"privateResourceCreatePageSeeAll": "Bekijk Alle Privébronnen",
"privateResourceAllowIcmpPing": "Sta ICMP Ping toe",
"privateResourceNetworkAccess": "Netwerktoegang",
"privateResourceNetworkAccessDescription": "Beheer TCP/UDP poorttoegang en of ICMP-ping is toegestaan voor deze bron.",
"hostSettings": "Hostinstellingen",
"cidrSettings": "CIDR-instellingen",
"createInternalResourceDialogResourceProperties": "Bron-eigenschappen", "createInternalResourceDialogResourceProperties": "Bron-eigenschappen",
"createInternalResourceDialogName": "Naam", "createInternalResourceDialogName": "Naam",
"createInternalResourceDialogSite": "Site", "createInternalResourceDialogSite": "Site",
"selectSite": "Selecteer site...", "selectSite": "Selecteer site...",
"multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}", "multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}",
"labelsSelectorLabelsCount": "{count, plural, one {# label} other {# labels}}",
"noSitesFound": "Geen sites gevonden.", "noSitesFound": "Geen sites gevonden.",
"createInternalResourceDialogProtocol": "Protocol", "createInternalResourceDialogProtocol": "Protocol",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Annuleren", "createInternalResourceDialogCancel": "Annuleren",
"createInternalResourceDialogCreateResource": "Bron aanmaken", "createInternalResourceDialogCreateResource": "Bron aanmaken",
"createInternalResourceDialogSuccess": "Succes", "createInternalResourceDialogSuccess": "Succes",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Interne bron succesvol aangemaakt", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Fout", "createInternalResourceDialogError": "Fout",
"createInternalResourceDialogFailedToCreateInternalResource": "Het aanmaken van de interne bron is mislukt", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Naam is verplicht", "createInternalResourceDialogNameRequired": "Naam is verplicht",
"createInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens", "createInternalResourceDialogNameMaxLength": "Naam mag niet langer zijn dan 255 tekens",
"createInternalResourceDialogPleaseSelectSite": "Selecteer alstublieft een site", "createInternalResourceDialogPleaseSelectSite": "Selecteer alstublieft een site",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "Het CIDR-bereik van het document op het netwerk van de site.", "createInternalResourceDialogDestinationCidrDescription": "Het CIDR-bereik van het document op het netwerk van de site.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Een optionele interne DNS-alias voor dit document.", "createInternalResourceDialogAliasDescription": "Een optionele interne DNS-alias voor dit document.",
"internalResourceAliasLocalWarning": "Aliassen die eindigen op .local kunnen resolutieproblemen veroorzaken vanwege mDNS op sommige netwerken.",
"internalResourceDownstreamSchemeRequired": "Schema is vereist voor HTTP-bronnen", "internalResourceDownstreamSchemeRequired": "Schema is vereist voor HTTP-bronnen",
"internalResourceHttpPortRequired": "Bestemmingspoort is vereist voor HTTP-bronnen", "internalResourceHttpPortRequired": "Bestemmingspoort is vereist voor HTTP-bronnen",
"siteConfiguration": "Configuratie", "siteConfiguration": "Configuratie",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Externe knooppunten", "sidebarRemoteExitNodes": "Externe knooppunten",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Geheim", "remoteExitNodeSecretKey": "Geheim",
"remoteExitNodeNetworkingTitle": "Netwerkinstellingen",
"remoteExitNodeNetworkingDescription": "Configureer hoe dit externe exit-knooppunt verkeer routeert en welke sites de voorkeur hebben om er doorheen te verbinden. Geavanceerde functies te gebruiken met backhaul-netwerkconfiguraties.",
"remoteExitNodeNetworkingSave": "Instellingen opslaan",
"remoteExitNodeNetworkingSaveSuccessTitle": "Netwerkinstellingen opgeslagen",
"remoteExitNodeNetworkingSaveSuccessDescription": "Netwerkinstellingen zijn succesvol bijgewerkt.",
"remoteExitNodeNetworkingSaveError": "Kon netwerkinstellingen niet opslaan",
"remoteExitNodeNetworkingSubnetsTitle": "Externe Subnets",
"remoteExitNodeNetworkingSubnetsDescription": "Definieer de CIDR-bereiken waarnaar dit externe exit-knooppunt verkeer zal routeren. Voer een geldige CIDR in (bijv. <code>10.0.0.0/8</code>) en druk op Enter om toe te voegen.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Voeg een CIDR-bereik toe (bijv. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Kon subnets niet laden",
"remoteExitNodeNetworkingLabelsTitle": "Voorkeurslabels",
"remoteExitNodeNetworkingLabelsDescription": "Sites met deze labels worden verplicht om verbinding te maken via dit externe exit-knooppunt.",
"remoteExitNodeNetworkingLabelsButtonText": "Selecteer labels...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Labels zoeken...",
"remoteExitNodeNetworkingLabelsLoadError": "Kon labels niet laden",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Externe knoop aanmaken", "title": "Externe knoop aanmaken",
"description": "Maak een nieuwe zelf-gehoste externe relais- en proxyservermodule", "description": "Maak een nieuwe zelf-gehoste externe relais- en proxyservermodule",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Er zijn geen knooppunten beschikbaar voor deze organisatie. Maak eerst een knooppunt aan om lokale sites te gebruiken.", "noRemoteExitNodesAvailableDescription": "Er zijn geen knooppunten beschikbaar voor deze organisatie. Maak eerst een knooppunt aan om lokale sites te gebruiken.",
"exitNode": "Exit Node", "exitNode": "Exit Node",
"country": "Land", "country": "Land",
"countryIsNot": "Land Is Niet",
"rulesMatchCountry": "Momenteel gebaseerd op bron IP", "rulesMatchCountry": "Momenteel gebaseerd op bron IP",
"region": "Regio", "region": "Regio",
"selectRegion": "Selecteer regio", "selectRegion": "Selecteer regio",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC provider", "idpGoogleDescription": "Google OAuth2/OIDC provider",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Subnet", "subnet": "Subnet",
"utilitySubnet": "Hulpmiddel Subnet",
"subnetDescription": "Het subnet van de netwerkconfiguratie van deze organisatie.", "subnetDescription": "Het subnet van de netwerkconfiguratie van deze organisatie.",
"customDomain": "Aangepast domein", "customDomain": "Aangepast domein",
"authPage": "Authenticatiepagina's", "authPage": "Authenticatiepagina's",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Tweestapsverificatie instellen is vereist. Log opnieuw in via {dashboardUrl}/auth/login voltooide deze stap. Kom daarna hier terug.", "twoFactorSetupRequired": "Tweestapsverificatie instellen is vereist. Log opnieuw in via {dashboardUrl}/auth/login voltooide deze stap. Kom daarna hier terug.",
"additionalSecurityRequired": "Extra beveiliging vereist", "additionalSecurityRequired": "Extra beveiliging vereist",
"organizationRequiresAdditionalSteps": "Deze organisatie vereist extra beveiligingsstappen voordat u toegang hebt tot de bronnen.", "organizationRequiresAdditionalSteps": "Deze organisatie vereist extra beveiligingsstappen voordat u toegang hebt tot de bronnen.",
"sessionExpired": "Sessie Verlopen",
"sessionExpiredReauthRequired": "Uw sessie is verlopen volgens het beveiligingsbeleid van uw organisatie. Verifieer alstublieft opnieuw om door te gaan.",
"reauthenticate": "Opnieuw verifiëren",
"completeTheseSteps": "Voltooi deze stappen", "completeTheseSteps": "Voltooi deze stappen",
"enableTwoFactorAuthentication": "Tweestapsverificatie inschakelen", "enableTwoFactorAuthentication": "Tweestapsverificatie inschakelen",
"completeSecuritySteps": "Voltooi beveiligingsstappen", "completeSecuritySteps": "Voltooi beveiligingsstappen",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Bron adres", "sourceAddress": "Bron adres",
"destinationAddress": "Adres bestemming", "destinationAddress": "Adres bestemming",
"duration": "Duur", "duration": "Duur",
"licenseRequiredToUse": "Een <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> licentie of <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is vereist om deze functie te gebruiken. <bookADemoLink>Boek een demo of POC trial</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "De <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is vereist om deze functie te gebruiken. Deze functie is ook beschikbaar in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Boek een demo of POC trial</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Certificaat Resolver", "certResolver": "Certificaat Resolver",
"certResolverDescription": "Selecteer de certificaat resolver die moet worden gebruikt voor deze resource.", "certResolverDescription": "Selecteer de certificaat resolver die moet worden gebruikt voor deze resource.",
"selectCertResolver": "Certificaat Resolver selecteren", "selectCertResolver": "Certificaat Resolver selecteren",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Organisatie of domein ID ontbreekt", "orgOrDomainIdMissing": "Organisatie of domein ID ontbreekt",
"loadingDNSRecords": "DNS-records laden...", "loadingDNSRecords": "DNS-records laden...",
"olmUpdateAvailableInfo": "Er is een bijgewerkte versie van Olm beschikbaar. Update alstublieft naar de nieuwste versie voor de beste ervaring.", "olmUpdateAvailableInfo": "Er is een bijgewerkte versie van Olm beschikbaar. Update alstublieft naar de nieuwste versie voor de beste ervaring.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Er is een bijgewerkte versie beschikbaar. Update naar de nieuwste versie voor de beste ervaring.",
"client": "Klant", "client": "Klant",
"proxyProtocol": "Proxy Protocol Instellingen", "proxyProtocol": "Proxy Protocol Instellingen",
"proxyProtocolDescription": "Proxyprotocol configureren om de IP-adressen van de client voor TCP-diensten te bewaren.", "proxyProtocolDescription": "Proxyprotocol configureren om de IP-adressen van de client voor TCP-diensten te bewaren.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Gebruikers toevoegen", "editInternalResourceDialogAddUsers": "Gebruikers toevoegen",
"editInternalResourceDialogAddClients": "Clienten toevoegen", "editInternalResourceDialogAddClients": "Clienten toevoegen",
"editInternalResourceDialogDestinationLabel": "Bestemming", "editInternalResourceDialogDestinationLabel": "Bestemming",
"editInternalResourceDialogDestinationDescription": "Specificeer het bestemmingsadres voor de interne bron. Dit kan een hostnaam, IP-adres of CIDR-bereik zijn, afhankelijk van de geselecteerde modus. Stel optioneel een interne DNS-alias in voor eenvoudigere identificatie.", "editInternalResourceDialogDestinationDescription": "Configureer hoe klanten toegang krijgen tot deze resource.",
"internalResourceFormMultiSiteRoutingHelp": "Selecteren van meerdere sites maakt veerkrachtige routing en failover mogelijk voor hoge beschikbaarheid.", "internalResourceFormMultiSiteRoutingHelp": "Selecteren van meerdere sites maakt veerkrachtige routing en failover mogelijk voor hoge beschikbaarheid.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Meer informatie", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Meer informatie",
"editInternalResourceDialogPortRestrictionsDescription": "Beperk toegang tot specifieke TCP/UDP-poorten of sta alle poorten toe/blokkeer.", "editInternalResourceDialogPortRestrictionsDescription": "Beperk toegang tot specifieke TCP/UDP-poorten of sta alle poorten toe/blokkeer.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "E-mail whitelist", "memberPortalEmailWhitelist": "E-mail whitelist",
"memberPortalResourceDisabled": "Bron Uitgeschakeld", "memberPortalResourceDisabled": "Bron Uitgeschakeld",
"memberPortalShowingResources": "Toont {start}-{end} van {total} bronnen", "memberPortalShowingResources": "Toont {start}-{end} van {total} bronnen",
"resourceLauncherTitle": "Bron Launcher",
"resourceSidebarLauncherTitle": "Startprogramma",
"resourceLauncherDescription": "Bekijk alle beschikbare bronnen en start ze vanuit één centraal punt",
"resourceLauncherSearchPlaceholder": "Zoek naar bronnen...",
"resourceLauncherDefaultView": "Standaard",
"resourceLauncherSaveView": "Weergave Opslaan",
"resourceLauncherSaveToCurrentView": "Opslaan naar huidige weergave",
"resourceLauncherSaveDefaultPersonal": "Sla voor mij op",
"resourceLauncherResetView": "Weergave Herstellen",
"resourceLauncherResetSystemDefault": "Reset naar standaardinstelling van het systeem",
"resourceLauncherSystemDefaultRestored": "Systeemstandaard hersteld",
"resourceLauncherSystemDefaultRestoredDescription": "De standaardweergave is teruggezet naar de oorspronkelijke instellingen.",
"resourceLauncherSaveAsNewView": "Opslaan als Nieuwe Weergave",
"resourceLauncherSaveAsNewViewDescription": "Geef deze weergave een naam om je huidige filters en indeling op te slaan.",
"resourceLauncherSaveForEveryone": "Opslaan voor Iedereen",
"resourceLauncherSaveForEveryoneDescription": "Deel deze weergave met alle organisatieleden. Als dit niet is aangevinkt, is de weergave alleen zichtbaar voor jou.",
"resourceLauncherMakePersonal": "Persoonlijk Maken",
"resourceLauncherFilter": "Filter",
"resourceLauncherFilterWithCount": "Filter, {count} toegepast",
"resourceLauncherSort": "Sorteren",
"resourceLauncherSortAscending": "Oplopend sorteren",
"resourceLauncherSortDescending": "Aflopend sorteren",
"resourceLauncherSettings": "Instellingen",
"resourceLauncherGroupBy": "Groep Op",
"resourceLauncherGroupBySite": "Site",
"resourceLauncherGroupByLabel": "Label",
"resourceLauncherGroupByNone": "Geen",
"resourceLauncherLayout": "Lay-out",
"resourceLauncherLayoutGrid": "Raster",
"resourceLauncherLayoutList": "Lijst",
"resourceLauncherShowLabels": "Labels Weergeven",
"resourceLauncherShowSiteTags": "Site Tags Weergeven",
"resourceLauncherShowRecents": "Recente Weergeven",
"resourceLauncherDeleteView": "Weergave Verwijderen",
"resourceLauncherDeleteViewTitle": "Weergave verwijderen",
"resourceLauncherDeleteViewQuestion": "Weet u zeker dat u deze launcher-weergave wilt verwijderen?",
"resourceLauncherDeleteViewConfirm": "Weergave verwijderen",
"resourceLauncherViewAsAdmin": "Bekijk als Admin",
"resourceLauncherResourceDetailsDescription": "Verbindingsinformatie en -status voor deze bron.",
"resourceLauncherResourceDetails": "Brongegevens",
"resourceLauncherAuthMethodsDescription": "Authenticatiemethoden ingeschakeld voor deze bron.",
"resourceLauncherPrivateClientRequired": "Maak verbinding met een client op uw apparaat om deze bron privé te benaderen.",
"resourceLauncherPrivateClientRequiredTitle": "Client Verbinding Vereist",
"resourceLauncherDownloadClient": "Client downloaden",
"resourceLauncherFailedToLoadDetails": "Kon brongegevens niet laden. U heeft mogelijk geen toegang meer tot deze bron.",
"resourceLauncherNoPortRestrictions": "Geen poortbeperkingen",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Geen label",
"resourceLauncherNoSite": "Geen Site",
"resourceLauncherNoResourcesInGroup": "Geen bronnen in deze groep",
"resourceLauncherEmptyStateTitle": "Geen Bronnen Beschikbaar",
"resourceLauncherEmptyStateDescription": "Je hebt nog geen toegang tot bronnen. Neem contact op met je beheerder om toegang aan te vragen.",
"resourceLauncherEmptyStateNoResultsTitle": "Geen Bronnen Gevonden",
"resourceLauncherEmptyStateNoResultsDescription": "Geen bronnen komen overeen met je huidige zoekopdracht of filters. Probeer ze aan te passen om te vinden wat je zoekt.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Geen bronnen komen overeen met \"{query}\". Probeer je zoekopdracht aan te passen of filters te wissen om alle bronnen te zien.",
"resourceLauncherSearchFirstTitle": "Zoek of Filter om te bladeren",
"resourceLauncherSearchFirstDescription": "U heeft toegang tot veel bronnen. Gebruik zoeken of filteren op site of label om te vinden wat u nodig heeft.",
"resourceLauncherSiteGroupingDisabled": "Sitegroeping is niet beschikbaar op deze schaal. Filter op site om een kleiner aantal te groeperen.",
"resourceLauncherLabelGroupingDisabled": "Labelgroepering is niet beschikbaar op deze schaal.",
"resourceLauncherCompactModeHint": "Een vereenvoudigde lijst weergegeven voor sneller bladeren. Gebruik zoeken of filters om resultaten te verfijnen.",
"resourceLauncherCompactGroupingHint": "Toepas site- of labelfilters om groepering mogelijk te maken.",
"resourceLauncherCopiedToClipboard": "Gekopieerd naar klembord",
"resourceLauncherCopiedAccessDescription": "Toegang tot bron is gekopieerd naar je klembord.",
"resourceLauncherViewNamePlaceholder": "Weergavenaam",
"resourceLauncherViewNameLabel": "Weergavenaam",
"resourceLauncherViewSaved": "Weergave opgeslagen",
"resourceLauncherViewSavedDescription": "Je launcher-weergave is opgeslagen.",
"resourceLauncherViewSaveFailed": "Kon weergave niet opslaan",
"resourceLauncherViewSaveFailedDescription": "Kon de launcher-weergave niet opslaan. Probeer het opnieuw.",
"resourceLauncherViewDeleted": "Weergave verwijderd",
"resourceLauncherViewDeletedDescription": "De launcher-weergave is verwijderd.",
"resourceLauncherViewDeleteFailed": "Kon weergave niet verwijderen",
"resourceLauncherViewDeleteFailedDescription": "Kon de launcher-weergave niet verwijderen. Probeer het opnieuw.",
"memberPortalPrevious": "Vorige", "memberPortalPrevious": "Vorige",
"memberPortalNext": "Volgende", "memberPortalNext": "Volgende",
"httpSettings": "HTTP-instellingen", "httpSettings": "HTTP-instellingen",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "Privésleutel is vereist", "sshPrivateKeyRequired": "Privésleutel is vereist",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Voer uw VNC-wachtwoord in om verbinding te maken", "vncSignInDescription": "Voer uw VNC-referenties in om verbinding te maken",
"vncUsernameOptional": "Gebruikersnaam (optioneel)",
"vncPasswordOptional": "Wachtwoord (optioneel)", "vncPasswordOptional": "Wachtwoord (optioneel)",
"vncNoResourceTarget": "Geen bron doelwit beschikbaar", "vncNoResourceTarget": "Geen bron doelwit beschikbaar",
"vncFailedToLoadNovnc": "Laden van noVNC mislukt", "vncFailedToLoadNovnc": "Laden van noVNC mislukt",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Upload mislukt", "rdpUploadFailed": "Upload mislukt",
"rdpUnicodeKeyboardMode": "Unicode toetsenbordmodus", "rdpUnicodeKeyboardMode": "Unicode toetsenbordmodus",
"sessionToolbarShow": "Toon werkbalk", "sessionToolbarShow": "Toon werkbalk",
"sessionToolbarHide": "Verberg werkbalk" "sessionToolbarHide": "Verberg werkbalk",
"actionUpdateSiteApprovals": "Sitegoedkeuringen bijwerken"
} }
+247 -19
View File
@@ -66,9 +66,15 @@
"local": "Lokalny", "local": "Lokalny",
"edit": "Edytuj", "edit": "Edytuj",
"siteConfirmDelete": "Potwierdź usunięcie witryny", "siteConfirmDelete": "Potwierdź usunięcie witryny",
"siteConfirmDeleteAndResources": "Potwierdź usunięcie witryny i zasobów",
"siteDelete": "Usuń witrynę", "siteDelete": "Usuń witrynę",
"siteDeleteAndResources": "Usuń witrynę i zasoby",
"siteMessageRemove": "Po usunięciu witryna nie będzie już dostępna. Wszystkie cele związane z witryną zostaną również usunięte.", "siteMessageRemove": "Po usunięciu witryna nie będzie już dostępna. Wszystkie cele związane z witryną zostaną również usunięte.",
"siteMessageRemoveAndResources": "To spowoduje trwałe usunięcie wszystkich zasobów publicznych i prywatnych powiązanych z tą witryną, nawet jeśli zasób jest także powiązany z innymi witrynami.",
"siteQuestionRemove": "Czy na pewno chcesz usunąć witrynę z organizacji?", "siteQuestionRemove": "Czy na pewno chcesz usunąć witrynę z organizacji?",
"siteQuestionRemoveAndResources": "Czy na pewno chcesz usunąć tę witrynę i wszystkie powiązane zasoby?",
"sitesTableDeleteSite": "Usuń witrynę",
"sitesTableDeleteSiteAndResources": "Usuń witrynę i zasoby",
"siteManageSites": "Zarządzaj stronami", "siteManageSites": "Zarządzaj stronami",
"siteDescription": "Tworzenie stron i zarządzanie nimi, aby włączyć połączenia z prywatnymi sieciami", "siteDescription": "Tworzenie stron i zarządzanie nimi, aby włączyć połączenia z prywatnymi sieciami",
"sitesBannerTitle": "Połącz dowolną sieć", "sitesBannerTitle": "Połącz dowolną sieć",
@@ -117,6 +123,16 @@
"siteUpdated": "Strona zaktualizowana", "siteUpdated": "Strona zaktualizowana",
"siteUpdatedDescription": "Strona została zaktualizowana.", "siteUpdatedDescription": "Strona została zaktualizowana.",
"siteGeneralDescription": "Skonfiguruj ustawienia ogólne dla tej witryny", "siteGeneralDescription": "Skonfiguruj ustawienia ogólne dla tej witryny",
"siteRestartTitle": "Restartuj Stronę",
"siteRestartDescription": "Uruchom ponownie tunel WireGuard dla tej strony. Spowoduje to tymczasowe przerwanie łączności.",
"siteRestartBody": "Użyj tego, jeśli tunel strony nie działa prawidłowo i chcesz wymusić ponowne połączenie bez ponownego uruchamiania hosta.",
"siteRestartButton": "Restartuj Stronę",
"siteRestartDialogMessage": "Czy na pewno chcesz uruchomić ponownie tunel WireGuard dla <b>{name}</b>? Strona tymczasowo straci łączność.",
"siteRestartWarning": "Strona tymczasowo rozłączy się podczas ponownego uruchamiania tunelu.",
"siteRestarted": "Strona zrestartowana",
"siteRestartedDescription": "Tunel WireGuard został ponownie uruchomiony.",
"siteErrorRestart": "Nie udało się zrestartować strony",
"siteErrorRestartDescription": "Wystąpił błąd podczas ponownego uruchamiania strony.",
"siteSettingDescription": "Skonfiguruj ustawienia na stronie", "siteSettingDescription": "Skonfiguruj ustawienia na stronie",
"siteResourcesTab": "Zasoby", "siteResourcesTab": "Zasoby",
"siteResourcesNoneOnSite": "Ta strona nie ma jeszcze żadnych zasobów publicznych ani prywatnych.", "siteResourcesNoneOnSite": "Ta strona nie ma jeszcze żadnych zasobów publicznych ani prywatnych.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Potwierdź usunięcie linku do udostępnienia", "shareDeleteConfirm": "Potwierdź usunięcie linku do udostępnienia",
"shareQuestionRemove": "Czy na pewno chcesz usunąć ten link udostępniania?", "shareQuestionRemove": "Czy na pewno chcesz usunąć ten link udostępniania?",
"shareMessageRemove": "Po usunięciu, link przestanie działać i wszyscy korzystający z niego stracą dostęp do zasobu.", "shareMessageRemove": "Po usunięciu, link przestanie działać i wszyscy korzystający z niego stracą dostęp do zasobu.",
"shareTokenDescription": "Token dostępu może być przekazywany na dwa sposoby: jako parametr zapytania lub w nagłówkach żądania. Muszą być przekazywane z klienta na każde żądanie uwierzytelnionego dostępu.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Token dostępu", "accessToken": "Token dostępu",
"usageExamples": "Przykłady użycia", "usageExamples": "Przykłady użycia",
"tokenId": "Identyfikator tokena", "tokenId": "Identyfikator tokena",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Tytuł (opcjonalnie)", "shareTitleOptional": "Tytuł (opcjonalnie)",
"sharePathOptional": "Ścieżka (opcjonalnie)", "sharePathOptional": "Ścieżka (opcjonalnie)",
"sharePathDescription": "Link przekieruje użytkowników do tej ścieżki po uwierzytelnieniu.", "sharePathDescription": "Link przekieruje użytkowników do tej ścieżki po uwierzytelnieniu.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Wygasa za", "expireIn": "Wygasa za",
"neverExpire": "Nigdy nie wygasa", "neverExpire": "Nigdy nie wygasa",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Czas wygaśnięcia to jak długo link będzie mógł być użyty i zapewni dostęp do zasobu. Po tym czasie link nie będzie już działał, a użytkownicy, którzy użyli tego linku, utracą dostęp do zasobu.", "shareExpireDescription": "Czas wygaśnięcia to jak długo link będzie mógł być użyty i zapewni dostęp do zasobu. Po tym czasie link nie będzie już działał, a użytkownicy, którzy użyli tego linku, utracą dostęp do zasobu.",
"shareSeeOnce": "Możesz zobaczyć ten link tylko raz. Pamiętaj, aby go skopiować.", "shareSeeOnce": "Możesz zobaczyć ten link tylko raz. Pamiętaj, aby go skopiować.",
"shareAccessHint": "Każdy z tym linkiem może uzyskać dostęp do zasobu. Podziel się nim ostrożnie.", "shareAccessHint": "Każdy z tym linkiem może uzyskać dostęp do zasobu. Podziel się nim ostrożnie.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Żądania proxy nad surowym TCP/UDP przy użyciu numeru portu. Wymaga stron aby połączyć się ze zdalnym węzłem.", "resourceRawDescriptionCloud": "Żądania proxy nad surowym TCP/UDP przy użyciu numeru portu. Wymaga stron aby połączyć się ze zdalnym węzłem.",
"resourceCreate": "Utwórz zasób", "resourceCreate": "Utwórz zasób",
"resourceCreateDescription": "Wykonaj poniższe kroki, aby utworzyć nowy zasób", "resourceCreateDescription": "Wykonaj poniższe kroki, aby utworzyć nowy zasób",
"resourcePublicCreate": "Utwórz zasób publiczny",
"resourcePublicCreateDescription": "Postępuj zgodnie z poniższymi krokami, aby utworzyć nowy zasób publiczny dostępny przez przeglądarkę internetową",
"resourceCreateGeneralDescription": "Skonfiguruj podstawowe ustawienia zasobu, w tym nazwę i typ", "resourceCreateGeneralDescription": "Skonfiguruj podstawowe ustawienia zasobu, w tym nazwę i typ",
"resourceSeeAll": "Zobacz wszystkie zasoby", "resourceSeeAll": "Zobacz wszystkie zasoby",
"resourceCreateGeneral": "Ogólny", "resourceCreateGeneral": "Ogólny",
@@ -431,8 +455,14 @@
"provisioningManage": "Dostarczanie", "provisioningManage": "Dostarczanie",
"provisioningDescription": "Zarządzaj kluczami rezerwacji i sprawdzaj oczekujące strony oczekujące na zatwierdzenie.", "provisioningDescription": "Zarządzaj kluczami rezerwacji i sprawdzaj oczekujące strony oczekujące na zatwierdzenie.",
"pendingSites": "Witryny oczekujące", "pendingSites": "Witryny oczekujące",
"siteApproveSuccess": "Witryna została pomyślnie zatwierdzona", "siteApproveSuccess": "Witryna i powiązane zasoby zostały zatwierdzone pomyślnie",
"siteApproveError": "Błąd zatwierdzania witryny", "siteApproveError": "Błąd zatwierdzania witryny",
"siteReject": "Odrzuć witrynę",
"siteQuestionReject": "Czy na pewno chcesz odrzucić tę witrynę?",
"siteMessageReject": "Spowoduje to trwałe usunięcie witryny i wszelkich powiązanych, nadal oczekujących zasobów.",
"siteConfirmReject": "Potwierdź odrzucenie witryny",
"siteRejectSuccess": "Witryna została odrzucona pomyślnie",
"siteRejectError": "Błąd podczas odrzucania witryny",
"provisioningKeys": "Klucze Zaopatrzenia", "provisioningKeys": "Klucze Zaopatrzenia",
"searchProvisioningKeys": "Szukaj kluczy zaopatrzenia...", "searchProvisioningKeys": "Szukaj kluczy zaopatrzenia...",
"provisioningKeysAdd": "Wygeneruj klucz zaopatrzenia", "provisioningKeysAdd": "Wygeneruj klucz zaopatrzenia",
@@ -448,7 +478,7 @@
"provisioningKeysSave": "Zapisz klucz zaopatrzenia", "provisioningKeysSave": "Zapisz klucz zaopatrzenia",
"provisioningKeysSaveDescription": "Możesz to zobaczyć tylko raz. Skopiuj je do bezpiecznego miejsca.", "provisioningKeysSaveDescription": "Możesz to zobaczyć tylko raz. Skopiuj je do bezpiecznego miejsca.",
"provisioningKeysErrorCreate": "Błąd podczas tworzenia klucza zaopatrzenia", "provisioningKeysErrorCreate": "Błąd podczas tworzenia klucza zaopatrzenia",
"provisioningKeysList": "Nowy klucz rezerwacji", "provisioningKeysList": "Nowy klucz aprowizacyjny",
"provisioningKeysMaxBatchSize": "Maksymalny rozmiar partii", "provisioningKeysMaxBatchSize": "Maksymalny rozmiar partii",
"provisioningKeysUnlimitedBatchSize": "Nieograniczony rozmiar partii (bez limitu)", "provisioningKeysUnlimitedBatchSize": "Nieograniczony rozmiar partii (bez limitu)",
"provisioningKeysMaxBatchUnlimited": "Nieograniczona", "provisioningKeysMaxBatchUnlimited": "Nieograniczona",
@@ -597,7 +627,8 @@
"idpNameInternal": "Wewnętrzny", "idpNameInternal": "Wewnętrzny",
"emailInvalid": "Nieprawidłowy adres e-mail", "emailInvalid": "Nieprawidłowy adres e-mail",
"inviteValidityDuration": "Proszę wybrać okres ważności", "inviteValidityDuration": "Proszę wybrać okres ważności",
"accessRoleSelectPlease": "Proszę wybrać rolę", "accessRoleSelectPlease": "Użytkownik musi należeć do co najmniej jednej roli.",
"accessRoleRequired": "Wymagana rola",
"removeOwnAdminRoleConfirmTitle": "Usunąć dostęp administratora?", "removeOwnAdminRoleConfirmTitle": "Usunąć dostęp administratora?",
"removeOwnAdminRoleConfirmDescription": "Po zapisaniu nie będziesz już posiadał uprawnień administratora w tej organizacji. Inny administrator może przywrócić dostęp, jeśli to konieczne.", "removeOwnAdminRoleConfirmDescription": "Po zapisaniu nie będziesz już posiadał uprawnień administratora w tej organizacji. Inny administrator może przywrócić dostęp, jeśli to konieczne.",
"removeOwnAdminRoleConfirmButton": "Usuń mój dostęp administratora", "removeOwnAdminRoleConfirmButton": "Usuń mój dostęp administratora",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Podstawowe Uwierzytelnianie Nagłówka", "policyAuthHeaderAuthTitle": "Podstawowe Uwierzytelnianie Nagłówka",
"policyAuthHeaderAuthDescription": "Walidacja niestandardowej nazwy i wartości nagłówka HTTP przy każdym żądaniu", "policyAuthHeaderAuthDescription": "Walidacja niestandardowej nazwy i wartości nagłówka HTTP przy każdym żądaniu",
"policyAuthHeaderAuthSummary": "Skonfigurowany nagłówek", "policyAuthHeaderAuthSummary": "Skonfigurowany nagłówek",
"policyAuthHeaderName": "Nazwa nagłówka", "policyAuthHeaderName": "Nazwa użytkownika",
"policyAuthHeaderValue": "Oczekiwana wartość", "policyAuthHeaderValue": "Hasło",
"policyAuthSetPasscode": "Ustaw hasło dostępu", "policyAuthSetPasscode": "Ustaw hasło dostępu",
"policyAuthSetPincode": "Ustaw kod PIN", "policyAuthSetPincode": "Ustaw kod PIN",
"policyAuthSetEmailWhitelist": "Ustaw białą listę e-mail", "policyAuthSetEmailWhitelist": "Ustaw białą listę e-mail",
@@ -903,7 +934,7 @@
"newtVersion": "Wersja", "newtVersion": "Wersja",
"architecture": "Architektura", "architecture": "Architektura",
"sites": "Witryny", "sites": "Witryny",
"siteWgAnyClients": "Użyj dowolnego klienta WireGuard, aby się połączyć. Będziesz musiał przekierować wewnętrzne zasoby za pomocą adresu IP.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Kompatybilny ze wszystkimi klientami WireGuard", "siteWgCompatibleAllClients": "Kompatybilny ze wszystkimi klientami WireGuard",
"siteWgManualConfigurationRequired": "Wymagana konfiguracja ręczna", "siteWgManualConfigurationRequired": "Wymagana konfiguracja ręczna",
"userErrorNotAdminOrOwner": "Użytkownik nie jest administratorem ani właścicielem", "userErrorNotAdminOrOwner": "Użytkownik nie jest administratorem ani właścicielem",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Utwórz użytkownika Org", "createOrgUser": "Utwórz użytkownika Org",
"actionUpdateOrg": "Aktualizuj organizację", "actionUpdateOrg": "Aktualizuj organizację",
"actionRemoveInvitation": "Usuń zaproszenie", "actionRemoveInvitation": "Usuń zaproszenie",
"actionRemoveUserRole": "Usuń rolę użytkownika",
"actionUpdateUser": "Zaktualizuj użytkownika", "actionUpdateUser": "Zaktualizuj użytkownika",
"actionGetUser": "Pobierz użytkownika", "actionGetUser": "Pobierz użytkownika",
"actionGetOrgUser": "Pobierz użytkownika organizacji", "actionGetOrgUser": "Pobierz użytkownika organizacji",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Zastosuj schemat", "actionApplyBlueprint": "Zastosuj schemat",
"actionListBlueprints": "Lista planów", "actionListBlueprints": "Lista planów",
"actionGetBlueprint": "Pobierz plan", "actionGetBlueprint": "Pobierz plan",
"actionCreateOrgWideLauncherView": "Utwórz Widok Uruchamiacza dla Całej Organizacji",
"setupToken": "Skonfiguruj token", "setupToken": "Skonfiguruj token",
"setupTokenDescription": "Wprowadź token konfiguracji z konsoli serwera.", "setupTokenDescription": "Wprowadź token konfiguracji z konsoli serwera.",
"setupTokenRequired": "Wymagany jest token konfiguracji", "setupTokenRequired": "Wymagany jest token konfiguracji",
"actionUpdateSite": "Aktualizuj witrynę", "actionUpdateSite": "Aktualizuj witrynę",
"actionApproveSite": "Zatwierdź witrynę",
"actionRejectSite": "Odrzuć witrynę",
"actionResetSiteBandwidth": "Zresetuj przepustowość organizacji", "actionResetSiteBandwidth": "Zresetuj przepustowość organizacji",
"actionListSiteRoles": "Lista dozwolonych ról witryny", "actionListSiteRoles": "Lista dozwolonych ról witryny",
"actionCreateResource": "Utwórz zasób", "actionCreateResource": "Utwórz zasób",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Ustaw kod PIN zasobu", "actionSetResourcePincode": "Ustaw kod PIN zasobu",
"actionSetResourceEmailWhitelist": "Ustaw białą listę email zasobu", "actionSetResourceEmailWhitelist": "Ustaw białą listę email zasobu",
"actionGetResourceEmailWhitelist": "Pobierz białą listę email zasobu", "actionGetResourceEmailWhitelist": "Pobierz białą listę email zasobu",
"actionGetResourcePolicy": "Pobierz politykę zasobów",
"actionUpdateResourcePolicy": "Zaktualizuj politykę zasobów",
"actionSetResourcePolicyUsers": "Ustaw użytkowników polityki zasobów",
"actionSetResourcePolicyRoles": "Ustaw role polityki zasobów",
"actionSetResourcePolicyPassword": "Ustaw hasło polityki zasobów",
"actionSetResourcePolicyPincode": "Ustaw kod PIN polityki zasobów",
"actionSetResourcePolicyHeaderAuth": "Ustaw nagłówkowe uwierzytelnianie polityki zasobów",
"actionSetResourcePolicyWhitelist": "Ustaw białą listę email polityki zasobów",
"actionSetResourcePolicyRules": "Ustaw zasady polityki zasobów",
"actionCreateTarget": "Utwórz cel", "actionCreateTarget": "Utwórz cel",
"actionDeleteTarget": "Usuń cel", "actionDeleteTarget": "Usuń cel",
"actionGetTarget": "Pobierz cel", "actionGetTarget": "Pobierz cel",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Wygeneruj token dostępu", "actionGenerateAccessToken": "Wygeneruj token dostępu",
"actionDeleteAccessToken": "Usuń token dostępu", "actionDeleteAccessToken": "Usuń token dostępu",
"actionListAccessTokens": "Lista tokenów dostępu", "actionListAccessTokens": "Lista tokenów dostępu",
"actionCreateResourceSessionToken": "Utwórz token sesji zasobu",
"actionCreateResourceRule": "Utwórz regułę zasobu", "actionCreateResourceRule": "Utwórz regułę zasobu",
"actionDeleteResourceRule": "Usuń regułę zasobu", "actionDeleteResourceRule": "Usuń regułę zasobu",
"actionListResourceRules": "Lista reguł zasobu", "actionListResourceRules": "Lista reguł zasobu",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Lista zaproszeń", "actionListInvitations": "Lista zaproszeń",
"actionExportLogs": "Eksportuj dzienniki", "actionExportLogs": "Eksportuj dzienniki",
"actionViewLogs": "Zobacz dzienniki", "actionViewLogs": "Zobacz dzienniki",
"actionCreateSiteProvisioningKey": "Utwórz klucz konfiguracji strony",
"actionListSiteProvisioningKeys": "Lista kluczy konfiguracji strony",
"actionUpdateSiteProvisioningKey": "Zaktualizuj klucz konfiguracji strony",
"actionDeleteSiteProvisioningKey": "Usuń klucz konfiguracji strony",
"noneSelected": "Nie wybrano", "noneSelected": "Nie wybrano",
"orgNotFound2": "Nie znaleziono organizacji.", "orgNotFound2": "Nie znaleziono organizacji.",
"search": "Szukaj…", "search": "Szukaj…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Ostatnio używany",
"otpAuthBack": "Powrót do hasła", "otpAuthBack": "Powrót do hasła",
"navbar": "Menu nawigacyjne", "navbar": "Menu nawigacyjne",
"navbarDescription": "Główne menu nawigacyjne aplikacji", "navbarDescription": "Główne menu nawigacyjne aplikacji",
"navbarDocsLink": "Dokumentacja", "navbarDocsLink": "Dokumentacja",
"commandPaletteTitle": "Paleta poleceń",
"commandPaletteDescription": "Szukaj stron, organizacji, zasobów i akcji",
"commandPaletteSearchPlaceholder": "Szukaj stron, zasobów, akcji...",
"commandPaletteNoResults": "Nie znaleziono wyników.",
"commandPaletteSearching": "Wyszukiwanie...",
"commandPaletteNavigation": "Nawigacja",
"commandPaletteOrganizations": "Organizacje",
"commandPaletteSites": "Witryny",
"commandPaletteResources": "Zasoby",
"commandPaletteUsers": "Użytkownicy",
"commandPaletteClients": "Klienci maszynowi",
"commandPaletteActions": "Akcje",
"commandPaletteCreateSite": "Utwórz witrynę",
"commandPaletteCreateProxyResource": "Utwórz zasób publiczny",
"commandPaletteCreatePrivateResource": "Utwórz zasób prywatny",
"commandPaletteCreateUser": "Utwórz użytkownika",
"commandPaletteCreateApiKey": "Utwórz klucz API",
"commandPaletteCreateMachineClient": "Utwórz klienta maszynowego",
"commandPaletteCreateAlertRule": "Utwórz regułę powiadomień",
"commandPaletteCreateIdentityProvider": "Utwórz dostawcę tożsamości",
"commandPaletteToggleTheme": "Przełącz motyw",
"commandPaletteChooseOrganization": "Wybierz organizację",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Nie można włączyć 2FA", "otpErrorEnable": "Nie można włączyć 2FA",
"otpErrorEnableDescription": "Wystąpił błąd podczas włączania 2FA", "otpErrorEnableDescription": "Wystąpił błąd podczas włączania 2FA",
"otpSetupCheckCode": "Wprowadź 6-cyfrowy kod", "otpSetupCheckCode": "Wprowadź 6-cyfrowy kod",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Zarządzanie", "sidebarManagement": "Zarządzanie",
"sidebarBillingAndLicenses": "Płatność i licencje", "sidebarBillingAndLicenses": "Płatność i licencje",
"sidebarLogsAnalytics": "Analityka", "sidebarLogsAnalytics": "Analityka",
"commandSites": "Witryny",
"commandActionModeInfo": "Wpisz \">\" aby otworzyć tryb akcji",
"commandResources": "Zasoby",
"commandProxyResources": "Zasoby publiczne",
"commandClientResources": "Zasoby prywatne",
"commandClients": "Klienci",
"commandUserDevices": "Urządzenia użytkownika",
"commandMachineClients": "Klienci maszynowi",
"commandDomains": "Domeny",
"commandRemoteExitNodes": "Zdalne węzły",
"commandTeam": "Zespół",
"commandUsers": "Użytkownicy",
"commandRoles": "Role",
"commandInvitations": "Zaproszenia",
"commandPolicies": "Polityki współdzielone",
"commandResourcePolicies": "Polityki zasobów publicznych",
"commandIdentityProviders": "Dostawcy tożsamości",
"commandApprovals": "Żądania zatwierdzeń",
"commandShareableLinks": "Linki do udostępnienia",
"commandOrganization": "Organizacja",
"commandLogsAndAnalytics": "Dzienniki i analizy",
"commandLogsAnalytics": "Analizy",
"commandLogsRequest": "Dzienniki żądań HTTP",
"commandLogsAccess": "Dzienniki uwierzytelniania",
"commandLogsAction": "Dzienniki działań administratora",
"commandLogsConnection": "Dzienniki połączeń",
"commandLogsStreaming": "Strumieniowanie zdarzeń",
"commandManagement": "Zarządzanie",
"commandAlerting": "Alarmy",
"commandProvisioning": "Dostarczanie",
"commandBluePrints": "Plany",
"commandApiKeys": "Klucze API",
"commandBillingAndLicenses": "Fakturowanie i licencje",
"commandBilling": "Fakturowanie",
"commandEnterpriseLicenses": "Licencje",
"commandSettings": "Ustawienia",
"commandLauncher": "Uruchamiacz",
"commandResourceLauncher": "Uruchamiacz zasobów",
"commandSearchResults": "Wyniki wyszukiwania",
"alertingTitle": "Alarmowanie", "alertingTitle": "Alarmowanie",
"alertingDescription": "Zdefiniuj źródła, ustawienia, i działania dla powiadomień", "alertingDescription": "Zdefiniuj źródła, ustawienia, i działania dla powiadomień",
"alertingRules": "Reguły alarmowe", "alertingRules": "Reguły alarmowe",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Subdomena: {subdomain}", "domainPickerSubdomain": "Subdomena: {subdomain}",
"domainPickerNamespace": "Przestrzeń nazw: {namespace}", "domainPickerNamespace": "Przestrzeń nazw: {namespace}",
"domainPickerShowMore": "Pokaż więcej", "domainPickerShowMore": "Pokaż więcej",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Wybierz region", "regionSelectorTitle": "Wybierz region",
"domainPickerRemoteExitNodeWarning": "Podane domeny nie są obsługiwane, gdy witryny łączą się ze zdalnymi węzłami wyjścia. Aby zasoby były dostępne w węzłach zdalnych, użyj domeny niestandardowej.", "domainPickerRemoteExitNodeWarning": "Podane domeny nie są obsługiwane, gdy witryny łączą się ze zdalnymi węzłami wyjścia. Aby zasoby były dostępne w węzłach zdalnych, użyj domeny niestandardowej.",
"regionSelectorInfo": "Wybór regionu pomaga nam zapewnić lepszą wydajność dla Twojej lokalizacji. Nie musisz być w tym samym regionie co Twój serwer.", "regionSelectorInfo": "Wybór regionu pomaga nam zapewnić lepszą wydajność dla Twojej lokalizacji. Nie musisz być w tym samym regionie co Twój serwer.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domeny", "billingDomains": "Domeny",
"billingOrganizations": "O masie całkowitej pojazdu przekraczającej 5 ton, ale nieprzekraczającej 5 ton", "billingOrganizations": "O masie całkowitej pojazdu przekraczającej 5 ton, ale nieprzekraczającej 5 ton",
"billingRemoteExitNodes": "Zdalne węzły", "billingRemoteExitNodes": "Zdalne węzły",
"billingPublicResources": "Zasoby publiczne",
"billingPrivateResources": "Zasoby prywatne",
"billingMachineClients": "Klienci maszynowi",
"billingNoLimitConfigured": "Nie skonfigurowano limitu", "billingNoLimitConfigured": "Nie skonfigurowano limitu",
"billingEstimatedPeriod": "Szacowany Okres Rozliczeniowy", "billingEstimatedPeriod": "Szacowany Okres Rozliczeniowy",
"billingIncludedUsage": "Zawarte użycie", "billingIncludedUsage": "Zawarte użycie",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Ile użytkowników możesz użyć", "billingUsersInfo": "Ile użytkowników możesz użyć",
"billingDomainInfo": "Ile domen możesz użyć", "billingDomainInfo": "Ile domen możesz użyć",
"billingRemoteExitNodesInfo": "Ile zdalnych węzłów możesz użyć", "billingRemoteExitNodesInfo": "Ile zdalnych węzłów możesz użyć",
"billingPublicResourcesInfo": "Ile zasobów publicznych możesz wykorzystać",
"billingPrivateResourcesInfo": "Ile zasobów prywatnych możesz wykorzystać",
"billingMachineClientsInfo": "Ile klientów maszynowych możesz wykorzystać",
"billingLicenseKeys": "Klucze licencyjne", "billingLicenseKeys": "Klucze licencyjne",
"billingLicenseKeysDescription": "Zarządzaj subskrypcjami kluczy licencyjnych", "billingLicenseKeysDescription": "Zarządzaj subskrypcjami kluczy licencyjnych",
"billingLicenseSubscription": "Subskrypcja licencji", "billingLicenseSubscription": "Subskrypcja licencji",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Podsieć", "subnetPlaceholder": "Podsieć",
"addressDescription": "Adres wewnętrzny klienta. Musi mieścić się w podsieci organizacji.", "addressDescription": "Adres wewnętrzny klienta. Musi mieścić się w podsieci organizacji.",
"selectSites": "Wybierz witryny", "selectSites": "Wybierz witryny",
"selectLabels": "Wybierz etykiety",
"sitesDescription": "Klient będzie miał łączność z wybranymi witrynami", "sitesDescription": "Klient będzie miał łączność z wybranymi witrynami",
"clientInstallOlm": "Zainstaluj Olm", "clientInstallOlm": "Zainstaluj Olm",
"clientInstallOlmDescription": "Uruchom Olm na swoim systemie", "clientInstallOlmDescription": "Uruchom Olm na swoim systemie",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Publiczne", "resourcesTableProxyResources": "Publiczne",
"resourcesTableClientResources": "Prywatny", "resourcesTableClientResources": "Prywatny",
"resourcesTableNoProxyResourcesFound": "Nie znaleziono zasobów proxy.", "resourcesTableNoProxyResourcesFound": "Nie znaleziono zasobów proxy.",
"resourcesTableNoInternalResourcesFound": "Nie znaleziono wewnętrznych zasobów.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Miejsce docelowe", "resourcesTableDestination": "Miejsce docelowe",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Adres aliasu", "resourcesTableAliasAddress": "Adres aliasu",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Anuluj", "editInternalResourceDialogCancel": "Anuluj",
"editInternalResourceDialogSaveResource": "Zapisz zasób", "editInternalResourceDialogSaveResource": "Zapisz zasób",
"editInternalResourceDialogSuccess": "Sukces", "editInternalResourceDialogSuccess": "Sukces",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Wewnętrzny zasób zaktualizowany pomyślnie", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Błąd", "editInternalResourceDialogError": "Błąd",
"editInternalResourceDialogFailedToUpdateInternalResource": "Nie udało się zaktualizować wewnętrznego zasobu", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Nazwa jest wymagana", "editInternalResourceDialogNameRequired": "Nazwa jest wymagana",
"editInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków", "editInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
"editInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1", "editInternalResourceDialogProxyPortMin": "Port proxy musi wynosić przynajmniej 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.", "editInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.",
"createInternalResourceDialogNoSitesAvailable": "Brak dostępnych stron", "createInternalResourceDialogNoSitesAvailable": "Brak dostępnych stron",
"createInternalResourceDialogNoSitesAvailableDescription": "Musisz mieć co najmniej jedną stronę Newt z skonfigurowanym podsiecią, aby tworzyć wewnętrzne zasoby.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Zamknij", "createInternalResourceDialogClose": "Zamknij",
"createInternalResourceDialogCreateClientResource": "Utwórz zasób prywatny", "createInternalResourceDialogCreateClientResource": "Utwórz zasób prywatny",
"createInternalResourceDialogCreateClientResourceDescription": "Utwórz nowy zasób, który będzie dostępny tylko dla klientów podłączonych do organizacji", "createInternalResourceDialogCreateClientResourceDescription": "Utwórz nowy zasób, który będzie dostępny tylko dla klientów podłączonych do organizacji",
"privateResourceGeneralDescription": "Skonfiguruj nazwę, identyfikator i inne ogólne ustawienia zasobów.",
"privateResourceCreatePageSeeAll": "Zobacz wszystkie zasoby prywatne",
"privateResourceAllowIcmpPing": "Zezwalaj na ping ICMP",
"privateResourceNetworkAccess": "Dostęp do sieci",
"privateResourceNetworkAccessDescription": "Kontroluj dostęp do portów TCP/UDP i czy ping ICMP jest dozwolony dla tego zasobu.",
"hostSettings": "Ustawienia hosta",
"cidrSettings": "Ustawienia CIDR",
"createInternalResourceDialogResourceProperties": "Właściwości zasobów", "createInternalResourceDialogResourceProperties": "Właściwości zasobów",
"createInternalResourceDialogName": "Nazwa", "createInternalResourceDialogName": "Nazwa",
"createInternalResourceDialogSite": "Witryna", "createInternalResourceDialogSite": "Witryna",
"selectSite": "Wybierz stronę...", "selectSite": "Wybierz stronę...",
"multiSitesSelectorSitesCount": "{count, plural, one {# witryna} few {# witryny} many {# witryn} other {# witryn}}", "multiSitesSelectorSitesCount": "{count, plural, one {# witryna} few {# witryny} many {# witryn} other {# witryn}}",
"labelsSelectorLabelsCount": "{count, plural, one {# etykieta} few {# etykiety} many {# etykiet} other {# etykiet}}",
"noSitesFound": "Nie znaleziono stron.", "noSitesFound": "Nie znaleziono stron.",
"createInternalResourceDialogProtocol": "Protokół", "createInternalResourceDialogProtocol": "Protokół",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Anuluj", "createInternalResourceDialogCancel": "Anuluj",
"createInternalResourceDialogCreateResource": "Utwórz zasób", "createInternalResourceDialogCreateResource": "Utwórz zasób",
"createInternalResourceDialogSuccess": "Sukces", "createInternalResourceDialogSuccess": "Sukces",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Wewnętrzny zasób utworzony pomyślnie", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Błąd", "createInternalResourceDialogError": "Błąd",
"createInternalResourceDialogFailedToCreateInternalResource": "Nie udało się utworzyć wewnętrznego zasobu", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Nazwa jest wymagana", "createInternalResourceDialogNameRequired": "Nazwa jest wymagana",
"createInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków", "createInternalResourceDialogNameMaxLength": "Nazwa nie może mieć więcej niż 255 znaków",
"createInternalResourceDialogPleaseSelectSite": "Proszę wybrać stronę", "createInternalResourceDialogPleaseSelectSite": "Proszę wybrać stronę",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "Zakres CIDR zasobu w sieci witryny.", "createInternalResourceDialogDestinationCidrDescription": "Zakres CIDR zasobu w sieci witryny.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.", "createInternalResourceDialogAliasDescription": "Opcjonalny wewnętrzny alias DNS dla tego zasobu.",
"internalResourceAliasLocalWarning": "Alias kończący się na .local może powodować problemy z rozpoznawaniem z powodu mDNS w niektórych sieciach.",
"internalResourceDownstreamSchemeRequired": "Schemat jest wymagany dla zasobów HTTP", "internalResourceDownstreamSchemeRequired": "Schemat jest wymagany dla zasobów HTTP",
"internalResourceHttpPortRequired": "Port docelowy jest wymagany dla zasobów HTTP", "internalResourceHttpPortRequired": "Port docelowy jest wymagany dla zasobów HTTP",
"siteConfiguration": "Konfiguracja", "siteConfiguration": "Konfiguracja",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Zdalne węzły", "sidebarRemoteExitNodes": "Zdalne węzły",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Sekret", "remoteExitNodeSecretKey": "Sekret",
"remoteExitNodeNetworkingTitle": "Ustawienia sieciowe",
"remoteExitNodeNetworkingDescription": "Skonfiguruj, jak ten zdalny węzeł wyjściowy przekierowuje ruch i które strony preferują połączenie przez niego. Zaawansowane funkcje do użycia z konfiguracją sieci backhaul.",
"remoteExitNodeNetworkingSave": "Zapisz ustawienia",
"remoteExitNodeNetworkingSaveSuccessTitle": "Ustawienia sieciowe zapisane",
"remoteExitNodeNetworkingSaveSuccessDescription": "Ustawienia sieciowe zostały pomyślnie zaktualizowane.",
"remoteExitNodeNetworkingSaveError": "Nie udało się zapisać ustawień sieciowych",
"remoteExitNodeNetworkingSubnetsTitle": "Zdalne Podsieci",
"remoteExitNodeNetworkingSubnetsDescription": "Zdefiniuj zakresy CIDR, które ten zdalny węzeł wyjściowy przekieruje ruch do. Wpisz prawidłowy CIDR (np. <code>10.0.0.0/8</code>) i naciśnij Enter, aby dodać.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Dodaj zakres CIDR (np. 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Nie udało się załadować podsieci",
"remoteExitNodeNetworkingLabelsTitle": "Etykiety preferencji",
"remoteExitNodeNetworkingLabelsDescription": "Strony z tymi etykietami będą zmuszone do połączenia się przez ten zdalny węzeł wyjściowy.",
"remoteExitNodeNetworkingLabelsButtonText": "Wybierz etykiety...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Szukaj etykiet...",
"remoteExitNodeNetworkingLabelsLoadError": "Nie udało się załadować etykiet",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Utwórz zdalny węzeł", "title": "Utwórz zdalny węzeł",
"description": "Utwórz nowy, samodzielnie hostowany węzeł przekaźnika zdalnego i serwera proxy", "description": "Utwórz nowy, samodzielnie hostowany węzeł przekaźnika zdalnego i serwera proxy",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Węzły nie są dostępne dla tej organizacji. Utwórz węzeł, aby używać lokalnych witryn.", "noRemoteExitNodesAvailableDescription": "Węzły nie są dostępne dla tej organizacji. Utwórz węzeł, aby używać lokalnych witryn.",
"exitNode": "Węzeł Wyjściowy", "exitNode": "Węzeł Wyjściowy",
"country": "Kraj", "country": "Kraj",
"countryIsNot": "Kraj nie jest",
"rulesMatchCountry": "Obecnie bazuje na adresie IP źródła", "rulesMatchCountry": "Obecnie bazuje na adresie IP źródła",
"region": "Region", "region": "Region",
"selectRegion": "Wybierz region", "selectRegion": "Wybierz region",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Dostawca Google OAuth2/OIDC", "idpGoogleDescription": "Dostawca Google OAuth2/OIDC",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Podsieć", "subnet": "Podsieć",
"utilitySubnet": "Użyteczna podsieć",
"subnetDescription": "Podsieć dla konfiguracji sieci tej organizacji.", "subnetDescription": "Podsieć dla konfiguracji sieci tej organizacji.",
"customDomain": "Niestandardowa domena", "customDomain": "Niestandardowa domena",
"authPage": "Strony uwierzytelniania", "authPage": "Strony uwierzytelniania",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Konfiguracja uwierzytelniania dwuskładnikowego jest wymagana. Zaloguj się ponownie przez {dashboardUrl}/auth/login dokończ ten krok. Następnie wróć tutaj.", "twoFactorSetupRequired": "Konfiguracja uwierzytelniania dwuskładnikowego jest wymagana. Zaloguj się ponownie przez {dashboardUrl}/auth/login dokończ ten krok. Następnie wróć tutaj.",
"additionalSecurityRequired": "Wymagane dodatkowe zabezpieczenie", "additionalSecurityRequired": "Wymagane dodatkowe zabezpieczenie",
"organizationRequiresAdditionalSteps": "Ta organizacja wymaga dodatkowych kroków bezpieczeństwa, zanim będziesz mógł uzyskać dostęp do zasobów.", "organizationRequiresAdditionalSteps": "Ta organizacja wymaga dodatkowych kroków bezpieczeństwa, zanim będziesz mógł uzyskać dostęp do zasobów.",
"sessionExpired": "Sesja wygasła",
"sessionExpiredReauthRequired": "Twoja sesja wygasła zgodnie z zasadami bezpieczeństwa Twojej organizacji. Proszę się ponownie zalogować, aby kontynuować.",
"reauthenticate": "Zaloguj się ponownie",
"completeTheseSteps": "Wykonaj te kroki", "completeTheseSteps": "Wykonaj te kroki",
"enableTwoFactorAuthentication": "Włącz uwierzytelnianie dwuskładnikowe", "enableTwoFactorAuthentication": "Włącz uwierzytelnianie dwuskładnikowe",
"completeSecuritySteps": "Zakończ kroki bezpieczeństwa", "completeSecuritySteps": "Zakończ kroki bezpieczeństwa",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Adres źródłowy", "sourceAddress": "Adres źródłowy",
"destinationAddress": "Adres docelowy", "destinationAddress": "Adres docelowy",
"duration": "Czas trwania", "duration": "Czas trwania",
"licenseRequiredToUse": "Do korzystania z tej funkcji wymagana jest licencja <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lub <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> . <bookADemoLink>Zarezerwuj wersję demonstracyjną lub wersję próbną POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> jest wymagany do korzystania z tej funkcji. Ta funkcja jest również dostępna w <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Zarezerwuj demo lub okres próbny POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Rozwiązywanie certyfikatów", "certResolver": "Rozwiązywanie certyfikatów",
"certResolverDescription": "Wybierz resolver certyfikatów do użycia dla tego zasobu.", "certResolverDescription": "Wybierz resolver certyfikatów do użycia dla tego zasobu.",
"selectCertResolver": "Wybierz Resolver certyfikatów", "selectCertResolver": "Wybierz Resolver certyfikatów",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Brakuje identyfikatora organizacji lub domeny", "orgOrDomainIdMissing": "Brakuje identyfikatora organizacji lub domeny",
"loadingDNSRecords": "Ładowanie rekordów DNS...", "loadingDNSRecords": "Ładowanie rekordów DNS...",
"olmUpdateAvailableInfo": "Dostępna jest zaktualizowana wersja Olm. Zaktualizuj do najnowszej wersji, aby uzyskać najlepsze doświadczenia.", "olmUpdateAvailableInfo": "Dostępna jest zaktualizowana wersja Olm. Zaktualizuj do najnowszej wersji, aby uzyskać najlepsze doświadczenia.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Dostępna jest zaktualizowana wersja. Zaktualizuj do najnowszej wersji, aby uzyskać najlepsze wrażenia z użytkowania.",
"client": "Klient", "client": "Klient",
"proxyProtocol": "Ustawienia protokołu proxy", "proxyProtocol": "Ustawienia protokołu proxy",
"proxyProtocolDescription": "Skonfiguruj protokół Proxy aby zachować adresy IP klienta dla usług TCP.", "proxyProtocolDescription": "Skonfiguruj protokół Proxy aby zachować adresy IP klienta dla usług TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Dodaj użytkowników", "editInternalResourceDialogAddUsers": "Dodaj użytkowników",
"editInternalResourceDialogAddClients": "Dodaj klientów", "editInternalResourceDialogAddClients": "Dodaj klientów",
"editInternalResourceDialogDestinationLabel": "Miejsce docelowe", "editInternalResourceDialogDestinationLabel": "Miejsce docelowe",
"editInternalResourceDialogDestinationDescription": "Określ adres docelowy dla wewnętrznego zasobu. Może to być nazwa hosta, adres IP lub zakres CIDR, w zależności od wybranego trybu. Opcjonalnie ustaw wewnętrzny alias DNS dla łatwiejszej identyfikacji.", "editInternalResourceDialogDestinationDescription": "Skonfiguruj sposób, w jaki klienci docierają do tego zasobu.",
"internalResourceFormMultiSiteRoutingHelp": "Wybór wielu stron umożliwia odporne trasowanie i awarię dla wysokiej dostępności.", "internalResourceFormMultiSiteRoutingHelp": "Wybór wielu stron umożliwia odporne trasowanie i awarię dla wysokiej dostępności.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Dowiedz się więcej", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Dowiedz się więcej",
"editInternalResourceDialogPortRestrictionsDescription": "Ogranicz dostęp do konkretnych portów TCP/UDP lub zezwól/zablokuj wszystkie porty.", "editInternalResourceDialogPortRestrictionsDescription": "Ogranicz dostęp do konkretnych portów TCP/UDP lub zezwól/zablokuj wszystkie porty.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Biała lista e-mail", "memberPortalEmailWhitelist": "Biała lista e-mail",
"memberPortalResourceDisabled": "Zasób wyłączony", "memberPortalResourceDisabled": "Zasób wyłączony",
"memberPortalShowingResources": "Wyświetlanie zasobów od {start} do {end} z {total}", "memberPortalShowingResources": "Wyświetlanie zasobów od {start} do {end} z {total}",
"resourceLauncherTitle": "Uruchamiacz Zasobów",
"resourceSidebarLauncherTitle": "Uruchamiacz",
"resourceLauncherDescription": "Wyświetl wszystkie dostępne zasoby i uruchom je w jednym centralnym hubie",
"resourceLauncherSearchPlaceholder": "Szukaj zasobów...",
"resourceLauncherDefaultView": "Domyślny",
"resourceLauncherSaveView": "Zapisz Widok",
"resourceLauncherSaveToCurrentView": "Zapisz do bieżącego widoku",
"resourceLauncherSaveDefaultPersonal": "Zapisz dla mnie",
"resourceLauncherResetView": "Resetuj Widok",
"resourceLauncherResetSystemDefault": "Przywróć do domyślnych ustawień systemowych",
"resourceLauncherSystemDefaultRestored": "Przywrócono domyślne ustawienia systemowe",
"resourceLauncherSystemDefaultRestoredDescription": "Domyślny widok został przywrócony do oryginalnych ustawień.",
"resourceLauncherSaveAsNewView": "Zapisz jako Nowy Widok",
"resourceLauncherSaveAsNewViewDescription": "Nadaj nazwę temu widokowi, aby zapisać swoje bieżące filtry i układ.",
"resourceLauncherSaveForEveryone": "Zapisz dla wszystkich",
"resourceLauncherSaveForEveryoneDescription": "Udostępnij ten widok wszystkim członkom organizacji. Gdy jest niezaznaczone, widok jest widoczny tylko dla Ciebie.",
"resourceLauncherMakePersonal": "Zrób osobisty",
"resourceLauncherFilter": "Filtr",
"resourceLauncherFilterWithCount": "Filtr, zastosowano {count}",
"resourceLauncherSort": "Sortuj",
"resourceLauncherSortAscending": "Sortuj rosnąco",
"resourceLauncherSortDescending": "Sortuj malejąco",
"resourceLauncherSettings": "Ustawienia",
"resourceLauncherGroupBy": "Grupuj według",
"resourceLauncherGroupBySite": "Witryna",
"resourceLauncherGroupByLabel": "Etykieta",
"resourceLauncherGroupByNone": "Brak",
"resourceLauncherLayout": "Układ",
"resourceLauncherLayoutGrid": "Siatka",
"resourceLauncherLayoutList": "Lista",
"resourceLauncherShowLabels": "Pokaż etykiety",
"resourceLauncherShowSiteTags": "Pokaż tagi stron",
"resourceLauncherShowRecents": "Pokaż ostatnie",
"resourceLauncherDeleteView": "Usuń Widok",
"resourceLauncherDeleteViewTitle": "Usuń widok",
"resourceLauncherDeleteViewQuestion": "Czy na pewno chcesz usunąć ten widok uruchamiania?",
"resourceLauncherDeleteViewConfirm": "Usuń widok",
"resourceLauncherViewAsAdmin": "Przeglądaj jako Administrator",
"resourceLauncherResourceDetailsDescription": "Informacje i status połączenia dla tego zasobu.",
"resourceLauncherResourceDetails": "Szczegóły zasobów",
"resourceLauncherAuthMethodsDescription": "Metody uwierzytelniania włączone dla tego zasobu.",
"resourceLauncherPrivateClientRequired": "Połącz się z klientem na swoim urządzeniu, aby uzyskać dostęp do tego zasobu prywatnie.",
"resourceLauncherPrivateClientRequiredTitle": "Wymagane połączenie z klientem",
"resourceLauncherDownloadClient": "Pobierz klienta",
"resourceLauncherFailedToLoadDetails": "Nie można załadować szczegółów zasobu. Możliwe, że nie masz już dostępu do tego zasobu.",
"resourceLauncherNoPortRestrictions": "Brak ograniczeń portów",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Bez etykiety",
"resourceLauncherNoSite": "Brak strony",
"resourceLauncherNoResourcesInGroup": "W tej grupie nie ma zasobów",
"resourceLauncherEmptyStateTitle": "Brak dostępnych zasobów",
"resourceLauncherEmptyStateDescription": "Jeszcze nie masz dostępu do żadnych zasobów. Skontaktuj się z administratorem, aby poprosić o dostęp.",
"resourceLauncherEmptyStateNoResultsTitle": "Nie znaleziono zasobów",
"resourceLauncherEmptyStateNoResultsDescription": "Żadne zasoby nie spełniają twojego bieżącego wyszukiwania lub filtrów. Spróbuj je dostosować, aby znaleźć to, czego szukasz.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Żadne zasoby nie odpowiadają \"{query}\". Spróbuj dostosować swoje wyszukiwanie lub usunąć filtry, aby zobaczyć wszystkie zasoby.",
"resourceLauncherSearchFirstTitle": "Szukaj lub filtruj, aby przeglądać",
"resourceLauncherSearchFirstDescription": "Masz dostęp do wielu zasobów. Użyj wyszukiwania lub filtruj według witryny lub etykiety, aby znaleźć to, czego potrzebujesz.",
"resourceLauncherSiteGroupingDisabled": "Grupowanie witryn jest niedostępne w tej skali. Filtruj według witryny, aby pogrupować mniejszy zestaw.",
"resourceLauncherLabelGroupingDisabled": "Grupowanie etykiet jest niedostępne w tej skali.",
"resourceLauncherCompactModeHint": "Wyświetlanie uproszczonej listy dla szybszego przeglądania. Użyj wyszukiwania lub filtrów, aby zawęzić wyniki.",
"resourceLauncherCompactGroupingHint": "Zastosuj filtry witryn lub etykiet, aby włączyć grupowanie.",
"resourceLauncherCopiedToClipboard": "Skopiowano do schowka",
"resourceLauncherCopiedAccessDescription": "Dostęp do zasobu został skopiowany do schowka.",
"resourceLauncherViewNamePlaceholder": "Nazwa widoku",
"resourceLauncherViewNameLabel": "Nazwa Widoku",
"resourceLauncherViewSaved": "Widok zapisany",
"resourceLauncherViewSavedDescription": "Twój widok uruchamiacza został zapisany.",
"resourceLauncherViewSaveFailed": "Nie udało się zapisać widoku",
"resourceLauncherViewSaveFailedDescription": "Nie można zapisać widoku uruchamiacza. Proszę spróbować ponownie.",
"resourceLauncherViewDeleted": "Widok usunięty",
"resourceLauncherViewDeletedDescription": "Widok uruchamiacza został usunięty.",
"resourceLauncherViewDeleteFailed": "Nie udało się usunąć widoku",
"resourceLauncherViewDeleteFailedDescription": "Nie można usunąć widoku uruchamiacza. Proszę spróbować ponownie.",
"memberPortalPrevious": "Poprzedni", "memberPortalPrevious": "Poprzedni",
"memberPortalNext": "Następny", "memberPortalNext": "Następny",
"httpSettings": "Ustawienia HTTP", "httpSettings": "Ustawienia HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "Wymagany jest klucz prywatny", "sshPrivateKeyRequired": "Wymagany jest klucz prywatny",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Wprowadź hasło VNC, aby się połączyć", "vncSignInDescription": "Wprowadź swoje dane uwierzytelniające VNC aby się połączyć",
"vncUsernameOptional": "Nazwa użytkownika (opcjonalnie)",
"vncPasswordOptional": "Hasło (opcjonalne)", "vncPasswordOptional": "Hasło (opcjonalne)",
"vncNoResourceTarget": "Brak dostępnego celu zasobu", "vncNoResourceTarget": "Brak dostępnego celu zasobu",
"vncFailedToLoadNovnc": "Błąd ładowania noVNC", "vncFailedToLoadNovnc": "Błąd ładowania noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Niepowodzenie przesyłania", "rdpUploadFailed": "Niepowodzenie przesyłania",
"rdpUnicodeKeyboardMode": "Tryb klawiatury Unicode", "rdpUnicodeKeyboardMode": "Tryb klawiatury Unicode",
"sessionToolbarShow": "Pokaż pasek narzędzi", "sessionToolbarShow": "Pokaż pasek narzędzi",
"sessionToolbarHide": "Ukryj pasek narzędzi" "sessionToolbarHide": "Ukryj pasek narzędzi",
"actionUpdateSiteApprovals": "Zaktualizuj zgody na stronę"
} }
+250 -22
View File
@@ -66,9 +66,15 @@
"local": "Localização", "local": "Localização",
"edit": "Alterar", "edit": "Alterar",
"siteConfirmDelete": "Confirmar que pretende apagar o site", "siteConfirmDelete": "Confirmar que pretende apagar o site",
"siteConfirmDeleteAndResources": "Confirmar Exclusão do Site e Recursos",
"siteDelete": "Excluir site", "siteDelete": "Excluir site",
"siteDeleteAndResources": "Excluir Site e Recursos",
"siteMessageRemove": "Uma vez removido, o site não estará mais acessível. Todas as metas associadas ao site também serão removidas.", "siteMessageRemove": "Uma vez removido, o site não estará mais acessível. Todas as metas associadas ao site também serão removidas.",
"siteMessageRemoveAndResources": "Isso excluirá permanentemente todos os recursos públicos e privados vinculados a este site, mesmo que um recurso também esteja associado a outros sites.",
"siteQuestionRemove": "Você tem certeza que deseja remover este site da organização?", "siteQuestionRemove": "Você tem certeza que deseja remover este site da organização?",
"siteQuestionRemoveAndResources": "Tem certeza de que deseja excluir este site e todos os recursos associados?",
"sitesTableDeleteSite": "Excluir Site",
"sitesTableDeleteSiteAndResources": "Excluir Site e Recursos",
"siteManageSites": "Gerir sites", "siteManageSites": "Gerir sites",
"siteDescription": "Criar e gerenciar sites para ativar a conectividade a redes privadas", "siteDescription": "Criar e gerenciar sites para ativar a conectividade a redes privadas",
"sitesBannerTitle": "Conectar a Qualquer Rede", "sitesBannerTitle": "Conectar a Qualquer Rede",
@@ -117,6 +123,16 @@
"siteUpdated": "Site atualizado", "siteUpdated": "Site atualizado",
"siteUpdatedDescription": "O site foi atualizado.", "siteUpdatedDescription": "O site foi atualizado.",
"siteGeneralDescription": "Configurar as configurações gerais para este site", "siteGeneralDescription": "Configurar as configurações gerais para este site",
"siteRestartTitle": "Reiniciar site",
"siteRestartDescription": "Reinicie o túnel WireGuard para este site. Isso interromperá brevemente a conectividade.",
"siteRestartBody": "Use isso se o túnel do site não estiver funcionando corretamente e você quiser forçar uma reconexão sem reiniciar o host.",
"siteRestartButton": "Reiniciar site",
"siteRestartDialogMessage": "Tem certeza de que deseja reiniciar o túnel WireGuard para <b>{name}</b>? O site perderá brevemente a conectividade.",
"siteRestartWarning": "O site será desconectado brevemente enquanto o túnel reinicia.",
"siteRestarted": "Site reiniciado",
"siteRestartedDescription": "O túnel WireGuard foi reiniciado.",
"siteErrorRestart": "Falha ao reiniciar o site",
"siteErrorRestartDescription": "Ocorreu um erro ao reiniciar o site.",
"siteSettingDescription": "Configurar as configurações no site", "siteSettingDescription": "Configurar as configurações no site",
"siteResourcesTab": "Recursos", "siteResourcesTab": "Recursos",
"siteResourcesNoneOnSite": "Este site ainda não possui recursos públicos ou privados.", "siteResourcesNoneOnSite": "Este site ainda não possui recursos públicos ou privados.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Confirmar exclusão do Link Compartilhável", "shareDeleteConfirm": "Confirmar exclusão do Link Compartilhável",
"shareQuestionRemove": "Tem certeza de que deseja excluir este link de compartilhamento?", "shareQuestionRemove": "Tem certeza de que deseja excluir este link de compartilhamento?",
"shareMessageRemove": "Uma vez excluído, o link não funcionará mais e qualquer pessoa que o utilizar perderá o acesso ao recurso.", "shareMessageRemove": "Uma vez excluído, o link não funcionará mais e qualquer pessoa que o utilizar perderá o acesso ao recurso.",
"shareTokenDescription": "O token de acesso pode ser passado de duas maneiras: como um parâmetro de consulta ou nos cabeçalhos da solicitação. Estes devem ser passados do cliente em todas as solicitações para acesso autenticado.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Token de acesso", "accessToken": "Token de acesso",
"usageExamples": "Exemplos de uso", "usageExamples": "Exemplos de uso",
"tokenId": "ID do Token", "tokenId": "ID do Token",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Título (opcional)", "shareTitleOptional": "Título (opcional)",
"sharePathOptional": "Caminho (opcional)", "sharePathOptional": "Caminho (opcional)",
"sharePathDescription": "O link redirecionará os usuários para este caminho após a autenticação.", "sharePathDescription": "O link redirecionará os usuários para este caminho após a autenticação.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Expira em", "expireIn": "Expira em",
"neverExpire": "Nunca expirar", "neverExpire": "Nunca expirar",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Tempo de expiração é quanto tempo o link será utilizável e oferecerá acesso ao recurso. Após este tempo, o link não funcionará mais, e os utilizadores que usaram este link perderão acesso ao recurso.", "shareExpireDescription": "Tempo de expiração é quanto tempo o link será utilizável e oferecerá acesso ao recurso. Após este tempo, o link não funcionará mais, e os utilizadores que usaram este link perderão acesso ao recurso.",
"shareSeeOnce": "Você só poderá ver este link uma vez. Certifique-se de copiá-lo.", "shareSeeOnce": "Você só poderá ver este link uma vez. Certifique-se de copiá-lo.",
"shareAccessHint": "Qualquer um com este link pode aceder o recurso. Compartilhe com cuidado.", "shareAccessHint": "Qualquer um com este link pode aceder o recurso. Compartilhe com cuidado.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy solicita por TCP/UDP bruto usando um número de porta. Requer que sites se conectem a um nó remoto.", "resourceRawDescriptionCloud": "Proxy solicita por TCP/UDP bruto usando um número de porta. Requer que sites se conectem a um nó remoto.",
"resourceCreate": "Criar Recurso", "resourceCreate": "Criar Recurso",
"resourceCreateDescription": "Siga os passos abaixo para criar um novo recurso", "resourceCreateDescription": "Siga os passos abaixo para criar um novo recurso",
"resourcePublicCreate": "Criar Recurso Público",
"resourcePublicCreateDescription": "Siga os passos abaixo para criar um novo recurso público acessível através de um navegador web",
"resourceCreateGeneralDescription": "Configure as configurações gerais do recurso, incluindo o nome e o tipo", "resourceCreateGeneralDescription": "Configure as configurações gerais do recurso, incluindo o nome e o tipo",
"resourceSeeAll": "Ver todos os recursos", "resourceSeeAll": "Ver todos os recursos",
"resourceCreateGeneral": "Gerais", "resourceCreateGeneral": "Gerais",
@@ -431,8 +455,14 @@
"provisioningManage": "Provisionamento", "provisioningManage": "Provisionamento",
"provisioningDescription": "Gerenciar chaves de provisionamento e revisar sites pendentes aguardando aprovação.", "provisioningDescription": "Gerenciar chaves de provisionamento e revisar sites pendentes aguardando aprovação.",
"pendingSites": "Sites pendentes", "pendingSites": "Sites pendentes",
"siteApproveSuccess": "Site aprovado com sucesso", "siteApproveSuccess": "Site e recursos associados aprovados com sucesso",
"siteApproveError": "Erro ao aprovar site", "siteApproveError": "Erro ao aprovar site",
"siteReject": "Rejeitar Site",
"siteQuestionReject": "Tem certeza de que deseja rejeitar este site?",
"siteMessageReject": "Isto eliminará permanentemente o site e quaisquer recursos associados que ainda estejam pendentes.",
"siteConfirmReject": "Confirmar Rejeição de Site",
"siteRejectSuccess": "Site rejeitado com sucesso",
"siteRejectError": "Erro ao rejeitar site",
"provisioningKeys": "Posicionando chaves", "provisioningKeys": "Posicionando chaves",
"searchProvisioningKeys": "Pesquisar chaves de provisionamento...", "searchProvisioningKeys": "Pesquisar chaves de provisionamento...",
"provisioningKeysAdd": "Gerar chave de provisionamento", "provisioningKeysAdd": "Gerar chave de provisionamento",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Salvar a chave de provisionamento", "provisioningKeysSave": "Salvar a chave de provisionamento",
"provisioningKeysSaveDescription": "Você só será capaz de ver esta vez. Copiá-lo para um lugar seguro.", "provisioningKeysSaveDescription": "Você só será capaz de ver esta vez. Copiá-lo para um lugar seguro.",
"provisioningKeysErrorCreate": "Erro ao criar chave de provisionamento", "provisioningKeysErrorCreate": "Erro ao criar chave de provisionamento",
"provisioningKeysList": "Nova chave de aprovisionamento", "provisioningKeysList": "Nova Chave de Provisionamento",
"provisioningKeysMaxBatchSize": "Tamanho máximo do lote", "provisioningKeysMaxBatchSize": "Tamanho Máximo do Lote",
"provisioningKeysUnlimitedBatchSize": "Tamanho ilimitado em lote (sem limite)", "provisioningKeysUnlimitedBatchSize": "Tamanho ilimitado em lote (sem limite)",
"provisioningKeysMaxBatchUnlimited": "Ilimitado", "provisioningKeysMaxBatchUnlimited": "Ilimitado",
"provisioningKeysMaxBatchSizeInvalid": "Informe um tamanho máximo válido em lote (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Informe um tamanho máximo válido em lote (11,000,000).",
"provisioningKeysValidUntil": "Valido ate", "provisioningKeysValidUntil": "Válido Até",
"provisioningKeysValidUntilHint": "Deixe em branco para nenhuma expiração.", "provisioningKeysValidUntilHint": "Deixe em branco para nenhuma expiração.",
"provisioningKeysValidUntilInvalid": "Informe uma data e hora válidas.", "provisioningKeysValidUntilInvalid": "Informe uma data e hora válidas.",
"provisioningKeysNumUsed": "Use percentual", "provisioningKeysNumUsed": "Use percentual",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "nunca", "provisioningKeysNeverUsed": "nunca",
"provisioningKeysEdit": "Editar chave de provisionamento", "provisioningKeysEdit": "Editar chave de provisionamento",
"provisioningKeysEditDescription": "Atualizar o tamanho máximo do lote e tempo de expiração para esta chave.", "provisioningKeysEditDescription": "Atualizar o tamanho máximo do lote e tempo de expiração para esta chave.",
"provisioningKeysApproveNewSites": "Aprovar novos sites", "provisioningKeysApproveNewSites": "Aprovar Novos Sites",
"provisioningKeysApproveNewSitesDescription": "Aprovar automaticamente sites que se registram com esta chave.", "provisioningKeysApproveNewSitesDescription": "Aprovar automaticamente sites que se registram com esta chave.",
"provisioningKeysUpdateError": "Erro ao atualizar chave de provisionamento", "provisioningKeysUpdateError": "Erro ao atualizar chave de provisionamento",
"provisioningKeysUpdated": "Chave de provisionamento atualizada", "provisioningKeysUpdated": "Chave de provisionamento atualizada",
@@ -597,7 +627,8 @@
"idpNameInternal": "Interno", "idpNameInternal": "Interno",
"emailInvalid": "Endereço de email inválido", "emailInvalid": "Endereço de email inválido",
"inviteValidityDuration": "Por favor, selecione uma duração", "inviteValidityDuration": "Por favor, selecione uma duração",
"accessRoleSelectPlease": "Por favor, selecione uma função", "accessRoleSelectPlease": "Um usuário deve pertencer a pelo menos um papel.",
"accessRoleRequired": "Papel necessário",
"removeOwnAdminRoleConfirmTitle": "Remover seu acesso de administrador?", "removeOwnAdminRoleConfirmTitle": "Remover seu acesso de administrador?",
"removeOwnAdminRoleConfirmDescription": "Você não terá mais permissões de administrador nesta organização após salvar. Outro administrador pode restaurar seu acesso, se necessário.", "removeOwnAdminRoleConfirmDescription": "Você não terá mais permissões de administrador nesta organização após salvar. Outro administrador pode restaurar seu acesso, se necessário.",
"removeOwnAdminRoleConfirmButton": "Remover Meu Acesso de Administrador", "removeOwnAdminRoleConfirmButton": "Remover Meu Acesso de Administrador",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Autenticação de Cabeçalho Básico", "policyAuthHeaderAuthTitle": "Autenticação de Cabeçalho Básico",
"policyAuthHeaderAuthDescription": "Valide um nome e valor de cabeçalho HTTP personalizado em cada solicitação", "policyAuthHeaderAuthDescription": "Valide um nome e valor de cabeçalho HTTP personalizado em cada solicitação",
"policyAuthHeaderAuthSummary": "Cabeçalho configurado", "policyAuthHeaderAuthSummary": "Cabeçalho configurado",
"policyAuthHeaderName": "Nome do Cabeçalho", "policyAuthHeaderName": "Nome de usuário",
"policyAuthHeaderValue": "Valor esperado", "policyAuthHeaderValue": "Palavra-passe",
"policyAuthSetPasscode": "Definir Código de Acesso", "policyAuthSetPasscode": "Definir Código de Acesso",
"policyAuthSetPincode": "Definir Código PIN", "policyAuthSetPincode": "Definir Código PIN",
"policyAuthSetEmailWhitelist": "Definir Lista de E-mails Permitidos", "policyAuthSetEmailWhitelist": "Definir Lista de E-mails Permitidos",
@@ -903,7 +934,7 @@
"newtVersion": "Versão", "newtVersion": "Versão",
"architecture": "Arquitetura", "architecture": "Arquitetura",
"sites": "sites", "sites": "sites",
"siteWgAnyClients": "Use qualquer cliente do WireGuard para se conectar. Você terá que endereçar recursos internos usando o IP de pares.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Compatível com todos os clientes WireGuard", "siteWgCompatibleAllClients": "Compatível com todos os clientes WireGuard",
"siteWgManualConfigurationRequired": "Configuração manual necessária", "siteWgManualConfigurationRequired": "Configuração manual necessária",
"userErrorNotAdminOrOwner": "Usuário não é administrador ou proprietário", "userErrorNotAdminOrOwner": "Usuário não é administrador ou proprietário",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Criar utilizador Org", "createOrgUser": "Criar utilizador Org",
"actionUpdateOrg": "Atualizar Organização", "actionUpdateOrg": "Atualizar Organização",
"actionRemoveInvitation": "Remover Convite", "actionRemoveInvitation": "Remover Convite",
"actionRemoveUserRole": "Remover Função de Utilizador",
"actionUpdateUser": "Atualizar Usuário", "actionUpdateUser": "Atualizar Usuário",
"actionGetUser": "Obter Usuário", "actionGetUser": "Obter Usuário",
"actionGetOrgUser": "Obter Utilizador da Organização", "actionGetOrgUser": "Obter Utilizador da Organização",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Aplicar Diagrama", "actionApplyBlueprint": "Aplicar Diagrama",
"actionListBlueprints": "Listar Modelos", "actionListBlueprints": "Listar Modelos",
"actionGetBlueprint": "Obter Modelo", "actionGetBlueprint": "Obter Modelo",
"actionCreateOrgWideLauncherView": "Criar Visualização do Lançador para Toda a Organização",
"setupToken": "Configuração do Token", "setupToken": "Configuração do Token",
"setupTokenDescription": "Digite o token de configuração do console do servidor.", "setupTokenDescription": "Digite o token de configuração do console do servidor.",
"setupTokenRequired": "Token de configuração é necessário", "setupTokenRequired": "Token de configuração é necessário",
"actionUpdateSite": "Atualizar Site", "actionUpdateSite": "Atualizar Site",
"actionApproveSite": "Aprovar Site",
"actionRejectSite": "Rejeitar Site",
"actionResetSiteBandwidth": "Redefinir banda da organização", "actionResetSiteBandwidth": "Redefinir banda da organização",
"actionListSiteRoles": "Listar Funções Permitidas do Site", "actionListSiteRoles": "Listar Funções Permitidas do Site",
"actionCreateResource": "Criar Recurso", "actionCreateResource": "Criar Recurso",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Definir Código PIN do Recurso", "actionSetResourcePincode": "Definir Código PIN do Recurso",
"actionSetResourceEmailWhitelist": "Definir Lista Permitida de Emails do Recurso", "actionSetResourceEmailWhitelist": "Definir Lista Permitida de Emails do Recurso",
"actionGetResourceEmailWhitelist": "Obter Lista Permitida de Emails do Recurso", "actionGetResourceEmailWhitelist": "Obter Lista Permitida de Emails do Recurso",
"actionGetResourcePolicy": "Obter Política de Recurso",
"actionUpdateResourcePolicy": "Atualizar Política de Recurso",
"actionSetResourcePolicyUsers": "Definir Utilizadores da Política de Recurso",
"actionSetResourcePolicyRoles": "Definir Papéis da Política de Recurso",
"actionSetResourcePolicyPassword": "Definir Palavra-passe da Política de Recurso",
"actionSetResourcePolicyPincode": "Definir Código PIN da Política de Recurso",
"actionSetResourcePolicyHeaderAuth": "Definir Autenticação de Cabeçalho da Política de Recurso",
"actionSetResourcePolicyWhitelist": "Definir Lista Permitida de Emails da Política de Recurso",
"actionSetResourcePolicyRules": "Definir Regras da Política de Recurso",
"actionCreateTarget": "Criar Alvo", "actionCreateTarget": "Criar Alvo",
"actionDeleteTarget": "Eliminar Alvo", "actionDeleteTarget": "Eliminar Alvo",
"actionGetTarget": "Obter Alvo", "actionGetTarget": "Obter Alvo",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Gerar Token de Acesso", "actionGenerateAccessToken": "Gerar Token de Acesso",
"actionDeleteAccessToken": "Eliminar Token de Acesso", "actionDeleteAccessToken": "Eliminar Token de Acesso",
"actionListAccessTokens": "Listar Tokens de Acesso", "actionListAccessTokens": "Listar Tokens de Acesso",
"actionCreateResourceSessionToken": "Criar Token de Sessão de Recurso",
"actionCreateResourceRule": "Criar Regra de Recurso", "actionCreateResourceRule": "Criar Regra de Recurso",
"actionDeleteResourceRule": "Eliminar Regra de Recurso", "actionDeleteResourceRule": "Eliminar Regra de Recurso",
"actionListResourceRules": "Listar Regras de Recurso", "actionListResourceRules": "Listar Regras de Recurso",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Listar Convites", "actionListInvitations": "Listar Convites",
"actionExportLogs": "Exportar logs", "actionExportLogs": "Exportar logs",
"actionViewLogs": "Visualizar registros", "actionViewLogs": "Visualizar registros",
"actionCreateSiteProvisioningKey": "Criar Chave de Provisionamento do Site",
"actionListSiteProvisioningKeys": "Listar Chaves de Provisionamento do Site",
"actionUpdateSiteProvisioningKey": "Atualizar Chave de Provisionamento do Site",
"actionDeleteSiteProvisioningKey": "Excluir Chave de Provisionamento do Site",
"noneSelected": "Nenhum selecionado", "noneSelected": "Nenhum selecionado",
"orgNotFound2": "Nenhuma organização encontrada.", "orgNotFound2": "Nenhuma organização encontrada.",
"search": "Pesquisar…", "search": "Pesquisar…",
@@ -1486,10 +1535,35 @@
"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",
"idpLastUsed": "Última Utilização",
"otpAuthBack": "Voltar à Palavra-passe", "otpAuthBack": "Voltar à Palavra-passe",
"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",
"commandPaletteTitle": "Paleta de Comando",
"commandPaletteDescription": "Pesquisar por páginas, organizações, recursos e ações",
"commandPaletteSearchPlaceholder": "Pesquisar páginas, recursos, ações...",
"commandPaletteNoResults": "Nenhum resultado encontrado.",
"commandPaletteSearching": "Buscando...",
"commandPaletteNavigation": "Navegação",
"commandPaletteOrganizations": "Organizações",
"commandPaletteSites": "Sites",
"commandPaletteResources": "Recursos",
"commandPaletteUsers": "Utilizadores",
"commandPaletteClients": "Clientes de Máquina",
"commandPaletteActions": "Ações",
"commandPaletteCreateSite": "Criar Site",
"commandPaletteCreateProxyResource": "Criar Recurso Público",
"commandPaletteCreatePrivateResource": "Criar Recurso Privado",
"commandPaletteCreateUser": "Criar Usuário",
"commandPaletteCreateApiKey": "Criar Chave API",
"commandPaletteCreateMachineClient": "Criar Cliente de Máquina",
"commandPaletteCreateAlertRule": "Criar Regra de Alerta",
"commandPaletteCreateIdentityProvider": "Criar Provedor de Identidade",
"commandPaletteToggleTheme": "Alternar Tema",
"commandPaletteChooseOrganization": "Escolher Organização",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Não foi possível ativar 2FA", "otpErrorEnable": "Não foi possível ativar 2FA",
"otpErrorEnableDescription": "Ocorreu um erro ao ativar 2FA", "otpErrorEnableDescription": "Ocorreu um erro ao ativar 2FA",
"otpSetupCheckCode": "Por favor, insira um código de 6 dígitos", "otpSetupCheckCode": "Por favor, insira um código de 6 dígitos",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Gestão", "sidebarManagement": "Gestão",
"sidebarBillingAndLicenses": "Faturamento e Licenças", "sidebarBillingAndLicenses": "Faturamento e Licenças",
"sidebarLogsAnalytics": "Análises", "sidebarLogsAnalytics": "Análises",
"commandSites": "Sites",
"commandActionModeInfo": "Digite \">\" Para Abrir Modo de Ação",
"commandResources": "Recursos",
"commandProxyResources": "Recursos Públicos",
"commandClientResources": "Recursos Privados",
"commandClients": "Clientes",
"commandUserDevices": "Dispositivos do Usuário",
"commandMachineClients": "Clientes de Máquina",
"commandDomains": "Domínios",
"commandRemoteExitNodes": "Nodos Remotos",
"commandTeam": "Equipe",
"commandUsers": "Utilizadores",
"commandRoles": "Papéis",
"commandInvitations": "Convites",
"commandPolicies": "Políticas Compartilhadas",
"commandResourcePolicies": "Políticas de Recursos Públicos",
"commandIdentityProviders": "Provedores de Identidade",
"commandApprovals": "Pedidos de Aprovação",
"commandShareableLinks": "Links Compartilháveis",
"commandOrganization": "Organização",
"commandLogsAndAnalytics": "Logs e Análises",
"commandLogsAnalytics": "Análises",
"commandLogsRequest": "Registros de Pedidos HTTP",
"commandLogsAccess": "Logs de Autenticação",
"commandLogsAction": "Logs de Ações do Administrador",
"commandLogsConnection": "Logs da Conexão",
"commandLogsStreaming": "Transmissão de Eventos",
"commandManagement": "Gestão",
"commandAlerting": "Alertas",
"commandProvisioning": "Providência",
"commandBluePrints": "Plantas",
"commandApiKeys": "Chaves API",
"commandBillingAndLicenses": "Faturamento e Licenças",
"commandBilling": "Faturamento",
"commandEnterpriseLicenses": "Licenças",
"commandSettings": "Configurações",
"commandLauncher": "Inicializador",
"commandResourceLauncher": "Inicializador de Recurso",
"commandSearchResults": "Resultados da Pesquisa",
"alertingTitle": "Alertas", "alertingTitle": "Alertas",
"alertingDescription": "Defina fontes, gatilhos e ações para notificações", "alertingDescription": "Defina fontes, gatilhos e ações para notificações",
"alertingRules": "Regras de alerta", "alertingRules": "Regras de alerta",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Subdomínio: {subdomain}", "domainPickerSubdomain": "Subdomínio: {subdomain}",
"domainPickerNamespace": "Namespace: {namespace}", "domainPickerNamespace": "Namespace: {namespace}",
"domainPickerShowMore": "Mostrar Mais", "domainPickerShowMore": "Mostrar Mais",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Selecionar Região", "regionSelectorTitle": "Selecionar Região",
"domainPickerRemoteExitNodeWarning": "Domínios fornecidos não são suportados quando os sites se conectam a nós de saída remota. Para recursos disponíveis em nós remotos, use um domínio personalizado.", "domainPickerRemoteExitNodeWarning": "Domínios fornecidos não são suportados quando os sites se conectam a nós de saída remota. Para recursos disponíveis em nós remotos, use um domínio personalizado.",
"regionSelectorInfo": "Selecionar uma região nos ajuda a fornecer melhor desempenho para sua localização. Você não precisa estar na mesma região que seu servidor.", "regionSelectorInfo": "Selecionar uma região nos ajuda a fornecer melhor desempenho para sua localização. Você não precisa estar na mesma região que seu servidor.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Domínios", "billingDomains": "Domínios",
"billingOrganizations": "Órgãos", "billingOrganizations": "Órgãos",
"billingRemoteExitNodes": "Nós remotos", "billingRemoteExitNodes": "Nós remotos",
"billingPublicResources": "Recursos Públicos",
"billingPrivateResources": "Recursos Privados",
"billingMachineClients": "Clientes de Máquina",
"billingNoLimitConfigured": "Nenhum limite configurado", "billingNoLimitConfigured": "Nenhum limite configurado",
"billingEstimatedPeriod": "Período Estimado de Cobrança", "billingEstimatedPeriod": "Período Estimado de Cobrança",
"billingIncludedUsage": "Uso Incluído", "billingIncludedUsage": "Uso Incluído",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Quantos usuários você pode usar", "billingUsersInfo": "Quantos usuários você pode usar",
"billingDomainInfo": "Quantos domínios você pode usar", "billingDomainInfo": "Quantos domínios você pode usar",
"billingRemoteExitNodesInfo": "Quantos nós remotos você pode usar", "billingRemoteExitNodesInfo": "Quantos nós remotos você pode usar",
"billingPublicResourcesInfo": "Quantos recursos públicos você pode usar",
"billingPrivateResourcesInfo": "Quantos recursos privados você pode usar",
"billingMachineClientsInfo": "Quantos clientes de máquina você pode usar",
"billingLicenseKeys": "Chaves de Licença", "billingLicenseKeys": "Chaves de Licença",
"billingLicenseKeysDescription": "Gerenciar suas subscrições de chave de licença", "billingLicenseKeysDescription": "Gerenciar suas subscrições de chave de licença",
"billingLicenseSubscription": "Assinatura de Licença", "billingLicenseSubscription": "Assinatura de Licença",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Sub-rede", "subnetPlaceholder": "Sub-rede",
"addressDescription": "O endereço interno do cliente. Deve estar dentro da sub-rede da organização.", "addressDescription": "O endereço interno do cliente. Deve estar dentro da sub-rede da organização.",
"selectSites": "Selecionar sites", "selectSites": "Selecionar sites",
"selectLabels": "Selecionar etiquetas",
"sitesDescription": "O cliente terá conectividade com os sites selecionados", "sitesDescription": "O cliente terá conectividade com os sites selecionados",
"clientInstallOlm": "Instalar Olm", "clientInstallOlm": "Instalar Olm",
"clientInstallOlmDescription": "Execute o Olm em seu sistema", "clientInstallOlmDescription": "Execute o Olm em seu sistema",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Público", "resourcesTableProxyResources": "Público",
"resourcesTableClientResources": "Privado", "resourcesTableClientResources": "Privado",
"resourcesTableNoProxyResourcesFound": "Nenhum recurso de proxy encontrado.", "resourcesTableNoProxyResourcesFound": "Nenhum recurso de proxy encontrado.",
"resourcesTableNoInternalResourcesFound": "Nenhum recurso interno encontrado.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Destino", "resourcesTableDestination": "Destino",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Endereço do Pseudônimo", "resourcesTableAliasAddress": "Endereço do Pseudônimo",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Cancelar", "editInternalResourceDialogCancel": "Cancelar",
"editInternalResourceDialogSaveResource": "Guardar Recurso", "editInternalResourceDialogSaveResource": "Guardar Recurso",
"editInternalResourceDialogSuccess": "Sucesso", "editInternalResourceDialogSuccess": "Sucesso",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Recurso interno atualizado com sucesso", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Erro", "editInternalResourceDialogError": "Erro",
"editInternalResourceDialogFailedToUpdateInternalResource": "Falha ao atualizar recurso interno", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Nome é obrigatório", "editInternalResourceDialogNameRequired": "Nome é obrigatório",
"editInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres", "editInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
"editInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1", "editInternalResourceDialogProxyPortMin": "Porta de proxy deve ser pelo menos 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.", "editInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.",
"createInternalResourceDialogNoSitesAvailable": "Nenhum Site Disponível", "createInternalResourceDialogNoSitesAvailable": "Nenhum Site Disponível",
"createInternalResourceDialogNoSitesAvailableDescription": "Você precisa ter pelo menos um site Newt com uma sub-rede configurada para criar recursos internos.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Fechar", "createInternalResourceDialogClose": "Fechar",
"createInternalResourceDialogCreateClientResource": "Criar Recurso Privado", "createInternalResourceDialogCreateClientResource": "Criar Recurso Privado",
"createInternalResourceDialogCreateClientResourceDescription": "Criar um novo recurso que só será acessível para clientes conectados à organização", "createInternalResourceDialogCreateClientResourceDescription": "Criar um novo recurso que só será acessível para clientes conectados à organização",
"privateResourceGeneralDescription": "Configure o nome, identificador e outras configurações gerais de recursos.",
"privateResourceCreatePageSeeAll": "Ver Todos os Recursos Privados",
"privateResourceAllowIcmpPing": "Permitir ICMP Ping",
"privateResourceNetworkAccess": "Acesso à Rede",
"privateResourceNetworkAccessDescription": "Controlar o acesso à porta TCP/UDP e se o ICMP ping é permitido para este recurso.",
"hostSettings": "Configurações do Host",
"cidrSettings": "Configurações CIDR",
"createInternalResourceDialogResourceProperties": "Propriedades do Recurso", "createInternalResourceDialogResourceProperties": "Propriedades do Recurso",
"createInternalResourceDialogName": "Nome", "createInternalResourceDialogName": "Nome",
"createInternalResourceDialogSite": "Site", "createInternalResourceDialogSite": "Site",
"selectSite": "Selecionar site...", "selectSite": "Selecionar site...",
"multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}", "multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}",
"labelsSelectorLabelsCount": "{count, plural, one {# rótulo} other {# rótulos}}",
"noSitesFound": "Nenhum site encontrado.", "noSitesFound": "Nenhum site encontrado.",
"createInternalResourceDialogProtocol": "Protocolo", "createInternalResourceDialogProtocol": "Protocolo",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Cancelar", "createInternalResourceDialogCancel": "Cancelar",
"createInternalResourceDialogCreateResource": "Criar Recurso", "createInternalResourceDialogCreateResource": "Criar Recurso",
"createInternalResourceDialogSuccess": "Sucesso", "createInternalResourceDialogSuccess": "Sucesso",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Recurso interno criado com sucesso", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Erro", "createInternalResourceDialogError": "Erro",
"createInternalResourceDialogFailedToCreateInternalResource": "Falha ao criar recurso interno", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Nome é obrigatório", "createInternalResourceDialogNameRequired": "Nome é obrigatório",
"createInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres", "createInternalResourceDialogNameMaxLength": "Nome deve ser inferior a 255 caracteres",
"createInternalResourceDialogPleaseSelectSite": "Por favor, selecione um site", "createInternalResourceDialogPleaseSelectSite": "Por favor, selecione um site",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "A faixa CIDR do recurso na rede do site.", "createInternalResourceDialogDestinationCidrDescription": "A faixa CIDR do recurso na rede do site.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.", "createInternalResourceDialogAliasDescription": "Um alias de DNS interno opcional para este recurso.",
"internalResourceAliasLocalWarning": "Os aliases terminando em .local podem causar problemas de resolução devido ao mDNS em algumas redes.",
"internalResourceDownstreamSchemeRequired": "Esquema é obrigatório para recursos HTTP", "internalResourceDownstreamSchemeRequired": "Esquema é obrigatório para recursos HTTP",
"internalResourceHttpPortRequired": "Porta de destino é obrigatória para recursos HTTP", "internalResourceHttpPortRequired": "Porta de destino é obrigatória para recursos HTTP",
"siteConfiguration": "Configuração", "siteConfiguration": "Configuração",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Nós remotos", "sidebarRemoteExitNodes": "Nós remotos",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Chave Secreta", "remoteExitNodeSecretKey": "Chave Secreta",
"remoteExitNodeNetworkingTitle": "Configurações de Rede",
"remoteExitNodeNetworkingDescription": "Configure como este nó de saída remoto roteia o tráfego e quais sites preferem se conectar através dele. Recursos avançados para serem usados com configurações de rede de backhaul.",
"remoteExitNodeNetworkingSave": "Guardar Configurações",
"remoteExitNodeNetworkingSaveSuccessTitle": "Configurações de rede salvas",
"remoteExitNodeNetworkingSaveSuccessDescription": "As configurações de rede foram atualizadas com sucesso.",
"remoteExitNodeNetworkingSaveError": "Falha ao guardar as configurações de rede",
"remoteExitNodeNetworkingSubnetsTitle": "Sub-redes Remotas",
"remoteExitNodeNetworkingSubnetsDescription": "Defina os intervalos de CIDR que este nó de saída remoto irá rotear o tráfego. Digite um CIDR válido (por exemplo, <code>10.0.0.0/8</code>) e pressione Enter para adicionar.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Adicione um intervalo de CIDR (por exemplo, 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Falha ao carregar sub-redes",
"remoteExitNodeNetworkingLabelsTitle": "Etiquetas de Preferência",
"remoteExitNodeNetworkingLabelsDescription": "Os sites com essas etiquetas serão forçados a se conectar através deste nó de saída remoto.",
"remoteExitNodeNetworkingLabelsButtonText": "Selecionar etiquetas...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Pesquisar etiquetas...",
"remoteExitNodeNetworkingLabelsLoadError": "Falha ao carregar etiquetas",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Criar Nó Remoto", "title": "Criar Nó Remoto",
"description": "Crie um novo nó de retransmissão e proxy servidor auto-hospedado", "description": "Crie um novo nó de retransmissão e proxy servidor auto-hospedado",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Nenhum nó está disponível para esta organização. Crie um nó primeiro para usar sites locais.", "noRemoteExitNodesAvailableDescription": "Nenhum nó está disponível para esta organização. Crie um nó primeiro para usar sites locais.",
"exitNode": "Nodo de Saída", "exitNode": "Nodo de Saída",
"country": "País", "country": "País",
"countryIsNot": "País Não é",
"rulesMatchCountry": "Atualmente baseado no IP de origem", "rulesMatchCountry": "Atualmente baseado no IP de origem",
"region": "Região", "region": "Região",
"selectRegion": "Selecionar região", "selectRegion": "Selecionar região",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Provedor Google OAuth2/OIDC", "idpGoogleDescription": "Provedor Google OAuth2/OIDC",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Sub-rede", "subnet": "Sub-rede",
"utilitySubnet": "Sub-rede de utilidade",
"subnetDescription": "A sub-rede para a configuração de rede dessa organização.", "subnetDescription": "A sub-rede para a configuração de rede dessa organização.",
"customDomain": "Domínio Personalizado", "customDomain": "Domínio Personalizado",
"authPage": "Páginas de Autenticação", "authPage": "Páginas de Autenticação",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Configuração de autenticação de dois fatores é necessária. Por favor, entre novamente via {dashboardUrl}/auth/login conclua este passo. Em seguida, volte aqui.", "twoFactorSetupRequired": "Configuração de autenticação de dois fatores é necessária. Por favor, entre novamente via {dashboardUrl}/auth/login conclua este passo. Em seguida, volte aqui.",
"additionalSecurityRequired": "Segurança adicional necessária", "additionalSecurityRequired": "Segurança adicional necessária",
"organizationRequiresAdditionalSteps": "Esta organização requer etapas de segurança adicionais antes que você possa acessar os recursos.", "organizationRequiresAdditionalSteps": "Esta organização requer etapas de segurança adicionais antes que você possa acessar os recursos.",
"sessionExpired": "Sessão Expirada",
"sessionExpiredReauthRequired": "Sua sessão expirou conforme a política de segurança da sua organização. Faça uma nova autenticação para continuar.",
"reauthenticate": "Reautenticar",
"completeTheseSteps": "Conclua estas etapas", "completeTheseSteps": "Conclua estas etapas",
"enableTwoFactorAuthentication": "Ativar autenticação de dois fatores", "enableTwoFactorAuthentication": "Ativar autenticação de dois fatores",
"completeSecuritySteps": "Passos de segurança completos", "completeSecuritySteps": "Passos de segurança completos",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Endereço de origem", "sourceAddress": "Endereço de origem",
"destinationAddress": "Endereço de destino", "destinationAddress": "Endereço de destino",
"duration": "Duração", "duration": "Duração",
"licenseRequiredToUse": "Uma licença <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> ou <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> é necessária para usar este recurso. <bookADemoLink>Reserve um teste de demonstração ou POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "O <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> é necessário para usar este recurso. Este recurso também está disponível no <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Reserve uma demonstração ou avaliação POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Resolvedor de Certificado", "certResolver": "Resolvedor de Certificado",
"certResolverDescription": "Selecione o resolvedor de certificados para este recurso.", "certResolverDescription": "Selecione o resolvedor de certificados para este recurso.",
"selectCertResolver": "Selecionar solucionador de certificado", "selectCertResolver": "Selecionar solucionador de certificado",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "ID da organização ou domínio está faltando", "orgOrDomainIdMissing": "ID da organização ou domínio está faltando",
"loadingDNSRecords": "Carregando registros DNS...", "loadingDNSRecords": "Carregando registros DNS...",
"olmUpdateAvailableInfo": "Uma versão atualizada do Olm está disponível. Atualize para a versão mais recente para ter a melhor experiência.", "olmUpdateAvailableInfo": "Uma versão atualizada do Olm está disponível. Atualize para a versão mais recente para ter a melhor experiência.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Uma versão atualizada está disponível. Por favor, atualize para a versão mais recente para uma melhor experiência.",
"client": "Cliente", "client": "Cliente",
"proxyProtocol": "Configurações de Protocolo Proxy", "proxyProtocol": "Configurações de Protocolo Proxy",
"proxyProtocolDescription": "Configurar o protocolo proxy para preservar endereços IP do cliente para serviços TCP.", "proxyProtocolDescription": "Configurar o protocolo proxy para preservar endereços IP do cliente para serviços TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Adicionar Usuários", "editInternalResourceDialogAddUsers": "Adicionar Usuários",
"editInternalResourceDialogAddClients": "Adicionar Clientes", "editInternalResourceDialogAddClients": "Adicionar Clientes",
"editInternalResourceDialogDestinationLabel": "Destino", "editInternalResourceDialogDestinationLabel": "Destino",
"editInternalResourceDialogDestinationDescription": "Especifique o endereço de destino para o recurso interno. Isso pode ser um nome de host, endereço IP ou intervalo CIDR, dependendo do modo selecionado. Opcionalmente, defina um alias interno de DNS para facilitar a identificação.", "editInternalResourceDialogDestinationDescription": "Configure como os clientes acessam este recurso.",
"internalResourceFormMultiSiteRoutingHelp": "Selecionar múltiplos sites permite roteamento resiliente e failover para alta disponibilidade.", "internalResourceFormMultiSiteRoutingHelp": "Selecionar múltiplos sites permite roteamento resiliente e failover para alta disponibilidade.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Saiba mais", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Saiba mais",
"editInternalResourceDialogPortRestrictionsDescription": "Restrinja o acesso a portas TCP/UDP específicas ou permita/bloqueie todas as portas.", "editInternalResourceDialogPortRestrictionsDescription": "Restrinja o acesso a portas TCP/UDP específicas ou permita/bloqueie todas as portas.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Lista de E-mails Permitidos", "memberPortalEmailWhitelist": "Lista de E-mails Permitidos",
"memberPortalResourceDisabled": "Recurso Desativado", "memberPortalResourceDisabled": "Recurso Desativado",
"memberPortalShowingResources": "Mostrando {start}-{end} de {total} recursos", "memberPortalShowingResources": "Mostrando {start}-{end} de {total} recursos",
"resourceLauncherTitle": "Lançador de Recursos",
"resourceSidebarLauncherTitle": "Inicializador",
"resourceLauncherDescription": "Veja todos os recursos disponíveis e inicie-os de um único local",
"resourceLauncherSearchPlaceholder": "Procurar recursos...",
"resourceLauncherDefaultView": "Padrão",
"resourceLauncherSaveView": "Salvar Visualização",
"resourceLauncherSaveToCurrentView": "Salvar na Visualização Atual",
"resourceLauncherSaveDefaultPersonal": "Salvar para mim",
"resourceLauncherResetView": "Redefinir Visualização",
"resourceLauncherResetSystemDefault": "Redefinir para o padrão do sistema",
"resourceLauncherSystemDefaultRestored": "Padrão do sistema restaurado",
"resourceLauncherSystemDefaultRestoredDescription": "A visualização padrão foi redefinida para as configurações originais.",
"resourceLauncherSaveAsNewView": "Salvar como Nova Visualização",
"resourceLauncherSaveAsNewViewDescription": "Dê um nome a esta visualização para salvar os filtros e layout atuais.",
"resourceLauncherSaveForEveryone": "Salvar para Todos",
"resourceLauncherSaveForEveryoneDescription": "Compartilhe esta visualização com todos os membros da organização. Quando desmarcado, a visualização é visível apenas para você.",
"resourceLauncherMakePersonal": "Tornar Pessoal",
"resourceLauncherFilter": "Filtro",
"resourceLauncherFilterWithCount": "Filtro, {count} aplicado",
"resourceLauncherSort": "Ordenar",
"resourceLauncherSortAscending": "Ordenar ascendente",
"resourceLauncherSortDescending": "Ordenar descendente",
"resourceLauncherSettings": "Configurações",
"resourceLauncherGroupBy": "Agrupar por",
"resourceLauncherGroupBySite": "Site",
"resourceLauncherGroupByLabel": "Marcador",
"resourceLauncherGroupByNone": "Nenhum",
"resourceLauncherLayout": "Layout",
"resourceLauncherLayoutGrid": "Grade",
"resourceLauncherLayoutList": "Lista",
"resourceLauncherShowLabels": "Mostrar Marcadores",
"resourceLauncherShowSiteTags": "Mostrar Etiquetas de Site",
"resourceLauncherShowRecents": "Mostrar Recents",
"resourceLauncherDeleteView": "Excluir Visualização",
"resourceLauncherDeleteViewTitle": "Excluir Visualização",
"resourceLauncherDeleteViewQuestion": "Tem certeza de que deseja excluir esta visualização de inicializador?",
"resourceLauncherDeleteViewConfirm": "Excluir Visualização",
"resourceLauncherViewAsAdmin": "Visualizar como Administrador",
"resourceLauncherResourceDetailsDescription": "Informações de conexão e status para este recurso.",
"resourceLauncherResourceDetails": "Detalhes do Recurso",
"resourceLauncherAuthMethodsDescription": "Métodos de autenticação habilitados para este recurso.",
"resourceLauncherPrivateClientRequired": "Conecte com um cliente no seu dispositivo para acessar este recurso privadamente.",
"resourceLauncherPrivateClientRequiredTitle": "Conexão do Cliente Obrigatória",
"resourceLauncherDownloadClient": "Baixar cliente",
"resourceLauncherFailedToLoadDetails": "Não foi possível carregar os detalhes do recurso. Você pode não ter mais acesso a este recurso.",
"resourceLauncherNoPortRestrictions": "Sem restrições de porta",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Sem Etiqueta",
"resourceLauncherNoSite": "Sem Site",
"resourceLauncherNoResourcesInGroup": "Nenhum recurso neste grupo",
"resourceLauncherEmptyStateTitle": "Nenhum Recurso Disponível",
"resourceLauncherEmptyStateDescription": "Você não tem acesso a nenhum recurso ainda. Entre em contato com seu administrador para solicitar acesso.",
"resourceLauncherEmptyStateNoResultsTitle": "Nenhum Recurso Encontrado",
"resourceLauncherEmptyStateNoResultsDescription": "Nenhum recurso corresponde à sua busca ou filtros atuais. Experimente ajustá-los para encontrar o que está procurando.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Nenhum recurso corresponde a \"{query}\". Tente ajustar sua busca ou limpar os filtros para ver todos os recursos.",
"resourceLauncherSearchFirstTitle": "Pesquisar ou Filtrar para Navegar",
"resourceLauncherSearchFirstDescription": "Você tem acesso a muitos recursos. Use a pesquisa ou filtre por site ou etiqueta para encontrar o que precisa.",
"resourceLauncherSiteGroupingDisabled": "Agrupamento de site indisponível nesta escala. Filtrar por site para agrupar um conjunto menor.",
"resourceLauncherLabelGroupingDisabled": "Agrupamento de etiquetas indisponível nesta escala.",
"resourceLauncherCompactModeHint": "Mostrando uma lista simplificada para navegação mais rápida. Use pesquisa ou filtros para restringir os resultados.",
"resourceLauncherCompactGroupingHint": "Aplique filtros de site ou etiqueta para habilitar o agrupamento.",
"resourceLauncherCopiedToClipboard": "Copiado para a área de transferência",
"resourceLauncherCopiedAccessDescription": "O acesso ao recurso foi copiado para sua área de transferência.",
"resourceLauncherViewNamePlaceholder": "Nome da Visualização",
"resourceLauncherViewNameLabel": "Nome da Visualização",
"resourceLauncherViewSaved": "Visualização salva",
"resourceLauncherViewSavedDescription": "Sua visualização do lançador foi salva.",
"resourceLauncherViewSaveFailed": "Falha ao salvar visualização",
"resourceLauncherViewSaveFailedDescription": "Não foi possível salvar a visualização do lançador. Por favor, tente novamente.",
"resourceLauncherViewDeleted": "Visualização excluída",
"resourceLauncherViewDeletedDescription": "A visualização do lançador foi excluída.",
"resourceLauncherViewDeleteFailed": "Falha ao excluir visualização",
"resourceLauncherViewDeleteFailedDescription": "Não foi possível excluir a visualização do lançador. Por favor, tente novamente.",
"memberPortalPrevious": "Anterior", "memberPortalPrevious": "Anterior",
"memberPortalNext": "Próximo", "memberPortalNext": "Próximo",
"httpSettings": "Configurações HTTP", "httpSettings": "Configurações HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "Chave privada é necessária", "sshPrivateKeyRequired": "Chave privada é necessária",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Digite sua senha VNC para conectar", "vncSignInDescription": "Digite suas credenciais VNC para conectar",
"vncUsernameOptional": "Nome de usuário (opcional)",
"vncPasswordOptional": "Senha (opcional)", "vncPasswordOptional": "Senha (opcional)",
"vncNoResourceTarget": "Nenhum alvo de recurso disponível", "vncNoResourceTarget": "Nenhum alvo de recurso disponível",
"vncFailedToLoadNovnc": "Falha ao carregar noVNC", "vncFailedToLoadNovnc": "Falha ao carregar noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Falha no upload", "rdpUploadFailed": "Falha no upload",
"rdpUnicodeKeyboardMode": "Modo de teclado Unicode", "rdpUnicodeKeyboardMode": "Modo de teclado Unicode",
"sessionToolbarShow": "Mostrar barra de ferramentas", "sessionToolbarShow": "Mostrar barra de ferramentas",
"sessionToolbarHide": "Ocultar barra de ferramentas" "sessionToolbarHide": "Ocultar barra de ferramentas",
"actionUpdateSiteApprovals": "Atualizar Aprovações do Site"
} }
+248 -20
View File
@@ -66,9 +66,15 @@
"local": "Локальный", "local": "Локальный",
"edit": "Редактировать", "edit": "Редактировать",
"siteConfirmDelete": "Подтвердить удаление сайта", "siteConfirmDelete": "Подтвердить удаление сайта",
"siteConfirmDeleteAndResources": "Подтвердите удаление сайта и ресурсов",
"siteDelete": "Удалить сайт", "siteDelete": "Удалить сайт",
"siteDeleteAndResources": "Удалить сайт и ресурсы",
"siteMessageRemove": "После удаления сайт больше не будет доступен. Все цели, связанные с сайтом, также будут удалены.", "siteMessageRemove": "После удаления сайт больше не будет доступен. Все цели, связанные с сайтом, также будут удалены.",
"siteMessageRemoveAndResources": "Это навсегда удалит все общественные и частные ресурсы, связанные с этим сайтом, даже если ресурс также связан с другими сайтами.",
"siteQuestionRemove": "Вы уверены, что хотите удалить сайт из организации?", "siteQuestionRemove": "Вы уверены, что хотите удалить сайт из организации?",
"siteQuestionRemoveAndResources": "Вы уверены, что хотите удалить этот сайт и все связанные с ним ресурсы?",
"sitesTableDeleteSite": "Удалить сайт",
"sitesTableDeleteSiteAndResources": "Удалить сайт и ресурсы",
"siteManageSites": "Управление сайтами", "siteManageSites": "Управление сайтами",
"siteDescription": "Создание и управление сайтами, чтобы включить подключение к приватным сетям", "siteDescription": "Создание и управление сайтами, чтобы включить подключение к приватным сетям",
"sitesBannerTitle": "Подключить любую сеть", "sitesBannerTitle": "Подключить любую сеть",
@@ -117,6 +123,16 @@
"siteUpdated": "Сайт обновлён", "siteUpdated": "Сайт обновлён",
"siteUpdatedDescription": "Сайт был успешно обновлён.", "siteUpdatedDescription": "Сайт был успешно обновлён.",
"siteGeneralDescription": "Настройте общие параметры для этого сайта", "siteGeneralDescription": "Настройте общие параметры для этого сайта",
"siteRestartTitle": "Перезагрузить сайт",
"siteRestartDescription": "Перезапустите туннель WireGuard для этого сайта. Это кратковременно прервет соединение.",
"siteRestartBody": "Используйте это, если туннель сайта не работает должным образом и вам нужно принудительно переподключиться без перезапуска хоста.",
"siteRestartButton": "Перезагрузить сайт",
"siteRestartDialogMessage": "Вы уверены, что хотите перезапустить туннель WireGuard для <b>{name}</b>? Сайт кратковременно потеряет соединение.",
"siteRestartWarning": "Сайт кратковременно отключится во время перезапуска туннеля.",
"siteRestarted": "Сайт перезапущен",
"siteRestartedDescription": "Туннель WireGuard был перезапущен.",
"siteErrorRestart": "Не удалось перезапустить сайт",
"siteErrorRestartDescription": "Произошла ошибка во время перезапуска сайта.",
"siteSettingDescription": "Настройка параметров на сайте", "siteSettingDescription": "Настройка параметров на сайте",
"siteResourcesTab": "Ресурсы", "siteResourcesTab": "Ресурсы",
"siteResourcesNoneOnSite": "На этом сайте пока нет публичных или частных ресурсов.", "siteResourcesNoneOnSite": "На этом сайте пока нет публичных или частных ресурсов.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Подтвердить удаление общей ссылки", "shareDeleteConfirm": "Подтвердить удаление общей ссылки",
"shareQuestionRemove": "Вы уверены, что хотите удалить эту общую ссылку?", "shareQuestionRemove": "Вы уверены, что хотите удалить эту общую ссылку?",
"shareMessageRemove": "После удаления ссылка перестанет работать, и все, кто ее использует, потеряют доступ к ресурсу.", "shareMessageRemove": "После удаления ссылка перестанет работать, и все, кто ее использует, потеряют доступ к ресурсу.",
"shareTokenDescription": "Токен доступа может быть передан двумя способами: как параметр запроса или в заголовках запроса. Они должны быть переданы от клиента по каждому запросу для аутентифицированного доступа.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Токен доступа", "accessToken": "Токен доступа",
"usageExamples": "Примеры использования", "usageExamples": "Примеры использования",
"tokenId": "ID токена", "tokenId": "ID токена",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Заголовок (необязательно)", "shareTitleOptional": "Заголовок (необязательно)",
"sharePathOptional": "Путь (необязательно)", "sharePathOptional": "Путь (необязательно)",
"sharePathDescription": "Ссылка перенаправит пользователей на этот путь после аутентификации.", "sharePathDescription": "Ссылка перенаправит пользователей на этот путь после аутентификации.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Срок действия", "expireIn": "Срок действия",
"neverExpire": "Бессрочный доступ", "neverExpire": "Бессрочный доступ",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Срок действия - это период, в течение которого ссылка будет работать и предоставлять доступ к ресурсу. После этого времени ссылка перестанет работать, и пользователи, использовавшие эту ссылку, потеряют доступ к ресурсу.", "shareExpireDescription": "Срок действия - это период, в течение которого ссылка будет работать и предоставлять доступ к ресурсу. После этого времени ссылка перестанет работать, и пользователи, использовавшие эту ссылку, потеряют доступ к ресурсу.",
"shareSeeOnce": "Вы сможете увидеть эту ссылку только один раз. Обязательно скопируйте ее.", "shareSeeOnce": "Вы сможете увидеть эту ссылку только один раз. Обязательно скопируйте ее.",
"shareAccessHint": "Любой, у кого есть эта ссылка, может получить доступ к ресурсу. Делитесь ею с осторожностью.", "shareAccessHint": "Любой, у кого есть эта ссылка, может получить доступ к ресурсу. Делитесь ею с осторожностью.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Прокси запросы через необработанный TCP/UDP с использованием номера порта. Требуется подключение сайтов к удаленному узлу.", "resourceRawDescriptionCloud": "Прокси запросы через необработанный TCP/UDP с использованием номера порта. Требуется подключение сайтов к удаленному узлу.",
"resourceCreate": "Создание ресурса", "resourceCreate": "Создание ресурса",
"resourceCreateDescription": "Следуйте инструкциям ниже для создания нового ресурса", "resourceCreateDescription": "Следуйте инструкциям ниже для создания нового ресурса",
"resourcePublicCreate": "Создать публичный ресурс",
"resourcePublicCreateDescription": "Следуйте инструкциям ниже, чтобы создать новый публичный ресурс, доступный через веб-браузер",
"resourceCreateGeneralDescription": "Настройте основные параметры ресурса, включая его имя и тип", "resourceCreateGeneralDescription": "Настройте основные параметры ресурса, включая его имя и тип",
"resourceSeeAll": "Посмотреть все ресурсы", "resourceSeeAll": "Посмотреть все ресурсы",
"resourceCreateGeneral": "Общие", "resourceCreateGeneral": "Общие",
@@ -431,8 +455,14 @@
"provisioningManage": "Подготовка", "provisioningManage": "Подготовка",
"provisioningDescription": "Управляйте предоставленными ключами и проверять непроверенные сайты, ожидающие утверждения.", "provisioningDescription": "Управляйте предоставленными ключами и проверять непроверенные сайты, ожидающие утверждения.",
"pendingSites": "Ожидающие сайты", "pendingSites": "Ожидающие сайты",
"siteApproveSuccess": "Сайт успешно утвержден", "siteApproveSuccess": "Сайт и связанные ресурсы успешно одобрены",
"siteApproveError": "Ошибка при утверждении сайта", "siteApproveError": "Ошибка при утверждении сайта",
"siteReject": "Отклонить сайт",
"siteQuestionReject": "Вы уверены, что хотите отклонить этот сайт?",
"siteMessageReject": "Этот процесс окончательно удалит сайт и все связанные с ним ресурсы, которые еще ожидают.",
"siteConfirmReject": "Подтвердите отклонение сайта",
"siteRejectSuccess": "Сайт успешно отклонен",
"siteRejectError": "Ошибка при отклонении сайта",
"provisioningKeys": "Ключи подготовки", "provisioningKeys": "Ключи подготовки",
"searchProvisioningKeys": "Поиск подготовительных ключей...", "searchProvisioningKeys": "Поиск подготовительных ключей...",
"provisioningKeysAdd": "Сгенерировать ключ подготовки", "provisioningKeysAdd": "Сгенерировать ключ подготовки",
@@ -448,8 +478,8 @@
"provisioningKeysSave": "Сохранить ключ подготовки", "provisioningKeysSave": "Сохранить ключ подготовки",
"provisioningKeysSaveDescription": "Вы сможете увидеть это только один раз. Скопируйте его в безопасное место.", "provisioningKeysSaveDescription": "Вы сможете увидеть это только один раз. Скопируйте его в безопасное место.",
"provisioningKeysErrorCreate": "Ошибка при создании ключа подготовки", "provisioningKeysErrorCreate": "Ошибка при создании ключа подготовки",
"provisioningKeysList": "Новый подготовительный ключ", "provisioningKeysList": "Новый ключ для подготовки",
"provisioningKeysMaxBatchSize": "Макс. размер партии", "provisioningKeysMaxBatchSize": "Максимальный размер партии",
"provisioningKeysUnlimitedBatchSize": "Неограниченный размер партии (без ограничений)", "provisioningKeysUnlimitedBatchSize": "Неограниченный размер партии (без ограничений)",
"provisioningKeysMaxBatchUnlimited": "Неограниченный", "provisioningKeysMaxBatchUnlimited": "Неограниченный",
"provisioningKeysMaxBatchSizeInvalid": "Введите максимальный размер пакета (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Введите максимальный размер пакета (11,000,000).",
@@ -597,7 +627,8 @@
"idpNameInternal": "Внутренний", "idpNameInternal": "Внутренний",
"emailInvalid": "Неверный адрес Email", "emailInvalid": "Неверный адрес Email",
"inviteValidityDuration": "Пожалуйста, выберите продолжительность", "inviteValidityDuration": "Пожалуйста, выберите продолжительность",
"accessRoleSelectPlease": "Пожалуйста, выберите роль", "accessRoleSelectPlease": "Пользователь должен принадлежать хотя бы к одной роли.",
"accessRoleRequired": "Требуется роль",
"removeOwnAdminRoleConfirmTitle": "Удалить доступ администратора?", "removeOwnAdminRoleConfirmTitle": "Удалить доступ администратора?",
"removeOwnAdminRoleConfirmDescription": "После сохранения у вас больше не будет прав администратора в этой организации. Другой администратор может восстановить доступ, если это необходимо.", "removeOwnAdminRoleConfirmDescription": "После сохранения у вас больше не будет прав администратора в этой организации. Другой администратор может восстановить доступ, если это необходимо.",
"removeOwnAdminRoleConfirmButton": "Удалить мой доступ администратора", "removeOwnAdminRoleConfirmButton": "Удалить мой доступ администратора",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Базовая аутентификация заголовка", "policyAuthHeaderAuthTitle": "Базовая аутентификация заголовка",
"policyAuthHeaderAuthDescription": "Проверка пользовательского имени и значения HTTP-заголовка для каждого запроса", "policyAuthHeaderAuthDescription": "Проверка пользовательского имени и значения HTTP-заголовка для каждого запроса",
"policyAuthHeaderAuthSummary": "Заголовок настроен", "policyAuthHeaderAuthSummary": "Заголовок настроен",
"policyAuthHeaderName": "Имя заголовка", "policyAuthHeaderName": "Имя пользователя",
"policyAuthHeaderValue": "Ожидаемое значение", "policyAuthHeaderValue": "Пароль",
"policyAuthSetPasscode": "Установить пароль", "policyAuthSetPasscode": "Установить пароль",
"policyAuthSetPincode": "Установить ПИН-код", "policyAuthSetPincode": "Установить ПИН-код",
"policyAuthSetEmailWhitelist": "Установить белый список email", "policyAuthSetEmailWhitelist": "Установить белый список email",
@@ -903,7 +934,7 @@
"newtVersion": "Версия", "newtVersion": "Версия",
"architecture": "Архитектура", "architecture": "Архитектура",
"sites": "Сайты", "sites": "Сайты",
"siteWgAnyClients": "Для подключения используйте любой клиент WireGuard. Вы должны будете адресовать внутренние ресурсы, используя IP адрес пира.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Совместим со всеми клиентами WireGuard", "siteWgCompatibleAllClients": "Совместим со всеми клиентами WireGuard",
"siteWgManualConfigurationRequired": "Требуется ручная настройка", "siteWgManualConfigurationRequired": "Требуется ручная настройка",
"userErrorNotAdminOrOwner": "Пользователь не является администратором или владельцем", "userErrorNotAdminOrOwner": "Пользователь не является администратором или владельцем",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Создать пользователя Org", "createOrgUser": "Создать пользователя Org",
"actionUpdateOrg": "Обновить организацию", "actionUpdateOrg": "Обновить организацию",
"actionRemoveInvitation": "Удалить приглашение", "actionRemoveInvitation": "Удалить приглашение",
"actionRemoveUserRole": "Удалить роль пользователя",
"actionUpdateUser": "Обновить пользователя", "actionUpdateUser": "Обновить пользователя",
"actionGetUser": "Получить пользователя", "actionGetUser": "Получить пользователя",
"actionGetOrgUser": "Получить пользователя организации", "actionGetOrgUser": "Получить пользователя организации",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Применить чертёж", "actionApplyBlueprint": "Применить чертёж",
"actionListBlueprints": "Список чертежей", "actionListBlueprints": "Список чертежей",
"actionGetBlueprint": "Получить чертёж", "actionGetBlueprint": "Получить чертёж",
"actionCreateOrgWideLauncherView": "Создать вид запуска на уровне организации",
"setupToken": "Код настройки", "setupToken": "Код настройки",
"setupTokenDescription": "Введите токен настройки из консоли сервера.", "setupTokenDescription": "Введите токен настройки из консоли сервера.",
"setupTokenRequired": "Токен настройки обязателен", "setupTokenRequired": "Токен настройки обязателен",
"actionUpdateSite": "Обновить сайт", "actionUpdateSite": "Обновить сайт",
"actionApproveSite": "Одобрить сайт",
"actionRejectSite": "Отклонить сайт",
"actionResetSiteBandwidth": "Сброс пропускной способности организации", "actionResetSiteBandwidth": "Сброс пропускной способности организации",
"actionListSiteRoles": "Список разрешенных ролей сайта", "actionListSiteRoles": "Список разрешенных ролей сайта",
"actionCreateResource": "Создать ресурс", "actionCreateResource": "Создать ресурс",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Установить ПИН-код ресурса", "actionSetResourcePincode": "Установить ПИН-код ресурса",
"actionSetResourceEmailWhitelist": "Настроить белый список ресурсов email", "actionSetResourceEmailWhitelist": "Настроить белый список ресурсов email",
"actionGetResourceEmailWhitelist": "Получить белый список ресурсов email", "actionGetResourceEmailWhitelist": "Получить белый список ресурсов email",
"actionGetResourcePolicy": "Получить политику ресурса",
"actionUpdateResourcePolicy": "Обновить политику ресурса",
"actionSetResourcePolicyUsers": "Установить пользователей политики ресурса",
"actionSetResourcePolicyRoles": "Установить роли политики ресурса",
"actionSetResourcePolicyPassword": "Установить пароль политики ресурса",
"actionSetResourcePolicyPincode": "Установить ПИН-код политики ресурса",
"actionSetResourcePolicyHeaderAuth": "Установить аутентификацию по заголовкам для политики ресурса",
"actionSetResourcePolicyWhitelist": "Установить белый список по email для политики ресурса",
"actionSetResourcePolicyRules": "Установить правила политики ресурса",
"actionCreateTarget": "Создать цель", "actionCreateTarget": "Создать цель",
"actionDeleteTarget": "Удалить цель", "actionDeleteTarget": "Удалить цель",
"actionGetTarget": "Получить цель", "actionGetTarget": "Получить цель",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Сгенерировать токен доступа", "actionGenerateAccessToken": "Сгенерировать токен доступа",
"actionDeleteAccessToken": "Удалить токен доступа", "actionDeleteAccessToken": "Удалить токен доступа",
"actionListAccessTokens": "Список токенов доступа", "actionListAccessTokens": "Список токенов доступа",
"actionCreateResourceSessionToken": "Создать токен сеанса ресурса",
"actionCreateResourceRule": "Создать правило ресурса", "actionCreateResourceRule": "Создать правило ресурса",
"actionDeleteResourceRule": "Удалить правило ресурса", "actionDeleteResourceRule": "Удалить правило ресурса",
"actionListResourceRules": "Список правил ресурса", "actionListResourceRules": "Список правил ресурса",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Список приглашений", "actionListInvitations": "Список приглашений",
"actionExportLogs": "Экспорт журналов", "actionExportLogs": "Экспорт журналов",
"actionViewLogs": "Просмотр журналов", "actionViewLogs": "Просмотр журналов",
"actionCreateSiteProvisioningKey": "Создать ключ конфигурации сайта",
"actionListSiteProvisioningKeys": "Список ключей конфигурации сайтов",
"actionUpdateSiteProvisioningKey": "Обновить ключ конфигурации сайта",
"actionDeleteSiteProvisioningKey": "Удалить ключ конфигурации сайта",
"noneSelected": "Ничего не выбрано", "noneSelected": "Ничего не выбрано",
"orgNotFound2": "Организации не найдены.", "orgNotFound2": "Организации не найдены.",
"search": "Поиск…", "search": "Поиск…",
@@ -1486,10 +1535,35 @@
"otpAuthDescription": "Введите код из вашего приложения-аутентификатора или один из ваших одноразовых резервных кодов.", "otpAuthDescription": "Введите код из вашего приложения-аутентификатора или один из ваших одноразовых резервных кодов.",
"otpAuthSubmit": "Отправить код", "otpAuthSubmit": "Отправить код",
"idpContinue": "Или продолжить с", "idpContinue": "Или продолжить с",
"idpLastUsed": "Последнее использование",
"otpAuthBack": "Назад к паролю", "otpAuthBack": "Назад к паролю",
"navbar": "Навигационное меню", "navbar": "Навигационное меню",
"navbarDescription": "Главное навигационное меню приложения", "navbarDescription": "Главное навигационное меню приложения",
"navbarDocsLink": "Документация", "navbarDocsLink": "Документация",
"commandPaletteTitle": "Палитра команд",
"commandPaletteDescription": "Поиск страниц, организаций, ресурсов и действий",
"commandPaletteSearchPlaceholder": "Поиск страниц, ресурсов, действий...",
"commandPaletteNoResults": "Результаты не найдены.",
"commandPaletteSearching": "Поиск...",
"commandPaletteNavigation": "Навигация",
"commandPaletteOrganizations": "Организации",
"commandPaletteSites": "Сайты",
"commandPaletteResources": "Ресурсы",
"commandPaletteUsers": "Пользователи",
"commandPaletteClients": "Клиенты машин",
"commandPaletteActions": "Действия",
"commandPaletteCreateSite": "Создать сайт",
"commandPaletteCreateProxyResource": "Создать публичный ресурс",
"commandPaletteCreatePrivateResource": "Создать частный ресурс",
"commandPaletteCreateUser": "Создать пользователя",
"commandPaletteCreateApiKey": "Создать ключ API",
"commandPaletteCreateMachineClient": "Создать клиент машин",
"commandPaletteCreateAlertRule": "Создать правило предупреждения",
"commandPaletteCreateIdentityProvider": "Создать поставщика удостоверений",
"commandPaletteToggleTheme": "Переключить тему",
"commandPaletteChooseOrganization": "Выбрать организацию",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "Невозможно включить 2FA", "otpErrorEnable": "Невозможно включить 2FA",
"otpErrorEnableDescription": "Произошла ошибка при включении 2FA", "otpErrorEnableDescription": "Произошла ошибка при включении 2FA",
"otpSetupCheckCode": "Пожалуйста, введите 6-значный код", "otpSetupCheckCode": "Пожалуйста, введите 6-значный код",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Управление", "sidebarManagement": "Управление",
"sidebarBillingAndLicenses": "Биллинг и лицензии", "sidebarBillingAndLicenses": "Биллинг и лицензии",
"sidebarLogsAnalytics": "Статистика", "sidebarLogsAnalytics": "Статистика",
"commandSites": "Сайты",
"commandActionModeInfo": "Введите \">\", чтобы открыть режим действий",
"commandResources": "Ресурсы",
"commandProxyResources": "Публичные ресурсы",
"commandClientResources": "Частные ресурсы",
"commandClients": "Клиенты",
"commandUserDevices": "Устройства пользователей",
"commandMachineClients": "Клиенты машин",
"commandDomains": "Домены",
"commandRemoteExitNodes": "Удаленные узлы",
"commandTeam": "Команда",
"commandUsers": "Пользователи",
"commandRoles": "Роли",
"commandInvitations": "Приглашения",
"commandPolicies": "Общие политики",
"commandResourcePolicies": "Политики публичных ресурсов",
"commandIdentityProviders": "Поставщики удостоверений",
"commandApprovals": "Запросы на одобрение",
"commandShareableLinks": "Общие ссылки",
"commandOrganization": "Организация",
"commandLogsAndAnalytics": "Логи и аналитика",
"commandLogsAnalytics": "Аналитика",
"commandLogsRequest": "HTTP журналы запросов",
"commandLogsAccess": "Журналы аутентификации",
"commandLogsAction": "Журналы административных действий",
"commandLogsConnection": "Журнал сетевых подключений",
"commandLogsStreaming": "Трансляция события",
"commandManagement": "Управление",
"commandAlerting": "Оповещения",
"commandProvisioning": "Провиженинг",
"commandBluePrints": "Шаблоны",
"commandApiKeys": "API ключи",
"commandBillingAndLicenses": "Выставление счетов и лицензии",
"commandBilling": "Выставление счетов",
"commandEnterpriseLicenses": "Лицензии",
"commandSettings": "Настройки",
"commandLauncher": "Запускатор",
"commandResourceLauncher": "Запускатор ресурсов",
"commandSearchResults": "Результаты поиска",
"alertingTitle": "Оповещения", "alertingTitle": "Оповещения",
"alertingDescription": "Определите источники, триггеры и действия для уведомлений", "alertingDescription": "Определите источники, триггеры и действия для уведомлений",
"alertingRules": "Правила оповещений", "alertingRules": "Правила оповещений",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Поддомен: {subdomain}", "domainPickerSubdomain": "Поддомен: {subdomain}",
"domainPickerNamespace": "Пространство имен: {namespace}", "domainPickerNamespace": "Пространство имен: {namespace}",
"domainPickerShowMore": "Показать еще", "domainPickerShowMore": "Показать еще",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Выберите регион", "regionSelectorTitle": "Выберите регион",
"domainPickerRemoteExitNodeWarning": "Предоставленные домены не поддерживаются при подключении сайтов к удаленным узлам. Для доступа к ресурсам на удаленных узлах используйте пользовательский домен.", "domainPickerRemoteExitNodeWarning": "Предоставленные домены не поддерживаются при подключении сайтов к удаленным узлам. Для доступа к ресурсам на удаленных узлах используйте пользовательский домен.",
"regionSelectorInfo": "Выбор региона помогает нам обеспечить лучшее качество обслуживания для вашего расположения. Вам необязательно находиться в том же регионе, что и ваш сервер.", "regionSelectorInfo": "Выбор региона помогает нам обеспечить лучшее качество обслуживания для вашего расположения. Вам необязательно находиться в том же регионе, что и ваш сервер.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Домены", "billingDomains": "Домены",
"billingOrganizations": "Орги", "billingOrganizations": "Орги",
"billingRemoteExitNodes": "Удаленные узлы", "billingRemoteExitNodes": "Удаленные узлы",
"billingPublicResources": "Публичные ресурсы",
"billingPrivateResources": "Частные ресурсы",
"billingMachineClients": "Клиенты машин",
"billingNoLimitConfigured": "Лимит не установлен", "billingNoLimitConfigured": "Лимит не установлен",
"billingEstimatedPeriod": "Предполагаемый период выставления счетов", "billingEstimatedPeriod": "Предполагаемый период выставления счетов",
"billingIncludedUsage": "Включенное использование", "billingIncludedUsage": "Включенное использование",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Сколько пользователей вы можете использовать", "billingUsersInfo": "Сколько пользователей вы можете использовать",
"billingDomainInfo": "Сколько доменов вы можете использовать", "billingDomainInfo": "Сколько доменов вы можете использовать",
"billingRemoteExitNodesInfo": "Сколько удаленных узлов вы можете использовать", "billingRemoteExitNodesInfo": "Сколько удаленных узлов вы можете использовать",
"billingPublicResourcesInfo": "Сколько публичных ресурсов вы можете использовать",
"billingPrivateResourcesInfo": "Сколько частных ресурсов вы можете использовать",
"billingMachineClientsInfo": "Сколько машинных клиентов вы можете использовать",
"billingLicenseKeys": "Лицензионные ключи", "billingLicenseKeys": "Лицензионные ключи",
"billingLicenseKeysDescription": "Управление подписками на лицензионные ключи", "billingLicenseKeysDescription": "Управление подписками на лицензионные ключи",
"billingLicenseSubscription": "Лицензионное соглашение", "billingLicenseSubscription": "Лицензионное соглашение",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Подсеть", "subnetPlaceholder": "Подсеть",
"addressDescription": "Внутренний адрес клиента. Должен находиться в подсети организации.", "addressDescription": "Внутренний адрес клиента. Должен находиться в подсети организации.",
"selectSites": "Выберите сайты", "selectSites": "Выберите сайты",
"selectLabels": "Выберите метки",
"sitesDescription": "Клиент будет иметь подключение к выбранным сайтам", "sitesDescription": "Клиент будет иметь подключение к выбранным сайтам",
"clientInstallOlm": "Установить Olm", "clientInstallOlm": "Установить Olm",
"clientInstallOlmDescription": "Запустите Olm на вашей системе", "clientInstallOlmDescription": "Запустите Olm на вашей системе",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Публичный", "resourcesTableProxyResources": "Публичный",
"resourcesTableClientResources": "Приватный", "resourcesTableClientResources": "Приватный",
"resourcesTableNoProxyResourcesFound": "Проксированных ресурсов не найдено.", "resourcesTableNoProxyResourcesFound": "Проксированных ресурсов не найдено.",
"resourcesTableNoInternalResourcesFound": "Внутренних ресурсов не найдено.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Пункт назначения", "resourcesTableDestination": "Пункт назначения",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "Псевдоним адреса", "resourcesTableAliasAddress": "Псевдоним адреса",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "Отмена", "editInternalResourceDialogCancel": "Отмена",
"editInternalResourceDialogSaveResource": "Сохранить ресурс", "editInternalResourceDialogSaveResource": "Сохранить ресурс",
"editInternalResourceDialogSuccess": "Успешно", "editInternalResourceDialogSuccess": "Успешно",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Внутренний ресурс успешно обновлен", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Ошибка", "editInternalResourceDialogError": "Ошибка",
"editInternalResourceDialogFailedToUpdateInternalResource": "Не удалось обновить внутренний ресурс", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Имя обязательно", "editInternalResourceDialogNameRequired": "Имя обязательно",
"editInternalResourceDialogNameMaxLength": "Имя не должно быть длиннее 255 символов", "editInternalResourceDialogNameMaxLength": "Имя не должно быть длиннее 255 символов",
"editInternalResourceDialogProxyPortMin": "Порт прокси должен быть не менее 1", "editInternalResourceDialogProxyPortMin": "Порт прокси должен быть не менее 1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.", "editInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.",
"createInternalResourceDialogNoSitesAvailable": "Нет доступных сайтов", "createInternalResourceDialogNoSitesAvailable": "Нет доступных сайтов",
"createInternalResourceDialogNoSitesAvailableDescription": "Вам необходимо иметь хотя бы один сайт Newt с настроенной подсетью для создания внутреннего ресурса.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Закрыть", "createInternalResourceDialogClose": "Закрыть",
"createInternalResourceDialogCreateClientResource": "Создать приватный ресурс", "createInternalResourceDialogCreateClientResource": "Создать приватный ресурс",
"createInternalResourceDialogCreateClientResourceDescription": "Создать новый ресурс, который будет доступен только клиентам, подключенным к организации", "createInternalResourceDialogCreateClientResourceDescription": "Создать новый ресурс, который будет доступен только клиентам, подключенным к организации",
"privateResourceGeneralDescription": "Настройте имя, идентификатор и другие общие параметры ресурса.",
"privateResourceCreatePageSeeAll": "Посмотреть все частные ресурсы",
"privateResourceAllowIcmpPing": "Разрешить ICMP Ping",
"privateResourceNetworkAccess": "Сетевой доступ",
"privateResourceNetworkAccessDescription": "Управляйте доступом к портам TCP/UDP и настройте разрешение ICMP ping для данного ресурса.",
"hostSettings": "Настройки хоста",
"cidrSettings": "Настройки CIDR",
"createInternalResourceDialogResourceProperties": "Свойства ресурса", "createInternalResourceDialogResourceProperties": "Свойства ресурса",
"createInternalResourceDialogName": "Имя", "createInternalResourceDialogName": "Имя",
"createInternalResourceDialogSite": "Сайт", "createInternalResourceDialogSite": "Сайт",
"selectSite": "Выберите сайт...", "selectSite": "Выберите сайт...",
"multiSitesSelectorSitesCount": "{count, plural, one {# сайт} few {# сайта} many {# сайтов} other {# сайтов}}", "multiSitesSelectorSitesCount": "{count, plural, one {# сайт} few {# сайта} many {# сайтов} other {# сайтов}}",
"labelsSelectorLabelsCount": "{count, plural, one {# метка} few {# метки} many {# меток} other {# меток}}",
"noSitesFound": "Сайты не найдены.", "noSitesFound": "Сайты не найдены.",
"createInternalResourceDialogProtocol": "Протокол", "createInternalResourceDialogProtocol": "Протокол",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "Отмена", "createInternalResourceDialogCancel": "Отмена",
"createInternalResourceDialogCreateResource": "Создать ресурс", "createInternalResourceDialogCreateResource": "Создать ресурс",
"createInternalResourceDialogSuccess": "Успешно", "createInternalResourceDialogSuccess": "Успешно",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Внутренний ресурс успешно создан", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Ошибка", "createInternalResourceDialogError": "Ошибка",
"createInternalResourceDialogFailedToCreateInternalResource": "Не удалось создать внутренний ресурс", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Имя обязательно", "createInternalResourceDialogNameRequired": "Имя обязательно",
"createInternalResourceDialogNameMaxLength": "Имя должно содержать менее 255 символов", "createInternalResourceDialogNameMaxLength": "Имя должно содержать менее 255 символов",
"createInternalResourceDialogPleaseSelectSite": "Пожалуйста, выберите сайт", "createInternalResourceDialogPleaseSelectSite": "Пожалуйста, выберите сайт",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "Диапазон CIDR ресурса в сети сайта.", "createInternalResourceDialogDestinationCidrDescription": "Диапазон CIDR ресурса в сети сайта.",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.", "createInternalResourceDialogAliasDescription": "Дополнительный внутренний DNS псевдоним для этого ресурса.",
"internalResourceAliasLocalWarning": "Псевдонимы, оканчивающиеся на .local, могут вызывать проблемы с разрешением из-за mDNS в некоторых сетях.",
"internalResourceDownstreamSchemeRequired": "Схема обязательна для HTTP ресурсов", "internalResourceDownstreamSchemeRequired": "Схема обязательна для HTTP ресурсов",
"internalResourceHttpPortRequired": "Порт назначения обязателен для HTTP ресурсов", "internalResourceHttpPortRequired": "Порт назначения обязателен для HTTP ресурсов",
"siteConfiguration": "Конфигурация", "siteConfiguration": "Конфигурация",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Удаленные узлы", "sidebarRemoteExitNodes": "Удаленные узлы",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "Секретный ключ", "remoteExitNodeSecretKey": "Секретный ключ",
"remoteExitNodeNetworkingTitle": "Настройки сети",
"remoteExitNodeNetworkingDescription": "Настройте, как этот удаленный узел выхода маршрутизирует трафик и какие сайты предпочитают подключаться через него. Расширенные функции для использования с конфигурациями магистральной сети.",
"remoteExitNodeNetworkingSave": "Сохранить настройки",
"remoteExitNodeNetworkingSaveSuccessTitle": "Сетевые настройки сохранены",
"remoteExitNodeNetworkingSaveSuccessDescription": "Сетевые настройки были успешно обновлены.",
"remoteExitNodeNetworkingSaveError": "Не удалось сохранить сетевые настройки",
"remoteExitNodeNetworkingSubnetsTitle": "Удалённые подсети",
"remoteExitNodeNetworkingSubnetsDescription": "Определите диапазоны CIDR, которые этот удаленный узел выхода будет использовать для маршрутизации трафика. Введите действительный CIDR (например, <code>10.0.0.0/8</code>) и нажмите Enter, чтобы добавить.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Добавить диапазон CIDR (например, 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Не удалось загрузить подсети",
"remoteExitNodeNetworkingLabelsTitle": "Этикетки предпочтений",
"remoteExitNodeNetworkingLabelsDescription": "Сайты с этими метками будут обязаны подключаться через этот удаленный узел выхода.",
"remoteExitNodeNetworkingLabelsButtonText": "Выберите метки...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Поиск меток...",
"remoteExitNodeNetworkingLabelsLoadError": "Не удалось загрузить метки",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Создать удалённый узел", "title": "Создать удалённый узел",
"description": "Создайте новый самостоятельный удалённый ретранслятор и узел прокси-сервера", "description": "Создайте новый самостоятельный удалённый ретранслятор и узел прокси-сервера",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Для этой организации узлы не доступны. Сначала создайте узел, чтобы использовать локальные сайты.", "noRemoteExitNodesAvailableDescription": "Для этой организации узлы не доступны. Сначала создайте узел, чтобы использовать локальные сайты.",
"exitNode": "Узел выхода", "exitNode": "Узел выхода",
"country": "Страна", "country": "Страна",
"countryIsNot": "Страна не является",
"rulesMatchCountry": "В настоящее время основано на исходном IP", "rulesMatchCountry": "В настоящее время основано на исходном IP",
"region": "Регион", "region": "Регион",
"selectRegion": "Выберите регион", "selectRegion": "Выберите регион",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC провайдер", "idpGoogleDescription": "Google OAuth2/OIDC провайдер",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "Подсеть", "subnet": "Подсеть",
"utilitySubnet": "Утилита подсети",
"subnetDescription": "Подсеть для конфигурации сети этой организации.", "subnetDescription": "Подсеть для конфигурации сети этой организации.",
"customDomain": "Пользовательский домен", "customDomain": "Пользовательский домен",
"authPage": "Страницы аутентификации", "authPage": "Страницы аутентификации",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "Требуется настройка двухфакторной аутентификации. Пожалуйста, войдите снова через {dashboardUrl}/auth/login завершить этот шаг. Затем вернитесь сюда.", "twoFactorSetupRequired": "Требуется настройка двухфакторной аутентификации. Пожалуйста, войдите снова через {dashboardUrl}/auth/login завершить этот шаг. Затем вернитесь сюда.",
"additionalSecurityRequired": "Требуется дополнительная безопасность", "additionalSecurityRequired": "Требуется дополнительная безопасность",
"organizationRequiresAdditionalSteps": "Эта организация требует дополнительных шагов безопасности, прежде чем вы сможете получить доступ к ресурсам.", "organizationRequiresAdditionalSteps": "Эта организация требует дополнительных шагов безопасности, прежде чем вы сможете получить доступ к ресурсам.",
"sessionExpired": "Сессия истекла",
"sessionExpiredReauthRequired": "Ваша сессия истекла согласно политике безопасности вашей организации. Пожалуйста, повторно пройдите аутентификацию, чтобы продолжить.",
"reauthenticate": "Повторная аутентификация",
"completeTheseSteps": "Выполните эти шаги", "completeTheseSteps": "Выполните эти шаги",
"enableTwoFactorAuthentication": "Включить двухфакторную аутентификацию", "enableTwoFactorAuthentication": "Включить двухфакторную аутентификацию",
"completeSecuritySteps": "Пройти шаги безопасности", "completeSecuritySteps": "Пройти шаги безопасности",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Адрес источника", "sourceAddress": "Адрес источника",
"destinationAddress": "Адрес назначения", "destinationAddress": "Адрес назначения",
"duration": "Продолжительность", "duration": "Продолжительность",
"licenseRequiredToUse": "Требуется лицензия на <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> или <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> для использования этой функции. <bookADemoLink>Забронируйте демонстрацию или пробный POC</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "<enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> требуется для использования этой функции. Эта функция также доступна в <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Забронируйте демонстрацию или пробный POC</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Резольвер сертификата", "certResolver": "Резольвер сертификата",
"certResolverDescription": "Выберите резолвер сертификата, который будет использоваться для этого ресурса.", "certResolverDescription": "Выберите резолвер сертификата, который будет использоваться для этого ресурса.",
"selectCertResolver": "Выберите резолвер сертификата", "selectCertResolver": "Выберите резолвер сертификата",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Отсутствует организация или ID домена", "orgOrDomainIdMissing": "Отсутствует организация или ID домена",
"loadingDNSRecords": "Загрузка записей DNS...", "loadingDNSRecords": "Загрузка записей DNS...",
"olmUpdateAvailableInfo": "Доступна обновленная версия Олма. Пожалуйста, обновитесь до последней версии.", "olmUpdateAvailableInfo": "Доступна обновленная версия Олма. Пожалуйста, обновитесь до последней версии.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Доступна обновленная версия. Пожалуйста, обновитесь до последней версии для получения лучшего опыта.",
"client": "Клиент", "client": "Клиент",
"proxyProtocol": "Настройки протокола прокси", "proxyProtocol": "Настройки протокола прокси",
"proxyProtocolDescription": "Настроить Прокси-протокол для сохранения IP-адресов клиента для служб TCP.", "proxyProtocolDescription": "Настроить Прокси-протокол для сохранения IP-адресов клиента для служб TCP.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Добавить пользователей", "editInternalResourceDialogAddUsers": "Добавить пользователей",
"editInternalResourceDialogAddClients": "Добавить клиентов", "editInternalResourceDialogAddClients": "Добавить клиентов",
"editInternalResourceDialogDestinationLabel": "Пункт назначения", "editInternalResourceDialogDestinationLabel": "Пункт назначения",
"editInternalResourceDialogDestinationDescription": "Укажите адрес назначения для внутреннего ресурса. Это может быть имя хоста, IP-адрес или диапазон CIDR в зависимости от выбранного режима. При необходимости установите внутренний DNS-алиас для облегчения идентификации.", "editInternalResourceDialogDestinationDescription": "Настройте, как клиенты получают доступ к этому ресурсу.",
"internalResourceFormMultiSiteRoutingHelp": "Выбор нескольких сайтов позволяет обеспечить отказоустойчивую маршрутизацию и фейловер для высокой доступности.", "internalResourceFormMultiSiteRoutingHelp": "Выбор нескольких сайтов позволяет обеспечить отказоустойчивую маршрутизацию и фейловер для высокой доступности.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Узнать больше", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Узнать больше",
"editInternalResourceDialogPortRestrictionsDescription": "Ограничьте доступ к определенным TCP/UDP-портам или разрешите/заблокируйте все порты.", "editInternalResourceDialogPortRestrictionsDescription": "Ограничьте доступ к определенным TCP/UDP-портам или разрешите/заблокируйте все порты.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "Белый список email", "memberPortalEmailWhitelist": "Белый список email",
"memberPortalResourceDisabled": "Ресурс отключён", "memberPortalResourceDisabled": "Ресурс отключён",
"memberPortalShowingResources": "Показаны {start}-{end} из {total} ресурсов", "memberPortalShowingResources": "Показаны {start}-{end} из {total} ресурсов",
"resourceLauncherTitle": "Запуск ресурса",
"resourceSidebarLauncherTitle": "Запускатор",
"resourceLauncherDescription": "Просмотрите все доступные ресурсы и запустите их из одного централизованного узла",
"resourceLauncherSearchPlaceholder": "Поиск ваших ресурсов...",
"resourceLauncherDefaultView": "По умолчанию",
"resourceLauncherSaveView": "Сохранить вид",
"resourceLauncherSaveToCurrentView": "Сохранить в текущий вид",
"resourceLauncherSaveDefaultPersonal": "Сохранить для меня",
"resourceLauncherResetView": "Сбросить вид",
"resourceLauncherResetSystemDefault": "Сбросить на системные настройки по умолчанию",
"resourceLauncherSystemDefaultRestored": "Системные настройки по умолчанию восстановлены",
"resourceLauncherSystemDefaultRestoredDescription": "Вид по умолчанию был сброшен до исходных настроек.",
"resourceLauncherSaveAsNewView": "Сохранить как новый вид",
"resourceLauncherSaveAsNewViewDescription": "Дайте этому виду имя, чтобы сохранить текущие фильтры и макет.",
"resourceLauncherSaveForEveryone": "Сохранить для всех",
"resourceLauncherSaveForEveryoneDescription": "Поделитесь этим видом со всеми членами организации. Если не отмечено, видимость только для вас.",
"resourceLauncherMakePersonal": "Сделать личным",
"resourceLauncherFilter": "Фильтр",
"resourceLauncherFilterWithCount": "Фильтр, применено {count}",
"resourceLauncherSort": "Сортировать",
"resourceLauncherSortAscending": "Сортировать по возрастанию",
"resourceLauncherSortDescending": "Сортировать по убыванию",
"resourceLauncherSettings": "Настройки",
"resourceLauncherGroupBy": "Группировать по",
"resourceLauncherGroupBySite": "Сайт",
"resourceLauncherGroupByLabel": "Метка",
"resourceLauncherGroupByNone": "Нет",
"resourceLauncherLayout": "Макет",
"resourceLauncherLayoutGrid": "Сетка",
"resourceLauncherLayoutList": "Список",
"resourceLauncherShowLabels": "Показать метки",
"resourceLauncherShowSiteTags": "Показать теги сайта",
"resourceLauncherShowRecents": "Показать недавно",
"resourceLauncherDeleteView": "Удалить вид",
"resourceLauncherDeleteViewTitle": "Удалить вид",
"resourceLauncherDeleteViewQuestion": "Вы уверены, что хотите удалить этот вид запускатора?",
"resourceLauncherDeleteViewConfirm": "Удалить вид",
"resourceLauncherViewAsAdmin": "Просмотр как администратор",
"resourceLauncherResourceDetailsDescription": "Информация о подключении и статус для данного ресурса.",
"resourceLauncherResourceDetails": "Детали ресурса",
"resourceLauncherAuthMethodsDescription": "Методы аутентификации, включенные для этого ресурса.",
"resourceLauncherPrivateClientRequired": "Подключитесь с клиентом на устройстве для доступа к этому ресурсу в частном порядке.",
"resourceLauncherPrivateClientRequiredTitle": "Требуется подключение клиента",
"resourceLauncherDownloadClient": "Скачать клиент",
"resourceLauncherFailedToLoadDetails": "Не удалось загрузить детали ресурса. Возможно, у вас больше нет доступа к этому ресурсу.",
"resourceLauncherNoPortRestrictions": "Нет ограничений портов",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Без меток",
"resourceLauncherNoSite": "Без сайта",
"resourceLauncherNoResourcesInGroup": "Нет ресурсов в данной группе",
"resourceLauncherEmptyStateTitle": "Нет доступных ресурсов",
"resourceLauncherEmptyStateDescription": "У вас пока нет доступа ни к одному ресурсу. Обратитесь к администратору, чтобы запросить доступ.",
"resourceLauncherEmptyStateNoResultsTitle": "Ресурсы не найдены",
"resourceLauncherEmptyStateNoResultsDescription": "Ни один ресурс не соответствует вашему текущему поисковому запросу или фильтрам. Попробуйте их изменить, чтобы найти нужное.",
"resourceLauncherEmptyStateNoResultsWithQuery": "Ни один ресурс не соответствует \"{query}\". Попробуйте изменить параметры поиска или очистить фильтры, чтобы увидеть все ресурсы.",
"resourceLauncherSearchFirstTitle": "Поиск или фильтр для просмотра",
"resourceLauncherSearchFirstDescription": "У вас есть доступ ко многим ресурсам. Используйте поиск или фильтр по сайту или метке, чтобы найти, что вам нужно.",
"resourceLauncherSiteGroupingDisabled": "Группировка по сайту недоступна в этом масштабе. Отфильтруйте по сайту, чтобы сгруппировать меньший набор.",
"resourceLauncherLabelGroupingDisabled": "Группировка по меткам недоступна в этом масштабе.",
"resourceLauncherCompactModeHint": "Показывается упрощённый список для более быстрого просмотра. Используйте поиск или фильтры, чтобы сузить результаты.",
"resourceLauncherCompactGroupingHint": "Примените фильтры сайта или меток, чтобы включить группировку.",
"resourceLauncherCopiedToClipboard": "Скопировано в буфер обмена",
"resourceLauncherCopiedAccessDescription": "Доступ к ресурсу был скопирован в ваш буфер обмена.",
"resourceLauncherViewNamePlaceholder": "Имя вида",
"resourceLauncherViewNameLabel": "Имя вида",
"resourceLauncherViewSaved": "Вид сохранён",
"resourceLauncherViewSavedDescription": "Ваш вид запуска был сохранён.",
"resourceLauncherViewSaveFailed": "Не удалось сохранить вид",
"resourceLauncherViewSaveFailedDescription": "Не удалось сохранить вид. Пожалуйста, попробуйте еще раз.",
"resourceLauncherViewDeleted": "Вид удалён",
"resourceLauncherViewDeletedDescription": "Вид запуска был удалён.",
"resourceLauncherViewDeleteFailed": "Не удалось удалить вид",
"resourceLauncherViewDeleteFailedDescription": "Не удалось удалить вид. Пожалуйста, попробуйте еще раз.",
"memberPortalPrevious": "Предыдущий", "memberPortalPrevious": "Предыдущий",
"memberPortalNext": "Следующий", "memberPortalNext": "Следующий",
"httpSettings": "Настройки HTTP", "httpSettings": "Настройки HTTP",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----НАЧАЛО ЛИЧНОГО КЛЮЧА OPENSSH-----", "sshPrivateKeyPlaceholder": "-----НАЧАЛО ЛИЧНОГО КЛЮЧА OPENSSH-----",
"sshPrivateKeyRequired": "Требуется личный ключ", "sshPrivateKeyRequired": "Требуется личный ключ",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Введите пароль VNC для подключения", "vncSignInDescription": "Введите ваши учетные данные VNC для подключения",
"vncUsernameOptional": "Имя пользователя (необязательно)",
"vncPasswordOptional": "Пароль (необязательно)", "vncPasswordOptional": "Пароль (необязательно)",
"vncNoResourceTarget": "Отсутствует целевой ресурс", "vncNoResourceTarget": "Отсутствует целевой ресурс",
"vncFailedToLoadNovnc": "Не удалось загрузить noVNC", "vncFailedToLoadNovnc": "Не удалось загрузить noVNC",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Ошибка загрузки", "rdpUploadFailed": "Ошибка загрузки",
"rdpUnicodeKeyboardMode": "Режим клавиатуры Unicode", "rdpUnicodeKeyboardMode": "Режим клавиатуры Unicode",
"sessionToolbarShow": "Показать панель инструментов", "sessionToolbarShow": "Показать панель инструментов",
"sessionToolbarHide": "Скрыть панель инструментов" "sessionToolbarHide": "Скрыть панель инструментов",
"actionUpdateSiteApprovals": "Обновить утверждения сайта"
} }
+250 -22
View File
@@ -66,9 +66,15 @@
"local": "Yerel", "local": "Yerel",
"edit": "Düzenle", "edit": "Düzenle",
"siteConfirmDelete": "Site Silmeyi Onayla", "siteConfirmDelete": "Site Silmeyi Onayla",
"siteConfirmDeleteAndResources": "Site ve Kaynakları Silmeyi Onayla",
"siteDelete": "Siteyi Sil", "siteDelete": "Siteyi Sil",
"siteDeleteAndResources": "Site ve Kaynakları Sil",
"siteMessageRemove": "Kaldırıldıktan sonra site artık erişilebilir olmayacaktır. Siteyle ilişkilendirilmiş tüm hedefler de kaldırılacaktır.", "siteMessageRemove": "Kaldırıldıktan sonra site artık erişilebilir olmayacaktır. Siteyle ilişkilendirilmiş tüm hedefler de kaldırılacaktır.",
"siteMessageRemoveAndResources": "Bu işlem, diğer sitelerle de ilişkilendirilmiş olsa bile, bu siteye bağlı tüm genel ve özel kaynakları kalıcı olarak silecektir.",
"siteQuestionRemove": "Siteyi organizasyondan kaldırmak istediğinizden emin misiniz?", "siteQuestionRemove": "Siteyi organizasyondan kaldırmak istediğinizden emin misiniz?",
"siteQuestionRemoveAndResources": "Bu siteyi ve tüm ilişkili kaynakları silmek istediğinizden emin misiniz?",
"sitesTableDeleteSite": "Siteyi Sil",
"sitesTableDeleteSiteAndResources": "Site ve Kaynakları Sil",
"siteManageSites": "Siteleri Yönet", "siteManageSites": "Siteleri Yönet",
"siteDescription": "Özel ağlara erişimi etkinleştirmek için siteler oluşturun ve yönetin", "siteDescription": "Özel ağlara erişimi etkinleştirmek için siteler oluşturun ve yönetin",
"sitesBannerTitle": "Herhangi Bir Ağa Bağlan", "sitesBannerTitle": "Herhangi Bir Ağa Bağlan",
@@ -117,6 +123,16 @@
"siteUpdated": "Site güncellendi", "siteUpdated": "Site güncellendi",
"siteUpdatedDescription": "Site güncellendi.", "siteUpdatedDescription": "Site güncellendi.",
"siteGeneralDescription": "Bu site için genel ayarları yapılandırın", "siteGeneralDescription": "Bu site için genel ayarları yapılandırın",
"siteRestartTitle": "Siteyi Yeniden Başlat",
"siteRestartDescription": "Bu site için WireGuard tünelini yeniden başlatın. Bu, bağlantıyı kısa süreliğine keser.",
"siteRestartBody": "Site tüneli düzgün çalışmadığında ve ana bilgisayarı yeniden başlatmadan bağlantıyı yeniden sağlamak istiyorsanız bunu kullanın.",
"siteRestartButton": "Siteyi Yeniden Başlat",
"siteRestartDialogMessage": "<b>{name}</b> için WireGuard tünelini yeniden başlatmak istediğinizden emin misiniz? Site kısa süreliğine bağlantıyı kaybedecektir.",
"siteRestartWarning": "Tünel yeniden başlatılırken site kısa süreliğine kesintiye uğrar.",
"siteRestarted": "Site yeniden başlatıldı",
"siteRestartedDescription": "WireGuard tüneli yeniden başlatıldı.",
"siteErrorRestart": "Sitenin yeniden başlatılması başarısız oldu",
"siteErrorRestartDescription": "Site yeniden başlatılırken bir hata oluştu.",
"siteSettingDescription": "Sitenizdeki ayarları yapılandırın", "siteSettingDescription": "Sitenizdeki ayarları yapılandırın",
"siteResourcesTab": "Kaynaklar", "siteResourcesTab": "Kaynaklar",
"siteResourcesNoneOnSite": "Bu sitede henüz genel veya özel kaynak yok.", "siteResourcesNoneOnSite": "Bu sitede henüz genel veya özel kaynak yok.",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "Paylaşılabilir Bağlantıyı Silmeyi Onayla", "shareDeleteConfirm": "Paylaşılabilir Bağlantıyı Silmeyi Onayla",
"shareQuestionRemove": "Bu paylaşım bağlantısını silmek istediğinizden emin misiniz?", "shareQuestionRemove": "Bu paylaşım bağlantısını silmek istediğinizden emin misiniz?",
"shareMessageRemove": "Silindikten sonra, bağlantı artık çalışmayacak ve kullanan herkes kaynağa erişimini kaybedecek.", "shareMessageRemove": "Silindikten sonra, bağlantı artık çalışmayacak ve kullanan herkes kaynağa erişimini kaybedecek.",
"shareTokenDescription": "Erişim jetonunuz iki şekilde iletilebilir: sorgu parametresi olarak veya istek başlıklarında. Kimlik doğrulanmış erişim için her istekten müşteri tarafından iletilmelidir.", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "Erişim Jetonu", "accessToken": "Erişim Jetonu",
"usageExamples": "Kullanım Örnekleri", "usageExamples": "Kullanım Örnekleri",
"tokenId": "Jeton ID", "tokenId": "Jeton ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "Başlık (isteğe bağlı)", "shareTitleOptional": "Başlık (isteğe bağlı)",
"sharePathOptional": "Yol (isteğe bağlı)", "sharePathOptional": "Yol (isteğe bağlı)",
"sharePathDescription": "Bağlantıdan sonra kullanıcıları bu yola yönlendirecek bağlantıyı tanımlayın.", "sharePathDescription": "Bağlantıdan sonra kullanıcıları bu yola yönlendirecek bağlantıyı tanımlayın.",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "Süresi Dolacak", "expireIn": "Süresi Dolacak",
"neverExpire": "Hiçbir Zaman Sona Ermez", "neverExpire": "Hiçbir Zaman Sona Ermez",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "Son kullanma süresi, bağlantının kullanılabilir ve kaynağa erişim sağlayacak süresidir. Bu süreden sonra bağlantı çalışmayı durduracak ve bu bağlantıyı kullanan kullanıcılar kaynağa erişimini kaybedecektir.", "shareExpireDescription": "Son kullanma süresi, bağlantının kullanılabilir ve kaynağa erişim sağlayacak süresidir. Bu süreden sonra bağlantı çalışmayı durduracak ve bu bağlantıyı kullanan kullanıcılar kaynağa erişimini kaybedecektir.",
"shareSeeOnce": "Bu bağlantıyı yalnızca bir kez görebileceksiniz. Kopyaladığınızdan emin olun.", "shareSeeOnce": "Bu bağlantıyı yalnızca bir kez görebileceksiniz. Kopyaladığınızdan emin olun.",
"shareAccessHint": "Bu bağlantıya sahip olan herkes kaynağa erişebilir. Dikkatle paylaşın.", "shareAccessHint": "Bu bağlantıya sahip olan herkes kaynağa erişebilir. Dikkatle paylaşın.",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "Proxy isteklerini bir port numarası kullanarak ham TCP/UDP üzerinden yapın. Sitelerin uzak bir düğüme bağlanması gereklidir.", "resourceRawDescriptionCloud": "Proxy isteklerini bir port numarası kullanarak ham TCP/UDP üzerinden yapın. Sitelerin uzak bir düğüme bağlanması gereklidir.",
"resourceCreate": "Kaynak Oluştur", "resourceCreate": "Kaynak Oluştur",
"resourceCreateDescription": "Yeni bir kaynak oluşturmak için aşağıdaki adımları izleyin", "resourceCreateDescription": "Yeni bir kaynak oluşturmak için aşağıdaki adımları izleyin",
"resourcePublicCreate": "Halka Açık Kaynak Oluştur",
"resourcePublicCreateDescription": "Web tarayıcısı üzerinden erişilebilen yeni bir genel kaynak oluşturmak için aşağıdaki adımları izleyin",
"resourceCreateGeneralDescription": "Adı ve türü dahil temel kaynak ayarlarını yapılandırın", "resourceCreateGeneralDescription": "Adı ve türü dahil temel kaynak ayarlarını yapılandırın",
"resourceSeeAll": "Tüm Kaynakları Gör", "resourceSeeAll": "Tüm Kaynakları Gör",
"resourceCreateGeneral": "Genel", "resourceCreateGeneral": "Genel",
@@ -431,8 +455,14 @@
"provisioningManage": "Tedarik", "provisioningManage": "Tedarik",
"provisioningDescription": "Tedarik anahtarlarını yönetin ve onay bekleyen siteleri gözden geçirin.", "provisioningDescription": "Tedarik anahtarlarını yönetin ve onay bekleyen siteleri gözden geçirin.",
"pendingSites": "Bekleyen Siteler", "pendingSites": "Bekleyen Siteler",
"siteApproveSuccess": "Site başarıyla onaylandı", "siteApproveSuccess": "Site ve ilgili kaynaklar başarıyla onaylandı",
"siteApproveError": "Site onaylanırken hata oluştu", "siteApproveError": "Site onaylanırken hata oluştu",
"siteReject": "Siteyi Reddet",
"siteQuestionReject": "Bu siteyi reddetmek istediğinizden emin misiniz?",
"siteMessageReject": "Bu işlem, siteyi ve hala beklemede olan herhangi bir ilgili kaynağı kalıcı olarak silecektir.",
"siteConfirmReject": "Site Reddetmeyi Onayla",
"siteRejectSuccess": "Site başarıyla reddedildi",
"siteRejectError": "Site reddedilirken hata oluştu",
"provisioningKeys": "Tedarik Anahtarları", "provisioningKeys": "Tedarik Anahtarları",
"searchProvisioningKeys": "Tedarik anahtarlarını ara...", "searchProvisioningKeys": "Tedarik anahtarlarını ara...",
"provisioningKeysAdd": "Tedarik Anahtarı Üret", "provisioningKeysAdd": "Tedarik Anahtarı Üret",
@@ -448,12 +478,12 @@
"provisioningKeysSave": "Tedarik anahtarını kaydet", "provisioningKeysSave": "Tedarik anahtarını kaydet",
"provisioningKeysSaveDescription": "Bunu yalnızca bir kez görebileceksiniz. Güvenli bir yere kopyalayın.", "provisioningKeysSaveDescription": "Bunu yalnızca bir kez görebileceksiniz. Güvenli bir yere kopyalayın.",
"provisioningKeysErrorCreate": "Tedarik anahtarı oluşturulurken hata oluştu", "provisioningKeysErrorCreate": "Tedarik anahtarı oluşturulurken hata oluştu",
"provisioningKeysList": "Yeni tedarik anahtarı", "provisioningKeysList": "Yeni Sağlama Anahtarı",
"provisioningKeysMaxBatchSize": "Maksimum toplu iş boyutu", "provisioningKeysMaxBatchSize": "Maksimum Toplu İş Boyutu",
"provisioningKeysUnlimitedBatchSize": "Sınırsız toplu iş boyutu (sınırlama yok)", "provisioningKeysUnlimitedBatchSize": "Sınırsız toplu iş boyutu (sınırlama yok)",
"provisioningKeysMaxBatchUnlimited": "Sınırsız", "provisioningKeysMaxBatchUnlimited": "Sınırsız",
"provisioningKeysMaxBatchSizeInvalid": "Geçerli bir maksimum toplu iş boyutu girin (11,000,000).", "provisioningKeysMaxBatchSizeInvalid": "Geçerli bir maksimum toplu iş boyutu girin (11,000,000).",
"provisioningKeysValidUntil": "Geçerlilik tarihi", "provisioningKeysValidUntil": "Geçerli Olma Süresi",
"provisioningKeysValidUntilHint": "Son kullanım tarihi için boş bırakın.", "provisioningKeysValidUntilHint": "Son kullanım tarihi için boş bırakın.",
"provisioningKeysValidUntilInvalid": "Geçerli bir tarih ve saat girin.", "provisioningKeysValidUntilInvalid": "Geçerli bir tarih ve saat girin.",
"provisioningKeysNumUsed": "Kullanım Sayısı", "provisioningKeysNumUsed": "Kullanım Sayısı",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "Asla", "provisioningKeysNeverUsed": "Asla",
"provisioningKeysEdit": "Tedarik Anahtarını Düzenle", "provisioningKeysEdit": "Tedarik Anahtarını Düzenle",
"provisioningKeysEditDescription": "Bu anahtar için maksimum toplu iş boyutunu ve son kullanma zamanını güncelleyin.", "provisioningKeysEditDescription": "Bu anahtar için maksimum toplu iş boyutunu ve son kullanma zamanını güncelleyin.",
"provisioningKeysApproveNewSites": "Yeni siteleri onayla", "provisioningKeysApproveNewSites": "Yeni Siteleri Onayla",
"provisioningKeysApproveNewSitesDescription": "Bu anahtar ile kayıt olan siteleri otomatik olarak onayla.", "provisioningKeysApproveNewSitesDescription": "Bu anahtar ile kayıt olan siteleri otomatik olarak onayla.",
"provisioningKeysUpdateError": "Tedarik anahtarı güncellenirken hata oluştu", "provisioningKeysUpdateError": "Tedarik anahtarı güncellenirken hata oluştu",
"provisioningKeysUpdated": "Tedarik anahtarı güncellendi", "provisioningKeysUpdated": "Tedarik anahtarı güncellendi",
@@ -597,7 +627,8 @@
"idpNameInternal": "Dahili", "idpNameInternal": "Dahili",
"emailInvalid": "Geçersiz e-posta adresi", "emailInvalid": "Geçersiz e-posta adresi",
"inviteValidityDuration": "Lütfen bir süre seçin", "inviteValidityDuration": "Lütfen bir süre seçin",
"accessRoleSelectPlease": "Lütfen bir rol seçin", "accessRoleSelectPlease": "Bir kullanıcı en az bir role ait olmalıdır.",
"accessRoleRequired": "Rol gerekli",
"removeOwnAdminRoleConfirmTitle": "Yönetici erişiminizi kaldırmak istiyor musunuz?", "removeOwnAdminRoleConfirmTitle": "Yönetici erişiminizi kaldırmak istiyor musunuz?",
"removeOwnAdminRoleConfirmDescription": "Kaydettikten sonra, bu organizasyonda artık yönetici izinleriniz olmayacak. Gerekirse başka bir yönetici erişimi geri yükleyebilir.", "removeOwnAdminRoleConfirmDescription": "Kaydettikten sonra, bu organizasyonda artık yönetici izinleriniz olmayacak. Gerekirse başka bir yönetici erişimi geri yükleyebilir.",
"removeOwnAdminRoleConfirmButton": "Yönetici Erişimi Kaldır", "removeOwnAdminRoleConfirmButton": "Yönetici Erişimi Kaldır",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "Temel Başlık Kimlik Doğrulama", "policyAuthHeaderAuthTitle": "Temel Başlık Kimlik Doğrulama",
"policyAuthHeaderAuthDescription": "Her istekte özel bir HTTP başlık adını ve değerini doğrulayın", "policyAuthHeaderAuthDescription": "Her istekte özel bir HTTP başlık adını ve değerini doğrulayın",
"policyAuthHeaderAuthSummary": "Başlık yapılandırıldı", "policyAuthHeaderAuthSummary": "Başlık yapılandırıldı",
"policyAuthHeaderName": "Başlık adı", "policyAuthHeaderName": "Kullanıcı Adı",
"policyAuthHeaderValue": "Beklenen değer", "policyAuthHeaderValue": "Şifre",
"policyAuthSetPasscode": "Şifreyi Ayarla", "policyAuthSetPasscode": "Şifreyi Ayarla",
"policyAuthSetPincode": "PIN Kodunu Ayarla", "policyAuthSetPincode": "PIN Kodunu Ayarla",
"policyAuthSetEmailWhitelist": "E-posta Beyaz Listesini Ayarla", "policyAuthSetEmailWhitelist": "E-posta Beyaz Listesini Ayarla",
@@ -903,7 +934,7 @@
"newtVersion": "Sürüm", "newtVersion": "Sürüm",
"architecture": "Mimari", "architecture": "Mimari",
"sites": "Siteler", "sites": "Siteler",
"siteWgAnyClients": "Herhangi bir WireGuard istemcisi kullanarak bağlanın. Dahili kaynaklara eş IP adresini kullanarak erişmeniz gerekecek.", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "Tüm WireGuard istemcileriyle uyumlu", "siteWgCompatibleAllClients": "Tüm WireGuard istemcileriyle uyumlu",
"siteWgManualConfigurationRequired": "Manuel yapılandırma gerekli", "siteWgManualConfigurationRequired": "Manuel yapılandırma gerekli",
"userErrorNotAdminOrOwner": "Kullanıcı yönetici veya sahibi değil", "userErrorNotAdminOrOwner": "Kullanıcı yönetici veya sahibi değil",
@@ -1378,6 +1409,7 @@
"createOrgUser": "Organizasyon Kullanıcısı Oluştur", "createOrgUser": "Organizasyon Kullanıcısı Oluştur",
"actionUpdateOrg": "Kuruluşu Güncelle", "actionUpdateOrg": "Kuruluşu Güncelle",
"actionRemoveInvitation": "Daveti Kaldır", "actionRemoveInvitation": "Daveti Kaldır",
"actionRemoveUserRole": "Kullanıcı Rolünü Kaldır",
"actionUpdateUser": "Kullanıcıyı Güncelle", "actionUpdateUser": "Kullanıcıyı Güncelle",
"actionGetUser": "Kullanıcıyı Getir", "actionGetUser": "Kullanıcıyı Getir",
"actionGetOrgUser": "Kuruluş Kullanıcısını Al", "actionGetOrgUser": "Kuruluş Kullanıcısını Al",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "Planı Uygula", "actionApplyBlueprint": "Planı Uygula",
"actionListBlueprints": "Plan Listesini Görüntüle", "actionListBlueprints": "Plan Listesini Görüntüle",
"actionGetBlueprint": "Planı Elde Et", "actionGetBlueprint": "Planı Elde Et",
"actionCreateOrgWideLauncherView": "Kuruluş Genelinde Başlatıcı Görünümü Oluşturma",
"setupToken": "Kurulum Simgesi", "setupToken": "Kurulum Simgesi",
"setupTokenDescription": "Sunucu konsolundan kurulum simgesini girin.", "setupTokenDescription": "Sunucu konsolundan kurulum simgesini girin.",
"setupTokenRequired": "Kurulum simgesi gerekli", "setupTokenRequired": "Kurulum simgesi gerekli",
"actionUpdateSite": "Siteyi Güncelle", "actionUpdateSite": "Siteyi Güncelle",
"actionApproveSite": "Siteyi Onayla",
"actionRejectSite": "Siteyi Reddet",
"actionResetSiteBandwidth": "Organizasyon Bant Genişliğini Sıfırla", "actionResetSiteBandwidth": "Organizasyon Bant Genişliğini Sıfırla",
"actionListSiteRoles": "İzin Verilen Site Rolleri Listele", "actionListSiteRoles": "İzin Verilen Site Rolleri Listele",
"actionCreateResource": "Kaynak Oluştur", "actionCreateResource": "Kaynak Oluştur",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "Kaynak PIN Kodunu Ayarla", "actionSetResourcePincode": "Kaynak PIN Kodunu Ayarla",
"actionSetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesi Ayarla", "actionSetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesi Ayarla",
"actionGetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesini Al", "actionGetResourceEmailWhitelist": "Kaynak E-posta Beyaz Listesini Al",
"actionGetResourcePolicy": "Kaynak Politikasını Al",
"actionUpdateResourcePolicy": "Kaynak Politikasını Güncelle",
"actionSetResourcePolicyUsers": "Kaynak Politika Kullanıcılarını Ayarla",
"actionSetResourcePolicyRoles": "Kaynak Politika Rolleri Ayarla",
"actionSetResourcePolicyPassword": "Kaynak Politika Şifresini Ayarla",
"actionSetResourcePolicyPincode": "Kaynak Politika Pincode Ayarla",
"actionSetResourcePolicyHeaderAuth": "Kaynak Politika Başlık Kimlik Doğrulama Ayarla",
"actionSetResourcePolicyWhitelist": "Kaynak Politika E-posta Beyaz Listesi Ayarla",
"actionSetResourcePolicyRules": "Kaynak Politika Kurallarını Ayarla",
"actionCreateTarget": "Hedef Oluştur", "actionCreateTarget": "Hedef Oluştur",
"actionDeleteTarget": "Hedefi Sil", "actionDeleteTarget": "Hedefi Sil",
"actionGetTarget": "Hedefi Al", "actionGetTarget": "Hedefi Al",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "Erişim Jetonu Oluştur", "actionGenerateAccessToken": "Erişim Jetonu Oluştur",
"actionDeleteAccessToken": "Erişim Jetonunu Sil", "actionDeleteAccessToken": "Erişim Jetonunu Sil",
"actionListAccessTokens": "Erişim Jetonlarını Listele", "actionListAccessTokens": "Erişim Jetonlarını Listele",
"actionCreateResourceSessionToken": "Kaynak Oturum Otomasyonu Oluştur",
"actionCreateResourceRule": "Kaynak Kuralı Oluştur", "actionCreateResourceRule": "Kaynak Kuralı Oluştur",
"actionDeleteResourceRule": "Kaynak Kuralını Sil", "actionDeleteResourceRule": "Kaynak Kuralını Sil",
"actionListResourceRules": "Kaynak Kurallarını Listele", "actionListResourceRules": "Kaynak Kurallarını Listele",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "Davetiyeleri Listele", "actionListInvitations": "Davetiyeleri Listele",
"actionExportLogs": "Kayıtları Dışa Aktar", "actionExportLogs": "Kayıtları Dışa Aktar",
"actionViewLogs": "Kayıtları Görüntüle", "actionViewLogs": "Kayıtları Görüntüle",
"actionCreateSiteProvisioningKey": "Site Sağlama Anahtarı Oluştur",
"actionListSiteProvisioningKeys": "Site Sağlama Anahtarlarını Listele",
"actionUpdateSiteProvisioningKey": "Site Sağlama Anahtarını Güncelle",
"actionDeleteSiteProvisioningKey": "Site Sağlama Anahtarını Sil",
"noneSelected": "Hiçbiri seçili değil", "noneSelected": "Hiçbiri seçili değil",
"orgNotFound2": "Hiçbir organizasyon bulunamadı.", "orgNotFound2": "Hiçbir organizasyon bulunamadı.",
"search": "Ara…", "search": "Ara…",
@@ -1486,10 +1535,35 @@
"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:",
"idpLastUsed": "Son Kullanılan",
"otpAuthBack": "Şifreye Geri Dön", "otpAuthBack": "Şifreye Geri Dön",
"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",
"commandPaletteTitle": "Komut Paleti",
"commandPaletteDescription": "Sayfalar, organizasyonlar, kaynaklar ve işlemler için arama yapın",
"commandPaletteSearchPlaceholder": "Sayfaları, kaynakları, işlemleri ara...",
"commandPaletteNoResults": "Sonuç bulunamadı.",
"commandPaletteSearching": "Aranıyor...",
"commandPaletteNavigation": "Navigasyon",
"commandPaletteOrganizations": "Organizasyonlar",
"commandPaletteSites": "Siteler",
"commandPaletteResources": "Kaynaklar",
"commandPaletteUsers": "Kullanıcılar",
"commandPaletteClients": "Makine İstemcileri",
"commandPaletteActions": "İşlemler",
"commandPaletteCreateSite": "Site Oluştur",
"commandPaletteCreateProxyResource": "Genel Kaynak Oluştur",
"commandPaletteCreatePrivateResource": "Özel Kaynak Oluştur",
"commandPaletteCreateUser": "Kullanıcı Oluştur",
"commandPaletteCreateApiKey": "API Anahtarı Oluştur",
"commandPaletteCreateMachineClient": "Makine İstemcisi Oluştur",
"commandPaletteCreateAlertRule": "Uyarı Kuralı Oluştur",
"commandPaletteCreateIdentityProvider": "Kimlik Sağlayıcı Oluştur",
"commandPaletteToggleTheme": "Temayı Aç/Kapat",
"commandPaletteChooseOrganization": "Organizasyon Seç",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "2FA etkinleştirilemedi", "otpErrorEnable": "2FA etkinleştirilemedi",
"otpErrorEnableDescription": "2FA etkinleştirilirken bir hata oluştu", "otpErrorEnableDescription": "2FA etkinleştirilirken bir hata oluştu",
"otpSetupCheckCode": "6 haneli bir kod girin", "otpSetupCheckCode": "6 haneli bir kod girin",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "Yönetim", "sidebarManagement": "Yönetim",
"sidebarBillingAndLicenses": "Faturalandırma & Lisanslar", "sidebarBillingAndLicenses": "Faturalandırma & Lisanslar",
"sidebarLogsAnalytics": "Analitik", "sidebarLogsAnalytics": "Analitik",
"commandSites": "Siteler",
"commandActionModeInfo": "Eylem Modunu Açmak İçin \">\" Yazın",
"commandResources": "Kaynaklar",
"commandProxyResources": "Genel Kaynaklar",
"commandClientResources": "Özel Kaynaklar",
"commandClients": "İstemciler",
"commandUserDevices": "Kullanıcı Aygıtları",
"commandMachineClients": "Makine İstemcileri",
"commandDomains": "Alan Adları",
"commandRemoteExitNodes": "Uzak Düğümler",
"commandTeam": "Ekip",
"commandUsers": "Kullanıcılar",
"commandRoles": "Roller",
"commandInvitations": "Davetiyeler",
"commandPolicies": "Paylaşılan Politikalar",
"commandResourcePolicies": "Genel Kaynaklar Politikaları",
"commandIdentityProviders": "Kimlik Sağlayıcılar",
"commandApprovals": "Onay İstekleri",
"commandShareableLinks": "Paylaşılabilir Bağlantılar",
"commandOrganization": "Organizasyon",
"commandLogsAndAnalytics": "Günlükler ve Analitik",
"commandLogsAnalytics": "Analitik",
"commandLogsRequest": "HTTP İstek Günlükleri",
"commandLogsAccess": "Kimlik Doğrulama Günlükleri",
"commandLogsAction": "Yönetim Eylemi Günlükleri",
"commandLogsConnection": "Ağ Günlükleri",
"commandLogsStreaming": "Olay Akışı",
"commandManagement": "Yönetim",
"commandAlerting": "Uyarılar",
"commandProvisioning": "Sağlama",
"commandBluePrints": "Planlar",
"commandApiKeys": "API Anahtarları",
"commandBillingAndLicenses": "Faturalama ve Lisanslar",
"commandBilling": "Faturalama",
"commandEnterpriseLicenses": "Lisanslar",
"commandSettings": "Ayarlar",
"commandLauncher": "Başlatıcı",
"commandResourceLauncher": "Kaynak Başlatıcı",
"commandSearchResults": "Arama Sonuçları",
"alertingTitle": "Uyarı", "alertingTitle": "Uyarı",
"alertingDescription": "Bildirimler için kaynakları, tetikleyicileri ve eylemleri tanımlayın", "alertingDescription": "Bildirimler için kaynakları, tetikleyicileri ve eylemleri tanımlayın",
"alertingRules": "Uyarı kuralları", "alertingRules": "Uyarı kuralları",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "Alt Alan: {subdomain}", "domainPickerSubdomain": "Alt Alan: {subdomain}",
"domainPickerNamespace": "Ad Alanı: {namespace}", "domainPickerNamespace": "Ad Alanı: {namespace}",
"domainPickerShowMore": "Daha Fazla Göster", "domainPickerShowMore": "Daha Fazla Göster",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "Bölge Seç", "regionSelectorTitle": "Bölge Seç",
"domainPickerRemoteExitNodeWarning": "Belirtilen alan adları, siteler uzak çıkış düğümlerine bağlandığında desteklenmez. Kaynakların uzak düğümlerde kullanılabilir olması için özel bir alan adı kullanın.", "domainPickerRemoteExitNodeWarning": "Belirtilen alan adları, siteler uzak çıkış düğümlerine bağlandığında desteklenmez. Kaynakların uzak düğümlerde kullanılabilir olması için özel bir alan adı kullanın.",
"regionSelectorInfo": "Bir bölge seçmek, konumunuz için daha iyi performans sağlamamıza yardımcı olur. Sunucunuzla aynı bölgede olmanıza gerek yoktur.", "regionSelectorInfo": "Bir bölge seçmek, konumunuz için daha iyi performans sağlamamıza yardımcı olur. Sunucunuzla aynı bölgede olmanıza gerek yoktur.",
@@ -1898,6 +2014,9 @@
"billingDomains": "Alan Adları", "billingDomains": "Alan Adları",
"billingOrganizations": "Organizasyonlar", "billingOrganizations": "Organizasyonlar",
"billingRemoteExitNodes": "Uzak Düğümler", "billingRemoteExitNodes": "Uzak Düğümler",
"billingPublicResources": "Genel Kaynaklar",
"billingPrivateResources": "Özel Kaynaklar",
"billingMachineClients": "Makine İstemcileri",
"billingNoLimitConfigured": "Hiçbir limit yapılandırılmadı", "billingNoLimitConfigured": "Hiçbir limit yapılandırılmadı",
"billingEstimatedPeriod": "Tahmini Fatura Dönemi", "billingEstimatedPeriod": "Tahmini Fatura Dönemi",
"billingIncludedUsage": "Dahil Kullanım", "billingIncludedUsage": "Dahil Kullanım",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "Kaç tane kullanıcı kullanabileceğiniz", "billingUsersInfo": "Kaç tane kullanıcı kullanabileceğiniz",
"billingDomainInfo": "Kaç tane alan adı kullanabileceğiniz", "billingDomainInfo": "Kaç tane alan adı kullanabileceğiniz",
"billingRemoteExitNodesInfo": "Kaç tane uzaktan düğüm kullanabileceğiniz", "billingRemoteExitNodesInfo": "Kaç tane uzaktan düğüm kullanabileceğiniz",
"billingPublicResourcesInfo": "Kaç adet genel kaynağı kullanabileceğinizi görün",
"billingPrivateResourcesInfo": "Kaç adet özel kaynağı kullanabileceğinizi görün",
"billingMachineClientsInfo": "Kaç adet makine istemcisi kullanabileceğinizi görün",
"billingLicenseKeys": "Lisans Anahtarları", "billingLicenseKeys": "Lisans Anahtarları",
"billingLicenseKeysDescription": "Lisans anahtarı aboneliklerinizi yönetin", "billingLicenseKeysDescription": "Lisans anahtarı aboneliklerinizi yönetin",
"billingLicenseSubscription": "Lisans Aboneliği", "billingLicenseSubscription": "Lisans Aboneliği",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "Alt ağ", "subnetPlaceholder": "Alt ağ",
"addressDescription": "İstemcinin dahili adresi. Organizasyon alt ağı içinde olmalıdır.", "addressDescription": "İstemcinin dahili adresi. Organizasyon alt ağı içinde olmalıdır.",
"selectSites": "Siteleri seçin", "selectSites": "Siteleri seçin",
"selectLabels": "Etiketleri seçin",
"sitesDescription": "Müşteri seçilen sitelere bağlantı kuracaktır", "sitesDescription": "Müşteri seçilen sitelere bağlantı kuracaktır",
"clientInstallOlm": "Olm Yükle", "clientInstallOlm": "Olm Yükle",
"clientInstallOlmDescription": "Sisteminizde Olm çalıştırın", "clientInstallOlmDescription": "Sisteminizde Olm çalıştırın",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "Herkese Açık", "resourcesTableProxyResources": "Herkese Açık",
"resourcesTableClientResources": "Özel", "resourcesTableClientResources": "Özel",
"resourcesTableNoProxyResourcesFound": "Hiçbir proxy kaynağı bulunamadı.", "resourcesTableNoProxyResourcesFound": "Hiçbir proxy kaynağı bulunamadı.",
"resourcesTableNoInternalResourcesFound": "Hiçbir dahili kaynak bulunamadı.", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "Hedef", "resourcesTableDestination": "Hedef",
"resourcesTableAlias": "Takma Ad", "resourcesTableAlias": "Takma Ad",
"resourcesTableAliasAddress": "Alias Adresi", "resourcesTableAliasAddress": "Alias Adresi",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "İptal", "editInternalResourceDialogCancel": "İptal",
"editInternalResourceDialogSaveResource": "Kaynağı Kaydet", "editInternalResourceDialogSaveResource": "Kaynağı Kaydet",
"editInternalResourceDialogSuccess": "Başarı", "editInternalResourceDialogSuccess": "Başarı",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Dahili kaynak başarıyla güncellendi", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "Hata", "editInternalResourceDialogError": "Hata",
"editInternalResourceDialogFailedToUpdateInternalResource": "Dahili kaynak güncellenemedi", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "Ad gerekli", "editInternalResourceDialogNameRequired": "Ad gerekli",
"editInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır", "editInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
"editInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır", "editInternalResourceDialogProxyPortMin": "Proxy bağlantı noktası en az 1 olmalıdır",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Takma Ad", "editInternalResourceDialogAlias": "Takma Ad",
"editInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.", "editInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.",
"createInternalResourceDialogNoSitesAvailable": "Site Bulunamadı", "createInternalResourceDialogNoSitesAvailable": "Site Bulunamadı",
"createInternalResourceDialogNoSitesAvailableDescription": "Dahili kaynak oluşturmak için en az bir Newt sitesine ve alt ağa sahip olmalısınız.", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "Kapat", "createInternalResourceDialogClose": "Kapat",
"createInternalResourceDialogCreateClientResource": "Özel Kaynak Oluştur", "createInternalResourceDialogCreateClientResource": "Özel Kaynak Oluştur",
"createInternalResourceDialogCreateClientResourceDescription": "Seçilen siteye bağlı istemcilere erişilebilir olacak yeni bir kaynak oluşturun", "createInternalResourceDialogCreateClientResourceDescription": "Seçilen siteye bağlı istemcilere erişilebilir olacak yeni bir kaynak oluşturun",
"privateResourceGeneralDescription": "Kaynağın adı, tanımlayıcı ve diğer genel ayarlarını yapılandırın.",
"privateResourceCreatePageSeeAll": "Tüm Özel Kaynakları Gör",
"privateResourceAllowIcmpPing": "ICMP Ping İzne Ver",
"privateResourceNetworkAccess": "Ağ Erişimi",
"privateResourceNetworkAccessDescription": "Bu kaynak için TCP/UDP port erişimini kontrol edin ve ICMP ping'in izin verilip verilmediğini kontrol edin.",
"hostSettings": "Sunucu Ayarları",
"cidrSettings": "CIDR Ayarları",
"createInternalResourceDialogResourceProperties": "Kaynak Özellikleri", "createInternalResourceDialogResourceProperties": "Kaynak Özellikleri",
"createInternalResourceDialogName": "Ad", "createInternalResourceDialogName": "Ad",
"createInternalResourceDialogSite": "Site", "createInternalResourceDialogSite": "Site",
"selectSite": "Site seç...", "selectSite": "Site seç...",
"multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# siteler}}", "multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# siteler}}",
"labelsSelectorLabelsCount": "{count, plural, one {# etiket} other {# etiketler}}",
"noSitesFound": "Site bulunamadı.", "noSitesFound": "Site bulunamadı.",
"createInternalResourceDialogProtocol": "Protokol", "createInternalResourceDialogProtocol": "Protokol",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "İptal", "createInternalResourceDialogCancel": "İptal",
"createInternalResourceDialogCreateResource": "Kaynak Oluştur", "createInternalResourceDialogCreateResource": "Kaynak Oluştur",
"createInternalResourceDialogSuccess": "Başarı", "createInternalResourceDialogSuccess": "Başarı",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "Dahili kaynak başarıyla oluşturuldu", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "Hata", "createInternalResourceDialogError": "Hata",
"createInternalResourceDialogFailedToCreateInternalResource": "Dahili kaynak oluşturulamadı", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "Ad gerekli", "createInternalResourceDialogNameRequired": "Ad gerekli",
"createInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır", "createInternalResourceDialogNameMaxLength": "Ad 255 karakterden kısa olmalıdır",
"createInternalResourceDialogPleaseSelectSite": "Lütfen bir site seçin", "createInternalResourceDialogPleaseSelectSite": "Lütfen bir site seçin",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "Site ağındaki kaynağın CIDR aralığı.", "createInternalResourceDialogDestinationCidrDescription": "Site ağındaki kaynağın CIDR aralığı.",
"createInternalResourceDialogAlias": "Takma Ad", "createInternalResourceDialogAlias": "Takma Ad",
"createInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.", "createInternalResourceDialogAliasDescription": "Bu kaynak için isteğe bağlı dahili DNS takma adı.",
"internalResourceAliasLocalWarning": "Bazı ağlarda mDNS nedeniyle .local ile biten takma adlar çözümleme sorunlarına neden olabilir.",
"internalResourceDownstreamSchemeRequired": "HTTP kaynakları için şema gereklidir", "internalResourceDownstreamSchemeRequired": "HTTP kaynakları için şema gereklidir",
"internalResourceHttpPortRequired": "HTTP kaynakları için hedef bağlantı noktası gereklidir", "internalResourceHttpPortRequired": "HTTP kaynakları için hedef bağlantı noktası gereklidir",
"siteConfiguration": "Yapılandırma", "siteConfiguration": "Yapılandırma",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "Uzak Düğümler", "sidebarRemoteExitNodes": "Uzak Düğümler",
"remoteExitNodeId": "Kimlik", "remoteExitNodeId": "Kimlik",
"remoteExitNodeSecretKey": "Gizli", "remoteExitNodeSecretKey": "Gizli",
"remoteExitNodeNetworkingTitle": "Ağ Ayarları",
"remoteExitNodeNetworkingDescription": "Bu uzak çıkış düğümünün trafiği nasıl yönlendireceğini ve hangi sitelerin bu üzerinden bağlanmayı tercih edeceğini yapılandırın. Gelişmiş özellikler geri bağlantı ağ konfigürasyonları ile kullanılmalıdır.",
"remoteExitNodeNetworkingSave": "Ayarları Kaydet",
"remoteExitNodeNetworkingSaveSuccessTitle": "Ağ ayarları kaydedildi",
"remoteExitNodeNetworkingSaveSuccessDescription": "Ağ ayarları başarıyla güncellendi.",
"remoteExitNodeNetworkingSaveError": "Ağ ayarları kaydedilemedi",
"remoteExitNodeNetworkingSubnetsTitle": "Uzak Alt Ağlar",
"remoteExitNodeNetworkingSubnetsDescription": "Bu uzak çıkış düğümünün trafiği taşıyacağı CIDR aralıklarını tanımlayın. Geçerli bir CIDR (örneğin, <code>10.0.0.0/8</code>) yazın ve eklemek için Enter tuşuna basın.",
"remoteExitNodeNetworkingSubnetsPlaceholder": "Bir CIDR aralığı ekle (örneğin, 10.0.0.0/8)",
"remoteExitNodeNetworkingSubnetsLoadError": "Alt ağlar yüklenemedi",
"remoteExitNodeNetworkingLabelsTitle": "Tercih Etiketleri",
"remoteExitNodeNetworkingLabelsDescription": "Bu etiketlere sahip siteler, bu uzak çıkış düğümü üzerinden bağlantı kurmaya zorlanacaktır.",
"remoteExitNodeNetworkingLabelsButtonText": "Etiketleri seç...",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Etiketleri ara...",
"remoteExitNodeNetworkingLabelsLoadError": "Etiketler yüklenemedi",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "Uzak Düğüm Oluştur", "title": "Uzak Düğüm Oluştur",
"description": "Yeni bir kendine misafir uzaktan ileti ve ara sunucu düğümü oluşturun", "description": "Yeni bir kendine misafir uzaktan ileti ve ara sunucu düğümü oluşturun",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "Bu organizasyon için düğüm mevcut değil. Yerel siteleri kullanmak için önce bir düğüm oluşturun.", "noRemoteExitNodesAvailableDescription": "Bu organizasyon için düğüm mevcut değil. Yerel siteleri kullanmak için önce bir düğüm oluşturun.",
"exitNode": "Çıkış Düğümü", "exitNode": "Çıkış Düğümü",
"country": "Ülke", "country": "Ülke",
"countryIsNot": "Ülke Değil",
"rulesMatchCountry": "Şu anda kaynak IP'ye dayanarak", "rulesMatchCountry": "Şu anda kaynak IP'ye dayanarak",
"region": "Bölge", "region": "Bölge",
"selectRegion": "Bölgeyi seçin", "selectRegion": "Bölgeyi seçin",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC sağlayıcısı", "idpGoogleDescription": "Google OAuth2/OIDC sağlayıcısı",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC sağlayıcısı", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC sağlayıcısı",
"subnet": "Alt ağ", "subnet": "Alt ağ",
"utilitySubnet": "Yardımcı Alt Ağ",
"subnetDescription": "Bu organizasyonun ağ yapılandırması için alt ağ.", "subnetDescription": "Bu organizasyonun ağ yapılandırması için alt ağ.",
"customDomain": "Özel Alan", "customDomain": "Özel Alan",
"authPage": "Kimlik Sayfaları", "authPage": "Kimlik Sayfaları",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "İki faktörlü kimlik doğrulama ayarı gereklidir. Bu adımı tamamlamak için lütfen tekrar {dashboardUrl}/auth/login üzerinden oturum açın. Sonra buraya geri dönün.", "twoFactorSetupRequired": "İki faktörlü kimlik doğrulama ayarı gereklidir. Bu adımı tamamlamak için lütfen tekrar {dashboardUrl}/auth/login üzerinden oturum açın. Sonra buraya geri dönün.",
"additionalSecurityRequired": "Ek Güvenlik Gereklidir", "additionalSecurityRequired": "Ek Güvenlik Gereklidir",
"organizationRequiresAdditionalSteps": "Bu kuruluş, kaynaklara erişmeden önce ek güvenlik adımları gerektirir.", "organizationRequiresAdditionalSteps": "Bu kuruluş, kaynaklara erişmeden önce ek güvenlik adımları gerektirir.",
"sessionExpired": "Oturum Süresi Doldu",
"sessionExpiredReauthRequired": "Organizasyonunuzun güvenlik politikası gereği oturum süreniz doldu. Devam etmek için yeniden kimlik doğrulaması yapın.",
"reauthenticate": "Yeniden Kimlik Doğrula",
"completeTheseSteps": "Bu adımları tamamlayın", "completeTheseSteps": "Bu adımları tamamlayın",
"enableTwoFactorAuthentication": "İki faktörlü kimlik doğrulamayı etkinleştir", "enableTwoFactorAuthentication": "İki faktörlü kimlik doğrulamayı etkinleştir",
"completeSecuritySteps": "Güvenlik Adımlarını Tamamla", "completeSecuritySteps": "Güvenlik Adımlarını Tamamla",
@@ -2946,8 +3098,8 @@
"sourceAddress": "Kaynak Adresi", "sourceAddress": "Kaynak Adresi",
"destinationAddress": "Hedef Adresi", "destinationAddress": "Hedef Adresi",
"duration": "Süre", "duration": "Süre",
"licenseRequiredToUse": "Bu özelliği kullanmak için bir <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> lisansı veya <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> gereklidir. <bookADemoLink>Tanıtım veya POC denemesi ayarlayın</bookADemoLink>.", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "Bu özelliği kullanmak için <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> gereklidir. Bu özellik ayrıca <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>da da mevcuttur. <bookADemoLink>Tanıtım veya POC denemesi ayarlayın</bookADemoLink>.", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "Sertifika Çözücü", "certResolver": "Sertifika Çözücü",
"certResolverDescription": "Bu kaynak için kullanılacak sertifika çözücüsünü seçin.", "certResolverDescription": "Bu kaynak için kullanılacak sertifika çözücüsünü seçin.",
"selectCertResolver": "Sertifika Çözücü Seçin", "selectCertResolver": "Sertifika Çözücü Seçin",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "Organizasyon veya Alan Adı Kimliği eksik", "orgOrDomainIdMissing": "Organizasyon veya Alan Adı Kimliği eksik",
"loadingDNSRecords": "DNS kayıtları yükleniyor...", "loadingDNSRecords": "DNS kayıtları yükleniyor...",
"olmUpdateAvailableInfo": "Olm'nin güncellenmiş bir sürümü mevcut. En iyi deneyim için lütfen en son sürüme güncelleyin.", "olmUpdateAvailableInfo": "Olm'nin güncellenmiş bir sürümü mevcut. En iyi deneyim için lütfen en son sürüme güncelleyin.",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "Güncellenmiş bir sürüm mevcut. En iyi deneyim için lütfen en son sürüme güncelleyin.",
"client": "İstemci", "client": "İstemci",
"proxyProtocol": "Proxy Protokol Ayarları", "proxyProtocol": "Proxy Protokol Ayarları",
"proxyProtocolDescription": "TCP hizmetleri için istemci IP adreslerini korumak amacıyla Proxy Protokolünü yapılandırın.", "proxyProtocolDescription": "TCP hizmetleri için istemci IP adreslerini korumak amacıyla Proxy Protokolünü yapılandırın.",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "Kullanıcılar Ekle", "editInternalResourceDialogAddUsers": "Kullanıcılar Ekle",
"editInternalResourceDialogAddClients": "Müşteriler Ekle", "editInternalResourceDialogAddClients": "Müşteriler Ekle",
"editInternalResourceDialogDestinationLabel": "Hedef", "editInternalResourceDialogDestinationLabel": "Hedef",
"editInternalResourceDialogDestinationDescription": "Dahili kaynak için hedef adresi belirtin. Seçilen moda bağlı olarak bu bir ana bilgisayar adı, IP adresi veya CIDR aralığı olabilir. Daha kolay tanımlama için isteğe bağlı olarak dahili bir DNS takma adı ayarlayın.", "editInternalResourceDialogDestinationDescription": "Bu kaynağa müşterilerin nasıl erişeceğini yapılandırın.",
"internalResourceFormMultiSiteRoutingHelp": "Birden fazla site seçmek, yüksek kullanılabilirlik için dirençli yönlendirme ve yedeklik sağlar.", "internalResourceFormMultiSiteRoutingHelp": "Birden fazla site seçmek, yüksek kullanılabilirlik için dirençli yönlendirme ve yedeklik sağlar.",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "Daha fazla bilgi", "internalResourceFormMultiSiteRoutingHelpLearnMore": "Daha fazla bilgi",
"editInternalResourceDialogPortRestrictionsDescription": "Belirtilen TCP/UDP portlarına erişimi kısıtlayın veya tüm portlara izin/engelleme verin.", "editInternalResourceDialogPortRestrictionsDescription": "Belirtilen TCP/UDP portlarına erişimi kısıtlayın veya tüm portlara izin/engelleme verin.",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "E-posta Beyaz Listesi", "memberPortalEmailWhitelist": "E-posta Beyaz Listesi",
"memberPortalResourceDisabled": "Kaynak Devre Dışı", "memberPortalResourceDisabled": "Kaynak Devre Dışı",
"memberPortalShowingResources": "{total} kaynaktan {start}-{end} gösteriliyor", "memberPortalShowingResources": "{total} kaynaktan {start}-{end} gösteriliyor",
"resourceLauncherTitle": "Kaynak Başlatıcı",
"resourceSidebarLauncherTitle": "Başlatıcı",
"resourceLauncherDescription": "Tüm mevcut kaynakları görün ve bunları merkezi bir merkezden başlatın",
"resourceLauncherSearchPlaceholder": "Kaynaklarınızı arayın...",
"resourceLauncherDefaultView": "Varsayılan",
"resourceLauncherSaveView": "Görünümü Kaydet",
"resourceLauncherSaveToCurrentView": "Mevcut Görünüme Kaydet",
"resourceLauncherSaveDefaultPersonal": "Benim için Kaydet",
"resourceLauncherResetView": "Görünümü Sıfırla",
"resourceLauncherResetSystemDefault": "Sistem Varsayılanını Sıfırla",
"resourceLauncherSystemDefaultRestored": "Sistem varsayılanı geri yüklendi",
"resourceLauncherSystemDefaultRestoredDescription": "Varsayılan görünüm orijinal ayarlara sıfırlandı.",
"resourceLauncherSaveAsNewView": "Yeni Görünüm Olarak Kaydet",
"resourceLauncherSaveAsNewViewDescription": "Geçerli filtrelerinizi ve düzeninizi kaydetmek için bu görünüme bir ad verin.",
"resourceLauncherSaveForEveryone": "Herkes İçin Kaydet",
"resourceLauncherSaveForEveryoneDescription": "Bu görünümü tüm kuruluş üyeleriyle paylaşın. İşaretli değilse, görünüm yalnızca size görünür olur.",
"resourceLauncherMakePersonal": "Kişisel Yap",
"resourceLauncherFilter": "Filtre",
"resourceLauncherFilterWithCount": "Filtre, {count} uygulandı",
"resourceLauncherSort": "Sıralama",
"resourceLauncherSortAscending": "Artan sırala",
"resourceLauncherSortDescending": "Azalan sırala",
"resourceLauncherSettings": "Ayarlar",
"resourceLauncherGroupBy": "Grupla",
"resourceLauncherGroupBySite": "Site",
"resourceLauncherGroupByLabel": "Etiket",
"resourceLauncherGroupByNone": "Hiçbiri",
"resourceLauncherLayout": "Düzen",
"resourceLauncherLayoutGrid": "Izgara",
"resourceLauncherLayoutList": "Liste",
"resourceLauncherShowLabels": "Etiketleri Göster",
"resourceLauncherShowSiteTags": "Site Etiketlerini Göster",
"resourceLauncherShowRecents": "Son Eklenenleri Göster",
"resourceLauncherDeleteView": "Görünümü Sil",
"resourceLauncherDeleteViewTitle": "Görünümü Sil",
"resourceLauncherDeleteViewQuestion": "Bu başlatıcı görünümünü silmek istediğinizden emin misiniz?",
"resourceLauncherDeleteViewConfirm": "Görünümü Sil",
"resourceLauncherViewAsAdmin": "Yönetici Olarak Görüntüle",
"resourceLauncherResourceDetailsDescription": "Bu kaynağın bağlantı bilgileri ve durumu.",
"resourceLauncherResourceDetails": "Kaynak Detayları",
"resourceLauncherAuthMethodsDescription": "Bu kaynak için etkin kimlik doğrulama yöntemleri.",
"resourceLauncherPrivateClientRequired": "Bu kaynağa özel olarak erişmek için cihazınızda bir istemci ile bağlanın.",
"resourceLauncherPrivateClientRequiredTitle": "İstemci Bağlantısı Gerekli",
"resourceLauncherDownloadClient": "İstemci indir",
"resourceLauncherFailedToLoadDetails": "Kaynak detayları yüklenemedi. Bu kaynağa artık erişiminiz olmayabilir.",
"resourceLauncherNoPortRestrictions": "Hiçbir port kısıtlaması yok",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "Etiketsiz",
"resourceLauncherNoSite": "Site Yok",
"resourceLauncherNoResourcesInGroup": "Bu grupta kaynak yok",
"resourceLauncherEmptyStateTitle": "Kullanılabilir Kaynak Yok",
"resourceLauncherEmptyStateDescription": "Henüz hiçbir kaynağa erişiminiz yok. Erişim istemek için yöneticinizle iletişime geçin.",
"resourceLauncherEmptyStateNoResultsTitle": "Kaynak Bulunamadı",
"resourceLauncherEmptyStateNoResultsDescription": "Mevcut arama veya filtrelerinizle eşleşen kaynak yok. Aradığınızı bulmak için ayarları değiştirmeyi deneyin.",
"resourceLauncherEmptyStateNoResultsWithQuery": "\"{query}\" ile eşleşen kaynak yok. Tüm kaynakları görmek için aramayı düzenlemeyi veya filtreleri temizlemeyi deneyin.",
"resourceLauncherSearchFirstTitle": "Aranacak ya da Göz Atılacak Filtreler",
"resourceLauncherSearchFirstDescription": "Birçok kaynağa erişiminiz var. İhtiyacınız olanı bulmak için site veya etiketle arayın veya filtreleyin.",
"resourceLauncherSiteGroupingDisabled": "Bu ölçekte site gruplama mevcut değil. Daha küçük bir seti gruplamak için siteye göre filtreleyin.",
"resourceLauncherLabelGroupingDisabled": "Bu ölçekte etiket gruplama mevcut değil.",
"resourceLauncherCompactModeHint": "Daha hızlı göz atmak için basitleştirilmiş bir liste gösteriliyor. Sonuçları daraltmak için arayın veya filtreler kullanın.",
"resourceLauncherCompactGroupingHint": "Gruplama etkinleştirmek için site veya etiket filtreleri uygulayın.",
"resourceLauncherCopiedToClipboard": "Panoya kopyalandı",
"resourceLauncherCopiedAccessDescription": "Kaynağa erişim panonuza kopyalandı.",
"resourceLauncherViewNamePlaceholder": "Görünüm adı",
"resourceLauncherViewNameLabel": "Görünüm Adı",
"resourceLauncherViewSaved": "Görünüm kaydedildi",
"resourceLauncherViewSavedDescription": "Başlatıcı görünümünüz kaydedildi.",
"resourceLauncherViewSaveFailed": "Görünüm kaydedilemedi",
"resourceLauncherViewSaveFailedDescription": "Başlatıcı görünümü kaydedilemedi. Lütfen yeniden deneyin.",
"resourceLauncherViewDeleted": "Görünüm silindi",
"resourceLauncherViewDeletedDescription": "Başlatıcı görünüm silindi.",
"resourceLauncherViewDeleteFailed": "Görünüm silinemedi",
"resourceLauncherViewDeleteFailedDescription": "Başlatıcı görünümü silinemedi. Lütfen tekrar deneyin.",
"memberPortalPrevious": "Önceki", "memberPortalPrevious": "Önceki",
"memberPortalNext": "Sonraki", "memberPortalNext": "Sonraki",
"httpSettings": "HTTP Ayarları", "httpSettings": "HTTP Ayarları",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BAŞLANGIÇ OPENSSH ÖZEL ANAHTARI-----", "sshPrivateKeyPlaceholder": "-----BAŞLANGIÇ OPENSSH ÖZEL ANAHTARI-----",
"sshPrivateKeyRequired": "Özel anahtar gereklidir", "sshPrivateKeyRequired": "Özel anahtar gereklidir",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "Bağlanmak için VNC parolanızı girin", "vncSignInDescription": "Bağlanmak için VNC kimlik bilgilerinizi girin",
"vncUsernameOptional": "Kullanıcı Adı (isteğe bağlı)",
"vncPasswordOptional": "Parola (isteğe bağlı)", "vncPasswordOptional": "Parola (isteğe bağlı)",
"vncNoResourceTarget": "Kaynak hedefi mevcut değil", "vncNoResourceTarget": "Kaynak hedefi mevcut değil",
"vncFailedToLoadNovnc": "NoVNC yüklenemedi", "vncFailedToLoadNovnc": "NoVNC yüklenemedi",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "Yükleme başarısız", "rdpUploadFailed": "Yükleme başarısız",
"rdpUnicodeKeyboardMode": "Unicode klavye modu", "rdpUnicodeKeyboardMode": "Unicode klavye modu",
"sessionToolbarShow": "Araç çubuğunu göster", "sessionToolbarShow": "Araç çubuğunu göster",
"sessionToolbarHide": "Araç çubuğunu gizle" "sessionToolbarHide": "Araç çubuğunu gizle",
"actionUpdateSiteApprovals": "Site Onaylarını Güncelle"
} }
+249 -21
View File
@@ -66,9 +66,15 @@
"local": "本地的", "local": "本地的",
"edit": "编辑", "edit": "编辑",
"siteConfirmDelete": "确认删除节点", "siteConfirmDelete": "确认删除节点",
"siteConfirmDeleteAndResources": "确认删除站点及资源",
"siteDelete": "删除节点", "siteDelete": "删除节点",
"siteDeleteAndResources": "删除站点及资源",
"siteMessageRemove": "一旦移除,节点将无法访问。与节点相关的所有目标也将被移除。", "siteMessageRemove": "一旦移除,节点将无法访问。与节点相关的所有目标也将被移除。",
"siteMessageRemoveAndResources": "这将永久删除与该站点关联的所有公共和私人资源,即使资源也与其他站点相关联。",
"siteQuestionRemove": "您确定要从组织中删除该节点吗?", "siteQuestionRemove": "您确定要从组织中删除该节点吗?",
"siteQuestionRemoveAndResources": "您确定要删除此站点及所有关联资源吗?",
"sitesTableDeleteSite": "删除站点",
"sitesTableDeleteSiteAndResources": "删除站点及资源",
"siteManageSites": "管理站点", "siteManageSites": "管理站点",
"siteDescription": "创建和管理站点,启用与私人网络的连接", "siteDescription": "创建和管理站点,启用与私人网络的连接",
"sitesBannerTitle": "连接任何网络", "sitesBannerTitle": "连接任何网络",
@@ -117,6 +123,16 @@
"siteUpdated": "站点已更新", "siteUpdated": "站点已更新",
"siteUpdatedDescription": "网站已更新。", "siteUpdatedDescription": "网站已更新。",
"siteGeneralDescription": "配置此站点的常规设置", "siteGeneralDescription": "配置此站点的常规设置",
"siteRestartTitle": "重启站点",
"siteRestartDescription": "重启此站点的WireGuard隧道。此操作将暂时中断连接。",
"siteRestartBody": "如果站点隧道无法正常工作,并且您希望在不重启主机的情况下强制重新连接,请使用此选项。",
"siteRestartButton": "重启站点",
"siteRestartDialogMessage": "确定要重启<b>{name}</b>的WireGuard隧道吗?站点将暂时断开连接。",
"siteRestartWarning": "隧道重启时,站点将暂时断开连接。",
"siteRestarted": "站点已重启",
"siteRestartedDescription": "WireGuard隧道已重启。",
"siteErrorRestart": "重启站点失败",
"siteErrorRestartDescription": "重启站点时发生错误。",
"siteSettingDescription": "配置站点设置", "siteSettingDescription": "配置站点设置",
"siteResourcesTab": "资源", "siteResourcesTab": "资源",
"siteResourcesNoneOnSite": "此站点尚无公开或私人资源。", "siteResourcesNoneOnSite": "此站点尚无公开或私人资源。",
@@ -162,7 +178,7 @@
"shareDeleteConfirm": "确认删除共享链接", "shareDeleteConfirm": "确认删除共享链接",
"shareQuestionRemove": "您确定要删除这个共享链接吗?", "shareQuestionRemove": "您确定要删除这个共享链接吗?",
"shareMessageRemove": "删除后,该链接将不再可用,使用它的任何人将失去对资源的访问权限。", "shareMessageRemove": "删除后,该链接将不再可用,使用它的任何人将失去对资源的访问权限。",
"shareTokenDescription": "访问令牌可以通过两种方式传递:作为查询参数或请求标题。 每次验证访问请求都必须从客户端传递。", "shareTokenDescription": "The access token can be passed as a query parameter or in request headers. By default it must be sent on every request. If session persistence is enabled, the first request exchanges it for a session cookie.",
"accessToken": "访问令牌", "accessToken": "访问令牌",
"usageExamples": "用法示例", "usageExamples": "用法示例",
"tokenId": "令牌 ID", "tokenId": "令牌 ID",
@@ -180,8 +196,14 @@
"shareTitleOptional": "标题 (可选)", "shareTitleOptional": "标题 (可选)",
"sharePathOptional": "路径(可选)", "sharePathOptional": "路径(可选)",
"sharePathDescription": "认证后,链接将把用户重定向到此路径。", "sharePathDescription": "认证后,链接将把用户重定向到此路径。",
"shareAssociateUserOptional": "Associate User (optional)",
"shareAssociateUserDescription": "When set, requests using this link are attributed to the user in access logs and identity headers. The link is removed if the user leaves the organization.",
"userSelect": "Select user",
"usersNotFound": "No users found",
"expireIn": "过期时间", "expireIn": "过期时间",
"neverExpire": "永不过期", "neverExpire": "永不过期",
"sharePersistSession": "Persist session after first use",
"sharePersistSessionDescription": "When enabled, the first request with this token via a query param or header sets a session cookie so later requests do not need the token. Leave off for API clients that should send the token on every request.",
"shareExpireDescription": "过期时间是链接可以使用并提供对资源的访问时间。 此时间后,链接将不再工作,使用此链接的用户将失去对资源的访问。", "shareExpireDescription": "过期时间是链接可以使用并提供对资源的访问时间。 此时间后,链接将不再工作,使用此链接的用户将失去对资源的访问。",
"shareSeeOnce": "您只能看到一次此链接。请确保复制它。", "shareSeeOnce": "您只能看到一次此链接。请确保复制它。",
"shareAccessHint": "任何具有此链接的人都可以访问该资源。小心地分享它。", "shareAccessHint": "任何具有此链接的人都可以访问该资源。小心地分享它。",
@@ -250,6 +272,8 @@
"resourceRawDescriptionCloud": "正在使用端口号使用 TCP/UDP 代理请求。需要站点连接到远程节点。", "resourceRawDescriptionCloud": "正在使用端口号使用 TCP/UDP 代理请求。需要站点连接到远程节点。",
"resourceCreate": "创建资源", "resourceCreate": "创建资源",
"resourceCreateDescription": "按照下面的步骤创建新资源", "resourceCreateDescription": "按照下面的步骤创建新资源",
"resourcePublicCreate": "创建公共资源",
"resourcePublicCreateDescription": "按照以下步骤创建一个可通过网页浏览器访问的新公共资源",
"resourceCreateGeneralDescription": "配置基本资源设置,包括名称和类型", "resourceCreateGeneralDescription": "配置基本资源设置,包括名称和类型",
"resourceSeeAll": "查看所有资源", "resourceSeeAll": "查看所有资源",
"resourceCreateGeneral": "概览", "resourceCreateGeneral": "概览",
@@ -431,8 +455,14 @@
"provisioningManage": "预配", "provisioningManage": "预配",
"provisioningDescription": "管理预配密钥,并审核待批准的站点。", "provisioningDescription": "管理预配密钥,并审核待批准的站点。",
"pendingSites": "待审批站点", "pendingSites": "待审批站点",
"siteApproveSuccess": "站点批准成功", "siteApproveSuccess": "站点及相关资源已成功审批",
"siteApproveError": "批准站点出错", "siteApproveError": "批准站点出错",
"siteReject": "拒绝站点",
"siteQuestionReject": "您确定要拒绝此站点吗?",
"siteMessageReject": "这将永久删除站点及所有尚未处理的相关资源。",
"siteConfirmReject": "确认拒绝站点",
"siteRejectSuccess": "站点已被成功拒绝",
"siteRejectError": "拒绝站点时出错",
"provisioningKeys": "置备键", "provisioningKeys": "置备键",
"searchProvisioningKeys": "搜索配备密钥...", "searchProvisioningKeys": "搜索配备密钥...",
"provisioningKeysAdd": "生成预配密钥", "provisioningKeysAdd": "生成预配密钥",
@@ -448,8 +478,8 @@
"provisioningKeysSave": "保存预配键", "provisioningKeysSave": "保存预配键",
"provisioningKeysSaveDescription": "您只能看到一次。复制它到一个安全的地方。", "provisioningKeysSaveDescription": "您只能看到一次。复制它到一个安全的地方。",
"provisioningKeysErrorCreate": "创建预配键时出错", "provisioningKeysErrorCreate": "创建预配键时出错",
"provisioningKeysList": "新预配", "provisioningKeysList": "新预配密钥",
"provisioningKeysMaxBatchSize": "最大批大小", "provisioningKeysMaxBatchSize": "最大批大小",
"provisioningKeysUnlimitedBatchSize": "无限批量大小(无限制)", "provisioningKeysUnlimitedBatchSize": "无限批量大小(无限制)",
"provisioningKeysMaxBatchUnlimited": "无限制", "provisioningKeysMaxBatchUnlimited": "无限制",
"provisioningKeysMaxBatchSizeInvalid": "输入一个有效的最大批处理大小(1-1,000,000)。", "provisioningKeysMaxBatchSizeInvalid": "输入一个有效的最大批处理大小(1-1,000,000)。",
@@ -462,7 +492,7 @@
"provisioningKeysNeverUsed": "永不过期", "provisioningKeysNeverUsed": "永不过期",
"provisioningKeysEdit": "编辑置备键", "provisioningKeysEdit": "编辑置备键",
"provisioningKeysEditDescription": "更新此密钥的最大批量大小和过期时间。", "provisioningKeysEditDescription": "更新此密钥的最大批量大小和过期时间。",
"provisioningKeysApproveNewSites": "批准新点", "provisioningKeysApproveNewSites": "批准新点",
"provisioningKeysApproveNewSitesDescription": "自动批准使用此密钥注册的节点。", "provisioningKeysApproveNewSitesDescription": "自动批准使用此密钥注册的节点。",
"provisioningKeysUpdateError": "更新预配键时出错", "provisioningKeysUpdateError": "更新预配键时出错",
"provisioningKeysUpdated": "置备密钥已更新", "provisioningKeysUpdated": "置备密钥已更新",
@@ -597,7 +627,8 @@
"idpNameInternal": "内部设置", "idpNameInternal": "内部设置",
"emailInvalid": "无效的电子邮件地址", "emailInvalid": "无效的电子邮件地址",
"inviteValidityDuration": "请选择持续时间", "inviteValidityDuration": "请选择持续时间",
"accessRoleSelectPlease": "请选择一个角色", "accessRoleSelectPlease": "用户必须至少属于一个角色",
"accessRoleRequired": "需要角色",
"removeOwnAdminRoleConfirmTitle": "移除你的管理员权限?", "removeOwnAdminRoleConfirmTitle": "移除你的管理员权限?",
"removeOwnAdminRoleConfirmDescription": "保存后,你将不再拥有该组织的管理员权限。如果需要,其他管理员可以恢复访问。", "removeOwnAdminRoleConfirmDescription": "保存后,你将不再拥有该组织的管理员权限。如果需要,其他管理员可以恢复访问。",
"removeOwnAdminRoleConfirmButton": "移除我的管理员访问权限", "removeOwnAdminRoleConfirmButton": "移除我的管理员访问权限",
@@ -848,8 +879,8 @@
"policyAuthHeaderAuthTitle": "基础标题认证", "policyAuthHeaderAuthTitle": "基础标题认证",
"policyAuthHeaderAuthDescription": "在每次请求上验证自定义 HTTP 标头名称和值", "policyAuthHeaderAuthDescription": "在每次请求上验证自定义 HTTP 标头名称和值",
"policyAuthHeaderAuthSummary": "标头已配置", "policyAuthHeaderAuthSummary": "标头已配置",
"policyAuthHeaderName": "标头名称", "policyAuthHeaderName": "用户名",
"policyAuthHeaderValue": "预期值", "policyAuthHeaderValue": "密码",
"policyAuthSetPasscode": "设定密码", "policyAuthSetPasscode": "设定密码",
"policyAuthSetPincode": "设置 PIN 码", "policyAuthSetPincode": "设置 PIN 码",
"policyAuthSetEmailWhitelist": "设置电子邮件白名单", "policyAuthSetEmailWhitelist": "设置电子邮件白名单",
@@ -903,7 +934,7 @@
"newtVersion": "版本", "newtVersion": "版本",
"architecture": "架构", "architecture": "架构",
"sites": "站点", "sites": "站点",
"siteWgAnyClients": "使用任何 WireGuard 客户端连接。您必须使用对等IP解决内部资源问题。", "siteWgAnyClients": "Use any WireGuard client to connect. You will have to address private resources using the peer IP.",
"siteWgCompatibleAllClients": "与所有WireGuard客户端兼容", "siteWgCompatibleAllClients": "与所有WireGuard客户端兼容",
"siteWgManualConfigurationRequired": "需要手动配置", "siteWgManualConfigurationRequired": "需要手动配置",
"userErrorNotAdminOrOwner": "用户不是管理员或所有者", "userErrorNotAdminOrOwner": "用户不是管理员或所有者",
@@ -1378,6 +1409,7 @@
"createOrgUser": "创建组织用户", "createOrgUser": "创建组织用户",
"actionUpdateOrg": "更新组织", "actionUpdateOrg": "更新组织",
"actionRemoveInvitation": "移除邀请", "actionRemoveInvitation": "移除邀请",
"actionRemoveUserRole": "移除用户角色",
"actionUpdateUser": "更新用户", "actionUpdateUser": "更新用户",
"actionGetUser": "获取用户", "actionGetUser": "获取用户",
"actionGetOrgUser": "获取组织用户", "actionGetOrgUser": "获取组织用户",
@@ -1395,10 +1427,13 @@
"actionApplyBlueprint": "应用蓝图", "actionApplyBlueprint": "应用蓝图",
"actionListBlueprints": "列表蓝图", "actionListBlueprints": "列表蓝图",
"actionGetBlueprint": "获取蓝图", "actionGetBlueprint": "获取蓝图",
"actionCreateOrgWideLauncherView": "创建组织范围的启动器视图",
"setupToken": "设置令牌", "setupToken": "设置令牌",
"setupTokenDescription": "从服务器控制台输入设置令牌。", "setupTokenDescription": "从服务器控制台输入设置令牌。",
"setupTokenRequired": "需要设置令牌", "setupTokenRequired": "需要设置令牌",
"actionUpdateSite": "更新站点", "actionUpdateSite": "更新站点",
"actionApproveSite": "批准站点",
"actionRejectSite": "拒绝站点",
"actionResetSiteBandwidth": "重置组织带宽", "actionResetSiteBandwidth": "重置组织带宽",
"actionListSiteRoles": "允许站点角色列表", "actionListSiteRoles": "允许站点角色列表",
"actionCreateResource": "创建资源", "actionCreateResource": "创建资源",
@@ -1414,6 +1449,15 @@
"actionSetResourcePincode": "设置资源粉码", "actionSetResourcePincode": "设置资源粉码",
"actionSetResourceEmailWhitelist": "设置资源电子邮件白名单", "actionSetResourceEmailWhitelist": "设置资源电子邮件白名单",
"actionGetResourceEmailWhitelist": "获取资源电子邮件白名单", "actionGetResourceEmailWhitelist": "获取资源电子邮件白名单",
"actionGetResourcePolicy": "获取资源策略",
"actionUpdateResourcePolicy": "更新资源策略",
"actionSetResourcePolicyUsers": "设置资源策略用户",
"actionSetResourcePolicyRoles": "设置资源策略角色",
"actionSetResourcePolicyPassword": "设置资源策略密码",
"actionSetResourcePolicyPincode": "设置资源策略密码",
"actionSetResourcePolicyHeaderAuth": "设置资源策略头部身份验证",
"actionSetResourcePolicyWhitelist": "设置资源策略邮件白名单",
"actionSetResourcePolicyRules": "设置资源策略规则",
"actionCreateTarget": "创建目标", "actionCreateTarget": "创建目标",
"actionDeleteTarget": "删除目标", "actionDeleteTarget": "删除目标",
"actionGetTarget": "获取目标", "actionGetTarget": "获取目标",
@@ -1433,6 +1477,7 @@
"actionGenerateAccessToken": "生成访问令牌", "actionGenerateAccessToken": "生成访问令牌",
"actionDeleteAccessToken": "删除访问令牌", "actionDeleteAccessToken": "删除访问令牌",
"actionListAccessTokens": "访问令牌", "actionListAccessTokens": "访问令牌",
"actionCreateResourceSessionToken": "创建资源会话令牌",
"actionCreateResourceRule": "创建资源规则", "actionCreateResourceRule": "创建资源规则",
"actionDeleteResourceRule": "删除资源规则", "actionDeleteResourceRule": "删除资源规则",
"actionListResourceRules": "列出资源规则", "actionListResourceRules": "列出资源规则",
@@ -1472,6 +1517,10 @@
"actionListInvitations": "邀请列表", "actionListInvitations": "邀请列表",
"actionExportLogs": "导出日志", "actionExportLogs": "导出日志",
"actionViewLogs": "查看日志", "actionViewLogs": "查看日志",
"actionCreateSiteProvisioningKey": "创建站点预配密钥",
"actionListSiteProvisioningKeys": "列出站点预配密钥",
"actionUpdateSiteProvisioningKey": "更新站点预配密钥",
"actionDeleteSiteProvisioningKey": "删除站点预配密钥",
"noneSelected": "未选择", "noneSelected": "未选择",
"orgNotFound2": "未找到组织。", "orgNotFound2": "未找到组织。",
"search": "搜索…", "search": "搜索…",
@@ -1486,10 +1535,35 @@
"otpAuthDescription": "从您的身份验证程序中输入代码或您的单次备份代码。", "otpAuthDescription": "从您的身份验证程序中输入代码或您的单次备份代码。",
"otpAuthSubmit": "提交代码", "otpAuthSubmit": "提交代码",
"idpContinue": "或者继续", "idpContinue": "或者继续",
"idpLastUsed": "上次使用",
"otpAuthBack": "回到密码", "otpAuthBack": "回到密码",
"navbar": "导航菜单", "navbar": "导航菜单",
"navbarDescription": "应用程序的主导航菜单", "navbarDescription": "应用程序的主导航菜单",
"navbarDocsLink": "文件", "navbarDocsLink": "文件",
"commandPaletteTitle": "命令面板",
"commandPaletteDescription": "搜索页、组织、资源和操作",
"commandPaletteSearchPlaceholder": "搜索页面、资源、操作……",
"commandPaletteNoResults": "未找到任何结果。",
"commandPaletteSearching": "搜索中……",
"commandPaletteNavigation": "导航",
"commandPaletteOrganizations": "组织",
"commandPaletteSites": "网站",
"commandPaletteResources": "资源",
"commandPaletteUsers": "用户",
"commandPaletteClients": "机器客户端",
"commandPaletteActions": "操作",
"commandPaletteCreateSite": "创建网站",
"commandPaletteCreateProxyResource": "创建公共资源",
"commandPaletteCreatePrivateResource": "创建私人资源",
"commandPaletteCreateUser": "创建用户",
"commandPaletteCreateApiKey": "创建 API 密钥",
"commandPaletteCreateMachineClient": "创建机器客户端",
"commandPaletteCreateAlertRule": "创建警报规则",
"commandPaletteCreateIdentityProvider": "创建身份提供商",
"commandPaletteToggleTheme": "切换主题",
"commandPaletteChooseOrganization": "选择组织",
"commandPaletteShortcutMac": "⌘K",
"commandPaletteShortcutWindows": "Ctrl K",
"otpErrorEnable": "无法启用 2FA", "otpErrorEnable": "无法启用 2FA",
"otpErrorEnableDescription": "启用 2FA 时出错", "otpErrorEnableDescription": "启用 2FA 时出错",
"otpSetupCheckCode": "请输入您的6位数字代码", "otpSetupCheckCode": "请输入您的6位数字代码",
@@ -1567,6 +1641,45 @@
"sidebarManagement": "管理", "sidebarManagement": "管理",
"sidebarBillingAndLicenses": "帐单和许可证", "sidebarBillingAndLicenses": "帐单和许可证",
"sidebarLogsAnalytics": "分析", "sidebarLogsAnalytics": "分析",
"commandSites": "网站",
"commandActionModeInfo": "输入 \">\" 打开操作模式",
"commandResources": "资源",
"commandProxyResources": "公共资源",
"commandClientResources": "私有资源",
"commandClients": "客户端",
"commandUserDevices": "用户设备",
"commandMachineClients": "机器客户端",
"commandDomains": "域",
"commandRemoteExitNodes": "远程节点",
"commandTeam": "团队",
"commandUsers": "用户",
"commandRoles": "角色",
"commandInvitations": "邀请",
"commandPolicies": "共享策略",
"commandResourcePolicies": "公共资源政策",
"commandIdentityProviders": "身份提供商",
"commandApprovals": "审批请求",
"commandShareableLinks": "可共享链接",
"commandOrganization": "组织",
"commandLogsAndAnalytics": "日志与分析",
"commandLogsAnalytics": "分析",
"commandLogsRequest": "HTTP 请求日志",
"commandLogsAccess": "身份验证日志",
"commandLogsAction": "管理员操作日志",
"commandLogsConnection": "网络日志",
"commandLogsStreaming": "事件流",
"commandManagement": "管理",
"commandAlerting": "警报",
"commandProvisioning": "配置",
"commandBluePrints": "蓝图",
"commandApiKeys": "API 密钥",
"commandBillingAndLicenses": "计费与许可证",
"commandBilling": "计费",
"commandEnterpriseLicenses": "许可证",
"commandSettings": "设置",
"commandLauncher": "启动器",
"commandResourceLauncher": "资源启动器",
"commandSearchResults": "搜索结果",
"alertingTitle": "告警", "alertingTitle": "告警",
"alertingDescription": "定义通知的来源、触发器和操作", "alertingDescription": "定义通知的来源、触发器和操作",
"alertingRules": "告警规则", "alertingRules": "告警规则",
@@ -1882,6 +1995,9 @@
"domainPickerSubdomain": "子域:{subdomain}", "domainPickerSubdomain": "子域:{subdomain}",
"domainPickerNamespace": "命名空间:{namespace}", "domainPickerNamespace": "命名空间:{namespace}",
"domainPickerShowMore": "显示更多", "domainPickerShowMore": "显示更多",
"domainPickerNoDomainsAvailableTitle": "No domains available",
"domainPickerNoDomainsAvailableDescription": "You don't have any domains set up yet. Create a domain to continue.",
"domainPickerNoDomainsAvailableAction": "Go to Domains",
"regionSelectorTitle": "选择区域", "regionSelectorTitle": "选择区域",
"domainPickerRemoteExitNodeWarning": "当站点连接到远程退出节点时不支持所提供的域。为了资源可在远程节点上使用,请使用自定义域名。", "domainPickerRemoteExitNodeWarning": "当站点连接到远程退出节点时不支持所提供的域。为了资源可在远程节点上使用,请使用自定义域名。",
"regionSelectorInfo": "选择区域以帮助提升您所在地的性能。您不必与服务器在相同的区域。", "regionSelectorInfo": "选择区域以帮助提升您所在地的性能。您不必与服务器在相同的区域。",
@@ -1898,6 +2014,9 @@
"billingDomains": "域", "billingDomains": "域",
"billingOrganizations": "球队", "billingOrganizations": "球队",
"billingRemoteExitNodes": "远程节点", "billingRemoteExitNodes": "远程节点",
"billingPublicResources": "公共资源",
"billingPrivateResources": "私有资源",
"billingMachineClients": "机器客户端",
"billingNoLimitConfigured": "未配置限制", "billingNoLimitConfigured": "未配置限制",
"billingEstimatedPeriod": "估计结算周期", "billingEstimatedPeriod": "估计结算周期",
"billingIncludedUsage": "包含的使用量", "billingIncludedUsage": "包含的使用量",
@@ -1926,6 +2045,9 @@
"billingUsersInfo": "您可以使用多少用户", "billingUsersInfo": "您可以使用多少用户",
"billingDomainInfo": "您可以使用多少域", "billingDomainInfo": "您可以使用多少域",
"billingRemoteExitNodesInfo": "您可以使用多少远程节点", "billingRemoteExitNodesInfo": "您可以使用多少远程节点",
"billingPublicResourcesInfo": "您可以使用多少公共资源",
"billingPrivateResourcesInfo": "您可以使用多少私有资源",
"billingMachineClientsInfo": "您可以使用多少机器客户端",
"billingLicenseKeys": "许可证密钥", "billingLicenseKeys": "许可证密钥",
"billingLicenseKeysDescription": "管理您的许可证密钥订阅", "billingLicenseKeysDescription": "管理您的许可证密钥订阅",
"billingLicenseSubscription": "许可订阅", "billingLicenseSubscription": "许可订阅",
@@ -2071,6 +2193,7 @@
"subnetPlaceholder": "子网", "subnetPlaceholder": "子网",
"addressDescription": "客户的内部地址。必须属于组织的子网。", "addressDescription": "客户的内部地址。必须属于组织的子网。",
"selectSites": "选择站点", "selectSites": "选择站点",
"selectLabels": "选择标签",
"sitesDescription": "客户端将与所选站点进行连接", "sitesDescription": "客户端将与所选站点进行连接",
"clientInstallOlm": "安装 Olm", "clientInstallOlm": "安装 Olm",
"clientInstallOlmDescription": "在您的系统上运行 Olm", "clientInstallOlmDescription": "在您的系统上运行 Olm",
@@ -2238,7 +2361,7 @@
"resourcesTableProxyResources": "", "resourcesTableProxyResources": "",
"resourcesTableClientResources": "私有资源", "resourcesTableClientResources": "私有资源",
"resourcesTableNoProxyResourcesFound": "未找到代理资源。", "resourcesTableNoProxyResourcesFound": "未找到代理资源。",
"resourcesTableNoInternalResourcesFound": "未找到内部资源。", "resourcesTableNoInternalResourcesFound": "No private resources found.",
"resourcesTableDestination": "目标", "resourcesTableDestination": "目标",
"resourcesTableAlias": "Alias", "resourcesTableAlias": "Alias",
"resourcesTableAliasAddress": "别名地址", "resourcesTableAliasAddress": "别名地址",
@@ -2261,9 +2384,9 @@
"editInternalResourceDialogCancel": "取消", "editInternalResourceDialogCancel": "取消",
"editInternalResourceDialogSaveResource": "保存资源", "editInternalResourceDialogSaveResource": "保存资源",
"editInternalResourceDialogSuccess": "成功", "editInternalResourceDialogSuccess": "成功",
"editInternalResourceDialogInternalResourceUpdatedSuccessfully": "内部资源更新成功", "editInternalResourceDialogInternalResourceUpdatedSuccessfully": "Private resource updated successfully",
"editInternalResourceDialogError": "错误", "editInternalResourceDialogError": "错误",
"editInternalResourceDialogFailedToUpdateInternalResource": "更新内部资源失败", "editInternalResourceDialogFailedToUpdateInternalResource": "Failed to update private resource",
"editInternalResourceDialogNameRequired": "名称为必填项", "editInternalResourceDialogNameRequired": "名称为必填项",
"editInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符", "editInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
"editInternalResourceDialogProxyPortMin": "代理端口必须至少为1", "editInternalResourceDialogProxyPortMin": "代理端口必须至少为1",
@@ -2289,15 +2412,23 @@
"editInternalResourceDialogAlias": "Alias", "editInternalResourceDialogAlias": "Alias",
"editInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。", "editInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。",
"createInternalResourceDialogNoSitesAvailable": "暂无可用站点", "createInternalResourceDialogNoSitesAvailable": "暂无可用站点",
"createInternalResourceDialogNoSitesAvailableDescription": "您需要至少配置一个子网的Newt站点来创建内部资源。", "createInternalResourceDialogNoSitesAvailableDescription": "You need to have at least one Newt site with a subnet configured to create private resources.",
"createInternalResourceDialogClose": "关闭", "createInternalResourceDialogClose": "关闭",
"createInternalResourceDialogCreateClientResource": "创建私有资源", "createInternalResourceDialogCreateClientResource": "创建私有资源",
"createInternalResourceDialogCreateClientResourceDescription": "创建一个新资源只能为连接到组织的客户端访问", "createInternalResourceDialogCreateClientResourceDescription": "创建一个新资源只能为连接到组织的客户端访问",
"privateResourceGeneralDescription": "配置名称、标识符和其他一般资源设置。",
"privateResourceCreatePageSeeAll": "查看所有私人资源",
"privateResourceAllowIcmpPing": "允许 ICMP Ping",
"privateResourceNetworkAccess": "网络访问",
"privateResourceNetworkAccessDescription": "控制此资源的 TCP/UDP 端口访问以及是否允许 ICMP ping。",
"hostSettings": "主机设置",
"cidrSettings": "CIDR 设置",
"createInternalResourceDialogResourceProperties": "资源属性", "createInternalResourceDialogResourceProperties": "资源属性",
"createInternalResourceDialogName": "名称", "createInternalResourceDialogName": "名称",
"createInternalResourceDialogSite": "站点", "createInternalResourceDialogSite": "站点",
"selectSite": "选择站点...", "selectSite": "选择站点...",
"multiSitesSelectorSitesCount": "{count, plural, other {# 个网站}}", "multiSitesSelectorSitesCount": "{count, plural, other {# 个网站}}",
"labelsSelectorLabelsCount": "{count, plural, other {# 标签}}",
"noSitesFound": "未找到站点。", "noSitesFound": "未找到站点。",
"createInternalResourceDialogProtocol": "协议", "createInternalResourceDialogProtocol": "协议",
"createInternalResourceDialogTcp": "TCP", "createInternalResourceDialogTcp": "TCP",
@@ -2310,9 +2441,9 @@
"createInternalResourceDialogCancel": "取消", "createInternalResourceDialogCancel": "取消",
"createInternalResourceDialogCreateResource": "创建资源", "createInternalResourceDialogCreateResource": "创建资源",
"createInternalResourceDialogSuccess": "成功", "createInternalResourceDialogSuccess": "成功",
"createInternalResourceDialogInternalResourceCreatedSuccessfully": "内部资源创建成功", "createInternalResourceDialogInternalResourceCreatedSuccessfully": "Private resource created successfully",
"createInternalResourceDialogError": "错误", "createInternalResourceDialogError": "错误",
"createInternalResourceDialogFailedToCreateInternalResource": "创建内部资源失败", "createInternalResourceDialogFailedToCreateInternalResource": "Failed to create private resource",
"createInternalResourceDialogNameRequired": "名称为必填项", "createInternalResourceDialogNameRequired": "名称为必填项",
"createInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符", "createInternalResourceDialogNameMaxLength": "名称长度必须小于255个字符",
"createInternalResourceDialogPleaseSelectSite": "请选择一个站点", "createInternalResourceDialogPleaseSelectSite": "请选择一个站点",
@@ -2338,6 +2469,7 @@
"createInternalResourceDialogDestinationCidrDescription": "站点网络上资源的 CIDR 范围。", "createInternalResourceDialogDestinationCidrDescription": "站点网络上资源的 CIDR 范围。",
"createInternalResourceDialogAlias": "Alias", "createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。", "createInternalResourceDialogAliasDescription": "此资源可选的内部DNS别名。",
"internalResourceAliasLocalWarning": "以 .local 结尾的别名可能会因某些网络上的 mDNS 而导致解析问题。",
"internalResourceDownstreamSchemeRequired": "HTTP 资源需要方案", "internalResourceDownstreamSchemeRequired": "HTTP 资源需要方案",
"internalResourceHttpPortRequired": "HTTP 资源需要目的端口", "internalResourceHttpPortRequired": "HTTP 资源需要目的端口",
"siteConfiguration": "配置", "siteConfiguration": "配置",
@@ -2371,6 +2503,21 @@
"sidebarRemoteExitNodes": "远程节点", "sidebarRemoteExitNodes": "远程节点",
"remoteExitNodeId": "ID", "remoteExitNodeId": "ID",
"remoteExitNodeSecretKey": "密钥", "remoteExitNodeSecretKey": "密钥",
"remoteExitNodeNetworkingTitle": "网络设置",
"remoteExitNodeNetworkingDescription": "配置此远程出口节点如何路由流量以及哪些站点优先通过其连接。高级功能可用于回程网络配置。",
"remoteExitNodeNetworkingSave": "保存设置",
"remoteExitNodeNetworkingSaveSuccessTitle": "网络设置已保存",
"remoteExitNodeNetworkingSaveSuccessDescription": "网络设置已成功更新。",
"remoteExitNodeNetworkingSaveError": "保存网络设置失败",
"remoteExitNodeNetworkingSubnetsTitle": "远程子网",
"remoteExitNodeNetworkingSubnetsDescription": "定义此远程出口节点将路由流量的CIDR范围。输入有效的CIDR(例如<code>10.0.0.0/8</code>)并按Enter键添加。",
"remoteExitNodeNetworkingSubnetsPlaceholder": "添加CIDR范围(例如10.0.0.0/8",
"remoteExitNodeNetworkingSubnetsLoadError": "无法加载子网",
"remoteExitNodeNetworkingLabelsTitle": "首选标签",
"remoteExitNodeNetworkingLabelsDescription": "拥有这些标签的站点将强制通过此远程出口节点连接。",
"remoteExitNodeNetworkingLabelsButtonText": "选择标签……",
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "搜索标签……",
"remoteExitNodeNetworkingLabelsLoadError": "无法加载标签",
"remoteExitNodeCreate": { "remoteExitNodeCreate": {
"title": "创建远程节点", "title": "创建远程节点",
"description": "创建一个新的自托管远程中继和代理服务器节点", "description": "创建一个新的自托管远程中继和代理服务器节点",
@@ -2424,6 +2571,7 @@
"noRemoteExitNodesAvailableDescription": "此组织没有可用的节点。首先创建一个节点来使用本地站点。", "noRemoteExitNodesAvailableDescription": "此组织没有可用的节点。首先创建一个节点来使用本地站点。",
"exitNode": "出口节点", "exitNode": "出口节点",
"country": "国家", "country": "国家",
"countryIsNot": "不在国家",
"rulesMatchCountry": "当前基于源 IP", "rulesMatchCountry": "当前基于源 IP",
"region": "地区", "region": "地区",
"selectRegion": "选择区域", "selectRegion": "选择区域",
@@ -2549,6 +2697,7 @@
"idpGoogleDescription": "Google OAuth2/OIDC 提供商", "idpGoogleDescription": "Google OAuth2/OIDC 提供商",
"idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider", "idpAzureDescription": "Microsoft Azure OAuth2/OIDC provider",
"subnet": "子网", "subnet": "子网",
"utilitySubnet": "实用程序子网",
"subnetDescription": "此组织网络配置的子网。", "subnetDescription": "此组织网络配置的子网。",
"customDomain": "自定义域", "customDomain": "自定义域",
"authPage": "身份验证页面", "authPage": "身份验证页面",
@@ -2632,6 +2781,9 @@
"twoFactorSetupRequired": "需要设置双因素身份验证。 请通过 {dashboardUrl}/auth/login 再次登录以完成此步骤。 然后,回到这里。", "twoFactorSetupRequired": "需要设置双因素身份验证。 请通过 {dashboardUrl}/auth/login 再次登录以完成此步骤。 然后,回到这里。",
"additionalSecurityRequired": "需要额外的安全", "additionalSecurityRequired": "需要额外的安全",
"organizationRequiresAdditionalSteps": "这个组织需要额外的安全步骤才能访问资源。", "organizationRequiresAdditionalSteps": "这个组织需要额外的安全步骤才能访问资源。",
"sessionExpired": "会话已过期",
"sessionExpiredReauthRequired": "根据贵组织的安全策略,您的会话已过期。请重新认证以继续。",
"reauthenticate": "重新认证",
"completeTheseSteps": "完成这些步骤", "completeTheseSteps": "完成这些步骤",
"enableTwoFactorAuthentication": "启用两步验证", "enableTwoFactorAuthentication": "启用两步验证",
"completeSecuritySteps": "完成安全步骤", "completeSecuritySteps": "完成安全步骤",
@@ -2946,8 +3098,8 @@
"sourceAddress": "源地址", "sourceAddress": "源地址",
"destinationAddress": "目的地址", "destinationAddress": "目的地址",
"duration": "期限", "duration": "期限",
"licenseRequiredToUse": "使用此功能需要<enterpriseLicenseLink>企业版</enterpriseLicenseLink>许可证或<pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>。<bookADemoLink>预约演示或POC试用</bookADemoLink>", "licenseRequiredToUse": "An <enterpriseLicenseLink>Enterprise Edition</enterpriseLicenseLink> license or <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink> is required to use this feature. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"ossEnterpriseEditionRequired": "需要 <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> 才能使用此功能。 此功能也可在 <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>上获取。 <bookADemoLink>预订演示或POC 试用</bookADemoLink>", "ossEnterpriseEditionRequired": "The <enterpriseEditionLink>Enterprise Edition</enterpriseEditionLink> is required to use this feature. This feature is also available in <pangolinCloudLink>Pangolin Cloud</pangolinCloudLink>. <bookADemoLink>Book a free demo or POC trial to learn more.</bookADemoLink>",
"certResolver": "证书解决器", "certResolver": "证书解决器",
"certResolverDescription": "选择用于此资源的证书解析器。", "certResolverDescription": "选择用于此资源的证书解析器。",
"selectCertResolver": "选择证书解析", "selectCertResolver": "选择证书解析",
@@ -2967,7 +3119,7 @@
"orgOrDomainIdMissing": "缺少机构或域 ID", "orgOrDomainIdMissing": "缺少机构或域 ID",
"loadingDNSRecords": "正在载入DNS记录...", "loadingDNSRecords": "正在载入DNS记录...",
"olmUpdateAvailableInfo": "有最新版本的 Olm 可用。请更新到最新版本以获取最佳体验。", "olmUpdateAvailableInfo": "有最新版本的 Olm 可用。请更新到最新版本以获取最佳体验。",
"updateAvailableInfo": "An updated version is available. Please update to the latest version for the best experience.", "updateAvailableInfo": "有新版本可用。请更新到最新版本以获得最佳体验。",
"client": "客户端:", "client": "客户端:",
"proxyProtocol": "代理协议设置", "proxyProtocol": "代理协议设置",
"proxyProtocolDescription": "配置代理协议以保留TCP服务的客户端 IP 地址。", "proxyProtocolDescription": "配置代理协议以保留TCP服务的客户端 IP 地址。",
@@ -3141,7 +3293,7 @@
"editInternalResourceDialogAddUsers": "添加用户", "editInternalResourceDialogAddUsers": "添加用户",
"editInternalResourceDialogAddClients": "添加客户端", "editInternalResourceDialogAddClients": "添加客户端",
"editInternalResourceDialogDestinationLabel": "目标", "editInternalResourceDialogDestinationLabel": "目标",
"editInternalResourceDialogDestinationDescription": "指定内部资源的目标地址。根据选择的模式,这可以是主机名、IP地址或CIDR范围。可选的,设置一个内部DNS别名以便于识别。", "editInternalResourceDialogDestinationDescription": "配置客户端如何访问此资源。",
"internalResourceFormMultiSiteRoutingHelp": "选择多个站点可以实现高可用性的弹性路由和故障转移。", "internalResourceFormMultiSiteRoutingHelp": "选择多个站点可以实现高可用性的弹性路由和故障转移。",
"internalResourceFormMultiSiteRoutingHelpLearnMore": "了解更多", "internalResourceFormMultiSiteRoutingHelpLearnMore": "了解更多",
"editInternalResourceDialogPortRestrictionsDescription": "限制访问特定的TCP/UDP端口或允许/阻止所有端口。", "editInternalResourceDialogPortRestrictionsDescription": "限制访问特定的TCP/UDP端口或允许/阻止所有端口。",
@@ -3534,6 +3686,80 @@
"memberPortalEmailWhitelist": "电子邮件白名单", "memberPortalEmailWhitelist": "电子邮件白名单",
"memberPortalResourceDisabled": "资源已禁用", "memberPortalResourceDisabled": "资源已禁用",
"memberPortalShowingResources": "显示 {start}-{end} 共 {total} 个资源", "memberPortalShowingResources": "显示 {start}-{end} 共 {total} 个资源",
"resourceLauncherTitle": "资源启动器",
"resourceSidebarLauncherTitle": "启动器",
"resourceLauncherDescription": "查看所有可用资源,并从一个中央集中访问它们",
"resourceLauncherSearchPlaceholder": "搜索您的资源……",
"resourceLauncherDefaultView": "默认",
"resourceLauncherSaveView": "保存视图",
"resourceLauncherSaveToCurrentView": "保存至当前视图",
"resourceLauncherSaveDefaultPersonal": "保存到我的",
"resourceLauncherResetView": "重置视图",
"resourceLauncherResetSystemDefault": "重置为系统默认",
"resourceLauncherSystemDefaultRestored": "系统默认已恢复",
"resourceLauncherSystemDefaultRestoredDescription": "已将默认视图重置为原始设置。",
"resourceLauncherSaveAsNewView": "另存为新视图",
"resourceLauncherSaveAsNewViewDescription": "为此视图命名,以便保存您当前的过滤器和布局。",
"resourceLauncherSaveForEveryone": "为所有人保存",
"resourceLauncherSaveForEveryoneDescription": "与所有组织成员共享此视图。如果未选中,此视图仅对您可见。",
"resourceLauncherMakePersonal": "创建个人",
"resourceLauncherFilter": "筛选",
"resourceLauncherFilterWithCount": "筛选,已应用{count}个",
"resourceLauncherSort": "排序",
"resourceLauncherSortAscending": "按升序排序",
"resourceLauncherSortDescending": "按降序排序",
"resourceLauncherSettings": "设置",
"resourceLauncherGroupBy": "按组",
"resourceLauncherGroupBySite": "站点",
"resourceLauncherGroupByLabel": "标签",
"resourceLauncherGroupByNone": "无",
"resourceLauncherLayout": "布局",
"resourceLauncherLayoutGrid": "网格",
"resourceLauncherLayoutList": "列表",
"resourceLauncherShowLabels": "显示标签",
"resourceLauncherShowSiteTags": "显示站点标签",
"resourceLauncherShowRecents": "显示最近使用",
"resourceLauncherDeleteView": "删除视图",
"resourceLauncherDeleteViewTitle": "删除视图",
"resourceLauncherDeleteViewQuestion": "您确定要删除此启动器视图吗?",
"resourceLauncherDeleteViewConfirm": "删除视图",
"resourceLauncherViewAsAdmin": "以管理员身份查看",
"resourceLauncherResourceDetailsDescription": "此资源的连接信息和状态。",
"resourceLauncherResourceDetails": "资源详情",
"resourceLauncherAuthMethodsDescription": "此资源启用的身份验证方法。",
"resourceLauncherPrivateClientRequired": "请在您的设备上连接客户端以私密访问此资源。",
"resourceLauncherPrivateClientRequiredTitle": "需要客户端连接",
"resourceLauncherDownloadClient": "下载客户端",
"resourceLauncherFailedToLoadDetails": "无法加载资源详细信息。您可能已经没有权限访问此资源。",
"resourceLauncherNoPortRestrictions": "无端口限制",
"resourceLauncherTcp": "TCP",
"resourceLauncherUdp": "UDP",
"resourceLauncherUnlabeled": "未标记",
"resourceLauncherNoSite": "无站点",
"resourceLauncherNoResourcesInGroup": "此组中没有资源",
"resourceLauncherEmptyStateTitle": "没有可用资源",
"resourceLauncherEmptyStateDescription": "您还没有访问任何资源。请联系您的管理员以请求访问。",
"resourceLauncherEmptyStateNoResultsTitle": "未找到资源",
"resourceLauncherEmptyStateNoResultsDescription": "没有资源与您当前的搜索或过滤器匹配。尝试调整它们以找到您想要的内容。",
"resourceLauncherEmptyStateNoResultsWithQuery": "没有资源匹配\"{query}\"。尝试调整您的搜索或清除过滤器以查看所有资源。",
"resourceLauncherSearchFirstTitle": "搜索或筛选以浏览",
"resourceLauncherSearchFirstDescription": "您可以访问许多资源。使用搜索或按站点或标签筛选以查找所需内容。",
"resourceLauncherSiteGroupingDisabled": "在此规模下无法进行站点分组。通过站点进行筛选以分组更小的集合。",
"resourceLauncherLabelGroupingDisabled": "在此规模下无法进行标签分组。",
"resourceLauncherCompactModeHint": "显示简化列表以便快速浏览。使用搜索或筛选器缩小结果范围。",
"resourceLauncherCompactGroupingHint": "应用站点或标签筛选器以启用分组。",
"resourceLauncherCopiedToClipboard": "已复制到剪贴板",
"resourceLauncherCopiedAccessDescription": "资源访问权限已复制到剪贴板。",
"resourceLauncherViewNamePlaceholder": "查看名称",
"resourceLauncherViewNameLabel": "查看名称",
"resourceLauncherViewSaved": "视图已保存",
"resourceLauncherViewSavedDescription": "您的启动器视图已保存。",
"resourceLauncherViewSaveFailed": "保存视图失败",
"resourceLauncherViewSaveFailedDescription": "无法保存启动器视图。请再试一次。",
"resourceLauncherViewDeleted": "视图已删除",
"resourceLauncherViewDeletedDescription": "启动器视图已删除。",
"resourceLauncherViewDeleteFailed": "删除视图失败",
"resourceLauncherViewDeleteFailedDescription": "无法删除启动器视图。请再试一次。",
"memberPortalPrevious": "上一页", "memberPortalPrevious": "上一页",
"memberPortalNext": "下一页", "memberPortalNext": "下一页",
"httpSettings": "HTTP 设置", "httpSettings": "HTTP 设置",
@@ -3569,7 +3795,8 @@
"sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----", "sshPrivateKeyPlaceholder": "-----BEGIN OPENSSH PRIVATE KEY-----",
"sshPrivateKeyRequired": "需要私钥", "sshPrivateKeyRequired": "需要私钥",
"vncTitle": "VNC", "vncTitle": "VNC",
"vncSignInDescription": "输入您的 VNC 密码以连接", "vncSignInDescription": "输入您的VNC凭据以连接",
"vncUsernameOptional": "用户名(可选)",
"vncPasswordOptional": "密码 (可选)", "vncPasswordOptional": "密码 (可选)",
"vncNoResourceTarget": "没有可用的资源目标", "vncNoResourceTarget": "没有可用的资源目标",
"vncFailedToLoadNovnc": "加载 noVNC 失败", "vncFailedToLoadNovnc": "加载 noVNC 失败",
@@ -3597,5 +3824,6 @@
"rdpUploadFailed": "上传失败", "rdpUploadFailed": "上传失败",
"rdpUnicodeKeyboardMode": "Unicode 键盘模式", "rdpUnicodeKeyboardMode": "Unicode 键盘模式",
"sessionToolbarShow": "显示工具栏", "sessionToolbarShow": "显示工具栏",
"sessionToolbarHide": "隐藏工具栏" "sessionToolbarHide": "隐藏工具栏",
"actionUpdateSiteApprovals": "更新站点审批"
} }
+1
View File
@@ -1099,6 +1099,7 @@
"actionGenerateAccessToken": "生成訪問令牌", "actionGenerateAccessToken": "生成訪問令牌",
"actionDeleteAccessToken": "刪除訪問令牌", "actionDeleteAccessToken": "刪除訪問令牌",
"actionListAccessTokens": "訪問令牌", "actionListAccessTokens": "訪問令牌",
"actionCreateResourceSessionToken": "建立資源工作階段權杖",
"actionCreateResourceRule": "創建資源規則", "actionCreateResourceRule": "創建資源規則",
"actionDeleteResourceRule": "刪除資源規則", "actionDeleteResourceRule": "刪除資源規則",
"actionListResourceRules": "列出資源規則", "actionListResourceRules": "列出資源規則",
+4 -4
View File
@@ -12,7 +12,7 @@
"@asteasolutions/zod-to-openapi": "8.5.0", "@asteasolutions/zod-to-openapi": "8.5.0",
"@aws-sdk/client-s3": "3.1056.0", "@aws-sdk/client-s3": "3.1056.0",
"@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz", "@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz",
"@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.0.tgz", "@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.1.tgz",
"@headlessui/react": "2.2.10", "@headlessui/react": "2.2.10",
"@hookform/resolvers": "5.4.0", "@hookform/resolvers": "5.4.0",
"@monaco-editor/react": "4.7.0", "@monaco-editor/react": "4.7.0",
@@ -1124,9 +1124,9 @@
"integrity": "sha512-9o7PkCw9fdvGTPs0hgsUJG10QleGgcdsSCw1ekLpUOlVXtWCuiuPH+0bPDFhLWxqbVA+8pyVhwqdOI+t1T3TNA==" "integrity": "sha512-9o7PkCw9fdvGTPs0hgsUJG10QleGgcdsSCw1ekLpUOlVXtWCuiuPH+0bPDFhLWxqbVA+8pyVhwqdOI+t1T3TNA=="
}, },
"node_modules/@devolutions/iron-remote-desktop-rdp": { "node_modules/@devolutions/iron-remote-desktop-rdp": {
"version": "0.0.0", "version": "0.0.1",
"resolved": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.0.tgz", "resolved": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.1.tgz",
"integrity": "sha512-O0YVpOJDwUzekH3N2QKj+48WP+56wI0sj4VmaJkGoW5XgyAj2ONn2k3i+vk17Eavx+Vg6vAg3lwYRAOK4kKIDQ==" "integrity": "sha512-sIHllJ6rJfAgClsUFjJfVGFjIxm6ZQRyGfinwCzHYgwnHAMFE+Kvm0YzR9tg811Fhjm5F6gNUSLAll+7Eh0Deg=="
}, },
"node_modules/@dotenvx/dotenvx": { "node_modules/@dotenvx/dotenvx": {
"version": "1.69.1", "version": "1.69.1",
+1 -1
View File
@@ -34,7 +34,7 @@
"dependencies": { "dependencies": {
"@asteasolutions/zod-to-openapi": "8.5.0", "@asteasolutions/zod-to-openapi": "8.5.0",
"@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz", "@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz",
"@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.0.tgz", "@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.1.tgz",
"@aws-sdk/client-s3": "3.1056.0", "@aws-sdk/client-s3": "3.1056.0",
"@headlessui/react": "2.2.10", "@headlessui/react": "2.2.10",
"@hookform/resolvers": "5.4.0", "@hookform/resolvers": "5.4.0",
Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

+5 -1
View File
@@ -21,6 +21,8 @@ export enum ActionsEnum {
getSite = "getSite", getSite = "getSite",
listSites = "listSites", listSites = "listSites",
updateSite = "updateSite", updateSite = "updateSite",
updateSiteApprovals = "updateSiteApprovals",
restartSite = "restartSite",
resetSiteBandwidth = "resetSiteBandwidth", resetSiteBandwidth = "resetSiteBandwidth",
reGenerateSecret = "reGenerateSecret", reGenerateSecret = "reGenerateSecret",
createResource = "createResource", createResource = "createResource",
@@ -70,6 +72,7 @@ export enum ActionsEnum {
setResourceWhitelist = "setResourceWhitelist", setResourceWhitelist = "setResourceWhitelist",
getResourceWhitelist = "getResourceWhitelist", getResourceWhitelist = "getResourceWhitelist",
generateAccessToken = "generateAccessToken", generateAccessToken = "generateAccessToken",
createResourceSessionToken = "createResourceSessionToken",
deleteAcessToken = "deleteAcessToken", deleteAcessToken = "deleteAcessToken",
listAccessTokens = "listAccessTokens", listAccessTokens = "listAccessTokens",
createResourceRule = "createResourceRule", createResourceRule = "createResourceRule",
@@ -178,7 +181,8 @@ export enum ActionsEnum {
setResourcePolicyPincode = "setResourcePolicyPincode", setResourcePolicyPincode = "setResourcePolicyPincode",
setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth", setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth",
setResourcePolicyWhitelist = "setResourcePolicyWhitelist", setResourcePolicyWhitelist = "setResourcePolicyWhitelist",
setResourcePolicyRules = "setResourcePolicyRules" setResourcePolicyRules = "setResourcePolicyRules",
createOrgWideLauncherView = "createOrgWideLauncherView"
} }
export async function checkUserActionPermission( export async function checkUserActionPermission(
+7 -4
View File
@@ -795,10 +795,13 @@ export const COUNTRIES = [
name: "Serbia", name: "Serbia",
code: "RS" code: "RS"
}, },
{ // Removed as this is a deprecated ISO country code, not supported anymore
name: "Serbia and Montenegro", // Also the individual flags for Serbia & Montenegro are already included in the list
code: "CS" // more details: https://en.wikipedia.org/wiki/ISO_3166-2:CS
}, // {
// name: "Serbia and Montenegro",
// code: "CS"
// },
{ {
name: "Seychelles", name: "Seychelles",
code: "SC" code: "SC"
+23
View File
@@ -1,3 +1,4 @@
import config from "@server/lib/config";
import { Pool, PoolConfig } from "pg"; import { Pool, PoolConfig } from "pg";
export function createPoolConfig( export function createPoolConfig(
@@ -39,6 +40,28 @@ export function attachPoolErrorHandlers(pool: Pool, label: string): void {
`Failed to set statement_timeout on ${label} client: ${err.message}` `Failed to set statement_timeout on ${label} client: ${err.message}`
); );
}); });
// Disable JIT compilation for this connection. Our hot-path queries
// (e.g. resource-by-domain lookups) join many tables but only ever
// return a handful of rows. When planner row estimates drift (e.g.
// due to autovacuum lag under write-heavy load), Postgres decides
// these plans are expensive enough to JIT-compile, which can add
// multiple seconds of pure compilation overhead per query and
// saturate the connection pool. JIT never pays off for these
// short-lived OLTP queries, so it's disabled outright rather than
// relying on statistics staying fresh.
//
// Set via a runtime SET command rather than the `options: "-c
// jit=off"` startup parameter: connections in SaaS mode go through
// a pooler (e.g. PgBouncer) that rejects arbitrary startup packet
// options with a protocol_violation (08P01) error.
if (config.getRawConfig().postgres?.pool.jit_mode == false) {
client.query("SET jit = off").catch((err: Error) => {
console.warn(
`Failed to set jit=off on ${label} client: ${err.message}`
);
});
}
}); });
} }
+41 -3
View File
@@ -2,6 +2,7 @@ import {
pgTable, pgTable,
serial, serial,
varchar, varchar,
unique,
boolean, boolean,
integer, integer,
bigint, bigint,
@@ -19,12 +20,13 @@ import {
roles, roles,
users, users,
exitNodes, exitNodes,
sessions,
clients,
resources, resources,
siteResources, siteResources,
targetHealthCheck, targetHealthCheck,
sites sites,
clients,
sessions,
labels
} from "./schema"; } from "./schema";
export const certificates = pgTable("certificates", { export const certificates = pgTable("certificates", {
@@ -197,6 +199,42 @@ export const remoteExitNodes = pgTable("remoteExitNode", {
}) })
}); });
export const remoteExitNodeResources = pgTable("remoteExitNodeResources", {
remoteExitNodeResourceId: serial("remoteExitNodeResourceId").primaryKey(),
remoteExitNodeId: varchar("remoteExitNodeId")
.notNull()
.references(() => remoteExitNodes.remoteExitNodeId, {
onDelete: "cascade"
}),
destination: varchar("destination").notNull() // a cidr range
});
export const remoteExitNodePreferenceLabels = pgTable(
// this controls what sites are enforced to connect to this node
"remoteExitNodePreferenceLabels",
{
remoteExitNodePreferenceLabelId: serial(
"remoteExitNodePreferenceLabelId"
).primaryKey(),
remoteExitNodeId: varchar("remoteExitNodeId")
.references(() => remoteExitNodes.remoteExitNodeId, {
onDelete: "cascade"
})
.notNull(),
labelId: integer("labelId")
.references(() => labels.labelId, {
onDelete: "cascade"
})
.notNull()
},
(t) => [
unique("remote_exit_node_preference_label_uniq").on(
t.remoteExitNodeId,
t.labelId
)
]
);
export const remoteExitNodeSessions = pgTable("remoteExitNodeSession", { export const remoteExitNodeSessions = pgTable("remoteExitNodeSession", {
sessionId: varchar("id").primaryKey(), sessionId: varchar("id").primaryKey(),
remoteExitNodeId: varchar("remoteExitNodeId") remoteExitNodeId: varchar("remoteExitNodeId")
+156 -85
View File
@@ -25,7 +25,8 @@ export const domains = pgTable("domains", {
certResolver: varchar("certResolver"), certResolver: varchar("certResolver"),
customCertResolver: varchar("customCertResolver"), customCertResolver: varchar("customCertResolver"),
preferWildcardCert: boolean("preferWildcardCert"), preferWildcardCert: boolean("preferWildcardCert"),
errorMessage: text("errorMessage") errorMessage: text("errorMessage"),
lastCheckedAt: integer("lastCheckedAt")
}); });
export const dnsRecords = pgTable("dnsRecords", { export const dnsRecords = pgTable("dnsRecords", {
@@ -106,6 +107,7 @@ export const sites = pgTable(
lastPing: integer("lastPing"), lastPing: integer("lastPing"),
address: varchar("address"), address: varchar("address"),
endpoint: varchar("endpoint"), endpoint: varchar("endpoint"),
localEndpoints: varchar("localEndpoints"), // JSON encoded list of string ips on the local machine to try to connect to
publicKey: varchar("publicKey"), publicKey: varchar("publicKey"),
lastHolePunch: bigint("lastHolePunch", { mode: "number" }), lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
listenPort: integer("listenPort"), listenPort: integer("listenPort"),
@@ -128,7 +130,8 @@ export const sites = pgTable(
t.exitNodeId, t.exitNodeId,
t.type, t.type,
t.siteId t.siteId
) ),
index("idx_sites_orgid_niceid").on(t.orgId, t.niceId)
] ]
); );
@@ -198,12 +201,17 @@ export const resources = pgTable(
authDaemonMode: varchar("authDaemonMode", { length: 32 }) authDaemonMode: varchar("authDaemonMode", { length: 32 })
.$type<"site" | "remote" | "native">() .$type<"site" | "remote" | "native">()
.default("site"), .default("site"),
authDaemonPort: integer("authDaemonPort").default(22123) authDaemonPort: integer("authDaemonPort").default(22123),
status: varchar("status")
.$type<"pending" | "approved">()
.default("approved")
}, },
(t) => [ (t) => [
index("idx_resources_fulldomain") index("idx_resources_fulldomain")
.on(t.fullDomain) .on(t.fullDomain)
.where(sql`${t.fullDomain} IS NOT NULL`) .where(sql`${t.fullDomain} IS NOT NULL`),
index("idx_resources_niceid").on(t.niceId),
index("idx_resources_orgid_niceid").on(t.orgId, t.niceId)
] ]
); );
@@ -218,6 +226,21 @@ export const labels = pgTable("labels", {
.notNull() .notNull()
}); });
export const launcherViews = pgTable("launcherViews", {
viewId: serial("viewId").primaryKey(),
orgId: varchar("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
userId: varchar("userId").references(() => users.userId, {
onDelete: "cascade"
}),
name: varchar("name").notNull(),
config: text("config").notNull(),
isDefault: boolean("isDefault").notNull().default(false),
createdAt: varchar("createdAt").notNull(),
updatedAt: varchar("updatedAt").notNull()
});
export const siteLabels = pgTable( export const siteLabels = pgTable(
"siteLabels", "siteLabels",
{ {
@@ -384,63 +407,80 @@ export const exitNodes = pgTable("exitNodes", {
region: varchar("region") region: varchar("region")
}); });
export const siteResources = pgTable("siteResources", { export const siteResources = pgTable(
// this is for the clients "siteResources",
siteResourceId: serial("siteResourceId").primaryKey(), {
orgId: varchar("orgId") // this is for the clients
.notNull() siteResourceId: serial("siteResourceId").primaryKey(),
.references(() => orgs.orgId, { onDelete: "cascade" }), orgId: varchar("orgId")
networkId: integer("networkId").references(() => networks.networkId, { .notNull()
onDelete: "set null" .references(() => orgs.orgId, { onDelete: "cascade" }),
}), networkId: integer("networkId").references(() => networks.networkId, {
defaultNetworkId: integer("defaultNetworkId").references( onDelete: "set null"
() => networks.networkId, }),
{ defaultNetworkId: integer("defaultNetworkId").references(
onDelete: "restrict" () => networks.networkId,
} {
), onDelete: "restrict"
niceId: varchar("niceId").notNull(), }
name: varchar("name").notNull(), ),
ssl: boolean("ssl").notNull().default(false), niceId: varchar("niceId").notNull(),
mode: varchar("mode").$type<"host" | "cidr" | "http" | "ssh">().notNull(), // "host" | "cidr" | "http" name: varchar("name").notNull(),
scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode ssl: boolean("ssl").notNull().default(false),
proxyPort: integer("proxyPort"), // only for port mode mode: varchar("mode")
destinationPort: integer("destinationPort"), // only for port mode .$type<"host" | "cidr" | "http" | "ssh">()
destination: varchar("destination"), // ip, cidr, hostname; validate against the mode .notNull(), // "host" | "cidr" | "http"
enabled: boolean("enabled").notNull().default(true), scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
alias: varchar("alias"), proxyPort: integer("proxyPort"), // only for port mode
aliasAddress: varchar("aliasAddress"), destinationPort: integer("destinationPort"), // only for port mode
tcpPortRangeString: varchar("tcpPortRangeString").notNull().default("*"), destination: varchar("destination"), // ip, cidr, hostname; validate against the mode
udpPortRangeString: varchar("udpPortRangeString").notNull().default("*"), enabled: boolean("enabled").notNull().default(true),
disableIcmp: boolean("disableIcmp").notNull().default(false), alias: varchar("alias"),
authDaemonPort: integer("authDaemonPort").default(22123), aliasAddress: varchar("aliasAddress"),
pamMode: varchar("pamMode", { length: 32 }) tcpPortRangeString: varchar("tcpPortRangeString")
.$type<"passthrough" | "push">() .notNull()
.default("passthrough"), .default("*"),
authDaemonMode: varchar("authDaemonMode", { length: 32 }) udpPortRangeString: varchar("udpPortRangeString")
.$type<"site" | "remote" | "native">() .notNull()
.default("site"), .default("*"),
domainId: varchar("domainId").references(() => domains.domainId, { disableIcmp: boolean("disableIcmp").notNull().default(false),
onDelete: "set null" authDaemonPort: integer("authDaemonPort").default(22123),
}), pamMode: varchar("pamMode", { length: 32 })
subdomain: varchar("subdomain"), .$type<"passthrough" | "push">()
fullDomain: varchar("fullDomain") .default("passthrough"),
}); authDaemonMode: varchar("authDaemonMode", { length: 32 })
.$type<"site" | "remote" | "native">()
.default("site"),
domainId: varchar("domainId").references(() => domains.domainId, {
onDelete: "set null"
}),
subdomain: varchar("subdomain"),
fullDomain: varchar("fullDomain"),
status: varchar("status")
.$type<"pending" | "approved">()
.default("approved")
},
(t) => [index("idx_siteresources_orgid_niceid").on(t.orgId, t.niceId)]
);
export const networks = pgTable("networks", { export const networks = pgTable(
networkId: serial("networkId").primaryKey(), "networks",
niceId: text("niceId"), {
name: text("name"), networkId: serial("networkId").primaryKey(),
scope: varchar("scope") niceId: text("niceId"),
.$type<"global" | "resource">() name: text("name"),
.notNull() scope: varchar("scope")
.default("global"), .$type<"global" | "resource">()
orgId: varchar("orgId") .notNull()
.references(() => orgs.orgId, { .default("global"),
onDelete: "cascade" orgId: varchar("orgId")
}) .references(() => orgs.orgId, {
.notNull() onDelete: "cascade"
}); })
.notNull()
},
(t) => [index("idx_networks_orgid").on(t.orgId)]
);
export const siteNetworks = pgTable( export const siteNetworks = pgTable(
"siteNetworks", "siteNetworks",
@@ -866,12 +906,16 @@ export const resourceAccessToken = pgTable("resourceAccessToken", {
resourceId: integer("resourceId") resourceId: integer("resourceId")
.notNull() .notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }), .references(() => resources.resourceId, { onDelete: "cascade" }),
userId: varchar("userId").references(() => users.userId, {
onDelete: "cascade"
}),
path: varchar("path"), path: varchar("path"),
tokenHash: varchar("tokenHash").notNull(), tokenHash: varchar("tokenHash").notNull(),
sessionLength: bigint("sessionLength", { mode: "number" }).notNull(), sessionLength: bigint("sessionLength", { mode: "number" }).notNull(),
expiresAt: bigint("expiresAt", { mode: "number" }), expiresAt: bigint("expiresAt", { mode: "number" }),
title: varchar("title"), title: varchar("title"),
description: varchar("description"), description: varchar("description"),
persistSession: boolean("persistSession").notNull().default(false),
createdAt: bigint("createdAt", { mode: "number" }).notNull() createdAt: bigint("createdAt", { mode: "number" }).notNull()
}); });
@@ -966,7 +1010,17 @@ export const resourceRules = pgTable("resourceRules", {
enabled: boolean("enabled").notNull().default(true), enabled: boolean("enabled").notNull().default(true),
priority: integer("priority").notNull(), priority: integer("priority").notNull(),
action: varchar("action").notNull(), // ACCEPT, DROP, PASS action: varchar("action").notNull(), // ACCEPT, DROP, PASS
match: varchar("match").notNull(), // CIDR, PATH, IP match: varchar("match")
.$type<
| "CIDR"
| "PATH"
| "IP"
| "COUNTRY"
| "COUNTRY_IS_NOT"
| "ASN"
| "REGION"
>()
.notNull(), // CIDR, PATH, IP
value: varchar("value").notNull() value: varchar("value").notNull()
}); });
@@ -981,33 +1035,45 @@ export const resourcePolicyRules = pgTable("resourcePolicyRules", {
priority: integer("priority").notNull(), priority: integer("priority").notNull(),
action: varchar("action").$type<"ACCEPT" | "DROP" | "PASS">().notNull(), action: varchar("action").$type<"ACCEPT" | "DROP" | "PASS">().notNull(),
match: varchar("match") match: varchar("match")
.$type<"CIDR" | "PATH" | "IP" | "COUNTRY" | "ASN" | "REGION">() .$type<
| "CIDR"
| "PATH"
| "IP"
| "COUNTRY"
| "COUNTRY_IS_NOT"
| "ASN"
| "REGION"
>()
.notNull(), .notNull(),
value: varchar("value").notNull() value: varchar("value").notNull()
}); });
export const resourcePolicies = pgTable("resourcePolicies", { export const resourcePolicies = pgTable(
resourcePolicyId: serial("resourcePolicyId").primaryKey(), "resourcePolicies",
sso: boolean("sso").notNull().default(true), {
applyRules: boolean("applyRules").notNull().default(false), resourcePolicyId: serial("resourcePolicyId").primaryKey(),
scope: varchar("scope") sso: boolean("sso").notNull().default(true),
.$type<"global" | "resource">() applyRules: boolean("applyRules").notNull().default(false),
.notNull() scope: varchar("scope")
.default("global"), .$type<"global" | "resource">()
emailWhitelistEnabled: boolean("emailWhitelistEnabled") .notNull()
.notNull() .default("global"),
.default(false), emailWhitelistEnabled: boolean("emailWhitelistEnabled")
idpId: integer("idpId").references(() => idp.idpId, { .notNull()
onDelete: "set null" .default(false),
}), idpId: integer("idpId").references(() => idp.idpId, {
niceId: text("niceId").notNull(), onDelete: "set null"
name: varchar("name").notNull(), }),
orgId: varchar("orgId") niceId: text("niceId").notNull(),
.references(() => orgs.orgId, { name: varchar("name").notNull(),
onDelete: "cascade" orgId: varchar("orgId")
}) .references(() => orgs.orgId, {
.notNull() onDelete: "cascade"
}); })
.notNull()
},
(t) => [index("idx_resourcepolicies_orgid_niceid").on(t.orgId, t.niceId)]
);
export const supporterKey = pgTable("supporterKey", { export const supporterKey = pgTable("supporterKey", {
keyId: serial("keyId").primaryKey(), keyId: serial("keyId").primaryKey(),
@@ -1131,7 +1197,10 @@ export const clients = pgTable(
"pending" | "approved" | "denied" "pending" | "approved" | "denied"
>() >()
}, },
(t) => [index("idx_clients_userid").on(t.userId)] (t) => [
index("idx_clients_userid").on(t.userId),
index("idx_clients_orgid_niceid").on(t.orgId, t.niceId)
]
); );
export const clientSitesAssociationsCache = pgTable( export const clientSitesAssociationsCache = pgTable(
@@ -1550,6 +1619,8 @@ export type RoundTripMessageTracker = InferSelectModel<
export type Network = InferSelectModel<typeof networks>; export type Network = InferSelectModel<typeof networks>;
export type StatusHistory = InferSelectModel<typeof statusHistory>; export type StatusHistory = InferSelectModel<typeof statusHistory>;
export type Label = InferSelectModel<typeof labels>; export type Label = InferSelectModel<typeof labels>;
export type LauncherView = InferSelectModel<typeof launcherViews>;
export type ResourcePolicy = InferSelectModel<typeof resourcePolicies>; export type ResourcePolicy = InferSelectModel<typeof resourcePolicies>;
export type RolePolicy = InferSelectModel<typeof rolePolicies>; export type RolePolicy = InferSelectModel<typeof rolePolicies>;
export type UserPolicy = InferSelectModel<typeof userPolicies>; export type UserPolicy = InferSelectModel<typeof userPolicies>;
export type ResourcePolicyRule = InferSelectModel<typeof resourcePolicyRules>;
+39 -3
View File
@@ -12,6 +12,7 @@ import {
clients, clients,
domains, domains,
exitNodes, exitNodes,
labels,
orgs, orgs,
resources, resources,
roles, roles,
@@ -21,9 +22,6 @@ import {
targetHealthCheck, targetHealthCheck,
users users
} from "./schema"; } from "./schema";
import { serial, varchar } from "drizzle-orm/mysql-core";
import { pgTable } from "drizzle-orm/pg-core";
import { bigint } from "zod";
export const certificates = sqliteTable("certificates", { export const certificates = sqliteTable("certificates", {
certId: integer("certId").primaryKey({ autoIncrement: true }), certId: integer("certId").primaryKey({ autoIncrement: true }),
@@ -195,6 +193,44 @@ export const remoteExitNodes = sqliteTable("remoteExitNode", {
}) })
}); });
export const remoteExitNodeResources = sqliteTable("remoteExitNodeResources", {
remoteExitNodeResourceId: integer("remoteExitNodeResourceId").primaryKey({
autoIncrement: true
}),
remoteExitNodeId: text("remoteExitNodeId")
.notNull()
.references(() => remoteExitNodes.remoteExitNodeId, {
onDelete: "cascade"
}),
destination: text("destination").notNull() // a cidr range
});
export const remoteExitNodePreferenceLabels = sqliteTable(
// this controls what sites are enforced to connect to this node
"remoteExitNodePreferenceLabels",
{
remoteExitNodePreferenceLabelId: integer(
"remoteExitNodePreferenceLabelId"
).primaryKey({ autoIncrement: true }),
remoteExitNodeId: text("remoteExitNodeId")
.references(() => remoteExitNodes.remoteExitNodeId, {
onDelete: "cascade"
})
.notNull(),
labelId: integer("labelId")
.references(() => labels.labelId, {
onDelete: "cascade"
})
.notNull()
},
(t) => [
uniqueIndex("remote_exit_node_preference_label_uniq").on(
t.remoteExitNodeId,
t.labelId
)
]
);
export const remoteExitNodeSessions = sqliteTable("remoteExitNodeSession", { export const remoteExitNodeSessions = sqliteTable("remoteExitNodeSession", {
sessionId: text("id").primaryKey(), sessionId: text("id").primaryKey(),
remoteExitNodeId: text("remoteExitNodeId") remoteExitNodeId: text("remoteExitNodeId")
+52 -5
View File
@@ -20,8 +20,10 @@ export const domains = sqliteTable("domains", {
failed: integer("failed", { mode: "boolean" }).notNull().default(false), failed: integer("failed", { mode: "boolean" }).notNull().default(false),
tries: integer("tries").notNull().default(0), tries: integer("tries").notNull().default(0),
certResolver: text("certResolver"), certResolver: text("certResolver"),
customCertResolver: text("customCertResolver"),
preferWildcardCert: integer("preferWildcardCert", { mode: "boolean" }), preferWildcardCert: integer("preferWildcardCert", { mode: "boolean" }),
errorMessage: text("errorMessage") errorMessage: text("errorMessage"),
lastCheckedAt: integer("lastCheckedAt")
}); });
export const dnsRecords = sqliteTable("dnsRecords", { export const dnsRecords = sqliteTable("dnsRecords", {
@@ -116,6 +118,7 @@ export const sites = sqliteTable("sites", {
// exit node stuff that is how to connect to the site when it has a wg server // exit node stuff that is how to connect to the site when it has a wg server
address: text("address"), // this is the address of the wireguard interface in newt address: text("address"), // this is the address of the wireguard interface in newt
endpoint: text("endpoint"), // this is how to reach gerbil externally - gets put into the wireguard config endpoint: text("endpoint"), // this is how to reach gerbil externally - gets put into the wireguard config
localEndpoints: text("localEndpoints"), // JSON encoded list of string ips on the local machine to try to connect to
publicKey: text("publicKey"), // TODO: Fix typo in publicKey publicKey: text("publicKey"), // TODO: Fix typo in publicKey
lastHolePunch: integer("lastHolePunch"), lastHolePunch: integer("lastHolePunch"),
listenPort: integer("listenPort"), listenPort: integer("listenPort"),
@@ -207,7 +210,8 @@ export const resources = sqliteTable("resources", {
authDaemonMode: text("authDaemonMode") authDaemonMode: text("authDaemonMode")
.$type<"site" | "remote" | "native">() .$type<"site" | "remote" | "native">()
.default("site"), .default("site"),
authDaemonPort: integer("authDaemonPort").default(22123) authDaemonPort: integer("authDaemonPort").default(22123),
status: text("status").$type<"pending" | "approved">().default("approved")
}); });
export const labels = sqliteTable("labels", { export const labels = sqliteTable("labels", {
@@ -221,6 +225,23 @@ export const labels = sqliteTable("labels", {
.notNull() .notNull()
}); });
export const launcherViews = sqliteTable("launcherViews", {
viewId: integer("viewId").primaryKey({ autoIncrement: true }),
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
userId: text("userId").references(() => users.userId, {
onDelete: "cascade"
}),
name: text("name").notNull(),
config: text("config").notNull(),
isDefault: integer("isDefault", { mode: "boolean" })
.notNull()
.default(false),
createdAt: text("createdAt").notNull(),
updatedAt: text("updatedAt").notNull()
});
export const siteLabels = sqliteTable( export const siteLabels = sqliteTable(
"siteLabels", "siteLabels",
{ {
@@ -428,7 +449,8 @@ export const siteResources = sqliteTable("siteResources", {
onDelete: "set null" onDelete: "set null"
}), }),
subdomain: text("subdomain"), subdomain: text("subdomain"),
fullDomain: text("fullDomain") fullDomain: text("fullDomain"),
status: text("status").$type<"pending" | "approved">().default("approved")
}); });
export const networks = sqliteTable("networks", { export const networks = sqliteTable("networks", {
@@ -1104,12 +1126,18 @@ export const resourceAccessToken = sqliteTable("resourceAccessToken", {
resourceId: integer("resourceId") resourceId: integer("resourceId")
.notNull() .notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }), .references(() => resources.resourceId, { onDelete: "cascade" }),
userId: text("userId").references(() => users.userId, {
onDelete: "cascade"
}),
path: text("path"), path: text("path"),
tokenHash: text("tokenHash").notNull(), tokenHash: text("tokenHash").notNull(),
sessionLength: integer("sessionLength").notNull(), sessionLength: integer("sessionLength").notNull(),
expiresAt: integer("expiresAt"), expiresAt: integer("expiresAt"),
title: text("title"), title: text("title"),
description: text("description"), description: text("description"),
persistSession: integer("persistSession", { mode: "boolean" })
.notNull()
.default(false),
createdAt: integer("createdAt").notNull() createdAt: integer("createdAt").notNull()
}); });
@@ -1205,7 +1233,17 @@ export const resourceRules = sqliteTable("resourceRules", {
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true), enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
priority: integer("priority").notNull(), priority: integer("priority").notNull(),
action: text("action").notNull(), // ACCEPT, DROP, PASS action: text("action").notNull(), // ACCEPT, DROP, PASS
match: text("match").notNull(), // CIDR, PATH, IP match: text("match")
.$type<
| "CIDR"
| "PATH"
| "IP"
| "COUNTRY"
| "COUNTRY_IS_NOT"
| "ASN"
| "REGION"
>()
.notNull(), // CIDR, PATH, IP
value: text("value").notNull() value: text("value").notNull()
}); });
@@ -1252,7 +1290,15 @@ export const resourcePolicyRules = sqliteTable("resourcePolicyRules", {
priority: integer("priority").notNull(), priority: integer("priority").notNull(),
action: text("action").$type<"ACCEPT" | "DROP" | "PASS">().notNull(), action: text("action").$type<"ACCEPT" | "DROP" | "PASS">().notNull(),
match: text("match") match: text("match")
.$type<"CIDR" | "PATH" | "IP" | "COUNTRY" | "ASN" | "REGION">() .$type<
| "CIDR"
| "PATH"
| "IP"
| "COUNTRY"
| "COUNTRY_IS_NOT"
| "ASN"
| "REGION"
>()
.notNull(), .notNull(),
value: text("value").notNull() value: text("value").notNull()
}); });
@@ -1549,6 +1595,7 @@ export type RoundTripMessageTracker = InferSelectModel<
>; >;
export type StatusHistory = InferSelectModel<typeof statusHistory>; export type StatusHistory = InferSelectModel<typeof statusHistory>;
export type Label = InferSelectModel<typeof labels>; export type Label = InferSelectModel<typeof labels>;
export type LauncherView = InferSelectModel<typeof launcherViews>;
export type ResourcePolicy = InferSelectModel<typeof resourcePolicies>; export type ResourcePolicy = InferSelectModel<typeof resourcePolicies>;
export type ResourcePolicyPincode = InferSelectModel< export type ResourcePolicyPincode = InferSelectModel<
typeof resourcePolicyPincode typeof resourcePolicyPincode
+36 -26
View File
@@ -1,28 +1,39 @@
export enum FeatureId { export enum LimitId {
USERS = "users", USERS = "users",
SITES = "sites", SITES = "sites",
EGRESS_DATA_MB = "egressDataMb", EGRESS_DATA_MB = "egressDataMb",
DOMAINS = "domains", DOMAINS = "domains",
REMOTE_EXIT_NODES = "remoteExitNodes", REMOTE_EXIT_NODES = "remoteExitNodes",
ORGINIZATIONS = "organizations", ORGANIZATIONS = "organizations",
PUBLIC_RESOURCES = "publicResources",
PRIVATE_RESOURCES = "privateResources",
MACHINE_CLIENTS = "machineClients",
TIER1 = "tier1" TIER1 = "tier1"
} }
export async function getFeatureDisplayName(featureId: FeatureId): Promise<string> { export async function getFeatureDisplayName(
featureId: LimitId
): Promise<string> {
switch (featureId) { switch (featureId) {
case FeatureId.USERS: case LimitId.USERS:
return "Users"; return "Users";
case FeatureId.SITES: case LimitId.SITES:
return "Sites"; return "Sites";
case FeatureId.EGRESS_DATA_MB: case LimitId.EGRESS_DATA_MB:
return "Egress Data (MB)"; return "Egress Data (MB)";
case FeatureId.DOMAINS: case LimitId.DOMAINS:
return "Domains"; return "Domains";
case FeatureId.REMOTE_EXIT_NODES: case LimitId.REMOTE_EXIT_NODES:
return "Remote Exit Nodes"; return "Remote Exit Nodes";
case FeatureId.ORGINIZATIONS: case LimitId.ORGANIZATIONS:
return "Organizations"; return "Organizations";
case FeatureId.TIER1: case LimitId.PUBLIC_RESOURCES:
return "Public Resources";
case LimitId.PRIVATE_RESOURCES:
return "Private Resources";
case LimitId.MACHINE_CLIENTS:
return "Machine Clients";
case LimitId.TIER1:
return "Home Lab"; return "Home Lab";
default: default:
return featureId; return featureId;
@@ -30,15 +41,16 @@ export async function getFeatureDisplayName(featureId: FeatureId): Promise<strin
} }
// this is from the old system // this is from the old system
export const FeatureMeterIds: Partial<Record<FeatureId, string>> = { // right now we are not charging for any data export const FeatureMeterIds: Partial<Record<LimitId, string>> = {
// right now we are not charging for any data
// [FeatureId.EGRESS_DATA_MB]: "mtr_61Srreh9eWrExDSCe41D3Ee2Ir7Wm5YW" // [FeatureId.EGRESS_DATA_MB]: "mtr_61Srreh9eWrExDSCe41D3Ee2Ir7Wm5YW"
}; };
export const FeatureMeterIdsSandbox: Partial<Record<FeatureId, string>> = { export const FeatureMeterIdsSandbox: Partial<Record<LimitId, string>> = {
// [FeatureId.EGRESS_DATA_MB]: "mtr_test_61Snh2a2m6qome5Kv41DCpkOb237B3dQ" // [FeatureId.EGRESS_DATA_MB]: "mtr_test_61Snh2a2m6qome5Kv41DCpkOb237B3dQ"
}; };
export function getFeatureMeterId(featureId: FeatureId): string | undefined { export function getFeatureMeterId(featureId: LimitId): string | undefined {
if ( if (
process.env.ENVIRONMENT == "prod" && process.env.ENVIRONMENT == "prod" &&
process.env.SANDBOX_MODE !== "true" process.env.SANDBOX_MODE !== "true"
@@ -49,22 +61,20 @@ export function getFeatureMeterId(featureId: FeatureId): string | undefined {
} }
} }
export function getFeatureIdByMetricId( export function getFeatureIdByMetricId(metricId: string): LimitId | undefined {
metricId: string return (Object.entries(FeatureMeterIds) as [LimitId, string][]).find(
): FeatureId | undefined {
return (Object.entries(FeatureMeterIds) as [FeatureId, string][]).find(
([_, v]) => v === metricId ([_, v]) => v === metricId
)?.[0]; )?.[0];
} }
export type FeaturePriceSet = Partial<Record<FeatureId, string>>; export type FeaturePriceSet = Partial<Record<LimitId, string>>;
export const tier1FeaturePriceSet: FeaturePriceSet = { export const tier1FeaturePriceSet: FeaturePriceSet = {
[FeatureId.TIER1]: "price_1SzVE3D3Ee2Ir7Wm6wT5Dl3G" [LimitId.TIER1]: "price_1SzVE3D3Ee2Ir7Wm6wT5Dl3G"
}; };
export const tier1FeaturePriceSetSandbox: FeaturePriceSet = { export const tier1FeaturePriceSetSandbox: FeaturePriceSet = {
[FeatureId.TIER1]: "price_1SxgpPDCpkOb237Bfo4rIsoT" [LimitId.TIER1]: "price_1SxgpPDCpkOb237Bfo4rIsoT"
}; };
export function getTier1FeaturePriceSet(): FeaturePriceSet { export function getTier1FeaturePriceSet(): FeaturePriceSet {
@@ -79,11 +89,11 @@ export function getTier1FeaturePriceSet(): FeaturePriceSet {
} }
export const tier2FeaturePriceSet: FeaturePriceSet = { export const tier2FeaturePriceSet: FeaturePriceSet = {
[FeatureId.USERS]: "price_1SzVCcD3Ee2Ir7Wmn6U3KvPN" [LimitId.USERS]: "price_1SzVCcD3Ee2Ir7Wmn6U3KvPN"
}; };
export const tier2FeaturePriceSetSandbox: FeaturePriceSet = { export const tier2FeaturePriceSetSandbox: FeaturePriceSet = {
[FeatureId.USERS]: "price_1SxaEHDCpkOb237BD9lBkPiR" [LimitId.USERS]: "price_1SxaEHDCpkOb237BD9lBkPiR"
}; };
export function getTier2FeaturePriceSet(): FeaturePriceSet { export function getTier2FeaturePriceSet(): FeaturePriceSet {
@@ -98,11 +108,11 @@ export function getTier2FeaturePriceSet(): FeaturePriceSet {
} }
export const tier3FeaturePriceSet: FeaturePriceSet = { export const tier3FeaturePriceSet: FeaturePriceSet = {
[FeatureId.USERS]: "price_1SzVDKD3Ee2Ir7WmPtOKNusv" [LimitId.USERS]: "price_1SzVDKD3Ee2Ir7WmPtOKNusv"
}; };
export const tier3FeaturePriceSetSandbox: FeaturePriceSet = { export const tier3FeaturePriceSetSandbox: FeaturePriceSet = {
[FeatureId.USERS]: "price_1SxaEODCpkOb237BiXdCBSfs" [LimitId.USERS]: "price_1SxaEODCpkOb237BiXdCBSfs"
}; };
export function getTier3FeaturePriceSet(): FeaturePriceSet { export function getTier3FeaturePriceSet(): FeaturePriceSet {
@@ -116,7 +126,7 @@ export function getTier3FeaturePriceSet(): FeaturePriceSet {
} }
} }
export function getFeatureIdByPriceId(priceId: string): FeatureId | undefined { export function getFeatureIdByPriceId(priceId: string): LimitId | undefined {
// Check all feature price sets // Check all feature price sets
const allPriceSets = [ const allPriceSets = [
getTier1FeaturePriceSet(), getTier1FeaturePriceSet(),
@@ -125,7 +135,7 @@ export function getFeatureIdByPriceId(priceId: string): FeatureId | undefined {
]; ];
for (const priceSet of allPriceSets) { for (const priceSet of allPriceSets) {
const entry = (Object.entries(priceSet) as [FeatureId, string][]).find( const entry = (Object.entries(priceSet) as [LimitId, string][]).find(
([_, price]) => price === priceId ([_, price]) => price === priceId
); );
if (entry) { if (entry) {
+5 -5
View File
@@ -1,19 +1,19 @@
import Stripe from "stripe"; import Stripe from "stripe";
import { FeatureId, FeaturePriceSet } from "./features"; import { LimitId, FeaturePriceSet } from "./features";
import { usageService } from "./usageService"; import { usageService } from "./usageService";
export async function getLineItems( export async function getLineItems(
featurePriceSet: FeaturePriceSet, featurePriceSet: FeaturePriceSet,
orgId: string, orgId: string
): Promise<Stripe.Checkout.SessionCreateParams.LineItem[]> { ): Promise<Stripe.Checkout.SessionCreateParams.LineItem[]> {
const users = await usageService.getUsage(orgId, FeatureId.USERS); const users = await usageService.getUsage(orgId, LimitId.USERS);
return Object.entries(featurePriceSet).map(([featureId, priceId]) => { return Object.entries(featurePriceSet).map(([featureId, priceId]) => {
let quantity: number | undefined; let quantity: number | undefined;
if (featureId === FeatureId.USERS) { if (featureId === LimitId.USERS) {
quantity = users?.instantaneousValue || 1; quantity = users?.instantaneousValue || 1;
} else if (featureId === FeatureId.TIER1) { } else if (featureId === LimitId.TIER1) {
quantity = 1; quantity = 1;
} }
+35 -23
View File
@@ -1,70 +1,82 @@
import { FeatureId } from "./features"; import { LimitId } from "./features";
export type LimitSet = Partial<{ export type LimitSet = Partial<{
[key in FeatureId]: { [key in LimitId]: {
value: number | null; // null indicates no limit value: number | null; // null indicates no limit
description?: string; description?: string;
}; };
}>; }>;
export const freeLimitSet: LimitSet = { export const freeLimitSet: LimitSet = {
[FeatureId.SITES]: { value: 5, description: "Basic limit" }, [LimitId.SITES]: { value: 5, description: "Basic limit" },
[FeatureId.USERS]: { value: 5, description: "Basic limit" }, [LimitId.USERS]: { value: 5, description: "Basic limit" },
[FeatureId.DOMAINS]: { value: 5, description: "Basic limit" }, [LimitId.DOMAINS]: { value: 5, description: "Basic limit" },
[FeatureId.REMOTE_EXIT_NODES]: { value: 1, description: "Basic limit" }, [LimitId.REMOTE_EXIT_NODES]: { value: 1, description: "Basic limit" },
[FeatureId.ORGINIZATIONS]: { value: 1, description: "Basic limit" }, [LimitId.ORGANIZATIONS]: { value: 1, description: "Basic limit" },
[LimitId.PUBLIC_RESOURCES]: { value: 15, description: "Basic limit" },
[LimitId.PRIVATE_RESOURCES]: { value: 15, description: "Basic limit" },
[LimitId.MACHINE_CLIENTS]: { value: 5, description: "Basic limit" }
}; };
export const tier1LimitSet: LimitSet = { export const tier1LimitSet: LimitSet = {
[FeatureId.USERS]: { value: 7, description: "Home limit" }, [LimitId.USERS]: { value: 7, description: "Home limit" },
[FeatureId.SITES]: { value: 10, description: "Home limit" }, [LimitId.SITES]: { value: 10, description: "Home limit" },
[FeatureId.DOMAINS]: { value: 10, description: "Home limit" }, [LimitId.DOMAINS]: { value: 10, description: "Home limit" },
[FeatureId.REMOTE_EXIT_NODES]: { value: 1, description: "Home limit" }, [LimitId.REMOTE_EXIT_NODES]: { value: 1, description: "Home limit" },
[FeatureId.ORGINIZATIONS]: { value: 1, description: "Home limit" }, [LimitId.ORGANIZATIONS]: { value: 1, description: "Home limit" },
[LimitId.PUBLIC_RESOURCES]: { value: 30, description: "Home limit" },
[LimitId.PRIVATE_RESOURCES]: { value: 30, description: "Home limit" },
[LimitId.MACHINE_CLIENTS]: { value: 10, description: "Home limit" }
}; };
export const tier2LimitSet: LimitSet = { export const tier2LimitSet: LimitSet = {
[FeatureId.USERS]: { [LimitId.USERS]: {
value: 50, value: 50,
description: "Team limit" description: "Team limit"
}, },
[FeatureId.SITES]: { [LimitId.SITES]: {
value: 50, value: 50,
description: "Team limit" description: "Team limit"
}, },
[FeatureId.DOMAINS]: { [LimitId.DOMAINS]: {
value: 50, value: 50,
description: "Team limit" description: "Team limit"
}, },
[FeatureId.REMOTE_EXIT_NODES]: { [LimitId.REMOTE_EXIT_NODES]: {
value: 3, value: 3,
description: "Team limit" description: "Team limit"
}, },
[FeatureId.ORGINIZATIONS]: { [LimitId.ORGANIZATIONS]: {
value: 1, value: 1,
description: "Team limit" description: "Team limit"
} },
[LimitId.PUBLIC_RESOURCES]: { value: 150, description: "Team limit" },
[LimitId.PRIVATE_RESOURCES]: { value: 150, description: "Team limit" },
[LimitId.MACHINE_CLIENTS]: { value: 25, description: "Team limit" }
}; };
export const tier3LimitSet: LimitSet = { export const tier3LimitSet: LimitSet = {
[FeatureId.USERS]: { [LimitId.USERS]: {
value: 250, value: 250,
description: "Business limit" description: "Business limit"
}, },
[FeatureId.SITES]: { [LimitId.SITES]: {
value: 250, value: 250,
description: "Business limit" description: "Business limit"
}, },
[FeatureId.DOMAINS]: { [LimitId.DOMAINS]: {
value: 100, value: 100,
description: "Business limit" description: "Business limit"
}, },
[FeatureId.REMOTE_EXIT_NODES]: { [LimitId.REMOTE_EXIT_NODES]: {
value: 20, value: 20,
description: "Business limit" description: "Business limit"
}, },
[FeatureId.ORGINIZATIONS]: { [LimitId.ORGANIZATIONS]: {
value: 5, value: 5,
description: "Business limit" description: "Business limit"
}, },
[LimitId.PUBLIC_RESOURCES]: { value: 750, description: "Business limit" },
[LimitId.PRIVATE_RESOURCES]: { value: 750, description: "Business limit" },
[LimitId.MACHINE_CLIENTS]: { value: 100, description: "Business limit" }
}; };
+2 -2
View File
@@ -1,7 +1,7 @@
import { db, limits } from "@server/db"; import { db, limits } from "@server/db";
import { and, eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { LimitSet } from "./limitSet"; import { LimitSet } from "./limitSet";
import { FeatureId } from "./features"; import { LimitId } from "./features";
import logger from "@server/logger"; import logger from "@server/logger";
class LimitService { class LimitService {
@@ -38,7 +38,7 @@ class LimitService {
async getOrgLimit( async getOrgLimit(
orgId: string, orgId: string,
featureId: FeatureId featureId: LimitId
): Promise<number | null> { ): Promise<number | null> {
const limitId = `${orgId}-${featureId}`; const limitId = `${orgId}-${featureId}`;
const [limit] = await db const [limit] = await db
-2
View File
@@ -23,7 +23,6 @@ export enum TierFeature {
StandaloneHealthChecks = "standaloneHealthChecks", StandaloneHealthChecks = "standaloneHealthChecks",
AlertingRules = "alertingRules", AlertingRules = "alertingRules",
WildcardSubdomain = "wildcardSubdomain", WildcardSubdomain = "wildcardSubdomain",
Labels = "labels",
NewtAutoUpdate = "newtAutoUpdate", NewtAutoUpdate = "newtAutoUpdate",
ResourcePolicies = "resourcePolicies", ResourcePolicies = "resourcePolicies",
AdvancedPublicResources = "advancedPublicResources", AdvancedPublicResources = "advancedPublicResources",
@@ -31,7 +30,6 @@ export enum TierFeature {
} }
export const tierMatrix: Record<TierFeature, Tier[]> = { export const tierMatrix: Record<TierFeature, Tier[]> = {
[TierFeature.Labels]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"], [TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.LoginPageDomain]: ["tier1", "tier2", "tier3", "enterprise"], [TierFeature.LoginPageDomain]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.DeviceApprovals]: ["tier1", "tier3", "enterprise"], [TierFeature.DeviceApprovals]: ["tier1", "tier3", "enterprise"],
+21 -16
View File
@@ -9,7 +9,7 @@ import {
Transaction, Transaction,
orgs orgs
} from "@server/db"; } from "@server/db";
import { FeatureId, getFeatureMeterId } from "./features"; import { LimitId, getFeatureMeterId } from "./features";
import logger from "@server/logger"; import logger from "@server/logger";
import { build } from "@server/build"; import { build } from "@server/build";
import { regionalCache as cache } from "#dynamic/lib/cache"; import { regionalCache as cache } from "#dynamic/lib/cache";
@@ -37,7 +37,7 @@ export class UsageService {
public async add( public async add(
orgId: string, orgId: string,
featureId: FeatureId, featureId: LimitId,
value: number, value: number,
transaction: any = null transaction: any = null
): Promise<Usage | null> { ): Promise<Usage | null> {
@@ -114,7 +114,7 @@ export class UsageService {
private async internalAddUsage( private async internalAddUsage(
orgId: string, // here the orgId is the billing org already resolved by getBillingOrg in updateCount orgId: string, // here the orgId is the billing org already resolved by getBillingOrg in updateCount
featureId: FeatureId, featureId: LimitId,
value: number, value: number,
trx: Transaction trx: Transaction
): Promise<Usage> { ): Promise<Usage> {
@@ -163,7 +163,7 @@ export class UsageService {
async updateCount( async updateCount(
orgId: string, orgId: string,
featureId: FeatureId, featureId: LimitId,
value?: number, value?: number,
customerId?: string customerId?: string
): Promise<void> { ): Promise<void> {
@@ -227,7 +227,7 @@ export class UsageService {
private async getCustomerId( private async getCustomerId(
orgId: string, orgId: string,
featureId: FeatureId featureId: LimitId
): Promise<string | null> { ): Promise<string | null> {
const orgIdToUse = await this.getBillingOrg(orgId); const orgIdToUse = await this.getBillingOrg(orgId);
@@ -269,18 +269,19 @@ export class UsageService {
public async getUsage( public async getUsage(
orgId: string, orgId: string,
featureId: FeatureId, featureId: LimitId,
trx: Transaction | typeof db = db trx: Transaction | typeof db = db
): Promise<Usage | null> { ): Promise<Usage | null> {
if (noop()) { if (noop()) {
return null; return null;
} }
const orgIdToUse = await this.getBillingOrg(orgId, trx); let orgIdToUse = orgId;
const usageId = `${orgIdToUse}-${featureId}`;
try { try {
orgIdToUse = await this.getBillingOrg(orgId, trx);
const usageId = `${orgIdToUse}-${featureId}`;
const [result] = await trx const [result] = await trx
.select() .select()
.from(usage) .from(usage)
@@ -340,8 +341,12 @@ export class UsageService {
`Failed to get usage for ${orgIdToUse}/${featureId}:`, `Failed to get usage for ${orgIdToUse}/${featureId}:`,
error error
); );
throw error; if (process.env.NODE_ENV !== "development") {
throw error;
}
} }
return null;
} }
public async getBillingOrg( public async getBillingOrg(
@@ -376,7 +381,7 @@ export class UsageService {
public async checkLimitSet( public async checkLimitSet(
orgId: string, orgId: string,
featureId?: FeatureId, featureId?: LimitId,
usage?: Usage, usage?: Usage,
trx: Transaction | typeof db = db trx: Transaction | typeof db = db
): Promise<boolean> { ): Promise<boolean> {
@@ -384,13 +389,13 @@ export class UsageService {
return false; return false;
} }
const orgIdToUse = await this.getBillingOrg(orgId, trx);
// This method should check the current usage against the limits set for the organization // This method should check the current usage against the limits set for the organization
// and kick out all of the sites on the org // and kick out all of the sites on the org
let hasExceededLimits = false; let hasExceededLimits = false;
let orgIdToUse = orgId;
try { try {
orgIdToUse = await this.getBillingOrg(orgId, trx);
let orgLimits: Limit[] = []; let orgLimits: Limit[] = [];
if (featureId) { if (featureId) {
// Get all limits set for this organization // Get all limits set for this organization
@@ -424,7 +429,7 @@ export class UsageService {
} else { } else {
currentUsage = await this.getUsage( currentUsage = await this.getUsage(
orgIdToUse, orgIdToUse,
limit.featureId as FeatureId, limit.featureId as LimitId,
trx trx
); );
} }
+5 -2
View File
@@ -8,7 +8,7 @@ import {
userSiteResources, userSiteResources,
clientSiteResources clientSiteResources
} from "@server/db"; } from "@server/db";
import { Config, ConfigSchema } from "./types"; import { Config, ConfigSchema, isTargetsOnlyResource } from "./types";
import { import {
PublicResourcesResults, PublicResourcesResults,
updatePublicResources updatePublicResources
@@ -64,6 +64,7 @@ export async function applyBlueprint({
let publicResourcesResults: PublicResourcesResults = []; let publicResourcesResults: PublicResourcesResults = [];
let privateResourcesResults: ClientResourcesResults = []; let privateResourcesResults: ClientResourcesResults = [];
await db.transaction(async (trx) => { await db.transaction(async (trx) => {
await updateResourcePolicies(orgId, config, trx); await updateResourcePolicies(orgId, config, trx);
@@ -172,7 +173,9 @@ export async function applyBlueprint({
} catch (err) { } catch (err) {
blueprintSucceeded = false; blueprintSucceeded = false;
blueprintMessage = `Blueprint applied with errors: ${err}`; blueprintMessage = `Blueprint applied with errors: ${err}`;
logger.error(blueprintMessage); logger.debug(
`Org ${orgId} blueprint apply issues: ${blueprintMessage}`
);
error = err; error = err;
} }
@@ -116,7 +116,7 @@ export async function applyNewtDockerBlueprint(
source: "NEWT" source: "NEWT"
}); });
} catch (error) { } catch (error) {
logger.error(`Failed to update database from config: ${error}`); logger.debug(`Failed to update database from config: ${error}`);
await sendToClient(newtId, { await sendToClient(newtId, {
type: "newt/blueprint/results", type: "newt/blueprint/results",
data: { data: {
+95 -7
View File
@@ -25,6 +25,9 @@ import { getNextAvailableAliasAddress } from "../ip";
import { createCertificate } from "#dynamic/routers/certificates/createCertificate"; import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed"; import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
import { tierMatrix } from "../billing/tierMatrix"; import { tierMatrix } from "../billing/tierMatrix";
import { build } from "@server/build";
import { LimitId } from "../billing";
import { usageService } from "../billing/usageService";
async function getDomainForSiteResource( async function getDomainForSiteResource(
siteResourceId: number | undefined, siteResourceId: number | undefined,
@@ -195,17 +198,19 @@ export async function updatePrivateResources(
} }
} }
let resourceStatusFromSite: "approved" | "pending" = "approved";
if (siteId && allSites.length === 0) { if (siteId && allSites.length === 0) {
// only add if there are not provided sites // only add if there are not provided sites
// Use the provided siteId directly, but verify it belongs to the org // Use the provided siteId directly, but verify it belongs to the org
const [siteSingle] = await trx const [siteSingle] = await trx
.select({ siteId: sites.siteId }) .select({ siteId: sites.siteId, status: sites.status })
.from(sites) .from(sites)
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId))) .where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
.limit(1); .limit(1);
if (siteSingle) { if (siteSingle) {
allSites.push(siteSingle); allSites.push(siteSingle);
} }
resourceStatusFromSite = siteSingle.status ?? "approved";
} }
if (allSites.length === 0) { if (allSites.length === 0) {
@@ -214,6 +219,13 @@ export async function updatePrivateResources(
); );
} }
const resourceEnabled =
resourceData.enabled == undefined || resourceData.enabled == null
? true
: resourceStatusFromSite === "pending"
? false
: resourceData.enabled;
if (existingResource) { if (existingResource) {
let domainInfo: let domainInfo:
| { subdomain: string | null; domainId: string } | { subdomain: string | null; domainId: string }
@@ -227,6 +239,31 @@ export async function updatePrivateResources(
); );
} }
if (resourceData.alias) {
const [aliasConflict] = await trx
.select({
siteResourceId: siteResources.siteResourceId
})
.from(siteResources)
.where(
and(
eq(siteResources.orgId, orgId),
eq(siteResources.alias, resourceData.alias),
ne(
siteResources.siteResourceId,
existingResource.siteResourceId
)
)
)
.limit(1);
if (aliasConflict) {
throw new Error(
`Alias ${resourceData.alias} already in use by another site resource in org ${orgId}`
);
}
}
// Update existing resource // Update existing resource
const [updatedResource] = await trx const [updatedResource] = await trx
.update(siteResources) .update(siteResources)
@@ -237,8 +274,7 @@ export async function updatePrivateResources(
scheme: resourceData.scheme, scheme: resourceData.scheme,
destination: resourceData.destination, destination: resourceData.destination,
destinationPort: resourceData["destination-port"], destinationPort: resourceData["destination-port"],
enabled: true, // hardcoded for now enabled: resourceEnabled,
// enabled: resourceData.enabled ?? true,
alias: resourceData.alias || null, alias: resourceData.alias || null,
disableIcmp: disableIcmp:
resourceData["disable-icmp"] || resourceData["disable-icmp"] ||
@@ -257,7 +293,8 @@ export async function updatePrivateResources(
pamMode: resourceData["auth-daemon"]?.pam || "passthrough", pamMode: resourceData["auth-daemon"]?.pam || "passthrough",
authDaemonMode: authDaemonMode:
resourceData["auth-daemon"]?.mode || "native", resourceData["auth-daemon"]?.mode || "native",
authDaemonPort: resourceData["auth-daemon"]?.port || 22123 authDaemonPort: resourceData["auth-daemon"]?.port || 22123,
status: resourceStatusFromSite
}) })
.where( .where(
eq( eq(
@@ -413,6 +450,34 @@ export async function updatePrivateResources(
oldSites: existingSiteIds oldSites: existingSiteIds
}); });
} else { } else {
// create a brand new resource
if (build == "saas") {
const usage = await usageService.getUsage(
orgId,
LimitId.PRIVATE_RESOURCES
);
if (!usage) {
throw new Error(
`Usage data not found for org ${orgId} and limit ${LimitId.PRIVATE_RESOURCES}`
);
}
const rejectResource = await usageService.checkLimitSet(
orgId,
LimitId.PRIVATE_RESOURCES,
{
...usage,
instantaneousValue: (usage.instantaneousValue || 0) + 1
} // We need to add one to know if we are violating the limit
);
if (rejectResource) {
throw new Error(
"Private resource limit exceeded. Please upgrade your plan."
);
}
}
let aliasAddress: string | null = null; let aliasAddress: string | null = null;
let releaseAliasLock: (() => Promise<void>) | null = null; let releaseAliasLock: (() => Promise<void>) | null = null;
if ( if (
@@ -440,6 +505,27 @@ export async function updatePrivateResources(
); );
} }
if (resourceData.alias) {
const [aliasConflict] = await trx
.select({
siteResourceId: siteResources.siteResourceId
})
.from(siteResources)
.where(
and(
eq(siteResources.orgId, orgId),
eq(siteResources.alias, resourceData.alias)
)
)
.limit(1);
if (aliasConflict) {
throw new Error(
`Alias ${resourceData.alias} already in use by another site resource in org ${orgId}`
);
}
}
const [network] = await trx const [network] = await trx
.insert(networks) .insert(networks)
.values({ .values({
@@ -462,8 +548,7 @@ export async function updatePrivateResources(
scheme: resourceData.scheme, scheme: resourceData.scheme,
destination: resourceData.destination, destination: resourceData.destination,
destinationPort: resourceData["destination-port"], destinationPort: resourceData["destination-port"],
enabled: true, // hardcoded for now enabled: resourceEnabled,
// enabled: resourceData.enabled ?? true,
alias: resourceData.alias || null, alias: resourceData.alias || null,
aliasAddress: aliasAddress, aliasAddress: aliasAddress,
disableIcmp: disableIcmp:
@@ -483,7 +568,8 @@ export async function updatePrivateResources(
pamMode: resourceData["auth-daemon"]?.pam || "passthrough", pamMode: resourceData["auth-daemon"]?.pam || "passthrough",
authDaemonMode: authDaemonMode:
resourceData["auth-daemon"]?.mode || "native", resourceData["auth-daemon"]?.mode || "native",
authDaemonPort: resourceData["auth-daemon"]?.port || 22123 authDaemonPort: resourceData["auth-daemon"]?.port || 22123,
status: resourceStatusFromSite
}) })
.returning(); .returning();
@@ -609,6 +695,8 @@ export async function updatePrivateResources(
`Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}` `Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}`
); );
await usageService.add(orgId, LimitId.PRIVATE_RESOURCES, 1, trx);
results.push({ results.push({
newSiteResource: newResource, newSiteResource: newResource,
newSites: allSites, newSites: allSites,
+102 -48
View File
@@ -1,56 +1,60 @@
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
import { hashPassword } from "@server/auth/password";
import { generateId } from "@server/auth/sessions/app";
import { build } from "@server/build";
import { import {
domains,
domainNamespaces, domainNamespaces,
domains,
orgDomains, orgDomains,
Resource, Resource,
resourceHeaderAuth, resourceHeaderAuth,
resourceHeaderAuthExtendedCompatibility, resourceHeaderAuthExtendedCompatibility,
resourcePassword,
resourcePincode, resourcePincode,
resourcePolicies,
resourcePolicyHeaderAuth,
resourcePolicyPassword,
resourcePolicyPincode,
resourcePolicyRules,
resourcePolicyWhiteList,
resourceRules, resourceRules,
resources,
resourceWhitelist, resourceWhitelist,
roleActions, roleActions,
rolePolicies,
roleResources, roleResources,
roles, roles,
Site,
sites,
Target, Target,
TargetHealthCheck, TargetHealthCheck,
targetHealthCheck, targetHealthCheck,
targets,
Transaction, Transaction,
userOrgs, userOrgs,
userPolicies,
userResources, userResources,
users, users,
resourcePolicies, type ResourceRule
resourcePolicyPassword,
resourcePolicyPincode,
resourcePolicyHeaderAuth,
resourcePolicyRules,
resourcePolicyWhiteList,
rolePolicies,
userPolicies
} from "@server/db"; } from "@server/db";
import { resources, targets, sites } from "@server/db";
import { eq, and, asc, or, ne, count, isNotNull } from "drizzle-orm";
import {
Config,
ConfigSchema,
isTargetsOnlyResource,
TargetData
} from "./types";
import logger from "@server/logger";
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
import { pickPort } from "@server/routers/target/helpers";
import { resourcePassword } from "@server/db";
import { getUniqueResourcePolicyName } from "@server/db/names"; import { getUniqueResourcePolicyName } from "@server/db/names";
import { hashPassword } from "@server/auth/password";
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
import { isValidRegionId } from "@server/db/regions"; import { isValidRegionId } from "@server/db/regions";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
import { fireHealthCheckUnknownAlert } from "@server/lib/alerts"; import { fireHealthCheckUnknownAlert } from "@server/lib/alerts";
import { tierMatrix } from "../billing/tierMatrix";
import { defaultRoleAllowedActions } from "@server/routers/role/createRole";
import { build } from "@server/build";
import { encrypt } from "@server/lib/crypto";
import { generateId } from "@server/auth/sessions/app";
import serverConfig from "@server/lib/config"; import serverConfig from "@server/lib/config";
import { encrypt } from "@server/lib/crypto";
import logger from "@server/logger";
import { defaultRoleAllowedActions } from "@server/routers/role/createRole";
import { pickPort } from "@server/routers/target/helpers";
import { and, asc, eq, isNotNull, ne, or } from "drizzle-orm";
import { tierMatrix } from "../billing/tierMatrix";
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
import { Config, isTargetsOnlyResource, TargetData } from "./types";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import next from "next";
import { LimitId } from "../billing";
import { usageService } from "../billing/usageService";
export type PublicResourcesResults = { export type PublicResourcesResults = {
proxyResource: Resource; proxyResource: Resource;
@@ -71,19 +75,40 @@ export async function updatePublicResources(
)) { )) {
const targetsToUpdate: Target[] = []; const targetsToUpdate: Target[] = [];
const healthchecksToUpdate: TargetHealthCheck[] = []; const healthchecksToUpdate: TargetHealthCheck[] = [];
let resource: Resource; let resource: Resource;
let resourceStatusFromSite: "approved" | "pending" = "approved";
let providedSite: Partial<Site> | undefined;
if (siteId) {
// Use the provided siteId directly, but verify it belongs to the org
[providedSite] = await trx
.select({
siteId: sites.siteId,
type: sites.type,
status: sites.status
})
.from(sites)
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
.limit(1);
resourceStatusFromSite = providedSite?.status ?? "approved";
}
async function createTarget( // reusable function to create a target async function createTarget( // reusable function to create a target
resourceId: number, resourceId: number,
targetData: TargetData targetData: TargetData
) { ) {
const targetSiteId = targetData.site; const targetSiteId = targetData.site;
let site; let site: Partial<Site> | undefined;
if (targetSiteId) { if (targetSiteId) {
// Look up site by niceId // Look up site by niceId
[site] = await trx [site] = await trx
.select({ siteId: sites.siteId, type: sites.type }) .select({
siteId: sites.siteId,
type: sites.type,
status: sites.status
})
.from(sites) .from(sites)
.where( .where(
and( and(
@@ -92,15 +117,9 @@ export async function updatePublicResources(
) )
) )
.limit(1); .limit(1);
} else if (siteId) { } else if (siteId && providedSite) {
// Use the provided siteId directly, but verify it belongs to the org // Use the provided siteId directly, but verify it belongs to the org
[site] = await trx site = providedSite;
.select({ siteId: sites.siteId, type: sites.type })
.from(sites)
.where(
and(eq(sites.siteId, siteId), eq(sites.orgId, orgId))
)
.limit(1);
} else { } else {
throw new Error(`Target site is required`); throw new Error(`Target site is required`);
} }
@@ -136,7 +155,7 @@ export async function updatePublicResources(
.insert(targets) .insert(targets)
.values({ .values({
resourceId: resourceId, resourceId: resourceId,
siteId: site.siteId, siteId: site.siteId!,
ip: targetData.hostname, ip: targetData.hostname,
mode: resourceData.mode as Target["mode"], mode: resourceData.mode as Target["mode"],
method: targetData.method, method: targetData.method,
@@ -169,7 +188,7 @@ export async function updatePublicResources(
.insert(targetHealthCheck) .insert(targetHealthCheck)
.values({ .values({
name: `${targetData.hostname}:${targetData.port}`, name: `${targetData.hostname}:${targetData.port}`,
siteId: site.siteId, siteId: site.siteId!,
targetId: newTarget.targetId, targetId: newTarget.targetId,
orgId: orgId, orgId: orgId,
hcEnabled: healthcheckData?.enabled || false, hcEnabled: healthcheckData?.enabled || false,
@@ -227,7 +246,10 @@ export async function updatePublicResources(
const resourceEnabled = const resourceEnabled =
resourceData.enabled == undefined || resourceData.enabled == null resourceData.enabled == undefined || resourceData.enabled == null
? true ? true
: resourceData.enabled; : resourceStatusFromSite === "pending"
? false
: resourceData.enabled;
const resourceSsl = const resourceSsl =
resourceData.ssl == undefined || resourceData.ssl == null resourceData.ssl == undefined || resourceData.ssl == null
? true ? true
@@ -403,7 +425,8 @@ export async function updatePublicResources(
? (resourceData["proxy-protocol-version"] ?? ? (resourceData["proxy-protocol-version"] ??
1) 1)
: 1, : 1,
resourcePolicyId: sharedPolicy.resourcePolicyId resourcePolicyId: sharedPolicy.resourcePolicyId,
status: resourceStatusFromSite
}) })
.where( .where(
eq( eq(
@@ -587,7 +610,8 @@ export async function updatePublicResources(
authDaemonPort: authDaemonPort:
resourceData["auth-daemon"]?.port || 22123, resourceData["auth-daemon"]?.port || 22123,
resourcePolicyId: null, resourcePolicyId: null,
defaultResourcePolicyId: inlinePolicyId defaultResourcePolicyId: inlinePolicyId,
status: resourceStatusFromSite
}) })
.where( .where(
eq( eq(
@@ -904,7 +928,7 @@ export async function updatePublicResources(
.update(resourceRules) .update(resourceRules)
.set({ .set({
action: getRuleAction(rule.action), action: getRuleAction(rule.action),
match: rule.match.toUpperCase(), match: rule.match.toUpperCase() as ResourceRule["match"],
value: getRuleValue( value: getRuleValue(
rule.match.toUpperCase(), rule.match.toUpperCase(),
rule.value rule.value
@@ -923,7 +947,7 @@ export async function updatePublicResources(
await trx.insert(resourceRules).values({ await trx.insert(resourceRules).values({
resourceId: existingResource.resourceId, resourceId: existingResource.resourceId,
action: getRuleAction(rule.action), action: getRuleAction(rule.action),
match: rule.match.toUpperCase(), match: rule.match.toUpperCase() as ResourceRule["match"],
value: getRuleValue( value: getRuleValue(
rule.match.toUpperCase(), rule.match.toUpperCase(),
rule.value rule.value
@@ -1005,6 +1029,33 @@ export async function updatePublicResources(
logger.debug(`Updated resource ${existingResource.resourceId}`); logger.debug(`Updated resource ${existingResource.resourceId}`);
} else { } else {
// create a brand new resource // create a brand new resource
if (build === "saas") {
const usage = await usageService.getUsage(
orgId,
LimitId.PUBLIC_RESOURCES
);
if (!usage) {
throw new Error(
`Usage data not found for org ${orgId} and limit ${LimitId.PUBLIC_RESOURCES}`
);
}
const rejectResource = await usageService.checkLimitSet(
orgId,
LimitId.PUBLIC_RESOURCES,
{
...usage,
instantaneousValue: (usage.instantaneousValue || 0) + 1
} // We need to add one to know if we are violating the limit
);
if (rejectResource) {
throw new Error(
"Public resource limit exceeded. Please upgrade your plan."
);
}
}
let domain; let domain;
if ( if (
["http", "ssh", "rdp", "vnc"].includes(resourceData.mode || "") ["http", "ssh", "rdp", "vnc"].includes(resourceData.mode || "")
@@ -1101,6 +1152,7 @@ export async function updatePublicResources(
.values({ .values({
orgId, orgId,
niceId: resourceNiceId, niceId: resourceNiceId,
status: resourceStatusFromSite,
name: resourceData.name || "Unnamed Resource", name: resourceData.name || "Unnamed Resource",
mode: resourceData.mode, mode: resourceData.mode,
proxyPort: ["http", "ssh", "rdp", "vnc"].includes( proxyPort: ["http", "ssh", "rdp", "vnc"].includes(
@@ -1260,7 +1312,7 @@ export async function updatePublicResources(
await trx.insert(resourceRules).values({ await trx.insert(resourceRules).values({
resourceId: newResource.resourceId, resourceId: newResource.resourceId,
action: getRuleAction(rule.action), action: getRuleAction(rule.action),
match: rule.match.toUpperCase(), match: rule.match.toUpperCase() as ResourceRule["match"],
value: getRuleValue( value: getRuleValue(
rule.match.toUpperCase(), rule.match.toUpperCase(),
rule.value rule.value
@@ -1294,6 +1346,8 @@ export async function updatePublicResources(
await createTarget(newResource.resourceId, targetData); await createTarget(newResource.resourceId, targetData);
} }
await usageService.add(orgId, LimitId.PUBLIC_RESOURCES, 1, trx);
logger.debug(`Created resource ${newResource.resourceId}`); logger.debug(`Created resource ${newResource.resourceId}`);
} }
@@ -1321,7 +1375,7 @@ function getRuleAction(input: string) {
function getRuleValue(match: string, value: string) { function getRuleValue(match: string, value: string) {
// if the match is a country, uppercase the value // if the match is a country, uppercase the value
if (match == "COUNTRY") { if (match === "COUNTRY" || match === "COUNTRY_IS_NOT") {
return value.toUpperCase(); return value.toUpperCase();
} }
return value; return value;
+2 -1
View File
@@ -347,12 +347,13 @@ function getRuleAction(input: string): "ACCEPT" | "DROP" | "PASS" {
function getRuleMatch( function getRuleMatch(
input: string input: string
): "CIDR" | "IP" | "PATH" | "COUNTRY" | "ASN" | "REGION" { ): "CIDR" | "IP" | "PATH" | "COUNTRY" | "COUNTRY_IS_NOT" | "ASN" | "REGION" {
return input.toUpperCase() as return input.toUpperCase() as
| "CIDR" | "CIDR"
| "IP" | "IP"
| "PATH" | "PATH"
| "COUNTRY" | "COUNTRY"
| "COUNTRY_IS_NOT"
| "ASN" | "ASN"
| "REGION"; | "REGION";
} }
+1 -1
View File
@@ -470,7 +470,7 @@ export const PrivateResourceSchema = z
// proxyPort: z.int().positive().optional(), // proxyPort: z.int().positive().optional(),
"destination-port": z.int().positive().optional(), "destination-port": z.int().positive().optional(),
destination: z.string().min(1).optional(), destination: z.string().min(1).optional(),
// enabled: z.boolean().default(true), enabled: z.boolean().default(true),
"tcp-ports": portRangeStringSchema.optional().default("*"), "tcp-ports": portRangeStringSchema.optional().default("*"),
"udp-ports": portRangeStringSchema.optional().default("*"), "udp-ports": portRangeStringSchema.optional().default("*"),
"disable-icmp": z.boolean().optional().default(false), "disable-icmp": z.boolean().optional().default(false),
+371 -393
View File
@@ -29,7 +29,7 @@ type ClientRow = typeof clients.$inferSelect;
function runQueuedClientAssociationRebuilds( function runQueuedClientAssociationRebuilds(
userId: string, userId: string,
queuedClients: ClientRow[] queuedClients: ClientRow[]
): void { ) {
if (queuedClients.length === 0) { if (queuedClients.length === 0) {
return; return;
} }
@@ -39,425 +39,403 @@ function runQueuedClientAssociationRebuilds(
uniqueClientsById.set(client.clientId, client); uniqueClientsById.set(client.clientId, client);
} }
void (async () => { for (const client of uniqueClientsById.values()) {
for (const client of uniqueClientsById.values()) { rebuildClientAssociationsFromClient(client).catch((error) => {
try { logger.error(
await rebuildClientAssociationsFromClient(client); `Error rebuilding client associations for client ${client.clientId} (user ${userId}): ${String(
} catch (error) { error
logger.error( )}`
`Failed rebuilding associations for client ${client.clientId} (user ${userId}): ${String(error)}` );
); });
} }
}
logger.debug( logger.debug(
`Queued association rebuild completed for ${uniqueClientsById.size} client(s) (user ${userId})` `Queued association rebuild completed for ${uniqueClientsById.size} client(s) (user ${userId})`
); );
})();
} }
export async function calculateUserClientsForOrgs( export async function calculateUserClientsForOrgs(
userId: string userId: string
): Promise<void> { ): Promise<void> {
const trx = primaryDb; const trx = primaryDb;
const queuedAssociationRebuilds: ClientRow[] = []; const queuedAssociationRebuilds: ClientRow[] = [];
const orgCache = new Map<string, typeof orgs.$inferSelect | null>();
const adminRoleCache = new Map<string, typeof roles.$inferSelect | null>();
const exitNodesCache = new Map<
string,
Awaited<ReturnType<typeof listExitNodes>>
>();
const isOrgLicensedCache = new Map<string, boolean>();
const existingClientCache = new Map<
string,
typeof clients.$inferSelect | null
>();
const roleClientAccessCache = new Map<string, boolean>();
const userClientAccessCache = new Map<string, boolean>();
const execute = async (transaction: Transaction | typeof db) => { const getOrgOlmKey = (orgId: string, olmId: string) => `${orgId}:${olmId}`;
const orgCache = new Map<string, typeof orgs.$inferSelect | null>(); const getRoleClientKey = (roleId: number, clientId: number) =>
const adminRoleCache = new Map< `${roleId}:${clientId}`;
string, const getUserClientKey = (cachedUserId: string, clientId: number) =>
typeof roles.$inferSelect | null `${cachedUserId}:${clientId}`;
>();
const exitNodesCache = new Map<
string,
Awaited<ReturnType<typeof listExitNodes>>
>();
const isOrgLicensedCache = new Map<string, boolean>();
const existingClientCache = new Map<
string,
typeof clients.$inferSelect | null
>();
const roleClientAccessCache = new Map<string, boolean>();
const userClientAccessCache = new Map<string, boolean>();
const getOrgOlmKey = (orgId: string, olmId: string) => const getOrg = async (orgId: string) => {
`${orgId}:${olmId}`; if (orgCache.has(orgId)) {
const getRoleClientKey = (roleId: number, clientId: number) => return orgCache.get(orgId) ?? null;
`${roleId}:${clientId}`;
const getUserClientKey = (cachedUserId: string, clientId: number) =>
`${cachedUserId}:${clientId}`;
const getOrg = async (orgId: string) => {
if (orgCache.has(orgId)) {
return orgCache.get(orgId) ?? null;
}
const [org] = await transaction
.select()
.from(orgs)
.where(eq(orgs.orgId, orgId));
orgCache.set(orgId, org ?? null);
return org ?? null;
};
const getAdminRole = async (orgId: string) => {
if (adminRoleCache.has(orgId)) {
return adminRoleCache.get(orgId) ?? null;
}
const [adminRole] = await transaction
.select()
.from(roles)
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
.limit(1);
adminRoleCache.set(orgId, adminRole ?? null);
return adminRole ?? null;
};
const getExitNodes = async (orgId: string) => {
if (exitNodesCache.has(orgId)) {
return exitNodesCache.get(orgId)!;
}
const exitNodes = await listExitNodes(orgId);
exitNodesCache.set(orgId, exitNodes);
return exitNodes;
};
const getIsOrgLicensed = async (orgId: string) => {
if (isOrgLicensedCache.has(orgId)) {
return isOrgLicensedCache.get(orgId)!;
}
const isOrgLicensed = await isLicensedOrSubscribed(
orgId,
tierMatrix.deviceApprovals
);
isOrgLicensedCache.set(orgId, isOrgLicensed);
return isOrgLicensed;
};
const getExistingClient = async (orgId: string, olmId: string) => {
const key = getOrgOlmKey(orgId, olmId);
if (existingClientCache.has(key)) {
return existingClientCache.get(key) ?? null;
}
const [existingClient] = await transaction
.select()
.from(clients)
.where(
and(
eq(clients.userId, userId),
eq(clients.orgId, orgId),
eq(clients.olmId, olmId)
)
)
.limit(1);
existingClientCache.set(key, existingClient ?? null);
return existingClient ?? null;
};
const hasRoleClientAccess = async (
roleId: number,
clientId: number
) => {
const key = getRoleClientKey(roleId, clientId);
if (roleClientAccessCache.has(key)) {
return roleClientAccessCache.get(key)!;
}
const [existingRoleClient] = await transaction
.select()
.from(roleClients)
.where(
and(
eq(roleClients.roleId, roleId),
eq(roleClients.clientId, clientId)
)
)
.limit(1);
const hasAccess = Boolean(existingRoleClient);
roleClientAccessCache.set(key, hasAccess);
return hasAccess;
};
const hasUserClientAccess = async (
cachedUserId: string,
clientId: number
) => {
const key = getUserClientKey(cachedUserId, clientId);
if (userClientAccessCache.has(key)) {
return userClientAccessCache.get(key)!;
}
const [existingUserClient] = await transaction
.select()
.from(userClients)
.where(
and(
eq(userClients.userId, cachedUserId),
eq(userClients.clientId, clientId)
)
)
.limit(1);
const hasAccess = Boolean(existingUserClient);
userClientAccessCache.set(key, hasAccess);
return hasAccess;
};
// Get all OLMs for this user
const userOlms = await transaction
.select()
.from(olms)
.where(eq(olms.userId, userId));
if (userOlms.length === 0) {
// No OLMs for this user, but we should still clean up any orphaned clients
await cleanupOrphanedClients(
userId,
transaction,
[],
queuedAssociationRebuilds
);
return;
} }
// Get all user orgs with all roles (for org list and role-based logic) const [org] = await trx
const userOrgRoleRows = await transaction
.select() .select()
.from(userOrgs) .from(orgs)
.innerJoin( .where(eq(orgs.orgId, orgId));
userOrgRoles, orgCache.set(orgId, org ?? null);
return org ?? null;
};
const getAdminRole = async (orgId: string) => {
if (adminRoleCache.has(orgId)) {
return adminRoleCache.get(orgId) ?? null;
}
const [adminRole] = await trx
.select()
.from(roles)
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
.limit(1);
adminRoleCache.set(orgId, adminRole ?? null);
return adminRole ?? null;
};
const getExitNodes = async (orgId: string) => {
if (exitNodesCache.has(orgId)) {
return exitNodesCache.get(orgId)!;
}
const exitNodes = await listExitNodes(orgId);
exitNodesCache.set(orgId, exitNodes);
return exitNodes;
};
const getIsOrgLicensed = async (orgId: string) => {
if (isOrgLicensedCache.has(orgId)) {
return isOrgLicensedCache.get(orgId)!;
}
const isOrgLicensed = await isLicensedOrSubscribed(
orgId,
tierMatrix.deviceApprovals
);
isOrgLicensedCache.set(orgId, isOrgLicensed);
return isOrgLicensed;
};
const getExistingClient = async (orgId: string, olmId: string) => {
const key = getOrgOlmKey(orgId, olmId);
if (existingClientCache.has(key)) {
return existingClientCache.get(key) ?? null;
}
const [existingClient] = await trx
.select()
.from(clients)
.where(
and( and(
eq(userOrgs.userId, userOrgRoles.userId), eq(clients.userId, userId),
eq(userOrgs.orgId, userOrgRoles.orgId) eq(clients.orgId, orgId),
eq(clients.olmId, olmId)
) )
) )
.innerJoin(roles, eq(userOrgRoles.roleId, roles.roleId)) .limit(1);
.where(eq(userOrgs.userId, userId));
const userOrgIds = [ existingClientCache.set(key, existingClient ?? null);
...new Set(userOrgRoleRows.map((r) => r.userOrgs.orgId))
]; return existingClient ?? null;
const orgIdToRoleRows = new Map< };
string,
(typeof userOrgRoleRows)[0][] const hasRoleClientAccess = async (roleId: number, clientId: number) => {
>(); const key = getRoleClientKey(roleId, clientId);
for (const r of userOrgRoleRows) { if (roleClientAccessCache.has(key)) {
const list = orgIdToRoleRows.get(r.userOrgs.orgId) ?? []; return roleClientAccessCache.get(key)!;
list.push(r);
orgIdToRoleRows.set(r.userOrgs.orgId, list);
}
const orgRequiresDeviceApprovalRole = new Map<string, boolean>();
for (const [orgId, roleRowsForOrg] of orgIdToRoleRows.entries()) {
orgRequiresDeviceApprovalRole.set(
orgId,
roleRowsForOrg.some((r) => r.roles.requireDeviceApproval)
);
} }
// For each OLM, ensure there's a client in each org the user is in const [existingRoleClient] = await trx
for (const olm of userOlms) { .select()
for (const orgId of orgIdToRoleRows.keys()) { .from(roleClients)
const roleRowsForOrg = orgIdToRoleRows.get(orgId)!; .where(
const userOrg = roleRowsForOrg[0].userOrgs; and(
eq(roleClients.roleId, roleId),
eq(roleClients.clientId, clientId)
)
)
.limit(1);
const org = await getOrg(orgId); const hasAccess = Boolean(existingRoleClient);
roleClientAccessCache.set(key, hasAccess);
if (!org) { return hasAccess;
logger.warn( };
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): org not found`
);
continue;
}
if (!org.subnet) { const hasUserClientAccess = async (
logger.warn( cachedUserId: string,
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): org has no subnet configured` clientId: number
); ) => {
continue; const key = getUserClientKey(cachedUserId, clientId);
} if (userClientAccessCache.has(key)) {
return userClientAccessCache.get(key)!;
// Get admin role for this org (needed for access grants)
const adminRole = await getAdminRole(orgId);
if (!adminRole) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no admin role found`
);
continue;
}
// Check if a client already exists for this OLM+user+org combination
const existingClient = await getExistingClient(
orgId,
olm.olmId
);
if (existingClient) {
// Ensure admin role has access to the client
const hasRoleAccess = await hasRoleClientAccess(
adminRole.roleId,
existingClient.clientId
);
if (!hasRoleAccess) {
await transaction.insert(roleClients).values({
roleId: adminRole.roleId,
clientId: existingClient.clientId
});
roleClientAccessCache.set(
getRoleClientKey(
adminRole.roleId,
existingClient.clientId
),
true
);
logger.debug(
`Granted admin role access to existing client ${existingClient.clientId} for OLM ${olm.olmId} in org ${orgId} (user ${userId})`
);
}
// Ensure user has access to the client
const hasUserAccess = await hasUserClientAccess(
userId,
existingClient.clientId
);
if (!hasUserAccess) {
await transaction.insert(userClients).values({
userId,
clientId: existingClient.clientId
});
userClientAccessCache.set(
getUserClientKey(userId, existingClient.clientId),
true
);
logger.debug(
`Granted user access to existing client ${existingClient.clientId} for OLM ${olm.olmId} in org ${orgId} (user ${userId})`
);
}
logger.debug(
`Client already exists for OLM ${olm.olmId} in org ${orgId} (user ${userId}), skipping creation`
);
continue;
}
// Get exit nodes for this org
const exitNodesList = await getExitNodes(orgId);
if (exitNodesList.length === 0) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no exit nodes found`
);
continue;
}
const randomExitNode =
exitNodesList[
Math.floor(Math.random() * exitNodesList.length)
];
// Get next available subnet
const { value: newSubnet, release: releaseSubnetLock } =
await getNextAvailableClientSubnet(orgId, transaction);
const subnet = newSubnet.split("/")[0];
const updatedSubnet = `${subnet}/${org.subnet.split("/")[1]}`;
const niceId = await getUniqueClientName(orgId);
const isOrgLicensed = await getIsOrgLicensed(userOrg.orgId);
const requireApproval =
build !== "oss" &&
isOrgLicensed &&
orgRequiresDeviceApprovalRole.get(orgId) === true;
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
const [newClient] = await transaction
.insert(clients)
.values(newClientData)
.returning();
await releaseSubnetLock();
existingClientCache.set(
getOrgOlmKey(orgId, olm.olmId),
newClient
);
// 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();
}
queuedAssociationRebuilds.push(newClient);
// Grant admin role access to the client
await transaction.insert(roleClients).values({
roleId: adminRole.roleId,
clientId: newClient.clientId
});
roleClientAccessCache.set(
getRoleClientKey(adminRole.roleId, newClient.clientId),
true
);
// Grant user access to the client
await transaction.insert(userClients).values({
userId,
clientId: newClient.clientId
});
userClientAccessCache.set(
getUserClientKey(userId, newClient.clientId),
true
);
logger.debug(
`Created client for OLM ${olm.olmId} in org ${orgId} (user ${userId}) with access granted to admin role and user`
);
}
} }
// Clean up clients in orgs the user is no longer in const [existingUserClient] = await trx
.select()
.from(userClients)
.where(
and(
eq(userClients.userId, cachedUserId),
eq(userClients.clientId, clientId)
)
)
.limit(1);
const hasAccess = Boolean(existingUserClient);
userClientAccessCache.set(key, hasAccess);
return hasAccess;
};
// Get all OLMs for this user
const userOlms = await trx
.select()
.from(olms)
.where(eq(olms.userId, userId));
if (userOlms.length === 0) {
// No OLMs for this user, but we should still clean up any orphaned clients
await cleanupOrphanedClients( await cleanupOrphanedClients(
userId, userId,
transaction, trx,
userOrgIds, [],
queuedAssociationRebuilds queuedAssociationRebuilds
); );
}; return;
}
// Get all user orgs with all roles (for org list and role-based logic)
const userOrgRoleRows = await trx
.select()
.from(userOrgs)
.innerJoin(
userOrgRoles,
and(
eq(userOrgs.userId, userOrgRoles.userId),
eq(userOrgs.orgId, userOrgRoles.orgId)
)
)
.innerJoin(roles, eq(userOrgRoles.roleId, roles.roleId))
.where(eq(userOrgs.userId, userId));
const userOrgIds = [
...new Set(userOrgRoleRows.map((r) => r.userOrgs.orgId))
];
const orgIdToRoleRows = new Map<string, (typeof userOrgRoleRows)[0][]>();
for (const r of userOrgRoleRows) {
const list = orgIdToRoleRows.get(r.userOrgs.orgId) ?? [];
list.push(r);
orgIdToRoleRows.set(r.userOrgs.orgId, list);
}
const orgRequiresDeviceApprovalRole = new Map<string, boolean>();
for (const [orgId, roleRowsForOrg] of orgIdToRoleRows.entries()) {
orgRequiresDeviceApprovalRole.set(
orgId,
roleRowsForOrg.some((r) => r.roles.requireDeviceApproval)
);
}
// For each OLM, ensure there's a client in each org the user is in
for (const olm of userOlms) {
for (const orgId of orgIdToRoleRows.keys()) {
const roleRowsForOrg = orgIdToRoleRows.get(orgId)!;
const userOrg = roleRowsForOrg[0].userOrgs;
const org = await getOrg(orgId);
if (!org) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): org not found`
);
continue;
}
if (!org.subnet) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): org has no subnet configured`
);
continue;
}
// Get admin role for this org (needed for access grants)
const adminRole = await getAdminRole(orgId);
if (!adminRole) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no admin role found`
);
continue;
}
// Check if a client already exists for this OLM+user+org combination
const existingClient = await getExistingClient(orgId, olm.olmId);
if (existingClient) {
// Ensure admin role has access to the client
const hasRoleAccess = await hasRoleClientAccess(
adminRole.roleId,
existingClient.clientId
);
if (!hasRoleAccess) {
await trx.insert(roleClients).values({
roleId: adminRole.roleId,
clientId: existingClient.clientId
});
roleClientAccessCache.set(
getRoleClientKey(
adminRole.roleId,
existingClient.clientId
),
true
);
logger.debug(
`Granted admin role access to existing client ${existingClient.clientId} for OLM ${olm.olmId} in org ${orgId} (user ${userId})`
);
}
// Ensure user has access to the client
const hasUserAccess = await hasUserClientAccess(
userId,
existingClient.clientId
);
if (!hasUserAccess) {
await trx.insert(userClients).values({
userId,
clientId: existingClient.clientId
});
userClientAccessCache.set(
getUserClientKey(userId, existingClient.clientId),
true
);
logger.debug(
`Granted user access to existing client ${existingClient.clientId} for OLM ${olm.olmId} in org ${orgId} (user ${userId})`
);
}
logger.debug(
`Client already exists for OLM ${olm.olmId} in org ${orgId} (user ${userId}), skipping creation`
);
continue;
}
// Get exit nodes for this org
const exitNodesList = await getExitNodes(orgId);
if (exitNodesList.length === 0) {
logger.warn(
`Skipping org ${orgId} for OLM ${olm.olmId} (user ${userId}): no exit nodes found`
);
continue;
}
const randomExitNode =
exitNodesList[Math.floor(Math.random() * exitNodesList.length)];
// Get next available subnet
const { value: newSubnet, release: releaseSubnetLock } =
await getNextAvailableClientSubnet(orgId, trx);
const subnet = newSubnet.split("/")[0];
const updatedSubnet = `${subnet}/${org.subnet.split("/")[1]}`;
const niceId = await getUniqueClientName(orgId);
const isOrgLicensed = await getIsOrgLicensed(userOrg.orgId);
const requireApproval =
build !== "oss" &&
isOrgLicensed &&
orgRequiresDeviceApprovalRole.get(orgId) === true;
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
const [newClient] = await trx
.insert(clients)
.values(newClientData)
.returning();
await releaseSubnetLock();
existingClientCache.set(getOrgOlmKey(orgId, olm.olmId), newClient);
// create approval request
if (requireApproval) {
await trx
.insert(approvals)
.values({
timestamp: Math.floor(new Date().getTime() / 1000),
orgId: userOrg.orgId,
clientId: newClient.clientId,
userId,
type: "user_device"
})
.returning();
}
queuedAssociationRebuilds.push(newClient);
// Grant admin role access to the client
await trx.insert(roleClients).values({
roleId: adminRole.roleId,
clientId: newClient.clientId
});
roleClientAccessCache.set(
getRoleClientKey(adminRole.roleId, newClient.clientId),
true
);
// Grant user access to the client
await trx.insert(userClients).values({
userId,
clientId: newClient.clientId
});
userClientAccessCache.set(
getUserClientKey(userId, newClient.clientId),
true
);
logger.debug(
`Created client for OLM ${olm.olmId} in org ${orgId} (user ${userId}) with access granted to admin role and user`
);
}
}
// Clean up clients in orgs the user is no longer in
await cleanupOrphanedClients(
userId,
trx,
userOrgIds,
queuedAssociationRebuilds
);
runQueuedClientAssociationRebuilds(userId, queuedAssociationRebuilds); runQueuedClientAssociationRebuilds(userId, queuedAssociationRebuilds);
} }
@@ -496,7 +474,7 @@ async function cleanupOrphanedClients(
) )
.returning(); .returning();
// Queue deleted clients for post-transaction association cleanup. // Queue deleted clients for post-trx association cleanup.
for (const deletedClient of deletedClients) { for (const deletedClient of deletedClients) {
queuedAssociationRebuilds.push(deletedClient); queuedAssociationRebuilds.push(deletedClient);
+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.19.0"; export const APP_VERSION = "1.20.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);
+83
View File
@@ -0,0 +1,83 @@
import logger from "@server/logger";
const MAX_RETRIES = 5;
const BASE_DELAY_MS = 50;
/**
* Detect transient errors that are safe to retry (connection drops, deadlocks,
* serialization failures). PostgreSQL deadlocks (40P01) are always safe to
* retry: the database guarantees exactly one winner per deadlock pair, so the
* loser just needs to try again.
*/
export function isTransientError(error: any): boolean {
if (!error) return false;
const message = (error.message || "").toLowerCase();
const causeMessage = (error.cause?.message || "").toLowerCase();
const code = error.code || error.cause?.code || "";
// Connection timeout / terminated
if (
message.includes("connection timeout") ||
message.includes("connection terminated") ||
message.includes("timeout exceeded when trying to connect") ||
causeMessage.includes("connection terminated unexpectedly") ||
causeMessage.includes("connection timeout")
) {
return true;
}
// PostgreSQL deadlock detected - always safe to retry (one winner guaranteed)
if (code === "40P01" || message.includes("deadlock")) {
return true;
}
// PostgreSQL serialization failure
if (code === "40001") {
return true;
}
// ECONNRESET, ECONNREFUSED, EPIPE, ETIMEDOUT
if (
code === "ECONNRESET" ||
code === "ECONNREFUSED" ||
code === "EPIPE" ||
code === "ETIMEDOUT"
) {
return true;
}
return false;
}
/**
* Simple retry wrapper with exponential backoff for transient errors
* (deadlocks, connection timeouts, unexpected disconnects).
*/
export async function withRetry<T>(
operation: () => Promise<T>,
context: string,
maxRetries: number = MAX_RETRIES,
baseDelayMs: number = BASE_DELAY_MS
): Promise<T> {
let attempt = 0;
while (true) {
try {
return await operation();
} catch (error: any) {
if (isTransientError(error) && attempt < maxRetries) {
attempt++;
const baseDelay = Math.pow(2, attempt - 1) * baseDelayMs;
const jitter = Math.random() * baseDelay;
const delay = baseDelay + jitter;
logger.warn(
`Transient DB error in ${context}, retrying attempt ${attempt}/${maxRetries} after ${delay.toFixed(0)}ms`,
{ code: error?.code ?? error?.cause?.code }
);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
}
+9 -7
View File
@@ -24,7 +24,7 @@ import { deletePeer } from "@server/routers/gerbil/peers";
import { OlmErrorCodes } from "@server/routers/olm/error"; import { OlmErrorCodes } from "@server/routers/olm/error";
import { sendTerminateClient } from "@server/routers/client/terminate"; import { sendTerminateClient } from "@server/routers/client/terminate";
import { usageService } from "./billing/usageService"; import { usageService } from "./billing/usageService";
import { FeatureId } from "./billing"; import { LimitId } from "./billing";
export type DeleteOrgByIdResult = { export type DeleteOrgByIdResult = {
deletedNewtIds: string[]; deletedNewtIds: string[];
@@ -140,7 +140,9 @@ export async function deleteOrgById(
.select({ count: count() }) .select({ count: count() })
.from(orgDomains) .from(orgDomains)
.where(eq(orgDomains.domainId, domainId)); .where(eq(orgDomains.domainId, domainId));
logger.info(`Found ${orgCount.count} orgs using domain ${domainId}`); logger.info(
`Found ${orgCount.count} orgs using domain ${domainId}`
);
if (orgCount.count === 1) { if (orgCount.count === 1) {
domainIdsToDelete.push(domainId); domainIdsToDelete.push(domainId);
} }
@@ -152,7 +154,7 @@ export async function deleteOrgById(
.where(inArray(domains.domainId, domainIdsToDelete)); .where(inArray(domains.domainId, domainIdsToDelete));
} }
await usageService.add(orgId, FeatureId.ORGINIZATIONS, -1, trx); // here we are decreasing the org count BEFORE deleting the org because we need to still be able to get the org to get the billing org inside of here await usageService.add(orgId, LimitId.ORGANIZATIONS, -1, trx); // here we are decreasing the org count BEFORE deleting the org because we need to still be able to get the org to get the billing org inside of here
await trx.delete(orgs).where(eq(orgs.orgId, orgId)); await trx.delete(orgs).where(eq(orgs.orgId, orgId));
@@ -199,22 +201,22 @@ export async function deleteOrgById(
if (org.billingOrgId) { if (org.billingOrgId) {
usageService.updateCount( usageService.updateCount(
org.billingOrgId, org.billingOrgId,
FeatureId.DOMAINS, LimitId.DOMAINS,
domainCount ?? 0 domainCount ?? 0
); );
usageService.updateCount( usageService.updateCount(
org.billingOrgId, org.billingOrgId,
FeatureId.SITES, LimitId.SITES,
siteCount ?? 0 siteCount ?? 0
); );
usageService.updateCount( usageService.updateCount(
org.billingOrgId, org.billingOrgId,
FeatureId.USERS, LimitId.USERS,
userCount ?? 0 userCount ?? 0
); );
usageService.updateCount( usageService.updateCount(
org.billingOrgId, org.billingOrgId,
FeatureId.REMOTE_EXIT_NODES, LimitId.REMOTE_EXIT_NODES,
remoteExitNodeCount ?? 0 remoteExitNodeCount ?? 0
); );
} }
+3 -5
View File
@@ -14,8 +14,6 @@ import {
} from "@server/db"; } from "@server/db";
import logger from "@server/logger"; import logger from "@server/logger";
import { removeTargets } from "@server/routers/newt/targets"; import { removeTargets } from "@server/routers/newt/targets";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
export type DeleteResourceResult = { export type DeleteResourceResult = {
deletedResource: Resource; deletedResource: Resource;
@@ -117,10 +115,10 @@ export async function runResourceDeleteSideEffects(
.limit(1); .limit(1);
if (!site) { if (!site) {
throw createHttpError( logger.debug(
HttpCode.NOT_FOUND, `Site with ID ${target.siteId} not found during resource delete side effects; skipping target removal`
`Site with ID ${target.siteId} not found`
); );
continue;
} }
if (site.pubKey && site.type === "newt") { if (site.pubKey && site.type === "newt") {
+82 -3
View File
@@ -1,6 +1,7 @@
import { and, eq, sql } from "drizzle-orm"; import { and, eq, inArray, sql } from "drizzle-orm";
import { import {
db, db,
resources,
siteNetworks, siteNetworks,
siteResources, siteResources,
targets, targets,
@@ -97,6 +98,64 @@ export function exceedsSiteAssociatedResourceDeleteLimit(
return resourceCount > MAX_SITE_ASSOCIATED_RESOURCES_FOR_BULK_DELETE; return resourceCount > MAX_SITE_ASSOCIATED_RESOURCES_FOR_BULK_DELETE;
} }
export async function getPendingResourceIdsForSite(
siteId: number,
trx: Transaction | typeof db = db
): Promise<number[]> {
const resourceIds = await getResourceIdsForSite(siteId, trx);
if (resourceIds.length === 0) {
return [];
}
const rows = await trx
.select({ resourceId: resources.resourceId })
.from(resources)
.where(
and(
inArray(resources.resourceId, resourceIds),
eq(resources.status, "pending")
)
);
return rows.map((row) => row.resourceId);
}
export async function getPendingSiteResourceIdsForSite(
siteId: number,
orgId: string,
trx: Transaction | typeof db = db
): Promise<number[]> {
const siteResourceIds = await getSiteResourceIdsForSite(siteId, orgId, trx);
if (siteResourceIds.length === 0) {
return [];
}
const rows = await trx
.select({ siteResourceId: siteResources.siteResourceId })
.from(siteResources)
.where(
and(
inArray(siteResources.siteResourceId, siteResourceIds),
eq(siteResources.status, "pending")
)
);
return rows.map((row) => row.siteResourceId);
}
export async function getPendingAssociatedResourceCountForSite(
siteId: number,
orgId: string,
trx: Transaction | typeof db = db
): Promise<number> {
const [resourceIds, siteResourceIds] = await Promise.all([
getPendingResourceIdsForSite(siteId, trx),
getPendingSiteResourceIdsForSite(siteId, orgId, trx)
]);
return resourceIds.length + siteResourceIds.length;
}
export async function deleteAssociatedResourcesForSite( export async function deleteAssociatedResourcesForSite(
siteId: number, siteId: number,
orgId: string, orgId: string,
@@ -105,12 +164,32 @@ export async function deleteAssociatedResourcesForSite(
const resourceIds = await getResourceIdsForSite(siteId, trx); const resourceIds = await getResourceIdsForSite(siteId, trx);
const siteResourceIds = await getSiteResourceIdsForSite(siteId, orgId, trx); const siteResourceIds = await getSiteResourceIdsForSite(siteId, orgId, trx);
const [resources, siteResourcesDeleted] = await Promise.all([ const [deletedResources, siteResourcesDeleted] = await Promise.all([
performDeleteResources(resourceIds, trx), performDeleteResources(resourceIds, trx),
performDeleteSiteResources(siteResourceIds, trx) performDeleteSiteResources(siteResourceIds, trx)
]); ]);
return { resources, siteResources: siteResourcesDeleted }; return { resources: deletedResources, siteResources: siteResourcesDeleted };
}
export async function deletePendingAssociatedResourcesForSite(
siteId: number,
orgId: string,
trx: Transaction | typeof db = db
): Promise<DeleteSiteAssociatedResourcesSideEffects> {
const resourceIds = await getPendingResourceIdsForSite(siteId, trx);
const siteResourceIds = await getPendingSiteResourceIdsForSite(
siteId,
orgId,
trx
);
const [deletedResources, siteResourcesDeleted] = await Promise.all([
performDeleteResources(resourceIds, trx),
performDeleteSiteResources(siteResourceIds, trx)
]);
return { resources: deletedResources, siteResources: siteResourcesDeleted };
} }
export async function runDeleteSiteAssociatedResourcesSideEffects( export async function runDeleteSiteAssociatedResourcesSideEffects(
+5 -1
View File
@@ -19,7 +19,11 @@ export async function verifyExitNodeOrgAccess(
export async function listExitNodes( export async function listExitNodes(
orgId: string, orgId: string,
filterOnline = false, filterOnline = false,
noCloud = false noCloud = false,
// Accepted for parity with the enterprise implementation (used there for
// site-label filtering of remote exit nodes). The OSS build has no remote
// exit nodes, so it is unused here.
siteId?: number
) { ) {
// TODO: pick which nodes to send and ping better than just all of them that are not remote // TODO: pick which nodes to send and ping better than just all of them that are not remote
const allExitNodes = await db const allExitNodes = await db
+49 -24
View File
@@ -1,30 +1,55 @@
import { db, exitNodes } from "@server/db"; import { db, exitNodes, Transaction } from "@server/db";
import config from "@server/lib/config"; import config from "@server/lib/config";
import { findNextAvailableCidr } from "@server/lib/ip"; import { findNextAvailableCidr } from "@server/lib/ip";
import { lockManager } from "#dynamic/lib/lock";
export async function getNextAvailableSubnet(): Promise<string> { /**
// Get all existing subnets from routes table * Reserves the next available exit node subnet.
const existingAddresses = await db *
.select({ * Exit node subnets must never overlap with one another - regardless of
address: exitNodes.address * which org(s) they belong to - since HA exit nodes can end up routing for
}) * the same org. This acquires a lock that the caller MUST release (via the
.from(exitNodes); * returned `release`) only after the chosen address has been durably
* persisted (e.g. after the enclosing transaction commits), otherwise
const addresses = existingAddresses.map((a) => a.address); * concurrent callers can race and pick the same subnet.
let subnet = findNextAvailableCidr( */
addresses, export async function getNextAvailableSubnet(
config.getRawConfig().gerbil.block_size, trx: Transaction | typeof db = db
config.getRawConfig().gerbil.subnet_group ): Promise<{ value: string; release: () => Promise<void> }> {
); const lockKey = "exit-node-subnet-allocation";
if (!subnet) { const acquired = await lockManager.acquireLockWithRetry(lockKey, 6000);
throw new Error("No available subnets remaining in space"); if (!acquired) {
throw new Error(`Failed to acquire lock: ${lockKey}`);
} }
const release = () => lockManager.releaseLock(lockKey, acquired);
// replace the last octet with 1 try {
subnet = // Get all existing subnets from routes table
subnet.split(".").slice(0, 3).join(".") + const existingAddresses = await trx
".1" + .select({
"/" + address: exitNodes.address
subnet.split("/")[1]; })
return subnet; .from(exitNodes);
const addresses = existingAddresses.map((a) => a.address);
let subnet = findNextAvailableCidr(
addresses,
config.getRawConfig().gerbil.block_size,
config.getRawConfig().gerbil.subnet_group
);
if (!subnet) {
throw new Error("No available subnets remaining in space");
}
// replace the last octet with 1
subnet =
subnet.split(".").slice(0, 3).join(".") +
".1" +
"/" +
subnet.split("/")[1];
return { value: subnet, release };
} catch (e) {
await release();
throw e;
}
} }
+12 -3
View File
@@ -333,7 +333,7 @@ export async function getNextAvailableClientSubnet(
if (!acquired) { if (!acquired) {
throw new Error(`Failed to acquire lock: ${lockKey}`); throw new Error(`Failed to acquire lock: ${lockKey}`);
} }
const release = () => lockManager.releaseLock(lockKey); const release = () => lockManager.releaseLock(lockKey, acquired);
try { try {
const [org] = await transaction const [org] = await transaction
@@ -395,7 +395,7 @@ export async function getNextAvailableAliasAddress(
if (!acquired) { if (!acquired) {
throw new Error(`Failed to acquire lock: ${lockKey}`); throw new Error(`Failed to acquire lock: ${lockKey}`);
} }
const release = () => lockManager.releaseLock(lockKey); const release = () => lockManager.releaseLock(lockKey, acquired);
try { try {
const [org] = await trx const [org] = await trx
@@ -463,7 +463,7 @@ export async function getNextAvailableOrgSubnet(): Promise<{
if (!acquired) { if (!acquired) {
throw new Error(`Failed to acquire lock: ${lockKey}`); throw new Error(`Failed to acquire lock: ${lockKey}`);
} }
const release = () => lockManager.releaseLock(lockKey); const release = () => lockManager.releaseLock(lockKey, acquired);
try { try {
const existingAddresses = await db const existingAddresses = await db
@@ -496,6 +496,7 @@ export function generateRemoteSubnets(
): string[] { ): string[] {
const remoteSubnets = allSiteResources const remoteSubnets = allSiteResources
.filter((sr) => { .filter((sr) => {
if (!sr.enabled) return false;
if (!sr.destination) return false; if (!sr.destination) return false;
if (sr.mode === "cidr") { if (sr.mode === "cidr") {
@@ -530,6 +531,7 @@ export function generateAliasConfig(allSiteResources: SiteResource[]): Alias[] {
return allSiteResources return allSiteResources
.filter( .filter(
(sr) => (sr) =>
sr.enabled &&
sr.aliasAddress && sr.aliasAddress &&
((sr.alias && (sr.mode == "host" || sr.mode == "ssh")) || ((sr.alias && (sr.mode == "host" || sr.mode == "ssh")) ||
(sr.fullDomain && sr.mode == "http")) (sr.fullDomain && sr.mode == "http"))
@@ -662,6 +664,13 @@ export async function generateSubnetProxyTargetV2(
subnet: string | null; subnet: string | null;
}[] }[]
): Promise<SubnetProxyTargetV2[] | undefined> { ): Promise<SubnetProxyTargetV2[] | undefined> {
if (!siteResource.enabled) {
logger.debug(
`Site resource ${siteResource.siteResourceId} is disabled, skipping target generation.`
);
return;
}
if (clients.length === 0) { if (clients.length === 0) {
logger.debug( logger.debug(
`No clients have access to site resource ${siteResource.siteResourceId}, skipping target generation.` `No clients have access to site resource ${siteResource.siteResourceId}, skipping target generation.`
+41 -31
View File
@@ -1,3 +1,5 @@
import { randomUUID } from "crypto";
const instanceId = `local-${Math.random().toString(36).slice(2)}-${Date.now()}`; const instanceId = `local-${Math.random().toString(36).slice(2)}-${Date.now()}`;
type LocalLockRecord = { type LocalLockRecord = {
@@ -15,58 +17,60 @@ export class LockManager {
} }
} }
private getLocalOwnerToken(): string {
return `${instanceId}:`;
}
/** /**
* Acquire a distributed lock using Redis SET with NX and PX options * Acquire a local in-process lock using an optimistic Map-based check.
* @param lockKey - Unique identifier for the lock * @param lockKey - Unique identifier for the lock
* @param ttlMs - Time to live in milliseconds * @param ttlMs - Time to live in milliseconds
* @returns Promise<boolean> - true if lock acquired, false otherwise * @returns Promise<string | null> - a token identifying this specific acquisition
* (truthy) on success, or null if the lock could not be acquired.
*/ */
async acquireLock( async acquireLock(
lockKey: string, lockKey: string,
ttlMs: number = 30000, ttlMs: number = 30000,
maxRetries: number = 3, maxRetries: number = 3,
retryDelayMs: number = 100 retryDelayMs: number = 100
): Promise<boolean> { ): Promise<string | null> {
for (let attempt = 0; attempt < maxRetries; attempt++) { for (let attempt = 0; attempt < maxRetries; attempt++) {
this.clearExpiredLocalLock(lockKey); this.clearExpiredLocalLock(lockKey);
const existing = localLocks.get(lockKey); const existing = localLocks.get(lockKey);
if (!existing) { if (!existing) {
const token = `${instanceId}:${randomUUID()}`;
localLocks.set(lockKey, { localLocks.set(lockKey, {
owner: this.getLocalOwnerToken(), owner: token,
expiresAt: Date.now() + ttlMs expiresAt: Date.now() + ttlMs
}); });
return true; return token;
}
if (existing.owner === this.getLocalOwnerToken()) {
existing.expiresAt = Date.now() + ttlMs;
localLocks.set(lockKey, existing);
return true;
} }
// The lock is currently held -- possibly by a different, unrelated
// caller in this same process. We intentionally do NOT treat
// same-process holders as automatically reentrant here: two
// independent logical operations (e.g. two different API requests)
// running concurrently in the same process must not both believe
// they hold the lock, or their writes under it can interleave
// unguarded. Just retry with backoff like any other contended lock.
if (attempt < maxRetries - 1) { if (attempt < maxRetries - 1) {
const delay = retryDelayMs * Math.pow(2, attempt); const delay = retryDelayMs * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay)); await new Promise((resolve) => setTimeout(resolve, delay));
} }
} }
return false; return null;
} }
/** /**
* Release a lock using Lua script to ensure atomicity * Release a lock previously acquired via acquireLock/acquireLockWithRetry.
* @param lockKey - Unique identifier for the lock * @param lockKey - Unique identifier for the lock
* @param token - the exact token returned by the acquisition being released.
* Required so a caller whose TTL already expired can't delete a
* different, currently-active holder's lock.
*/ */
async releaseLock(lockKey: string): Promise<void> { async releaseLock(lockKey: string, token: string): Promise<void> {
this.clearExpiredLocalLock(lockKey); this.clearExpiredLocalLock(lockKey);
const existing = localLocks.get(lockKey); const existing = localLocks.get(lockKey);
if (existing && existing.owner === this.getLocalOwnerToken()) { if (existing && existing.owner === token) {
localLocks.delete(lockKey); localLocks.delete(lockKey);
} }
} }
@@ -100,23 +104,29 @@ export class LockManager {
const ttl = Math.max(0, existing.expiresAt - Date.now()); const ttl = Math.max(0, existing.expiresAt - Date.now());
return { return {
exists: true, exists: true,
ownedByMe: existing.owner === this.getLocalOwnerToken(), ownedByMe: existing.owner.startsWith(`${instanceId}:`),
ttl, ttl,
owner: existing.owner.split(":")[0] owner: existing.owner.split(":")[0]
}; };
} }
/** /**
* Extend the TTL of an existing lock owned by this worker * Extend the TTL of an existing lock, provided the token matches the
* acquisition currently holding it.
* @param lockKey - Unique identifier for the lock * @param lockKey - Unique identifier for the lock
* @param ttlMs - New TTL in milliseconds * @param ttlMs - New TTL in milliseconds
* @param token - the token returned by the acquisition being extended
* @returns Promise<boolean> - true if extended successfully * @returns Promise<boolean> - true if extended successfully
*/ */
async extendLock(lockKey: string, ttlMs: number): Promise<boolean> { async extendLock(
lockKey: string,
ttlMs: number,
token: string
): Promise<boolean> {
this.clearExpiredLocalLock(lockKey); this.clearExpiredLocalLock(lockKey);
const existing = localLocks.get(lockKey); const existing = localLocks.get(lockKey);
if (!existing || existing.owner !== this.getLocalOwnerToken()) { if (!existing || existing.owner !== token) {
return false; return false;
} }
@@ -131,14 +141,14 @@ export class LockManager {
* @param ttlMs - Time to live in milliseconds * @param ttlMs - Time to live in milliseconds
* @param maxRetries - Maximum number of retry attempts * @param maxRetries - Maximum number of retry attempts
* @param baseDelayMs - Base delay between retries in milliseconds * @param baseDelayMs - Base delay between retries in milliseconds
* @returns Promise<boolean> - true if lock acquired * @returns Promise<string | null> - token if acquired, null otherwise
*/ */
async acquireLockWithRetry( async acquireLockWithRetry(
lockKey: string, lockKey: string,
ttlMs: number = 30000, ttlMs: number = 30000,
maxRetries: number = 5, maxRetries: number = 5,
baseDelayMs: number = 100 baseDelayMs: number = 100
): Promise<boolean> { ): Promise<string | null> {
for (let attempt = 0; attempt <= maxRetries; attempt++) { for (let attempt = 0; attempt <= maxRetries; attempt++) {
const acquired = await this.acquireLock( const acquired = await this.acquireLock(
lockKey, lockKey,
@@ -148,7 +158,7 @@ export class LockManager {
); );
if (acquired) { if (acquired) {
return true; return acquired;
} }
if (attempt < maxRetries) { if (attempt < maxRetries) {
@@ -158,7 +168,7 @@ export class LockManager {
} }
} }
return false; return null;
} }
/** /**
@@ -173,16 +183,16 @@ export class LockManager {
fn: () => Promise<T>, fn: () => Promise<T>,
ttlMs: number = 30000 ttlMs: number = 30000
): Promise<T> { ): Promise<T> {
const acquired = await this.acquireLock(lockKey, ttlMs); const token = await this.acquireLock(lockKey, ttlMs);
if (!acquired) { if (!token) {
throw new Error(`Failed to acquire lock: ${lockKey}`); throw new Error(`Failed to acquire lock: ${lockKey}`);
} }
try { try {
return await fn(); return await fn();
} finally { } finally {
await this.releaseLock(lockKey); await this.releaseLock(lockKey, token);
} }
} }
@@ -204,7 +214,7 @@ export class LockManager {
let locksOwnedByMe = 0; let locksOwnedByMe = 0;
for (const value of localLocks.values()) { for (const value of localLocks.values()) {
if (value.owner === this.getLocalOwnerToken()) { if (value.owner.startsWith(`${instanceId}:`)) {
locksOwnedByMe++; locksOwnedByMe++;
} }
} }
+24
View File
@@ -0,0 +1,24 @@
export const ORG_REBUILD_CONCURRENCY_LIMIT = 10;
const orgActiveRebuilds = new Map<string, number>();
export async function incrementOrgRebuildCount(orgId: string): Promise<void> {
orgActiveRebuilds.set(orgId, (orgActiveRebuilds.get(orgId) ?? 0) + 1);
}
export async function decrementOrgRebuildCount(orgId: string): Promise<void> {
const current = orgActiveRebuilds.get(orgId) ?? 0;
if (current <= 1) {
orgActiveRebuilds.delete(orgId);
} else {
orgActiveRebuilds.set(orgId, current - 1);
}
}
export async function getOrgActiveRebuildCount(orgId: string): Promise<number> {
return orgActiveRebuilds.get(orgId) ?? 0;
}
export async function checkOrgRebuildRateLimit(orgId: string): Promise<boolean> {
return (orgActiveRebuilds.get(orgId) ?? 0) >= ORG_REBUILD_CONCURRENCY_LIMIT;
}
+2 -1
View File
@@ -184,7 +184,8 @@ export const configSchema = z
.number() .number()
.positive() .positive()
.optional() .optional()
.default(5000) .default(5000),
jit_mode: z.boolean().default(true)
}) })
.optional() .optional()
.prefault({}) .prefault({})
+250 -144
View File
@@ -45,11 +45,24 @@ import {
} from "@server/routers/client/targets"; } from "@server/routers/client/targets";
import { lockManager } from "#dynamic/lib/lock"; import { lockManager } from "#dynamic/lib/lock";
import { rebuildQueue } from "#dynamic/lib/rebuildQueue"; import { rebuildQueue } from "#dynamic/lib/rebuildQueue";
import { withRetry, isTransientError } from "@server/lib/dbRetry";
import {
checkOrgRebuildRateLimit,
decrementOrgRebuildCount,
incrementOrgRebuildCount,
ORG_REBUILD_CONCURRENCY_LIMIT
} from "#dynamic/lib/orgRebuildCounter";
export { ORG_REBUILD_CONCURRENCY_LIMIT };
// TTL for rebuild-association locks. These functions can fan out into many // TTL for rebuild-association locks. These functions can fan out into many
// peer/proxy updates, so give them a generous window. // peer/proxy updates, so give them a generous window.
const REBUILD_ASSOCIATIONS_LOCK_TTL_MS = 120000; const REBUILD_ASSOCIATIONS_LOCK_TTL_MS = 120000;
export async function isOrgRebuildRateLimited(orgId: string): Promise<boolean> {
return checkOrgRebuildRateLimit(orgId);
}
const REBUILD_IDLE_POLL_INTERVAL_MS = 300; const REBUILD_IDLE_POLL_INTERVAL_MS = 300;
const REBUILD_IDLE_DEFAULT_TIMEOUT_MS = 130_000; // slightly longer than lock TTL const REBUILD_IDLE_DEFAULT_TIMEOUT_MS = 130_000; // slightly longer than lock TTL
const REBUILD_IDLE_HANDLER_TIMEOUT_MS = 5_000; const REBUILD_IDLE_HANDLER_TIMEOUT_MS = 5_000;
@@ -271,11 +284,22 @@ export async function getClientSiteResourceAccess(
export async function rebuildClientAssociationsFromSiteResource( export async function rebuildClientAssociationsFromSiteResource(
siteResource: SiteResource siteResource: SiteResource
) { ) {
await incrementOrgRebuildCount(siteResource.orgId);
try { try {
return await lockManager.withLock( // The whole locked rebuild is idempotent (it diffs full expected vs.
`rebuild-client-associations:site-resource:${siteResource.siteResourceId}`, // actual state each time), so on a transient DB error it's safe to
() => rebuildClientAssociationsFromSiteResourceImpl(siteResource), // retry the entire thing rather than just the failed query.
REBUILD_ASSOCIATIONS_LOCK_TTL_MS return await withRetry(
() =>
lockManager.withLock(
`rebuild-client-associations:site-resource:${siteResource.siteResourceId}`,
() =>
rebuildClientAssociationsFromSiteResourceImpl(
siteResource
),
REBUILD_ASSOCIATIONS_LOCK_TTL_MS
),
`rebuildClientAssociationsFromSiteResource:${siteResource.siteResourceId}`
); );
} catch (err: any) { } catch (err: any) {
if ( if (
@@ -291,7 +315,20 @@ export async function rebuildClientAssociationsFromSiteResource(
}); });
return { mergedAllClients: [] }; return { mergedAllClients: [] };
} }
if (isTransientError(err)) {
logger.warn(
`rebuildClientAssociations: transient DB error rebuilding site resource ${siteResource.siteResourceId} persisted after retries, queuing for deferred processing:`,
err
);
await rebuildQueue.enqueue({
type: "site-resource",
id: siteResource.siteResourceId
});
return { mergedAllClients: [] };
}
throw err; throw err;
} finally {
await decrementOrgRebuildCount(siteResource.orgId);
} }
} }
@@ -448,6 +485,7 @@ async function rebuildClientAssociationsFromSiteResourceImpl(
await trx await trx
.insert(clientSiteResourcesAssociationsCache) .insert(clientSiteResourcesAssociationsCache)
.values(clientSiteResourcesToInsert) .values(clientSiteResourcesToInsert)
.onConflictDoNothing()
.returning(); .returning();
logger.debug( logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteResourceId=${siteResource.siteResourceId} inserted clientSiteResource associations` `rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteResourceId=${siteResource.siteResourceId} inserted clientSiteResource associations`
@@ -495,121 +533,148 @@ async function rebuildClientAssociationsFromSiteResourceImpl(
for (const site of sitesToProcess) { for (const site of sitesToProcess) {
const siteId = site.siteId; const siteId = site.siteId;
logger.debug( try {
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] processing siteId=${siteId} for siteResourceId=${siteResource.siteResourceId}` logger.debug(
); `rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] processing siteId=${siteId} for siteResourceId=${siteResource.siteResourceId}`
);
const existingClientSites = await trx const existingClientSites = await trx
.select({ .select({
clientId: clientSitesAssociationsCache.clientId clientId: clientSitesAssociationsCache.clientId
}) })
.from(clientSitesAssociationsCache) .from(clientSitesAssociationsCache)
.where(eq(clientSitesAssociationsCache.siteId, siteId)); .where(eq(clientSitesAssociationsCache.siteId, siteId));
const existingClientSiteIds = existingClientSites.map( const existingClientSiteIds = existingClientSites.map(
(row) => row.clientId (row) => row.clientId
); );
logger.debug( logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} existingClientSiteIds=[${existingClientSiteIds.join(", ")}]` `rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} existingClientSiteIds=[${existingClientSiteIds.join(", ")}]`
); );
// Get full client details for existing clients (needed for sending delete messages) // Get full client details for existing clients (needed for sending delete messages)
const existingClients = const existingClients =
existingClientSiteIds.length > 0 existingClientSiteIds.length > 0
? await trx ? await trx
.select({ .select({
clientId: clients.clientId, clientId: clients.clientId,
pubKey: clients.pubKey, pubKey: clients.pubKey,
subnet: clients.subnet subnet: clients.subnet
}) })
.from(clients) .from(clients)
.where(inArray(clients.clientId, existingClientSiteIds)) .where(
inArray(clients.clientId, existingClientSiteIds)
)
: [];
const otherResourceClientIds =
clientsFromOtherResourcesBySite.get(siteId) ??
new Set<number>();
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} otherResourceClientIds=[${[...otherResourceClientIds].join(", ")}] mergedAllClientIds=[${mergedAllClientIds.join(", ")}]`
);
// Expected clients from this resource are site-scoped: if this site is
// no longer attached to the resource, the expected set is empty.
const expectedClientIdsForSite = currentSiteIdSet.has(siteId)
? mergedAllClientIds
: []; : [];
const otherResourceClientIds = // Note: we deliberately do NOT exclude clients covered by another
clientsFromOtherResourcesBySite.get(siteId) ?? new Set<number>(); // site resource here (unlike clientSitesToRemove below). Doing so
// previously caused a permanent gap: if resource A saw resource B's
logger.debug( // cache row and skipped adding (assuming B would maintain it), and
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} otherResourceClientIds=[${[...otherResourceClientIds].join(", ")}] mergedAllClientIds=[${mergedAllClientIds.join(", ")}]` // B's own rebuild made the same assumption about A, the site-level
); // row could end up never inserted by anyone even though both
// resources' client associations were otherwise correct.
// Expected clients from this resource are site-scoped: if this site is // onConflictDoNothing makes a redundant insert harmless, so there's
// no longer attached to the resource, the expected set is empty. // no correctness reason to skip here.
const expectedClientIdsForSite = currentSiteIdSet.has(siteId) const clientSitesToAdd = expectedClientIdsForSite.filter(
? mergedAllClientIds (clientId) => !existingClientSiteIds.includes(clientId)
: [];
const clientSitesToAdd = expectedClientIdsForSite.filter(
(clientId) =>
!existingClientSiteIds.includes(clientId) &&
!otherResourceClientIds.has(clientId) // dont add if already connected via another site resource
);
const clientSitesToInsert = clientSitesToAdd.map((clientId) => ({
clientId,
siteId
}));
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} clientSites toAdd=[${clientSitesToAdd.join(", ")}]`
);
if (clientSitesToInsert.length > 0) {
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} inserting ${clientSitesToInsert.length} clientSite association(s)`
); );
await trx
.insert(clientSitesAssociationsCache)
.values(clientSitesToInsert)
.returning();
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} inserted clientSite associations`
);
} else {
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} no clientSite associations to insert`
);
}
// Now remove any client-site associations that should no longer exist const clientSitesToInsert = clientSitesToAdd.map((clientId) => ({
const clientSitesToRemove = existingClientSiteIds.filter( clientId,
(clientId) => siteId
!expectedClientIdsForSite.includes(clientId) && }));
!otherResourceClientIds.has(clientId) // dont remove if there is still another connection for another site resource
);
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} clientSites toRemove=[${clientSitesToRemove.join(", ")}]`
);
if (clientSitesToRemove.length > 0) {
logger.debug( logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} deleting ${clientSitesToRemove.length} clientSite association(s)` `rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} clientSites toAdd=[${clientSitesToAdd.join(", ")}]`
); );
await trx
.delete(clientSitesAssociationsCache) if (clientSitesToInsert.length > 0) {
.where( logger.debug(
and( `rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} inserting ${clientSitesToInsert.length} clientSite association(s)`
eq(clientSitesAssociationsCache.siteId, siteId),
inArray(
clientSitesAssociationsCache.clientId,
clientSitesToRemove
)
)
); );
} await trx
.insert(clientSitesAssociationsCache)
.values(clientSitesToInsert)
.onConflictDoNothing()
.returning();
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} inserted clientSite associations`
);
} else {
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} no clientSite associations to insert`
);
}
// Now handle the messages to add/remove peers on both the newt and olm sides // Now remove any client-site associations that should no longer exist
await handleMessagesForSiteClients( const clientSitesToRemove = existingClientSiteIds.filter(
site, (clientId) =>
siteId, !expectedClientIdsForSite.includes(clientId) &&
mergedAllClients, !otherResourceClientIds.has(clientId) // dont remove if there is still another connection for another site resource
existingClients, );
clientSitesToAdd,
clientSitesToRemove, logger.debug(
trx `rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} clientSites toRemove=[${clientSitesToRemove.join(", ")}]`
); );
if (clientSitesToRemove.length > 0) {
logger.debug(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} deleting ${clientSitesToRemove.length} clientSite association(s)`
);
await trx
.delete(clientSitesAssociationsCache)
.where(
and(
eq(clientSitesAssociationsCache.siteId, siteId),
inArray(
clientSitesAssociationsCache.clientId,
clientSitesToRemove
)
)
);
}
// Now handle the messages to add/remove peers on both the newt and olm sides
await handleMessagesForSiteClients(
site,
siteId,
mergedAllClients,
existingClients,
clientSitesToAdd,
clientSitesToRemove,
trx
);
} catch (err) {
// Don't let a failure on one site abort processing of every
// other site queued after it in this run. Since we're not
// re-throwing, the outer wrapper's retry/requeue logic never
// sees this failure, so explicitly queue this resource for a
// follow-up pass to reconcile whatever this site didn't get to.
logger.error(
`rebuildClientAssociations: [rebuildClientAssociationsFromSiteResource] siteId=${siteId} failed while processing site for siteResourceId=${siteResource.siteResourceId}, continuing with remaining sites and queuing a follow-up pass:`,
err
);
await rebuildQueue.enqueue({
type: "site-resource",
id: siteResource.siteResourceId
});
}
} }
// Handle subnet proxy target updates for the resource associations // Handle subnet proxy target updates for the resource associations
@@ -642,7 +707,7 @@ async function handleMessagesForSiteClients(
trx: Transaction | typeof db = db trx: Transaction | typeof db = db
): Promise<void> { ): Promise<void> {
if (!site.exitNodeId) { if (!site.exitNodeId) {
logger.warn( logger.debug(
`Exit node ID not on site ${site.siteId} so there is no reason to update clients because it must be offline` `Exit node ID not on site ${site.siteId} so there is no reason to update clients because it must be offline`
); );
return; return;
@@ -656,14 +721,14 @@ async function handleMessagesForSiteClients(
.limit(1); .limit(1);
if (!exitNode) { if (!exitNode) {
logger.warn( logger.debug(
`Exit node not found for site ${site.siteId} so there is no reason to update clients because it must be offline` `Exit node not found for site ${site.siteId} so there is no reason to update clients because it must be offline`
); );
return; return;
} }
if (!site.publicKey) { if (!site.publicKey) {
logger.warn( logger.debug(
`Site publicKey not set for site ${site.siteId} so cannot add peers to clients` `Site publicKey not set for site ${site.siteId} so cannot add peers to clients`
); );
return; return;
@@ -677,7 +742,7 @@ async function handleMessagesForSiteClients(
.where(eq(newts.siteId, siteId)) .where(eq(newts.siteId, siteId))
.limit(1); .limit(1);
if (!newt) { if (!newt) {
logger.warn( logger.debug(
`Newt not found for site ${siteId} so cannot add peers to clients` `Newt not found for site ${siteId} so cannot add peers to clients`
); );
return; return;
@@ -902,7 +967,7 @@ export async function updateClientSiteDestinations(
for (const site of sitesData) { for (const site of sitesData) {
if (!site.sites.subnet) { if (!site.sites.subnet) {
logger.warn(`Site ${site.sites.siteId} has no subnet, skipping`); logger.debug(`Site ${site.sites.siteId} has no subnet, skipping`);
continue; continue;
} }
@@ -1496,9 +1561,19 @@ export async function handleMessagingForUpdatedSiteResource(
updatedSiteResource.udpPortRangeString || updatedSiteResource.udpPortRangeString ||
existingSiteResource.disableIcmp !== existingSiteResource.disableIcmp !==
updatedSiteResource.disableIcmp); updatedSiteResource.disableIcmp);
// Toggling enabled on/off doesn't change any of the fields above, but it
// does change whether targets/peer data should exist at all, so it needs
// to drive the same old->new diff machinery: going enabled->disabled
// diffs "real data" against "nothing" (a remove), and disabled->enabled
// diffs "nothing" against "real data" (an add). generateSubnetProxyTargetV2/
// generateRemoteSubnets/generateAliasConfig already return nothing for a
// disabled resource, so no other changes are needed here.
const enabledChanged =
existingSiteResource &&
existingSiteResource.enabled !== updatedSiteResource.enabled;
logger.debug( logger.debug(
`handleMessagingForUpdatedSiteResource: change flags destinationChanged=${Boolean(destinationChanged)} destinationPortChanged=${Boolean(destinationPortChanged)} aliasChanged=${Boolean(aliasChanged)} fullDomainChanged=${Boolean(fullDomainChanged)} sslChanged=${Boolean(sslChanged)} portRangesChanged=${Boolean(portRangesChanged)}` `handleMessagingForUpdatedSiteResource: change flags destinationChanged=${Boolean(destinationChanged)} destinationPortChanged=${Boolean(destinationPortChanged)} aliasChanged=${Boolean(aliasChanged)} fullDomainChanged=${Boolean(fullDomainChanged)} sslChanged=${Boolean(sslChanged)} portRangesChanged=${Boolean(portRangesChanged)} enabledChanged=${Boolean(enabledChanged)}`
); );
// if the existingSiteResource is undefined (new resource) we don't need to do anything here, the rebuild above handled it all // if the existingSiteResource is undefined (new resource) we don't need to do anything here, the rebuild above handled it all
@@ -1509,14 +1584,16 @@ export async function handleMessagingForUpdatedSiteResource(
fullDomainChanged || fullDomainChanged ||
sslChanged || sslChanged ||
portRangesChanged || portRangesChanged ||
destinationPortChanged destinationPortChanged ||
enabledChanged
) { ) {
const shouldUpdateTargets = const shouldUpdateTargets =
destinationChanged || destinationChanged ||
sslChanged || sslChanged ||
portRangesChanged || portRangesChanged ||
fullDomainChanged || fullDomainChanged ||
destinationPortChanged; destinationPortChanged ||
enabledChanged;
logger.debug( logger.debug(
`handleMessagingForUpdatedSiteResource: entering unchanged-site update path shouldUpdateTargets=${shouldUpdateTargets}` `handleMessagingForUpdatedSiteResource: entering unchanged-site update path shouldUpdateTargets=${shouldUpdateTargets}`
@@ -1592,20 +1669,22 @@ export async function handleMessagingForUpdatedSiteResource(
peerDataUpdateBatch.push({ peerDataUpdateBatch.push({
clientId: client.clientId, clientId: client.clientId,
siteId, siteId,
remoteSubnets: destinationChanged remoteSubnets:
? { destinationChanged || enabledChanged
oldRemoteSubnets: !oldDestinationStillInUseBySite ? {
? generateRemoteSubnets([ oldRemoteSubnets:
existingSiteResource !oldDestinationStillInUseBySite
]) ? generateRemoteSubnets([
: [], existingSiteResource
newRemoteSubnets: generateRemoteSubnets([ ])
updatedSiteResource : [],
]) newRemoteSubnets: generateRemoteSubnets([
} updatedSiteResource
: undefined, ])
}
: undefined,
aliases: aliases:
aliasChanged || fullDomainChanged // the full domain is sent down as an alias aliasChanged || fullDomainChanged || enabledChanged // the full domain is sent down as an alias
? { ? {
oldAliases: generateAliasConfig([ oldAliases: generateAliasConfig([
existingSiteResource existingSiteResource
@@ -1638,12 +1717,20 @@ export async function handleMessagingForUpdatedSiteResource(
export async function rebuildClientAssociationsFromClient( export async function rebuildClientAssociationsFromClient(
client: Client client: Client
): Promise<void> { ): Promise<void> {
const trx = primaryDb; await incrementOrgRebuildCount(client.orgId);
try { try {
return await lockManager.withLock( const trx = primaryDb;
`rebuild-client-associations:client:${client.clientId}`, // The whole locked rebuild is idempotent (it diffs full expected vs.
() => rebuildClientAssociationsFromClientImpl(client, trx), // actual state each time), so on a transient DB error it's safe to
REBUILD_ASSOCIATIONS_LOCK_TTL_MS // retry the entire thing rather than just the failed query.
return await withRetry(
() =>
lockManager.withLock(
`rebuild-client-associations:client:${client.clientId}`,
() => rebuildClientAssociationsFromClientImpl(client, trx),
REBUILD_ASSOCIATIONS_LOCK_TTL_MS
),
`rebuildClientAssociationsFromClient:${client.clientId}`
); );
} catch (err: any) { } catch (err: any) {
if ( if (
@@ -1659,7 +1746,20 @@ export async function rebuildClientAssociationsFromClient(
}); });
return; return;
} }
if (isTransientError(err)) {
logger.warn(
`rebuildClientAssociations: transient DB error rebuilding client ${client.clientId} persisted after retries, queuing for deferred processing:`,
err
);
await rebuildQueue.enqueue({
type: "client",
id: client.clientId
});
return;
}
throw err; throw err;
} finally {
await decrementOrgRebuildCount(client.orgId);
} }
} }
@@ -1808,12 +1908,15 @@ async function rebuildClientAssociationsFromClientImpl(
// Insert new associations // Insert new associations
if (resourcesToAdd.length > 0) { if (resourcesToAdd.length > 0) {
await trx.insert(clientSiteResourcesAssociationsCache).values( await trx
resourcesToAdd.map((siteResourceId) => ({ .insert(clientSiteResourcesAssociationsCache)
clientId: client.clientId, .values(
siteResourceId resourcesToAdd.map((siteResourceId) => ({
})) clientId: client.clientId,
); siteResourceId
}))
)
.onConflictDoNothing();
} }
// Remove old associations // Remove old associations
@@ -1851,12 +1954,15 @@ async function rebuildClientAssociationsFromClientImpl(
// Insert new site associations // Insert new site associations
if (sitesToAdd.length > 0) { if (sitesToAdd.length > 0) {
await trx.insert(clientSitesAssociationsCache).values( await trx
sitesToAdd.map((siteId) => ({ .insert(clientSitesAssociationsCache)
clientId: client.clientId, .values(
siteId sitesToAdd.map((siteId) => ({
})) clientId: client.clientId,
); siteId
}))
)
.onConflictDoNothing();
} }
// Remove old site associations // Remove old site associations
+127 -6
View File
@@ -1,8 +1,14 @@
import logger from "@server/logger";
import { isTransientError } from "@server/lib/dbRetry";
export type RebuildJobType = "site-resource" | "client"; export type RebuildJobType = "site-resource" | "client";
export interface RebuildJob { export interface RebuildJob {
type: RebuildJobType; type: RebuildJobType;
id: number; id: number;
// Number of times this job has already been re-queued after a transient
// failure. Absent/0 means it has not failed yet.
attempt?: number;
} }
export interface RebuildJobHandlers { export interface RebuildJobHandlers {
@@ -16,12 +22,127 @@ export interface RebuildQueueManager {
isQueued(job: RebuildJob): Promise<boolean>; isQueued(job: RebuildJob): Promise<boolean>;
} }
class NoopRebuildQueue implements RebuildQueueManager { // In-process FIFO used when there is no Redis to back a distributed queue
async enqueue(_job: RebuildJob): Promise<void> {} // (OSS build, or Redis unavailable). A job that loses the per-resource
startProcessing(_handlers: RebuildJobHandlers): void {} // rebuild lock race lands here instead of being silently dropped, and gets
async isQueued(_job: RebuildJob): Promise<boolean> { // retried shortly after against fresh DB state.
return false; const POLL_INTERVAL_MS = 500;
const BATCH_SIZE = 5;
// A job that fails with a transient DB error gets re-queued with backoff
// instead of being dropped, up to this many times.
const MAX_JOB_ATTEMPTS = 5;
const JOB_RETRY_BASE_DELAY_MS = 1000;
function dedupeKey(job: RebuildJob): string {
return `${job.type}:${job.id}`;
}
class InMemoryRebuildQueue implements RebuildQueueManager {
private queue: RebuildJob[] = [];
private queuedSet = new Set<string>();
private processing = false;
private processingStarted = false;
private handlers: RebuildJobHandlers | null = null;
async isQueued(job: RebuildJob): Promise<boolean> {
return this.queuedSet.has(dedupeKey(job));
}
async enqueue(job: RebuildJob): Promise<void> {
const key = dedupeKey(job);
if (this.queuedSet.has(key)) {
logger.debug(
`Rebuild queue: skipped duplicate queued job ${job.type}:${job.id}`
);
return;
}
this.queuedSet.add(key);
this.queue.push(job);
logger.debug(
`Rebuild queue: enqueued ${job.type}:${job.id} (queue position: tail)`
);
}
startProcessing(handlers: RebuildJobHandlers): void {
if (this.processingStarted) return;
this.processingStarted = true;
this.handlers = handlers;
setInterval(() => {
this.tryProcessBatch().catch((err) => {
logger.error(
"Rebuild queue: unhandled error in process loop:",
err
);
});
}, POLL_INTERVAL_MS);
logger.info("Rebuild queue processor started (in-memory)");
}
private async tryProcessBatch(): Promise<void> {
if (this.processing || !this.handlers || this.queue.length === 0) {
return;
}
this.processing = true;
try {
for (let i = 0; i < BATCH_SIZE; i++) {
const job = this.queue.shift();
if (!job) break; // queue drained
// Remove from the dedupe set once dequeued so the same job
// can be re-queued while this one is in progress.
this.queuedSet.delete(dedupeKey(job));
logger.debug(
`Rebuild queue: processing ${job.type}:${job.id}`
);
try {
if (job.type === "site-resource") {
await this.handlers.onSiteResource(job.id);
} else if (job.type === "client") {
await this.handlers.onClient(job.id);
} else {
logger.warn(
`Rebuild queue: unknown job type "${(job as any).type}", discarding`
);
}
logger.debug(
`Rebuild queue: completed ${job.type}:${job.id}`
);
} catch (err) {
const attempt = (job.attempt ?? 0) + 1;
if (isTransientError(err) && attempt <= MAX_JOB_ATTEMPTS) {
const delay =
JOB_RETRY_BASE_DELAY_MS * Math.pow(2, attempt - 1);
logger.warn(
`Rebuild queue: job ${job.type}:${job.id} hit a transient error (attempt ${attempt}/${MAX_JOB_ATTEMPTS}), re-queuing in ${delay}ms:`,
err
);
setTimeout(() => {
this.enqueue({ ...job, attempt }).catch(
(enqueueErr) =>
logger.error(
`Rebuild queue: failed to re-queue ${job.type}:${job.id} after transient error:`,
enqueueErr
)
);
}, delay);
} else {
logger.error(
`Rebuild queue: job ${job.type}:${job.id} threw an error:`,
err
);
}
}
}
} finally {
this.processing = false;
}
} }
} }
export const rebuildQueue: RebuildQueueManager = new NoopRebuildQueue(); export const rebuildQueue: RebuildQueueManager = new InMemoryRebuildQueue();
+49 -18
View File
@@ -8,26 +8,42 @@ const STATUS_HISTORY_CACHE_TTL = 60; // seconds
function statusHistoryCacheKey( function statusHistoryCacheKey(
entityType: string, entityType: string,
entityId: number, entityId: number,
days: number days: number,
tzOffsetMinutes: number
): string { ): string {
return `statusHistory:${entityType}:${entityId}:${days}`; return `statusHistory:${entityType}:${entityId}:${days}:${tzOffsetMinutes}`;
}
// Returns the epoch seconds of the most recent local-calendar-day midnight,
// where "local" is defined by tzOffsetMinutes (minutes to ADD to UTC to get
// local time, e.g. Australia/Sydney standard time is 600). Defaults to 0
// (UTC) so callers that don't pass a timezone keep the original behavior.
function localMidnightSec(tzOffsetMinutes: number): number {
const localNow = new Date(Date.now() + tzOffsetMinutes * 60_000);
localNow.setUTCHours(0, 0, 0, 0);
return Math.floor(localNow.getTime() / 1000) - tzOffsetMinutes * 60;
} }
export async function getCachedStatusHistory( export async function getCachedStatusHistory(
entityType: string, entityType: string,
entityId: number, entityId: number,
days: number days: number,
tzOffsetMinutes: number = 0
): Promise<StatusHistoryResponse> { ): Promise<StatusHistoryResponse> {
const cacheKey = statusHistoryCacheKey(entityType, entityId, days); const cacheKey = statusHistoryCacheKey(
entityType,
entityId,
days,
tzOffsetMinutes
);
const cached = await cache.get<StatusHistoryResponse>(cacheKey); const cached = await cache.get<StatusHistoryResponse>(cacheKey);
if (cached !== undefined) { if (cached !== undefined) {
return cached; return cached;
} }
// Anchor to UTC midnight so the query window aligns with stable calendar days // Anchor to local midnight (UTC when tzOffsetMinutes is 0) so the query
const utcToday = new Date(); // window aligns with stable calendar days for the requesting client
utcToday.setUTCHours(0, 0, 0, 0); const todayMidnightSec = localMidnightSec(tzOffsetMinutes);
const todayMidnightSec = Math.floor(utcToday.getTime() / 1000);
const startSec = todayMidnightSec - days * 86400; const startSec = todayMidnightSec - days * 86400;
const events = await logsDb const events = await logsDb
@@ -63,7 +79,8 @@ export async function getCachedStatusHistory(
const { buckets, totalDowntime } = computeBuckets( const { buckets, totalDowntime } = computeBuckets(
events, events,
days, days,
priorStatus priorStatus,
tzOffsetMinutes
); );
const totalWindow = days * 86400; const totalWindow = days * 86400;
const overallUptime = const overallUptime =
@@ -99,11 +116,19 @@ export const statusHistoryQuerySchema = z
days: z days: z
.string() .string()
.optional() .optional()
.transform((v) => (v ? parseInt(v, 10) : 90)) .transform((v) => (v ? parseInt(v, 10) : 90)),
// Minutes to add to UTC to get the requesting client's local time
// (e.g. Australia/Sydney standard time is 600). Optional and
// defaults to 0 (UTC) so older clients keep the prior behavior.
tzOffsetMinutes: z
.string()
.optional()
.transform((v) => (v ? parseInt(v, 10) : 0))
}) })
.pipe( .pipe(
z.object({ z.object({
days: z.number().int().min(1).max(365) days: z.number().int().min(1).max(365),
tzOffsetMinutes: z.number().int().min(-720).max(840)
}) })
); );
@@ -133,15 +158,15 @@ export function computeBuckets(
id: number; id: number;
}[], }[],
days: number, days: number,
priorStatus: string | null = null priorStatus: string | null = null,
tzOffsetMinutes: number = 0
): { buckets: StatusHistoryDayBucket[]; totalDowntime: number } { ): { buckets: StatusHistoryDayBucket[]; totalDowntime: number } {
const nowSec = Math.floor(Date.now() / 1000); const nowSec = Math.floor(Date.now() / 1000);
// Anchor bucket boundaries to UTC midnight so dates are stable calendar days // Anchor bucket boundaries to local midnight (UTC when tzOffsetMinutes is
// and don't drift as the cache expires and is recomputed // 0) so dates are stable calendar days for the requesting client and
const utcToday = new Date(); // don't drift as the cache expires and is recomputed
utcToday.setUTCHours(0, 0, 0, 0); const todayMidnightSec = localMidnightSec(tzOffsetMinutes);
const todayMidnightSec = Math.floor(utcToday.getTime() / 1000);
const buckets: StatusHistoryDayBucket[] = []; const buckets: StatusHistoryDayBucket[] = [];
let totalDowntime = 0; let totalDowntime = 0;
@@ -237,7 +262,13 @@ export function computeBuckets(
) )
: 100; : 100;
const dateStr = new Date(dayStartSec * 1000).toISOString().slice(0, 10); // Shift by the client's offset before formatting so the label reflects
// their local calendar date rather than the UTC date of dayStartSec
const dateStr = new Date(
(dayStartSec + tzOffsetMinutes * 60) * 1000
)
.toISOString()
.slice(0, 10);
const hasAnyData = currentStatus !== null || dayEvents.length > 0; const hasAnyData = currentStatus !== null || dayEvents.length > 0;
+13 -3
View File
@@ -2,6 +2,7 @@ import {
db, db,
Org, Org,
orgs, orgs,
resourceAccessToken,
resources, resources,
siteResources, siteResources,
sites, sites,
@@ -14,7 +15,7 @@ import {
} from "@server/db"; } from "@server/db";
import { eq, and, inArray, ne, exists } from "drizzle-orm"; import { eq, and, inArray, ne, exists } from "drizzle-orm";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { LimitId } from "@server/lib/billing";
export async function assignUserToOrg( export async function assignUserToOrg(
org: Org, org: Org,
@@ -61,7 +62,7 @@ export async function assignUserToOrg(
); );
if (orgsInBillingDomainThatTheUserIsStillIn.length === 0) { if (orgsInBillingDomainThatTheUserIsStillIn.length === 0) {
await usageService.add(org.orgId, FeatureId.USERS, 1, trx); await usageService.add(org.orgId, LimitId.USERS, 1, trx);
} }
} }
} }
@@ -83,6 +84,15 @@ export async function removeUserFromOrg(
.delete(userOrgs) .delete(userOrgs)
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, org.orgId))); .where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, org.orgId)));
await trx
.delete(resourceAccessToken)
.where(
and(
eq(resourceAccessToken.userId, userId),
eq(resourceAccessToken.orgId, org.orgId)
)
);
await trx.delete(userResources).where( await trx.delete(userResources).where(
and( and(
eq(userResources.userId, userId), eq(userResources.userId, userId),
@@ -157,7 +167,7 @@ export async function removeUserFromOrg(
); );
if (orgsInBillingDomainThatTheUserIsStillIn.length === 0) { if (orgsInBillingDomainThatTheUserIsStillIn.length === 0) {
await usageService.add(org.orgId, FeatureId.USERS, -1, trx); await usageService.add(org.orgId, LimitId.USERS, -1, trx);
} }
} }
} }
+2
View File
@@ -74,6 +74,7 @@ export const RESOURCE_RULE_MATCH_TYPES = [
"IP", "IP",
"PATH", "PATH",
"COUNTRY", "COUNTRY",
"COUNTRY_IS_NOT",
"ASN", "ASN",
"REGION" "REGION"
] as const; ] as const;
@@ -96,6 +97,7 @@ export function getResourceRuleValueValidationError(
case "REGION": case "REGION":
return isValidRegionId(value) ? null : "Invalid region ID provided"; return isValidRegionId(value) ? null : "Invalid region ID provided";
case "COUNTRY": case "COUNTRY":
case "COUNTRY_IS_NOT":
return COUNTRIES.some((country) => country.code === value) return COUNTRIES.some((country) => country.code === value)
? null ? null
: "Invalid country code provided"; : "Invalid country code provided";
+1
View File
@@ -17,3 +17,4 @@ export * from "./verifyApiKeySiteResourceAccess";
export * from "./verifyApiKeyIdpAccess"; export * from "./verifyApiKeyIdpAccess";
export * from "./verifyApiKeyDomainAccess"; export * from "./verifyApiKeyDomainAccess";
export * from "./verifyApiKeyResourcePolicyAccess"; export * from "./verifyApiKeyResourcePolicyAccess";
export * from "./verifyApiKeySiteProvisioningKeyAccess";
@@ -0,0 +1,111 @@
import { Request, Response, NextFunction } from "express";
import {
db,
siteProvisioningKeys,
siteProvisioningKeyOrg,
apiKeyOrg
} from "@server/db";
import { and, eq } from "drizzle-orm";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
import { getFirstString } from "@server/lib/requestParams";
export async function verifyApiKeySiteProvisioningKeyAccess(
req: Request,
res: Response,
next: NextFunction
) {
try {
const apiKey = req.apiKey;
const siteProvisioningKeyId =
getFirstString(req.params.siteProvisioningKeyId) ||
getFirstString(req.body.siteProvisioningKeyId) ||
getFirstString(req.query.siteProvisioningKeyId);
const orgId = getFirstString(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 (!siteProvisioningKeyId) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Invalid key ID")
);
}
if (apiKey.isRoot) {
// Root keys can access any site provisioning key in any org
return next();
}
const [row] = await db
.select()
.from(siteProvisioningKeys)
.innerJoin(
siteProvisioningKeyOrg,
and(
eq(
siteProvisioningKeys.siteProvisioningKeyId,
siteProvisioningKeyOrg.siteProvisioningKeyId
),
eq(siteProvisioningKeyOrg.orgId, orgId)
)
)
.where(
eq(
siteProvisioningKeys.siteProvisioningKeyId,
siteProvisioningKeyId
)
)
.limit(1);
if (!row?.siteProvisioningKeys || !row.siteProvisioningKeyOrg) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Site provisioning key with ID ${siteProvisioningKeyId} 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, row.siteProvisioningKeyOrg.orgId)
)
)
.limit(1);
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 site provisioning key access"
)
);
}
}
+1
View File
@@ -18,6 +18,7 @@ export enum OpenAPITags {
OrgIdp = "Identity Provider (Organization Only)", OrgIdp = "Identity Provider (Organization Only)",
Client = "Client", Client = "Client",
ApiKey = "API Key", ApiKey = "API Key",
SiteProvisioningKey = "Site Provisioning Key",
Domain = "Domain", Domain = "Domain",
Blueprint = "Blueprint", Blueprint = "Blueprint",
Ssh = "SSH", Ssh = "SSH",
+81 -4
View File
@@ -18,12 +18,15 @@ import {
resources, resources,
targets, targets,
sites, sites,
siteLabels,
remoteExitNodes,
remoteExitNodePreferenceLabels,
targetHealthCheck, targetHealthCheck,
Transaction Transaction
} from "@server/db"; } from "@server/db";
import logger from "@server/logger"; import logger from "@server/logger";
import { ExitNodePingResult } from "@server/routers/newt"; import { ExitNodePingResult } from "@server/routers/newt";
import { eq, and, or, ne, isNull } from "drizzle-orm"; import { eq, and, or, ne, isNull, inArray } from "drizzle-orm";
import axios from "axios"; import axios from "axios";
import config from "../config"; import config from "../config";
@@ -150,7 +153,8 @@ export async function verifyExitNodeOrgAccess(
export async function listExitNodes( export async function listExitNodes(
orgId: string, orgId: string,
filterOnline = false, filterOnline = false,
noCloud = false noCloud = false,
siteId?: number
) { ) {
const allExitNodes = await db const allExitNodes = await db
.select({ .select({
@@ -237,7 +241,7 @@ export async function listExitNodes(
// }) // })
// ); // );
const remoteExitNodes = allExitNodes.filter( let remoteExitNodesList = allExitNodes.filter(
(node) => (node) =>
node.type === "remoteExitNode" && (!filterOnline || node.online) node.type === "remoteExitNode" && (!filterOnline || node.online)
); );
@@ -246,9 +250,82 @@ export async function listExitNodes(
node.type === "gerbil" && (!filterOnline || node.online) && !noCloud node.type === "gerbil" && (!filterOnline || node.online) && !noCloud
); );
// Apply label-based filtering to remote exit nodes if siteId is provided
if (siteId !== undefined && remoteExitNodesList.length > 0) {
// Get the site's labels
const siteLabelRows = await db
.select({ labelId: siteLabels.labelId })
.from(siteLabels)
.where(eq(siteLabels.siteId, siteId));
const siteLabelIds = new Set(siteLabelRows.map((r) => r.labelId));
// Get the remoteExitNode records for these exit nodes so we have the remoteExitNodeId
const exitNodeIds = remoteExitNodesList.map((n) => n.exitNodeId);
const remoteNodeRows = await db
.select({
exitNodeId: remoteExitNodes.exitNodeId,
remoteExitNodeId: remoteExitNodes.remoteExitNodeId
})
.from(remoteExitNodes)
.where(inArray(remoteExitNodes.exitNodeId, exitNodeIds));
const exitNodeIdToRemoteId = new Map(
remoteNodeRows
.filter((r) => r.exitNodeId !== null)
.map((r) => [r.exitNodeId!, r.remoteExitNodeId])
);
// Get preference labels for all remote exit nodes
const remoteExitNodeIds = remoteNodeRows.map((r) => r.remoteExitNodeId);
const prefLabelRows =
remoteExitNodeIds.length > 0
? await db
.select({
remoteExitNodeId:
remoteExitNodePreferenceLabels.remoteExitNodeId,
labelId: remoteExitNodePreferenceLabels.labelId
})
.from(remoteExitNodePreferenceLabels)
.where(
inArray(
remoteExitNodePreferenceLabels.remoteExitNodeId,
remoteExitNodeIds
)
)
: [];
// Build a map of remoteExitNodeId -> Set of labelIds
const prefLabelsMap = new Map<string, Set<number>>();
for (const row of prefLabelRows) {
if (!prefLabelsMap.has(row.remoteExitNodeId)) {
prefLabelsMap.set(row.remoteExitNodeId, new Set());
}
prefLabelsMap.get(row.remoteExitNodeId)!.add(row.labelId);
}
// Filter: include node if it has no preference labels, or if site shares at least one label
const filtered = remoteExitNodesList.filter((node) => {
const remoteId = exitNodeIdToRemoteId.get(node.exitNodeId);
if (!remoteId) return true; // no remoteExitNode record, don't filter
const prefLabels = prefLabelsMap.get(remoteId);
if (!prefLabels || prefLabels.size === 0) return true; // no preference labels, include
// include only if site has at least one matching label
for (const labelId of siteLabelIds) {
if (prefLabels.has(labelId)) return true;
}
return false;
});
// Only apply the filtered list if at least one remote node remains;
// otherwise fall through to the gerbil fallback below
if (filtered.length > 0 || remoteExitNodesList.length === 0) {
remoteExitNodesList = filtered;
}
}
// THIS PROVIDES THE FALL // THIS PROVIDES THE FALL
const exitNodesList = const exitNodesList =
remoteExitNodes.length > 0 ? remoteExitNodes : gerbilExitNodes; remoteExitNodesList.length > 0 ? remoteExitNodesList : gerbilExitNodes;
return exitNodesList; return exitNodesList;
} }
+55 -56
View File
@@ -32,55 +32,59 @@ export class LockManager {
} }
} }
private getLocalOwnerToken(): string {
return `${instanceId}:`;
}
/** /**
* Acquire a distributed lock using Redis SET with NX and PX options * Acquire a distributed lock using Redis SET with NX and PX options
* @param lockKey - Unique identifier for the lock * @param lockKey - Unique identifier for the lock
* @param ttlMs - Time to live in milliseconds * @param ttlMs - Time to live in milliseconds
* @returns Promise<boolean> - true if lock acquired, false otherwise * @returns Promise<string | null> - a token identifying this specific acquisition
* (truthy) on success, or null if the lock could not be acquired.
*/ */
async acquireLock( async acquireLock(
lockKey: string, lockKey: string,
ttlMs: number = 30000, ttlMs: number = 30000,
maxRetries: number = 3, maxRetries: number = 3,
retryDelayMs: number = 100 retryDelayMs: number = 100
): Promise<boolean> { ): Promise<string | null> {
if (!redis || !redis.status || redis.status !== "ready") { if (!redis || !redis.status || redis.status !== "ready") {
for (let attempt = 0; attempt < maxRetries; attempt++) { for (let attempt = 0; attempt < maxRetries; attempt++) {
this.clearExpiredLocalLock(lockKey); this.clearExpiredLocalLock(lockKey);
const existing = localLocks.get(lockKey); const existing = localLocks.get(lockKey);
if (!existing) { if (!existing) {
const token = `${instanceId}:${uuidv4()}`;
localLocks.set(lockKey, { localLocks.set(lockKey, {
owner: this.getLocalOwnerToken(), owner: token,
expiresAt: Date.now() + ttlMs expiresAt: Date.now() + ttlMs
}); });
return true; return token;
}
if (existing.owner === this.getLocalOwnerToken()) {
existing.expiresAt = Date.now() + ttlMs;
localLocks.set(lockKey, existing);
return true;
} }
// Do not treat a same-process holder as automatically
// reentrant -- see the note in the Redis branch below.
if (attempt < maxRetries - 1) { if (attempt < maxRetries - 1) {
const delay = retryDelayMs * Math.pow(2, attempt); const delay = retryDelayMs * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay)); await new Promise((resolve) => setTimeout(resolve, delay));
} }
} }
return false; return null;
} }
const lockValue = `${instanceId}:${Date.now()}`;
const redisKey = `lock:${lockKey}`; const redisKey = `lock:${lockKey}`;
for (let attempt = 0; attempt < maxRetries; attempt++) { for (let attempt = 0; attempt < maxRetries; attempt++) {
try { try {
// Every acquisition attempt gets its own unique token, even
// within the same process. Two independent logical operations
// (e.g. two different API requests handled by the same server)
// racing for this key must never both believe they hold the
// lock -- if we treated "existing value starts with my
// instanceId" as reentrant success, a second unrelated caller
// on this process could barge in while the first is still
// mid-flight, and their writes under the lock would interleave
// unguarded.
const lockValue = `${instanceId}:${uuidv4()}`;
// 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(
@@ -93,19 +97,7 @@ export class LockManager {
if (result === "OK") { if (result === "OK") {
logger.debug(`Lock acquired: ${lockKey} by ${instanceId}`); logger.debug(`Lock acquired: ${lockKey} by ${instanceId}`);
return true; return lockValue;
}
// Check if the existing lock is from this worker (reentrant behavior)
const existingValue = await redis.get(redisKey);
if (
existingValue &&
existingValue.startsWith(`${instanceId}:`)
) {
// Extend the lock TTL since it's the same worker
await redis.pexpire(redisKey, ttlMs);
logger.debug(`Lock extended: ${lockKey} by ${instanceId}`);
return true;
} }
// If this isn't our last attempt, wait before retrying with exponential backoff // If this isn't our last attempt, wait before retrying with exponential backoff
@@ -132,18 +124,23 @@ export class LockManager {
logger.debug( logger.debug(
`Failed to acquire lock ${lockKey} after ${maxRetries} attempts` `Failed to acquire lock ${lockKey} after ${maxRetries} attempts`
); );
return false; return null;
} }
/** /**
* Release a lock using Lua script to ensure atomicity * Release a lock previously acquired via acquireLock/acquireLockWithRetry,
* using a Lua script to ensure we only delete it if it still matches the
* exact token from that acquisition (not just "owned by this process") --
* this ensures a caller whose TTL already expired can't delete a
* different, currently-active holder's lock.
* @param lockKey - Unique identifier for the lock * @param lockKey - Unique identifier for the lock
* @param token - the exact token returned by the acquisition being released
*/ */
async releaseLock(lockKey: string): Promise<void> { async releaseLock(lockKey: string, token: string): Promise<void> {
if (!redis || !redis.status || redis.status !== "ready") { if (!redis || !redis.status || redis.status !== "ready") {
this.clearExpiredLocalLock(lockKey); this.clearExpiredLocalLock(lockKey);
const existing = localLocks.get(lockKey); const existing = localLocks.get(lockKey);
if (existing && existing.owner === this.getLocalOwnerToken()) { if (existing && existing.owner === token) {
localLocks.delete(lockKey); localLocks.delete(lockKey);
} }
return; return;
@@ -151,13 +148,12 @@ export class LockManager {
const redisKey = `lock:${lockKey}`; const redisKey = `lock:${lockKey}`;
// Lua script to ensure we only delete the lock if it belongs to this worker
const luaScript = ` const luaScript = `
local key = KEYS[1] local key = KEYS[1]
local worker_prefix = ARGV[1] local expected_value = ARGV[1]
local current_value = redis.call('GET', key) local current_value = redis.call('GET', key)
if current_value and string.find(current_value, worker_prefix, 1, true) == 1 then if current_value and current_value == expected_value then
return redis.call('DEL', key) return redis.call('DEL', key)
else else
return 0 return 0
@@ -169,16 +165,14 @@ export class LockManager {
luaScript, luaScript,
1, 1,
redisKey, redisKey,
`${instanceId}:` token
)) as number; )) as number;
if (result === 1) { if (result === 1) {
logger.debug(`Lock released: ${lockKey} by ${instanceId}`); logger.debug(`Lock released: ${lockKey} by ${instanceId}`);
} else { } else {
logger.warn( logger.warn(
`Lock not released - not owned by worker: ${lockKey} by ${ `Lock not released - token did not match current holder: ${lockKey} (attempted by ${instanceId})`
instanceId
}`
); );
} }
} catch (error) { } catch (error) {
@@ -230,7 +224,7 @@ export class LockManager {
const ttl = Math.max(0, existing.expiresAt - Date.now()); const ttl = Math.max(0, existing.expiresAt - Date.now());
return { return {
exists: true, exists: true,
ownedByMe: existing.owner === this.getLocalOwnerToken(), ownedByMe: existing.owner.startsWith(`${instanceId}:`),
ttl, ttl,
owner: existing.owner.split(":")[0] owner: existing.owner.split(":")[0]
}; };
@@ -261,17 +255,23 @@ export class LockManager {
} }
/** /**
* Extend the TTL of an existing lock owned by this worker * Extend the TTL of an existing lock, provided the token matches the
* acquisition currently holding it.
* @param lockKey - Unique identifier for the lock * @param lockKey - Unique identifier for the lock
* @param ttlMs - New TTL in milliseconds * @param ttlMs - New TTL in milliseconds
* @param token - the token returned by the acquisition being extended
* @returns Promise<boolean> - true if extended successfully * @returns Promise<boolean> - true if extended successfully
*/ */
async extendLock(lockKey: string, ttlMs: number): Promise<boolean> { async extendLock(
lockKey: string,
ttlMs: number,
token: string
): Promise<boolean> {
if (!redis || !redis.status || redis.status !== "ready") { if (!redis || !redis.status || redis.status !== "ready") {
this.clearExpiredLocalLock(lockKey); this.clearExpiredLocalLock(lockKey);
const existing = localLocks.get(lockKey); const existing = localLocks.get(lockKey);
if (!existing || existing.owner !== this.getLocalOwnerToken()) { if (!existing || existing.owner !== token) {
return false; return false;
} }
@@ -282,14 +282,13 @@ export class LockManager {
const redisKey = `lock:${lockKey}`; const redisKey = `lock:${lockKey}`;
// Lua script to extend TTL only if lock is owned by this worker
const luaScript = ` const luaScript = `
local key = KEYS[1] local key = KEYS[1]
local worker_prefix = ARGV[1] local expected_value = ARGV[1]
local ttl = tonumber(ARGV[2]) local ttl = tonumber(ARGV[2])
local current_value = redis.call('GET', key) local current_value = redis.call('GET', key)
if current_value and string.find(current_value, worker_prefix, 1, true) == 1 then if current_value and current_value == expected_value then
return redis.call('PEXPIRE', key, ttl) return redis.call('PEXPIRE', key, ttl)
else else
return 0 return 0
@@ -301,7 +300,7 @@ export class LockManager {
luaScript, luaScript,
1, 1,
redisKey, redisKey,
`${instanceId}:`, token,
ttlMs.toString() ttlMs.toString()
)) as number; )) as number;
@@ -324,14 +323,14 @@ export class LockManager {
* @param ttlMs - Time to live in milliseconds * @param ttlMs - Time to live in milliseconds
* @param maxRetries - Maximum number of retry attempts * @param maxRetries - Maximum number of retry attempts
* @param baseDelayMs - Base delay between retries in milliseconds * @param baseDelayMs - Base delay between retries in milliseconds
* @returns Promise<boolean> - true if lock acquired * @returns Promise<string | null> - token if acquired, null otherwise
*/ */
async acquireLockWithRetry( async acquireLockWithRetry(
lockKey: string, lockKey: string,
ttlMs: number = 30000, ttlMs: number = 30000,
maxRetries: number = 5, maxRetries: number = 5,
baseDelayMs: number = 100 baseDelayMs: number = 100
): Promise<boolean> { ): Promise<string | null> {
for (let attempt = 0; attempt <= maxRetries; attempt++) { for (let attempt = 0; attempt <= maxRetries; attempt++) {
const acquired = await this.acquireLock( const acquired = await this.acquireLock(
lockKey, lockKey,
@@ -341,7 +340,7 @@ export class LockManager {
); );
if (acquired) { if (acquired) {
return true; return acquired;
} }
if (attempt < maxRetries) { if (attempt < maxRetries) {
@@ -355,7 +354,7 @@ export class LockManager {
logger.warn( logger.warn(
`Failed to acquire lock ${lockKey} after ${maxRetries + 1} attempts` `Failed to acquire lock ${lockKey} after ${maxRetries + 1} attempts`
); );
return false; return null;
} }
/** /**
@@ -370,16 +369,16 @@ export class LockManager {
fn: () => Promise<T>, fn: () => Promise<T>,
ttlMs: number = 30000 ttlMs: number = 30000
): Promise<T> { ): Promise<T> {
const acquired = await this.acquireLock(lockKey, ttlMs); const token = await this.acquireLock(lockKey, ttlMs);
if (!acquired) { if (!token) {
throw new Error(`Failed to acquire lock: ${lockKey}`); throw new Error(`Failed to acquire lock: ${lockKey}`);
} }
try { try {
return await fn(); return await fn();
} finally { } finally {
await this.releaseLock(lockKey); await this.releaseLock(lockKey, token);
} }
} }
@@ -402,7 +401,7 @@ export class LockManager {
let locksOwnedByMe = 0; let locksOwnedByMe = 0;
for (const value of localLocks.values()) { for (const value of localLocks.values()) {
if (value.owner === this.getLocalOwnerToken()) { if (value.owner.startsWith(`${instanceId}:`)) {
locksOwnedByMe++; locksOwnedByMe++;
} }
} }
+105
View File
@@ -0,0 +1,105 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 { redis } from "#private/lib/redis";
import logger from "@server/logger";
export const ORG_REBUILD_CONCURRENCY_LIMIT = 10;
// Safety-net TTL: slightly longer than the rebuild lock TTL (120 s). If a
// server process dies while holding a rebuild, this ensures the counter key
// eventually expires rather than staying inflated forever.
const ORG_REBUILD_COUNT_TTL_MS = 180000;
const KEY_PREFIX = "rebuild-org-count:";
// In-memory fallback used when Redis is unavailable.
const localFallback = new Map<string, number>();
function isRedisReady(): boolean {
return !!(redis && redis.status === "ready");
}
export async function incrementOrgRebuildCount(orgId: string): Promise<void> {
if (!isRedisReady()) {
localFallback.set(orgId, (localFallback.get(orgId) ?? 0) + 1);
return;
}
try {
const key = `${KEY_PREFIX}${orgId}`;
await redis!.incr(key);
// Always refresh the TTL so the key doesn't expire while rebuilds are
// still in progress. The TTL is purely a crash-recovery safety net.
await redis!.pexpire(key, ORG_REBUILD_COUNT_TTL_MS);
} catch (err) {
logger.warn(
`orgRebuildCounter: Redis increment failed for org ${orgId}, falling back to local:`,
err
);
localFallback.set(orgId, (localFallback.get(orgId) ?? 0) + 1);
}
}
export async function decrementOrgRebuildCount(orgId: string): Promise<void> {
if (!isRedisReady()) {
const current = localFallback.get(orgId) ?? 0;
if (current <= 1) {
localFallback.delete(orgId);
} else {
localFallback.set(orgId, current - 1);
}
return;
}
try {
const key = `${KEY_PREFIX}${orgId}`;
const count = await redis!.decr(key);
if (count <= 0) {
await redis!.del(key);
}
} catch (err) {
logger.warn(
`orgRebuildCounter: Redis decrement failed for org ${orgId}, falling back to local:`,
err
);
const current = localFallback.get(orgId) ?? 0;
if (current <= 1) {
localFallback.delete(orgId);
} else {
localFallback.set(orgId, current - 1);
}
}
}
export async function getOrgActiveRebuildCount(orgId: string): Promise<number> {
if (!isRedisReady()) {
return localFallback.get(orgId) ?? 0;
}
try {
const key = `${KEY_PREFIX}${orgId}`;
const val = await redis!.get(key);
return val ? parseInt(val, 10) : 0;
} catch (err) {
logger.warn(
`orgRebuildCounter: Redis get failed for org ${orgId}, falling back to local:`,
err
);
return localFallback.get(orgId) ?? 0;
}
}
export async function checkOrgRebuildRateLimit(
orgId: string
): Promise<boolean> {
return (
(await getOrgActiveRebuildCount(orgId)) >= ORG_REBUILD_CONCURRENCY_LIMIT
);
}
+16 -18
View File
@@ -12,7 +12,7 @@
*/ */
import logger from "@server/logger"; import logger from "@server/logger";
import redisManager from "#private/lib/redis"; import { regionalRedisManager as redisManager } from "#private/lib/redis";
import { build } from "@server/build"; import { build } from "@server/build";
// Rate limiting configuration // Rate limiting configuration
@@ -152,10 +152,9 @@ export class RateLimitService {
); );
// Set TTL using the client directly - this prevents the key from persisting forever // Set TTL using the client directly - this prevents the key from persisting forever
if (redisManager.getClient()) { const writeClient = redisManager.getClient();
await redisManager if (writeClient) {
.getClient() await writeClient.expire(globalKey, RATE_LIMIT_WINDOW + 10);
.expire(globalKey, RATE_LIMIT_WINDOW + 10);
} }
// Update tracking // Update tracking
@@ -204,10 +203,12 @@ export class RateLimitService {
); );
// Set TTL using the client directly - this prevents the key from persisting forever // Set TTL using the client directly - this prevents the key from persisting forever
if (redisManager.getClient()) { const writeClient = redisManager.getClient();
await redisManager if (writeClient) {
.getClient() await writeClient.expire(
.expire(messageTypeKey, RATE_LIMIT_WINDOW + 10); messageTypeKey,
RATE_LIMIT_WINDOW + 10
);
} }
// Update tracking // Update tracking
@@ -487,16 +488,13 @@ export class RateLimitService {
await redisManager.del(globalKey); await redisManager.del(globalKey);
// Get all message type keys for this client and delete them // Get all message type keys for this client and delete them
const client = redisManager.getClient(); const messageTypeKeys = await redisManager.keys(
if (client) { `ratelimit:${clientId}:*`
const messageTypeKeys = await client.keys( );
`ratelimit:${clientId}:*` if (messageTypeKeys.length > 0) {
await Promise.all(
messageTypeKeys.map((key) => redisManager.del(key))
); );
if (messageTypeKeys.length > 0) {
await Promise.all(
messageTypeKeys.map((key) => redisManager.del(key))
);
}
} }
} }
} }
+36 -4
View File
@@ -14,12 +14,16 @@
import { redis } from "#private/lib/redis"; import { redis } from "#private/lib/redis";
import { lockManager } from "#private/lib/lock"; import { lockManager } from "#private/lib/lock";
import logger from "@server/logger"; import logger from "@server/logger";
import { isTransientError } from "@server/lib/dbRetry";
export type RebuildJobType = "site-resource" | "client"; export type RebuildJobType = "site-resource" | "client";
export interface RebuildJob { export interface RebuildJob {
type: RebuildJobType; type: RebuildJobType;
id: number; id: number;
// Number of times this job has already been re-queued after a transient
// failure. Absent/0 means it has not failed yet.
attempt?: number;
} }
export interface RebuildJobHandlers { export interface RebuildJobHandlers {
@@ -43,6 +47,11 @@ const PROCESSOR_LOCK_TTL_MS = 120000 * BATCH_SIZE + 30000; // ~630 s
const POLL_INTERVAL_MS = 500; const POLL_INTERVAL_MS = 500;
// A job that fails with a transient DB error gets re-queued with backoff
// instead of being dropped, up to this many times.
const MAX_JOB_ATTEMPTS = 5;
const JOB_RETRY_BASE_DELAY_MS = 1000;
class RedisRebuildQueue { class RedisRebuildQueue {
private processingStarted = false; private processingStarted = false;
@@ -180,10 +189,33 @@ class RedisRebuildQueue {
`Rebuild queue: completed ${job.type}:${job.id}` `Rebuild queue: completed ${job.type}:${job.id}`
); );
} catch (err) { } catch (err) {
logger.error( const attempt = (job.attempt ?? 0) + 1;
`Rebuild queue: job ${job.type}:${job.id} threw an error:`, if (
err isTransientError(err) &&
); attempt <= MAX_JOB_ATTEMPTS
) {
const delay =
JOB_RETRY_BASE_DELAY_MS *
Math.pow(2, attempt - 1);
logger.warn(
`Rebuild queue: job ${job.type}:${job.id} hit a transient error (attempt ${attempt}/${MAX_JOB_ATTEMPTS}), re-queuing in ${delay}ms:`,
err
);
setTimeout(() => {
this.enqueue({ ...job, attempt }).catch(
(enqueueErr) =>
logger.error(
`Rebuild queue: failed to re-queue ${job.type}:${job.id} after transient error:`,
enqueueErr
)
);
}, delay);
} else {
logger.error(
`Rebuild queue: job ${job.type}:${job.id} threw an error:`,
err
);
}
} }
} }
}, },
+80 -18
View File
@@ -894,6 +894,19 @@ class RegionalRedisManager {
return opts; return opts;
} }
// The regional Redis StatefulSet's "redis" service pins to pod redis-0
// (primary). The replica (redis-1) is only reachable through the
// per-pod headless service: <svc>.<namespace>.svc.cluster.local ->
// redis-1.redis-headless.<namespace>.svc.cluster.local. Returns null
// if the configured host doesn't match that pattern (e.g. local dev),
// in which case callers should fall back to the primary for reads.
private getReplicaHost(primaryHost: string): string | null {
const match = primaryHost.match(/^redis\.([^.]+)\.svc\.cluster\.local$/);
if (!match) return null;
const namespace = match[1];
return `redis-1.redis-headless.${namespace}.svc.cluster.local`;
}
private initializeClients(): void { private initializeClients(): void {
const cfg = this.getConfig(); const cfg = this.getConfig();
const baseOpts = { const baseOpts = {
@@ -907,35 +920,42 @@ class RegionalRedisManager {
try { try {
this.writeClient = new Redis(baseOpts); this.writeClient = new Redis(baseOpts);
// redis-1 (replica) handles reads; fall back to primary if not resolvable
this.readClient = new Redis({
...baseOpts,
host: cfg.host!.replace(/^(.*?)(\.\S+)$/, (_, h, rest) => {
// Derive replica hostname from the headless service pattern:
// redis.redis.svc.cluster.local -> redis-1.redis-headless.redis.svc.cluster.local
// If it doesn't look like a k8s service, just use the same host
return h + rest;
})
});
// For simplicity use same host for both; callers can always read from primary const replicaHost = this.getReplicaHost(cfg.host!);
// The real replica routing is handled by the StatefulSet headless service this.readClient = replicaHost
this.readClient = this.writeClient; ? new Redis({ ...baseOpts, host: replicaHost })
: this.writeClient;
this.writeClient.on("ready", () => { this.writeClient.on("ready", () => {
logger.info("Regional Redis client ready"); logger.info("Regional Redis write client ready");
this.isHealthy = true; this.isHealthy = true;
}); });
this.writeClient.on("error", (err) => { this.writeClient.on("error", (err) => {
logger.error("Regional Redis client error:", err); logger.error("Regional Redis write client error:", err);
this.isHealthy = false; this.isHealthy = false;
}); });
this.writeClient.on("reconnecting", () => { this.writeClient.on("reconnecting", () => {
logger.info("Regional Redis client reconnecting..."); logger.info("Regional Redis write client reconnecting...");
this.isHealthy = false; this.isHealthy = false;
}); });
logger.info("Regional Redis client initialized"); if (this.readClient !== this.writeClient) {
this.readClient.on("ready", () => {
logger.info("Regional Redis read client ready");
});
this.readClient.on("error", (err) => {
logger.error("Regional Redis read client error:", err);
});
this.readClient.on("reconnecting", () => {
logger.info("Regional Redis read client reconnecting...");
});
}
logger.info(
replicaHost
? `Regional Redis client initialized (reads routed to replica ${replicaHost})`
: "Regional Redis client initialized (no replica resolvable, reads routed to primary)"
);
} catch (error) { } catch (error) {
logger.error("Failed to initialize regional Redis client:", error); logger.error("Failed to initialize regional Redis client:", error);
this.isEnabled = false; this.isEnabled = false;
@@ -1000,13 +1020,55 @@ class RegionalRedisManager {
} }
} }
public getClient(): Redis | null {
return this.writeClient;
}
public async hget(key: string, field: string): Promise<string | null> {
if (!this.isRedisEnabled() || !this.readClient) return null;
try {
return await this.readClient.hget(key, field);
} catch (error) {
logger.error("Regional Redis HGET error:", error);
return null;
}
}
public async hset(
key: string,
field: string,
value: string
): Promise<boolean> {
if (!this.isRedisEnabled() || !this.writeClient) return false;
try {
await this.writeClient.hset(key, field, value);
return true;
} catch (error) {
logger.error("Regional Redis HSET error:", error);
return false;
}
}
public async hgetall(key: string): Promise<Record<string, string>> {
if (!this.isRedisEnabled() || !this.readClient) return {};
try {
return await this.readClient.hgetall(key);
} catch (error) {
logger.error("Regional Redis HGETALL error:", error);
return {};
}
}
public async disconnect(): Promise<void> { public async disconnect(): Promise<void> {
try { try {
if (this.readClient && this.readClient !== this.writeClient) {
await this.readClient.quit();
}
this.readClient = null;
if (this.writeClient) { if (this.writeClient) {
await this.writeClient.quit(); await this.writeClient.quit();
this.writeClient = null; this.writeClient = null;
} }
this.readClient = null;
logger.info("Regional Redis client disconnected"); logger.info("Regional Redis client disconnected");
} catch (error) { } catch (error) {
logger.error("Error disconnecting regional Redis client:", error); logger.error("Error disconnecting regional Redis client:", error);
@@ -17,6 +17,7 @@ import HttpCode from "@server/types/HttpCode";
import { build } from "@server/build"; import { build } from "@server/build";
import { getOrgTierData } from "#private/lib/billing"; import { getOrgTierData } from "#private/lib/billing";
import { Tier } from "@server/types/Tiers"; import { Tier } from "@server/types/Tiers";
import logger from "@server/logger";
export function verifyValidSubscription(tiers: Tier[]) { export function verifyValidSubscription(tiers: Tier[]) {
return async function ( return async function (
@@ -30,9 +31,9 @@ export function verifyValidSubscription(tiers: Tier[]) {
} }
const orgId = const orgId =
req.params.orgId || req.params?.orgId ||
req.body.orgId || req.body?.orgId ||
req.query.orgId || req.query?.orgId ||
req.userOrgId; req.userOrgId;
if (!orgId) { if (!orgId) {
@@ -65,6 +66,7 @@ export function verifyValidSubscription(tiers: Tier[]) {
return next(); return next();
} catch (e) { } catch (e) {
logger.error(e);
return next( return next(
createHttpError( createHttpError(
HttpCode.INTERNAL_SERVER_ERROR, HttpCode.INTERNAL_SERVER_ERROR,
@@ -17,3 +17,4 @@ export * from "./queryAccessAuditLog";
export * from "./exportAccessAuditLog"; export * from "./exportAccessAuditLog";
export * from "./queryConnectionAuditLog"; export * from "./queryConnectionAuditLog";
export * from "./exportConnectionAuditLog"; export * from "./exportConnectionAuditLog";
export * from "./logAccessAuditAttempt";
@@ -0,0 +1,95 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 { NextFunction } from "express";
import { Request, Response } from "express";
import { z } from "zod";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
import { fromError } from "zod-validation-error";
import response from "@server/lib/response";
import logger from "@server/logger";
import { logAccessAudit } from "#private/lib/logAccessAudit";
export const logAccessAuditAttemptSchema = z.object({
resourceId: z.number().int().positive(),
action: z.boolean(),
type: z.enum(["login", "ssh", "vnc", "rdp"])
});
export const logAccessAuditAttemptParams = z.object({
orgId: z.string()
});
export async function logAccessAuditAttempt(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedBody = logAccessAuditAttemptSchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error)
)
);
}
const parsedParams = logAccessAuditAttemptParams.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error)
)
);
}
const { orgId } = parsedParams.data;
const { resourceId, action, type } = parsedBody.data;
const username = req.user?.username;
const userId = req.user?.userId;
await logAccessAudit({
orgId: orgId,
resourceId: resourceId,
action: action,
...(username && userId
? {
user: {
username,
userId
}
}
: {}),
type: type,
userAgent: req.headers["user-agent"],
requestIp: req.ip
});
return response<null>(res, {
data: null,
success: true,
error: false,
message: "Access audit attempt logged successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
@@ -22,7 +22,7 @@ import {
import { registry } from "@server/openApi"; import { registry } from "@server/openApi";
import { NextFunction } from "express"; import { NextFunction } from "express";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { eq, gt, lt, and, count, desc, inArray, isNull } from "drizzle-orm"; import { eq, gt, lt, and, count, desc, inArray, isNull, or } from "drizzle-orm";
import { OpenAPITags } from "@server/openApi"; import { OpenAPITags } from "@server/openApi";
import { z } from "zod"; import { z } from "zod";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
@@ -120,7 +120,10 @@ function getWhere(data: Q) {
lt(accessAuditLog.timestamp, data.timeEnd), lt(accessAuditLog.timestamp, data.timeEnd),
eq(accessAuditLog.orgId, data.orgId), eq(accessAuditLog.orgId, data.orgId),
data.resourceId data.resourceId
? eq(accessAuditLog.resourceId, data.resourceId) ? or(
eq(accessAuditLog.resourceId, data.resourceId),
eq(accessAuditLog.siteResourceId, data.resourceId)
)
: undefined, : undefined,
data.actor ? eq(accessAuditLog.actor, data.actor) : undefined, data.actor ? eq(accessAuditLog.actor, data.actor) : undefined,
data.actorType data.actorType
@@ -233,7 +236,6 @@ async function enrichWithResourceDetails(
const details = siteResourceMap.get(log.siteResourceId); const details = siteResourceMap.get(log.siteResourceId);
return { return {
...log, ...log,
resourceId: log.siteResourceId,
resourceName: details?.name ?? null, resourceName: details?.name ?? null,
resourceNiceId: details?.niceId ?? null resourceNiceId: details?.niceId ?? null
}; };
+2 -2
View File
@@ -25,7 +25,7 @@ import {
getTier1FeaturePriceSet, getTier1FeaturePriceSet,
getTier3FeaturePriceSet, getTier3FeaturePriceSet,
getTier2FeaturePriceSet, getTier2FeaturePriceSet,
FeatureId, LimitId,
type FeaturePriceSet type FeaturePriceSet
} from "@server/lib/billing"; } from "@server/lib/billing";
import { getLineItems } from "@server/lib/billing/getLineItems"; import { getLineItems } from "@server/lib/billing/getLineItems";
@@ -214,7 +214,7 @@ export async function changeTier(
} }
// Map to the corresponding feature in the new tier // Map to the corresponding feature in the new tier
const newPriceId = targetPriceSet[FeatureId.USERS]; const newPriceId = targetPriceSet[LimitId.USERS];
if (newPriceId) { if (newPriceId) {
return { return {
+27 -6
View File
@@ -24,7 +24,7 @@ import { fromZodError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { Limit, limits, Usage, usage } from "@server/db"; import { Limit, limits, Usage, usage } from "@server/db";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { LimitId } from "@server/lib/billing";
import { GetOrgUsageResponse } from "@server/routers/billing/types"; import { GetOrgUsageResponse } from "@server/routers/billing/types";
const getOrgSchema = z.strictObject({ const getOrgSchema = z.strictObject({
@@ -93,16 +93,28 @@ export async function getOrgUsage(
// Get usage for org // Get usage for org
const usageData = []; const usageData = [];
const sites = await usageService.getUsage(orgId, FeatureId.SITES); const sites = await usageService.getUsage(orgId, LimitId.SITES);
const users = await usageService.getUsage(orgId, FeatureId.USERS); const users = await usageService.getUsage(orgId, LimitId.USERS);
const domains = await usageService.getUsage(orgId, FeatureId.DOMAINS); const domains = await usageService.getUsage(orgId, LimitId.DOMAINS);
const remoteExitNodes = await usageService.getUsage( const remoteExitNodes = await usageService.getUsage(
orgId, orgId,
FeatureId.REMOTE_EXIT_NODES LimitId.REMOTE_EXIT_NODES
); );
const organizations = await usageService.getUsage( const organizations = await usageService.getUsage(
orgId, orgId,
FeatureId.ORGINIZATIONS LimitId.ORGANIZATIONS
);
const publicResources = await usageService.getUsage(
orgId,
LimitId.PUBLIC_RESOURCES
);
const privateResources = await usageService.getUsage(
orgId,
LimitId.PRIVATE_RESOURCES
);
const machineClients = await usageService.getUsage(
orgId,
LimitId.MACHINE_CLIENTS
); );
// const egressData = await usageService.getUsage( // const egressData = await usageService.getUsage(
// orgId, // orgId,
@@ -127,6 +139,15 @@ export async function getOrgUsage(
if (organizations) { if (organizations) {
usageData.push(organizations); usageData.push(organizations);
} }
if (publicResources) {
usageData.push(publicResources);
}
if (privateResources) {
usageData.push(privateResources);
}
if (machineClients) {
usageData.push(machineClients);
}
const orgLimits = await db const orgLimits = await db
.select() .select()
+66 -74
View File
@@ -31,7 +31,6 @@ import * as siteProvisioning from "#private/routers/siteProvisioning";
import * as eventStreamingDestination from "#private/routers/eventStreamingDestination"; import * as eventStreamingDestination from "#private/routers/eventStreamingDestination";
import * as alertRule from "#private/routers/alertRule"; import * as alertRule from "#private/routers/alertRule";
import * as healthChecks from "#private/routers/healthChecks"; import * as healthChecks from "#private/routers/healthChecks";
import * as labels from "#private/routers/labels";
import * as client from "@server/routers/client"; import * as client from "@server/routers/client";
import * as resource from "#private/routers/resource"; import * as resource from "#private/routers/resource";
import * as policy from "#private/routers/policy"; import * as policy from "#private/routers/policy";
@@ -329,6 +328,44 @@ authenticated.delete(
remoteExitNode.deleteRemoteExitNode remoteExitNode.deleteRemoteExitNode
); );
authenticated.get(
"/org/:orgId/remote-exit-node/:remoteExitNodeId/resources",
verifyValidLicense,
verifyOrgAccess,
verifyRemoteExitNodeAccess,
verifyUserHasAction(ActionsEnum.getRemoteExitNode),
remoteExitNode.listRemoteExitNodeResources
);
authenticated.post(
"/org/:orgId/remote-exit-node/:remoteExitNodeId/resources",
verifyValidLicense,
verifyOrgAccess,
verifyRemoteExitNodeAccess,
verifyUserHasAction(ActionsEnum.updateRemoteExitNode),
logActionAudit(ActionsEnum.updateRemoteExitNode),
remoteExitNode.setRemoteExitNodeResources
);
authenticated.get(
"/org/:orgId/remote-exit-node/:remoteExitNodeId/preference-labels",
verifyValidLicense,
verifyOrgAccess,
verifyRemoteExitNodeAccess,
verifyUserHasAction(ActionsEnum.getRemoteExitNode),
remoteExitNode.listRemoteExitNodePreferenceLabels
);
authenticated.post(
"/org/:orgId/remote-exit-node/:remoteExitNodeId/preference-labels",
verifyValidLicense,
verifyOrgAccess,
verifyRemoteExitNodeAccess,
verifyUserHasAction(ActionsEnum.updateRemoteExitNode),
logActionAudit(ActionsEnum.updateRemoteExitNode),
remoteExitNode.setRemoteExitNodePreferenceLabels
);
authenticated.put( authenticated.put(
"/org/:orgId/login-page", "/org/:orgId/login-page",
verifyValidLicense, verifyValidLicense,
@@ -495,29 +532,31 @@ authRouter.post(
auth.transferSession auth.transferSession
); );
authenticated.post( if (build !== "saas") {
"/license/activate", authenticated.post(
verifyUserIsServerAdmin, "/license/activate",
license.activateLicense verifyUserIsServerAdmin,
); license.activateLicense
);
authenticated.get( authenticated.get(
"/license/keys", "/license/keys",
verifyUserIsServerAdmin, verifyUserIsServerAdmin,
license.listLicenseKeys license.listLicenseKeys
); );
authenticated.delete( authenticated.delete(
"/license/:licenseKey", "/license/:licenseKey",
verifyUserIsServerAdmin, verifyUserIsServerAdmin,
license.deleteLicenseKey license.deleteLicenseKey
); );
authenticated.post( authenticated.post(
"/license/recheck", "/license/recheck",
verifyUserIsServerAdmin, verifyUserIsServerAdmin,
license.recheckStatus license.recheckStatus
); );
}
authenticated.get( authenticated.get(
"/org/:orgId/logs/action", "/org/:orgId/logs/action",
@@ -770,59 +809,6 @@ authenticated.get(
alertRule.getAlertRule alertRule.getAlertRule
); );
authenticated.get(
"/org/:orgId/labels",
verifyValidLicense,
verifyOrgAccess,
verifyValidSubscription(tierMatrix.labels),
verifyUserHasAction(ActionsEnum.listOrgLabels),
labels.listOrgLabels
);
authenticated.post(
"/org/:orgId/labels",
verifyValidLicense,
verifyOrgAccess,
verifyValidSubscription(tierMatrix.labels),
verifyUserHasAction(ActionsEnum.createOrgLabel),
labels.createOrgLabel
);
authenticated.patch(
"/org/:orgId/label/:labelId",
verifyValidLicense,
verifyOrgAccess,
verifyValidSubscription(tierMatrix.labels),
verifyUserHasAction(ActionsEnum.updateOrgLabel),
labels.updateOrgLabel
);
authenticated.delete(
"/org/:orgId/label/:labelId",
verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.deleteOrgLabel),
labels.deleteOrgLabel
);
authenticated.put(
"/org/:orgId/label/:labelId/attach",
verifyValidLicense,
verifyOrgAccess,
verifyValidSubscription(tierMatrix.labels),
verifyUserHasAction(ActionsEnum.attachLabelToItem),
labels.attachLabelToItem
);
authenticated.put(
"/org/:orgId/label/:labelId/detach",
verifyValidLicense,
verifyOrgAccess,
verifyValidSubscription(tierMatrix.labels),
verifyUserHasAction(ActionsEnum.detachLabelFromItem),
labels.detachLabelFromItem
);
authenticated.get( authenticated.get(
"/org/:orgId/health-checks", "/org/:orgId/health-checks",
verifyValidLicense, verifyValidLicense,
@@ -878,3 +864,9 @@ authenticated.post(
verifyClientAccess, verifyClientAccess,
client.rebuildClientAssociationsCacheRoute client.rebuildClientAssociationsCacheRoute
); );
authenticated.post(
"/org/:orgId/logs/access/attempt",
verifyOrgAccess,
logs.logAccessAuditAttempt
);
+34 -30
View File
@@ -29,37 +29,41 @@ export async function createExitNode(
.where(eq(exitNodes.publicKey, publicKey)); .where(eq(exitNodes.publicKey, publicKey));
let exitNode: ExitNode; let exitNode: ExitNode;
if (!exitNodeQuery) { if (!exitNodeQuery) {
const address = await getNextAvailableSubnet(); const { value: address, release } = await getNextAvailableSubnet();
// TODO: eventually we will want to get the next available port so that we can multiple exit nodes try {
// const listenPort = await getNextAvailablePort(); // TODO: eventually we will want to get the next available port so that we can multiple exit nodes
const listenPort = config.getRawConfig().gerbil.start_port; // const listenPort = await getNextAvailablePort();
let subEndpoint = ""; const listenPort = config.getRawConfig().gerbil.start_port;
if (config.getRawConfig().gerbil.use_subdomain) { let subEndpoint = "";
subEndpoint = await getUniqueExitNodeEndpointName(); if (config.getRawConfig().gerbil.use_subdomain) {
subEndpoint = await getUniqueExitNodeEndpointName();
}
const exitNodeName =
config.getRawConfig().gerbil.exit_node_name ||
`Exit Node ${publicKey.slice(0, 8)}`;
// create a new exit node
[exitNode] = await db
.insert(exitNodes)
.values({
publicKey,
endpoint: `${subEndpoint}${subEndpoint != "" ? "." : ""}${config.getRawConfig().gerbil.base_endpoint}`,
address,
listenPort,
online: true,
reachableAt,
name: exitNodeName
})
.returning()
.execute();
logger.info(
`Created new exit node ${exitNode.name} with address ${exitNode.address} and port ${exitNode.listenPort}`
);
} finally {
await release();
} }
const exitNodeName =
config.getRawConfig().gerbil.exit_node_name ||
`Exit Node ${publicKey.slice(0, 8)}`;
// create a new exit node
[exitNode] = await db
.insert(exitNodes)
.values({
publicKey,
endpoint: `${subEndpoint}${subEndpoint != "" ? "." : ""}${config.getRawConfig().gerbil.base_endpoint}`,
address,
listenPort,
online: true,
reachableAt,
name: exitNodeName
})
.returning()
.execute();
logger.info(
`Created new exit node ${exitNode.name} with address ${exitNode.address} and port ${exitNode.listenPort}`
);
} else { } else {
// update the reachable at // update the reachable at
[exitNode] = await db [exitNode] = await db
@@ -55,9 +55,14 @@ export async function getHealthCheckStatusHistory(
const entityType = "health_check"; const entityType = "health_check";
const entityId = parsedParams.data.healthCheckId; const entityId = parsedParams.data.healthCheckId;
const { days } = parsedQuery.data; const { days, tzOffsetMinutes } = parsedQuery.data;
const data = await getCachedStatusHistory(entityType, entityId, days); const data = await getCachedStatusHistory(
entityType,
entityId,
days,
tzOffsetMinutes
);
return response<StatusHistoryResponse>(res, { return response<StatusHistoryResponse>(res, {
data, data,
+318 -2
View File
@@ -58,7 +58,8 @@ import {
resourceRules, resourceRules,
resourcePolicyRules, resourcePolicyRules,
userOrgRoles, userOrgRoles,
roles roles,
resourceAccessToken
} from "@server/db"; } from "@server/db";
import { eq, and, inArray, isNotNull, isNull, ne, or, sql } from "drizzle-orm"; import { eq, and, inArray, isNotNull, isNull, ne, or, sql } from "drizzle-orm";
import { alias } from "@server/db"; import { alias } from "@server/db";
@@ -81,11 +82,16 @@ import config from "@server/lib/config";
import { exchangeSession } from "@server/routers/badger"; import { exchangeSession } from "@server/routers/badger";
import { import {
ResourceSessionValidationResult, ResourceSessionValidationResult,
createResourceSession,
serializeResourceSessionCookie,
validateResourceSessionToken validateResourceSessionToken
} from "@server/auth/sessions/resource"; } from "@server/auth/sessions/resource";
import { checkExitNodeOrg, resolveExitNodes } from "#private/lib/exitNodes"; import { checkExitNodeOrg, resolveExitNodes } from "#private/lib/exitNodes";
import { maxmindLookup } from "@server/db/maxmind"; import { maxmindLookup } from "@server/db/maxmind";
import { verifyResourceAccessToken } from "@server/auth/verifyResourceAccessToken"; import { verifyResourceAccessToken } from "@server/auth/verifyResourceAccessToken";
import { generateSessionToken } from "@server/auth/sessions/app";
import { logAccessAudit } from "#private/lib/logAccessAudit";
import { getUserOrgRoles } from "@server/lib/userOrgRoles";
import semver from "semver"; import semver from "semver";
import { maxmindAsnLookup } from "@server/db/maxmindAsn"; import { maxmindAsnLookup } from "@server/db/maxmindAsn";
import { checkOrgAccessPolicy } from "@server/lib/checkOrgAccessPolicy"; import { checkOrgAccessPolicy } from "@server/lib/checkOrgAccessPolicy";
@@ -178,6 +184,73 @@ const validateResourceAccessTokenBodySchema = z.strictObject({
accessToken: z.string() accessToken: z.string()
}); });
const createAccessTokenSessionParamsSchema = z.strictObject({
resourceId: z.coerce.number().int().positive()
});
const createAccessTokenSessionBodySchema = z.strictObject({
accessTokenId: z.string().min(1)
});
const getAccessTokenParamsSchema = z.strictObject({
accessTokenId: z.string().min(1)
});
const logAccessAuditBodySchema = z.strictObject({
action: z.boolean(),
type: z.string(),
orgId: z.string(),
resourceId: z.number().optional(),
siteResourceId: z.number().optional(),
user: z
.object({
username: z.string(),
userId: z.string()
})
.optional(),
apiKey: z
.object({
name: z.string().nullable(),
apiKeyId: z.string()
})
.optional(),
metadata: z.any().optional(),
userAgent: z.string().optional(),
requestIp: z.string().optional()
});
type AccessTokenUserData = {
userId: string;
username: string;
email: string | null;
name: string | null;
role: string | null;
};
async function resolveAccessTokenUserData(
userId: string,
orgId: string
): Promise<AccessTokenUserData | undefined> {
const [user] = await db
.select()
.from(users)
.where(eq(users.userId, userId))
.limit(1);
if (!user) {
return undefined;
}
const userOrgRoles = await getUserOrgRoles(user.userId, orgId);
return {
userId: user.userId,
username: user.username,
email: user.email,
name: user.name,
role: userOrgRoles.map((r) => r.roleName).join(", ") || null
};
}
// Certificates by domains query validation // Certificates by domains query validation
const getCertificatesByDomainsQuerySchema = z.strictObject({ const getCertificatesByDomainsQuerySchema = z.strictObject({
// Accept domains as string or array (domains or domains[]) // Accept domains as string or array (domains or domains[])
@@ -1695,6 +1768,7 @@ hybridRouter.get(
) { ) {
for (const rule of rules) { for (const rule of rules) {
if (rule.match == "COUNTRY") { if (rule.match == "COUNTRY") {
// @ts-expect-error this is for backward compatibility
rule.match = "GEOIP"; rule.match = "GEOIP";
} }
} }
@@ -1828,8 +1902,23 @@ hybridRouter.post(
resourceId resourceId
}); });
let userData: AccessTokenUserData | undefined;
if (
result.valid &&
result.tokenItem?.userId &&
result.tokenItem.orgId
) {
userData = await resolveAccessTokenUserData(
result.tokenItem.userId,
result.tokenItem.orgId
);
}
return response(res, { return response(res, {
data: result, data: {
...result,
userData
},
success: true, success: true,
error: false, error: false,
message: result.valid message: result.valid
@@ -1849,6 +1938,233 @@ hybridRouter.post(
} }
); );
// Create a resource session from a valid access token (for remote nodes)
hybridRouter.post(
"/resource/:resourceId/session/create-access-token",
async (req: Request, res: Response, next: NextFunction) => {
try {
const parsedParams = createAccessTokenSessionParamsSchema.safeParse(
req.params
);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const parsedBody = createAccessTokenSessionBodySchema.safeParse(
req.body
);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const { resourceId } = parsedParams.data;
const { accessTokenId } = parsedBody.data;
const [tokenItem] = await db
.select()
.from(resourceAccessToken)
.where(eq(resourceAccessToken.accessTokenId, accessTokenId))
.limit(1);
if (!tokenItem || tokenItem.resourceId !== resourceId) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
"Access token not found"
)
);
}
if (!tokenItem.persistSession) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"Access token does not allow session persistence"
)
);
}
const [resource] = await db
.select()
.from(resources)
.where(eq(resources.resourceId, resourceId))
.limit(1);
if (!resource || !resource.fullDomain) {
return next(
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
);
}
const token = generateSessionToken();
const sess = await createResourceSession({
resourceId: resource.resourceId,
token,
accessTokenId: tokenItem.accessTokenId,
sessionLength: tokenItem.sessionLength,
expiresAt: tokenItem.expiresAt,
doNotExtend: tokenItem.expiresAt ? true : false
});
const cookieName = config.getRawConfig().server.session_cookie_name;
const cookie = serializeResourceSessionCookie(
cookieName,
resource.fullDomain,
token,
!resource.ssl,
new Date(sess.expiresAt)
);
return response(res, {
data: { cookie },
success: true,
error: false,
message: "Access token session created successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to create access token session"
)
);
}
}
);
// Resolve access token metadata for remote nodes (cookie session path)
hybridRouter.get(
"/resource/access-token/:accessTokenId",
async (req: Request, res: Response, next: NextFunction) => {
try {
const parsedParams = getAccessTokenParamsSchema.safeParse(
req.params
);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { accessTokenId } = parsedParams.data;
const [tokenItem] = await db
.select()
.from(resourceAccessToken)
.where(eq(resourceAccessToken.accessTokenId, accessTokenId))
.limit(1);
if (!tokenItem) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
"Access token not found"
)
);
}
let userData: AccessTokenUserData | undefined;
if (tokenItem.userId) {
userData = await resolveAccessTokenUserData(
tokenItem.userId,
tokenItem.orgId
);
}
return response(res, {
data: { tokenItem, userData },
success: true,
error: false,
message: "Access token retrieved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to get access token"
)
);
}
}
);
// Access audit log from remote nodes
hybridRouter.post(
"/logs/access",
async (req: Request, res: Response, next: NextFunction) => {
try {
const parsedBody = logAccessAuditBodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const remoteExitNode = req.remoteExitNode;
if (!remoteExitNode || !remoteExitNode.exitNodeId) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"Remote exit node not found"
)
);
}
if (
await checkExitNodeOrg(
remoteExitNode.exitNodeId,
parsedBody.data.orgId
)
) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Exit node not allowed for this organization"
)
);
}
await logAccessAudit(parsedBody.data);
return response(res, {
data: null,
success: true,
error: false,
message: "Access audit log saved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to save access audit log"
)
);
}
}
);
const geoIpLookupParamsSchema = z.object({ const geoIpLookupParamsSchema = z.object({
ip: z.union([z.ipv4(), z.ipv6()]) ip: z.union([z.ipv4(), z.ipv6()])
}); });
+44
View File
@@ -16,6 +16,7 @@ import * as org from "#private/routers/org";
import * as logs from "#private/routers/auditLogs"; import * as logs from "#private/routers/auditLogs";
import * as alertEvents from "#private/routers/alertEvents"; import * as alertEvents from "#private/routers/alertEvents";
import * as certificates from "#private/routers/certificates"; import * as certificates from "#private/routers/certificates";
import * as siteProvisioning from "#private/routers/siteProvisioning";
import { import {
verifyApiKeyHasAction, verifyApiKeyHasAction,
@@ -24,6 +25,7 @@ import {
verifyApiKeyIdpAccess, verifyApiKeyIdpAccess,
verifyApiKeyRoleAccess, verifyApiKeyRoleAccess,
verifyApiKeyUserAccess, verifyApiKeyUserAccess,
verifyApiKeySiteProvisioningKeyAccess,
verifyLimits verifyLimits
} from "@server/middlewares"; } from "@server/middlewares";
import * as user from "#private/routers/user"; import * as user from "#private/routers/user";
@@ -215,3 +217,45 @@ authenticated.delete(
logActionAudit(ActionsEnum.removeUserRole), logActionAudit(ActionsEnum.removeUserRole),
user.removeUserRole user.removeUserRole
); );
authenticated.put(
"/org/:orgId/site-provisioning-key",
verifyValidLicense,
verifyValidSubscription(tierMatrix.siteProvisioningKeys),
verifyApiKeyOrgAccess,
verifyLimits,
verifyApiKeyHasAction(ActionsEnum.createSiteProvisioningKey),
logActionAudit(ActionsEnum.createSiteProvisioningKey),
siteProvisioning.createSiteProvisioningKey
);
authenticated.get(
"/org/:orgId/site-provisioning-keys",
verifyValidLicense,
verifyValidSubscription(tierMatrix.siteProvisioningKeys),
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.listSiteProvisioningKeys),
siteProvisioning.listSiteProvisioningKeys
);
authenticated.delete(
"/org/:orgId/site-provisioning-key/:siteProvisioningKeyId",
verifyValidLicense,
verifyValidSubscription(tierMatrix.siteProvisioningKeys),
verifyApiKeyOrgAccess,
verifyApiKeySiteProvisioningKeyAccess,
verifyApiKeyHasAction(ActionsEnum.deleteSiteProvisioningKey),
logActionAudit(ActionsEnum.deleteSiteProvisioningKey),
siteProvisioning.deleteSiteProvisioningKey
);
authenticated.patch(
"/org/:orgId/site-provisioning-key/:siteProvisioningKeyId",
verifyValidLicense,
verifyValidSubscription(tierMatrix.siteProvisioningKeys),
verifyApiKeyOrgAccess,
verifyApiKeySiteProvisioningKeyAccess,
verifyApiKeyHasAction(ActionsEnum.updateSiteProvisioningKey),
logActionAudit(ActionsEnum.updateSiteProvisioningKey),
siteProvisioning.updateSiteProvisioningKey
);
-19
View File
@@ -1,19 +0,0 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 "./listOrgLabels";
export * from "./createOrgLabel";
export * from "./updateOrgLabel";
export * from "./attachLabelToItem";
export * from "./detachLabelFromItem";
export * from "./deleteOrgLabel";
@@ -215,7 +215,7 @@ export async function sendTrialNotification(
if (resetLimits) { if (resetLimits) {
// this will only fire if they have not upgraded yet because when upgrading we delete the trial // this will only fire if they have not upgraded yet because when upgrading we delete the trial
await handleSubscriptionLifesycle(orgId, "cancled"); await handleSubscriptionLifesycle(orgId, "canceled");
logger.debug( logger.debug(
`Trial ended for org ${orgId}, limits reset to free tier` `Trial ended for org ${orgId}, limits reset to free tier`
); );
@@ -23,6 +23,7 @@ import { and, eq, sql } from "drizzle-orm";
import { removeUserFromOrg } from "@server/lib/userOrg"; import { removeUserFromOrg } from "@server/lib/userOrg";
import { calculateUserClientsForOrgs } from "@server/lib/calculateUserClientsForOrgs"; import { calculateUserClientsForOrgs } from "@server/lib/calculateUserClientsForOrgs";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { isOrgRebuildRateLimited } from "@server/lib/rebuildClientAssociations";
const paramsSchema = z const paramsSchema = z
.object({ .object({
@@ -90,6 +91,15 @@ export async function unassociateOrgIdp(
); );
} }
if (await isOrgRebuildRateLimited(org.orgId)) {
return next(
createHttpError(
HttpCode.TOO_MANY_REQUESTS,
"Too many concurrent rebuild operations for this organization. Please retry after a moment."
)
);
}
const orgUsersFromIdp = await db const orgUsersFromIdp = await db
.select({ .select({
userId: userOrgs.userId, userId: userOrgs.userId,
@@ -35,7 +35,7 @@ import logger from "@server/logger";
import { and, eq, inArray, ne } from "drizzle-orm"; import { and, eq, inArray, ne } from "drizzle-orm";
import { getNextAvailableSubnet } from "@server/lib/exitNodes"; import { getNextAvailableSubnet } from "@server/lib/exitNodes";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { LimitId } from "@server/lib/billing";
import { CreateRemoteExitNodeResponse } from "@server/routers/remoteExitNode/types"; import { CreateRemoteExitNodeResponse } from "@server/routers/remoteExitNode/types";
export const paramsSchema = z.object({ export const paramsSchema = z.object({
@@ -79,7 +79,10 @@ export async function createRemoteExitNode(
const { remoteExitNodeId, secret } = parsedBody.data; const { remoteExitNodeId, secret } = parsedBody.data;
if (req.user && (!req.userOrgRoleIds || req.userOrgRoleIds.length === 0)) { if (
req.user &&
(!req.userOrgRoleIds || req.userOrgRoleIds.length === 0)
) {
return next( return next(
createHttpError(HttpCode.FORBIDDEN, "User does not have a role") createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
); );
@@ -87,13 +90,13 @@ export async function createRemoteExitNode(
const usage = await usageService.getUsage( const usage = await usageService.getUsage(
orgId, orgId,
FeatureId.REMOTE_EXIT_NODES LimitId.REMOTE_EXIT_NODES
); );
if (usage) { if (usage) {
const rejectRemoteExitNodes = await usageService.checkLimitSet( const rejectRemoteExitNodes = await usageService.checkLimitSet(
orgId, orgId,
FeatureId.REMOTE_EXIT_NODES, LimitId.REMOTE_EXIT_NODES,
{ {
...usage, ...usage,
instantaneousValue: (usage.instantaneousValue || 0) + 1 instantaneousValue: (usage.instantaneousValue || 0) + 1
@@ -111,8 +114,6 @@ export async function createRemoteExitNode(
} }
const secretHash = await hashPassword(secret); const secretHash = await hashPassword(secret);
// const address = await getNextAvailableSubnet();
const address = "100.89.140.1/24"; // FOR NOW LETS HARDCODE THESE ADDRESSES
const [existingRemoteExitNode] = await db const [existingRemoteExitNode] = await db
.select() .select()
@@ -188,89 +189,106 @@ export async function createRemoteExitNode(
); );
} }
await db.transaction(async (trx) => { // If this remote exit node isn't already backing an exit node in
if (!existingExitNode) { // another org, we're about to create a brand new one. Reserve a
const [res] = await trx // subnet for it up front so the allocation lock is held across the
.insert(exitNodes) // whole insert - this guarantees exit node subnets never overlap,
.values({ // even under concurrent creation, which matters for HA setups.
name: remoteExitNodeId, let releaseSubnetLock: (() => Promise<void>) | null = null;
address, let newExitNodeAddress: string | null = null;
endpoint: "", if (!existingExitNode) {
publicKey: "", const { value, release } = await getNextAvailableSubnet();
listenPort: 0, newExitNodeAddress = value;
online: false, releaseSubnetLock = release;
type: "remoteExitNode" }
})
.returning();
existingExitNode = res;
}
if (!existingRemoteExitNode) { try {
await trx.insert(remoteExitNodes).values({ await db.transaction(async (trx) => {
remoteExitNodeId: remoteExitNodeId, if (!existingExitNode) {
secretHash, const [res] = await trx
dateCreated: moment().toISOString(), .insert(exitNodes)
exitNodeId: existingExitNode.exitNodeId .values({
}); name: remoteExitNodeId,
} else { address: newExitNodeAddress!,
// update the existing remote exit node endpoint: "",
await trx publicKey: "",
.update(remoteExitNodes) listenPort: 0,
.set({ online: false,
exitNodeId: existingExitNode.exitNodeId type: "remoteExitNode"
}) })
.where( .returning();
eq( existingExitNode = res;
remoteExitNodes.remoteExitNodeId,
existingRemoteExitNode.remoteExitNodeId
)
);
}
if (!existingExitNodeOrg) {
await trx.insert(exitNodeOrgs).values({
exitNodeId: existingExitNode.exitNodeId,
orgId: orgId
});
}
// calculate if the node is in any other of the orgs before we count it as an add to the billing org
if (org.billingOrgId) {
const otherBillingOrgs = await trx
.select()
.from(orgs)
.where(
and(
eq(orgs.billingOrgId, org.billingOrgId),
ne(orgs.orgId, orgId)
)
);
const billingOrgIds = otherBillingOrgs.map((o) => o.orgId);
const orgsInBillingDomainThatTheNodeIsStillIn = await trx
.select()
.from(exitNodeOrgs)
.where(
and(
eq(
exitNodeOrgs.exitNodeId,
existingExitNode.exitNodeId
),
inArray(exitNodeOrgs.orgId, billingOrgIds)
)
);
if (orgsInBillingDomainThatTheNodeIsStillIn.length === 0) {
await usageService.add(
orgId,
FeatureId.REMOTE_EXIT_NODES,
1,
trx
);
} }
}
}); if (!existingRemoteExitNode) {
await trx.insert(remoteExitNodes).values({
remoteExitNodeId: remoteExitNodeId,
secretHash,
dateCreated: moment().toISOString(),
exitNodeId: existingExitNode.exitNodeId
});
} else {
// update the existing remote exit node
await trx
.update(remoteExitNodes)
.set({
exitNodeId: existingExitNode.exitNodeId
})
.where(
eq(
remoteExitNodes.remoteExitNodeId,
existingRemoteExitNode.remoteExitNodeId
)
);
}
if (!existingExitNodeOrg) {
await trx.insert(exitNodeOrgs).values({
exitNodeId: existingExitNode.exitNodeId,
orgId: orgId
});
}
// calculate if the node is in any other of the orgs before we count it as an add to the billing org
if (org.billingOrgId) {
const otherBillingOrgs = await trx
.select()
.from(orgs)
.where(
and(
eq(orgs.billingOrgId, org.billingOrgId),
ne(orgs.orgId, orgId)
)
);
const billingOrgIds = otherBillingOrgs.map((o) => o.orgId);
const orgsInBillingDomainThatTheNodeIsStillIn = await trx
.select()
.from(exitNodeOrgs)
.where(
and(
eq(
exitNodeOrgs.exitNodeId,
existingExitNode.exitNodeId
),
inArray(exitNodeOrgs.orgId, billingOrgIds)
)
);
if (orgsInBillingDomainThatTheNodeIsStillIn.length === 0) {
await usageService.add(
orgId,
LimitId.REMOTE_EXIT_NODES,
1,
trx
);
}
}
});
} finally {
await releaseSubnetLock?.();
}
const token = generateSessionToken(); const token = generateSessionToken();
await createRemoteExitNodeSession(token, remoteExitNodeId); await createRemoteExitNodeSession(token, remoteExitNodeId);
@@ -22,7 +22,7 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { LimitId } from "@server/lib/billing";
const paramsSchema = z.strictObject({ const paramsSchema = z.strictObject({
orgId: z.string().min(1), orgId: z.string().min(1),
@@ -117,7 +117,7 @@ export async function deleteRemoteExitNode(
if (orgsInBillingDomainThatTheNodeIsStillIn.length === 0) { if (orgsInBillingDomainThatTheNodeIsStillIn.length === 0) {
await usageService.add( await usageService.add(
orgId, orgId,
FeatureId.REMOTE_EXIT_NODES, LimitId.REMOTE_EXIT_NODES,
-1, -1,
trx trx
); );
@@ -23,3 +23,7 @@ export * from "./pickRemoteExitNodeDefaults";
export * from "./quickStartRemoteExitNode"; export * from "./quickStartRemoteExitNode";
export * from "./offlineChecker"; export * from "./offlineChecker";
export * from "./exitNodeReconnectScheduler"; export * from "./exitNodeReconnectScheduler";
export * from "./listRemoteExitNodeResources";
export * from "./setRemoteExitNodeResources";
export * from "./listRemoteExitNodePreferenceLabels";
export * from "./setRemoteExitNodePreferenceLabels";
@@ -0,0 +1,102 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 { NextFunction, Request, Response } from "express";
import { z } from "zod";
import {
db,
labels,
remoteExitNodePreferenceLabels,
remoteExitNodes
} 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 { ListRemoteExitNodePreferenceLabelsResponse } from "@server/routers/remoteExitNode";
const paramsSchema = z.strictObject({
orgId: z.string().min(1),
remoteExitNodeId: z.string().min(1)
});
export async function listRemoteExitNodePreferenceLabels(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { remoteExitNodeId } = parsedParams.data;
const [remoteExitNode] = await db
.select()
.from(remoteExitNodes)
.where(eq(remoteExitNodes.remoteExitNodeId, remoteExitNodeId))
.limit(1);
if (!remoteExitNode) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Remote exit node with ID ${remoteExitNodeId} not found`
)
);
}
const rows = await db
.select({
remoteExitNodePreferenceLabelId:
remoteExitNodePreferenceLabels.remoteExitNodePreferenceLabelId,
labelId: remoteExitNodePreferenceLabels.labelId,
name: labels.name,
color: labels.color
})
.from(remoteExitNodePreferenceLabels)
.innerJoin(
labels,
eq(labels.labelId, remoteExitNodePreferenceLabels.labelId)
)
.where(
eq(
remoteExitNodePreferenceLabels.remoteExitNodeId,
remoteExitNodeId
)
);
return response<ListRemoteExitNodePreferenceLabelsResponse>(res, {
data: { labels: rows },
success: true,
error: false,
message:
"Remote exit node preference labels retrieved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
@@ -0,0 +1,83 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 { NextFunction, Request, Response } from "express";
import { z } from "zod";
import { db, remoteExitNodeResources, remoteExitNodes } 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 { ListRemoteExitNodeResourcesResponse } from "@server/routers/remoteExitNode/types";
const paramsSchema = z.strictObject({
orgId: z.string().min(1),
remoteExitNodeId: z.string().min(1)
});
export async function listRemoteExitNodeResources(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { remoteExitNodeId } = parsedParams.data;
const [remoteExitNode] = await db
.select()
.from(remoteExitNodes)
.where(eq(remoteExitNodes.remoteExitNodeId, remoteExitNodeId))
.limit(1);
if (!remoteExitNode) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Remote exit node with ID ${remoteExitNodeId} not found`
)
);
}
const resources = await db
.select()
.from(remoteExitNodeResources)
.where(
eq(remoteExitNodeResources.remoteExitNodeId, remoteExitNodeId)
);
return response<ListRemoteExitNodeResourcesResponse>(res, {
data: { resources },
success: true,
error: false,
message: "Remote exit node resources retrieved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
@@ -0,0 +1,160 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 { NextFunction, Request, Response } from "express";
import { z } from "zod";
import {
db,
labels,
remoteExitNodePreferenceLabels,
remoteExitNodes
} from "@server/db";
import { and, eq, 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 { SetRemoteExitNodePreferenceLabelsResponse } from "@server/routers/remoteExitNode";
const paramsSchema = z.strictObject({
orgId: z.string().min(1),
remoteExitNodeId: z.string().min(1)
});
const bodySchema = z.strictObject({
labelIds: z.array(z.number().int().positive())
});
export type SetRemoteExitNodePreferenceLabelsBody = z.infer<typeof bodySchema>;
export async function setRemoteExitNodePreferenceLabels(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { orgId, remoteExitNodeId } = parsedParams.data;
const parsedBody = bodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const { labelIds } = parsedBody.data;
const [remoteExitNode] = await db
.select()
.from(remoteExitNodes)
.where(eq(remoteExitNodes.remoteExitNodeId, remoteExitNodeId))
.limit(1);
if (!remoteExitNode) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Remote exit node with ID ${remoteExitNodeId} not found`
)
);
}
// Validate all provided labelIds belong to this org
if (labelIds.length > 0) {
const existingLabels = await db
.select({ labelId: labels.labelId })
.from(labels)
.where(
and(
eq(labels.orgId, orgId),
inArray(labels.labelId, labelIds)
)
);
if (existingLabels.length !== labelIds.length) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"One or more label IDs are invalid or do not belong to this organization"
)
);
}
}
// Replace all preference labels atomically
await db
.delete(remoteExitNodePreferenceLabels)
.where(
eq(
remoteExitNodePreferenceLabels.remoteExitNodeId,
remoteExitNodeId
)
);
if (labelIds.length > 0) {
await db.insert(remoteExitNodePreferenceLabels).values(
labelIds.map((labelId) => ({
remoteExitNodeId,
labelId
}))
);
}
const rows = await db
.select({
remoteExitNodePreferenceLabelId:
remoteExitNodePreferenceLabels.remoteExitNodePreferenceLabelId,
labelId: remoteExitNodePreferenceLabels.labelId,
name: labels.name,
color: labels.color
})
.from(remoteExitNodePreferenceLabels)
.innerJoin(
labels,
eq(labels.labelId, remoteExitNodePreferenceLabels.labelId)
)
.where(
eq(
remoteExitNodePreferenceLabels.remoteExitNodeId,
remoteExitNodeId
)
);
return response<SetRemoteExitNodePreferenceLabelsResponse>(res, {
data: { labels: rows },
success: true,
error: false,
message: "Remote exit node preference labels updated successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
@@ -0,0 +1,153 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 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 { NextFunction, Request, Response } from "express";
import { z } from "zod";
import {
db,
newts,
remoteExitNodeResources,
remoteExitNodes,
sites
} 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 { sendToClientsBatch } from "#private/routers/ws";
import { canCompress } from "@server/lib/clientVersionChecks";
import { SetRemoteExitNodeResourcesResponse } from "@server/routers/remoteExitNode";
const paramsSchema = z.strictObject({
orgId: z.string().min(1),
remoteExitNodeId: z.string().min(1)
});
const cidrRegex =
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$|^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))$/;
const bodySchema = z.strictObject({
destinations: z.array(
z.string().regex(cidrRegex, "Must be a valid CIDR range")
)
});
export type SetRemoteExitNodeResourcesBody = z.infer<typeof bodySchema>;
export async function setRemoteExitNodeResources(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedParams = paramsSchema.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error).toString()
)
);
}
const { remoteExitNodeId } = parsedParams.data;
const parsedBody = bodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const { destinations } = parsedBody.data;
const [remoteExitNode] = await db
.select()
.from(remoteExitNodes)
.where(eq(remoteExitNodes.remoteExitNodeId, remoteExitNodeId))
.limit(1);
if (!remoteExitNode) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Remote exit node with ID ${remoteExitNodeId} not found`
)
);
}
// Replace all resources atomically
await db
.delete(remoteExitNodeResources)
.where(
eq(remoteExitNodeResources.remoteExitNodeId, remoteExitNodeId)
);
if (destinations.length > 0) {
await db.insert(remoteExitNodeResources).values(
destinations.map((destination) => ({
remoteExitNodeId,
destination
}))
);
}
const resources = await db
.select()
.from(remoteExitNodeResources)
.where(
eq(remoteExitNodeResources.remoteExitNodeId, remoteExitNodeId)
);
// Notify all newts connected to this remote exit node's exit node
if (remoteExitNode.exitNodeId) {
const connectedNewts = await db
.select({ newtId: newts.newtId, version: newts.version })
.from(newts)
.innerJoin(sites, eq(newts.siteId, sites.siteId))
.where(eq(sites.exitNodeId, remoteExitNode.exitNodeId));
await sendToClientsBatch(
connectedNewts.map(({ newtId, version }) => ({
clientId: newtId,
message: {
type: "newt/wg/subnets/update",
data: { subnets: destinations }
},
options: {
incrementConfigVersion: true,
compress: canCompress(version, "newt")
}
}))
);
}
return response<SetRemoteExitNodeResourcesResponse>(res, {
data: { resources },
success: true,
error: false,
message: "Remote exit node resources updated successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}
@@ -26,6 +26,8 @@ import {
import logger from "@server/logger"; import logger from "@server/logger";
import { hashPassword } from "@server/auth/password"; import { hashPassword } from "@server/auth/password";
import type { CreateSiteProvisioningKeyResponse } from "@server/routers/siteProvisioning/types"; import type { CreateSiteProvisioningKeyResponse } from "@server/routers/siteProvisioning/types";
import { createApiResponseSchema } from "@server/lib/openapi/createApiResponseSchema";
import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z.object({ const paramsSchema = z.object({
orgId: z.string().nonempty() orgId: z.string().nonempty()
@@ -34,10 +36,17 @@ const paramsSchema = z.object({
const bodySchema = z const bodySchema = z
.strictObject({ .strictObject({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
maxBatchSize: z.union([ maxBatchSize: z
z.null(), .union([
z.coerce.number().int().positive().max(1_000_000) z.null(),
]), z.coerce.number().int().positive().max(1_000_000)
])
.openapi({
type: "number",
default: null,
description:
"Maximum number of sites that can be provisioned in a single batch. If null, there is no limit."
}),
validUntil: z.string().max(255).optional(), validUntil: z.string().max(255).optional(),
approveNewSites: z.boolean().optional().default(true) approveNewSites: z.boolean().optional().default(true)
}) })
@@ -57,6 +66,49 @@ const bodySchema = z
export type CreateSiteProvisioningKeyBody = z.infer<typeof bodySchema>; export type CreateSiteProvisioningKeyBody = z.infer<typeof bodySchema>;
const CreateSiteProvisioningKeyResponseDataSchema = z.object({
siteProvisioningKeyId: z.string(),
orgId: z.string(),
name: z.string(),
siteProvisioningKey: z.string(),
lastChars: z.string(),
createdAt: z.string(),
lastUsed: z.string().nullable(),
maxBatchSize: z.number().nullable(),
numUsed: z.number(),
validUntil: z.string().nullable(),
approveNewSites: z.boolean()
});
registry.registerPath({
method: "put",
path: "/org/{orgId}/site-provisioning-key",
description: "Create a new site provisioning key for the organization.",
tags: [OpenAPITags.SiteProvisioningKey],
request: {
params: paramsSchema,
body: {
content: {
"application/json": {
schema: bodySchema
}
}
}
},
responses: {
201: {
description: "Successful response",
content: {
"application/json": {
schema: createApiResponseSchema(
CreateSiteProvisioningKeyResponseDataSchema
)
}
}
}
}
});
export async function createSiteProvisioningKey( export async function createSiteProvisioningKey(
req: Request, req: Request,
res: Response, res: Response,
@@ -13,23 +13,46 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
import { z } from "zod"; import { z } from "zod";
import { import { db, siteProvisioningKeyOrg, siteProvisioningKeys } from "@server/db";
db,
siteProvisioningKeyOrg,
siteProvisioningKeys
} from "@server/db";
import { and, eq } from "drizzle-orm"; import { and, eq } 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";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z.object({ const paramsSchema = z.object({
siteProvisioningKeyId: z.string().nonempty(), siteProvisioningKeyId: z.string().nonempty(),
orgId: z.string().nonempty() orgId: z.string().nonempty()
}); });
registry.registerPath({
method: "delete",
path: "/org/{orgId}/site-provisioning-key/{siteProvisioningKeyId}",
description: "Delete a site provisioning key.",
tags: [OpenAPITags.SiteProvisioningKey],
request: {
params: paramsSchema
},
responses: {
200: {
description: "Successful response",
content: {
"application/json": {
schema: z.object({
data: z.record(z.string(), z.any()).nullable(),
success: z.boolean(),
error: z.boolean(),
message: z.string(),
status: z.number()
})
}
}
}
}
});
export async function deleteSiteProvisioningKey( export async function deleteSiteProvisioningKey(
req: Request, req: Request,
res: Response, res: Response,
@@ -11,11 +11,7 @@
* This file is not licensed under the AGPLv3. * This file is not licensed under the AGPLv3.
*/ */
import { import { db, siteProvisioningKeyOrg, siteProvisioningKeys } from "@server/db";
db,
siteProvisioningKeyOrg,
siteProvisioningKeys
} 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";
import response from "@server/lib/response"; import response from "@server/lib/response";
@@ -25,6 +21,8 @@ import { z } from "zod";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import type { ListSiteProvisioningKeysResponse } from "@server/routers/siteProvisioning/types"; import type { ListSiteProvisioningKeysResponse } from "@server/routers/siteProvisioning/types";
import { createApiResponseSchema } from "@server/lib/openapi/createApiResponseSchema";
import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z.object({ const paramsSchema = z.object({
orgId: z.string().nonempty() orgId: z.string().nonempty()
@@ -45,11 +43,55 @@ const querySchema = z.object({
.pipe(z.int().nonnegative()) .pipe(z.int().nonnegative())
}); });
const ListSiteProvisioningKeysResponseDataSchema = z.object({
siteProvisioningKeys: z.array(
z.object({
siteProvisioningKeyId: z.string(),
orgId: z.string(),
lastChars: z.string(),
createdAt: z.string(),
name: z.string(),
lastUsed: z.string().nullable(),
maxBatchSize: z.number().nullable(),
numUsed: z.number(),
validUntil: z.string().nullable(),
approveNewSites: z.boolean()
})
),
pagination: z.object({
total: z.number(),
limit: z.number(),
offset: z.number()
})
});
registry.registerPath({
method: "get",
path: "/org/{orgId}/site-provisioning-keys",
description: "List all site provisioning keys for an organization.",
tags: [OpenAPITags.SiteProvisioningKey],
request: {
params: paramsSchema,
query: querySchema
},
responses: {
200: {
description: "Successful response",
content: {
"application/json": {
schema: createApiResponseSchema(
ListSiteProvisioningKeysResponseDataSchema
)
}
}
}
}
});
function querySiteProvisioningKeys(orgId: string) { function querySiteProvisioningKeys(orgId: string) {
return db return db
.select({ .select({
siteProvisioningKeyId: siteProvisioningKeyId: siteProvisioningKeys.siteProvisioningKeyId,
siteProvisioningKeys.siteProvisioningKeyId,
orgId: siteProvisioningKeyOrg.orgId, orgId: siteProvisioningKeyOrg.orgId,
lastChars: siteProvisioningKeys.lastChars, lastChars: siteProvisioningKeys.lastChars,
createdAt: siteProvisioningKeys.createdAt, createdAt: siteProvisioningKeys.createdAt,
@@ -13,11 +13,7 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
import { z } from "zod"; import { z } from "zod";
import { import { db, siteProvisioningKeyOrg, siteProvisioningKeys } from "@server/db";
db,
siteProvisioningKeyOrg,
siteProvisioningKeys
} from "@server/db";
import { and, eq } from "drizzle-orm"; import { and, eq } 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";
@@ -25,6 +21,8 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import type { UpdateSiteProvisioningKeyResponse } from "@server/routers/siteProvisioning/types"; import type { UpdateSiteProvisioningKeyResponse } from "@server/routers/siteProvisioning/types";
import { createApiResponseSchema } from "@server/lib/openapi/createApiResponseSchema";
import { OpenAPITags, registry } from "@server/openApi";
const paramsSchema = z.object({ const paramsSchema = z.object({
siteProvisioningKeyId: z.string().nonempty(), siteProvisioningKeyId: z.string().nonempty(),
@@ -38,7 +36,13 @@ const bodySchema = z
z.null(), z.null(),
z.coerce.number().int().positive().max(1_000_000) z.coerce.number().int().positive().max(1_000_000)
]) ])
.optional(), .optional()
.openapi({
type: "number",
default: null,
description:
"Maximum number of sites that can be provisioned in a single batch. If null, there is no limit."
}),
validUntil: z.string().max(255).optional(), validUntil: z.string().max(255).optional(),
approveNewSites: z.boolean().optional() approveNewSites: z.boolean().optional()
}) })
@@ -50,7 +54,8 @@ const bodySchema = z
) { ) {
ctx.addIssue({ ctx.addIssue({
code: "custom", code: "custom",
message: "Provide maxBatchSize and/or validUntil and/or approveNewSites", message:
"Provide maxBatchSize and/or validUntil and/or approveNewSites",
path: ["maxBatchSize"] path: ["maxBatchSize"]
}); });
} }
@@ -69,6 +74,48 @@ const bodySchema = z
export type UpdateSiteProvisioningKeyBody = z.infer<typeof bodySchema>; export type UpdateSiteProvisioningKeyBody = z.infer<typeof bodySchema>;
const UpdateSiteProvisioningKeyResponseDataSchema = z.object({
siteProvisioningKeyId: z.string(),
orgId: z.string(),
name: z.string(),
lastChars: z.string(),
createdAt: z.string(),
lastUsed: z.string().nullable(),
maxBatchSize: z.number().nullable(),
numUsed: z.number(),
validUntil: z.string().nullable(),
approveNewSites: z.boolean()
});
registry.registerPath({
method: "patch",
path: "/org/{orgId}/site-provisioning-key/{siteProvisioningKeyId}",
description: "Update a site provisioning key.",
tags: [OpenAPITags.SiteProvisioningKey],
request: {
params: paramsSchema,
body: {
content: {
"application/json": {
schema: bodySchema
}
}
}
},
responses: {
200: {
description: "Successful response",
content: {
"application/json": {
schema: createApiResponseSchema(
UpdateSiteProvisioningKeyResponseDataSchema
)
}
}
}
}
});
export async function updateSiteProvisioningKey( export async function updateSiteProvisioningKey(
req: Request, req: Request,
res: Response, res: Response,
+13 -1
View File
@@ -23,7 +23,10 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
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 { rebuildClientAssociationsFromClient } from "@server/lib/rebuildClientAssociations"; import {
rebuildClientAssociationsFromClient,
isOrgRebuildRateLimited
} from "@server/lib/rebuildClientAssociations";
const addUserRoleParamsSchema = z.strictObject({ const addUserRoleParamsSchema = z.strictObject({
userId: z.string(), userId: z.string(),
@@ -128,6 +131,15 @@ export async function addUserRole(
); );
} }
if (await isOrgRebuildRateLimited(role.orgId)) {
return next(
createHttpError(
HttpCode.TOO_MANY_REQUESTS,
"Too many concurrent rebuild operations for this organization. Please retry after a moment."
)
);
}
let newUserRole: { let newUserRole: {
userId: string; userId: string;
orgId: string; orgId: string;
+13 -1
View File
@@ -21,7 +21,10 @@ import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { rebuildClientAssociationsFromClient } from "@server/lib/rebuildClientAssociations"; import {
rebuildClientAssociationsFromClient,
isOrgRebuildRateLimited
} from "@server/lib/rebuildClientAssociations";
const setUserOrgRolesParamsSchema = z.strictObject({ const setUserOrgRolesParamsSchema = z.strictObject({
orgId: z.string(), orgId: z.string(),
@@ -87,6 +90,15 @@ export async function setUserOrgRoles(
); );
} }
if (await isOrgRebuildRateLimited(orgId)) {
return next(
createHttpError(
HttpCode.TOO_MANY_REQUESTS,
"Too many concurrent rebuild operations for this organization. Please retry after a moment."
)
);
}
const orgRoles = await db const orgRoles = await db
.select({ roleId: roles.roleId, isAdmin: roles.isAdmin }) .select({ roleId: roles.roleId, isAdmin: roles.isAdmin })
.from(roles) .from(roles)
+2 -2
View File
@@ -26,7 +26,7 @@ import {
} from "@server/db"; } from "@server/db";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "@server/db"; import { db } from "@server/db";
import { recordPing } from "@server/routers/newt/pingAccumulator"; import { recordSitePing } from "@server/routers/newt/pingAccumulator";
import { validateNewtSessionToken } from "@server/auth/sessions/newt"; import { validateNewtSessionToken } from "@server/auth/sessions/newt";
import { validateOlmSessionToken } from "@server/auth/sessions/olm"; import { validateOlmSessionToken } from "@server/auth/sessions/olm";
import logger from "@server/logger"; import logger from "@server/logger";
@@ -1063,7 +1063,7 @@ const setupConnection = async (
// pending pings in a single batched UPDATE every ~10s, which // pending pings in a single batched UPDATE every ~10s, which
// prevents connection pool exhaustion under load (especially // prevents connection pool exhaustion under load (especially
// with cross-region latency to the database). // with cross-region latency to the database).
recordPing(newtClient.siteId); recordSitePing(newtClient.siteId);
}); });
} }
@@ -1,4 +1,3 @@
import { hash } from "@node-rs/argon2";
import { import {
generateId, generateId,
generateIdFromEntropySize, generateIdFromEntropySize,
@@ -8,18 +7,18 @@ import { db } from "@server/db";
import { import {
ResourceAccessToken, ResourceAccessToken,
resourceAccessToken, resourceAccessToken,
resources resources,
userOrgs
} from "@server/db"; } from "@server/db";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import response from "@server/lib/response"; import response from "@server/lib/response";
import { eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import { z } from "zod"; import { z } from "zod";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import logger from "@server/logger"; import logger from "@server/logger";
import { createDate, TimeSpan } from "oslo"; import { createDate, TimeSpan } from "oslo";
import { hashPassword } from "@server/auth/password";
import { encodeHexLowerCase } from "@oslojs/encoding"; import { encodeHexLowerCase } from "@oslojs/encoding";
import { sha256 } from "@oslojs/crypto/sha2"; import { sha256 } from "@oslojs/crypto/sha2";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
@@ -28,7 +27,9 @@ export const generateAccessTokenBodySchema = z.strictObject({
validForSeconds: z.int().positive().optional(), // seconds validForSeconds: z.int().positive().optional(), // seconds
title: z.string().optional(), title: z.string().optional(),
path: z.string().optional(), path: z.string().optional(),
description: z.string().optional() description: z.string().optional(),
persistSession: z.boolean().optional().default(false),
userId: z.string().optional()
}); });
export const generateAccssTokenParamsSchema = z.strictObject({ export const generateAccssTokenParamsSchema = z.strictObject({
@@ -101,7 +102,14 @@ export async function generateAccessToken(
} }
const { resourceId } = parsedParams.data; const { resourceId } = parsedParams.data;
const { validForSeconds, title, path, description } = parsedBody.data; const {
validForSeconds,
title,
path,
description,
persistSession,
userId
} = parsedBody.data;
const [resource] = await db const [resource] = await db
.select() .select()
@@ -112,6 +120,28 @@ export async function generateAccessToken(
return next(createHttpError(HttpCode.NOT_FOUND, "Resource not found")); return next(createHttpError(HttpCode.NOT_FOUND, "Resource not found"));
} }
if (userId) {
const [membership] = await db
.select()
.from(userOrgs)
.where(
and(
eq(userOrgs.userId, userId),
eq(userOrgs.orgId, resource.orgId)
)
)
.limit(1);
if (!membership) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"User is not a member of this organization"
)
);
}
}
try { try {
const sessionLength = validForSeconds const sessionLength = validForSeconds
? validForSeconds * 1000 ? validForSeconds * 1000
@@ -133,23 +163,27 @@ export async function generateAccessToken(
accessTokenId: id, accessTokenId: id,
orgId: resource.orgId, orgId: resource.orgId,
resourceId, resourceId,
userId: userId || null,
tokenHash, tokenHash,
expiresAt: expiresAt || null, expiresAt: expiresAt || null,
sessionLength: sessionLength, sessionLength: sessionLength,
title: title || null, title: title || null,
path: path || null, path: path || null,
description: description || null, description: description || null,
persistSession,
createdAt: new Date().getTime() createdAt: new Date().getTime()
}) })
.returning({ .returning({
accessTokenId: resourceAccessToken.accessTokenId, accessTokenId: resourceAccessToken.accessTokenId,
orgId: resourceAccessToken.orgId, orgId: resourceAccessToken.orgId,
resourceId: resourceAccessToken.resourceId, resourceId: resourceAccessToken.resourceId,
userId: resourceAccessToken.userId,
expiresAt: resourceAccessToken.expiresAt, expiresAt: resourceAccessToken.expiresAt,
sessionLength: resourceAccessToken.sessionLength, sessionLength: resourceAccessToken.sessionLength,
title: resourceAccessToken.title, title: resourceAccessToken.title,
path: resourceAccessToken.path, path: resourceAccessToken.path,
description: resourceAccessToken.description, description: resourceAccessToken.description,
persistSession: resourceAccessToken.persistSession,
createdAt: resourceAccessToken.createdAt createdAt: resourceAccessToken.createdAt
}) })
.execute(); .execute();
+10 -2
View File
@@ -6,12 +6,13 @@ import {
userResources, userResources,
roleResources, roleResources,
resourceAccessToken, resourceAccessToken,
sites sites,
users
} from "@server/db"; } from "@server/db";
import response from "@server/lib/response"; import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import { sql, eq, or, inArray, and, count, isNull, lt, gt } from "drizzle-orm"; import { sql, eq, or, inArray, and, count, isNull, gt } from "drizzle-orm";
import logger from "@server/logger"; import logger from "@server/logger";
import stoi from "@server/lib/stoi"; import stoi from "@server/lib/stoi";
import { fromZodError } from "zod-validation-error"; import { fromZodError } from "zod-validation-error";
@@ -55,11 +56,16 @@ function queryAccessTokens(
accessTokenId: resourceAccessToken.accessTokenId, accessTokenId: resourceAccessToken.accessTokenId,
orgId: resourceAccessToken.orgId, orgId: resourceAccessToken.orgId,
resourceId: resourceAccessToken.resourceId, resourceId: resourceAccessToken.resourceId,
userId: resourceAccessToken.userId,
userName: users.name,
username: users.username,
userEmail: users.email,
sessionLength: resourceAccessToken.sessionLength, sessionLength: resourceAccessToken.sessionLength,
expiresAt: resourceAccessToken.expiresAt, expiresAt: resourceAccessToken.expiresAt,
tokenHash: resourceAccessToken.tokenHash, tokenHash: resourceAccessToken.tokenHash,
title: resourceAccessToken.title, title: resourceAccessToken.title,
description: resourceAccessToken.description, description: resourceAccessToken.description,
persistSession: resourceAccessToken.persistSession,
createdAt: resourceAccessToken.createdAt, createdAt: resourceAccessToken.createdAt,
resourceName: resources.name, resourceName: resources.name,
resourceNiceId: resources.niceId, resourceNiceId: resources.niceId,
@@ -75,6 +81,7 @@ function queryAccessTokens(
eq(resourceAccessToken.resourceId, resources.resourceId) eq(resourceAccessToken.resourceId, resources.resourceId)
) )
.leftJoin(sites, eq(resources.resourceId, sites.siteId)) .leftJoin(sites, eq(resources.resourceId, sites.siteId))
.leftJoin(users, eq(resourceAccessToken.userId, users.userId))
.where( .where(
and( and(
inArray( inArray(
@@ -97,6 +104,7 @@ function queryAccessTokens(
eq(resourceAccessToken.resourceId, resources.resourceId) eq(resourceAccessToken.resourceId, resources.resourceId)
) )
.leftJoin(sites, eq(resources.resourceId, sites.siteId)) .leftJoin(sites, eq(resources.resourceId, sites.siteId))
.leftJoin(users, eq(resourceAccessToken.userId, users.userId))
.where( .where(
and( and(
inArray( inArray(
+1
View File
@@ -68,6 +68,7 @@ export type QueryAccessAuditLogResponse = {
actorType: string | null; actorType: string | null;
actorId: string | null; actorId: string | null;
resourceId: number | null; resourceId: number | null;
siteResourceId: number | null;
resourceName: string | null; resourceName: string | null;
resourceNiceId: string | null; resourceNiceId: string | null;
ip: string | null; ip: string | null;
+2 -2
View File
@@ -20,7 +20,7 @@ import { getOrgTierData } from "#dynamic/lib/billing";
import { deleteOrgById, sendTerminationMessages } from "@server/lib/deleteOrg"; import { deleteOrgById, sendTerminationMessages } from "@server/lib/deleteOrg";
import { UserType } from "@server/types/UserTypes"; import { UserType } from "@server/types/UserTypes";
import { usageService } from "@server/lib/billing/usageService"; import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing"; import { LimitId } from "@server/lib/billing";
const deleteMyAccountBody = z.strictObject({ const deleteMyAccountBody = z.strictObject({
password: z.string().optional(), password: z.string().optional(),
@@ -220,7 +220,7 @@ export async function deleteMyAccount(
await trx.delete(users).where(eq(users.userId, userId)); await trx.delete(users).where(eq(users.userId, userId));
// loop through the other orgs and decrement the count // loop through the other orgs and decrement the count
for (const userOrg of otherOrgsTheUserWasIn) { for (const userOrg of otherOrgsTheUserWasIn) {
await usageService.add(userOrg.orgId, FeatureId.USERS, -1, trx); await usageService.add(userOrg.orgId, LimitId.USERS, -1, trx);
} }
}); });

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