Compare commits

..

368 Commits

Author SHA1 Message Date
Owen 6969671fc4 Log status inside of the trigger api calls 2026-04-21 14:04:38 -07:00
Owen e765f661a7 Fix errors 2026-04-21 12:17:24 -07:00
Owen 7da3719a00 Add descriptions and adjust ui 2026-04-21 12:09:19 -07:00
Owen 206b3a7d22 Adding external actions 2026-04-21 11:52:15 -07:00
Owen ed327626bb Working on newt compat 2026-04-21 09:47:20 -07:00
Owen b59262b7af Merge branch 'dev' into alerting-rules 2026-04-20 21:21:03 -07:00
Owen 8093904d47 Adjust ui 2026-04-20 21:20:45 -07:00
miloschwartz 66c0ed5bf0 slightly improve add user form 2026-04-20 21:15:55 -07:00
Owen 725603101b Support the all types in the schema and engine 2026-04-20 21:00:28 -07:00
miloschwartz 7f0264dec3 fix collapsed sidebar bottom padding issue 2026-04-20 20:48:50 -07:00
Owen 5e88862e29 Support all resources,sites,health checks 2026-04-20 20:48:14 -07:00
miloschwartz b3bc70875b fix count on list domains endpoint 2026-04-20 20:46:38 -07:00
miloschwartz 34dc4c2d07 remove tcp/udp text to reduce cloud confusion 2026-04-20 20:41:38 -07:00
miloschwartz 2ef7a709d3 use new tabs in devices modal 2026-04-20 20:36:15 -07:00
Owen d7a9e1a517 Polish the create and link to table 2026-04-20 20:14:25 -07:00
Owen f938e9c3c0 Paginate the tables with queries 2026-04-20 20:05:59 -07:00
Owen c8d560d78f Reorder sidebar 2026-04-20 18:25:04 -07:00
Owen 3641969dd4 Remove bruno 2026-04-20 18:23:43 -07:00
Owen 49b3163bbe Making form and lang better 2026-04-20 18:14:30 -07:00
Owen 1a36475afa Add inline creation 2026-04-20 18:02:14 -07:00
miloschwartz 335de04a4e adjust theme 2026-04-20 18:00:22 -07:00
Owen f38069623b Add resource 2026-04-20 17:48:44 -07:00
Owen 0a70896080 Add toggle types 2026-04-20 17:37:01 -07:00
Owen 5a09062070 roleIds are numbers 2026-04-20 17:19:44 -07:00
miloschwartz 47be3dbdf9 hide add idp button when no mode set 2026-04-20 17:06:56 -07:00
Owen 9f5f89c9eb Remove debug log 2026-04-20 17:05:47 -07:00
Owen 2e8d170114 Hide protocol by default 2026-04-20 17:05:12 -07:00
Owen bf1787acd5 Merge branch 'dev' into alerting-rules 2026-04-20 16:54:20 -07:00
miloschwartz 78ff835ac9 Merge branch 'dev' of https://github.com/fosrl/pangolin into dev 2026-04-20 16:50:00 -07:00
miloschwartz 3c005c9ab1 rename log tabls for clarity and update font 2026-04-20 16:49:45 -07:00
Owen 54adcd2c56 Show the endpoint if its there 2026-04-20 15:08:48 -07:00
Owen 9a6408d28c Refresh domains for latest status 2026-04-20 14:57:24 -07:00
Owen 2dad97cb6b Add ability to predefine a root api key 2026-04-20 12:19:21 -07:00
Owen Schwartz 0ac97ecd5e Merge pull request #2877 from fosrl/dev
Fix import
2026-04-19 11:33:08 -07:00
Owen 387049beac Dynamic -> private import 2026-04-19 11:31:48 -07:00
Owen Schwartz c9240ecb84 Merge pull request #2876 from fosrl/dev
Update translations
2026-04-19 11:27:17 -07:00
Owen Schwartz b87e71c557 Merge pull request #2875 from fosrl/crowdin_dev
New Crowdin updates
2026-04-19 11:26:34 -07:00
Owen Schwartz 866293aa5a New translations en-us.json (Spanish) 2026-04-19 11:25:02 -07:00
Owen Schwartz e142dd32b4 New translations en-us.json (Norwegian Bokmal) 2026-04-19 11:25:00 -07:00
Owen Schwartz 949786dab5 New translations en-us.json (Chinese Simplified) 2026-04-19 11:24:59 -07:00
Owen Schwartz 2dd142b0e9 New translations en-us.json (Turkish) 2026-04-19 11:24:57 -07:00
Owen Schwartz dfd16a6752 New translations en-us.json (Russian) 2026-04-19 11:24:55 -07:00
Owen Schwartz f4454d4d48 New translations en-us.json (Portuguese) 2026-04-19 11:24:54 -07:00
Owen Schwartz e7efc917f0 New translations en-us.json (Polish) 2026-04-19 11:24:52 -07:00
Owen Schwartz 5ffe1ba07d New translations en-us.json (Dutch) 2026-04-19 11:24:51 -07:00
Owen Schwartz b56e2972c4 New translations en-us.json (Korean) 2026-04-19 11:24:49 -07:00
Owen Schwartz ca1a084397 New translations en-us.json (Italian) 2026-04-19 11:24:47 -07:00
Owen Schwartz a7a1f81e9d New translations en-us.json (German) 2026-04-19 11:24:46 -07:00
Owen Schwartz 9c09f17dc5 New translations en-us.json (Czech) 2026-04-19 11:24:44 -07:00
Owen Schwartz 21e2c022c7 New translations en-us.json (Bulgarian) 2026-04-19 11:24:42 -07:00
Owen Schwartz 222cbc886d New translations en-us.json (French) 2026-04-19 11:24:41 -07:00
miloschwartz db2e76bd31 Merge branch 'dev' of https://github.com/fosrl/pangolin into dev 2026-04-19 11:22:46 -07:00
Owen Schwartz bf32cc150d Merge pull request #2874 from fosrl/dev
1.17.1-s.5
2026-04-19 11:21:41 -07:00
miloschwartz 967de0b79f fix metadata for public resources 2026-04-19 11:19:23 -07:00
Owen 22231e6c45 Dont show home 2026-04-19 11:18:43 -07:00
miloschwartz 20ed9966b9 add better page metadata titles 2026-04-18 12:05:54 -07:00
Owen b2d5a1ffdf Remove weird extra status history component 2026-04-17 17:45:49 -07:00
Owen a5b8a44e78 Add the status to the resources and ajust location 2026-04-17 17:40:00 -07:00
miloschwartz dddf060e1a Merge branch 'cross-org-idp' into dev 2026-04-17 17:27:34 -07:00
Owen df8104fe56 Write the resource status as well 2026-04-17 17:25:51 -07:00
miloschwartz a569054e94 dont set org mapping by default 2026-04-17 17:25:21 -07:00
Owen 8214700eaa More refreshing and status history displays 2026-04-17 17:18:15 -07:00
miloschwartz 5885e8eb39 dont allow import idp if not paid 2026-04-17 17:14:21 -07:00
Owen 74165aa1cc Cleaning up ui 2026-04-17 17:01:55 -07:00
Owen 0872fd5818 Make the healch checks tabs 2026-04-17 15:38:38 -07:00
Owen 008ad0a1de Showing the paid feature 2026-04-17 15:33:26 -07:00
Owen f74791111e Paywalling 2026-04-17 15:14:01 -07:00
miloschwartz 22964cff0f fix sidebar footer on member page 2026-04-17 14:42:10 -07:00
miloschwartz e952c2d34a fix styles on enterprise edition banners 2026-04-17 14:36:10 -07:00
Owen 408eaf55f6 Merge branch 'dev' into alerting-rules 2026-04-17 14:29:36 -07:00
Owen 0a043af482 Delete update usage on orgs when user deletes
Fixes #2839
2026-04-17 14:28:43 -07:00
miloschwartz 8324445895 add auto provsion section back to create global idp 2026-04-17 10:59:24 -07:00
miloschwartz 796d14a9e4 support org mapping on org idp 2026-04-16 22:12:15 -07:00
Owen bd89867ecb Fix form not updating correctly 2026-04-16 21:42:48 -07:00
Owen 3645cc5759 Update websocket to be consistant with streaming 2026-04-16 21:27:06 -07:00
miloschwartz 707cc4b275 move idp mode check to a middleware 2026-04-16 21:00:48 -07:00
miloschwartz 93400ace27 import and unassocaite org idp 2026-04-16 20:58:18 -07:00
Owen f932cc7aca Fix status history and show on the health check 2026-04-16 20:55:21 -07:00
Owen c1782a2650 Add uptime tracking 2026-04-16 18:25:25 -07:00
Owen d6c15c8b81 Add resource column to hc and remove — 2026-04-16 17:42:30 -07:00
Owen b958537f3e Adjust the form 2026-04-16 17:05:25 -07:00
Owen 597cae2b78 Poll for status to show updates 2026-04-16 16:53:18 -07:00
Owen c4308aaa69 Working on ui 2026-04-16 16:30:28 -07:00
miloschwartz 6fb8dae966 adjust sidebar 2026-04-16 16:26:13 -07:00
Owen a9d68bd0cf Standardize the healch check form between the two 2026-04-16 16:20:30 -07:00
Owen 5fcb80a193 Merge branch 'dev' into alerting-rules 2026-04-16 15:53:43 -07:00
Owen a27a169160 Keep the cert around for a couple of cycles 2026-04-16 15:51:47 -07:00
Owen f0a1de3474 Show picker only when have remote node 2026-04-16 15:33:29 -07:00
Owen Schwartz 79c6fcac95 Merge pull request #2864 from fosrl/dev
1.17.1-s.4
2026-04-16 15:07:29 -07:00
Owen 50697e32c2 Simplify create site 2026-04-16 15:06:30 -07:00
Owen 6fe74a9f8d Allow clearing the instance name on the licenses 2026-04-16 14:44:16 -07:00
Owen a246de2b1f Allow create portal session for enterprise too 2026-04-16 14:44:16 -07:00
miloschwartz 5ac8e4e098 remove redundant pangolin text in footer in saas 2026-04-16 12:05:17 -07:00
Owen 57579e635c Working on alerting 2026-04-16 11:49:48 -07:00
Owen 1a1d1cfb83 Not null removed 2026-04-15 20:40:23 -07:00
Owen 1397e61643 Create hcs freely 2026-04-15 20:32:02 -07:00
Owen a04e2a5e00 Transititioning the hc table and firing the alerts 2026-04-15 17:46:04 -07:00
Owen b169a872a7 Fix header 2026-04-15 16:40:15 -07:00
Owen 1d4b2b1da1 seperate out the offline checker logic 2026-04-15 16:40:04 -07:00
Owen ad15b7c3c6 Add new intervals and tcp mode to health checks 2026-04-15 16:31:15 -07:00
Owen b070570cb6 Sites and health checks are many to one 2026-04-15 15:57:25 -07:00
Owen 55595ec042 Trying to use more consistant components 2026-04-15 15:51:41 -07:00
Owen 5e505224d0 Basic ui is working 2026-04-15 15:26:27 -07:00
Owen 3c6775992d Merge branch 'private-http-ha' into alerting-rules 2026-04-15 14:59:50 -07:00
Owen bf64e226d3 Many to one on sites and health checks 2026-04-15 14:58:33 -07:00
Owen f379986a59 Allow many to one on the receipients on the rules 2026-04-15 14:48:50 -07:00
Owen 22ead84aa7 Update license year 2026-04-15 14:42:48 -07:00
Owen 570ff75164 Merge branch 'dev' into alerting-rules 2026-04-15 14:41:29 -07:00
Owen aa95e5bb86 Update year 2026-04-15 14:41:13 -07:00
Owen 87a554b6ef Add crud 2026-04-15 14:33:55 -07:00
Owen cf741a6f87 Add stub 2026-04-15 14:26:34 -07:00
Owen 7d50703c26 First pass 2026-04-14 21:58:36 -07:00
Owen 33182bcf85 Add init alert schema 2026-04-14 21:43:16 -07:00
Owen fb29efeff3 Merge branch 'dev' into alerting-rules 2026-04-14 21:10:10 -07:00
Owen Schwartz 7d13ed79b2 Merge pull request #2862 from fosrl/dev
1.17.3
2026-04-14 20:33:04 -07:00
Owen Schwartz c1f65c802c Merge pull request #2861 from fosrl/crowdin_dev
New Crowdin updates
2026-04-14 20:32:03 -07:00
Owen Schwartz bcc429221e New translations en-us.json (Spanish) 2026-04-14 20:30:58 -07:00
Owen Schwartz bd73609b9e New translations en-us.json (Norwegian Bokmal) 2026-04-14 20:30:56 -07:00
Owen Schwartz 2dbb21a7f2 New translations en-us.json (Chinese Simplified) 2026-04-14 20:30:55 -07:00
Owen Schwartz fe68533ff2 New translations en-us.json (Turkish) 2026-04-14 20:30:53 -07:00
Owen Schwartz 01a40daf38 New translations en-us.json (Russian) 2026-04-14 20:30:51 -07:00
Owen Schwartz 097744275f New translations en-us.json (Portuguese) 2026-04-14 20:30:49 -07:00
Owen Schwartz e481a4d847 New translations en-us.json (Polish) 2026-04-14 20:30:48 -07:00
Owen Schwartz 95c6bb4de6 New translations en-us.json (Dutch) 2026-04-14 20:30:46 -07:00
Owen Schwartz 18e194e152 New translations en-us.json (Korean) 2026-04-14 20:30:44 -07:00
Owen Schwartz b2f391307b New translations en-us.json (Italian) 2026-04-14 20:30:43 -07:00
Owen Schwartz a4da3c7ba2 New translations en-us.json (German) 2026-04-14 20:30:41 -07:00
Owen Schwartz af3abef3bf New translations en-us.json (Czech) 2026-04-14 20:30:39 -07:00
Owen Schwartz f7633a43ce New translations en-us.json (Bulgarian) 2026-04-14 20:30:38 -07:00
Owen Schwartz ffd345f044 New translations en-us.json (French) 2026-04-14 20:30:36 -07:00
Owen ae36d3228f Remove journal 2026-04-14 20:23:56 -07:00
Owen 1c78a6b483 Adjust self serve 2026-04-14 20:21:34 -07:00
Owen Schwartz b6c6590aad New translations en-us.json (Norwegian Bokmal) 2026-04-14 19:48:12 -07:00
Owen Schwartz 5a792e9913 New translations en-us.json (Chinese Simplified) 2026-04-14 19:48:11 -07:00
Owen Schwartz a2f822889d New translations en-us.json (Turkish) 2026-04-14 19:48:09 -07:00
Owen Schwartz 83ba463a34 New translations en-us.json (Russian) 2026-04-14 19:48:07 -07:00
Owen Schwartz a909c5cbe0 New translations en-us.json (Portuguese) 2026-04-14 19:48:06 -07:00
Owen Schwartz d615f34f94 New translations en-us.json (Polish) 2026-04-14 19:48:04 -07:00
Owen Schwartz 37378895cf New translations en-us.json (Dutch) 2026-04-14 19:48:02 -07:00
Owen Schwartz 19ef055296 New translations en-us.json (Korean) 2026-04-14 19:48:00 -07:00
Owen Schwartz 599fa5eb30 New translations en-us.json (Italian) 2026-04-14 19:47:59 -07:00
Owen Schwartz 4d82b37cab New translations en-us.json (German) 2026-04-14 19:47:57 -07:00
Owen Schwartz 77d01d50db New translations en-us.json (Czech) 2026-04-14 19:47:55 -07:00
Owen Schwartz 013c1ab92c New translations en-us.json (Bulgarian) 2026-04-14 19:47:53 -07:00
Owen Schwartz d4fc60f2f4 New translations en-us.json (Spanish) 2026-04-14 19:47:52 -07:00
Owen Schwartz cd25cde47f New translations en-us.json (French) 2026-04-14 19:47:50 -07:00
Owen af709331fb Add missing DnsRecords type 2026-04-14 19:46:25 -07:00
Owen e20a21bacd Contact support 2026-04-14 19:46:19 -07:00
Owen 49ae5eecb6 Filter only approved sites 2026-04-13 21:56:35 -07:00
Owen 74b3b283f7 Fix #2848 2026-04-13 21:30:19 -07:00
Owen Schwartz 9fe4f78269 Merge pull request #2857 from fosrl/dev
Proxy targets returns an array
2026-04-13 20:57:15 -07:00
Owen 646e440dec Merge branch 'dev' into private-http-ha 2026-04-13 20:52:47 -07:00
Owen 03d95874e6 Proxy targets returns an array 2026-04-13 20:44:35 -07:00
Milo Schwartz bd3d6994c1 Merge pull request #2856 from fosrl/update-readme
fix image
2026-04-13 20:29:36 -07:00
miloschwartz 5fd78817a8 fix image 2026-04-13 20:28:05 -07:00
Owen 1b9a395432 Add logging for debugging 2026-04-13 17:56:55 -07:00
Owen 3996e14e70 Add comment 2026-04-13 17:56:51 -07:00
Owen 7a40084bf4 Rename for better understanding 2026-04-13 17:21:34 -07:00
Owen 30fd48a14a HA site crud working 2026-04-13 17:17:28 -07:00
Owen Schwartz 72bc125f84 Merge pull request #2854 from fosrl/dev
Rename script
2026-04-13 16:23:39 -07:00
Owen 5d51af4330 Rename script 2026-04-13 16:22:53 -07:00
Owen 173a81ead8 Fixing up the crud for multiple sites 2026-04-13 16:22:22 -07:00
Owen 676eacc9cf Invert logic for pangolin dns 2026-04-13 16:06:23 -07:00
Owen Schwartz b18ea66def Merge pull request #2853 from fosrl/dev
1.17.1-s.1
2026-04-13 12:28:08 -07:00
Owen 93998f9fd5 Fix ts issue 2026-04-13 12:27:29 -07:00
Owen c554e69514 Fill the width 2026-04-13 12:11:15 -07:00
Owen a6e10e55cc Handle grandfather on the front end 2026-04-13 12:08:30 -07:00
Owen Schwartz 41f541a531 Merge pull request #2852 from fosrl/dev
1.17.1-s.0
2026-04-13 11:36:36 -07:00
Owen 9cb1043545 Push back date 2026-04-13 11:33:51 -07:00
Owen Schwartz 96e33d33b0 Merge pull request #2851 from fosrl/crowdin_dev
New Crowdin updates
2026-04-13 11:25:53 -07:00
Owen Schwartz ccc7003ac1 New translations en-us.json (Spanish) 2026-04-13 11:24:32 -07:00
Owen Schwartz 93cbd47b5d New translations en-us.json (Norwegian Bokmal) 2026-04-13 11:24:30 -07:00
Owen Schwartz 8b808e44b6 New translations en-us.json (Chinese Simplified) 2026-04-13 11:24:28 -07:00
Owen Schwartz 0644e26297 New translations en-us.json (Turkish) 2026-04-13 11:24:27 -07:00
Owen Schwartz 682653b977 New translations en-us.json (Russian) 2026-04-13 11:24:25 -07:00
Owen Schwartz 0053cfc8fc New translations en-us.json (Portuguese) 2026-04-13 11:24:23 -07:00
Owen Schwartz 5cb62a30cc New translations en-us.json (Polish) 2026-04-13 11:24:21 -07:00
Owen Schwartz e596a63058 New translations en-us.json (Dutch) 2026-04-13 11:24:19 -07:00
Owen Schwartz 3ec32afb37 New translations en-us.json (Korean) 2026-04-13 11:24:17 -07:00
Owen Schwartz 0189a86757 New translations en-us.json (Italian) 2026-04-13 11:24:15 -07:00
Owen Schwartz ee32307654 New translations en-us.json (German) 2026-04-13 11:24:14 -07:00
Owen Schwartz 2f08e6b838 New translations en-us.json (Czech) 2026-04-13 11:24:12 -07:00
Owen Schwartz c8a3fc350d New translations en-us.json (Bulgarian) 2026-04-13 11:24:10 -07:00
Owen Schwartz dc63ef1284 New translations en-us.json (French) 2026-04-13 11:24:07 -07:00
Owen 92332fb02f Hide the home unless you have it 2026-04-13 11:17:14 -07:00
miloschwartz acc6a26654 update readme 2026-04-13 11:12:09 -07:00
Owen 2bd4d2faaf Merge branch 'main' into dev 2026-04-13 10:50:12 -07:00
Owen 1e77ead488 Adjust functioning of ee button 2026-04-13 10:49:57 -07:00
Owen 561a9ab379 Merge branch 'private-site-ha' into private-http-ha 2026-04-13 10:25:49 -07:00
Milo Schwartz c008ef7c1b Merge pull request #2850 from fosrl/miloschwartz-patch-1
Update README.md
2026-04-13 10:04:55 -07:00
Milo Schwartz 02dfeed3ce Update README.md 2026-04-13 13:03:53 -04:00
Owen Schwartz 34cc2e0ed1 Merge pull request #2841 from AdnanSilajdzic/fix/worldmap-typescript-followup
fix(worldmap): correct topojson feature typing
2026-04-13 09:42:05 -07:00
Owen 71497a7887 Merge branch 'dev' into private-site-ha 2026-04-12 17:54:07 -07:00
Owen aa41a63430 Dont run the acme in saas or when we control dns 2026-04-12 17:50:27 -07:00
Owen 0db55daff6 Merge branch 'private-http' of github.com:fosrl/pangolin into private-http 2026-04-12 17:47:59 -07:00
Owen 9b271950d2 Push down certs when they are detected 2026-04-12 17:31:51 -07:00
Owen 89b6b1fb56 Placeholder screen and certs are working 2026-04-12 16:49:49 -07:00
miloschwartz f5d0694574 change user devices column name from online to connected 2026-04-12 15:27:14 -07:00
miloschwartz f91da2ec46 fix no default idp selector showing on ce closes #2813 2026-04-12 15:20:09 -07:00
miloschwartz 89471a0174 include site name in target dropdown in public resources table 2026-04-12 15:09:40 -07:00
Owen 789b991c56 Logging and http working 2026-04-12 15:08:17 -07:00
miloschwartz 0cbcc0c29c remove extra sites query 2026-04-12 14:58:55 -07:00
miloschwartz b5e239d1ad adjust button size 2026-04-12 12:24:52 -07:00
miloschwartz 5f79e8ebbd Merge branch 'private-http' of https://github.com/fosrl/pangolin into private-http 2026-04-12 12:17:57 -07:00
miloschwartz 1564c4bee7 add multi site selector for ha on private resources 2026-04-12 12:17:45 -07:00
Owen 0cf385b718 CRUD and newt mode http mostly working 2026-04-12 12:15:29 -07:00
Adnan Silajdzic 0cb04d0290 fix(worldmap): correct topojson feature typing 2026-04-12 17:05:53 +00:00
Owen 83ecf53776 Add logging 2026-04-11 21:56:39 -07:00
Owen 5803da4893 Crud working 2026-04-11 21:09:12 -07:00
miloschwartz e118e5b047 add list alises endpoint 2026-04-11 21:03:35 -07:00
miloschwartz 7e4e8ea266 add niceId to list user resources 2026-04-11 17:56:16 -07:00
Owen fc4633db91 Add domain component to the site resource 2026-04-11 17:19:18 -07:00
Owen 2f386f8e47 Grandfather in old users 2026-04-11 16:59:43 -07:00
Owen f4ea572f6b Fix #2828 2026-04-11 16:50:28 -07:00
Owen Schwartz 825df7da63 Merge pull request #2806 from jbelke/fix-invite-email-encoding
Fix invite email encoding
2026-04-11 16:37:49 -07:00
Owen Schwartz cd34f0a7b0 Merge pull request #2799 from LaurenceJJones/fix/proxy-target-deletion
fix: use targetId as row identifier
2026-04-11 16:35:09 -07:00
Owen Schwartz b1b22c439a Merge pull request #2825 from AdnanSilajdzic/fix/worldmap-hover-stuck-public
fix(analytics): prevent countries from getting stuck highlighted on world map
2026-04-11 16:32:32 -07:00
Owen eac747849b Restrict namespaces to paid plans due to abuse 2026-04-11 14:22:00 -07:00
Owen 9e50569c31 Merge branch 'private-http' of github.com:fosrl/pangolin into private-http 2026-04-10 17:23:06 -04:00
Owen a19f0acfb9 Working 2026-04-10 17:21:54 -04:00
Adnan Silajdzic 1aedf9da0a fix(worldmap): avoid stuck country hover state 2026-04-10 14:37:48 +00:00
miloschwartz 8a47d69d0d fix domain picker 2026-04-09 22:48:43 -04:00
miloschwartz 73482c2a05 disable ssh access tab on http mode 2026-04-09 22:38:04 -04:00
miloschwartz 79751c208d basic ui working 2026-04-09 22:24:39 -04:00
Owen 510931e7d6 Add ssl to schema 2026-04-09 21:02:20 -04:00
Owen 584a8e7d1d Generate certs and add placeholder screen 2026-04-09 20:53:03 -04:00
miloschwartz a74378e1d3 show domain and destination with port in table 2026-04-09 18:17:08 -04:00
miloschwartz 840684aeba dont show wildcard in domain picker 2026-04-09 17:54:25 -04:00
Owen c027c8958b Add scheme 2026-04-09 17:54:17 -04:00
miloschwartz a730f4da1d dont show wildcard in domain picker 2026-04-09 17:54:08 -04:00
miloschwartz d73796b92e add new modes, port input, and domain picker 2026-04-09 17:49:22 -04:00
Owen 96b9123306 Merge branch 'dev' into private-site-ha 2026-04-09 17:39:45 -04:00
Owen e4cbf088b4 Working on defining the schema to send down 2026-04-09 17:23:24 -04:00
Owen 333ccb8438 Restrict to make sure there is an alias 2026-04-09 17:10:48 -04:00
miloschwartz f57012eb90 dont show international domain warning when capital letter present 2026-04-09 17:06:04 -04:00
miloschwartz 34387d9859 simplify wildcard domain on non pangolin-dns 2026-04-09 17:04:28 -04:00
Owen eb771ceda4 Add http to mode and put destinationPort back 2026-04-09 17:02:08 -04:00
miloschwartz 80f5914fdd add pluto 2026-04-09 16:15:19 -04:00
miloschwartz eaa70da4dd add pluto 2026-04-09 16:14:46 -04:00
Owen 1efd2af44b Sync acme certs into the database 2026-04-09 15:38:36 -04:00
Owen 466f137590 Fix migration by testing for orphans 2026-04-09 10:29:51 -04:00
Joshua Belke 028df8bf27 fix: remove encodeURIComponent from invite link email parameter
The @ symbol in email addresses was being encoded as %40 when
constructing invite URLs, causing broken or garbled links when
copied/shared by users.

- Remove encodeURIComponent(email) from server-side invite link
  construction in inviteUser.ts (both new invite and regenerate paths)
- Remove encodeURIComponent(email) from client-side redirect URLs in
  InviteStatusCard.tsx (login, signup, and useEffect redirect paths)
- Valid Zod-validated email addresses do not contain characters that
  require URL encoding for safe query parameter use (@ is permitted
  in query strings per RFC 3986 §3.4)
2026-04-07 14:58:27 -04:00
Owen 28ef5238c9 Add CODEOWNERS 2026-04-07 11:36:02 -04:00
Laurence 7d3d5b2b22 use targetid also on proxy create as that also has same issue 2026-04-06 14:17:04 +01:00
Laurence 81eba50c9a fix: use targetId as row identifier
fix: 2797
2026-04-06 14:03:33 +01:00
Owen Schwartz 3436105bec Merge pull request #2784 from fosrl/dev
Try to prevent deadlocks
2026-04-03 23:01:09 -04:00
Owen d948d2ec33 Try to prevent deadlocks 2026-04-03 22:55:04 -04:00
Owen Schwartz 4b3375ab8e Merge pull request #2783 from fosrl/dev
Fix 1.17.0
2026-04-03 22:42:03 -04:00
Owen 6b8a3c8d77 Revert #2570
Fix #2782
2026-04-03 22:37:42 -04:00
Owen ba9794c067 Put middleware back
Fix #2781
2026-04-03 22:16:26 -04:00
Owen Schwartz 6ce165bfd5 Merge pull request #2780 from fosrl/dev
1.17.0
2026-04-03 18:19:40 -04:00
Owen eb4b2daaab Use the right encryption 2026-04-03 17:59:21 -04:00
Owen 8cbc8dec89 Generate address 2026-04-03 17:25:39 -04:00
Owen e89e60d50b Encrypt the streaming data 2026-04-03 15:33:29 -04:00
Owen c45308f234 Send to the right place 2026-04-03 15:33:29 -04:00
Owen Schwartz 40205c40c5 Merge pull request #2779 from fosrl/crowdin_dev
New Crowdin updates
2026-04-03 15:00:11 -04:00
Owen Schwartz f3fe2dd33b New translations en-us.json (Spanish) 2026-04-03 14:58:56 -04:00
Owen Schwartz 8edcc45033 New translations en-us.json (Norwegian Bokmal) 2026-04-03 14:58:55 -04:00
Owen Schwartz 91471a4aca New translations en-us.json (Chinese Simplified) 2026-04-03 14:58:53 -04:00
Owen Schwartz ae2c37a2f6 New translations en-us.json (Turkish) 2026-04-03 14:58:52 -04:00
Owen Schwartz c8208f0a88 New translations en-us.json (Russian) 2026-04-03 14:58:50 -04:00
Owen Schwartz e11dfbd29c New translations en-us.json (Portuguese) 2026-04-03 14:58:49 -04:00
Owen Schwartz b375d20598 New translations en-us.json (Polish) 2026-04-03 14:58:48 -04:00
Owen Schwartz c4b82c69f8 New translations en-us.json (Dutch) 2026-04-03 14:58:47 -04:00
Owen Schwartz c9a00420a0 New translations en-us.json (Korean) 2026-04-03 14:58:45 -04:00
Owen Schwartz 36ef9cd442 New translations en-us.json (Italian) 2026-04-03 14:58:44 -04:00
Owen Schwartz 5e08779ab0 New translations en-us.json (German) 2026-04-03 14:58:42 -04:00
Owen Schwartz 16a0e1ce7b New translations en-us.json (Czech) 2026-04-03 14:58:41 -04:00
Owen Schwartz 8b03484ade New translations en-us.json (Bulgarian) 2026-04-03 14:58:39 -04:00
Owen Schwartz 9da9974adf New translations en-us.json (French) 2026-04-03 14:58:38 -04:00
Owen Schwartz 6f80cf3db2 New translations en-us.json (Spanish) 2026-04-03 13:03:44 -04:00
Owen Schwartz 76d8f44779 New translations en-us.json (Norwegian Bokmal) 2026-04-03 13:03:43 -04:00
Owen Schwartz 700c92efcb New translations en-us.json (Chinese Simplified) 2026-04-03 13:03:41 -04:00
Owen Schwartz d17e0c9f50 New translations en-us.json (Turkish) 2026-04-03 13:03:39 -04:00
Owen Schwartz f00b9794f5 New translations en-us.json (Russian) 2026-04-03 13:03:38 -04:00
Owen Schwartz daff59c93f New translations en-us.json (Portuguese) 2026-04-03 13:03:36 -04:00
Owen Schwartz aa8954366c New translations en-us.json (Polish) 2026-04-03 13:03:35 -04:00
Owen Schwartz 87464d53bd New translations en-us.json (Dutch) 2026-04-03 13:03:33 -04:00
Owen Schwartz e04f17c9aa New translations en-us.json (Korean) 2026-04-03 13:03:32 -04:00
Owen Schwartz b25e3499d8 New translations en-us.json (Italian) 2026-04-03 13:03:30 -04:00
Owen Schwartz 2e6f74a6f8 New translations en-us.json (German) 2026-04-03 13:03:28 -04:00
Owen Schwartz 8eee0ca5a5 New translations en-us.json (Czech) 2026-04-03 13:03:26 -04:00
Owen Schwartz c2ebc0a0ff New translations en-us.json (Bulgarian) 2026-04-03 13:03:24 -04:00
Owen Schwartz 03c905a7af New translations en-us.json (French) 2026-04-03 13:03:22 -04:00
Owen Schwartz 035644eaf7 Merge pull request #2778 from fosrl/dev
1.17.0-s.2
2026-04-03 12:35:03 -04:00
Owen 8ce45a1acd Update casting again 2026-04-03 12:34:37 -04:00
Owen Schwartz 16e7233a3e Merge pull request #2777 from fosrl/dev
1.17.0-s.1
2026-04-03 12:19:23 -04:00
Owen a331dd3fb4 Merge branch 'dev' of github.com:fosrl/pangolin into dev 2026-04-03 12:18:33 -04:00
Owen Schwartz e3e2938b28 Merge pull request #2761 from fosrl/crowdin_dev
New Crowdin updates
2026-04-03 12:16:31 -04:00
Owen 73e96b1b28 Type cast data 2026-04-03 12:15:39 -04:00
miloschwartz b8194295ec fix translation syntax err 2026-04-03 11:47:54 -04:00
miloschwartz 382a46dfff fix text formatting in delete dialog 2026-04-03 11:44:56 -04:00
Owen Schwartz 1f74e1b320 Merge pull request #2776 from fosrl/dev
1.17.0-s.0
2026-04-03 11:39:35 -04:00
Owen fee780cb81 Add siem to migration 2026-04-03 11:32:02 -04:00
Owen 5056cba85d Add siem to migration 2026-04-03 11:32:02 -04:00
miloschwartz dab38ff82c use debug log on log stream start 2026-04-03 11:16:56 -04:00
Owen d83fa63af5 Fix to null out the rewrite on the frontend too 2026-04-02 21:58:14 -04:00
Owen d5837ab718 Fix to use the stored data 2026-04-02 21:57:59 -04:00
Owen Schwartz f85cfc4c68 New translations en-us.json (Spanish) 2026-04-02 18:35:13 -04:00
Owen Schwartz 0b2aceafe0 New translations en-us.json (Norwegian Bokmal) 2026-04-02 18:35:11 -04:00
Owen Schwartz 059db34a53 New translations en-us.json (Chinese Simplified) 2026-04-02 18:35:10 -04:00
Owen Schwartz bc1ea86b4e New translations en-us.json (Turkish) 2026-04-02 18:35:09 -04:00
Owen Schwartz 9f2ced1933 New translations en-us.json (Russian) 2026-04-02 18:35:08 -04:00
Owen Schwartz 013cff9b6e New translations en-us.json (Portuguese) 2026-04-02 18:35:06 -04:00
Owen Schwartz aa19437031 New translations en-us.json (Polish) 2026-04-02 18:35:05 -04:00
Owen Schwartz e848ef848b New translations en-us.json (Dutch) 2026-04-02 18:35:03 -04:00
Owen Schwartz bb6605337f New translations en-us.json (Korean) 2026-04-02 18:35:02 -04:00
Owen Schwartz 8df8383468 New translations en-us.json (Italian) 2026-04-02 18:35:01 -04:00
Owen Schwartz a7e9de3ac4 New translations en-us.json (German) 2026-04-02 18:34:59 -04:00
Owen Schwartz 8df41f514e New translations en-us.json (Czech) 2026-04-02 18:34:58 -04:00
Owen Schwartz c2bf50b121 New translations en-us.json (Bulgarian) 2026-04-02 18:34:56 -04:00
Owen Schwartz 4e7dcbd7b5 New translations en-us.json (French) 2026-04-02 18:34:55 -04:00
Owen b7ccb92236 Merge branch 'main' into dev 2026-04-02 17:39:25 -04:00
Owen Schwartz 23a151dd45 Merge pull request #2771 from LaurenceJJones/feature/systemd-install-instructions
enhance: Systemd newt instructions
2026-04-02 12:13:44 -04:00
Laurence 122079ddb2 split unix to linux and macos, show method everything other than windows, change nixos all to flake so makes sense under method 2026-04-02 17:05:50 +01:00
Owen Schwartz 1d0b0ae6ec Merge pull request #2770 from fosrl/revert-2766-feature/systemd-install-instructions
Revert "enhance: Systemd newt unit instructions"
2026-04-02 11:43:15 -04:00
Owen Schwartz a55dd769cf Revert "enhance: Systemd newt unit instructions" 2026-04-02 11:43:01 -04:00
Owen Schwartz f1a0bc97e3 New translations en-us.json (Spanish) 2026-04-02 11:42:52 -04:00
Owen Schwartz a57dfd1d12 New translations en-us.json (Norwegian Bokmal) 2026-04-02 11:42:50 -04:00
Owen Schwartz c0a8304b91 New translations en-us.json (Chinese Simplified) 2026-04-02 11:42:48 -04:00
Owen Schwartz ab7b968e28 New translations en-us.json (Turkish) 2026-04-02 11:42:47 -04:00
Owen Schwartz f10b40c3b0 New translations en-us.json (Russian) 2026-04-02 11:42:45 -04:00
Owen Schwartz 7878ac9c76 New translations en-us.json (Portuguese) 2026-04-02 11:42:43 -04:00
Owen Schwartz 0752951842 New translations en-us.json (Polish) 2026-04-02 11:42:41 -04:00
Owen Schwartz 06bb6636a1 New translations en-us.json (Dutch) 2026-04-02 11:42:39 -04:00
Owen Schwartz 2fdd332a31 New translations en-us.json (Korean) 2026-04-02 11:42:38 -04:00
Owen Schwartz 98b1e9546a New translations en-us.json (Italian) 2026-04-02 11:42:36 -04:00
Owen Schwartz 184aa65c6d New translations en-us.json (German) 2026-04-02 11:42:34 -04:00
Owen Schwartz 70b3a432a4 New translations en-us.json (Czech) 2026-04-02 11:42:33 -04:00
Owen Schwartz fb4fc75bd8 New translations en-us.json (Bulgarian) 2026-04-02 11:42:31 -04:00
Owen Schwartz 0479ed9e7f New translations en-us.json (French) 2026-04-02 11:42:29 -04:00
Owen Schwartz 1dc3409135 Merge pull request #2766 from LaurenceJJones/feature/systemd-install-instructions
enhance: Systemd newt unit instructions
2026-04-02 11:40:50 -04:00
Laurence 1bb89fce26 enhance: Systemd newt unit
Add a systemd unit option directly from dashboard to prevent copy and paste mistakes
2026-04-02 12:21:53 +01:00
Owen Schwartz 8f3fbb94d2 New translations en-us.json (Spanish) 2026-04-01 09:58:52 -07:00
Owen Schwartz e8c35bec1c New translations en-us.json (Norwegian Bokmal) 2026-04-01 09:58:50 -07:00
Owen Schwartz 728e7252eb New translations en-us.json (Chinese Simplified) 2026-04-01 09:58:49 -07:00
Owen Schwartz 1218507f7d New translations en-us.json (Turkish) 2026-04-01 09:58:47 -07:00
Owen Schwartz a2dff0a35d New translations en-us.json (Russian) 2026-04-01 09:58:46 -07:00
Owen Schwartz f411180908 New translations en-us.json (Portuguese) 2026-04-01 09:58:44 -07:00
Owen Schwartz 231a19b679 New translations en-us.json (Polish) 2026-04-01 09:58:43 -07:00
Owen Schwartz 58a87a986a New translations en-us.json (Dutch) 2026-04-01 09:58:41 -07:00
Owen Schwartz 61a78ef352 New translations en-us.json (Korean) 2026-04-01 09:58:39 -07:00
Owen Schwartz e28e5ebb4e New translations en-us.json (Italian) 2026-04-01 09:58:38 -07:00
Owen Schwartz 19cef8c453 New translations en-us.json (German) 2026-04-01 09:58:36 -07:00
Owen Schwartz 1290d6cd5c New translations en-us.json (Czech) 2026-04-01 09:58:35 -07:00
Owen Schwartz ad301074db New translations en-us.json (Bulgarian) 2026-04-01 09:58:33 -07:00
Owen Schwartz 30a756d254 New translations en-us.json (French) 2026-04-01 09:58:32 -07:00
Owen 363c13c387 Impvove communication 2026-04-01 09:53:49 -07:00
Owen 08e4afaef0 Update hp log message 2026-03-31 17:06:56 -07:00
Owen 69aa6e2d1d Prevent increase in writes on reconnect 2026-03-31 17:00:06 -07:00
Owen 547865e0da Mark targets unhealthy when site is down
Fix #2675
Fix #2700
Fix #1742
2026-03-31 16:24:53 -07:00
Owen 3a9e79e6d5 Filter only newt sites on private resources 2026-03-31 16:17:17 -07:00
miloschwartz 4cce6e0820 add node graph and editor 2026-03-29 20:25:17 -07:00
miloschwartz 2841c5ed4e basic rules 2026-03-29 14:19:26 -07:00
Owen 02033f611f First pass at HA 2026-03-23 11:44:02 -07:00
Owen 1366901e24 Adjust build functions 2026-03-22 14:40:57 -07:00
Owen c4f48f5748 WIP - more conversion 2026-03-22 14:29:47 -07:00
Owen c48bc71443 Update crud endpoints and ui 2026-03-22 14:18:34 -07:00
Owen d85496453f Change SSH WIP 2026-03-21 10:40:12 -07:00
Owen 21b91374a3 Merge branch 'private-site-ha' of github.com:fosrl/pangolin into private-site-ha 2026-03-20 17:24:27 -07:00
Owen a1ce7f54a0 Continue to rebase 2026-03-20 09:17:10 -07:00
Owen 87524fe8ae Remove siteSiteResources 2026-03-19 21:53:52 -07:00
Owen 2093bb5357 Remove siteSiteResources 2026-03-19 21:44:59 -07:00
Owen 6f2e37948c Its many to one now 2026-03-19 21:30:00 -07:00
Owen b7421e47cc Switch to using networks 2026-03-19 21:22:04 -07:00
Owen 7cbe3d42a1 Working on refactoring 2026-03-19 12:10:04 -07:00
Owen d8b511b198 Adjust create and update to be many to one 2026-03-18 20:54:49 -07:00
Owen 102a235407 Adjust schema for many to one site resources 2026-03-18 20:54:38 -07:00
509 changed files with 23587 additions and 7392 deletions
+1
View File
@@ -0,0 +1 @@
* @oschwartz10612 @miloschwartz
+32 -26
View File
@@ -35,43 +35,53 @@
</div>
<p align="center">
<a href="https://docs.pangolin.net/careers/join-us">
<img src="https://img.shields.io/badge/🚀_We're_Hiring!-Join_Our_Team-brightgreen?style=for-the-badge" alt="We're Hiring!" />
</a>
</p>
<p align="center">
<strong>
Get started with Pangolin at <a href="https://app.pangolin.net/auth/signup">app.pangolin.net</a>
</strong>
</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, all with zero-trust security and granular access control.
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.
## Installation
- Check out the [quick install guide](https://docs.pangolin.net/self-host/quick-install) for how to install and set up Pangolin.
- Install from the [DigitalOcean marketplace](https://marketplace.digitalocean.com/apps/pangolin-ce-1?refcode=edf0480eeb81) for a one-click pre-configured installer.
- Get started for free with [Pangolin Cloud](https://app.pangolin.net/).
- Or, check out the [quick install guide](https://docs.pangolin.net/self-host/quick-install) for how to self-host Pangolin.
- Install from the [DigitalOcean marketplace](https://marketplace.digitalocean.com/apps/pangolin-ce-1?refcode=edf0480eeb81) for a one-click pre-configured installer.
<img src="public/screenshots/hero.png" />
<img src="public/screenshots/hero.png" alt="Pangolin" width="100%" />
## Deployment Options
| <img width=500 /> | Description |
|-----------------|--------------|
| **Pangolin Cloud** | Fully managed service with instant setup and pay-as-you-go pricing — no infrastructure required. Or, self-host your own [remote node](https://docs.pangolin.net/manage/remote-node/understanding-nodes) and connect to our control plane. |
| **Self-Host: Community Edition** | Free, open source, and licensed under AGPL-3. |
| **Self-Host: Enterprise Edition** | Licensed under Fossorial Commercial License. Free for personal and hobbyist use, and for businesses earning under \$100K USD annually. |
- **Pangolin Cloud** - Fully managed service - no infrastructure required.
- **Self-Host: Community Edition** - Free, open source, and licensed under AGPL-3.
- **Self-Host: Enterprise Edition** - Licensed under Fossorial Commercial License. Free for personal and hobbyist use, and for businesses making less than \$100K USD gross annual revenue.
## Key Features
| <img width=500 /> | <img width=500 /> |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
| **Connect remote networks with sites**<br /><br />Pangolin's lightweight site connectors create secure tunnels from remote networks without requiring public IP addresses or open ports. Sites make any network anywhere available for authorized access. | <img src="public/screenshots/sites.png" width=500 /><tr></tr> |
| **Browser-based reverse proxy access**<br /><br />Expose web applications through identity and context-aware tunneled reverse proxies. Pangolin handles routing, load balancing, health checking, and automatic SSL certificates without exposing your network directly to the internet. Users access applications through any web browser with authentication and granular access control. | <img src="public/clip.gif" width=500 /><tr></tr> |
| **Client-based private resource access**<br /><br />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. | <img src="public/screenshots/private-resources.png" width=500 /><tr></tr> |
| **Zero-trust granular access**<br /><br />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 and services you explicitly define, reducing security risk and attack surface. | <img src="public/screenshots/user-devices.png" width=500 /><tr></tr> |
### Connect remote networks with sites and NAT traversal
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.
<img src="public/screenshots/sites.png" alt="Sites" width="100%" />
### 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.
<img src="public/clip.gif" alt="Reverse proxy access" width="100%" />
### Client-based private resource access
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.
<img src="public/screenshots/private-resources.png" alt="Private resources" width="100%" />
### 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.
<img src="public/screenshots/users.png" alt="Users from identity provider with roles" width="100%" />
## Download Clients
@@ -87,7 +97,7 @@ Download the Pangolin client for your platform:
### Sign up now
Create an account at [app.pangolin.net](https://app.pangolin.net) to get started with Pangolin Cloud. A generous free tier is available.
Create a free account at [app.pangolin.net](https://app.pangolin.net) to get started with Pangolin Cloud.
### Check out the docs
@@ -102,7 +112,3 @@ Pangolin is dual licensed under the AGPL-3 and the [Fossorial Commercial License
## Contributions
Please see [CONTRIBUTING](./CONTRIBUTING.md) in the repository for guidelines and best practices.
---
WireGuard® is a registered trademark of Jason A. Donenfeld.
-17
View File
@@ -1,17 +0,0 @@
meta {
name: Create API Key
type: http
seq: 1
}
put {
url: http://localhost:3000/api/v1/api-key
body: json
auth: inherit
}
body:json {
{
"isRoot": true
}
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Delete API Key
type: http
seq: 2
}
delete {
url: http://localhost:3000/api/v1/api-key/dm47aacqxxn3ubj
body: none
auth: inherit
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: List API Key Actions
type: http
seq: 6
}
get {
url: http://localhost:3000/api/v1/api-key/ex0izu2c37fjz9x/actions
body: none
auth: inherit
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: List Org API Keys
type: http
seq: 4
}
get {
url: http://localhost:3000/api/v1/org/home-lab/api-keys
body: none
auth: inherit
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: List Root API Keys
type: http
seq: 3
}
get {
url: http://localhost:3000/api/v1/root/api-keys
body: none
auth: inherit
}
-17
View File
@@ -1,17 +0,0 @@
meta {
name: Set API Key Actions
type: http
seq: 5
}
post {
url: http://localhost:3000/api/v1/api-key/ex0izu2c37fjz9x/actions
body: json
auth: inherit
}
body:json {
{
"actionIds": ["listSites"]
}
}
-17
View File
@@ -1,17 +0,0 @@
meta {
name: Set API Key Orgs
type: http
seq: 7
}
post {
url: http://localhost:3000/api/v1/api-key/ex0izu2c37fjz9x/orgs
body: json
auth: inherit
}
body:json {
{
"orgIds": ["home-lab"]
}
}
-3
View File
@@ -1,3 +0,0 @@
meta {
name: API Keys
}
-18
View File
@@ -1,18 +0,0 @@
meta {
name: 2fa-disable
type: http
seq: 6
}
post {
url: http://localhost:3000/api/v1/auth/2fa/disable
body: json
auth: none
}
body:json {
{
"password": "aaaaa-1A",
"code": "377289"
}
}
-17
View File
@@ -1,17 +0,0 @@
meta {
name: 2fa-enable
type: http
seq: 4
}
post {
url: http://localhost:3000/api/v1/auth/2fa/enable
body: json
auth: none
}
body:json {
{
"code": "374138"
}
}
-17
View File
@@ -1,17 +0,0 @@
meta {
name: 2fa-request
type: http
seq: 5
}
post {
url: http://localhost:3000/api/v1/auth/2fa/request
body: json
auth: none
}
body:json {
{
"password": "aaaaa-1A"
}
}
-18
View File
@@ -1,18 +0,0 @@
meta {
name: change-password
type: http
seq: 9
}
post {
url: http://localhost:3000/api/v1/auth/change-password
body: json
auth: none
}
body:json {
{
"oldPassword": "",
"newPassword": ""
}
}
-18
View File
@@ -1,18 +0,0 @@
meta {
name: login
type: http
seq: 1
}
post {
url: http://localhost:3000/api/v1/auth/login
body: json
auth: none
}
body:json {
{
"email": "admin@fosrl.io",
"password": "Password123!"
}
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: logout
type: http
seq: 3
}
post {
url: http://localhost:4000/api/v1/auth/logout
body: none
auth: none
}
-17
View File
@@ -1,17 +0,0 @@
meta {
name: reset-password-request
type: http
seq: 10
}
post {
url: http://localhost:3000/api/v1/auth/reset-password/request
body: json
auth: none
}
body:json {
{
"email": "milo@pangolin.net"
}
}
-19
View File
@@ -1,19 +0,0 @@
meta {
name: reset-password
type: http
seq: 11
}
post {
url: http://localhost:3000/api/v1/auth/reset-password
body: json
auth: none
}
body:json {
{
"token": "3uhsbom72dwdhboctwrtntyd6jrlg4jtf5oaxy4k",
"newPassword": "aaaaa-1A",
"code": "6irqCGR3"
}
}
-18
View File
@@ -1,18 +0,0 @@
meta {
name: signup
type: http
seq: 2
}
put {
url: http://localhost:3000/api/v1/auth/signup
body: json
auth: none
}
body:json {
{
"email": "numbat@pangolin.net",
"password": "Password123!"
}
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: verify-email-request
type: http
seq: 8
}
post {
url: http://localhost:3000/api/v1/auth/verify-email/request
body: none
auth: none
}
-17
View File
@@ -1,17 +0,0 @@
meta {
name: verify-email
type: http
seq: 7
}
post {
url: http://localhost:3000/api/v1/auth/verify-email
body: json
auth: none
}
body:json {
{
"code": "50317187"
}
}
-15
View File
@@ -1,15 +0,0 @@
meta {
name: verify-user
type: http
seq: 4
}
get {
url: http://localhost:3001/api/v1/badger/verify-user?sessionId=mb52273jkb6t3oys2bx6ur5x7rcrkl26c7warg3e
body: none
auth: none
}
params:query {
sessionId: mb52273jkb6t3oys2bx6ur5x7rcrkl26c7warg3e
}
-22
View File
@@ -1,22 +0,0 @@
meta {
name: createClient
type: http
seq: 1
}
put {
url: http://localhost:3000/api/v1/site/1/client
body: json
auth: none
}
body:json {
{
"siteId": 1,
"name": "test",
"type": "olm",
"subnet": "100.90.129.4/30",
"olmId": "029yzunhx6nh3y5",
"secret": "l0ymp075y3d4rccb25l6sqpgar52k09etunui970qq5gj7x6"
}
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: pickClientDefaults
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1/site/1/pick-client-defaults
body: none
auth: none
}
-22
View File
@@ -1,22 +0,0 @@
meta {
name: Create OIDC Provider
type: http
seq: 1
}
put {
url: http://localhost:3000/api/v1/org/home-lab/idp/oidc
body: json
auth: inherit
}
body:json {
{
"clientId": "JJoSvHCZcxnXT2sn6CObj6a21MuKNRXs3kN5wbys",
"clientSecret": "2SlGL2wOGgMEWLI9yUuMAeFxre7qSNJVnXMzyepdNzH1qlxYnC4lKhhQ6a157YQEkYH3vm40KK4RCqbYiF8QIweuPGagPX3oGxEj2exwutoXFfOhtq4hHybQKoFq01Z3",
"authUrl": "http://localhost:9000/application/o/authorize/",
"tokenUrl": "http://localhost:9000/application/o/token/",
"scopes": ["email", "openid", "profile"],
"userIdentifier": "email"
}
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Generate OIDC URL
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1
body: none
auth: inherit
}
-3
View File
@@ -1,3 +0,0 @@
meta {
name: IDP
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Traefik Config
type: http
seq: 1
}
get {
url: http://localhost:3001/api/v1/traefik-config
body: none
auth: inherit
}
-3
View File
@@ -1,3 +0,0 @@
meta {
name: Internal
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Create Newt
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1/newt
body: none
auth: none
}
-18
View File
@@ -1,18 +0,0 @@
meta {
name: Get Token
type: http
seq: 1
}
get {
url: http://localhost:3000/api/v1/auth/newt/get-token
body: json
auth: none
}
body:json {
{
"newtId": "o0d4rdxq3stnz7b",
"secret": "sy7l09fnaesd03iwrfp9m3qf0ryn19g0zf3dqieaazb4k7vk"
}
}
-15
View File
@@ -1,15 +0,0 @@
meta {
name: createOlm
type: http
seq: 1
}
put {
url: http://localhost:3000/api/v1/olm
body: none
auth: inherit
}
settings {
encodeUrl: true
}
-8
View File
@@ -1,8 +0,0 @@
meta {
name: Olm
seq: 15
}
auth {
mode: inherit
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Check Id
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1/org/checkId
body: none
auth: none
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: listOrgs
type: http
seq: 1
}
get {
url:
body: none
auth: none
}
@@ -1,11 +0,0 @@
meta {
name: createRemoteExitNode
type: http
seq: 1
}
put {
url: http://localhost:4000/api/v1/org/org_i21aifypnlyxur2/remote-exit-node
body: none
auth: none
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: listResourcesByOrg
type: http
seq: 1
}
get {
url:
body: none
auth: none
}
-16
View File
@@ -1,16 +0,0 @@
meta {
name: listResourcesBySite
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1/site/1/resources?limit=10&offset=0
body: none
auth: none
}
params:query {
limit: 10
offset: 0
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Get Site
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1/org/test/sites/mexican-mole-lizard-windy
body: none
auth: none
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: listSites
type: http
seq: 1
}
get {
url:
body: none
auth: none
}
-16
View File
@@ -1,16 +0,0 @@
meta {
name: listTargets
type: http
seq: 1
}
get {
url: http://localhost:3000/api/v1/resource/web.main.localhost/targets?limit=10&offset=0
body: none
auth: none
}
params:query {
limit: 10
offset: 0
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: Test
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1
body: none
auth: inherit
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: traefik-config
type: http
seq: 1
}
get {
url: http://localhost:3001/api/v1/traefik-config
body: none
auth: none
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: adminListUsers
type: http
seq: 2
}
get {
url: http://localhost:3000/api/v1/users
body: none
auth: none
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: adminRemoveUser
type: http
seq: 3
}
delete {
url: http://localhost:3000/api/v1/user/ky5r7ivqs8wc7u4
body: none
auth: none
}
-11
View File
@@ -1,11 +0,0 @@
meta {
name: getUser
type: http
seq: 1
}
get {
url:
body: none
auth: none
}
-13
View File
@@ -1,13 +0,0 @@
{
"version": "1",
"name": "Pangolin",
"type": "collection",
"ignore": [
"node_modules",
".git"
],
"presets": {
"requestType": "http",
"requestUrl": "http://localhost:3000/api/v1"
}
}
+1
View File
@@ -0,0 +1 @@
*-journal
@@ -86,6 +86,8 @@ entryPoints:
http:
tls:
certResolver: "letsencrypt"
middlewares:
- crowdsec@file
encodedCharacters:
allowEncodedSlash: true
allowEncodedQuestionMark: true
-115
View File
@@ -1,115 +0,0 @@
import os
import sys
# --- Configuration ---
# The header text to be added to the files.
HEADER_TEXT = """/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
"""
def should_add_header(file_path):
"""
Checks if a file should receive the commercial license header.
Returns True if 'private' is in the path or file content.
"""
# Check if 'private' is in the file path (case-insensitive)
if 'server/private' in file_path.lower():
return True
# Check if 'private' is in the file content (case-insensitive)
# try:
# with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
# content = f.read()
# if 'private' in content.lower():
# return True
# except Exception as e:
# print(f"Could not read file {file_path}: {e}")
return False
def process_directory(root_dir):
"""
Recursively scans a directory and adds headers to qualifying .ts or .tsx files,
skipping any 'node_modules' directories.
"""
print(f"Scanning directory: {root_dir}")
files_processed = 0
headers_added = 0
for root, dirs, files in os.walk(root_dir):
# --- MODIFICATION ---
# Exclude 'node_modules' directories from the scan to improve performance.
if 'node_modules' in dirs:
dirs.remove('node_modules')
for file in files:
if file.endswith('.ts') or file.endswith('.tsx'):
file_path = os.path.join(root, file)
files_processed += 1
try:
with open(file_path, 'r+', encoding='utf-8') as f:
original_content = f.read()
has_header = original_content.startswith(HEADER_TEXT.strip())
if should_add_header(file_path):
# Add header only if it's not already there
if not has_header:
f.seek(0, 0) # Go to the beginning of the file
f.write(HEADER_TEXT.strip() + '\n\n' + original_content)
print(f"Added header to: {file_path}")
headers_added += 1
else:
print(f"Header already exists in: {file_path}")
else:
# Remove header if it exists but shouldn't be there
if has_header:
# Find the end of the header and remove it (including following newlines)
header_with_newlines = HEADER_TEXT.strip() + '\n\n'
if original_content.startswith(header_with_newlines):
content_without_header = original_content[len(header_with_newlines):]
else:
# Handle case where there might be different newline patterns
header_end = len(HEADER_TEXT.strip())
# Skip any newlines after the header
while header_end < len(original_content) and original_content[header_end] in '\n\r':
header_end += 1
content_without_header = original_content[header_end:]
f.seek(0)
f.write(content_without_header)
f.truncate()
print(f"Removed header from: {file_path}")
headers_added += 1 # Reusing counter for modifications
except Exception as e:
print(f"Error processing file {file_path}: {e}")
print("\n--- Scan Complete ---")
print(f"Total .ts or .tsx files found: {files_processed}")
print(f"Files modified (headers added/removed): {headers_added}")
if __name__ == "__main__":
# Get the target directory from the command line arguments.
# If no directory is provided, it uses the current directory ('.').
if len(sys.argv) > 1:
target_directory = sys.argv[1]
else:
target_directory = '.' # Default to current directory
if not os.path.isdir(target_directory):
print(f"Error: Directory '{target_directory}' not found.")
sys.exit(1)
process_directory(os.path.abspath(target_directory))
+137
View File
@@ -0,0 +1,137 @@
import os
import sys
# --- Configuration ---
# The header text to be added to the files.
HEADER_TEXT = """/*
* 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.
*/
"""
HEADER_NORMALIZED = HEADER_TEXT.strip()
def extract_leading_block_comment(content):
"""
If the file content begins with a /* ... */ block comment, return the
full text of that comment (including the delimiters) and the index at
which the rest of the file starts (after any trailing newlines).
Returns (None, 0) when no such comment is found.
"""
stripped = content.lstrip()
if not stripped.startswith('/*'):
return None, 0
# Account for any leading whitespace before the comment
comment_start = content.index('/*')
end_marker = content.find('*/', comment_start + 2)
if end_marker == -1:
return None, 0
comment_end = end_marker + 2 # position just after '*/'
comment_text = content[comment_start:comment_end].strip()
# Advance past any whitespace / newlines that follow the closing */
rest_start = comment_end
while rest_start < len(content) and content[rest_start] in '\n\r':
rest_start += 1
return comment_text, rest_start
def should_add_header(file_path):
"""
Checks if a file should receive the commercial license header.
Returns True if 'server/private' is in the path.
"""
if 'server/private' in file_path.lower():
return True
return False
def process_directory(root_dir):
"""
Recursively scans a directory and adds/replaces/removes headers in
qualifying .ts or .tsx files, skipping any 'node_modules' directories.
"""
print(f"Scanning directory: {root_dir}")
files_processed = 0
files_modified = 0
for root, dirs, files in os.walk(root_dir):
# Exclude 'node_modules' directories from the scan.
if 'node_modules' in dirs:
dirs.remove('node_modules')
for file in files:
if not (file.endswith('.ts') or file.endswith('.tsx')):
continue
file_path = os.path.join(root, file)
files_processed += 1
try:
with open(file_path, 'r', encoding='utf-8') as f:
original_content = f.read()
existing_comment, body_start = extract_leading_block_comment(
original_content
)
has_any_header = existing_comment is not None
has_correct_header = existing_comment == HEADER_NORMALIZED
body = original_content[body_start:] if has_any_header else original_content
if should_add_header(file_path):
if has_correct_header:
print(f"Header up-to-date: {file_path}")
else:
# Either no header exists or the header is outdated - write
# the correct one.
action = "Replaced header in" if has_any_header else "Added header to"
new_content = HEADER_NORMALIZED + '\n\n' + body
with open(file_path, 'w', encoding='utf-8') as f:
f.write(new_content)
print(f"{action}: {file_path}")
files_modified += 1
else:
if has_any_header:
# Remove the header - it shouldn't be here.
with open(file_path, 'w', encoding='utf-8') as f:
f.write(body)
print(f"Removed header from: {file_path}")
files_modified += 1
else:
print(f"No header needed: {file_path}")
except Exception as e:
print(f"Error processing file {file_path}: {e}")
print("\n--- Scan Complete ---")
print(f"Total .ts or .tsx files found: {files_processed}")
print(f"Files modified (added/replaced/removed): {files_modified}")
if __name__ == "__main__":
# Get the target directory from the command line arguments.
# If no directory is provided, it uses the current directory ('.').
if len(sys.argv) > 1:
target_directory = sys.argv[1]
else:
target_directory = '.' # Default to current directory
if not os.path.isdir(target_directory):
print(f"Error: Directory '{target_directory}' not found.")
sys.exit(1)
process_directory(os.path.abspath(target_directory))
+41 -12
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Ключът за осигуряване е актуализиран",
"provisioningKeysUpdatedDescription": "Вашите промени бяха запазени.",
"provisioningKeysBannerTitle": "Ключове за осигуряване на сайта",
"provisioningKeysBannerDescription": "Генерирайте ключ за осигуряване и го използвайте с Newt конектора за автоматично създаване на сайтове при първото стартиране няма нужда от създаване на отделни идентификационни данни за всеки сайт.",
"provisioningKeysBannerDescription": "Генерирайте ключ за осигуряване и го използвайте със съединителя Newt за автоматично създаване на сайтове при първоначално стартиране - не е необходимо да се създават отделни идентификационни данни за всеки сайт.",
"provisioningKeysBannerButtonText": "Научете повече",
"pendingSitesBannerTitle": "Чакащи сайтове",
"pendingSitesBannerDescription": "Сайтовете, които се свързват чрез ключ за осигуряване, се появяват тук за преглед. Одобрете всеки сайт, преди да стане активен и да получи достъп до вашите ресурси.",
"pendingSitesBannerDescription": "Сайтовете, които се свързват с ключ за осигуряване, ще се появят тук за преглед.",
"pendingSitesBannerButtonText": "Научете повече",
"apiKeysSettings": "Настройки на {apiKeyName}",
"userTitle": "Управление на всички потребители",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Неуспешно активиране на лицензионния ключ",
"licenseErrorKeyActivateDescription": "Възникна грешка при активирането на лицензионния ключ.",
"licenseAbout": "Относно лицензите",
"licenseBannerTitle": "Активирайте своята корпоративна лицензия",
"licenseBannerDescription": "Отключете корпоративните функции за вашият хостинг на Pangolin. Закупете лицензионен ключ, за да активирате премиум възможности, след това го добавете по-долу.",
"licenseBannerGetLicense": "Вземете лиценз",
"licenseBannerViewDocs": "Преглед на документацията",
"communityEdition": "Комюнити издание",
"licenseAboutDescription": "Това е за бизнес и корпоративни потребители, които използват Pangolin в търговска среда. Ако използвате Pangolin за лична употреба, можете да игнорирате този раздел.",
"licenseKeyActivated": "Лицензионният ключ е активиран",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Моля, въведете валиден номер на порт",
"targetErrorNoSite": "Няма избран сайт",
"targetErrorNoSiteDescription": "Моля, изберете сайт за целта",
"targetTargetsCleared": "Мишените са премахнати",
"targetTargetsClearedDescription": "Всички цели са били премахнати от този ресурс",
"targetCreated": "Целта е създадена",
"targetCreatedDescription": "Целта беше успешно създадена",
"targetErrorCreate": "Неуспешно създаване на целта",
@@ -892,6 +898,7 @@
"idpDisplayName": "Име за показване за този доставчик на идентичност",
"idpAutoProvisionUsers": "Автоматично потребителско създаване",
"idpAutoProvisionUsersDescription": "Когато е активирано, потребителите ще бъдат автоматично създадени в системата при първо влизане с възможност за свързване на потребителите с роли и организации.",
"idpAutoProvisionConfigureAfterCreate": "Можете да конфигурирате настройките за автоматично предоставяне, след като дистрибуторът на самоличност бъде създаден.",
"licenseBadge": "ЕЕ",
"idpType": "Тип доставчик",
"idpTypeDescription": "Изберете типа доставчик на идентичност, който искате да конфигурирате",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Карта на роля по подразбиране",
"defaultMappingsRoleDescription": "Резултатът от този израз трябва да върне името на ролята, както е дефинирано в организацията, като стринг.",
"defaultMappingsOrg": "Карта на организация по подразбиране",
"defaultMappingsOrgDescription": "Този израз трябва да върне ID на организацията или 'true', за да бъде разрешен достъпът на потребителя до организацията.",
"defaultMappingsOrgDescription": "При задаване, този израз трябва да върне идентификационния номер на организацията или true, за да се даде достъп на потребителя до тази организация. Ако не е зададено, дефинирането на роля е достатъчно: потребителят има право на достъп, стига валидно картографиране на роля да бъде разрешено за него в рамките на организацията.",
"defaultMappingsSubmit": "Запазване на файловете по подразбиране",
"orgPoliciesEdit": "Редактиране на Организационна Политика",
"org": "Организация",
@@ -1987,7 +1994,7 @@
"description": "По-надежден и по-нисък поддръжка на Самостоятелно-хостван Панголиин сървър с допълнителни екстри",
"introTitle": "Управлявано Самостоятелно-хостван Панголиин",
"introDescription": "е опция за внедряване, предназначена за хора, които искат простота и допълнителна надеждност, като същевременно запазят данните си частни и самостоятелно-хоствани.",
"introDetail": "С тази опция все още управлявате свой собствен Панголиин възел вашите тунели, SSL терминатора и трафик остават на вашия сървър. Разликата е, че управлението и мониторингът се обработват чрез нашия облачен панел за контрол, който отключва редица предимства:",
"introDetail": "С тази опция все още управлявате свой собствен Панголиин възел - вашите тунели, SSL терминатора и трафик остават на вашия сървър. Разликата е, че управлението и мониторингът се обработват чрез нашия облачен панел за контрол, който отключва редица предимства:",
"benefitSimplerOperations": {
"title": "По-прости операции",
"description": "Няма нужда да управлявате свой собствен имейл сървър или да настройвате сложни аларми. Ще получите проверки и предупреждения при прекъсване от самото начало."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Открит международен домейн",
"willbestoredas": "Ще бъде съхранено като:",
"roleMappingDescription": "Определете как се разпределят ролите на потребителите при вписване, когато е активирано автоматично предоставяне.",
"roleMappingDescription": "Определете как ролите се присвояват на потребителите, когато се вписват с този доставчик на самоличност.",
"selectRole": "Избор на роля",
"roleMappingExpression": "Израз",
"selectRolePlaceholder": "Избор на роля",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Изберете домейн за страницата за удостоверяване на организацията",
"domainPickerProvidedDomain": "Предоставен домейн",
"domainPickerFreeProvidedDomain": "Безплатен предоставен домейн",
"domainPickerFreeDomainsPaidFeature": "Предоставените домейни са платена функция. Абонирайте се, за да получите домейн, включен във вашия план - няма нужда да използвате вашия собствен.",
"domainPickerVerified": "Проверено",
"domainPickerUnverified": "Непроверено",
"domainPickerManual": "Ръчно",
"domainPickerInvalidSubdomainStructure": "Този поддомен съдържа невалидни знаци или структура. Ще бъде автоматично пречистен при запазване.",
"domainPickerError": "Грешка",
"domainPickerErrorLoadDomains": "Неуспешно зареждане на домейни на организацията",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Разкриване на употреба",
"description": "Изберете лицензионен клас, който точно отразява вашата целена употреба. Персоналният лиценз позволява безплатно ползване на софтуера за индивидуална, некомерсиална или маломащабна комерсиална дейност с годишен брутен приход под 100,000 USD. Всяко ползване извън тези граници включително ползване във фирма, организация или друга доходоносна среда изисква валиден корпоративен лиценз и плащане на съответната лицензионна такса. Всички потребители, независимо дали са лични или корпоративни, трябва да спазват Условията на Fossorial Commercial License."
"description": "Изберете лицензионен клас, който точно отразява вашата целена употреба. Персоналният лиценз позволява безплатно ползване на софтуера за индивидуална, некомерсиална или маломащабна комерсиална дейност с годишен брутен приход под 100,000 USD. Всяко ползване извън тези граници - включително ползване във фирма, организация или друга доходоносна среда - изисква валиден корпоративен лиценз и плащане на съответната лицензионна такса. Всички потребители, независимо дали са лични или корпоративни, трябва да спазват Условията на Fossorial Commercial License."
},
"trialPeriodInformation": {
"title": "Информация за пробен период",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Скала",
"description": "Предприятие, 50 потребители, 50 сайта и приоритетна поддръжка."
"description": "Функции за корпоративни клиенти, 50 потребители, 100 сайта и приоритетна поддръжка."
}
},
"personalUseOnly": "Само за лична употреба (безплатен лиценз без плащане)",
"personalUseOnly": "Само за лична употреба (безплатен лиценз - без проверка)",
"buttons": {
"continueToCheckout": "Продължете към плащане"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Машинни клиенти",
"install": "Инсталирай",
"run": "Изпълни",
"envFile": "Файл за среда",
"serviceFile": "Файл за услуга",
"enableAndStart": "Активиране и стартиране",
"clientNameDescription": "Показваното име на клиента, което може да се промени по-късно.",
"clientAddress": "Клиентски адрес (Разширено)",
"setupFailedToFetchSubnet": "Неуспешно извличане на подмрежа по подразбиране",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Без удостоверяване",
"httpDestAuthNoneDescription": "Изпращане на заявки без заглавие за удостоверяване.",
"httpDestAuthBearerTitle": "Bearer Токен",
"httpDestAuthBearerDescription": "Добавя заглавие за удостоверяване Bearer <token> към всяка заявка.",
"httpDestAuthBearerDescription": "Добавя заглавие Authorization: Bearer '<token>' към всяка заявка.",
"httpDestAuthBearerPlaceholder": "Вашият API ключ или токен",
"httpDestAuthBasicTitle": "Основно удостоверяване",
"httpDestAuthBasicDescription": "Добавя заглавие за удостоверяване Basic <credentials> към всяка заявка. Осигурете идентификационни данни като потребителско име:парола.",
"httpDestAuthBasicDescription": "Добавя заглавие Authorization: Basic '<credentials>'. Осигурете идентификационни данни като потребителско име:парола.",
"httpDestAuthBasicPlaceholder": "потребителско име:парола",
"httpDestAuthCustomTitle": "Персонализирано заглавие",
"httpDestAuthCustomDescription": "Посочете персонализирано име и стойност на заглавието за удостоверяване (например X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "JSON масив",
"httpDestFormatJsonArrayDescription": "Една заявка на партида, тялото е JSON масив. Съвместим с повечето общи уеб куки и Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Една заявка на партида, тялото е ново линии отделени JSON един обект на ред, няма външен масив. Изисквано от Splunk HEC, Elastic / OpenSearch и Grafana.",
"httpDestFormatNdjsonDescription": "Една заявка на партида, тялото е ново линии отделени JSON - един обект на ред, няма външен масив. Изисквано от Splunk HEC, Elastic / OpenSearch и Grafana.",
"httpDestFormatSingleTitle": "Едно събитие на заявка",
"httpDestFormatSingleDescription": "Изпращат се отделни HTTP POST за всяко индивидуално събитие. Използвайте само за крайни точки, които не могат да обработват партиди.",
"httpDestLogTypesTitle": "Видове логове",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Дестинацията беше актуализирана успешно",
"httpDestCreatedSuccess": "Дестинацията беше създадена успешно",
"httpDestUpdateFailed": "Неуспешно актуализиране на дестинацията",
"httpDestCreateFailed": "Неуспешно създаване на дестинацията"
"httpDestCreateFailed": "Неуспешно създаване на дестинацията",
"idpAddActionCreateNew": "Създайте нов доставчик на самоличност",
"idpAddActionImportFromOrg": "Импортиране от друга организация",
"idpImportDialogTitle": "Импортиране на доставчик на самоличност",
"idpImportDialogDescription": "Изберете доставчик на самоличност от организация, в която сте администратор. Той ще бъде свързан с тази организация.",
"idpImportSearchPlaceholder": "Търсене по име на организация или доставчик...",
"idpImportEmpty": "Няма намерени доставчици на самоличност.",
"idpImportedDescription": "Доставчикът на самоличност беше импортиран успешно.",
"idpDeleteGlobalQuestion": "Сигурни ли сте, че искате да изтриете този доставчик на самоличност завинаги?",
"idpDeleteGlobalDescription": "Това ще изтрие доставичка на самоличност завинаги от всички организации, с които е свързан.",
"idpUnassociateTitle": "Отвързване на доставчик на самоличност",
"idpUnassociateQuestion": "Сигурни ли сте, че искате да отвържете този доставчик на самоличност от тази организация?",
"idpUnassociateDescription": "Всички потребители, свързани с този доставчик на самоличност, ще бъдат премахнати от тази организация, но доставчика на самоличност ще продължи да съществува за други свързани организации.",
"idpUnassociateConfirm": "Потвърдете отвързване на доставчика на самоличност",
"idpUnassociateWarning": "Това не може да бъде отменено за тази организация.",
"idpUnassociatedDescription": "Доставчика на самоличност е успешно отвързан от тази организация",
"idpUnassociateMenu": "Отвързване",
"idpDeleteAllOrgsMenu": "Изтриване"
}
+39 -10
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Zajišťovací klíč byl aktualizován",
"provisioningKeysUpdatedDescription": "Vaše změny byly uloženy.",
"provisioningKeysBannerTitle": "Klíče pro poskytování webu",
"provisioningKeysBannerDescription": "Vygenerujte konfigurační klíč a používejte jej pomocí nového konektoru k automatickému vytváření stránek při prvním startu není třeba nastavovat samostatné přihlašovací údaje pro každý web.",
"provisioningKeysBannerDescription": "Vygenerujte klíč pro zřízení a použijte ho s Newt konektorem k automatickému vytvoření stránek při prvním spuštění není potřeba nastavit samostatné přihlašovací údaje pro každou stránku.",
"provisioningKeysBannerButtonText": "Zjistit více",
"pendingSitesBannerTitle": "Nevyřízené weby",
"pendingSitesBannerDescription": "Zde se zobrazují stránky, které se připojují pomocí doplňovacího klíče. Schválte každý web předtím, než bude aktivní, a získejte přístup k vašim zdrojům.",
"pendingSitesBannerDescription": "Stránky, které se připojují pomocí klíče pro zřízení, se zde objeví ke kontrole.",
"pendingSitesBannerButtonText": "Zjistit více",
"apiKeysSettings": "Nastavení {apiKeyName}",
"userTitle": "Spravovat všechny uživatele",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Nepodařilo se aktivovat licenční klíč",
"licenseErrorKeyActivateDescription": "Došlo k chybě při aktivaci licenčního klíče.",
"licenseAbout": "O licencích",
"licenseBannerTitle": "Aktivovat vaši firemní licenci",
"licenseBannerDescription": "Odemkněte firemní funkce pro vaši samohostovanou instanci Pangolin. Zakupte si licenční klíč pro aktivaci prémiových možností a poté jej přidejte níže.",
"licenseBannerGetLicense": "Zakoupit licenci",
"licenseBannerViewDocs": "Zobrazit dokumentaci",
"communityEdition": "Komunitní edice",
"licenseAboutDescription": "To je pro obchodní a podnikové uživatele, kteří používají Pangolin v komerčním prostředí. Pokud používáte Pangolin pro osobní použití, můžete tuto sekci ignorovat.",
"licenseKeyActivated": "Licenční klíč aktivován",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Zadejte platné číslo portu",
"targetErrorNoSite": "Není vybrán žádný web",
"targetErrorNoSiteDescription": "Vyberte prosím web pro cíl",
"targetTargetsCleared": "Cíle vymazány",
"targetTargetsClearedDescription": "Všechny cíle byly odstraněny z tohoto zdroje",
"targetCreated": "Cíl byl vytvořen",
"targetCreatedDescription": "Cíl byl úspěšně vytvořen",
"targetErrorCreate": "Nepodařilo se vytvořit cíl",
@@ -892,6 +898,7 @@
"idpDisplayName": "Zobrazované jméno tohoto poskytovatele identity",
"idpAutoProvisionUsers": "Automatická úprava uživatelů",
"idpAutoProvisionUsersDescription": "Pokud je povoleno, uživatelé budou automaticky vytvářeni v systému při prvním přihlášení, s možností namapovat uživatele na role a organizace.",
"idpAutoProvisionConfigureAfterCreate": "Nastavení automatického poskytování lze nakonfigurovat, jakmile je vytvořen poskytovatel identity.",
"licenseBadge": "PE",
"idpType": "Typ poskytovatele",
"idpTypeDescription": "Vyberte typ poskytovatele identity, který chcete nakonfigurovat",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Výchozí mapování rolí",
"defaultMappingsRoleDescription": "Výsledek tohoto výrazu musí vrátit název role definovaný v organizaci jako řetězec.",
"defaultMappingsOrg": "Výchozí mapování organizace",
"defaultMappingsOrgDescription": "Tento výraz musí vrátit org ID nebo pravdu, aby měl uživatel přístup k organizaci.",
"defaultMappingsOrgDescription": "Pokud je nastaven, musí tento výraz vracet ID organizace nebo pravda, aby k této organizaci měl uživatel přístup. Pokud není nastaveno, je dostačující definice mapování rolí: uživateli je umožněn přístup, pokud pro něj lze v rámci organizace vyřešit platné mapování rolí.",
"defaultMappingsSubmit": "Uložit výchozí mapování",
"orgPoliciesEdit": "Upravit zásady organizace",
"org": "Organizace",
@@ -1987,7 +1994,7 @@
"description": "Spolehlivější a nízko udržovaný Pangolinův server s dalšími zvony a bičkami",
"introTitle": "Spravovaný Pangolin",
"introDescription": "je možnost nasazení určená pro lidi, kteří chtějí jednoduchost a spolehlivost při zachování soukromých a samoobslužných dat.",
"introDetail": "Pomocí této volby stále provozujete vlastní uzel Pangolin tunely, SSL terminály a provoz všech pobytů na vašem serveru. Rozdíl spočívá v tom, že řízení a monitorování se řeší prostřednictvím našeho cloudového panelu, který odemkne řadu výhod:",
"introDetail": "Pomocí této volby stále provozujete vlastní uzel Pangolin - tunely, SSL terminály a provoz všech pobytů na vašem serveru. Rozdíl spočívá v tom, že řízení a monitorování se řeší prostřednictvím našeho cloudového panelu, který odemkne řadu výhod:",
"benefitSimplerOperations": {
"title": "Jednoduchý provoz",
"description": "Není třeba spouštět svůj vlastní poštovní server nebo nastavit komplexní upozornění. Ze schránky dostanete upozornění na zdravotní kontrolu a výpadek."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Zjištěna mezinárodní doména",
"willbestoredas": "Bude uloženo jako:",
"roleMappingDescription": "Určete, jak jsou role přiřazeny uživatelům, když se přihlásí, když je povoleno automatické poskytnutí služby.",
"roleMappingDescription": "Určete, jak jsou role přiřazeny uživatelům, když se přihlásí s tímto poskytovatelem identity.",
"selectRole": "Vyberte roli",
"roleMappingExpression": "Výraz",
"selectRolePlaceholder": "Vyberte roli",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Vyberte doménu pro ověřovací stránku organizace",
"domainPickerProvidedDomain": "Poskytnutá doména",
"domainPickerFreeProvidedDomain": "Zdarma poskytnutá doména",
"domainPickerFreeDomainsPaidFeature": "Poskytnuté domény jsou placenou funkcí. Předplaťte si plán, abyste získali doménu zahrnutou v plánu nemusíte si přinést vlastní.",
"domainPickerVerified": "Ověřeno",
"domainPickerUnverified": "Neověřeno",
"domainPickerManual": "Ruční nastavení",
"domainPickerInvalidSubdomainStructure": "Tato subdoména obsahuje neplatné znaky nebo strukturu. Bude automaticky sanitována při uložení.",
"domainPickerError": "Chyba",
"domainPickerErrorLoadDomains": "Nepodařilo se načíst domény organizace",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Měřítko",
"description": "Podnikové funkce, 50 uživatelů, 50 míst a prioritní podpory."
"description": "Podnikové funkce, 50 uživatelů, 100 stránek a prioritní podpora."
}
},
"personalUseOnly": "Pouze osobní použití (bezplatná licence bez platby)",
"personalUseOnly": "Pouze pro osobní použití (zdarma licence - bez ověření)",
"buttons": {
"continueToCheckout": "Pokračovat do pokladny"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Strojoví klienti",
"install": "Instalovat",
"run": "Spustit",
"envFile": "Konfigurační soubor prostředí",
"serviceFile": "Služební soubor",
"enableAndStart": "Povolit a spustit",
"clientNameDescription": "Zobrazované jméno klienta, které lze později změnit.",
"clientAddress": "Adresa klienta (Rozšířeno)",
"setupFailedToFetchSubnet": "Nepodařilo se načíst výchozí podsíť",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Žádné ověření",
"httpDestAuthNoneDescription": "Odešle žádosti bez záhlaví autorizace.",
"httpDestAuthBearerTitle": "Token na doručitele",
"httpDestAuthBearerDescription": "Přidá autorizaci: Hlavička Bearer <token> ke každému požadavku.",
"httpDestAuthBearerDescription": "Přidává hlavičku Authorization: Bearer '<token>' k každému požadavku.",
"httpDestAuthBearerPlaceholder": "Váš API klíč nebo token",
"httpDestAuthBasicTitle": "Základní ověření",
"httpDestAuthBasicDescription": "Přidá autorizaci: Základní <credentials> hlavička. Poskytněte přihlašovací údaje jako uživatelské jméno:password.",
"httpDestAuthBasicDescription": "Přidává hlavičku Authorization: Basic '<credentials>'. Poskytněte přihlašovací údaje ve formátu uživatelské jméno:heslo.",
"httpDestAuthBasicPlaceholder": "uživatelské jméno:heslo",
"httpDestAuthCustomTitle": "Vlastní záhlaví",
"httpDestAuthCustomDescription": "Zadejte název a hodnotu vlastního HTTP hlavičky pro ověření (např. X-API-Key).",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Cíl byl úspěšně aktualizován",
"httpDestCreatedSuccess": "Cíl byl úspěšně vytvořen",
"httpDestUpdateFailed": "Nepodařilo se aktualizovat cíl",
"httpDestCreateFailed": "Nepodařilo se vytvořit cíl"
"httpDestCreateFailed": "Nepodařilo se vytvořit cíl",
"idpAddActionCreateNew": "Vytvořit nového poskytovatele identity",
"idpAddActionImportFromOrg": "Importovat z jiné organizace",
"idpImportDialogTitle": "Importovat poskytovatele identity",
"idpImportDialogDescription": "Vyberte poskytovatele identity z organizace, v níž jste administrátor. Tento poskytovatel bude propojen s touto organizací.",
"idpImportSearchPlaceholder": "Hledat podle názvu organizace nebo poskytovatele...",
"idpImportEmpty": "Nebyli nalezeni žádní poskytovatelé identity.",
"idpImportedDescription": "Poskytovatel identity byl úspěšně importován.",
"idpDeleteGlobalQuestion": "Opravdu chcete trvale smazat tohoto poskytovatele identity?",
"idpDeleteGlobalDescription": "Tímto bude poskytovatel identity trvale odstraněn ze všech organizací, se kterými je spojen.",
"idpUnassociateTitle": "Odpojit poskytovatele identity",
"idpUnassociateQuestion": "Opravdu chcete odpojit tohoto poskytovatele identity od této organizace?",
"idpUnassociateDescription": "Všichni uživatelé spojení s tímto poskytovatelem identity budou odstraněni z této organizace, ale poskytovatel identity zůstane nadále existovat pro ostatní přidružené organizace.",
"idpUnassociateConfirm": "Potvrdit odpojení poskytovatele identity",
"idpUnassociateWarning": "Toto nelze pro tuto organizaci vrátit.",
"idpUnassociatedDescription": "Poskytovatel identity byl úspěšně odpojen od této organizace",
"idpUnassociateMenu": "Odpojit",
"idpDeleteAllOrgsMenu": "Odstranit"
}
+40 -11
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Bereitstellungsschlüssel aktualisiert",
"provisioningKeysUpdatedDescription": "Ihre Änderungen wurden gespeichert.",
"provisioningKeysBannerTitle": "Website-Bereitstellungsschlüssel",
"provisioningKeysBannerDescription": "Generieren Sie einen Bereitstellungsschlüssel und verwenden Sie ihn mit dem Newt-Konnektor, um beim ersten Start automatisch Sites zu erstellen keine Notwendigkeit, separate Anmeldeinformationen für jede Seite einzurichten.",
"provisioningKeysBannerDescription": "Generieren Sie einen Bereitstellungsschlüssel und verwenden Sie ihn mit dem Newt-Connector, um Standorte beim ersten Start automatisch zu erstellen - keine Notwendigkeit, separate Anmeldedaten für jede Seite einzurichten.",
"provisioningKeysBannerButtonText": "Mehr erfahren",
"pendingSitesBannerTitle": "Ausstehende Seiten",
"pendingSitesBannerDescription": "Sites, die sich mit einem Bereitstellungsschlüssel verbinden, erscheinen hier zur Überprüfung. Bestätigen Sie jede Site, bevor sie aktiv wird und erhalten Zugriff auf Ihre Ressourcen.",
"pendingSitesBannerDescription": "Websites, die mit einem Bereitstellungsschlüssel verbunden sind, erscheinen hier zur Überprüfung.",
"pendingSitesBannerButtonText": "Mehr erfahren",
"apiKeysSettings": "{apiKeyName} Einstellungen",
"userTitle": "Alle Benutzer verwalten",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Fehler beim Aktivieren des Lizenzschlüssels",
"licenseErrorKeyActivateDescription": "Beim Aktivieren des Lizenzschlüssels ist ein Fehler aufgetreten.",
"licenseAbout": "Über Lizenzierung",
"licenseBannerTitle": "Aktivieren Sie Ihre Enterprise-Lizenz",
"licenseBannerDescription": "Schalten Sie Unternehmensfunktionen für Ihre selbstgehostete Pangolin-Instanz frei. Kaufen Sie einen Lizenzschlüssel, um Premium-Funktionen zu aktivieren, und fügen Sie ihn dann unten hinzu.",
"licenseBannerGetLicense": "Lizenz erhalten",
"licenseBannerViewDocs": "Dokumentation anzeigen",
"communityEdition": "Community-Edition",
"licenseAboutDescription": "Dies ist für Geschäfts- und Unternehmensanwender, die Pangolin in einem kommerziellen Umfeld einsetzen. Wenn Sie Pangolin für den persönlichen Gebrauch verwenden, können Sie diesen Abschnitt ignorieren.",
"licenseKeyActivated": "Lizenzschlüssel aktiviert",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Bitte geben Sie eine gültige Portnummer ein",
"targetErrorNoSite": "Kein Standort ausgewählt",
"targetErrorNoSiteDescription": "Bitte wähle einen Standort für das Ziel aus",
"targetTargetsCleared": "Ziele gelöscht",
"targetTargetsClearedDescription": "Alle Ziele wurden aus dieser Ressource entfernt",
"targetCreated": "Ziel erstellt",
"targetCreatedDescription": "Ziel wurde erfolgreich erstellt",
"targetErrorCreate": "Fehler beim Erstellen des Ziels",
@@ -892,6 +898,7 @@
"idpDisplayName": "Ein Anzeigename für diesen Identitätsanbieter",
"idpAutoProvisionUsers": "Automatische Benutzerbereitstellung",
"idpAutoProvisionUsersDescription": "Wenn aktiviert, werden Benutzer beim ersten Login automatisch im System erstellt, mit der Möglichkeit, Benutzer Rollen und Organisationen zuzuordnen.",
"idpAutoProvisionConfigureAfterCreate": "Sie können die automatische Bereitstellung einstellen, sobald der Identitätsanbieter erstellt ist.",
"licenseBadge": "EE",
"idpType": "Anbietertyp",
"idpTypeDescription": "Wählen Sie den Typ des Identitätsanbieters, den Sie konfigurieren möchten",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Standard-Rollenzuordnung",
"defaultMappingsRoleDescription": "JMESPath zur Extraktion von Rolleninformationen aus dem ID-Token. Das Ergebnis dieses Ausdrucks muss den Rollennamen als String zurückgeben, wie er in der Organisation definiert ist.",
"defaultMappingsOrg": "Standard-Organisationszuordnung",
"defaultMappingsOrgDescription": "JMESPath zur Extraktion von Organisationsinformationen aus dem ID-Token. Dieser Ausdruck muss die Organisations-ID oder true zurückgeben, damit der Benutzer Zugriff auf die Organisation erhält.",
"defaultMappingsOrgDescription": "Wenn diese Einstellung festgelegt ist, muss dieser Ausdruck die Organisations-ID oder wahr zurückgeben, damit der Benutzer diese Organisation betreten kann. Ist sie nicht festgelegt, reicht die Definition einer Rollenzuordnung aus: Der Benutzer darf eintreten, solange eine gültige Rollenzuordnung innerhalb der Organisation für ihn aufgelöst werden kann.",
"defaultMappingsSubmit": "Standardzuordnungen speichern",
"orgPoliciesEdit": "Organisationsrichtlinie bearbeiten",
"org": "Organisation",
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Internationale Domain erkannt",
"willbestoredas": "Wird gespeichert als:",
"roleMappingDescription": "Legen Sie fest, wie den Benutzern Rollen zugewiesen werden, wenn sie sich anmelden, wenn Auto Provision aktiviert ist.",
"roleMappingDescription": "Bestimmen Sie, wie Rollen zugewiesen werden, wenn sich Benutzer mit diesem Identitätsanbieter anmelden.",
"selectRole": "Wählen Sie eine Rolle",
"roleMappingExpression": "Ausdruck",
"selectRolePlaceholder": "Rolle auswählen",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Wählen Sie eine Domain für die Authentifizierungsseite der Organisation",
"domainPickerProvidedDomain": "Angegebene Domain",
"domainPickerFreeProvidedDomain": "Kostenlose Domain",
"domainPickerFreeDomainsPaidFeature": "Bereitgestellte Domains sind ein kostenpflichtiges Feature. Abonnieren Sie, um eine Domain in Ihrem Tarif zu erhalten keine Notwendigkeit, Ihre eigene mitzubringen.",
"domainPickerVerified": "Verifiziert",
"domainPickerUnverified": "Nicht verifiziert",
"domainPickerManual": "Manuell",
"domainPickerInvalidSubdomainStructure": "Diese Subdomain enthält ungültige Zeichen oder Struktur. Sie wird beim Speichern automatisch bereinigt.",
"domainPickerError": "Fehler",
"domainPickerErrorLoadDomains": "Fehler beim Laden der Organisations-Domains",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Verwendungsanzeige",
"description": "Wählen Sie die Lizenz-Ebene, die Ihre beabsichtigte Nutzung genau widerspiegelt. Die Persönliche Lizenz erlaubt die freie Nutzung der Software für individuelle, nicht-kommerzielle oder kleine kommerzielle Aktivitäten mit jährlichen Brutto-Einnahmen von 100.000 USD. Über diese Grenzen hinausgehende Verwendungszwecke einschließlich der Verwendung innerhalb eines Unternehmens, einer Organisation, oder eine andere umsatzgenerierende Umgebung erfordert eine gültige Enterprise-Lizenz und die Zahlung der Lizenzgebühr. Alle Benutzer, ob Personal oder Enterprise, müssen die Fossorial Commercial License Bedingungen einhalten."
"description": "Wählen Sie die Lizenz-Ebene, die Ihre beabsichtigte Nutzung genau widerspiegelt. Die Persönliche Lizenz erlaubt die freie Nutzung der Software für individuelle, nicht-kommerzielle oder kleine kommerzielle Aktivitäten mit jährlichen Brutto-Einnahmen von 100.000 USD. Über diese Grenzen hinausgehende Verwendungszwecke einschließlich der Verwendung innerhalb eines Unternehmens, einer Organisation, oder eine andere umsatzgenerierende Umgebung - erfordert eine gültige Enterprise-Lizenz und die Zahlung der Lizenzgebühr. Alle Benutzer, ob Personal oder Enterprise, müssen die Fossorial Commercial License Bedingungen einhalten."
},
"trialPeriodInformation": {
"title": "Testperiode Information",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Maßstab",
"description": "Enterprise Features, 50 Benutzer, 50 Sites und Prioritätsunterstützung."
"description": "Unternehmensmerkmale, 50 Benutzer, 100 Standorte und prioritärer Support."
}
},
"personalUseOnly": "Nur persönliche Nutzung (kostenlose Lizenz keine Kasse)",
"personalUseOnly": "Nur persönliche Nutzung (kostenlose Lizenz - kein Checkout)",
"buttons": {
"continueToCheckout": "Weiter zur Kasse"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Maschinen-Clients",
"install": "Installieren",
"run": "Ausführen",
"envFile": "Umgebungsdatei",
"serviceFile": "Servicedatei",
"enableAndStart": "Aktivieren und Starten",
"clientNameDescription": "Der Anzeigename des Clients, der später geändert werden kann.",
"clientAddress": "Clientadresse (Erweitert)",
"setupFailedToFetchSubnet": "Fehler beim Abrufen des Standard-Subnetzes",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Keine Authentifizierung",
"httpDestAuthNoneDescription": "Sendet Anfragen ohne Autorisierungs-Header.",
"httpDestAuthBearerTitle": "Bären-Token",
"httpDestAuthBearerDescription": "Fügt eine Berechtigung hinzu: Bearer <token> Header zu jeder Anfrage.",
"httpDestAuthBearerDescription": "Fügt jedem Anfrage-Header eine \"Authorization: Bearer '<token>'\" hinzu.",
"httpDestAuthBearerPlaceholder": "Ihr API-Schlüssel oder Token",
"httpDestAuthBasicTitle": "Einfacher Auth",
"httpDestAuthBasicDescription": "Fügt eine Autorisierung hinzu: Basic <credentials> Kopfzeile hinzu. Geben Sie Anmeldedaten als Benutzername:password an.",
"httpDestAuthBasicDescription": "Fügt einen \"Authorization: Basic '<credentials>'\"-Header hinzu. Geben Sie die Anmeldedaten als Benutzername:Passwort an.",
"httpDestAuthBasicPlaceholder": "benutzername:password",
"httpDestAuthCustomTitle": "Eigene Kopfzeile",
"httpDestAuthCustomDescription": "Geben Sie einen eigenen HTTP-Header-Namen und einen Wert für die Authentifizierung an (z.B. X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "JSON Array",
"httpDestFormatJsonArrayDescription": "Eine Anfrage pro Stapel ist ein JSON-Array. Kompatibel mit den meisten generischen Webhooks und Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Eine Anfrage pro Batch, der Körper ist newline-getrenntes JSON ein Objekt pro Zeile, kein äußeres Array. Benötigt von Splunk HEC, Elastic / OpenSearch, und Grafana Loki.",
"httpDestFormatNdjsonDescription": "Eine Anfrage pro Batch, der Körper ist newline-getrenntes JSON - ein Objekt pro Zeile, kein äußeres Array. Benötigt von Splunk HEC, Elastic / OpenSearch, und Grafana Loki.",
"httpDestFormatSingleTitle": "Ein Ereignis pro Anfrage",
"httpDestFormatSingleDescription": "Sendet eine separate HTTP-POST für jedes einzelne Ereignis. Nur für Endpunkte, die Batches nicht handhaben können.",
"httpDestLogTypesTitle": "Log-Typen",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Ziel erfolgreich aktualisiert",
"httpDestCreatedSuccess": "Ziel erfolgreich erstellt",
"httpDestUpdateFailed": "Fehler beim Aktualisieren des Ziels",
"httpDestCreateFailed": "Fehler beim Erstellen des Ziels"
"httpDestCreateFailed": "Fehler beim Erstellen des Ziels",
"idpAddActionCreateNew": "Neuen Identitätsanbieter erstellen",
"idpAddActionImportFromOrg": "Von einer anderen Organisation importieren",
"idpImportDialogTitle": "Identitätsanbieter importieren",
"idpImportDialogDescription": "Wählen Sie einen Identitätsanbieter aus einer Organisation, in der Sie Administrator sind. Er wird mit dieser Organisation verknüpft.",
"idpImportSearchPlaceholder": "Nach Organisation oder Anbieternamen suchen...",
"idpImportEmpty": "Keine Identitätsanbieter gefunden.",
"idpImportedDescription": "Identitätsanbieter erfolgreich importiert.",
"idpDeleteGlobalQuestion": "Sind Sie sicher, dass Sie diesen Identitätsanbieter dauerhaft löschen möchten?",
"idpDeleteGlobalDescription": "Dies wird den Identitätsanbieter dauerhaft von allen Organisationen löschen, mit denen er verbunden ist.",
"idpUnassociateTitle": "Verknüpfung mit Identitätsanbieter aufheben",
"idpUnassociateQuestion": "Sind Sie sicher, dass Sie die Verknüpfung dieses Identitätsanbieters mit dieser Organisation aufheben möchten?",
"idpUnassociateDescription": "Alle Benutzer, die mit diesem Identitätsanbieter verbunden sind, werden aus dieser Organisation entfernt, aber der Identitätsanbieter bleibt für andere verbundene Organisationen weiterhin bestehen.",
"idpUnassociateConfirm": "Verknüpfung des Identitätsanbieters aufheben bestätigen",
"idpUnassociateWarning": "Dies kann für diese Organisation nicht rückgängig gemacht werden.",
"idpUnassociatedDescription": "Identitätsanbieter erfolgreich von dieser Organisation gelöst",
"idpUnassociateMenu": "Verknüpfung aufheben",
"idpDeleteAllOrgsMenu": "Löschen"
}
+254 -43
View File
@@ -1,4 +1,8 @@
{
"contactSalesEnable": "Contact sales to enable this feature.",
"contactSalesBookDemo": "Book a demo",
"contactSalesOr": "or",
"contactSalesContactUs": "contact us",
"setupCreate": "Create the organization, site, and resources",
"headerAuthCompatibilityInfo": "Enable this to force a 401 Unauthorized response when an authentication token is missing. This is required for browsers or specific HTTP libraries that do not send credentials without a server challenge.",
"headerAuthCompatibility": "Extended compatibility",
@@ -163,7 +167,7 @@
"proxyResourceTitle": "Manage Public Resources",
"proxyResourceDescription": "Create and manage resources that are publicly accessible through a web browser",
"proxyResourcesBannerTitle": "Web-based Public Access",
"proxyResourcesBannerDescription": "Public resources are HTTPS or TCP/UDP proxies accessible to anyone on the internet through a web browser. Unlike private resources, they do not require client-side software and can include identity and context-aware access policies.",
"proxyResourcesBannerDescription": "Public resources are HTTPS proxies accessible to anyone on the internet through a web browser. Unlike private resources, they do not require client-side software and can include identity and context-aware access policies.",
"clientResourceTitle": "Manage Private Resources",
"clientResourceDescription": "Create and manage resources that are only accessible through a connected client",
"privateResourcesBannerTitle": "Zero-Trust Private Access",
@@ -371,16 +375,16 @@
"provisioningKeysUpdated": "Provisioning key updated",
"provisioningKeysUpdatedDescription": "Your changes have been saved.",
"provisioningKeysBannerTitle": "Site Provisioning Keys",
"provisioningKeysBannerDescription": "Generate a provisioning key and use it with the Newt connector to automatically create sites on first startup no need to set up separate credentials for each site.",
"provisioningKeysBannerDescription": "Generate a provisioning key and use it with the Newt connector to automatically create sites on first startup - no need to set up separate credentials for each site.",
"provisioningKeysBannerButtonText": "Learn More",
"pendingSitesBannerTitle": "Pending Sites",
"pendingSitesBannerDescription": "Sites that connect using a provisioning key appear here for review. Approve each site before it becomes active and gains access to your resources.",
"pendingSitesBannerDescription": "Sites that connect using a provisioning key appear here for review.",
"pendingSitesBannerButtonText": "Learn More",
"apiKeysSettings": "{apiKeyName} Settings",
"userTitle": "Manage All Users",
"userDescription": "View and manage all users in the system",
"userAbount": "About User Management",
"userAbountDescription": "This table displays all root user objects in the system. Each user may belong to multiple organizations. Removing a user from an organization does not delete their root user object - they will remain in the system. To completely remove a user from the system, you must delete their root user object using the delete action in this table.",
"userAbountDescription": "This table displays all base user objects in the system. Each user may belong to multiple organizations. Removing a user from an organization does not delete their base user object. They will remain in the system. To completely remove a user from the system, you must delete their base user object using the delete action in this table.",
"userServer": "Server Users",
"userSearch": "Search server users...",
"userErrorDelete": "Error deleting user",
@@ -405,6 +409,10 @@
"licenseErrorKeyActivate": "Failed to activate license key",
"licenseErrorKeyActivateDescription": "An error occurred while activating the license key.",
"licenseAbout": "About Licensing",
"licenseBannerTitle": "Enable Your Enterprise License",
"licenseBannerDescription": "Unlock enterprise features for your self-hosted Pangolin instance. Purchase a license key to activate premium capabilities, then add it below.",
"licenseBannerGetLicense": "Get a License",
"licenseBannerViewDocs": "View Documentation",
"communityEdition": "Community Edition",
"licenseAboutDescription": "This is for business and enterprise users who are using Pangolin in a commercial environment. If you are using Pangolin for personal use, you can ignore this section.",
"licenseKeyActivated": "License key activated",
@@ -519,7 +527,7 @@
"userSettings": "User Information",
"userSettingsDescription": "Enter the details for the new user",
"inviteEmailSent": "Send invite email to user",
"inviteValid": "Valid For",
"inviteValid": "Invite Valid For (days)",
"selectDuration": "Select duration",
"selectResource": "Select Resource",
"filterByResource": "Filter By Resource",
@@ -894,6 +902,7 @@
"idpDisplayName": "A display name for this identity provider",
"idpAutoProvisionUsers": "Auto Provision Users",
"idpAutoProvisionUsersDescription": "When enabled, users will be automatically created in the system upon first login with the ability to map users to roles and organizations.",
"idpAutoProvisionConfigureAfterCreate": "You can configure auto provision settings once the identity provider is created.",
"licenseBadge": "EE",
"idpType": "Provider Type",
"idpTypeDescription": "Select the type of identity provider you want to configure",
@@ -945,7 +954,7 @@
"defaultMappingsRole": "Default Role Mapping",
"defaultMappingsRoleDescription": "The result of this expression must return the role name as defined in the organization as a string.",
"defaultMappingsOrg": "Default Organization Mapping",
"defaultMappingsOrgDescription": "When set, this expression must return the organization ID or true for the user to access that organization. When unset, defining an organization policy for that org is enough: the user is allowed in as long as a valid role mapping can be resolved for them within the organization.",
"defaultMappingsOrgDescription": "When set, this expression must return the organization ID or true for the user to access that organization. When unset, defining a role mapping is enough: the user is allowed in as long as a valid role mapping can be resolved for them within the organization.",
"defaultMappingsSubmit": "Save Default Mappings",
"orgPoliciesEdit": "Edit Organization Policy",
"org": "Organization",
@@ -1252,6 +1261,7 @@
"actionViewLogs": "View Logs",
"noneSelected": "None selected",
"orgNotFound2": "No organizations found.",
"search": "Search…",
"searchPlaceholder": "Search...",
"emptySearchOptions": "No options found",
"create": "Create",
@@ -1336,10 +1346,138 @@
"sidebarGeneral": "Manage",
"sidebarLogAndAnalytics": "Log & Analytics",
"sidebarBluePrints": "Blueprints",
"sidebarAlerting": "Alerting",
"sidebarOrganization": "Organization",
"sidebarManagement": "Management",
"sidebarBillingAndLicenses": "Billing & Licenses",
"sidebarLogsAnalytics": "Analytics",
"alertingTitle": "Alerting",
"alertingDescription": "Define sources, triggers, and actions for notifications",
"alertingRules": "Alert rules",
"alertingSearchRules": "Search rules…",
"alertingAddRule": "Create Rule",
"alertingColumnSource": "Source",
"alertingColumnTrigger": "Trigger",
"alertingColumnActions": "Actions",
"alertingColumnEnabled": "Enabled",
"alertingDeleteQuestion": "Delete this alert rule? This cannot be undone.",
"alertingDeleteRule": "Delete alert rule",
"alertingRuleDeleted": "Alert rule deleted",
"alertingRuleSaved": "Alert rule saved",
"alertingEditRule": "Edit alert rule",
"alertingCreateRule": "Create alert rule",
"alertingRuleCredenzaDescription": "Choose what to watch, when to fire, and how to notify your team.",
"alertingRuleNamePlaceholder": "Production site down",
"alertingRuleEnabled": "Rule enabled",
"alertingSectionSource": "Source",
"alertingSourceType": "Source type",
"alertingSourceSite": "Site",
"alertingSourceHealthCheck": "Health check",
"alertingPickSites": "Sites",
"alertingPickHealthChecks": "Health checks",
"alertingPickResources": "Resources",
"alertingAllSites": "All Sites",
"alertingAllSitesDescription": "Alert fires for any site",
"alertingSpecificSites": "Specific Sites",
"alertingSpecificSitesDescription": "Choose specific sites to watch",
"alertingAllHealthChecks": "All Health Checks",
"alertingAllHealthChecksDescription": "Alert fires for any health check",
"alertingSpecificHealthChecks": "Specific Health Checks",
"alertingSpecificHealthChecksDescription": "Choose specific health checks to watch",
"alertingAllResources": "All Resources",
"alertingAllResourcesDescription": "Alert fires for any resource",
"alertingSpecificResources": "Specific resources",
"alertingSpecificResourcesDescription": "Choose specific resources to watch",
"alertingSelectResources": "Select resources…",
"alertingResourcesSelected": "{count} resources selected",
"alertingResourcesEmpty": "No resources with targets in the first 10 results.",
"alertingSectionTrigger": "Trigger",
"alertingTrigger": "When to alert",
"alertingTriggerSiteOnline": "Site online",
"alertingTriggerSiteOffline": "Site offline",
"alertingTriggerSiteToggle": "Site status changes",
"alertingTriggerHcHealthy": "Health check healthy",
"alertingTriggerHcUnhealthy": "Health check unhealthy",
"alertingTriggerHcToggle": "Health check status changes",
"alertingTriggerResourceHealthy": "Resource healthy",
"alertingTriggerResourceUnhealthy": "Resource unhealthy",
"alertingSearchHealthChecks": "Search health checks…",
"alertingHealthChecksEmpty": "No health checks available.",
"alertingTriggerResourceToggle": "Resource status changes",
"alertingSourceResource": "Resource",
"alertingSectionActions": "Actions",
"alertingAddAction": "Add action",
"alertingActionNotify": "Email",
"alertingActionNotifyDescription": "Send email notifications to users or roles",
"alertingActionWebhook": "Webhook",
"alertingActionWebhookDescription": "Send an HTTP request to a custom endpoint",
"alertingExternalIntegration": "External Integration",
"alertingExternalPagerDutyDescription": "Send alerts to PagerDuty for incident management",
"alertingExternalOpsgenieDescription": "Route alerts to Opsgenie for on-call management",
"alertingExternalServiceNowDescription": "Create ServiceNow incidents from alert events",
"alertingExternalIncidentIoDescription": "Trigger Incident.io workflows from alert events",
"alertingActionType": "Action type",
"alertingNotifyUsers": "Users",
"alertingNotifyRoles": "Roles",
"alertingNotifyEmails": "Email addresses",
"alertingEmailPlaceholder": "Add email and press Enter",
"alertingWebhookMethod": "HTTP method",
"alertingWebhookSecret": "Signing secret (optional)",
"alertingWebhookSecretPlaceholder": "HMAC secret",
"alertingWebhookHeaders": "Headers",
"alertingAddHeader": "Add header",
"alertingSelectSites": "Select sites…",
"alertingSitesSelected": "{count} sites selected",
"alertingSelectHealthChecks": "Select health checks…",
"alertingHealthChecksSelected": "{count} health checks selected",
"alertingNoHealthChecks": "No targets with health checks enabled",
"alertingHealthCheckStub": "Health check source selection is not wired up yet - you can still configure triggers and actions.",
"alertingSelectUsers": "Select users…",
"alertingUsersSelected": "{count} users selected",
"alertingSelectRoles": "Select roles…",
"alertingRolesSelected": "{count} roles selected",
"alertingSummarySites": "Sites ({count})",
"alertingSummaryHealthChecks": "Health checks ({count})",
"alertingSummaryResources": "Resources ({count})",
"alertingErrorNameRequired": "Enter a name",
"alertingErrorActionsMin": "Add at least one action",
"alertingErrorPickSites": "Select at least one site",
"alertingErrorPickHealthChecks": "Select at least one health check",
"alertingErrorPickResources": "Select at least one resource",
"alertingErrorTriggerSite": "Choose a site trigger",
"alertingErrorTriggerHealth": "Choose a health check trigger",
"alertingErrorTriggerResource": "Choose a resource trigger",
"alertingErrorNotifyRecipients": "Pick users, roles, or at least one email",
"alertingConfigureSource": "Configure Source",
"alertingConfigureTrigger": "Configure Trigger",
"alertingConfigureActions": "Configure Actions",
"alertingBackToRules": "Back to Rules",
"alertingDraftBadge": "Draft - save to store this rule",
"alertingSidebarHint": "Click a step on the canvas to edit it here.",
"alertingGraphCanvasTitle": "Rule Flow",
"alertingGraphCanvasDescription": "Visual overview of source, trigger, and actions. Select a node to edit it in the panel.",
"alertingNodeNotConfigured": "Not configured yet",
"alertingNodeActionsCount": "{count, plural, one {# action} other {# actions}}",
"alertingNodeRoleSource": "Source",
"alertingNodeRoleTrigger": "Trigger",
"alertingNodeRoleAction": "Action",
"alertingTabRules": "Alert Rules",
"alertingTabHealthChecks": "Health Checks",
"standaloneHcTableTitle": "Health Checks",
"standaloneHcSearchPlaceholder": "Search health checks…",
"standaloneHcAddButton": "Create Health Check",
"standaloneHcCreateTitle": "Create Health Check",
"standaloneHcEditTitle": "Edit Health Check",
"standaloneHcDescription": "Configure a HTTP or TCP health check for use in alert rules.",
"standaloneHcNameLabel": "Name",
"standaloneHcNamePlaceholder": "My HTTP Monitor",
"standaloneHcDeleteTitle": "Delete health check",
"standaloneHcDeleteQuestion": "Delete this health check? This cannot be undone.",
"standaloneHcDeleted": "Health check deleted",
"standaloneHcSaved": "Health check saved",
"standaloneHcColumnHealth": "Health",
"standaloneHcColumnMode": "Mode",
"standaloneHcColumnTarget": "Target",
"blueprints": "Blueprints",
"blueprintsDescription": "Apply declarative configurations and view previous runs",
"blueprintAdd": "Add Blueprint",
@@ -1745,8 +1883,8 @@
"retryAttempts": "Retry Attempts",
"expectedResponseCodes": "Expected Response Codes",
"expectedResponseCodesDescription": "HTTP status code that indicates healthy status. If left blank, 200-300 is considered healthy.",
"customHeaders": "Custom Headers",
"customHeadersDescription": "Headers new line separated: Header-Name: value",
"customHeaders": "Custom Request Headers",
"customHeadersDescription": "Request headers sent to the downstream targets. Headers new line separated: Header-Name: value",
"headersValidationError": "Headers must be in the format: Header-Name: value",
"saveHealthCheck": "Save Health Check",
"healthCheckSaved": "Health Check Saved",
@@ -1758,8 +1896,17 @@
"healthCheckIntervalMin": "Check interval must be at least 5 seconds",
"healthCheckTimeoutMin": "Timeout must be at least 1 second",
"healthCheckRetryMin": "Retry attempts must be at least 1",
"httpMethod": "HTTP Method",
"selectHttpMethod": "Select HTTP method",
"healthCheckMode": "Check Mode",
"healthCheckStrategy": "Strategy",
"healthCheckModeDescription": "TCP mode verifies connectivity only. HTTP mode validates the HTTP response.",
"healthyThreshold": "Healthy Threshold",
"healthyThresholdDescription": "Consecutive successes required before marking as healthy.",
"unhealthyThreshold": "Unhealthy Threshold",
"unhealthyThresholdDescription": "Consecutive failures required before marking as unhealthy.",
"healthCheckHealthyThresholdMin": "Healthy threshold must be at least 1",
"healthCheckUnhealthyThresholdMin": "Unhealthy threshold must be at least 1",
"httpMethod": "Scheme",
"selectHttpMethod": "Select scheme",
"domainPickerSubdomainLabel": "Subdomain",
"domainPickerBaseDomainLabel": "Base Domain",
"domainPickerSearchDomains": "Search domains...",
@@ -1817,6 +1964,11 @@
"editInternalResourceDialogModePort": "Port",
"editInternalResourceDialogModeHost": "Host",
"editInternalResourceDialogModeCidr": "CIDR",
"editInternalResourceDialogModeHttp": "HTTP",
"editInternalResourceDialogModeHttps": "HTTPS",
"editInternalResourceDialogScheme": "Scheme",
"editInternalResourceDialogEnableSsl": "Enable SSL",
"editInternalResourceDialogEnableSslDescription": "Enable SSL/TLS encryption for secure HTTPS connections to the destination.",
"editInternalResourceDialogDestination": "Destination",
"editInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.",
"editInternalResourceDialogDestinationIPDescription": "The IP or hostname address of the resource on the site's network.",
@@ -1832,6 +1984,7 @@
"createInternalResourceDialogName": "Name",
"createInternalResourceDialogSite": "Site",
"selectSite": "Select site...",
"multiSitesSelectorSitesCount": "{count, plural, one {# site} other {# sites}}",
"noSitesFound": "No sites found.",
"createInternalResourceDialogProtocol": "Protocol",
"createInternalResourceDialogTcp": "TCP",
@@ -1860,11 +2013,19 @@
"createInternalResourceDialogModePort": "Port",
"createInternalResourceDialogModeHost": "Host",
"createInternalResourceDialogModeCidr": "CIDR",
"createInternalResourceDialogModeHttp": "HTTP",
"createInternalResourceDialogModeHttps": "HTTPS",
"scheme": "Scheme",
"createInternalResourceDialogScheme": "Scheme",
"createInternalResourceDialogEnableSsl": "Enable SSL",
"createInternalResourceDialogEnableSslDescription": "Enable SSL/TLS encryption for secure HTTPS connections to the destination.",
"createInternalResourceDialogDestination": "Destination",
"createInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.",
"createInternalResourceDialogDestinationCidrDescription": "The CIDR range of the resource on the site's network.",
"createInternalResourceDialogAlias": "Alias",
"createInternalResourceDialogAliasDescription": "An optional internal DNS alias for this resource.",
"internalResourceDownstreamSchemeRequired": "Scheme is required for HTTP resources",
"internalResourceHttpPortRequired": "Destination port is required for HTTP resources",
"siteConfiguration": "Configuration",
"siteAcceptClientConnections": "Accept Client Connections",
"siteAcceptClientConnectionsDescription": "Allow user devices and clients to access resources on this site. This can be changed later.",
@@ -1989,7 +2150,7 @@
"description": "More reliable and low-maintenance self-hosted Pangolin server with extra bells and whistles",
"introTitle": "Managed Self-Hosted Pangolin",
"introDescription": "is a deployment option designed for people who want simplicity and extra reliability while still keeping their data private and self-hosted.",
"introDetail": "With this option, you still run your own Pangolin node your tunnels, SSL termination, and traffic all stay on your server. The difference is that management and monitoring are handled through our cloud dashboard, which unlocks a number of benefits:",
"introDetail": "With this option, you still run your own Pangolin node - your tunnels, SSL termination, and traffic all stay on your server. The difference is that management and monitoring are handled through our cloud dashboard, which unlocks a number of benefits:",
"benefitSimplerOperations": {
"title": "Simpler operations",
"description": "No need to run your own mail server or set up complex alerting. You'll get health checks and downtime alerts out of the box."
@@ -2022,7 +2183,7 @@
},
"internationaldomaindetected": "International Domain Detected",
"willbestoredas": "Will be stored as:",
"roleMappingDescription": "Determine how roles are assigned to users when they sign in when Auto Provision is enabled.",
"roleMappingDescription": "Determine how roles are assigned to users when they sign in with this identity provider.",
"selectRole": "Select a Role",
"roleMappingExpression": "Expression",
"selectRolePlaceholder": "Choose a role",
@@ -2113,9 +2274,11 @@
"addDomainToEnableCustomAuthPages": "Users will be able to access the organization's login page and complete resource authentication using this domain.",
"selectDomainForOrgAuthPage": "Select a domain for the organization's authentication page",
"domainPickerProvidedDomain": "Provided Domain",
"domainPickerFreeProvidedDomain": "Free Provided Domain",
"domainPickerFreeProvidedDomain": "Provided Domain",
"domainPickerFreeDomainsPaidFeature": "Provided domains are a paid feature. Subscribe to get a domain included with your plan - no need to bring your own.",
"domainPickerVerified": "Verified",
"domainPickerUnverified": "Unverified",
"domainPickerManual": "Manual",
"domainPickerInvalidSubdomainStructure": "This subdomain contains invalid characters or structure. It will be sanitized automatically when you save.",
"domainPickerError": "Error",
"domainPickerErrorLoadDomains": "Failed to load organization domains",
@@ -2290,7 +2453,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Usage Disclosure",
"description": "Select the license tier that accurately reflects your intended use. The Personal License permits free use of the Software for individual, non-commercial or small-scale commercial activities with annual gross revenue under $100,000 USD. Any use beyond these limits including use within a business, organization, or other revenue-generating environment requires a valid Enterprise License and payment of the applicable licensing fee. All users, whether Personal or Enterprise, must comply with the Fossorial Commercial License Terms."
"description": "Select the license tier that accurately reflects your intended use. The Personal License permits free use of the Software for individual, non-commercial or small-scale commercial activities with annual gross revenue under $100,000 USD. Any use beyond these limits - including use within a business, organization, or other revenue-generating environment - requires a valid Enterprise License and payment of the applicable licensing fee. All users, whether Personal or Enterprise, must comply with the Fossorial Commercial License Terms."
},
"trialPeriodInformation": {
"title": "Trial Period Information",
@@ -2345,10 +2508,10 @@
},
"scale": {
"title": "Scale",
"description": "Enterprise features, 50 users, 50 sites, and priority support."
"description": "Enterprise features, 50 users, 100 sites, and priority support."
}
},
"personalUseOnly": "Personal use only (free license no checkout)",
"personalUseOnly": "Personal use only (free license - no checkout)",
"buttons": {
"continueToCheckout": "Continue to Checkout"
},
@@ -2409,7 +2572,7 @@
"action": "Action",
"actor": "Actor",
"timestamp": "Timestamp",
"accessLogs": "Access Logs",
"accessLogs": "Authentication Logs",
"exportCsv": "Export CSV",
"exportError": "Unknown error when exporting CSV",
"exportCsvTooltip": "Within Time Range",
@@ -2422,6 +2585,7 @@
"validPassword": "Valid Password",
"validEmail": "Valid email",
"validSSO": "Valid SSO",
"connectedClient": "Connected Client",
"resourceBlocked": "Resource Blocked",
"droppedByRule": "Dropped by Rule",
"noSessions": "No Sessions",
@@ -2429,25 +2593,25 @@
"noMoreAuthMethods": "No Valid Auth",
"ip": "IP",
"reason": "Reason",
"requestLogs": "Request Logs",
"requestLogs": "HTTPS Request Logs",
"requestAnalytics": "Request Analytics",
"host": "Host",
"location": "Location",
"actionLogs": "Action Logs",
"sidebarLogsRequest": "Request Logs",
"sidebarLogsAccess": "Access Logs",
"sidebarLogsAction": "Action Logs",
"actionLogs": "Admin Action Logs",
"sidebarLogsRequest": "HTTPS Request Logs",
"sidebarLogsAccess": "Authentication Logs",
"sidebarLogsAction": "Admin Action Logs",
"logRetention": "Log Retention",
"logRetentionDescription": "Manage how long different types of logs are retained for this organization or disable them",
"requestLogsDescription": "View detailed request logs for resources in this organization",
"requestLogsDescription": "View detailed request logs for HTTPS resources in this organization",
"requestAnalyticsDescription": "View detailed request analytics for resources in this organization",
"logRetentionRequestLabel": "Request Log Retention",
"logRetentionRequestLabel": "HTTPS Request Log Retention",
"logRetentionRequestDescription": "How long to retain request logs",
"logRetentionAccessLabel": "Access Log Retention",
"logRetentionAccessLabel": "Authentication Log Retention",
"logRetentionAccessDescription": "How long to retain access logs",
"logRetentionActionLabel": "Action Log Retention",
"logRetentionActionLabel": "Admin Action Log Retention",
"logRetentionActionDescription": "How long to retain action logs",
"logRetentionConnectionLabel": "Connection Log Retention",
"logRetentionConnectionLabel": "Network Log Retention",
"logRetentionConnectionDescription": "How long to retain connection logs",
"logRetentionDisabled": "Disabled",
"logRetention3Days": "3 days",
@@ -2459,10 +2623,10 @@
"logRetentionEndOfFollowingYear": "End of following year",
"actionLogsDescription": "View a history of actions performed in this organization",
"accessLogsDescription": "View access auth requests for resources in this organization",
"connectionLogs": "Connection Logs",
"connectionLogsDescription": "View connection logs for tunnels in this organization",
"sidebarLogsConnection": "Connection Logs",
"sidebarLogsStreaming": "Streaming",
"connectionLogs": "Network Logs",
"connectionLogsDescription": "View network session logs handled by sites in this organization",
"sidebarLogsConnection": "Network Logs",
"sidebarLogsStreaming": "Event Streaming",
"sourceAddress": "Source Address",
"destinationAddress": "Destination Address",
"duration": "Duration",
@@ -2609,6 +2773,9 @@
"machineClients": "Machine Clients",
"install": "Install",
"run": "Run",
"envFile": "Environment File",
"serviceFile": "Service File",
"enableAndStart": "Enable and Start",
"clientNameDescription": "The display name of the client that can be changed later.",
"clientAddress": "Client Address (Advanced)",
"setupFailedToFetchSubnet": "Failed to fetch default subnet",
@@ -2656,8 +2823,12 @@
"editInternalResourceDialogAddUsers": "Add Users",
"editInternalResourceDialogAddClients": "Add Clients",
"editInternalResourceDialogDestinationLabel": "Destination",
"editInternalResourceDialogDestinationDescription": "Specify the destination address for the internal resource. This can be a hostname, IP address, or CIDR range depending on the selected mode. Optionally set an internal DNS alias for easier identification.",
"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.",
"editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.",
"createInternalResourceDialogHttpConfiguration": "HTTP configuration",
"createInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
"editInternalResourceDialogHttpConfiguration": "HTTP configuration",
"editInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
"editInternalResourceDialogTcp": "TCP",
"editInternalResourceDialogUdp": "UDP",
"editInternalResourceDialogIcmp": "ICMP",
@@ -2696,6 +2867,8 @@
"maintenancePageMessagePlaceholder": "We'll be back soon! Our site is currently undergoing scheduled maintenance.",
"maintenancePageMessageDescription": "Detailed message explaining the maintenance",
"maintenancePageTimeTitle": "Estimated Completion Time (Optional)",
"privateMaintenanceScreenTitle": "Private Placeholder Screen",
"privateMaintenanceScreenMessage": "This domain is being used on a private resource. Please connect using the Pangolin client to access this resource.",
"maintenanceTime": "e.g., 2 hours, Nov 1 at 5:00 PM",
"maintenanceEstimatedTimeDescription": "When you expect maintenance to be completed",
"editDomain": "Edit Domain",
@@ -2815,9 +2988,9 @@
"streamingHttpWebhookTitle": "HTTP Webhook",
"streamingHttpWebhookDescription": "Send events to any HTTP endpoint with flexible authentication and templating.",
"streamingS3Title": "Amazon S3",
"streamingS3Description": "Stream events to an S3-compatible object storage bucket. Coming soon.",
"streamingS3Description": "Stream events to an S3-compatible object storage bucket.",
"streamingDatadogTitle": "Datadog",
"streamingDatadogDescription": "Forward events directly to your Datadog account. Coming soon.",
"streamingDatadogDescription": "Forward events directly to your Datadog account.",
"streamingTypePickerDescription": "Choose a destination type to get started.",
"streamingFailedToLoad": "Failed to load destinations",
"streamingUnexpectedError": "An unexpected error occurred.",
@@ -2833,6 +3006,14 @@
"httpDestAddTitle": "Add HTTP Destination",
"httpDestEditDescription": "Update the configuration for this HTTP event streaming destination.",
"httpDestAddDescription": "Configure a new HTTP endpoint to receive your organization's events.",
"S3DestEditTitle": "Edit Destination",
"S3DestAddTitle": "Add S3 Destination",
"S3DestEditDescription": "Update the configuration for this S3 event streaming destination.",
"S3DestAddDescription": "Configure a new S3 endpoint to receive your organization's events.",
"datadogDestEditTitle": "Edit Destination",
"datadogDestAddTitle": "Add Datadog Destination",
"datadogDestEditDescription": "Update the configuration for this Datadog event streaming destination.",
"datadogDestAddDescription": "Configure a new Datadog endpoint to receive your organization's events.",
"httpDestTabSettings": "Settings",
"httpDestTabHeaders": "Headers",
"httpDestTabBody": "Body",
@@ -2840,17 +3021,17 @@
"httpDestNamePlaceholder": "My HTTP destination",
"httpDestUrlLabel": "Destination URL",
"httpDestUrlErrorHttpRequired": "URL must use http or https",
"httpDestUrlErrorHttpsRequired": "HTTPS is required on cloud deployments",
"httpDestUrlErrorHttpsRequired": "HTTPS is required",
"httpDestUrlErrorInvalid": "Enter a valid URL (e.g. https://example.com/webhook)",
"httpDestAuthTitle": "Authentication",
"httpDestAuthDescription": "Choose how requests to your endpoint are authenticated.",
"httpDestAuthNoneTitle": "No Authentication",
"httpDestAuthNoneDescription": "Sends requests without an Authorization header.",
"httpDestAuthBearerTitle": "Bearer Token",
"httpDestAuthBearerDescription": "Adds an Authorization: Bearer <token> header to each request.",
"httpDestAuthBearerDescription": "Adds an Authorization: Bearer '<token>' header to each request.",
"httpDestAuthBearerPlaceholder": "Your API key or token",
"httpDestAuthBasicTitle": "Basic Auth",
"httpDestAuthBasicDescription": "Adds an Authorization: Basic <credentials> header. Provide credentials as username:password.",
"httpDestAuthBasicDescription": "Adds an Authorization: Basic '<credentials>' header. Provide credentials as username:password.",
"httpDestAuthBasicPlaceholder": "username:password",
"httpDestAuthCustomTitle": "Custom Header",
"httpDestAuthCustomDescription": "Specify a custom HTTP header name and value for authentication (e.g. X-API-Key).",
@@ -2872,23 +3053,53 @@
"httpDestFormatJsonArrayTitle": "JSON Array",
"httpDestFormatJsonArrayDescription": "One request per batch, body is a JSON array. Compatible with most generic webhooks and Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "One request per batch, body is newline-delimited JSON one object per line, no outer array. Required by Splunk HEC, Elastic / OpenSearch, and Grafana Loki.",
"httpDestFormatNdjsonDescription": "One request per batch, body is newline-delimited JSON - one object per line, no outer array. Required by Splunk HEC, Elastic / OpenSearch, and Grafana Loki.",
"httpDestFormatSingleTitle": "One Event Per Request",
"httpDestFormatSingleDescription": "Sends a separate HTTP POST for each individual event. Use only for endpoints that cannot handle batches.",
"httpDestLogTypesTitle": "Log Types",
"httpDestLogTypesDescription": "Choose which log types are forwarded to this destination. Only enabled log types will be streamed.",
"httpDestAccessLogsTitle": "Access Logs",
"httpDestAccessLogsTitle": "Authentication Logs",
"httpDestAccessLogsDescription": "Resource access attempts, including authenticated and denied requests.",
"httpDestActionLogsTitle": "Action Logs",
"httpDestActionLogsTitle": "Admin Action Logs",
"httpDestActionLogsDescription": "Administrative actions performed by users within the organization.",
"httpDestConnectionLogsTitle": "Connection Logs",
"httpDestConnectionLogsTitle": "Network Logs",
"httpDestConnectionLogsDescription": "Site and tunnel connection events, including connects and disconnects.",
"httpDestRequestLogsTitle": "Request Logs",
"httpDestRequestLogsTitle": "HTTPS Request Logs",
"httpDestRequestLogsDescription": "HTTP request logs for proxied resources, including method, path, and response code.",
"httpDestSaveChanges": "Save Changes",
"httpDestCreateDestination": "Create Destination",
"httpDestUpdatedSuccess": "Destination updated successfully",
"httpDestCreatedSuccess": "Destination created successfully",
"httpDestUpdateFailed": "Failed to update destination",
"httpDestCreateFailed": "Failed to create destination"
"httpDestCreateFailed": "Failed to create destination",
"followRedirects": "Follow Redirects",
"followRedirectsDescription": "Automatically follow HTTP redirects for requests.",
"alertingErrorWebhookUrl": "Please enter a valid URL for the webhook.",
"healthCheckStrategyHttp": "Validates connectivity and checks the HTTP response status.",
"healthCheckStrategyTcp": "Verifies TCP connectivity only, without inspecting the response.",
"healthCheckStrategySnmp": "Makes an SNMP get request to check the health of network devices and infrastructure.",
"healthCheckStrategyIcmp": "Uses ICMP echo requests (pings) to check if a resource is reachable and responsive.",
"healthCheckTabStrategy": "Strategy",
"healthCheckTabConnection": "Connection",
"healthCheckTabAdvanced": "Advanced",
"healthCheckStrategyNotAvailable": "This strategy is not available. Please contact sales to enable this feature.",
"uptime30d": "Uptime (30d)",
"idpAddActionCreateNew": "Create new identity provider",
"idpAddActionImportFromOrg": "Import from another organization",
"idpImportDialogTitle": "Import Identity Provider",
"idpImportDialogDescription": "Choose an identity provider from an organization where you are an admin. It will be linked to this organization.",
"idpImportSearchPlaceholder": "Search by organization or provider name...",
"idpImportEmpty": "No identity providers found.",
"idpImportedDescription": "Identity provider imported successfully.",
"idpDeleteGlobalQuestion": "Are you sure you want to permanently delete this identity provider?",
"idpDeleteGlobalDescription": "This will permanently delete the identity provider from all organizations it is associated with.",
"idpUnassociateTitle": "Unassociate Identity Provider",
"idpUnassociateQuestion": "Are you sure you want to unassociate this identity provider from this organization?",
"idpUnassociateDescription": "All users associated with this identity provider will be removed from this organization, but the identity provider will still continue to exist for other associated organizations.",
"idpUnassociateConfirm": "Confirm Unassociate Identity Provider",
"idpUnassociateWarning": "This cannot be undone for this organization.",
"idpUnassociatedDescription": "Identity provider unassociated from this organization successfully",
"idpUnassociateMenu": "Unassociate",
"idpDeleteAllOrgsMenu": "Delete",
"publicIpEndpoint": "Endpoint"
}
+40 -11
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Clave de aprovisionamiento actualizada",
"provisioningKeysUpdatedDescription": "Sus cambios han sido guardados.",
"provisioningKeysBannerTitle": "Claves de aprovisionamiento del sitio",
"provisioningKeysBannerDescription": "Generar una clave de aprovisionamiento y usarla con el conector Newt para crear automáticamente sitios en el primer inicio no es necesario configurar credenciales separadas para cada sitio.",
"provisioningKeysBannerDescription": "Genere una clave de aprovisionamiento y utilícela con el conector Newt para crear automáticamente sitios en el primer inicio: no es necesario configurar credenciales separadas para cada sitio.",
"provisioningKeysBannerButtonText": "Saber más",
"pendingSitesBannerTitle": "Sitios pendientes",
"pendingSitesBannerDescription": "Los sitios que se conectan usando una clave de aprovisionamiento aparecen aquí para su revisión. Aprobar cada sitio antes de que se active y obtenga acceso a sus recursos.",
"pendingSitesBannerDescription": "Los sitios que se conectan utilizando una clave de aprovisionamiento aparecen aquí para su revisión.",
"pendingSitesBannerButtonText": "Saber más",
"apiKeysSettings": "Ajustes {apiKeyName}",
"userTitle": "Administrar todos los usuarios",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Error al activar la clave de licencia",
"licenseErrorKeyActivateDescription": "Se ha producido un error al activar la clave de licencia.",
"licenseAbout": "Acerca de la licencia",
"licenseBannerTitle": "Habilitar su Licencia Enterprise",
"licenseBannerDescription": "Desbloquea funciones empresariales para tu instancia autohospedada de Pangolin. Compra una clave de licencia para activar capacidades premium, luego agréguela a continuación.",
"licenseBannerGetLicense": "Obtener una Licencia",
"licenseBannerViewDocs": "Ver Documentación",
"communityEdition": "Edición comunitaria",
"licenseAboutDescription": "Esto es para usuarios empresariales y empresariales que utilizan Pangolin en un entorno comercial. Si estás usando Pangolin para uso personal, puedes ignorar esta sección.",
"licenseKeyActivated": "Clave de licencia activada",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Por favor, introduzca un número de puerto válido",
"targetErrorNoSite": "Ningún sitio seleccionado",
"targetErrorNoSiteDescription": "Por favor, seleccione un sitio para el objetivo",
"targetTargetsCleared": "Objetivos eliminados",
"targetTargetsClearedDescription": "Todos los objetivos han sido eliminados de este recurso",
"targetCreated": "Objetivo creado",
"targetCreatedDescription": "El objetivo se ha creado correctamente",
"targetErrorCreate": "Error al crear el objetivo",
@@ -892,6 +898,7 @@
"idpDisplayName": "Un nombre mostrado para este proveedor de identidad",
"idpAutoProvisionUsers": "Auto-Provisión de Usuarios",
"idpAutoProvisionUsersDescription": "Cuando está habilitado, los usuarios serán creados automáticamente en el sistema al iniciar sesión con la capacidad de asignar a los usuarios a roles y organizaciones.",
"idpAutoProvisionConfigureAfterCreate": "Puede configurar las configuraciones de provisión automática una vez que se haya creado el proveedor de identidad.",
"licenseBadge": "EE",
"idpType": "Tipo de proveedor",
"idpTypeDescription": "Seleccione el tipo de proveedor de identidad que desea configurar",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Mapeo de Rol por defecto",
"defaultMappingsRoleDescription": "El resultado de esta expresión debe devolver el nombre del rol tal y como se define en la organización como una cadena.",
"defaultMappingsOrg": "Mapeo de organización por defecto",
"defaultMappingsOrgDescription": "Esta expresión debe devolver el ID de org o verdadero para que el usuario pueda acceder a la organización.",
"defaultMappingsOrgDescription": "Cuando se establece, esta expresión debe devolver el ID de la organización o verdadero para que el usuario acceda a esa organización. Cuando no se establece, definir un mapeo de roles es suficiente: se permite la entrada del usuario siempre que se pueda resolver un mapeo de roles válido para él dentro de la organización.",
"defaultMappingsSubmit": "Guardar asignaciones por defecto",
"orgPoliciesEdit": "Editar Política de Organización",
"org": "Organización",
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Dominio Internacional detectado",
"willbestoredas": "Se almacenará como:",
"roleMappingDescription": "Determinar cómo se asignan los roles a los usuarios cuando se registran cuando está habilitada la provisión automática.",
"roleMappingDescription": "Determine cómo se asignan los roles a los usuarios cuando inician sesión con este proveedor de identidad.",
"selectRole": "Seleccione un rol",
"roleMappingExpression": "Expresión",
"selectRolePlaceholder": "Elija un rol",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Seleccione un dominio para la página de autenticación de la organización",
"domainPickerProvidedDomain": "Dominio proporcionado",
"domainPickerFreeProvidedDomain": "Dominio proporcionado gratis",
"domainPickerFreeDomainsPaidFeature": "Los dominios proporcionados son una función de pago. Suscríbete para obtener un dominio incluido con tu plan - no necesitas traer el tuyo propio.",
"domainPickerVerified": "Verificado",
"domainPickerUnverified": "Sin verificar",
"domainPickerManual": "Manual",
"domainPickerInvalidSubdomainStructure": "Este subdominio contiene caracteres o estructura no válidos. Se limpiará automáticamente al guardar.",
"domainPickerError": "Error",
"domainPickerErrorLoadDomains": "Error al cargar los dominios de la organización",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Divulgación de uso",
"description": "Seleccione el nivel de licencia que refleje con precisión su uso previsto. La Licencia Personal permite el uso libre del Software para actividades comerciales individuales, no comerciales o de pequeña escala con ingresos brutos anuales inferiores a $100,000 USD. Cualquier uso más allá de estos límites incluyendo el uso dentro de una empresa, organización, u otro entorno de generación de ingresos requiere una Licencia Empresarial válida y el pago de la cuota de licencia aplicable. Todos los usuarios, ya sean personales o empresariales, deben cumplir con las Condiciones de Licencia Comercial Fossorial."
"description": "Seleccione el nivel de licencia que refleje con precisión su uso previsto. La Licencia Personal permite el uso libre del Software para actividades comerciales individuales, no comerciales o de pequeña escala con ingresos brutos anuales inferiores a $100,000 USD. Cualquier uso más allá de estos límites - incluyendo el uso dentro de una empresa, organización, u otro entorno de generación de ingresos - requiere una Licencia Empresarial válida y el pago de la cuota de licencia aplicable. Todos los usuarios, ya sean personales o empresariales, deben cumplir con las Condiciones de Licencia Comercial Fossorial."
},
"trialPeriodInformation": {
"title": "Información del período de prueba",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Escala",
"description": "Características de la empresa, 50 usuarios, 50 sitios y soporte prioritario."
"description": "Funcionalidades empresariales, 50 usuarios, 100 sitios y soporte prioritario."
}
},
"personalUseOnly": "Solo uso personal (licencia gratuita, sin pago)",
"personalUseOnly": "Solo uso personal (licencia gratuita - sin salida)",
"buttons": {
"continueToCheckout": "Continuar con el pago"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Clientes de la máquina",
"install": "Instalar",
"run": "Ejecutar",
"envFile": "Archivo de Entorno",
"serviceFile": "Archivo de Servicio",
"enableAndStart": "Habilitar y empezar",
"clientNameDescription": "El nombre mostrado del cliente que se puede cambiar más adelante.",
"clientAddress": "Dirección del cliente (Avanzado)",
"setupFailedToFetchSubnet": "No se pudo obtener la subred por defecto",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Sin autenticación",
"httpDestAuthNoneDescription": "Envía solicitudes sin un encabezado de autorización.",
"httpDestAuthBearerTitle": "Tóken de portador",
"httpDestAuthBearerDescription": "Añade una autorización: portador <token> encabezado a cada solicitud.",
"httpDestAuthBearerDescription": "Añade un encabezado Authorization: Bearer '<token>' a cada solicitud.",
"httpDestAuthBearerPlaceholder": "Tu clave o token API",
"httpDestAuthBasicTitle": "Auth Básica",
"httpDestAuthBasicDescription": "Añade una Autorización: encabezado básico <credentials> . Proporcione credenciales como nombre de usuario: contraseña.",
"httpDestAuthBasicDescription": "Añade un encabezado Authorization: Basic '<credenciales>'. Proporcione las credenciales como nombredeusuario:contraseña.",
"httpDestAuthBasicPlaceholder": "usuario:contraseña",
"httpDestAuthCustomTitle": "Cabecera personalizada",
"httpDestAuthCustomDescription": "Especifique un nombre de cabecera HTTP personalizado y un valor para la autenticación (por ejemplo, X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "Matriz JSON",
"httpDestFormatJsonArrayDescription": "Una petición por lote, cuerpo es una matriz JSON. Compatible con la mayoría de los webhooks y Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Una petición por lote, el cuerpo es JSON delimitado por línea un objeto por línea, sin arrays externos. Requerido por Splunk HEC, Elastic / OpenSearch, y Grafana Loki.",
"httpDestFormatNdjsonDescription": "Una petición por lote, el cuerpo es JSON delimitado por línea - un objeto por línea, sin arrays externos. Requerido por Splunk HEC, Elastic / OpenSearch, y Grafana Loki.",
"httpDestFormatSingleTitle": "Un evento por solicitud",
"httpDestFormatSingleDescription": "Envía un HTTP POST separado para cada evento individual. Úsalo sólo para los extremos que no pueden manejar lotes.",
"httpDestLogTypesTitle": "Tipos de Log",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Destino actualizado correctamente",
"httpDestCreatedSuccess": "Destino creado correctamente",
"httpDestUpdateFailed": "Error al actualizar destino",
"httpDestCreateFailed": "Error al crear el destino"
"httpDestCreateFailed": "Error al crear el destino",
"idpAddActionCreateNew": "Crear nuevo proveedor de identidad",
"idpAddActionImportFromOrg": "Importar de otra organización",
"idpImportDialogTitle": "Importar Proveedor de Identidad",
"idpImportDialogDescription": "Elija un proveedor de identidad de una organización donde usted sea administrador. Se vinculará a esta organización.",
"idpImportSearchPlaceholder": "Buscar por nombre de organización o proveedor...",
"idpImportEmpty": "No se encontraron proveedores de identidad.",
"idpImportedDescription": "Proveedor de identidad importado con éxito.",
"idpDeleteGlobalQuestion": "¿Está seguro de que desea eliminar permanentemente este proveedor de identidad?",
"idpDeleteGlobalDescription": "Esto eliminará permanentemente el proveedor de identidad de todas las organizaciones con las que está asociado.",
"idpUnassociateTitle": "Desasociar Proveedor de Identidad",
"idpUnassociateQuestion": "¿Está seguro de que desea desasociar este proveedor de identidad de esta organización?",
"idpUnassociateDescription": "Todos los usuarios asociados con este proveedor de identidad serán eliminados de esta organización, pero el proveedor de identidad continuará existiendo para otras organizaciones asociadas.",
"idpUnassociateConfirm": "Confirme Desasociar Proveedor de Identidad",
"idpUnassociateWarning": "Esto no se puede deshacer para esta organización.",
"idpUnassociatedDescription": "Proveedor de identidad desasociado de esta organización con éxito",
"idpUnassociateMenu": "Desasociar",
"idpDeleteAllOrgsMenu": "Eliminar"
}
+41 -12
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Clé de provisioning mise à jour",
"provisioningKeysUpdatedDescription": "Vos modifications ont été enregistrées.",
"provisioningKeysBannerTitle": "Clés de provisioning du site",
"provisioningKeysBannerDescription": "Générez une clé de provisioning et utilisez-la avec le connecteur Newt pour créer automatiquement des sites au premier démarrage — pas besoin de configurer des identifiants distincts pour chaque site.",
"provisioningKeysBannerDescription": "Générez une clé de provisionnement et utilisez-la avec le connecteur Newt pour créer automatiquement des sites lors du premier démarrage - sans besoin de configurer des identifiants séparés pour chaque site.",
"provisioningKeysBannerButtonText": "En savoir plus",
"pendingSitesBannerTitle": "Sites en attente",
"pendingSitesBannerDescription": "Les sites qui se connectent à l'aide d'une clé de provisioning apparaissent ici pour être revus. Approuver chaque site avant qu'il ne devienne actif et qu'il accède à vos ressources.",
"pendingSitesBannerDescription": "Les sites qui se connectent en utilisant une clé de provisionnement apparaissent ici pour révision.",
"pendingSitesBannerButtonText": "En savoir plus",
"apiKeysSettings": "Paramètres de {apiKeyName}",
"userTitle": "Gérer tous les utilisateurs",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Échec de l'activation de la clé de licence",
"licenseErrorKeyActivateDescription": "Une erreur s'est produite lors de l'activation de la clé de licence.",
"licenseAbout": "À propos de la licence",
"licenseBannerTitle": "Activer Votre Licence Entreprise",
"licenseBannerDescription": "Débloquez les fonctionnalités d'entreprise pour votre instance autohébergée de Pangolin. Achetez une clé de licence pour activer les capacités premium, puis ajoutez-la ci-dessous.",
"licenseBannerGetLicense": "Obtenez une Licence",
"licenseBannerViewDocs": "Afficher la Documentation",
"communityEdition": "Edition Communautaire",
"licenseAboutDescription": "Ceci est destiné aux entreprises qui utilisent Pangolin dans un environnement commercial. Si vous utilisez Pangolin pour un usage personnel, vous pouvez ignorer cette section.",
"licenseKeyActivated": "Clé de licence activée",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Veuillez entrer un numéro de port valide",
"targetErrorNoSite": "Aucun site sélectionné",
"targetErrorNoSiteDescription": "Veuillez sélectionner un site pour la cible",
"targetTargetsCleared": "Cibles effacées",
"targetTargetsClearedDescription": "Toutes les cibles ont été retirées de cette ressource",
"targetCreated": "Cible créée",
"targetCreatedDescription": "La cible a été créée avec succès",
"targetErrorCreate": "Impossible de créer la cible",
@@ -892,6 +898,7 @@
"idpDisplayName": "Un nom d'affichage pour ce fournisseur d'identité",
"idpAutoProvisionUsers": "Approvisionnement automatique des utilisateurs",
"idpAutoProvisionUsersDescription": "Lorsque cette option est activée, les utilisateurs seront automatiquement créés dans le système lors de leur première connexion avec la possibilité de mapper les utilisateurs aux rôles et aux organisations.",
"idpAutoProvisionConfigureAfterCreate": "Vous pouvez configurer les paramètres de provisionnement automatique une fois le fournisseur d'identités créé.",
"licenseBadge": "EE",
"idpType": "Type de fournisseur",
"idpTypeDescription": "Sélectionnez le type de fournisseur d'identité que vous souhaitez configurer",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Mappage de rôle par défaut",
"defaultMappingsRoleDescription": "JMESPath pour extraire les informations de rôle du jeton ID. Le résultat de cette expression doit renvoyer le nom du rôle tel que défini dans l'organisation sous forme de chaîne.",
"defaultMappingsOrg": "Mappage d'organisation par défaut",
"defaultMappingsOrgDescription": "JMESPath pour extraire les informations d'organisation du jeton ID. Cette expression doit renvoyer l'ID de l'organisation ou true pour que l'utilisateur soit autorisé à accéder à l'organisation.",
"defaultMappingsOrgDescription": "Lorsque défini, cette expression doit renvoyer l'identifiant de l'organisation ou vrai pour que l'utilisateur accède à cette organisation. Lorsqu'indéfini, définir un mappage de rôle est suffisant : l'utilisateur est autorisé tant qu'un mappage de rôle valide peut être résolu pour lui au sein de l'organisation.",
"defaultMappingsSubmit": "Enregistrer les mappages par défaut",
"orgPoliciesEdit": "Modifier la politique d'organisation",
"org": "Organisation",
@@ -1987,7 +1994,7 @@
"description": "Serveur Pangolin auto-hébergé avec des cloches et des sifflets supplémentaires",
"introTitle": "Pangolin auto-hébergé géré",
"introDescription": "est une option de déploiement conçue pour les personnes qui veulent de la simplicité et de la fiabilité tout en gardant leurs données privées et auto-hébergées.",
"introDetail": "Avec cette option, vous exécutez toujours votre propre nœud Pangolin vos tunnels, la terminaison SSL et le trafic restent sur votre serveur. La différence est que la gestion et la surveillance sont gérées via notre tableau de bord du cloud, qui déverrouille un certain nombre d'avantages :",
"introDetail": "Avec cette option, vous exécutez toujours votre propre nœud Pangolin - vos tunnels, la terminaison SSL et le trafic restent sur votre serveur. La différence est que la gestion et la surveillance sont gérées via notre tableau de bord du cloud, qui déverrouille un certain nombre d'avantages :",
"benefitSimplerOperations": {
"title": "Opérations plus simples",
"description": "Pas besoin de faire tourner votre propre serveur de messagerie ou de configurer des alertes complexes. Vous obtiendrez des contrôles de santé et des alertes de temps d'arrêt par la suite."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Domaine international détecté",
"willbestoredas": "Sera stocké comme :",
"roleMappingDescription": "Détermine comment les rôles sont assignés aux utilisateurs lorsqu'ils se connectent lorsque la fourniture automatique est activée.",
"roleMappingDescription": "Déterminez comment les rôles sont attribués aux utilisateurs lorsqu'ils se connectent avec ce fournisseur d'identité.",
"selectRole": "Sélectionnez un rôle",
"roleMappingExpression": "Expression",
"selectRolePlaceholder": "Choisir un rôle",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Sélectionnez un domaine pour la page d'authentification de l'organisation",
"domainPickerProvidedDomain": "Domaine fourni",
"domainPickerFreeProvidedDomain": "Domaine fourni gratuitement",
"domainPickerFreeDomainsPaidFeature": "Les domaines fournis sont une fonctionnalité payante. Abonnez-vous pour obtenir un domaine inclus avec votre plan - plus besoin de fournir le vôtre.",
"domainPickerVerified": "Vérifié",
"domainPickerUnverified": "Non vérifié",
"domainPickerManual": "Manuel",
"domainPickerInvalidSubdomainStructure": "Ce sous-domaine contient des caractères ou une structure non valide. Il sera automatiquement nettoyé lorsque vous enregistrez.",
"domainPickerError": "Erreur",
"domainPickerErrorLoadDomains": "Impossible de charger les domaines de l'organisation",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Divulgation d'utilisation",
"description": "Sélectionnez le niveau de licence qui correspond exactement à votre utilisation prévue. La Licence Personnelle autorise l'utilisation libre du Logiciel pour des activités commerciales individuelles, non commerciales ou à petite échelle avec un revenu annuel brut inférieur à 100 000 USD. Toute utilisation au-delà de ces limites y compris l'utilisation au sein d'une entreprise, d'une organisation, ou tout autre environnement générateur de revenus nécessite une licence dentreprise valide et le paiement des droits de licence applicables. Tous les utilisateurs, qu'ils soient personnels ou d'entreprise, doivent se conformer aux conditions de licence commerciale Fossorial."
"description": "Sélectionnez le niveau de licence qui correspond exactement à votre utilisation prévue. La Licence Personnelle autorise l'utilisation libre du Logiciel pour des activités commerciales individuelles, non commerciales ou à petite échelle avec un revenu annuel brut inférieur à 100 000 USD. Toute utilisation au-delà de ces limites - y compris l'utilisation au sein d'une entreprise, d'une organisation, ou tout autre environnement générateur de revenus - nécessite une licence dentreprise valide et le paiement des droits de licence applicables. Tous les utilisateurs, qu'ils soient personnels ou d'entreprise, doivent se conformer aux conditions de licence commerciale Fossorial."
},
"trialPeriodInformation": {
"title": "Informations sur la période d'essai",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Échelle",
"description": "Fonctionnalités d'entreprise, 50 utilisateurs, 50 sites et une prise en charge prioritaire."
"description": "Fonctionnalités d'entreprise, 50 utilisateurs, 100 sites et support prioritaire."
}
},
"personalUseOnly": "Utilisation personnelle uniquement (licence gratuite — sans checkout)",
"personalUseOnly": "Usage personnel uniquement (licence gratuite - pas de validation)",
"buttons": {
"continueToCheckout": "Continuer vers le paiement"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Clients Machines",
"install": "Installer",
"run": "Exécuter",
"envFile": "Fichier Environnement",
"serviceFile": "Fichier de Service",
"enableAndStart": "Activer et Démarrer",
"clientNameDescription": "Le nom d'affichage du client qui peut être modifié plus tard.",
"clientAddress": "Adresse du client (Avancé)",
"setupFailedToFetchSubnet": "Impossible de récupérer le sous-réseau par défaut",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Aucune authentification",
"httpDestAuthNoneDescription": "Envoie des requêtes sans en-tête d'autorisation.",
"httpDestAuthBearerTitle": "Jeton de Porteur",
"httpDestAuthBearerDescription": "Ajoute un en-tête Authorization: Bearer <token> à chaque requête.",
"httpDestAuthBearerDescription": "Ajoute un en-tête Authorization: Bearer '<token>' à chaque requête.",
"httpDestAuthBearerPlaceholder": "Votre clé API ou votre jeton",
"httpDestAuthBasicTitle": "Authentification basique",
"httpDestAuthBasicDescription": "Ajoute une autorisation : en-tête de base <credentials> . Fournissez des informations d'identification comme nom d'utilisateur:mot de passe.",
"httpDestAuthBasicDescription": "Ajoute un en-tête Authorization: Basic '<credentials>'. Fournissez les identifiants sous la forme nom d'utilisateur:mot de passe.",
"httpDestAuthBasicPlaceholder": "nom d'utilisateur:mot de passe",
"httpDestAuthCustomTitle": "En-tête personnalisé",
"httpDestAuthCustomDescription": "Spécifiez un nom d'en-tête HTTP personnalisé et une valeur pour l'authentification (par exemple X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "Tableau JSON",
"httpDestFormatJsonArrayDescription": "Une requête par lot, le corps est un tableau JSON. Compatible avec la plupart des webhooks génériques et des datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Une requête par lot, body est un JSON délimité par une nouvelle ligne un objet par ligne, pas de tableau extérieur. Requis par Splunk HEC, Elastic / OpenSearch, et Grafana Loki.",
"httpDestFormatNdjsonDescription": "Une requête par lot, body est un JSON délimité par une nouvelle ligne - un objet par ligne, pas de tableau extérieur. Requis par Splunk HEC, Elastic / OpenSearch, et Grafana Loki.",
"httpDestFormatSingleTitle": "Un événement par demande",
"httpDestFormatSingleDescription": "Envoie un POST HTTP séparé pour chaque événement individuel. Utilisé uniquement pour les terminaux qui ne peuvent pas gérer des lots.",
"httpDestLogTypesTitle": "Types de logs",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Destination mise à jour avec succès",
"httpDestCreatedSuccess": "Destination créée avec succès",
"httpDestUpdateFailed": "Impossible de mettre à jour la destination",
"httpDestCreateFailed": "Impossible de créer la destination"
"httpDestCreateFailed": "Impossible de créer la destination",
"idpAddActionCreateNew": "Créer un nouveau fournisseur d'identité",
"idpAddActionImportFromOrg": "Importer d'une autre organisation",
"idpImportDialogTitle": "Importer le fournisseur d'identité",
"idpImportDialogDescription": "Choisissez un fournisseur d'identités d'une organisation où vous êtes administrateur. Il sera lié à cette organisation.",
"idpImportSearchPlaceholder": "Recherche par nom d'organisation ou de fournisseur...",
"idpImportEmpty": "Aucun fournisseur d'identités trouvé.",
"idpImportedDescription": "Fournisseur d'identités importé avec succès.",
"idpDeleteGlobalQuestion": "Êtes-vous sûr de vouloir supprimer définitivement ce fournisseur d'identités?",
"idpDeleteGlobalDescription": "Cela supprimera définitivement le fournisseur d'identités de toutes les organisations auxquelles il est associé.",
"idpUnassociateTitle": "Dissocier le fournisseur d'identité",
"idpUnassociateQuestion": "Êtes-vous sûr de vouloir dissocier ce fournisseur d'identités de cette organisation?",
"idpUnassociateDescription": "Tous les utilisateurs associés à ce fournisseur d'identités seront retirés de cette organisation, mais le fournisseur d'identités continuera d'exister pour d'autres organisations associées.",
"idpUnassociateConfirm": "Confirmer la dissociation du fournisseur d'identités",
"idpUnassociateWarning": "Cela ne peut pas être annulé pour cette organisation.",
"idpUnassociatedDescription": "Fournisseur d'identités dissocié de cette organisation avec succès",
"idpUnassociateMenu": "Dissocier",
"idpDeleteAllOrgsMenu": "Supprimer"
}
+99 -70
View File
@@ -1,19 +1,19 @@
{
"setupCreate": "Creare l'organizzazione, il sito e le risorse",
"headerAuthCompatibilityInfo": "Abilita questo per forzare una risposta 401 Unauthorized quando manca un token di autenticazione. Questo è richiesto per browser o librerie HTTP specifiche che non inviano credenziali senza una sfida del server.",
"headerAuthCompatibilityInfo": "Abilita questa funzionalità per forzare una risposta 401 Unauthorized quando manca un token di autenticazione. Questo è richiesto per browser o librerie HTTP specifiche che non inviano credenziali senza una sfida del server.",
"headerAuthCompatibility": "Compatibilità estesa",
"setupNewOrg": "Nuova Organizzazione",
"setupCreateOrg": "Crea Organizzazione",
"setupCreateResources": "Crea Risorse",
"setupOrgName": "Nome Dell'Organizzazione",
"setupOrgName": "Nome dell'Organizzazione",
"orgDisplayName": "Questo è il nome visualizzato dell'organizzazione.",
"orgId": "Id Organizzazione",
"setupIdentifierMessage": "Questo è l'identificatore univoco per l'organizzazione.",
"setupErrorIdentifier": "L'ID dell'organizzazione è già utilizzato. Si prega di sceglierne uno diverso.",
"componentsErrorNoMemberCreate": "Al momento non sei un membro di nessuna organizzazione. Crea un'organizzazione per iniziare.",
"componentsErrorNoMember": "Attualmente non sei membro di nessuna organizzazione.",
"welcome": "Benvenuti a Pangolin",
"welcomeTo": "Benvenuto a",
"welcome": "Benvenuto su Pangolin!",
"welcomeTo": "Benvenuto su Pangolin!",
"componentsCreateOrg": "Crea un'organizzazione",
"componentsMember": "Sei un membro di {count, plural, =0 {nessuna organizzazione} one {un'organizzazione} other {# organizzazioni}}.",
"componentsInvalidKey": "Rilevata chiave di licenza non valida o scaduta. Segui i termini di licenza per continuare a utilizzare tutte le funzionalità.",
@@ -27,7 +27,7 @@
"inviteLoginUser": "Assicurati di aver effettuato l'accesso come utente corretto.",
"inviteErrorNoUser": "Siamo spiacenti, ma sembra che l'invito che stai cercando di accedere non sia per un utente che esiste.",
"inviteCreateUser": "Si prega di creare un account prima.",
"goHome": "Vai A Home",
"goHome": "Vai alla Home",
"inviteLogInOtherUser": "Accedi come utente diverso",
"createAnAccount": "Crea un account",
"inviteNotAccepted": "Invito Non Accettato",
@@ -51,7 +51,7 @@
"edit": "Modifica",
"siteConfirmDelete": "Conferma Eliminazione Sito",
"siteDelete": "Elimina Sito",
"siteMessageRemove": "Una volta rimosso il sito non sarà più accessibile. Tutti gli obiettivi associati al sito verranno rimossi.",
"siteMessageRemove": "Una volta rimosso il sito non sarà più accessibile. Tutti gli oggetti associati al sito verranno rimossi.",
"siteQuestionRemove": "Sei sicuro di voler rimuovere il sito dall'organizzazione?",
"siteManageSites": "Gestisci Siti",
"siteDescription": "Creare e gestire siti per abilitare la connettività a reti private",
@@ -75,9 +75,9 @@
"siteLoadWGConfig": "Caricamento configurazione WireGuard...",
"siteDocker": "Espandi per i dettagli di distribuzione Docker",
"toggle": "Attiva/disattiva",
"dockerCompose": "Composizione Docker",
"dockerCompose": "Docker Compose",
"dockerRun": "Corsa Docker",
"siteLearnLocal": "I siti locali non tunnel, saperne di più",
"siteLearnLocal": "I siti locali non effettuano il tunnel, per saperne di più",
"siteConfirmCopy": "Ho copiato la configurazione",
"searchSitesProgress": "Cerca siti...",
"siteAdd": "Aggiungi Sito",
@@ -88,29 +88,29 @@
"operatingSystem": "Sistema Operativo",
"commands": "Comandi",
"recommended": "Consigliato",
"siteNewtDescription": "Per la migliore esperienza utente, utilizzare Newt. Utilizza WireGuard sotto il cofano e ti permette di indirizzare le tue risorse private tramite il loro indirizzo LAN sulla tua rete privata dall'interno della dashboard Pangolin.",
"siteNewtDescription": "Per la migliore esperienza utente utilizzare Newt, che usa WireGuard sotto il cofano e ti permette di indirizzare le tue risorse private tramite il loro indirizzo LAN sulla tua rete privata dall'interno della dashboard Pangolin.",
"siteRunsInDocker": "Esegue nel Docker",
"siteRunsInShell": "Esegue in shell su macOS, Linux e Windows",
"siteErrorDelete": "Errore nell'eliminare il sito",
"siteErrorDelete": "Errore nella eliminazione del sito",
"siteErrorUpdate": "Impossibile aggiornare il sito",
"siteErrorUpdateDescription": "Si è verificato un errore durante l'aggiornamento del sito.",
"siteUpdated": "Sito aggiornato",
"siteUpdatedDescription": "Il sito è stato aggiornato.",
"siteGeneralDescription": "Configura le impostazioni generali per questo sito",
"siteSettingDescription": "Configura le impostazioni del sito",
"siteSetting": "Impostazioni {siteName}",
"siteSetting": "Impostazioni del sito {siteName}",
"siteNewtTunnel": "Nuovo Sito (Consigliato)",
"siteNewtTunnelDescription": "Modo più semplice per creare un entrypoint in qualsiasi rete. Nessuna configurazione aggiuntiva.",
"siteWg": "WireGuard Base",
"siteWgDescription": "Usa qualsiasi client WireGuard per stabilire un tunnel. Impostazione NAT manuale richiesta.",
"siteWgDescriptionSaas": "Usa qualsiasi client WireGuard per stabilire un tunnel. Impostazione NAT manuale richiesta. FUNZIONA SOLO SU NODI AUTO-OSPITATI",
"siteWgDescription": "Usa un qualsiasi client WireGuard per stabilire un tunnel. Impostazione NAT manuale richiesta.",
"siteWgDescriptionSaas": "Usa un qualsiasi client WireGuard per stabilire un tunnel. Impostazione NAT manuale richiesta.",
"siteLocalDescription": "Solo risorse locali. Nessun tunneling.",
"siteLocalDescriptionSaas": "Solo risorse locali. Nessun tunneling. Disponibile solo su nodi remoti.",
"siteSeeAll": "Vedi Tutti I Siti",
"siteTunnelDescription": "Determinare come si desidera connettersi al sito",
"siteTunnelDescription": "Selezionare la modalità con la quale si desidera connettersi al sito",
"siteNewtCredentials": "Credenziali",
"siteNewtCredentialsDescription": "Questo è come il sito si autenticerà con il server",
"remoteNodeCredentialsDescription": "Questo è come il nodo remoto si autenticherà con il server",
"siteNewtCredentialsDescription": "Questo è come il sito si autenticherà con il server",
"remoteNodeCredentialsDescription": "Questo è il modo in cui il nodo remoto si autenticherà con il server",
"siteCredentialsSave": "Salva le credenziali",
"siteCredentialsSaveDescription": "Potrai vederlo solo una volta. Assicurati di copiarlo in un luogo sicuro.",
"siteInfo": "Informazioni Sito",
@@ -140,8 +140,8 @@
"shareCreateDescription": "Chiunque con questo link può accedere alla risorsa",
"shareTitleOptional": "Titolo (facoltativo)",
"expireIn": "Scadenza In",
"neverExpire": "Mai scadere",
"shareExpireDescription": "Il tempo di scadenza è 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.",
"neverExpire": "Nessuna scadenza",
"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.",
"shareAccessHint": "Chiunque abbia questo link può accedere alla risorsa. Condividilo con cura.",
"shareTokenUsage": "Vedi Utilizzo Token Di Accesso",
@@ -161,9 +161,9 @@
"never": "Mai",
"shareErrorSelectResource": "Seleziona una risorsa",
"proxyResourceTitle": "Gestisci Risorse Pubbliche",
"proxyResourceDescription": "Creare e gestire risorse accessibili al pubblico tramite un browser web",
"proxyResourceDescription": "Creare e gestire risorse pubbliche accessibili tramite un browser web",
"proxyResourcesBannerTitle": "Accesso Pubblico Basato sul Web",
"proxyResourcesBannerDescription": "Le risorse pubbliche sono proxy HTTPS o TCP/UDP accessibili a chiunque su Internet tramite un browser web. A differenza delle risorse private, non richiedono software lato client e possono includere politiche di accesso basate su identità e contesto.",
"proxyResourcesBannerDescription": "Le risorse pubbliche sono proxy HTTPS o TCP/UDP accessibili da chiunque tramite Internet da un browser web. A differenza delle risorse private non richiedono software lato client e possono includere politiche di accesso basate su identità e contesto.",
"clientResourceTitle": "Gestisci Risorse Private",
"clientResourceDescription": "Crea e gestisci risorse accessibili solo tramite un client connesso",
"privateResourcesBannerTitle": "Accesso Privato Zero-Trust",
@@ -174,12 +174,12 @@
"authentication": "Autenticazione",
"protected": "Protetto",
"notProtected": "Non Protetto",
"resourceMessageRemove": "Una volta rimossa, la risorsa non sarà più accessibile. Tutti gli obiettivi associati alla risorsa saranno rimossi.",
"resourceMessageRemove": "Una volta rimossa la risorsa non sarà più accessibile. Tutti gli oggetti target associati alla risorsa saranno rimossi.",
"resourceQuestionRemove": "Sei sicuro di voler rimuovere la risorsa dall'organizzazione?",
"resourceHTTP": "Risorsa HTTPS",
"resourceHTTPDescription": "Richieste proxy su HTTPS usando un nome di dominio completo.",
"resourceRaw": "Risorsa Raw TCP/UDP",
"resourceRawDescription": "Richieste proxy su TCP/UDP grezzo utilizzando un numero di porta.",
"resourceRawDescription": "Richieste proxy su TCP/UDP raw utilizzando un numero di porta.",
"resourceRawDescriptionCloud": "Richiesta proxy su TCP/UDP grezzo utilizzando un numero di porta. Richiede siti per connettersi a un nodo remoto.",
"resourceCreate": "Crea Risorsa",
"resourceCreateDescription": "Segui i passaggi seguenti per creare una nuova risorsa",
@@ -192,7 +192,7 @@
"selectCountry": "Seleziona paese",
"searchCountries": "Cerca paesi...",
"noCountryFound": "Nessun paese trovato.",
"siteSelectionDescription": "Questo sito fornirà connettività all'obiettivo.",
"siteSelectionDescription": "Questo sito fornirà connettività all'oggetto target.",
"resourceType": "Tipo Di Risorsa",
"resourceTypeDescription": "Determinare come accedere alla risorsa",
"resourceHTTPSSettings": "Impostazioni HTTPS",
@@ -206,13 +206,13 @@
"protocol": "Protocollo",
"protocolSelect": "Seleziona un protocollo",
"resourcePortNumber": "Numero Porta",
"resourcePortNumberDescription": "Il numero di porta esterna per le richieste di proxy.",
"resourcePortNumberDescription": "Il numero di porta esterna per le richieste proxy.",
"back": "Indietro",
"cancel": "Annulla",
"resourceConfig": "Snippet Di Configurazione",
"resourceConfigDescription": "Copia e incolla questi snippet di configurazione per configurare la risorsa TCP/UDP",
"resourceAddEntrypoints": "Traefik: Aggiungi Ingresso",
"resourceExposePorts": "Gerbil: espone le porte in Docker componi",
"resourceAddEntrypoints": "Traefik: Aggiungi Entrypoint",
"resourceExposePorts": "Gerbil: espone le porte in Docker Compose",
"resourceLearnRaw": "Scopri come configurare le risorse TCP/UDP",
"resourceBack": "Torna alle risorse",
"resourceGoTo": "Vai alla Risorsa",
@@ -228,7 +228,7 @@
"rules": "Regole",
"resourceSettingDescription": "Configura le impostazioni sulla risorsa",
"resourceSetting": "Impostazioni {resourceName}",
"alwaysAllow": "Autenticazione Bypass",
"alwaysAllow": "Bypass Autenticazione",
"alwaysDeny": "Blocca Accesso",
"passToAuth": "Passa all'autenticazione",
"orgSettingsDescription": "Configura le impostazioni dell'organizzazione",
@@ -237,11 +237,11 @@
"saveGeneralSettings": "Salva Impostazioni Generali",
"saveSettings": "Salva Impostazioni",
"orgDangerZone": "Zona Pericolosa",
"orgDangerZoneDescription": "Una volta che si elimina questo org, non c'è ritorno. Si prega di essere certi.",
"orgDangerZoneDescription": "Una volta che si elimina questa org non sarà possibile tornare indietro, assicurarsi quindi di essere certi della decisione.",
"orgDelete": "Elimina Organizzazione",
"orgDeleteConfirm": "Conferma Elimina Organizzazione",
"orgMessageRemove": "Questa azione è irreversibile e cancellerà tutti i dati associati.",
"orgMessageConfirm": "Per confermare, digita il nome dell'organizzazione qui sotto.",
"orgMessageConfirm": "Per confermare digita il nome dell'organizzazione qui sotto.",
"orgQuestionRemove": "Sei sicuro di voler rimuovere l'organizzazione?",
"orgUpdated": "Organizzazione aggiornata",
"orgUpdatedDescription": "L'organizzazione è stata aggiornata.",
@@ -254,10 +254,10 @@
"orgDeleted": "Organizzazione eliminata",
"orgDeletedMessage": "L'organizzazione e i suoi dati sono stati eliminati.",
"deleteAccount": "Elimina Account",
"deleteAccountDescription": "Elimina definitivamente il tuo account, tutte le organizzazioni che possiedi e tutti i dati all'interno di tali organizzazioni. Questo non può essere annullato.",
"deleteAccountDescription": "Elimina definitivamente il tuo account, tutte le organizzazioni che possiedi e tutti i dati all'interno di tali organizzazioni. Questa operazione non può essere annullata.",
"deleteAccountButton": "Elimina Account",
"deleteAccountConfirmTitle": "Elimina Account",
"deleteAccountConfirmMessage": "Questo cancellerà definitivamente il tuo account, tutte le organizzazioni che possiedi e tutti i dati all'interno di tali organizzazioni. Questo non può essere annullato.",
"deleteAccountConfirmMessage": "Questa operazione cancellerà definitivamente il tuo account, tutte le organizzazioni che possiedi e tutti i dati all'interno di tali organizzazioni. Questa operazione non può essere annullata.",
"deleteAccountConfirmString": "elimina account",
"deleteAccountSuccess": "Account Eliminato",
"deleteAccountSuccessMessage": "Il tuo account è stato eliminato.",
@@ -272,7 +272,7 @@
"accessUserCreate": "Crea Utente",
"accessUserRemove": "Rimuovi Utente",
"username": "Nome utente",
"identityProvider": "Provider Di Identità",
"identityProvider": "Provider Identità",
"role": "Ruolo",
"nameRequired": "Il nome è obbligatorio",
"accessRolesManage": "Gestisci Ruoli",
@@ -328,8 +328,8 @@
"apiKeysDelete": "Elimina Chiave API",
"apiKeysManage": "Gestisci Chiavi API",
"apiKeysDescription": "Le chiavi API sono utilizzate per autenticarsi con l'API di integrazione",
"provisioningKeysTitle": "Chiave Di Provvedimento",
"provisioningKeysManage": "Gestisci Chiavi Di Provvedimento",
"provisioningKeysTitle": "Chiave di provisioning",
"provisioningKeysManage": "Gestisci Chiavi di provisioning",
"provisioningKeysDescription": "Le chiavi di provisioning vengono utilizzate per autenticare il provisioning automatico del sito per la tua organizzazione.",
"provisioningManage": "Accantonamento",
"provisioningDescription": "Gestire le chiavi di provisioning e rivedere i siti in attesa di approvazione.",
@@ -337,25 +337,25 @@
"siteApproveSuccess": "Sito approvato con successo",
"siteApproveError": "Errore nell'approvazione del sito",
"provisioningKeys": "Chiavi Di Provvedimento",
"searchProvisioningKeys": "Cerca i tasti di provisioning ...",
"provisioningKeysAdd": "Genera Chiave Di Provvedimento",
"provisioningKeysErrorDelete": "Errore nell'eliminare la chiave di provisioning",
"provisioningKeysErrorDeleteMessage": "Errore nell'eliminare la chiave di provisioning",
"searchProvisioningKeys": "Cerca le chiavi di provisioning...",
"provisioningKeysAdd": "Genera Chiave di provisioning",
"provisioningKeysErrorDelete": "Errore nell'eliminazione della chiave di provisioning",
"provisioningKeysErrorDeleteMessage": "Errore nell'eliminazione della chiave di provisioning",
"provisioningKeysQuestionRemove": "Sei sicuro di voler rimuovere questa chiave di provisioning dall'organizzazione?",
"provisioningKeysMessageRemove": "Una volta rimossa, la chiave non può più essere utilizzata per il provisioning.",
"provisioningKeysDeleteConfirm": "Conferma Elimina Chiave Provvisoria",
"provisioningKeysDeleteConfirm": "Conferma Eliminazione della chiave di provisioning",
"provisioningKeysDelete": "Elimina chiave di provisioning",
"provisioningKeysCreate": "Genera Chiave Di Provvedimento",
"provisioningKeysCreate": "Genera Chiave di provisioning",
"provisioningKeysCreateDescription": "Genera una nuova chiave di provisioning per l'organizzazione",
"provisioningKeysSeeAll": "Vedi tutte le chiavi di provisioning",
"provisioningKeysSave": "Salva la chiave di provisioning",
"provisioningKeysSaveDescription": "Sarai in grado di vedere solo una volta. Copiarlo in un posto sicuro.",
"provisioningKeysErrorCreate": "Errore nella creazione della chiave di provisioning",
"provisioningKeysList": "Nuova chiave di provisioning",
"provisioningKeysMaxBatchSize": "Dimensione massima lotto",
"provisioningKeysUnlimitedBatchSize": "Dimensione illimitata del lotto (nessun limite)",
"provisioningKeysMaxBatchSize": "Dimensione massima batch",
"provisioningKeysUnlimitedBatchSize": "Dimensione illimitata del batch (nessun limite)",
"provisioningKeysMaxBatchUnlimited": "Illimitato",
"provisioningKeysMaxBatchSizeInvalid": "Inserisci un lotto massimo valido (11.000.000).",
"provisioningKeysMaxBatchSizeInvalid": "Inserisci una dimensione massima valida del batch (11.000.000).",
"provisioningKeysValidUntil": "Valido fino al",
"provisioningKeysValidUntilHint": "Lasciare vuoto per nessuna scadenza.",
"provisioningKeysValidUntilInvalid": "Inserisci una data e ora valide.",
@@ -363,18 +363,18 @@
"provisioningKeysLastUsed": "Ultimo utilizzo",
"provisioningKeysNoExpiry": "Nessuna scadenza",
"provisioningKeysNeverUsed": "Mai",
"provisioningKeysEdit": "Modifica Chiave Di Provvedimento",
"provisioningKeysEditDescription": "Aggiorna la dimensione massima del lotto e il tempo di scadenza per questa chiave.",
"provisioningKeysEdit": "Modifica Chiave di provisioning",
"provisioningKeysEditDescription": "Aggiorna la dimensione massima del batch e il tempo di scadenza per questa chiave.",
"provisioningKeysApproveNewSites": "Approva nuovi siti",
"provisioningKeysApproveNewSitesDescription": "Approvare automaticamente i siti che si registrano con questa chiave.",
"provisioningKeysUpdateError": "Errore nell'aggiornamento della chiave di provisioning",
"provisioningKeysUpdated": "Chiave di accantonamento aggiornata",
"provisioningKeysUpdated": "Chiave di provisioning aggiornata",
"provisioningKeysUpdatedDescription": "Le tue modifiche sono state salvate.",
"provisioningKeysBannerTitle": "Chiavi Di Provvedimento Sito",
"provisioningKeysBannerDescription": "Generare una chiave di provisioning e usarla con il connettore Newt per creare automaticamente siti al primo avvio non è necessario impostare credenziali separate per ogni sito.",
"provisioningKeysBannerTitle": "Chiavi di provisioning del Sito",
"provisioningKeysBannerDescription": "Genera una chiave di provisioning e usala con il connettore Newt per creare automaticamente i siti al primo avvio - non è necessario configurare credenziali separate per ogni sito.",
"provisioningKeysBannerButtonText": "Scopri di più",
"pendingSitesBannerTitle": "Siti In Attesa",
"pendingSitesBannerDescription": "I siti che si connettono utilizzando una chiave di provisioning appaiono qui per la revisione. Approva ogni sito prima che diventi attivo e ottenga l'accesso alle tue risorse.",
"pendingSitesBannerDescription": "I siti che si connettono utilizzando una chiave di provisioning vengono visualizzati qui per la revisione.",
"pendingSitesBannerButtonText": "Scopri di più",
"apiKeysSettings": "Impostazioni {apiKeyName}",
"userTitle": "Gestisci Tutti Gli Utenti",
@@ -386,7 +386,7 @@
"userErrorDelete": "Errore nell'eliminare l'utente",
"userDeleteConfirm": "Conferma Eliminazione Utente",
"userDeleteServer": "Elimina utente dal server",
"userMessageRemove": "L'utente verrà rimosso da tutte le organizzazioni ed essere completamente rimosso dal server.",
"userMessageRemove": "L'utente verrà rimosso da tutte le organizzazioni e verrà completamente rimosso dal server.",
"userQuestionRemove": "Sei sicuro di voler eliminare definitivamente l'utente dal server?",
"licenseKey": "Chiave Di Licenza",
"valid": "Valido",
@@ -404,9 +404,13 @@
"licenseKeyDeletedDescription": "La chiave di licenza è stata eliminata.",
"licenseErrorKeyActivate": "Attivazione della chiave di licenza non riuscita",
"licenseErrorKeyActivateDescription": "Si è verificato un errore nell'attivazione della chiave di licenza.",
"licenseAbout": "Informazioni Su Licenze",
"licenseAbout": "Informazioni sul Licensing",
"licenseBannerTitle": "Attiva la tua Licenza Enterprise",
"licenseBannerDescription": "Sblocca le funzionalità enterprise per la tua istanza Pangolin auto-ospitata. Acquista una chiave di licenza per attivare le capacità premium e poi aggiungila qui sotto.",
"licenseBannerGetLicense": "Ottieni una Licenza",
"licenseBannerViewDocs": "Visualizza Documentazione",
"communityEdition": "Edizione Community",
"licenseAboutDescription": "Questo è per gli utenti aziendali e aziendali che utilizzano Pangolin in un ambiente commerciale. Se stai usando Pangolin per uso personale, puoi ignorare questa sezione.",
"licenseAboutDescription": "Questa sezione è per gli utenti aziendali e aziendali che utilizzano Pangolin in un ambiente commerciale. Se stai usando Pangolin per uso personale, puoi ignorare questa sezione.",
"licenseKeyActivated": "Chiave di licenza attivata",
"licenseKeyActivatedDescription": "La chiave di licenza è stata attivata correttamente.",
"licenseErrorKeyRecheck": "Impossibile ricontrollare le chiavi di licenza",
@@ -429,7 +433,7 @@
"licenseHostDescription": "Gestisci la chiave di licenza principale per l'host.",
"licensedNot": "Non Licenziato",
"hostId": "ID Host",
"licenseReckeckAll": "Ricontrolla Tutte Le Tasti",
"licenseReckeckAll": "Ricontrolla Tutte le chiavi",
"licenseSiteUsage": "Utilizzo Siti",
"licenseSiteUsageDecsription": "Visualizza il numero di siti che utilizzano questa licenza.",
"licenseNoSiteLimit": "Non c'è alcun limite al numero di siti che utilizzano un host senza licenza.",
@@ -480,7 +484,7 @@
"userOrgRemoved": "Utente rimosso",
"userOrgRemovedDescription": "L'utente {email} è stato rimosso dall'organizzazione.",
"userQuestionOrgRemove": "Sei sicuro di voler rimuovere questo utente dall'organizzazione?",
"userMessageOrgRemove": "Una volta rimosso, questo utente non avrà più accesso all'organizzazione. Puoi sempre reinvitarlo in seguito, ma dovrà accettare nuovamente l'invito.",
"userMessageOrgRemove": "Una volta rimosso questo utente non avrà più accesso all'organizzazione. Puoi sempre reinvitarlo in seguito, ma dovrà accettare nuovamente l'invito.",
"userRemoveOrgConfirm": "Conferma Rimozione Utente",
"userRemoveOrg": "Rimuovi Utente dall'Organizzazione",
"users": "Utenti",
@@ -532,13 +536,13 @@
"approve": "Approva",
"approved": "Approvato",
"denied": "Negato",
"deniedApproval": "Omologazione Negata",
"deniedApproval": "Approvazione Negata",
"all": "Tutti",
"deny": "Nega",
"viewDetails": "Visualizza Dettagli",
"requestingNewDeviceApproval": "ha richiesto un nuovo dispositivo",
"resetFilters": "Ripristina Filtri",
"totalBlocked": "Richieste Bloccate Da Pangolino",
"totalBlocked": "Richieste Bloccate Da Pangolin",
"totalRequests": "Totale Richieste",
"requestsByCountry": "Richieste Per Paese",
"requestsByDay": "Richieste Per Giorno",
@@ -546,7 +550,7 @@
"allowed": "Consentito",
"topCountries": "Paesi Principali",
"accessRoleSelect": "Seleziona ruolo",
"inviteEmailSentDescription": "È stata inviata un'email all'utente con il link di accesso qui sotto. Devono accedere al link per accettare l'invito.",
"inviteEmailSentDescription": "È stata inviata un'email all'utente con il link di accesso qui sotto. L'utente deve accedere al link per accettare l'invito.",
"inviteSentDescription": "L'utente è stato invitato. Deve accedere al link qui sotto per accettare l'invito.",
"inviteExpiresIn": "L'invito scadrà tra {days, plural, one {# giorno} other {# giorni}}.",
"idpTitle": "Informazioni Generali",
@@ -562,7 +566,7 @@
"userSaved": "Utente salvato",
"userSavedDescription": "L'utente è stato aggiornato.",
"autoProvisioned": "Auto Provisioned",
"autoProvisionSettings": "Impostazioni Automatiche Di Fornitura",
"autoProvisionSettings": "Impostazioni Automatiche di provisioning",
"autoProvisionedDescription": "Permetti a questo utente di essere gestito automaticamente dal provider di identità",
"accessControlsDescription": "Gestisci cosa questo utente può accedere e fare nell'organizzazione",
"accessControlsSubmit": "Salva Controlli di Accesso",
@@ -576,9 +580,9 @@
"proxyErrorInvalidHeader": "Valore dell'intestazione Host personalizzata non valido. Usa il formato nome dominio o salva vuoto per rimuovere l'intestazione Host personalizzata.",
"proxyErrorTls": "Nome Server TLS non valido. Usa il formato nome dominio o salva vuoto per rimuovere il Nome Server TLS.",
"proxyEnableSSL": "Abilita SSL",
"proxyEnableSSLDescription": "Abilita la crittografia SSL/TLS per connessioni HTTPS sicure agli obiettivi.",
"proxyEnableSSLDescription": "Abilita la crittografia SSL/TLS per connessioni HTTPS sicure alle risorse interne target.",
"target": "Target",
"configureTarget": "Configura Obiettivi",
"configureTarget": "Configura Risorse Interne",
"targetErrorFetch": "Impossibile recuperare i target",
"targetErrorFetchDescription": "Si è verificato un errore durante il recupero dei target",
"siteErrorFetch": "Impossibile recuperare la risorsa",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Inserisci un numero di porta valido",
"targetErrorNoSite": "Nessun sito selezionato",
"targetErrorNoSiteDescription": "Si prega di selezionare un sito per l'obiettivo",
"targetTargetsCleared": "Obiettivi cancellati",
"targetTargetsClearedDescription": "Tutti gli obiettivi sono stati rimossi da questa risorsa",
"targetCreated": "Destinazione creata",
"targetCreatedDescription": "L'obiettivo è stato creato con successo",
"targetErrorCreate": "Impossibile creare l'obiettivo",
@@ -892,6 +898,7 @@
"idpDisplayName": "Un nome visualizzato per questo provider di identità",
"idpAutoProvisionUsers": "Provisioning Automatico Utenti",
"idpAutoProvisionUsersDescription": "Quando abilitato, gli utenti verranno creati automaticamente nel sistema al primo accesso con la possibilità di mappare gli utenti a ruoli e organizzazioni.",
"idpAutoProvisionConfigureAfterCreate": "Puoi configurare le impostazioni di auto fornitura una volta creato il provider di identità.",
"licenseBadge": "EE",
"idpType": "Tipo di Provider",
"idpTypeDescription": "Seleziona il tipo di provider di identità che desideri configurare",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Mappatura Ruolo Predefinito",
"defaultMappingsRoleDescription": "JMESPath per estrarre informazioni sul ruolo dal token ID. Il risultato di questa espressione deve restituire il nome del ruolo come definito nell'organizzazione come stringa.",
"defaultMappingsOrg": "Mappatura Organizzazione Predefinita",
"defaultMappingsOrgDescription": "JMESPath per estrarre informazioni sull'organizzazione dal token ID. Questa espressione deve restituire l'ID dell'organizzazione o true affinché l'utente possa accedere all'organizzazione.",
"defaultMappingsOrgDescription": "Quando impostata, questa espressione deve restituire l'ID dell'organizzazione o true affinché l'utente possa accedere a quell'organizzazione. Quando non impostata, è sufficiente definire una mappatura di ruoli: l'utente è autorizzato se esiste una mappatura di ruolo valida per loro all'interno dell'organizzazione.",
"defaultMappingsSubmit": "Salva Mappature Predefinite",
"orgPoliciesEdit": "Modifica Politica Organizzazione",
"org": "Organizzazione",
@@ -1987,7 +1994,7 @@
"description": "Server Pangolin self-hosted più affidabile e a bassa manutenzione con campanelli e fischietti extra",
"introTitle": "Managed Self-Hosted Pangolin",
"introDescription": "è un'opzione di distribuzione progettata per le persone che vogliono la semplicità e l'affidabilità extra mantenendo i loro dati privati e self-hosted.",
"introDetail": "Con questa opzione, esegui ancora il tuo nodo Pangolin i tunnel, la terminazione SSL e il traffico rimangono tutti sul tuo server. La differenza è che la gestione e il monitoraggio sono gestiti attraverso il nostro cruscotto cloud, che sblocca una serie di vantaggi:",
"introDetail": "Con questa opzione, esegui ancora il tuo nodo Pangolin - i tunnel, la terminazione SSL e il traffico rimangono tutti sul tuo server. La differenza è che la gestione e il monitoraggio sono gestiti attraverso il nostro cruscotto cloud, che sblocca una serie di vantaggi:",
"benefitSimplerOperations": {
"title": "Operazioni più semplici",
"description": "Non è necessario eseguire il proprio server di posta o impostare un avviso complesso. Otterrai controlli di salute e avvisi di inattività fuori dalla casella."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Dominio Internazionale Rilevato",
"willbestoredas": "Verrà conservato come:",
"roleMappingDescription": "Determinare come i ruoli sono assegnati agli utenti quando accedono quando è abilitata la fornitura automatica.",
"roleMappingDescription": "Determina come i ruoli vengono assegnati agli utenti quando si accede con questo provider di identità.",
"selectRole": "Seleziona un ruolo",
"roleMappingExpression": "Espressione",
"selectRolePlaceholder": "Scegli un ruolo",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Seleziona un dominio per la pagina di autenticazione dell'organizzazione",
"domainPickerProvidedDomain": "Dominio Fornito",
"domainPickerFreeProvidedDomain": "Dominio Fornito Gratuito",
"domainPickerFreeDomainsPaidFeature": "I domini forniti sono una funzionalità a pagamento. Abbonati per ricevere un dominio incluso con il tuo piano - non è necessario portare il proprio.",
"domainPickerVerified": "Verificato",
"domainPickerUnverified": "Non Verificato",
"domainPickerManual": "Manuale",
"domainPickerInvalidSubdomainStructure": "Questo sottodominio contiene caratteri o struttura non validi. Sarà sanificato automaticamente quando si salva.",
"domainPickerError": "Errore",
"domainPickerErrorLoadDomains": "Impossibile caricare i domini dell'organizzazione",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Trasparenza Di Utilizzo",
"description": "Seleziona il livello di licenza che rispecchia accuratamente il tuo utilizzo previsto. La Licenza Personale consente l'uso gratuito del Software per le attività commerciali individuali, non commerciali o su piccola scala con entrate lorde annue inferiori a $100.000 USD. Qualsiasi uso oltre questi limiti compreso l'uso all'interno di un'azienda, organizzazione, o altro ambiente generatore di entrate richiede una licenza Enterprise valida e il pagamento della tassa di licenza applicabile. Tutti gli utenti, siano essi personali o aziendali, devono rispettare i termini di licenza commerciale Fossorial."
"description": "Seleziona il livello di licenza che rispecchia accuratamente il tuo utilizzo previsto. La Licenza Personale consente l'uso gratuito del Software per le attività commerciali individuali, non commerciali o su piccola scala con entrate lorde annue inferiori a $100.000 USD. Qualsiasi uso oltre questi limiti - compreso l'uso all'interno di un'azienda, organizzazione, o altro ambiente generatore di entrate - richiede una licenza Enterprise valida e il pagamento della tassa di licenza applicabile. Tutti gli utenti, siano essi personali o aziendali, devono rispettare i termini di licenza commerciale Fossorial."
},
"trialPeriodInformation": {
"title": "Informazioni Periodo Di Prova",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Scala",
"description": "Funzionalità aziendali, 50 utenti, 50 siti e supporto prioritario."
"description": "Funzionalità aziendali, 50 utenti, 100 siti e supporto prioritario."
}
},
"personalUseOnly": "Solo uso personale (licenza gratuita nessun checkout)",
"personalUseOnly": "Uso personale esclusivo (licenza gratuita - nessun pagamento)",
"buttons": {
"continueToCheckout": "Continua al Checkout"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Machine Clients",
"install": "Installa",
"run": "Esegui",
"envFile": "File di ambiente",
"serviceFile": "File di servizio",
"enableAndStart": "Abilita e avvia",
"clientNameDescription": "Il nome visualizzato del client che può essere modificato in seguito.",
"clientAddress": "Indirizzo Client (Avanzato)",
"setupFailedToFetchSubnet": "Recupero della sottorete predefinita non riuscito",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Nessuna Autenticazione",
"httpDestAuthNoneDescription": "Invia richieste senza intestazione autorizzazione.",
"httpDestAuthBearerTitle": "Token Del Portatore",
"httpDestAuthBearerDescription": "Aggiunge un'intestazione Autorizzazione: Bearer <token> ad ogni richiesta.",
"httpDestAuthBearerDescription": "Aggiunge un'intestazione Authorization: Bearer '<token>' a ogni richiesta.",
"httpDestAuthBearerPlaceholder": "La tua chiave API o token",
"httpDestAuthBasicTitle": "Autenticazione Base",
"httpDestAuthBasicDescription": "Aggiunge un'autorizzazione: intestazione di base <credentials> . Fornisce le credenziali come username:password.",
"httpDestAuthBasicDescription": "Aggiunge un'intestazione Authorization: Basic '<credentials>'. Fornire le credenziali come username:password.",
"httpDestAuthBasicPlaceholder": "username:password",
"httpDestAuthCustomTitle": "Intestazione Personalizzata",
"httpDestAuthCustomDescription": "Specifica un nome e un valore di intestazione HTTP personalizzati per l'autenticazione (ad esempio X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "JSON Array",
"httpDestFormatJsonArrayDescription": "Una richiesta per lotto, corpo è un array JSON. Compatibile con la maggior parte dei webhooks generici e Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Una richiesta per lotto, corpo è newline-delimited JSON un oggetto per linea, nessun array esterno. Richiesto da Splunk HEC, Elastic / OpenSearch, e Grafana Loki.",
"httpDestFormatNdjsonDescription": "Una richiesta per lotto, corpo è newline-delimited JSON - un oggetto per linea, nessun array esterno. Richiesto da Splunk HEC, Elastic / OpenSearch, e Grafana Loki.",
"httpDestFormatSingleTitle": "Un Evento Per Richiesta",
"httpDestFormatSingleDescription": "Invia un HTTP POST separato per ogni singolo evento. Usa solo per gli endpoint che non possono gestire i batch.",
"httpDestLogTypesTitle": "Tipi Di Log",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Destinazione aggiornata con successo",
"httpDestCreatedSuccess": "Destinazione creata con successo",
"httpDestUpdateFailed": "Impossibile aggiornare la destinazione",
"httpDestCreateFailed": "Impossibile creare la destinazione"
"httpDestCreateFailed": "Impossibile creare la destinazione",
"idpAddActionCreateNew": "Crea nuovo provider di identità",
"idpAddActionImportFromOrg": "Importa da un'altra organizzazione",
"idpImportDialogTitle": "Importa Provider di Identità",
"idpImportDialogDescription": "Scegli un provider di identità da un'organizzazione di cui sei amministratore. Verrà collegato a questa organizzazione.",
"idpImportSearchPlaceholder": "Cerca per nome organizzazione o provider...",
"idpImportEmpty": "Nessun provider di identità trovato.",
"idpImportedDescription": "Provider di identità importato con successo.",
"idpDeleteGlobalQuestion": "Sei sicuro di voler eliminare definitivamente questo provider di identità?",
"idpDeleteGlobalDescription": "Questo eliminerà definitivamente il provider di identità da tutte le organizzazioni con cui è associato.",
"idpUnassociateTitle": "Disassociare Provider di Identità",
"idpUnassociateQuestion": "Sei sicuro di voler disassociare questo provider di identità da questa organizzazione?",
"idpUnassociateDescription": "Tutti gli utenti associati a questo provider di identità verranno rimossi da questa organizzazione, ma il provider di identità continuerà ad esistere per altre organizzazioni associate.",
"idpUnassociateConfirm": "Conferma Disassociazione Provider di Identità",
"idpUnassociateWarning": "Questo non può essere annullato per questa organizzazione.",
"idpUnassociatedDescription": "Provider di identità disassociato con successo da questa organizzazione",
"idpUnassociateMenu": "Disassocia",
"idpDeleteAllOrgsMenu": "Elimina"
}
+40 -11
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "프로비저닝 키가 업데이트되었습니다",
"provisioningKeysUpdatedDescription": "변경 사항이 저장되었습니다.",
"provisioningKeysBannerTitle": "사이트 프로비저닝 키",
"provisioningKeysBannerDescription": "프로비저닝 키를 생성하 Newt 커넥터와 함께 사용실행자동으로 사이트를 생성하세요 — 각 사이트마다 별도의 인증을 설정할 필요 없습니다.",
"provisioningKeysBannerDescription": "프로비저닝 키를 생성하 Newt 커넥터와 함께 사용하여시작사이트를 자동 생성 - 각 사이트에 대한 별도 자격 증명이 필요 없습니다.",
"provisioningKeysBannerButtonText": "자세히 알아보기",
"pendingSitesBannerTitle": "대기중인 사이트",
"pendingSitesBannerDescription": "프로비저닝 키를 사용하여 연결하는 사이트 검토 대기 중입니다. 사이트가 활성화되어 리소스에 액세스하기 전에 각 사이트를 승인하세요.",
"pendingSitesBannerDescription": "프로비저닝 키를 사용하여 연결 사이트 검토를 위해 여기에 표시됩니다.",
"pendingSitesBannerButtonText": "자세히 알아보기",
"apiKeysSettings": "{apiKeyName} 설정",
"userTitle": "모든 사용자 관리",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "라이센스 키 활성화에 실패했습니다.",
"licenseErrorKeyActivateDescription": "라이센스 키를 활성화하는 동안 오류가 발생했습니다",
"licenseAbout": "라이센스에 대한 정보",
"licenseBannerTitle": "기업 라이선스 활성화",
"licenseBannerDescription": "자체 호스팅된 Pangolin 인스턴스에서 기업 기능을 잠금 해제하십시오. 라이선스 키를 구입하여 프리미엄 기능을 활성화하고 아래에 추가하십시오.",
"licenseBannerGetLicense": "라이선스 획득",
"licenseBannerViewDocs": "문서 보기",
"communityEdition": "커뮤니티 에디션",
"licenseAboutDescription": "이것은 상업적 환경에서 Pangolin을 사용하는 비즈니스 및 기업 사용자용입니다. 개인 용도로 Pangolin을 사용하는 경우 이 섹션을 무시할 수 있습니다.",
"licenseKeyActivated": "라이센스 키가 활성화되었습니다",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "유효한 포트 번호를 입력하세요.",
"targetErrorNoSite": "선택된 사이트 없음",
"targetErrorNoSiteDescription": "대상을 위해 사이트를 선택하세요.",
"targetTargetsCleared": "대상이 제거됨",
"targetTargetsClearedDescription": "이 리소스에서 모든 대상이 제거되었습니다",
"targetCreated": "대상 생성",
"targetCreatedDescription": "대상이 성공적으로 생성되었습니다.",
"targetErrorCreate": "대상 생성 실패",
@@ -892,6 +898,7 @@
"idpDisplayName": "이 신원 공급자를 위한 표시 이름",
"idpAutoProvisionUsers": "사용자 자동 프로비저닝",
"idpAutoProvisionUsersDescription": "활성화되면 사용자가 첫 로그인 시 시스템에 자동으로 생성되며, 사용자와 역할 및 조직을 매핑할 수 있습니다.",
"idpAutoProvisionConfigureAfterCreate": "아이덴티티 공급자가 생성되면 자동 프로비저닝 설정을 구성할 수 있습니다.",
"licenseBadge": "EE",
"idpType": "제공자 유형",
"idpTypeDescription": "구성할 ID 공급자의 유형을 선택하십시오.",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "기본 역할 매핑",
"defaultMappingsRoleDescription": "이 표현식의 결과는 조직에서 정의된 역할 이름을 문자열로 반환해야 합니다.",
"defaultMappingsOrg": "기본 조직 매핑",
"defaultMappingsOrgDescription": "이 표현식은 사용자가 조직에 접근할 수 있도록 조직 ID 또는 true를 반환해야 합니다.",
"defaultMappingsOrgDescription": "이 표현식은 사용자가 조직에 접근할 수 있도록 조직 ID 또는 true를 반환해야 합니다. 설정되지 않으면, 역할 매핑 정의가 충분합니다: 사용자는 유효한 역할 매핑이 해석되는 한 조직에 허용됩니다.",
"defaultMappingsSubmit": "기본 매핑 저장",
"orgPoliciesEdit": "조직 정책 편집",
"org": "조직",
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "국제 도메인 감지됨",
"willbestoredas": "다음으로 저장됩니다:",
"roleMappingDescription": "자동 프로비저닝이 활성화되면 사용자가 로그인할 때 역할이 할당되는 방법을 결정합니다.",
"roleMappingDescription": "사용자가 이 아이덴티티 공급자로 로그인할 때 역할이 할당되는 방법을 결정합니다.",
"selectRole": "역할 선택",
"roleMappingExpression": "표현식",
"selectRolePlaceholder": "역할 선택",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "조직 인증 페이지에 대한 도메인을 선택하세요.",
"domainPickerProvidedDomain": "제공된 도메인",
"domainPickerFreeProvidedDomain": "무료 제공된 도메인",
"domainPickerFreeDomainsPaidFeature": "제공된 도메인은 유료 기능입니다. 요금제에 도메인이 포함되도록 구독하세요. - 별도로 도메인을 준비할 필요 없습니다.",
"domainPickerVerified": "검증됨",
"domainPickerUnverified": "검증되지 않음",
"domainPickerManual": "수동",
"domainPickerInvalidSubdomainStructure": "이 하위 도메인은 잘못된 문자 또는 구조를 포함하고 있습니다. 저장 시 자동으로 정리됩니다.",
"domainPickerError": "오류",
"domainPickerErrorLoadDomains": "조직 도메인 로드 실패",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "사용 공개",
"description": "당신의 의도된 사용에 정확히 맞는 라이선스 등급을 선택하세요. 개인 라이선스는 연간 총 수익 100,000 USD 이하의 개인, 비상업적 또는 소규모 상업 활동을 위한 소프트웨어의 무료 사용을 허용합니다. 이러한 제한을 넘는 모든 사용 비즈니스, 조직 또는 기타 수익 창출 환경 내에서의 사용 은 유효한 엔터프라이즈 라이선스 및 해당 라이선스 수수료의 지불이 필요합니다. 개인 또는 기업 사용자는 모두 Fossorial 상용 라이선스 조건을 준수해야 합니다."
"description": "당신의 의도된 사용에 정확히 맞는 라이선스 등급을 선택하세요. 개인 라이선스는 연간 총 수익 100,000 USD 이하의 개인, 비상업적 또는 소규모 상업 활동을 위한 소프트웨어의 무료 사용을 허용합니다. 이러한 제한을 넘는 모든 사용 - 비즈니스, 조직 또는 기타 수익 창출 환경 내에서의 사용 - 은 유효한 엔터프라이즈 라이선스 및 해당 라이선스 수수료의 지불이 필요합니다. 개인 또는 기업 사용자는 모두 Fossorial 상용 라이선스 조건을 준수해야 합니다."
},
"trialPeriodInformation": {
"title": "시험 기간 정보",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "스케일",
"description": "기업 기능, 50명의 사용자, 50개의 사이트, 우선 지원."
"description": "기업 기능, 50명의 사용자, 100개의 사이트, 그리고 우선 지원."
}
},
"personalUseOnly": "개인 사용 전용 (무료 라이— 체크아웃 없음)",
"personalUseOnly": "개인용으로만 사용 (무료 라이- 결제 없음)",
"buttons": {
"continueToCheckout": "결제로 진행"
},
@@ -2607,6 +2616,9 @@
"machineClients": "기계 클라이언트",
"install": "설치",
"run": "실행",
"envFile": "환경 파일",
"serviceFile": "서비스 파일",
"enableAndStart": "활성화 및 시작",
"clientNameDescription": "나중에 변경할 수 있는 클라이언트의 표시 이름입니다.",
"clientAddress": "클라이언트 주소(고급)",
"setupFailedToFetchSubnet": "기본값 로드 실패",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "인증 없음",
"httpDestAuthNoneDescription": "Authorization 헤더 없이 요청을 보냅니다.",
"httpDestAuthBearerTitle": "Bearer 토큰",
"httpDestAuthBearerDescription": "모든 요청에 Authorization: Bearer <token> 헤더를 추가합니다.",
"httpDestAuthBearerDescription": " 요청에 Authorization: Bearer '<token>' 헤더를 추가합니다.",
"httpDestAuthBearerPlaceholder": "API 키 또는 토큰",
"httpDestAuthBasicTitle": "기본 인증",
"httpDestAuthBasicDescription": "Authorization: Basic <credentials> 헤더를 추가합니다. 자격 증명은 username:password 형식으로 제공하세요.",
"httpDestAuthBasicDescription": "Authorization: Basic '<credentials>' 헤더를 추가합니다. 자격 증명은 사용자 이름:비밀번호로 제공합니다.",
"httpDestAuthBasicPlaceholder": "사용자 이름:비밀번호",
"httpDestAuthCustomTitle": "사용자 정의 헤더",
"httpDestAuthCustomDescription": "인증을 위한 사용자 정의 HTTP 헤더 이름 및 값을 지정하세요 (예: X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "JSON 배열",
"httpDestFormatJsonArrayDescription": "각 배치마다 요청 하나씩, 본문은 JSON 배열입니다. 대부분의 일반 웹훅 및 Datadog과 호환됩니다.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "각 배치마다 요청 하나씩, 본문은 줄 구분 JSON 한 라인에 하나의 객체가 있으며 외부 배열이 없습니다. Splunk HEC, Elastic / OpenSearch, Grafana Loki에 필요합니다.",
"httpDestFormatNdjsonDescription": "각 배치마다 요청 하나씩, 본문은 줄 구분 JSON - 한 라인에 하나의 객체가 있으며 외부 배열이 없습니다. Splunk HEC, Elastic / OpenSearch, Grafana Loki에 필요합니다.",
"httpDestFormatSingleTitle": "각 요청 당 하나의 이벤트",
"httpDestFormatSingleDescription": "각 개별 이벤트에 대해 별도의 HTTP POST를 전송합니다. 배치를 처리할 수 없는 엔드포인트에만 사용하세요.",
"httpDestLogTypesTitle": "로그 유형",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "대상지가 성공적으로 업데이트되었습니다",
"httpDestCreatedSuccess": "대상지가 성공적으로 생성되었습니다",
"httpDestUpdateFailed": "대상지를 업데이트하는 데 실패했습니다",
"httpDestCreateFailed": "대상지를 생성하는 데 실패했습니다"
"httpDestCreateFailed": "대상지를 생성하는 데 실패했습니다",
"idpAddActionCreateNew": "새로운 아이덴티티 공급자 생성",
"idpAddActionImportFromOrg": "다른 조직에서 가져오기",
"idpImportDialogTitle": "아이덴티티 공급자 가져오기",
"idpImportDialogDescription": "관리자인 조직에서 아이덴티티 공급자를 선택하십시오. 이는 이 조직에 연결됩니다.",
"idpImportSearchPlaceholder": "조직 또는 공급자 이름으로 검색...",
"idpImportEmpty": "아이덴티티 공급자를 찾을 수 없습니다.",
"idpImportedDescription": "아이덴티티 공급자가 성공적으로 가져왔습니다.",
"idpDeleteGlobalQuestion": "정말로 이 아이덴티티 공급자를 영구적으로 삭제하시겠습니까?",
"idpDeleteGlobalDescription": "이것은 연관된 모든 조직에서 아이덴티티 공급자를 영구적으로 삭제합니다.",
"idpUnassociateTitle": "아이덴티티 공급자의 연관 해제",
"idpUnassociateQuestion": "정말로 이 조직에서 이 아이덴티티 공급자의 연관을 해제하시겠습니까?",
"idpUnassociateDescription": "이 아이덴티티 공급자와 연관된 모든 사용자는 이 조직에서 제거될 것이지만, 아이덴티티 공급자는 다른 연관된 조직에 계속해서 존재할 것입니다.",
"idpUnassociateConfirm": "아이덴티티 공급자 연관 해제 확인",
"idpUnassociateWarning": "이 조직에서 이것은 되돌릴 수 없습니다.",
"idpUnassociatedDescription": "아이덴티티 공급자가 이 조직에서 성공적으로 연관 해제되었습니다",
"idpUnassociateMenu": "연관 해제",
"idpDeleteAllOrgsMenu": "삭제"
}
+39 -10
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Foreslå nøkkel oppdatert",
"provisioningKeysUpdatedDescription": "Dine endringer er lagret.",
"provisioningKeysBannerTitle": "Sidens bestemmende nøkler",
"provisioningKeysBannerDescription": "Generer en foreløpig nøkkel og bruk den med Nyhetskontakten for å automatisk opprette sider ved første oppstart — trenger ikke å sette opp separat innloggingsinformasjon for hver side.",
"provisioningKeysBannerDescription": "Generer en provisjonsnøkkel og bruk den med Newt-kontakten for automatisk opprettelse av nettsteder ved første oppstart - ingen behov for å sette opp separate legitimasjoner for hvert nettsted.",
"provisioningKeysBannerButtonText": "Lær mer",
"pendingSitesBannerTitle": "Ventende nettsteder",
"pendingSitesBannerDescription": "Nettsteder som kobler deg til ved hjelp av en bestemmelsestekst, vises her for gjennomgang. Godkjenn hvert nettsted før det blir aktivt og får tilgang til ressursene dine.",
"pendingSitesBannerDescription": "Nettsteder som kobler seg til ved bruk av en provisjonsnøkkel vises her for vurdering.",
"pendingSitesBannerButtonText": "Lær mer",
"apiKeysSettings": "{apiKeyName} Innstillinger",
"userTitle": "Administrer alle brukere",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Aktivering av lisensnøkkel feilet",
"licenseErrorKeyActivateDescription": "Det oppstod en feil under aktivering av lisensnøkkelen.",
"licenseAbout": "Om Lisensiering",
"licenseBannerTitle": "Aktiver din bedriftslisens",
"licenseBannerDescription": "Lås opp bedriftsfunksjoner for din egenvertede Pangolin-instans. Kjøp en lisensnøkkel for å aktivere premium-funksjoner og legg den inn nedenfor.",
"licenseBannerGetLicense": "Få en lisens",
"licenseBannerViewDocs": "Vis dokumentasjon",
"communityEdition": "Fellesskapsutgave",
"licenseAboutDescription": "Dette er for bedrifts- og foretaksbrukere som bruker Pangolin i et kommersielt miljø. Hvis du bruker Pangolin til personlig bruk, kan du ignorere denne seksjonen.",
"licenseKeyActivated": "Lisensnøkkel aktivert",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Vennligst skriv inn et gyldig portnummer",
"targetErrorNoSite": "Ingen nettsted valgt",
"targetErrorNoSiteDescription": "Velg et nettsted for målet",
"targetTargetsCleared": "Mål ryddet",
"targetTargetsClearedDescription": "Alle mål har blitt fjernet fra denne ressursen",
"targetCreated": "Mål opprettet",
"targetCreatedDescription": "Målet har blitt opprettet",
"targetErrorCreate": "Kunne ikke opprette målet",
@@ -892,6 +898,7 @@
"idpDisplayName": "Et visningsnavn for denne identitetsleverandøren",
"idpAutoProvisionUsers": "Automatisk brukerklargjøring",
"idpAutoProvisionUsersDescription": "Når aktivert, opprettes brukere automatisk i systemet ved første innlogging, med mulighet til å tilordne brukere til roller og organisasjoner.",
"idpAutoProvisionConfigureAfterCreate": "Du kan konfigurere autoprovisjonsinnstillingene når identitetsleverandøren er opprettet.",
"licenseBadge": "EE",
"idpType": "Leverandørtype",
"idpTypeDescription": "Velg typen identitetsleverandør du ønsker å konfigurere",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Standard rolletilordning",
"defaultMappingsRoleDescription": "Resultatet av dette uttrykket må returnere rollenavnet slik det er definert i organisasjonen som en streng.",
"defaultMappingsOrg": "Standard organisasjonstilordning",
"defaultMappingsOrgDescription": "Dette uttrykket returnere organisasjons-ID-en eller «true» for å gi brukeren tilgang til organisasjonen.",
"defaultMappingsOrgDescription": "Når denne er satt, må uttrykket returnere organisasjons-IDen eller «true» for at brukeren skal få tilgang til den organisasjonen. Når den ikke er satt, er det nok å definere en rolletilordning: brukeren gis tilgang så lenge en gyldig rolletilknytting kan løses for dem i organisasjonen.",
"defaultMappingsSubmit": "Lagre standard tilordninger",
"orgPoliciesEdit": "Rediger Organisasjonspolicy",
"org": "Organisasjon",
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Internasjonalt domene oppdaget",
"willbestoredas": "Vil bli lagret som:",
"roleMappingDescription": "Bestem hvordan roller tilordnes brukere når innloggingen er aktivert når autog-rapportering er aktivert.",
"roleMappingDescription": "Bestem hvordan roller tildeles brukere når de logger inn med denne identitetsleverandøren.",
"selectRole": "Velg en rolle",
"roleMappingExpression": "Uttrykk",
"selectRolePlaceholder": "Velg en rolle",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Velg et domene for organisasjonens autentiseringsside",
"domainPickerProvidedDomain": "Gitt domene",
"domainPickerFreeProvidedDomain": "Gratis oppgitt domene",
"domainPickerFreeDomainsPaidFeature": "Angitte domener er en betalingsfunksjon. Abonner for å få et domene inkludert i din plan ingen behov for å ta med ditt eget.",
"domainPickerVerified": "Bekreftet",
"domainPickerUnverified": "Uverifisert",
"domainPickerManual": "Manuell",
"domainPickerInvalidSubdomainStructure": "Dette underdomenet inneholder ugyldige tegn eller struktur. Det vil automatisk bli utsatt når du lagrer.",
"domainPickerError": "Feil",
"domainPickerErrorLoadDomains": "Kan ikke laste organisasjonens domener",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Skala",
"description": "Enterprise features, 50 brukere, 50 nettsteder og prioritetsstøtte."
"description": "Funksjoner for bedrifter, 50 brukere, 100 nettsteder og prioritert support."
}
},
"personalUseOnly": "Kun personlig bruk (gratis lisens - ingen utsjekking)",
"personalUseOnly": "Kun personlig bruk (gratis lisens - ingen kasse)",
"buttons": {
"continueToCheckout": "Fortsett til kassen"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Maskinklienter",
"install": "Installer",
"run": "Kjør",
"envFile": "Miljøfil",
"serviceFile": "Tjenestefil",
"enableAndStart": "Aktiver og start",
"clientNameDescription": "Visningsnavnet til klienten som kan endres senere.",
"clientAddress": "Klientadresse (avansert)",
"setupFailedToFetchSubnet": "Kunne ikke hente standard undernett",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Ingen godkjenning",
"httpDestAuthNoneDescription": "Sender forespørsler uten autorisasjonsoverskrift.",
"httpDestAuthBearerTitle": "Bærer Symbol",
"httpDestAuthBearerDescription": "Legger til en autorisasjon: Bearer <token> header til hver forespørsel.",
"httpDestAuthBearerDescription": "Legger til en Autorisasjon: Bearer '<token>' header til hver forespørsel.",
"httpDestAuthBearerPlaceholder": "Din API-nøkkel eller token",
"httpDestAuthBasicTitle": "Standard Auth",
"httpDestAuthBasicDescription": "Legger til en godkjenning: Grunnleggende <credentials> overskrift. Angi legitimasjon som brukernavn:passord.",
"httpDestAuthBasicDescription": "Legger til en Autorisasjon: Basic '<credentials>' header. Gi legitimasjon som brukernavn:passord.",
"httpDestAuthBasicPlaceholder": "brukernavn:passord",
"httpDestAuthCustomTitle": "Egendefinert topptekst",
"httpDestAuthCustomDescription": "Angi et egendefinert HTTP headers navn og verdi for autentisering (f.eks X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "JSON liste",
"httpDestFormatJsonArrayDescription": "Én forespørsel per batch, innholdet er en JSON-liste. Kompatibel med de mest generiske webhooks og Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Én forespørsel per sats, innholdet er nytt avgrenset JSON et objekt per linje, ingen ytterarray. Kreves av Splunk HEC, Elastisk/OpenSearch, og Grafana Loki.",
"httpDestFormatNdjsonDescription": "Én forespørsel per sats, innholdet er nytt avgrenset JSON - et objekt per linje, ingen ytterarray. Kreves av Splunk HEC, Elastisk/OpenSearch, og Grafana Loki.",
"httpDestFormatSingleTitle": "En hendelse per forespørsel",
"httpDestFormatSingleDescription": "Sender en separat HTTP POST for hver enkelt hendelse. Bruk bare for endepunkter som ikke kan håndtere batcher.",
"httpDestLogTypesTitle": "Logg typer",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Målet er oppdatert",
"httpDestCreatedSuccess": "Målet er opprettet",
"httpDestUpdateFailed": "Kunne ikke oppdatere destinasjon",
"httpDestCreateFailed": "Kan ikke opprette mål"
"httpDestCreateFailed": "Kan ikke opprette mål",
"idpAddActionCreateNew": "Opprett ny identitetsleverandør",
"idpAddActionImportFromOrg": "Importer fra en annen organisasjon",
"idpImportDialogTitle": "Importer identitetsleverandør",
"idpImportDialogDescription": "Velg en identitetsleverandør fra en organisasjon der du er admin. Den vil bli knyttet til denne organisasjonen.",
"idpImportSearchPlaceholder": "Søk etter organisasjons- eller leverandørnavn...",
"idpImportEmpty": "Ingen identitetsleverandører funnet.",
"idpImportedDescription": "Identitetsleverandøren ble importert vellykket.",
"idpDeleteGlobalQuestion": "Er du sikker på at du vil slette denne identitetsleverandøren permanent?",
"idpDeleteGlobalDescription": "Dette vil slette identitetsleverandøren permanent fra alle organisasjoner den er tilknyttet.",
"idpUnassociateTitle": "Frakoble identitetsleverandør",
"idpUnassociateQuestion": "Er du sikker på at du vil frakoble denne identitetsleverandøren fra denne organisasjonen?",
"idpUnassociateDescription": "Alle brukere knyttet til denne identitetsleverandøren vil bli fjernet fra denne organisasjonen, men identitetsleverandøren vil fortsatt eksistere for andre tilknyttede organisasjoner.",
"idpUnassociateConfirm": "Bekreft frakobling av identitetsleverandør",
"idpUnassociateWarning": "Dette kan ikke angres for denne organisasjonen.",
"idpUnassociatedDescription": "Identitetsleverandør er vellykket frakoblet fra denne organisasjonen",
"idpUnassociateMenu": "Frakoble",
"idpDeleteAllOrgsMenu": "Slett"
}
+38 -9
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Provisie sleutel bijgewerkt",
"provisioningKeysUpdatedDescription": "Uw wijzigingen zijn opgeslagen.",
"provisioningKeysBannerTitle": "Bewerkingssleutels voor websites",
"provisioningKeysBannerDescription": "Genereer een provisioning-sleutel en gebruik deze met de Newt-connector om automatisch sites aan te maken bij het opstarten van de eerste opstart- het is niet nodig om afzonderlijke inloggegevens in te stellen voor elke site.",
"provisioningKeysBannerDescription": "Genereer een inrichtingssleutel en gebruik deze met de Newt-connector om automatisch sites te maken bij de eerste opstart - er is geen behoefte om aparte inloggegevens voor elke site in te stellen.",
"provisioningKeysBannerButtonText": "Meer informatie",
"pendingSitesBannerTitle": "Openstaande sites",
"pendingSitesBannerDescription": "Sites die met elkaar verbinden met behulp van een provisioning-sleutel verschijnen hier voor beoordeling. Accepteer elke site voordat deze actief wordt en krijgt toegang tot uw bronnen.",
"pendingSitesBannerDescription": "Sites die verbinding maken met een inrichtingssleutel verschijnen hier voor beoordeling.",
"pendingSitesBannerButtonText": "Meer informatie",
"apiKeysSettings": "{apiKeyName} instellingen",
"userTitle": "Alle gebruikers beheren",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Licentiesleutel activeren mislukt",
"licenseErrorKeyActivateDescription": "Er is een fout opgetreden tijdens het activeren van de licentiesleutel.",
"licenseAbout": "Over licenties",
"licenseBannerTitle": "Activeer Uw Enterprise Licentie",
"licenseBannerDescription": "Ontgrendel enterprise-functies voor uw zelf-gehoste Pangolin-instantie. Koop een licentiesleutel om premium mogelijkheden te activeren, voeg deze vervolgens hieronder toe.",
"licenseBannerGetLicense": "Koop een Licentie",
"licenseBannerViewDocs": "Bekijk Documentatie",
"communityEdition": "Community editie",
"licenseAboutDescription": "Dit geldt voor gebruikers van bedrijven en ondernemingen die Pangolin in gebruiken in een commerciële omgeving. Als u Pangolin gebruikt voor persoonlijk gebruik, kunt u dit gedeelte negeren.",
"licenseKeyActivated": "Licentiesleutel geactiveerd",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Voer een geldig poortnummer in",
"targetErrorNoSite": "Geen site geselecteerd",
"targetErrorNoSiteDescription": "Selecteer een site voor het doel",
"targetTargetsCleared": "Doelen gewist",
"targetTargetsClearedDescription": "Alle doelen zijn verwijderd van deze bron",
"targetCreated": "Doel aangemaakt",
"targetCreatedDescription": "Doel is succesvol aangemaakt",
"targetErrorCreate": "Kan doel niet aanmaken",
@@ -892,6 +898,7 @@
"idpDisplayName": "Een weergavenaam voor deze identiteitsprovider",
"idpAutoProvisionUsers": "Auto Provisie Gebruikers",
"idpAutoProvisionUsersDescription": "Wanneer ingeschakeld, worden gebruikers automatisch in het systeem aangemaakt wanneer ze de eerste keer inloggen met de mogelijkheid om gebruikers toe te wijzen aan rollen en organisaties.",
"idpAutoProvisionConfigureAfterCreate": "U kunt automatische voorzieningsinstellingen configureren zodra de identiteitsprovider is aangemaakt.",
"licenseBadge": "EE",
"idpType": "Type provider",
"idpTypeDescription": "Selecteer het type identiteitsprovider dat u wilt configureren",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Standaard Rol Toewijzing",
"defaultMappingsRoleDescription": "Het resultaat van deze uitdrukking moet de rolnaam zoals gedefinieerd in de organisatie als tekenreeks teruggeven.",
"defaultMappingsOrg": "Standaard organisatie mapping",
"defaultMappingsOrgDescription": "Deze expressie moet de org-ID teruggeven of waar om de gebruiker toegang te geven tot de organisatie.",
"defaultMappingsOrgDescription": "Wanneer ingesteld, moet deze expressie de organisatie-ID of waar retourneren voor de gebruiker om toegang te krijgen tot die organisatie. Als het niet is ingesteld, is het definiëren van een roltoewijzing voldoende: de gebruiker is toegestaan zolang een geldige roltoewijzing voor hen binnen de organisatie kan worden opgelost.",
"defaultMappingsSubmit": "Standaard toewijzingen opslaan",
"orgPoliciesEdit": "Organisatie beleid bewerken",
"org": "Organisatie",
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Internationaal Domein Gedetecteerd",
"willbestoredas": "Zal worden opgeslagen als:",
"roleMappingDescription": "Bepaal hoe rollen worden toegewezen aan gebruikers wanneer ze inloggen wanneer Auto Provision is ingeschakeld.",
"roleMappingDescription": "Bepaal hoe rollen aan gebruikers worden toegewezen wanneer ze zich aanmelden met deze identiteitsprovider.",
"selectRole": "Selecteer een rol",
"roleMappingExpression": "Expressie",
"selectRolePlaceholder": "Kies een rol",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Selecteer een domein voor de authenticatiepagina van de organisatie",
"domainPickerProvidedDomain": "Opgegeven domein",
"domainPickerFreeProvidedDomain": "Gratis verstrekt domein",
"domainPickerFreeDomainsPaidFeature": "Geleverde domeinen zijn een betaalde functie. Abonneer je om een domein bij je plan te krijgen - je hoeft er zelf geen mee te brengen.",
"domainPickerVerified": "Geverifieerd",
"domainPickerUnverified": "Ongeverifieerd",
"domainPickerManual": "Handleiding",
"domainPickerInvalidSubdomainStructure": "Dit subdomein bevat ongeldige tekens of structuur. Het zal automatisch worden gesaneerd wanneer u opslaat.",
"domainPickerError": "Foutmelding",
"domainPickerErrorLoadDomains": "Fout bij het laden van organisatiedomeinen",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Schaal",
"description": "Enterprise functies, 50 gebruikers, 50 sites en prioriteit ondersteuning."
"description": "Enterprise-functies, 50 gebruikers, 100 sites en prioritaire ondersteuning."
}
},
"personalUseOnly": "Alleen persoonlijk gebruik (gratis licentie - geen afrekenen)",
"personalUseOnly": "Alleen voor persoonlijk gebruik (gratis licentie - geen afrekening)",
"buttons": {
"continueToCheckout": "Doorgaan naar afrekenen"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Machine Clienten",
"install": "Installeren",
"run": "Uitvoeren",
"envFile": "Omgevingsbestand",
"serviceFile": "Servicebestand",
"enableAndStart": "Inschakelen en Starten",
"clientNameDescription": "De weergavenaam van de client die later gewijzigd kan worden.",
"clientAddress": "Klant adres (Geavanceerd)",
"setupFailedToFetchSubnet": "Kan standaard subnet niet ophalen",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Geen authenticatie",
"httpDestAuthNoneDescription": "Stuurt verzoeken zonder toestemmingskop.",
"httpDestAuthBearerTitle": "Betere Token",
"httpDestAuthBearerDescription": "Voegt een machtiging toe: Drager <token> header aan elke aanvraag.",
"httpDestAuthBearerDescription": "Voegt een Authorization: Bearer '<token>' header toe aan elk verzoek.",
"httpDestAuthBearerPlaceholder": "Uw API-sleutel of -token",
"httpDestAuthBasicTitle": "Basis authenticatie",
"httpDestAuthBasicDescription": "Voegt een Authorizatie toe: Basis <credentials> kop. Geef inloggegevens op als gebruikersnaam:wachtwoord.",
"httpDestAuthBasicDescription": "Voegt een Authorization: Basic '<credentials>' header toe. Verstrek inloggegevens als gebruikersnaam:wachtwoord.",
"httpDestAuthBasicPlaceholder": "Gebruikersnaam:wachtwoord",
"httpDestAuthCustomTitle": "Aangepaste koptekst",
"httpDestAuthCustomDescription": "Specificeer een aangepaste HTTP header naam en waarde voor authenticatie (bijv. X-API-Key).",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Bestemming succesvol bijgewerkt",
"httpDestCreatedSuccess": "Bestemming succesvol aangemaakt",
"httpDestUpdateFailed": "Bijwerken bestemming mislukt",
"httpDestCreateFailed": "Aanmaken bestemming mislukt"
"httpDestCreateFailed": "Aanmaken bestemming mislukt",
"idpAddActionCreateNew": "Nieuwe identiteitsprovider aanmaken",
"idpAddActionImportFromOrg": "Importeer vanuit een andere organisatie",
"idpImportDialogTitle": "Importeer Identiteitsprovider",
"idpImportDialogDescription": "Kies een identiteitsprovider van een organisatie waar u beheerder bent. Het wordt gekoppeld aan deze organisatie.",
"idpImportSearchPlaceholder": "Zoek op organisatie- of providernamen...",
"idpImportEmpty": "Geen identiteitsproviders gevonden.",
"idpImportedDescription": "Identiteitsprovider succesvol geïmporteerd.",
"idpDeleteGlobalQuestion": "Weet u zeker dat u deze identiteitsprovider permanent wilt verwijderen?",
"idpDeleteGlobalDescription": "Hiermee wordt de identiteitsprovider permanent verwijderd uit alle organisaties waarmee het is geassocieerd.",
"idpUnassociateTitle": "Koppel Identiteitsprovider los",
"idpUnassociateQuestion": "Weet u zeker dat u deze identiteitsprovider van deze organisatie wilt loskoppelen?",
"idpUnassociateDescription": "Alle gebruikers die aan deze identiteitsprovider zijn gekoppeld, worden uit deze organisatie verwijderd, maar de identiteitsprovider blijft bestaan voor andere gerelateerde organisaties.",
"idpUnassociateConfirm": "Bevestig ontkoppelen identiteitsprovider",
"idpUnassociateWarning": "Dit kan niet ongedaan worden gemaakt voor deze organisatie.",
"idpUnassociatedDescription": "Identiteitsprovider succesvol losgekoppeld van deze organisatie",
"idpUnassociateMenu": "Ontkoppelen",
"idpDeleteAllOrgsMenu": "Verwijderen"
}
+40 -11
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Klucz zaopatrzenia zaktualizowany",
"provisioningKeysUpdatedDescription": "Twoje zmiany zostały zapisane.",
"provisioningKeysBannerTitle": "Klucze Zaopatrzenia witryny",
"provisioningKeysBannerDescription": "Wygeneruj klucz tworzenia rezerw i użyj go z konektorem Newt do automatycznego tworzenia witryn przy pierwszym uruchomieniu nie ma potrzeby ustawiania oddzielnych poświadczeń dla każdej witryny.",
"provisioningKeysBannerDescription": "Wygeneruj klucz provisioning i użyj go z konektorem Newt do automatycznego tworzenia witryn przy pierwszym uruchomieniu - nie ma potrzeby konfigurowania oddzielnych poświadczeń dla każdej witryny.",
"provisioningKeysBannerButtonText": "Dowiedz się więcej",
"pendingSitesBannerTitle": "Witryny oczekujące",
"pendingSitesBannerDescription": "Witryny, które łączą się przy użyciu klucza zaopatrzenia, pojawiają się tutaj, aby przejrzeć. Zatwierdź każdą witrynę, zanim stanie się aktywna i uzyska dostęp do twoich zasobów.",
"pendingSitesBannerDescription": "Witryny, które łączą się za pomocą klucza provisioning, pojawią się tutaj do przeglądu.",
"pendingSitesBannerButtonText": "Dowiedz się więcej",
"apiKeysSettings": "Ustawienia {apiKeyName}",
"userTitle": "Zarządzaj wszystkimi użytkownikami",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Nie udało się aktywować klucza licencji",
"licenseErrorKeyActivateDescription": "Wystąpił błąd podczas aktywacji klucza licencyjnego.",
"licenseAbout": "O licencjonowaniu",
"licenseBannerTitle": "Aktywuj swoją licencję Enterprise",
"licenseBannerDescription": "Odblokuj funkcje korporacyjne dla swojego autonomicznego wdrożenia Pangolin. Kup klucz licencyjny, aby aktywować możliwości premium, a następnie wprowadź go poniżej.",
"licenseBannerGetLicense": "Uzyskaj licencję",
"licenseBannerViewDocs": "Zobacz dokumentację",
"communityEdition": "Edycja Społecznościowa",
"licenseAboutDescription": "Dotyczy to przedsiębiorstw i przedsiębiorstw, którzy stosują Pangolin w środowisku handlowym. Jeśli używasz Pangolin do użytku osobistego, możesz zignorować tę sekcję.",
"licenseKeyActivated": "Klucz licencyjny aktywowany",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Wprowadź prawidłowy numer portu",
"targetErrorNoSite": "Nie wybrano witryny",
"targetErrorNoSiteDescription": "Wybierz witrynę docelową",
"targetTargetsCleared": "Cele wyczyszczone",
"targetTargetsClearedDescription": "Wszystkie cele zostały usunięte z tego zasobu",
"targetCreated": "Cel utworzony",
"targetCreatedDescription": "Cel został utworzony pomyślnie",
"targetErrorCreate": "Nie udało się utworzyć celu",
@@ -892,6 +898,7 @@
"idpDisplayName": "Nazwa wyświetlana dla tego dostawcy tożsamości",
"idpAutoProvisionUsers": "Automatyczne tworzenie użytkowników",
"idpAutoProvisionUsersDescription": "Gdy włączone, użytkownicy będą automatycznie tworzeni w systemie przy pierwszym logowaniu z możliwością mapowania użytkowników do ról i organizacji.",
"idpAutoProvisionConfigureAfterCreate": "Możesz skonfigurować automatyczne ustawienia provision, gdy dostawca tożsamości zostanie utworzony.",
"licenseBadge": "EE",
"idpType": "Typ dostawcy",
"idpTypeDescription": "Wybierz typ dostawcy tożsamości, który chcesz skonfigurować",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Domyślne mapowanie roli",
"defaultMappingsRoleDescription": "JMESPath do wydobycia informacji o roli z tokena ID. Wynik tego wyrażenia musi zwrócić nazwę roli zdefiniowaną w organizacji jako ciąg znaków.",
"defaultMappingsOrg": "Domyślne mapowanie organizacji",
"defaultMappingsOrgDescription": "JMESPath do wydobycia informacji o organizacji z tokena ID. To wyrażenie musi zwrócić ID organizacji lub true, aby użytkownik mógł uzyskać dostęp do organizacji.",
"defaultMappingsOrgDescription": "Gdy jest ustawiona, ta wyrażenie musi zwrócić identyfikator organizacji lub true, aby użytkownik mógł uzyskać dostęp do tej organizacji. Gdy nie jest ustawiona, wystarczające jest zdefiniowanie mapowania ról: użytkownik jest dopuszczony, o ile można rozwiązać dla niego ważne mapowanie ról w organizacji.",
"defaultMappingsSubmit": "Zapisz domyślne mapowania",
"orgPoliciesEdit": "Edytuj politykę organizacji",
"org": "Organizacja",
@@ -1987,7 +1994,7 @@
"description": "Większa niezawodność i niska konserwacja serwera Pangolin z dodatkowymi dzwonkami i sygnałami",
"introTitle": "Zarządzany samowystarczalny Pangolin",
"introDescription": "jest opcją wdrażania zaprojektowaną dla osób, które chcą prostoty i dodatkowej niezawodności, przy jednoczesnym utrzymaniu swoich danych prywatnych i samodzielnych.",
"introDetail": "Z tą opcją nadal obsługujesz swój własny węzeł Pangolin tunele, zakończenie SSL i ruch na Twoim serwerze. Różnica polega na tym, że zarządzanie i monitorowanie odbywa się za pomocą naszej tablicy rozdzielczej, która odblokowuje szereg korzyści:",
"introDetail": "Z tą opcją nadal obsługujesz swój własny węzeł Pangolin - tunele, zakończenie SSL i ruch na Twoim serwerze. Różnica polega na tym, że zarządzanie i monitorowanie odbywa się za pomocą naszej tablicy rozdzielczej, która odblokowuje szereg korzyści:",
"benefitSimplerOperations": {
"title": "Uproszczone operacje",
"description": "Nie ma potrzeby uruchamiania własnego serwera pocztowego lub ustawiania skomplikowanych powiadomień. Będziesz mieć kontrolę zdrowia i powiadomienia o przestoju."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Wykryto międzynarodową domenę",
"willbestoredas": "Będą przechowywane jako:",
"roleMappingDescription": "Określ jak role są przypisywane do użytkowników podczas logowania się, gdy automatyczne świadczenie jest włączone.",
"roleMappingDescription": "Określ, jak role są przypisywane użytkownikom podczas logowania się z tym dostawcą tożsamości.",
"selectRole": "Wybierz rolę",
"roleMappingExpression": "Wyrażenie",
"selectRolePlaceholder": "Wybierz rolę",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Wybierz domenę dla strony uwierzytelniania organizacji",
"domainPickerProvidedDomain": "Dostarczona domena",
"domainPickerFreeProvidedDomain": "Darmowa oferowana domena",
"domainPickerFreeDomainsPaidFeature": "Dostarczane domeny to funkcja płatna. Subskrybuj, aby uzyskać domenę w ramach swojego planu - nie ma potrzeby przynoszenia własnej.",
"domainPickerVerified": "Zweryfikowano",
"domainPickerUnverified": "Niezweryfikowane",
"domainPickerManual": "Podręcznik",
"domainPickerInvalidSubdomainStructure": "Ta subdomena zawiera nieprawidłowe znaki lub strukturę. Zostanie ona automatycznie oczyszczona po zapisaniu.",
"domainPickerError": "Błąd",
"domainPickerErrorLoadDomains": "Nie udało się załadować domen organizacji",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Skala",
"description": "Cechy przedsiębiorstw, 50 użytkowników, 50 obiektów i wsparcie priorytetowe."
"description": "Funkcje dla przedsiębiorstw, 50 użytkowników, 100 witryn i priorytetowe wsparcie."
}
},
"personalUseOnly": "Wyłącznie do użytku osobistego (bezpłatna licencja brak zamówień)",
"personalUseOnly": "Tylko do użytku osobistego (darmowa licencja - bez płatności)",
"buttons": {
"continueToCheckout": "Przejdź do zamówienia"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Klienci maszyn",
"install": "Zainstaluj",
"run": "Uruchom",
"envFile": "Plik środowiska",
"serviceFile": "Plik serwisu",
"enableAndStart": "Włącz i Uruchom",
"clientNameDescription": "Wyświetlana nazwa klienta, która może zostać zmieniona później.",
"clientAddress": "Adres klienta (Zaawansowany)",
"setupFailedToFetchSubnet": "Nie udało się pobrać domyślnej podsieci",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Brak uwierzytelniania",
"httpDestAuthNoneDescription": "Wysyła żądania bez nagłówka autoryzacji.",
"httpDestAuthBearerTitle": "Token Bearer",
"httpDestAuthBearerDescription": "Dodaje autoryzację: nagłówek Bearer <token> do każdego żądania.",
"httpDestAuthBearerDescription": "Dodaje nagłówek Authorization: Bearer '<token>' do każdego żądania.",
"httpDestAuthBearerPlaceholder": "Twój klucz API lub token",
"httpDestAuthBasicTitle": "Podstawowa Autoryzacja",
"httpDestAuthBasicDescription": "Dodaje Autoryzacja: Nagłówek Basic <credentials> . Podaj poświadczenia jako nazwę użytkownika: hasło.",
"httpDestAuthBasicDescription": "Dodaje nagłówek Authorization: Basic '<credentials>'. Podaj poświadczenia w formacie użytkownik:hasło.",
"httpDestAuthBasicPlaceholder": "Nazwa użytkownika:hasło",
"httpDestAuthCustomTitle": "Niestandardowy nagłówek",
"httpDestAuthCustomDescription": "Określ niestandardową nazwę nagłówka HTTP i wartość dla uwierzytelniania (np. X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "Tablica JSON",
"httpDestFormatJsonArrayDescription": "Jedna prośba na partię, treść jest tablicą JSON. Kompatybilna z najbardziej ogólnymi webhookami i Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Jedno żądanie na partię, ciałem jest plik JSON rozdzielony na newline-delimited jeden obiekt na wiersz, bez tablicy zewnętrznej. Wymagane przez Splunk HEC, Elastic / OpenSesearch i Grafana Loki.",
"httpDestFormatNdjsonDescription": "Jedno żądanie na partię, ciałem jest plik JSON rozdzielony na newline-delimited - jeden obiekt na wiersz, bez tablicy zewnętrznej. Wymagane przez Splunk HEC, Elastic / OpenSesearch i Grafana Loki.",
"httpDestFormatSingleTitle": "Jedno wydarzenie na żądanie",
"httpDestFormatSingleDescription": "Wysyła oddzielny POST HTTP dla każdego zdarzenia. Użyj tylko dla punktów końcowych, które nie mogą obsługiwać partii.",
"httpDestLogTypesTitle": "Typy logów",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Cel został pomyślnie zaktualizowany",
"httpDestCreatedSuccess": "Cel został utworzony pomyślnie",
"httpDestUpdateFailed": "Nie udało się zaktualizować miejsca docelowego",
"httpDestCreateFailed": "Nie udało się utworzyć miejsca docelowego"
"httpDestCreateFailed": "Nie udało się utworzyć miejsca docelowego",
"idpAddActionCreateNew": "Utwórz nowego dostawcę tożsamości",
"idpAddActionImportFromOrg": "Importuj z innej organizacji",
"idpImportDialogTitle": "Importuj dostawcę tożsamości",
"idpImportDialogDescription": "Wybierz dostawcę tożsamości z organizacji, w której jesteś administratorem. Zostanie on powiązany z tą organizacją.",
"idpImportSearchPlaceholder": "Szukaj według nazwy organizacji lub dostawcy...",
"idpImportEmpty": "Nie znaleziono dostawców tożsamości.",
"idpImportedDescription": "Dostawca tożsamości został pomyślnie zaimportowany.",
"idpDeleteGlobalQuestion": "Czy na pewno chcesz trwale usunąć tego dostawcę tożsamości?",
"idpDeleteGlobalDescription": "Spowoduje to trwałe usunięcie dostawcy tożsamości ze wszystkich organizacji, z którymi jest powiązany.",
"idpUnassociateTitle": "Odłącz dostawcę tożsamości",
"idpUnassociateQuestion": "Czy na pewno chcesz odłączyć tego dostawcę tożsamości od tej organizacji?",
"idpUnassociateDescription": "Wszystkie użytkownicy powiązani z tym dostawcą tożsamości zostaną usunięci z tej organizacji, ale dostawca tożsamości będzie nadal istniał dla innych powiązanych organizacji.",
"idpUnassociateConfirm": "Potwierdź odłączenie dostawcy tożsamości",
"idpUnassociateWarning": "Tego nie można cofnąć dla tej organizacji.",
"idpUnassociatedDescription": "Dostawca tożsamości pomyślnie odłączony od tej organizacji",
"idpUnassociateMenu": "Odłącz",
"idpDeleteAllOrgsMenu": "Usuń"
}
+41 -12
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Chave de provisionamento atualizada",
"provisioningKeysUpdatedDescription": "Suas alterações foram salvas.",
"provisioningKeysBannerTitle": "Chaves de provisionamento do site",
"provisioningKeysBannerDescription": "Gerar uma chave de provisionamento e usá-la com o conector de Newt para criar automaticamente sites na primeira inicialização — não é necessário configurar credenciais separadas para cada site.",
"provisioningKeysBannerDescription": "Gere uma chave de provisionamento e use-a com o conector Newt para criar sites automaticamente na primeira inicialização - sem necessidade de configurar credenciais separadas para cada site.",
"provisioningKeysBannerButtonText": "Saiba mais",
"pendingSitesBannerTitle": "Sites pendentes",
"pendingSitesBannerDescription": "Sites que conectam usando uma chave de provisionamento aparecem aqui para revisão. Aprovar cada site antes de se tornar ativo e ganhar acesso a seus recursos.",
"pendingSitesBannerDescription": "Sites que se conectam usando uma chave de provisionamento aparecem aqui para revisão.",
"pendingSitesBannerButtonText": "Saiba mais",
"apiKeysSettings": "Configurações de {apiKeyName}",
"userTitle": "Gerir Todos os Utilizadores",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Falha ao ativar a chave de licença",
"licenseErrorKeyActivateDescription": "Ocorreu um erro ao ativar a chave da licença.",
"licenseAbout": "Sobre Licenciamento",
"licenseBannerTitle": "Ative Sua Licença Corporativa",
"licenseBannerDescription": "Desbloqueie recursos empresariais para sua instância de Pangolin autohospedada. Compre uma chave de licença para ativar recursos premium e adicione-a abaixo.",
"licenseBannerGetLicense": "Obter Licença",
"licenseBannerViewDocs": "Ver Documentação",
"communityEdition": "Edição da Comunidade",
"licenseAboutDescription": "Isto destina-se aos utilizadores empresariais e empresariais que estão a usar o Pangolin num ambiente comercial. Se você estiver usando o Pangolin para uso pessoal, você pode ignorar esta seção.",
"licenseKeyActivated": "Chave de licença ativada",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Por favor, digite um número de porta válido",
"targetErrorNoSite": "Nenhum site selecionado",
"targetErrorNoSiteDescription": "Selecione um site para o destino",
"targetTargetsCleared": "Alvos limpos",
"targetTargetsClearedDescription": "Todos os alvos foram removidos deste recurso",
"targetCreated": "Destino criado",
"targetCreatedDescription": "O alvo foi criado com sucesso",
"targetErrorCreate": "Falha ao criar destino",
@@ -892,6 +898,7 @@
"idpDisplayName": "Um nome de exibição para este provedor de identidade",
"idpAutoProvisionUsers": "Provisionamento Automático de Utilizadores",
"idpAutoProvisionUsersDescription": "Quando ativado, os utilizadores serão criados automaticamente no sistema no primeiro login com a capacidade de mapear utilizadores para funções e organizações.",
"idpAutoProvisionConfigureAfterCreate": "Você pode configurar as definições de auto provisão assim que o provedor de identidade for criado.",
"licenseBadge": "EE",
"idpType": "Tipo de Provedor",
"idpTypeDescription": "Selecione o tipo de provedor de identidade que deseja configurar",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Mapeamento de Função Padrão",
"defaultMappingsRoleDescription": "JMESPath para extrair informações de função do token ID. O resultado desta expressão deve retornar o nome da função como definido na organização como uma string.",
"defaultMappingsOrg": "Mapeamento de Organização Padrão",
"defaultMappingsOrgDescription": "JMESPath para extrair informações da organização do token ID. Esta expressão deve retornar o ID da organização ou verdadeiro para que o utilizador tenha permissão para aceder à organização.",
"defaultMappingsOrgDescription": "Quando definida, esta expressão deve retornar o ID da organização ou verdadeiro para que o usuário acesse essa organização. Quando não definida, a definição de um mapeamento de papel é suficiente: o usuário é permitido desde que um mapeamento de papel válido possa ser resolvido para ele dentro da organização.",
"defaultMappingsSubmit": "Guardar Mapeamentos Padrão",
"orgPoliciesEdit": "Editar Política da Organização",
"org": "Organização",
@@ -1987,7 +1994,7 @@
"description": "Servidor Pangolin auto-hospedado mais confiável e com baixa manutenção com sinos extras e assobiamentos",
"introTitle": "Pangolin Auto-Hospedado Gerenciado",
"introDescription": "é uma opção de implantação projetada para pessoas que querem simplicidade e confiança adicional, mantendo os seus dados privados e auto-hospedados.",
"introDetail": "Com esta opção, você ainda roda seu próprio nó Pangolin seus túneis, terminação SSL e tráfego todos permanecem no seu servidor. A diferença é que a gestão e a monitorização são geridos através do nosso painel de nuvem, que desbloqueia vários benefícios:",
"introDetail": "Com esta opção, você ainda roda seu próprio nó Pangolin - seus túneis, terminação SSL e tráfego todos permanecem no seu servidor. A diferença é que a gestão e a monitorização são geridos através do nosso painel de nuvem, que desbloqueia vários benefícios:",
"benefitSimplerOperations": {
"title": "Operações simples",
"description": "Não é necessário executar o seu próprio servidor de e-mail ou configurar um alerta complexo. Você receberá fora de caixa verificações de saúde e alertas de tempo de inatividade."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Domínio Internacional Detectado",
"willbestoredas": "Será armazenado como:",
"roleMappingDescription": "Determinar como as funções são atribuídas aos usuários quando eles fazem login quando Auto Provisão está habilitada.",
"roleMappingDescription": "Determine como os papéis são atribuídos aos usuários quando eles entram com este provedor de identidade.",
"selectRole": "Selecione uma função",
"roleMappingExpression": "Expressão",
"selectRolePlaceholder": "Escolha uma função",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Selecione um domínio para a página de autenticação da organização",
"domainPickerProvidedDomain": "Domínio fornecido",
"domainPickerFreeProvidedDomain": "Domínio fornecido grátis",
"domainPickerFreeDomainsPaidFeature": "Os domínios fornecidos são um recurso pago. Assine para obter um domínio incluído no seu plano - não há necessidade de trazer o seu próprio.",
"domainPickerVerified": "Verificada",
"domainPickerUnverified": "Não verificado",
"domainPickerManual": "Manual",
"domainPickerInvalidSubdomainStructure": "Este subdomínio contém caracteres ou estrutura inválidos. Ele será eliminado automaticamente quando você salvar.",
"domainPickerError": "ERRO",
"domainPickerErrorLoadDomains": "Falha ao carregar domínios da organização",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Divulgação de uso",
"description": "Selecione o nível de licença que reflete corretamente seu uso pretendido. A Licença Pessoal permite o uso livre do Software para atividades comerciais individuais, não comerciais ou em pequena escala com rendimento bruto anual inferior a 100.000 USD. Qualquer uso além destes limites incluindo uso dentro de um negócio, organização, ou outro ambiente gerador de receitas requer uma Licença Enterprise válida e o pagamento da taxa aplicável de licenciamento. Todos os usuários, pessoais ou empresariais, devem cumprir os Termos da Licença Comercial Fossorial."
"description": "Selecione o nível de licença que reflete corretamente seu uso pretendido. A Licença Pessoal permite o uso livre do Software para atividades comerciais individuais, não comerciais ou em pequena escala com rendimento bruto anual inferior a 100.000 USD. Qualquer uso além destes limites - incluindo uso dentro de um negócio, organização, ou outro ambiente gerador de receitas - requer uma Licença Enterprise válida e o pagamento da taxa aplicável de licenciamento. Todos os usuários, pessoais ou empresariais, devem cumprir os Termos da Licença Comercial Fossorial."
},
"trialPeriodInformation": {
"title": "Informações do Período de Avaliação",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Escala",
"description": "Recursos de empresa, 50 usuários, 50 sites e apoio prioritário."
"description": "Recursos empresariais, 50 usuários, 100 sites, e suporte prioritário."
}
},
"personalUseOnly": "Apenas uso pessoal (licença gratuita sem check-out)",
"personalUseOnly": "Uso pessoal apenas (licença gratuita - sem checkout)",
"buttons": {
"continueToCheckout": "Continuar com checkout"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Clientes de máquina",
"install": "Instale",
"run": "Executar",
"envFile": "Arquivo de Ambiente",
"serviceFile": "Arquivo de Serviço",
"enableAndStart": "Ativar e Iniciar",
"clientNameDescription": "O nome de exibição do cliente que pode ser alterado mais tarde.",
"clientAddress": "Endereço do Cliente (Avançado)",
"setupFailedToFetchSubnet": "Falha ao buscar a subrede padrão",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Sem Autenticação",
"httpDestAuthNoneDescription": "Envia pedidos sem um cabeçalho de autorização.",
"httpDestAuthBearerTitle": "Token do portador",
"httpDestAuthBearerDescription": "Adiciona uma autorização: Bearer <token> header a cada requisição.",
"httpDestAuthBearerDescription": "Adiciona um cabeçalho Authorization: Bearer '<token>' a cada solicitação.",
"httpDestAuthBearerPlaceholder": "Sua chave de API ou token",
"httpDestAuthBasicTitle": "Autenticação básica",
"httpDestAuthBasicDescription": "Adiciona uma Autorização: cabeçalho <credentials> básico. Forneça credenciais como nome de usuário:senha.",
"httpDestAuthBasicDescription": "Adiciona um cabeçalho Authorization: Basic '<credentials>'. Forneça as credenciais como username:password.",
"httpDestAuthBasicPlaceholder": "Usuário:password",
"httpDestAuthCustomTitle": "Cabeçalho personalizado",
"httpDestAuthCustomDescription": "Especifique um nome e valor de cabeçalho HTTP personalizado para autenticação (por exemplo, X-API-Key).",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "Matriz JSON",
"httpDestFormatJsonArrayDescription": "Um pedido por lote, o corpo é um array JSON. Compatível com a maioria dos webhooks genéricos e Datadog.",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "Um pedido por lote, o corpo é um JSON delimitado por nova-linha um objeto por linha, sem array exterior. Requerido pelo Splunk HEC, Elástico / OpenSearch, e Grafana Loki.",
"httpDestFormatNdjsonDescription": "Um pedido por lote, o corpo é um JSON delimitado por nova-linha - um objeto por linha, sem array exterior. Requerido pelo Splunk HEC, Elástico / OpenSearch, e Grafana Loki.",
"httpDestFormatSingleTitle": "Um Evento por Requisição",
"httpDestFormatSingleDescription": "Envia um POST HTTP separado para cada evento. Utilize apenas para endpoints que não podem manipular lotes.",
"httpDestLogTypesTitle": "Tipos de log",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Destino atualizado com sucesso",
"httpDestCreatedSuccess": "Destino criado com sucesso",
"httpDestUpdateFailed": "Falha ao atualizar destino",
"httpDestCreateFailed": "Falha ao criar destino"
"httpDestCreateFailed": "Falha ao criar destino",
"idpAddActionCreateNew": "Criar novo provedor de identidade",
"idpAddActionImportFromOrg": "Importar de outra organização",
"idpImportDialogTitle": "Importar Provedor de Identidade",
"idpImportDialogDescription": "Escolha um provedor de identidade de uma organização onde você é administrador. Ele será vinculado a esta organização.",
"idpImportSearchPlaceholder": "Pesquisar por nome de organização ou provedor...",
"idpImportEmpty": "Nenhum provedor de identidade encontrado.",
"idpImportedDescription": "Provedor de identidade importado com sucesso.",
"idpDeleteGlobalQuestion": "Tem certeza de que deseja eliminar permanentemente este provedor de identidade?",
"idpDeleteGlobalDescription": "Isso eliminará permanentemente o provedor de identidade de todas as organizações com as quais está associado.",
"idpUnassociateTitle": "Desassociar Provedor de Identidade",
"idpUnassociateQuestion": "Tem certeza de que deseja desassociar este provedor de identidade desta organização?",
"idpUnassociateDescription": "Todos os usuários associados a este provedor de identidade serão removidos desta organização, mas o provedor de identidade continuará a existir para outras organizações associadas.",
"idpUnassociateConfirm": "Confirmar Desassociação do Provedor de Identidade",
"idpUnassociateWarning": "Isso não pode ser desfeito para esta organização.",
"idpUnassociatedDescription": "Provedor de identidade desassociado desta organização com sucesso",
"idpUnassociateMenu": "Desassociar",
"idpDeleteAllOrgsMenu": "Excluir"
}
+42 -13
View File
@@ -56,7 +56,7 @@
"siteManageSites": "Управление сайтами",
"siteDescription": "Создание и управление сайтами, чтобы включить подключение к приватным сетям",
"sitesBannerTitle": "Подключить любую сеть",
"sitesBannerDescription": "Сайт это соединение с удаленной сетью, которое позволяет Pangolin предоставлять доступ к ресурсам, будь они общедоступными или частными, пользователям в любом месте. Установите сетевой коннектор сайта (Newt) там, где можно запустить исполняемый файл или контейнер, чтобы установить соединение.",
"sitesBannerDescription": "Сайт - это соединение с удаленной сетью, которое позволяет Pangolin предоставлять доступ к ресурсам, будь они общедоступными или частными, пользователям в любом месте. Установите сетевой коннектор сайта (Newt) там, где можно запустить исполняемый файл или контейнер, чтобы установить соединение.",
"sitesBannerButtonText": "Установить сайт",
"approvalsBannerTitle": "Одобрить или запретить доступ к устройству",
"approvalsBannerDescription": "Просмотрите и подтвердите или отклоните запросы на доступ к устройству от пользователей. Когда требуется подтверждение устройства, пользователи должны получить одобрение администратора, прежде чем их устройства смогут подключиться к ресурсам вашей организации.",
@@ -163,7 +163,7 @@
"proxyResourceTitle": "Управление публичными ресурсами",
"proxyResourceDescription": "Создание и управление ресурсами, которые доступны через веб-браузер",
"proxyResourcesBannerTitle": "Общедоступный доступ через веб",
"proxyResourcesBannerDescription": "Общедоступные ресурсы это прокси-по HTTPS или TCP/UDP, доступные любому пользователю в Интернете через веб-браузер. В отличие от частных ресурсов, они не требуют программного обеспечения на стороне клиента и могут включать политики доступа на основе идентификации и контекста.",
"proxyResourcesBannerDescription": "Общедоступные ресурсы - это прокси-по HTTPS или TCP/UDP, доступные любому пользователю в Интернете через веб-браузер. В отличие от частных ресурсов, они не требуют программного обеспечения на стороне клиента и могут включать политики доступа на основе идентификации и контекста.",
"clientResourceTitle": "Управление приватными ресурсами",
"clientResourceDescription": "Создание и управление ресурсами, которые доступны только через подключенный клиент",
"privateResourcesBannerTitle": "Частный доступ с нулевым доверием",
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Ключ подготовки обновлен",
"provisioningKeysUpdatedDescription": "Ваши изменения были сохранены.",
"provisioningKeysBannerTitle": "Ключи подготовки сайта",
"provisioningKeysBannerDescription": "Генерировать подготовительный ключ и использовать его вместе с Новым коннектором для автоматического создания сайтов при первом запуске нет необходимости настраивать отдельные учетные данные для каждого сайта.",
"provisioningKeysBannerDescription": "Создайте ключ настройки и используйте его с соединителем Newt для автоматического создания сайтов при первом запуске - нет необходимости настраивать отдельные учетные данные для каждого сайта.",
"provisioningKeysBannerButtonText": "Узнать больше",
"pendingSitesBannerTitle": "Ожидающие сайты",
"pendingSitesBannerDescription": "Сайты, связанные с использованием ключа подготовки, появляются здесь для проверки. Одобрите каждый сайт, прежде чем он станет активным и получит доступ к вашим ресурсам.",
"pendingSitesBannerDescription": "Сайты, подключающиеся с помощью ключа настройки, отображаются здесь для проверки.",
"pendingSitesBannerButtonText": "Узнать больше",
"apiKeysSettings": "Настройки {apiKeyName}",
"userTitle": "Управление всеми пользователями",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Не удалось активировать лицензионный ключ",
"licenseErrorKeyActivateDescription": "Произошла ошибка при активации лицензионного ключа.",
"licenseAbout": "О лицензировании",
"licenseBannerTitle": "Активируйте вашу корпоративную лицензию",
"licenseBannerDescription": "Откройте доступ к корпоративным функциям для вашей локально размещаемой версии Pangolin. Приобретите лицензионный ключ, чтобы активировать премиум-функции, затем добавьте его ниже.",
"licenseBannerGetLicense": "Получить лицензию",
"licenseBannerViewDocs": "Посмотреть документацию",
"communityEdition": "Community Edition",
"licenseAboutDescription": "Это для бизнес и корпоративных пользователей, использующих Pangolin в коммерческой среде. Если вы используете Pangolin для личного использования, вы можете игнорировать этот раздел.",
"licenseKeyActivated": "Лицензионный ключ активирован",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Пожалуйста, введите правильный номер порта",
"targetErrorNoSite": "Сайт не выбран",
"targetErrorNoSiteDescription": "Пожалуйста, выберите сайт для цели",
"targetTargetsCleared": "Цели очищены",
"targetTargetsClearedDescription": "Все цели удалены из этого ресурса",
"targetCreated": "Цель создана",
"targetCreatedDescription": "Цель была успешно создана",
"targetErrorCreate": "Не удалось создать цель",
@@ -892,6 +898,7 @@
"idpDisplayName": "Отображаемое имя для этого поставщика удостоверений",
"idpAutoProvisionUsers": "Автоматическое создание пользователей",
"idpAutoProvisionUsersDescription": "При включении пользователи будут автоматически создаваться в системе при первом входе с возможностью сопоставления пользователей с ролями и организациями.",
"idpAutoProvisionConfigureAfterCreate": "Вы можете настроить параметры автоматического обеспечения после создания поставщика удостоверений.",
"licenseBadge": "EE",
"idpType": "Тип поставщика",
"idpTypeDescription": "Выберите тип поставщика удостоверений, который вы хотите настроить",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Сопоставление ролей по умолчанию",
"defaultMappingsRoleDescription": "Результат этого выражения должен возвращать имя роли, как определено в организации, в виде строки.",
"defaultMappingsOrg": "Сопоставление организаций по умолчанию",
"defaultMappingsOrgDescription": "Это выражение должно возвращать ID организации или true для разрешения доступа пользователя к организации.",
"defaultMappingsOrgDescription": "При установке это выражение должно возвращать ID организации или true, чтобы пользователь мог получить доступ к этой организации. При отсутствии настройка отображения роли достаточно: пользователю разрешено войти, пока для него может быть решено отображение гарантированной роли в организации.",
"defaultMappingsSubmit": "Сохранить сопоставления по умолчанию",
"orgPoliciesEdit": "Редактировать политику организации",
"org": "Организация",
@@ -1987,7 +1994,7 @@
"description": "Более надежный и низко обслуживаемый сервер Pangolin с дополнительными колокольнями и свистками",
"introTitle": "Управляемый Само-Хост Панголина",
"introDescription": "- это вариант развертывания, предназначенный для людей, которые хотят простоты и надёжности, сохраняя при этом свои данные конфиденциальными и самостоятельными.",
"introDetail": "С помощью этой опции вы по-прежнему используете узел Pangolin туннели, SSL, и весь остающийся на вашем сервере. Разница заключается в том, что управление и мониторинг осуществляются через нашу панель инструментов из облака, которая открывает ряд преимуществ:",
"introDetail": "С помощью этой опции вы по-прежнему используете узел Pangolin - туннели, SSL, и весь остающийся на вашем сервере. Разница заключается в том, что управление и мониторинг осуществляются через нашу панель инструментов из облака, которая открывает ряд преимуществ:",
"benefitSimplerOperations": {
"title": "Более простые операции",
"description": "Не нужно запускать свой собственный почтовый сервер или настроить комплексное оповещение. Вы будете получать проверки состояния здоровья и оповещения о неисправностях из коробки."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Обнаружен международный домен",
"willbestoredas": "Будет храниться как:",
"roleMappingDescription": "Определите, как роли, назначаемые пользователям, когда они войдут в систему автоматического профиля.",
"roleMappingDescription": "Определите, как роли присваиваются пользователям при входе с этим поставщиком удостоверений.",
"selectRole": "Выберите роль",
"roleMappingExpression": "Выражение",
"selectRolePlaceholder": "Выберите роль",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Выберите домен для страницы аутентификации организации",
"domainPickerProvidedDomain": "Домен предоставлен",
"domainPickerFreeProvidedDomain": "Бесплатный домен",
"domainPickerFreeDomainsPaidFeature": "Предоставленные домены являются платной функцией. Подпишитесь, чтобы получить домен, включенный в ваш план - не нужно приносить свой собственный.",
"domainPickerVerified": "Подтверждено",
"domainPickerUnverified": "Не подтверждено",
"domainPickerManual": "Ручной",
"domainPickerInvalidSubdomainStructure": "Этот поддомен содержит недопустимые символы или структуру. Он будет очищен автоматически при сохранении.",
"domainPickerError": "Ошибка",
"domainPickerErrorLoadDomains": "Не удалось загрузить домены организации",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Раскрытие",
"description": "Выберите уровень лицензии, который точно отражает ваше предполагаемое использование. Личная Лицензия разрешает свободное использование Программного Обеспечения для частной, некоммерческой или малой коммерческой деятельности с годовым валовым доходом до $100 000 USD. Любое использование сверх этих пределов включая использование в бизнесе, организацию, или другой приносящей доход среде требует действительной лицензии предприятия и уплаты соответствующей лицензионной платы. Все пользователи, будь то Личные или Предприятия, обязаны соблюдать условия коммерческой лицензии Fossoral."
"description": "Выберите уровень лицензии, который точно отражает ваше предполагаемое использование. Личная Лицензия разрешает свободное использование Программного Обеспечения для частной, некоммерческой или малой коммерческой деятельности с годовым валовым доходом до $100 000 USD. Любое использование сверх этих пределов - включая использование в бизнесе, организацию, или другой приносящей доход среде - требует действительной лицензии предприятия и уплаты соответствующей лицензионной платы. Все пользователи, будь то Личные или Предприятия, обязаны соблюдать условия коммерческой лицензии Fossoral."
},
"trialPeriodInformation": {
"title": "Информация о пробном периоде",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Масштаб",
"description": "Функции предприятия, 50 пользователей, 50 сайтов, а также приоритетная поддержка."
"description": "Функции корпоративного уровня, 50 пользователей, 100 сайтов и приоритетная поддержка."
}
},
"personalUseOnly": "Только для личного пользования (бесплатная лицензия без оформления)",
"personalUseOnly": "Только для личного использования (бесплатная лицензия - без оформления на кассе)",
"buttons": {
"continueToCheckout": "Продолжить оформление заказа"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Машинные клиенты",
"install": "Установить",
"run": "Запустить",
"envFile": "Файл окружения",
"serviceFile": "Сервисный файл",
"enableAndStart": "Включить и запустить",
"clientNameDescription": "Отображаемое имя клиента, которое может быть изменено позже.",
"clientAddress": "Адрес клиента (Дополнительно)",
"setupFailedToFetchSubnet": "Не удалось получить подсеть по умолчанию",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Нет аутентификации",
"httpDestAuthNoneDescription": "Отправляет запросы без заголовка авторизации.",
"httpDestAuthBearerTitle": "Жетон носителя",
"httpDestAuthBearerDescription": "Добавляет заголовок Authorization: Bearer <token> к каждому запросу.",
"httpDestAuthBearerDescription": "Добавляет заголовок Authorization: Bearer '<token>' к каждому запросу.",
"httpDestAuthBearerPlaceholder": "Ваш ключ API или токен",
"httpDestAuthBasicTitle": "Базовая авторизация",
"httpDestAuthBasicDescription": "Добавляет Authorization: Basic <credentials> header. Предоставьте учетные данные в качестве имени пользователя:password.",
"httpDestAuthBasicDescription": "Добавляет заголовок Authorization: Basic '<credentials>'. Укажите учетные данные в формате username:password.",
"httpDestAuthBasicPlaceholder": "имя пользователя:пароль",
"httpDestAuthCustomTitle": "Пользовательский заголовок",
"httpDestAuthCustomDescription": "Укажите пользовательское имя заголовка HTTP и значение для аутентификации (например, X-API-Key).",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Адрес назначения успешно обновлен",
"httpDestCreatedSuccess": "Адрес назначения успешно создан",
"httpDestUpdateFailed": "Не удалось обновить место назначения",
"httpDestCreateFailed": "Не удалось создать место назначения"
"httpDestCreateFailed": "Не удалось создать место назначения",
"idpAddActionCreateNew": "Создать нового поставщика удостоверений",
"idpAddActionImportFromOrg": "Импортировать из другой организации",
"idpImportDialogTitle": "Импортировать поставщика удостоверений",
"idpImportDialogDescription": "Выберите поставщика удостоверений из организации, где вы являетесь администратором. Он будет связан с этой организацией.",
"idpImportSearchPlaceholder": "Поиск по организации или имени поставщика...",
"idpImportEmpty": "Поставщики удостоверений не найдены.",
"idpImportedDescription": "Поставщик удостоверений успешно импортирован.",
"idpDeleteGlobalQuestion": "Вы уверены, что хотите навсегда удалить этого поставщика удостоверений?",
"idpDeleteGlobalDescription": "Это навсегда удалит поставщика удостоверений из всех организаций, с которыми он связан.",
"idpUnassociateTitle": "Рассоединить провайдера удостоверений",
"idpUnassociateQuestion": "Вы уверены, что хотите рассоединить этого поставщика удостоверений с этой организацией?",
"idpUnassociateDescription": "Все пользователи, связанные с этим поставщиком удостоверений, будут удалены из этой организации, но поставщик удостоверений будет продолжать существовать для других связанных организаций.",
"idpUnassociateConfirm": "Подтвердите рассоединение поставщика удостоверений",
"idpUnassociateWarning": "Это не может быть отменено для этой организации.",
"idpUnassociatedDescription": "Поставщик удостоверений успешно рассоединен с этой организацией",
"idpUnassociateMenu": "Рассоединить",
"idpDeleteAllOrgsMenu": "Удалить"
}
+40 -11
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "Tedarik anahtarı güncellendi",
"provisioningKeysUpdatedDescription": "Değişiklikleriniz kaydedildi.",
"provisioningKeysBannerTitle": "Site Tedarik Anahtarları",
"provisioningKeysBannerDescription": "Tedarik anahtarı oluşturun ve ilk başlangıçta siteleri otomatik olarak oluşturmak için Newt konektörüyle kullanın her site için ayrı kimlik bilgileri ayarlamaya gerek yoktur.",
"provisioningKeysBannerDescription": "Bir sağlama anahtarı oluşturun ve ilk başlangıçta siteleri otomatik olarak oluşturmak için Newt bağlayıcısını kullanın - her site için ayrı kimlik bilgileri ayarlamaya gerek yok.",
"provisioningKeysBannerButtonText": "Daha fazla bilgi",
"pendingSitesBannerTitle": "Bekleyen Siteler",
"pendingSitesBannerDescription": "Tedarik anahtarı kullanarak bağlanan siteler burada incelenmek için görünür. Aktif hale gelmeden ve kaynaklarınıza erişim kazanmadan önce her siteyi onaylayın.",
"pendingSitesBannerDescription": "Bir sağlama anahtarı kullanarak bağlanan siteler, inceleme için burada görünür.",
"pendingSitesBannerButtonText": "Daha fazla bilgi",
"apiKeysSettings": "{apiKeyName} Ayarları",
"userTitle": "Tüm Kullanıcıları Yönet",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "Lisans anahtarı etkinleştirilemedi",
"licenseErrorKeyActivateDescription": "Lisans anahtarı etkinleştirilirken bir hata oluştu.",
"licenseAbout": "Lisans Hakkında",
"licenseBannerTitle": "Kurumsal Lisansınızı Etkinleştirin",
"licenseBannerDescription": "Kendi barındırdığınız Pangolin örneğiniz için kurumsal özelliklerin kilidini açın. Premium yetenekleri etkinleştirmek için bir lisans anahtarı satın alın, ardından aşağıya ekleyin.",
"licenseBannerGetLicense": "Lisans Alın",
"licenseBannerViewDocs": "Dokümantasyonu Görüntüleyin",
"communityEdition": "Topluluk Sürümü",
"licenseAboutDescription": "Bu, Pangolin'i ticari bir ortamda kullanan işletme ve kurumsal kullanıcılar içindir. Pangolin'i kişisel kullanım için kullanıyorsanız, bu bölümü görmezden gelebilirsiniz.",
"licenseKeyActivated": "Lisans anahtarı etkinleştirildi",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "Lütfen geçerli bir port numarası girin",
"targetErrorNoSite": "Hiçbir site seçili değil",
"targetErrorNoSiteDescription": "Lütfen hedef için bir site seçin",
"targetTargetsCleared": "Hedefler temizlendi",
"targetTargetsClearedDescription": "Bu kaynaktan tüm hedefler kaldırıldı",
"targetCreated": "Hedef oluşturuldu",
"targetCreatedDescription": "Hedef başarıyla oluşturuldu",
"targetErrorCreate": "Hedef oluşturma başarısız oldu",
@@ -892,6 +898,7 @@
"idpDisplayName": "Bu kimlik sağlayıcı için bir görüntü adı",
"idpAutoProvisionUsers": "Kullanıcıları Otomatik Sağla",
"idpAutoProvisionUsersDescription": "Etkinleştirildiğinde, kullanıcılar rol ve organizasyonlara eşleme yeteneğiyle birlikte sistemde otomatik olarak oluşturulacak.",
"idpAutoProvisionConfigureAfterCreate": "Kimlik sağlayıcı oluşturulduktan sonra otomatik sağlama ayarlarını yapılandırabilirsiniz.",
"licenseBadge": " ",
"idpType": "Sağlayıcı Türü",
"idpTypeDescription": "Yapılandırmak istediğiniz kimlik sağlayıcısı türünü seçin",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "Varsayılan Rol Eşleme",
"defaultMappingsRoleDescription": "JMESPath to extract role information from the ID token. The result of this expression must return the role name as defined in the organization as a string.",
"defaultMappingsOrg": "Varsayılan Kuruluş Eşleme",
"defaultMappingsOrgDescription": "JMESPath to extract organization information from the ID token. This expression must return the org ID or true for the user to be allowed to access the organization.",
"defaultMappingsOrgDescription": "Ayarladığınızda, bu ifade kullanıcının o kuruluşa erişmesi için kuruluş kimliğini veya doğru değerini döndürmelidir. Ayarlamadığınızda, rol eşleme tanımlamak yeterlidir: kullanıcı, kuruluş içinde onlar için geçerli bir rol eşlemesi çözümlenebildiği sürece erişime izin verilir.",
"defaultMappingsSubmit": "Varsayılan Eşlemeleri Kaydet",
"orgPoliciesEdit": "Kuruluş Politikasını Düzenle",
"org": "Kuruluş",
@@ -1987,7 +1994,7 @@
"description": "Daha güvenilir ve düşük bakım gerektiren, ekstra özelliklere sahip kendi kendine barındırabileceğiniz Pangolin sunucusu",
"introTitle": "Yönetilen Kendi Kendine Barındırılan Pangolin",
"introDescription": "Bu, basitlik ve ekstra güvenilirlik arayan, ancak verilerini gizli tutmak ve kendi sunucularında barındırmak isteyen kişiler için tasarlanmış bir dağıtım seçeneğidir.",
"introDetail": "Bu seçenekle, kendi Pangolin düğümünüzü çalıştırmaya devam edersiniz tünelleriniz, SSL bitişiniz ve trafiğiniz tamamen sunucunuzda kalır. Fark, yönetim ve izlemeyi bulut panomuz üzerinden gerçekleştiririz, bu da bir dizi avantaj sağlar:",
"introDetail": "Bu seçenekle, kendi Pangolin düğümünüzü çalıştırmaya devam edersiniz - tünelleriniz, SSL bitişiniz ve trafiğiniz tamamen sunucunuzda kalır. Fark, yönetim ve izlemeyi bulut panomuz üzerinden gerçekleştiririz, bu da bir dizi avantaj sağlar:",
"benefitSimplerOperations": {
"title": "Daha basit işlemler",
"description": "Kendi e-posta sunucunuzu çalıştırmanıza veya karmaşık uyarılar kurmanıza gerek yok. Sağlık kontrolleri ve kesinti uyarılarını kutudan çıktığı gibi alırsınız."
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "Uluslararası Alan Adı Tespit Edildi",
"willbestoredas": "Şu şekilde depolanacak:",
"roleMappingDescription": "Otomatik Sağlama etkinleştirildiğinde kullanıcıların oturum açarken rollerin nasıl atandığını belirleyin.",
"roleMappingDescription": "Bu kimlik sağlayıcı ile oturum açıldığında kullanıcılara rollerin nasıl atandığını belirleyin.",
"selectRole": "Bir Rol Seçin",
"roleMappingExpression": "İfade",
"selectRolePlaceholder": "Bir rol seçin",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "Kuruluşun kimlik doğrulama sayfası için bir alan seçin",
"domainPickerProvidedDomain": "Sağlanan Alan Adı",
"domainPickerFreeProvidedDomain": "Ücretsiz Sağlanan Alan Adı",
"domainPickerFreeDomainsPaidFeature": "Sağlanan alan adları ücretli bir özelliktir. Planınıza dahil bir alan adı almak için abone olun - kendi alan adınızı getirmenize gerek yok.",
"domainPickerVerified": "Doğrulandı",
"domainPickerUnverified": "Doğrulanmadı",
"domainPickerManual": "Manuel",
"domainPickerInvalidSubdomainStructure": "Bu alt alan adı geçersiz karakterler veya yapı içeriyor. Kaydettiğinizde otomatik olarak temizlenecektir.",
"domainPickerError": "Hata",
"domainPickerErrorLoadDomains": "Organizasyon alan adları yüklenemedi",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "Kullanım Açıklaması",
"description": "Kullanım amacınızı doğru bir şekilde yansıtan lisans seviyesini seçin. Kişisel Lisans, yazılımın bireysel, ticari olmayan veya yıllık geliri 100,000 ABD Dolarının altında olan küçük ölçekli ticari faaliyetlerde ücretsiz kullanılmasına izin verir. Bu sınırların ötesinde kullanım bir işletme, organizasyon veya diğer gelir getirici ortamlarda kullanım dahil olmak üzere geçerli bir Kurumsal Lisans ve ilgili lisans ücretinin ödenmesini gerektirir. Tüm kullanıcılar, ister Kişisel ister Kurumsal, Fossorial Ticari Lisans Şartlarına uymalıdır."
"description": "Kullanım amacınızı doğru bir şekilde yansıtan lisans seviyesini seçin. Kişisel Lisans, yazılımın bireysel, ticari olmayan veya yıllık geliri 100,000 ABD Dolarının altında olan küçük ölçekli ticari faaliyetlerde ücretsiz kullanılmasına izin verir. Bu sınırların ötesinde kullanım - bir işletme, organizasyon veya diğer gelir getirici ortamlarda kullanım dahil olmak üzere - geçerli bir Kurumsal Lisans ve ilgili lisans ücretinin ödenmesini gerektirir. Tüm kullanıcılar, ister Kişisel ister Kurumsal, Fossorial Ticari Lisans Şartlarına uymalıdır."
},
"trialPeriodInformation": {
"title": "Deneme Süresi Bilgileri",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "Ölçek",
"description": "Kurumsal özellikler, 50 kullanıcı, 50 site ve öncelikli destek."
"description": "Kurumsal özellikler, 50 kullanıcı, 100 site ve öncelikli destek."
}
},
"personalUseOnly": "Yalnızca kişisel kullanım (ücretsiz lisans ödeme yapılmaz)",
"personalUseOnly": "Kişisel kullanım için (ücretsiz lisans - ödeme yok)",
"buttons": {
"continueToCheckout": "Ödemeye Devam Et"
},
@@ -2607,6 +2616,9 @@
"machineClients": "Makine İstemcileri",
"install": "Yükle",
"run": "Çalıştır",
"envFile": "Ortam Dosyası",
"serviceFile": "Servis Dosyası",
"enableAndStart": "Etkinleştir ve Başlat",
"clientNameDescription": "Daha sonra değiştirilebilecek istemcinin görünen adı.",
"clientAddress": "İstemci Adresi (Gelişmiş)",
"setupFailedToFetchSubnet": "Varsayılan alt ağ alınamadı",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "Kimlik Doğrulama Yok",
"httpDestAuthNoneDescription": "Yetkilendirme başlığı olmadan istekler gönderir.",
"httpDestAuthBearerTitle": "Taşıyıcı Jetonu",
"httpDestAuthBearerDescription": "Her isteğe bir Yetkilendirme: Taşıyıcı <token> başlığı ekler.",
"httpDestAuthBearerDescription": "Her isteğe bir Yetkilendirme: Taşıyıcı '<token>' üst bilgisi ekler.",
"httpDestAuthBearerPlaceholder": "API anahtarınız veya jetonunuz",
"httpDestAuthBasicTitle": "Temel Kimlik Doğrulama",
"httpDestAuthBasicDescription": "Authorization: Temel <belirtecikler> başlığı ekler. Yetkilendirmeleri kullanıcı adı:şifre olarak sağlayın.",
"httpDestAuthBasicDescription": "Bir Yetkilendirme: Temel '<credentials>' üst bilgisi ekler. Kimlik bilgilerini kullanıcı adı:şifre olarak sağlayın.",
"httpDestAuthBasicPlaceholder": "kullanıcı adı:şifre",
"httpDestAuthCustomTitle": "Özel Başlık",
"httpDestAuthCustomDescription": "Kimlik doğrulama için özel bir HTTP başlık adı ve değer belirtin (örn. X-API-Key).",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "Hedef başarıyla güncellendi",
"httpDestCreatedSuccess": "Hedef başarıyla oluşturuldu",
"httpDestUpdateFailed": "Hedef güncellenemedi",
"httpDestCreateFailed": "Hedef oluşturulamadı"
"httpDestCreateFailed": "Hedef oluşturulamadı",
"idpAddActionCreateNew": "Yeni kimlik sağlayıcı oluştur",
"idpAddActionImportFromOrg": "Başka bir kuruluştan içe aktar",
"idpImportDialogTitle": "Kimlik Sağlayıcı İçe Aktar",
"idpImportDialogDescription": "Bir kuruluştan yönetici olduğunuz bir kimlik sağlayıcı seçin. Bu kuruluşla ilişkilendirilecektir.",
"idpImportSearchPlaceholder": "Kuruluş veya sağlayıcı adına göre ara...",
"idpImportEmpty": "Hiçbir kimlik sağlayıcı bulunamadı.",
"idpImportedDescription": "Kimlik sağlayıcı başarıyla içe aktarıldı.",
"idpDeleteGlobalQuestion": "Bu kimlik sağlayıcıyı kalıcı olarak silmek istediğinizden emin misiniz?",
"idpDeleteGlobalDescription": "Bu, kimlik sağlayıcıyı ilişkilendirildiği tüm kuruluşlardan kalıcı olarak silecektir.",
"idpUnassociateTitle": "Kimlik Sağlayıcının İlişkisini Kes",
"idpUnassociateQuestion": "Bu kimlik sağlayıcının bu kuruluştan ilişiğini kesmek istediğinizden emin misiniz?",
"idpUnassociateDescription": "Bu kimlik sağlayıcı ile ilişkilendirilen tüm kullanıcılar bu kuruluştan kaldırılacaktır, ancak kimlik sağlayıcı diğer ilişkilendirilen kuruluşlar için var olmaya devam edecektir.",
"idpUnassociateConfirm": "Kimlik Sağlayıcının İlişkisinin Kesilmesini Onayla",
"idpUnassociateWarning": "Bu işlem bu kuruluş için geri alınamaz.",
"idpUnassociatedDescription": "Kimlik sağlayıcı bu kuruluştan başarıyla ayrıldı",
"idpUnassociateMenu": "İlişkiyi Kes",
"idpDeleteAllOrgsMenu": "Sil"
}
+41 -12
View File
@@ -371,10 +371,10 @@
"provisioningKeysUpdated": "置备密钥已更新",
"provisioningKeysUpdatedDescription": "您的更改已保存。",
"provisioningKeysBannerTitle": "站点置备密钥",
"provisioningKeysBannerDescription": "生成一个预配键并使用它来在首次启动时自动创建站点——无需为每个站点设置单独的凭。",
"provisioningKeysBannerDescription": "生成一个供应密钥,并将其与 Newt 连接器一起使用,以在首次启动时自动创建站点 - 无需为每个站点设置单独的凭。",
"provisioningKeysBannerButtonText": "了解更多",
"pendingSitesBannerTitle": "待定站点",
"pendingSitesBannerDescription": "使用预配键连接的站点会出现在这里供审核。在站点开始运行之前批准并获取对您资源的访问权限。",
"pendingSitesBannerDescription": "使用供应密钥连接的站点将在此显示以供审核。",
"pendingSitesBannerButtonText": "了解更多",
"apiKeysSettings": "{apiKeyName} 设置",
"userTitle": "管理所有用户",
@@ -405,6 +405,10 @@
"licenseErrorKeyActivate": "激活许可证密钥失败",
"licenseErrorKeyActivateDescription": "激活许可证密钥时出错。",
"licenseAbout": "关于许可协议",
"licenseBannerTitle": "启用您的企业许可证",
"licenseBannerDescription": "为您自行托管的Pangolin实例解锁企业功能。购买许可证密钥以激活高级功能,然后在下方添加。",
"licenseBannerGetLicense": "获取许可证",
"licenseBannerViewDocs": "查看文档",
"communityEdition": "社区版",
"licenseAboutDescription": "这是针对商业环境中使用Pangolin的商业和企业用户。 如果您正在使用 Pangolin 供个人使用,您可以忽略此部分。",
"licenseKeyActivated": "授权密钥已激活",
@@ -624,6 +628,8 @@
"targetErrorInvalidPortDescription": "请输入有效的端口号",
"targetErrorNoSite": "没有选择站点",
"targetErrorNoSiteDescription": "请选择目标站点",
"targetTargetsCleared": "目标已清除",
"targetTargetsClearedDescription": "所有目标已从此资源中移除",
"targetCreated": "目标已创建",
"targetCreatedDescription": "目标已成功创建",
"targetErrorCreate": "创建目标失败",
@@ -892,6 +898,7 @@
"idpDisplayName": "此身份提供商的显示名称",
"idpAutoProvisionUsers": "自动提供用户",
"idpAutoProvisionUsersDescription": "如果启用,用户将在首次登录时自动在系统中创建,并且能够映射用户到角色和组织。",
"idpAutoProvisionConfigureAfterCreate": "您可以在创建身份提供者后配置自动配置设置。",
"licenseBadge": "EE",
"idpType": "提供者类型",
"idpTypeDescription": "选择您想要配置的身份提供者类型",
@@ -943,7 +950,7 @@
"defaultMappingsRole": "默认角色映射",
"defaultMappingsRoleDescription": "此表达式的结果必须返回组织中定义的角色名称作为字符串。",
"defaultMappingsOrg": "默认组织映射",
"defaultMappingsOrgDescription": "此表达式必须返回 组织IDtrue 才能允许用户访问组织。",
"defaultMappingsOrgDescription": "设置时,此表达式必须返回组织IDtrue才能用户访问组织。如果未设置,定义角色映射就足够了:只要在组织内可以为用户找出有效角色映射,用户就被允许进入。",
"defaultMappingsSubmit": "保存默认映射",
"orgPoliciesEdit": "编辑组织策略",
"org": "组织",
@@ -1987,7 +1994,7 @@
"description": "更可靠和低维护自我托管的 Pangolin 服务器,带有额外的铃声和告密器",
"introTitle": "托管自托管的潘戈林公司",
"introDescription": "这是一种部署选择,为那些希望简洁和额外可靠的人设计,同时仍然保持他们的数据的私密性和自我托管性。",
"introDetail": "通过此选项,您仍然运行您自己的 Pangolin 节点 — — 您的隧道、SSL 终止,并且流量在您的服务器上保持所有状态。 不同之处在于,管理和监测是通过我们的云层仪表板进行的,该仪表板开启了一些好处:",
"introDetail": "通过此选项,您仍然运行您自己的 Pangolin 节点 - - 您的隧道、SSL 终止,并且流量在您的服务器上保持所有状态。 不同之处在于,管理和监测是通过我们的云层仪表板进行的,该仪表板开启了一些好处:",
"benefitSimplerOperations": {
"title": "简单的操作",
"description": "无需运行您自己的邮件服务器或设置复杂的警报。您将从方框中获得健康检查和下限提醒。"
@@ -2020,7 +2027,7 @@
},
"internationaldomaindetected": "检测到国际域",
"willbestoredas": "储存为:",
"roleMappingDescription": "确定当用户启用自动配送时如何分配他们的角色。",
"roleMappingDescription": "确定当用户使用此身份提供者登陆时如何分配角色。",
"selectRole": "选择角色",
"roleMappingExpression": "表达式",
"selectRolePlaceholder": "选择角色",
@@ -2112,8 +2119,10 @@
"selectDomainForOrgAuthPage": "选择组织认证页面的域",
"domainPickerProvidedDomain": "提供的域",
"domainPickerFreeProvidedDomain": "免费提供的域",
"domainPickerFreeDomainsPaidFeature": "提供的域名是付费功能。订阅即可将域名包含在您的计划中-无需自带域名。",
"domainPickerVerified": "已验证",
"domainPickerUnverified": "未验证",
"domainPickerManual": "手动",
"domainPickerInvalidSubdomainStructure": "此子域包含无效的字符或结构。当您保存时,它将被自动清除。",
"domainPickerError": "错误",
"domainPickerErrorLoadDomains": "加载组织域名失败",
@@ -2288,7 +2297,7 @@
"alerts": {
"commercialUseDisclosure": {
"title": "使用情况披露",
"description": "选择能准确反映您预定用途的许可等级。 个人许可证允许对个人、非商业性或小型商业活动免费使用软件,年收入毛额不到100 000美元。 超出这些限度的任何用途,包括在企业、组织内的用途。 或其他创收环境——需要有效的企业许可证和支付适用的许可证费用。 所有用户,不论是个人还是企业,都必须遵守寄养商业许可证条款。"
"description": "选择能准确反映您预定用途的许可等级。 个人许可证允许对个人、非商业性或小型商业活动免费使用软件,年收入毛额不到100 000美元。 超出这些限度的任何用途,包括在企业、组织内的用途。 或其他创收环境--需要有效的企业许可证和支付适用的许可证费用。 所有用户,不论是个人还是企业,都必须遵守寄养商业许可证条款。"
},
"trialPeriodInformation": {
"title": "试用期信息",
@@ -2343,10 +2352,10 @@
},
"scale": {
"title": "缩放比例",
"description": "企业特征、50个用户、50个站点优先支持。"
"description": "企业功能,50个用户100个站点,以及优先支持。"
}
},
"personalUseOnly": "仅个人使用 (免费许可证-无签出)",
"personalUseOnly": "仅个人使用免费许可 - 无需结账)",
"buttons": {
"continueToCheckout": "继续签出"
},
@@ -2607,6 +2616,9 @@
"machineClients": "机器客户端",
"install": "安装",
"run": "运行",
"envFile": "环境文件",
"serviceFile": "服务文件",
"enableAndStart": "启用并启动",
"clientNameDescription": "可以稍后更改的客户端的显示名称。",
"clientAddress": "客户端地址 (高级)",
"setupFailedToFetchSubnet": "获取默认子网失败",
@@ -2845,10 +2857,10 @@
"httpDestAuthNoneTitle": "无身份验证",
"httpDestAuthNoneDescription": "在没有授权头的情况下发送请求。",
"httpDestAuthBearerTitle": "持有者令牌",
"httpDestAuthBearerDescription": "添加授权:每个请求的标题为 <token>。",
"httpDestAuthBearerDescription": "在每个请求中添加授权:Bearer “<token>” 头。",
"httpDestAuthBearerPlaceholder": "您的 API 密钥或令牌",
"httpDestAuthBasicTitle": "基本认证",
"httpDestAuthBasicDescription": "添加授权:基本 <credentials> 头。提供用户名:密码凭据。",
"httpDestAuthBasicDescription": "添加一个Authorization: Basic \"<凭据>\" 标头。 以用户名:密码形式提供凭据。",
"httpDestAuthBasicPlaceholder": "用户名:密码",
"httpDestAuthCustomTitle": "自定义标题",
"httpDestAuthCustomDescription": "指定自定义 HTTP 头名称和身份验证值 (例如,X-API 键)。",
@@ -2870,7 +2882,7 @@
"httpDestFormatJsonArrayTitle": "JSON 数组",
"httpDestFormatJsonArrayDescription": "每批一个请求,实体是一个 JSON 数组。与大多数通用的 Web 钩子和数据兼容。",
"httpDestFormatNdjsonTitle": "NDJSON",
"httpDestFormatNdjsonDescription": "每批有一个请求,物体是换行符限制的 JSON ——每行一个对象,不是外部数组。 Sluk HEC、Elastic / OpenSearch和Grafana Loki所需。",
"httpDestFormatNdjsonDescription": "每批有一个请求,物体是换行符限制的 JSON --每行一个对象,不是外部数组。 Sluk HEC、Elastic / OpenSearch和Grafana Loki所需。",
"httpDestFormatSingleTitle": "每个请求一个事件",
"httpDestFormatSingleDescription": "为每个事件单独发送一个 HTTP POST。仅用于无法处理批量的端点。",
"httpDestLogTypesTitle": "日志类型",
@@ -2888,5 +2900,22 @@
"httpDestUpdatedSuccess": "目标已成功更新",
"httpDestCreatedSuccess": "目标创建成功",
"httpDestUpdateFailed": "更新目标失败",
"httpDestCreateFailed": "创建目标失败"
"httpDestCreateFailed": "创建目标失败",
"idpAddActionCreateNew": "创建新的身份提供者",
"idpAddActionImportFromOrg": "从另一个组织导入",
"idpImportDialogTitle": "导入身份提供者",
"idpImportDialogDescription": "从您是管理员的组织中选择一个身份提供者。它将关联到本组织。",
"idpImportSearchPlaceholder": "按组织或提供者名称搜索……",
"idpImportEmpty": "未找到身份提供者。",
"idpImportedDescription": "身份提供者已成功导入。",
"idpDeleteGlobalQuestion": "您确定要永久删除此身份提供者吗?",
"idpDeleteGlobalDescription": "这将永久删除与其关联的所有组织中的身份提供者。",
"idpUnassociateTitle": "取消关联身份提供者",
"idpUnassociateQuestion": "您确定要将此身份提供者从此组织中取消关联吗?",
"idpUnassociateDescription": "与此身份提供者关联的所有用户将从该组织中移除,但身份提供者仍会继续存在于关联的其他组织中。",
"idpUnassociateConfirm": "确认取消关联身份提供者",
"idpUnassociateWarning": "此操作无法对该组织撤销。",
"idpUnassociatedDescription": "身份提供者已成功从该组织中取消关联",
"idpUnassociateMenu": "取消关联",
"idpDeleteAllOrgsMenu": "删除"
}
+2397 -2393
View File
File diff suppressed because it is too large Load Diff
+123 -13
View File
@@ -44,6 +44,7 @@
"@tailwindcss/forms": "0.5.11",
"@tanstack/react-query": "5.90.21",
"@tanstack/react-table": "8.21.3",
"@xyflow/react": "^12.8.4",
"arctic": "3.7.0",
"axios": "1.13.5",
"better-sqlite3": "11.9.1",
@@ -89,13 +90,13 @@
"reodotdev": "1.1.0",
"resend": "6.9.2",
"semver": "7.7.4",
"sshpk": "^1.18.0",
"sshpk": "1.18.0",
"stripe": "20.4.1",
"swagger-ui-express": "5.0.1",
"tailwind-merge": "3.5.0",
"topojson-client": "3.1.0",
"tw-animate-css": "1.4.0",
"use-debounce": "^10.1.0",
"use-debounce": "10.1.0",
"uuid": "13.0.0",
"vaul": "1.1.2",
"visionscarto-world-atlas": "1.0.0",
@@ -130,7 +131,7 @@
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@types/semver": "7.7.1",
"@types/sshpk": "^1.17.4",
"@types/sshpk": "1.17.4",
"@types/swagger-ui-express": "4.1.8",
"@types/topojson-client": "3.1.5",
"@types/ws": "8.18.1",
@@ -1058,6 +1059,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -2353,6 +2355,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2375,6 +2378,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2397,6 +2401,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2413,6 +2418,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2429,6 +2435,7 @@
"cpu": [
"arm"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2445,6 +2452,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2461,6 +2469,7 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2477,6 +2486,7 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2493,6 +2503,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2509,6 +2520,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2525,6 +2537,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2541,6 +2554,7 @@
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2563,6 +2577,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2585,6 +2600,7 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2607,6 +2623,7 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2629,6 +2646,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2651,6 +2669,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2673,6 +2692,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -2695,6 +2715,7 @@
"cpu": [
"wasm32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
@@ -2714,6 +2735,7 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2733,6 +2755,7 @@
"cpu": [
"ia32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -2752,6 +2775,7 @@
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -3011,6 +3035,7 @@
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": "^14.21.3 || >=16"
},
@@ -6957,6 +6982,7 @@
"resolved": "https://registry.npmjs.org/@react-email/text/-/text-0.1.6.tgz",
"integrity": "sha512-TYqkioRS45wTR5il3dYk/SbUjjEdhSwh9BtRNB99qNH1pXAwA45H7rAuxehiu8iJQJH0IyIr+6n62gBz9ezmsw==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=20.0.0"
},
@@ -8417,6 +8443,7 @@
"version": "5.90.21",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz",
"integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==",
"peer": true,
"dependencies": {
"@tanstack/query-core": "5.90.20"
},
@@ -8532,6 +8559,7 @@
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*"
}
@@ -8691,7 +8719,6 @@
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
"integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-selection": "*"
@@ -8807,7 +8834,6 @@
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
"integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/d3-shape": {
@@ -8842,7 +8868,6 @@
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
"integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-selection": "*"
@@ -8852,7 +8877,6 @@
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
"integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/d3-interpolate": "*",
@@ -8879,6 +8903,7 @@
"integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^5.0.0",
@@ -8974,6 +8999,7 @@
"integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.18.0"
}
@@ -9001,6 +9027,7 @@
"integrity": "sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*",
"pg-protocol": "*",
@@ -9026,6 +9053,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"devOptional": true,
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -9036,6 +9064,7 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -9122,8 +9151,7 @@
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/@types/ws": {
"version": "8.18.1",
@@ -9197,6 +9225,7 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -9651,6 +9680,38 @@
"win32"
]
},
"node_modules/@xyflow/react": {
"version": "12.8.4",
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.8.4.tgz",
"integrity": "sha512-bqUu4T5QSHiCFPkoH+b+LROKwQJdLvcjhGbNW9c1dLafCBRjmH1IYz0zPE+lRDXCtQ9kRyFxz3tG19+8VORJ1w==",
"license": "MIT",
"dependencies": {
"@xyflow/system": "0.0.68",
"classcat": "^5.0.3",
"zustand": "^4.4.0"
},
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17"
}
},
"node_modules/@xyflow/system": {
"version": "0.0.68",
"resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.68.tgz",
"integrity": "sha512-QDG2wxIG4qX+uF8yzm1ULVZrcXX3MxPBoxv7O52FWsX87qIImOqifUhfa/TwsvLdzn7ic2DDBH1uI8TKbdNTYA==",
"license": "MIT",
"dependencies": {
"@types/d3-drag": "^3.0.7",
"@types/d3-interpolate": "^3.0.4",
"@types/d3-selection": "^3.0.10",
"@types/d3-transition": "^3.0.8",
"@types/d3-zoom": "^3.0.8",
"d3-drag": "^3.0.0",
"d3-interpolate": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
}
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@@ -9670,6 +9731,7 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -10118,6 +10180,7 @@
"integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.26.0"
}
@@ -10189,6 +10252,7 @@
"integrity": "sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==",
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
@@ -10317,6 +10381,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -10499,6 +10564,12 @@
"url": "https://polar.sh/cva"
}
},
"node_modules/classcat": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz",
"integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
"license": "MIT"
},
"node_modules/cli-spinners": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
@@ -11223,6 +11294,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
"peer": true,
"engines": {
"node": ">=12"
}
@@ -11663,7 +11735,6 @@
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz",
"integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==",
"license": "(MPL-2.0 OR Apache-2.0)",
"peer": true,
"engines": {
"node": ">=20"
},
@@ -12298,6 +12369,7 @@
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -12383,6 +12455,7 @@
"integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2",
@@ -12519,6 +12592,7 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -12912,6 +12986,7 @@
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT",
"peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
@@ -15329,7 +15404,6 @@
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz",
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
"license": "MIT",
"peer": true,
"dependencies": {
"dompurify": "3.2.7",
"marked": "14.0.0"
@@ -15340,7 +15414,6 @@
"resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz",
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
"license": "MIT",
"peer": true,
"bin": {
"marked": "bin/marked.js"
},
@@ -15429,6 +15502,7 @@
"resolved": "https://registry.npmjs.org/next/-/next-15.5.14.tgz",
"integrity": "sha512-M6S+4JyRjmKic2Ssm7jHUPkE6YUJ6lv4507jprsSZLulubz0ihO2E+S4zmQK3JZ2ov81JrugukKU4Tz0ivgqqQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@next/env": "15.5.14",
"@swc/helpers": "0.5.15",
@@ -16388,6 +16462,7 @@
"resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz",
"integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==",
"license": "MIT",
"peer": true,
"dependencies": {
"pg-connection-string": "^2.12.0",
"pg-pool": "^3.13.0",
@@ -16892,6 +16967,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -16923,6 +16999,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -17215,6 +17292,7 @@
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz",
"integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=18.0.0"
},
@@ -18676,7 +18754,8 @@
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/tapable": {
"version": "2.3.2",
@@ -19151,6 +19230,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -19578,6 +19658,7 @@
"resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz",
"integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@colors/colors": "^1.6.0",
"@dabh/diagnostics": "^2.0.8",
@@ -19784,6 +19865,7 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -19799,6 +19881,34 @@
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
}
},
"node_modules/zustand": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz",
"integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
"license": "MIT",
"dependencies": {
"use-sync-external-store": "^1.2.2"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"@types/react": ">=16.8",
"immer": ">=9.0.6",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"immer": {
"optional": true
},
"react": {
"optional": true
}
}
}
}
}
+1
View File
@@ -67,6 +67,7 @@
"@tailwindcss/forms": "0.5.11",
"@tanstack/react-query": "5.90.21",
"@tanstack/react-table": "8.21.3",
"@xyflow/react": "^12.8.4",
"arctic": "3.7.0",
"axios": "1.13.5",
"better-sqlite3": "11.9.1",
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 KiB

After

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 KiB

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 KiB

After

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 KiB

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

+13 -1
View File
@@ -144,7 +144,19 @@ export enum ActionsEnum {
createEventStreamingDestination = "createEventStreamingDestination",
updateEventStreamingDestination = "updateEventStreamingDestination",
deleteEventStreamingDestination = "deleteEventStreamingDestination",
listEventStreamingDestinations = "listEventStreamingDestinations"
listEventStreamingDestinations = "listEventStreamingDestinations",
createAlertRule = "createAlertRule",
updateAlertRule = "updateAlertRule",
deleteAlertRule = "deleteAlertRule",
listAlertRules = "listAlertRules",
getAlertRule = "getAlertRule",
createHealthCheck = "createHealthCheck",
updateHealthCheck = "updateHealthCheck",
deleteHealthCheck = "deleteHealthCheck",
listHealthChecks = "listHealthChecks",
triggerSiteAlert = "triggerSiteAlert",
triggerResourceAlert = "triggerResourceAlert",
triggerHealthCheckAlert = "triggerHealthCheckAlert"
}
export async function checkUserActionPermission(
+108 -2
View File
@@ -16,11 +16,14 @@ import {
domains,
orgs,
targets,
roles,
users,
exitNodes,
sessions,
clients,
resources,
siteResources,
targetHealthCheck,
sites
} from "./schema";
@@ -425,7 +428,9 @@ export const eventStreamingDestinations = pgTable(
orgId: varchar("orgId", { length: 255 })
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
sendConnectionLogs: boolean("sendConnectionLogs").notNull().default(false),
sendConnectionLogs: boolean("sendConnectionLogs")
.notNull()
.default(false),
sendRequestLogs: boolean("sendRequestLogs").notNull().default(false),
sendActionLogs: boolean("sendActionLogs").notNull().default(false),
sendAccessLogs: boolean("sendAccessLogs").notNull().default(false),
@@ -447,7 +452,9 @@ export const eventStreamingCursors = pgTable(
onDelete: "cascade"
}),
logType: varchar("logType", { length: 50 }).notNull(), // "request" | "action" | "access" | "connection"
lastSentId: bigint("lastSentId", { mode: "number" }).notNull().default(0),
lastSentId: bigint("lastSentId", { mode: "number" })
.notNull()
.default(0),
lastSentAt: bigint("lastSentAt", { mode: "number" }) // epoch milliseconds, null if never sent
},
(table) => [
@@ -458,6 +465,104 @@ export const eventStreamingCursors = pgTable(
]
);
export const alertRules = pgTable("alertRules", {
alertRuleId: serial("alertRuleId").primaryKey(),
orgId: varchar("orgId", { length: 255 })
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
name: varchar("name", { length: 255 }).notNull(),
// Single field encodes both source and trigger - no redundancy
eventType: varchar("eventType", { length: 100 })
.$type<
| "site_online"
| "site_offline"
| "site_toggle"
| "health_check_healthy"
| "health_check_unhealthy"
| "health_check_toggle"
| "resource_healthy"
| "resource_unhealthy"
| "resource_toggle"
>()
.notNull(),
// Nullable depending on eventType
enabled: boolean("enabled").notNull().default(true),
cooldownSeconds: integer("cooldownSeconds").notNull().default(300),
allSites: boolean("allSites").notNull().default(false),
allHealthChecks: boolean("allHealthChecks").notNull().default(false),
allResources: boolean("allResources").notNull().default(false),
lastTriggeredAt: bigint("lastTriggeredAt", { mode: "number" }), // nullable
createdAt: bigint("createdAt", { mode: "number" }).notNull(),
updatedAt: bigint("updatedAt", { mode: "number" }).notNull()
});
export const alertSites = pgTable("alertSites", {
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
siteId: integer("siteId")
.notNull()
.references(() => sites.siteId, { onDelete: "cascade" })
});
export const alertHealthChecks = pgTable("alertHealthChecks", {
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
healthCheckId: integer("healthCheckId")
.notNull()
.references(() => targetHealthCheck.targetHealthCheckId, {
onDelete: "cascade"
})
});
export const alertResources = pgTable("alertResources", {
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" })
});
// Separating channels by type avoids the mixed-shape problem entirely
export const alertEmailActions = pgTable("alertEmailActions", {
emailActionId: serial("emailActionId").primaryKey(),
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
enabled: boolean("enabled").notNull().default(true),
lastSentAt: bigint("lastSentAt", { mode: "number" }) // nullable
});
export const alertEmailRecipients = pgTable("alertEmailRecipients", {
recipientId: serial("recipientId").primaryKey(),
emailActionId: integer("emailActionId")
.notNull()
.references(() => alertEmailActions.emailActionId, {
onDelete: "cascade"
}),
// At least one of these should be set - enforced at app level
userId: varchar("userId").references(() => users.userId, {
onDelete: "cascade"
}),
roleId: integer("roleId").references(() => roles.roleId, {
onDelete: "cascade"
}),
email: varchar("email", { length: 255 }) // external emails not tied to a user
});
export const alertWebhookActions = pgTable("alertWebhookActions", {
webhookActionId: serial("webhookActionId").primaryKey(),
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
webhookUrl: text("webhookUrl").notNull(),
config: text("config"), // encrypted JSON with auth config (authType, credentials)
enabled: boolean("enabled").notNull().default(true),
lastSentAt: bigint("lastSentAt", { mode: "number" }) // nullable
});
export type Approval = InferSelectModel<typeof approvals>;
export type Limit = InferSelectModel<typeof limits>;
export type Account = InferSelectModel<typeof account>;
@@ -495,3 +600,4 @@ export type EventStreamingDestination = InferSelectModel<
export type EventStreamingCursor = InferSelectModel<
typeof eventStreamingCursors
>;
export type AlertResources = InferSelectModel<typeof alertResources>;
+80 -12
View File
@@ -57,7 +57,9 @@ export const orgs = pgTable("orgs", {
settingsLogRetentionDaysAction: integer("settingsLogRetentionDaysAction") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0),
settingsLogRetentionDaysConnection: integer("settingsLogRetentionDaysConnection") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
settingsLogRetentionDaysConnection: integer(
"settingsLogRetentionDaysConnection"
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0),
sshCaPrivateKey: text("sshCaPrivateKey"), // Encrypted SSH CA private key (PEM format)
@@ -101,7 +103,9 @@ export const sites = pgTable("sites", {
lastHolePunch: bigint("lastHolePunch", { mode: "number" }),
listenPort: integer("listenPort"),
dockerSocketEnabled: boolean("dockerSocketEnabled").notNull().default(true),
status: varchar("status").$type<"pending" | "approved">().default("approved")
status: varchar("status")
.$type<"pending" | "approved">()
.default("approved")
});
export const resources = pgTable("resources", {
@@ -182,9 +186,15 @@ export const targets = pgTable("targets", {
export const targetHealthCheck = pgTable("targetHealthCheck", {
targetHealthCheckId: serial("targetHealthCheckId").primaryKey(),
targetId: integer("targetId")
.notNull()
.references(() => targets.targetId, { onDelete: "cascade" }),
targetId: integer("targetId").references(() => targets.targetId, {
onDelete: "cascade"
}),
orgId: varchar("orgId")
.references(() => orgs.orgId, {
onDelete: "cascade"
})
.notNull(),
name: varchar("name"),
hcEnabled: boolean("hcEnabled").notNull().default(false),
hcPath: varchar("hcPath"),
hcScheme: varchar("hcScheme"),
@@ -201,7 +211,9 @@ export const targetHealthCheck = pgTable("targetHealthCheck", {
hcHealth: text("hcHealth")
.$type<"unknown" | "healthy" | "unhealthy">()
.default("unknown"), // "unknown", "healthy", "unhealthy"
hcTlsServerName: text("hcTlsServerName")
hcTlsServerName: text("hcTlsServerName"),
hcHealthyThreshold: integer("hcHealthyThreshold").default(1),
hcUnhealthyThreshold: integer("hcUnhealthyThreshold").default(1)
});
export const exitNodes = pgTable("exitNodes", {
@@ -222,16 +234,23 @@ export const exitNodes = pgTable("exitNodes", {
export const siteResources = pgTable("siteResources", {
// this is for the clients
siteResourceId: serial("siteResourceId").primaryKey(),
siteId: integer("siteId")
.notNull()
.references(() => sites.siteId, { onDelete: "cascade" }),
orgId: varchar("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
networkId: integer("networkId").references(() => networks.networkId, {
onDelete: "set null"
}),
defaultNetworkId: integer("defaultNetworkId").references(
() => networks.networkId,
{
onDelete: "restrict"
}
),
niceId: varchar("niceId").notNull(),
name: varchar("name").notNull(),
mode: varchar("mode").$type<"host" | "cidr">().notNull(), // "host" | "cidr" | "port"
protocol: varchar("protocol"), // only for port mode
ssl: boolean("ssl").notNull().default(false),
mode: varchar("mode").$type<"host" | "cidr" | "http">().notNull(), // "host" | "cidr" | "http"
scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
proxyPort: integer("proxyPort"), // only for port mode
destinationPort: integer("destinationPort"), // only for port mode
destination: varchar("destination").notNull(), // ip, cidr, hostname; validate against the mode
@@ -244,7 +263,38 @@ export const siteResources = pgTable("siteResources", {
authDaemonPort: integer("authDaemonPort").default(22123),
authDaemonMode: varchar("authDaemonMode", { length: 32 })
.$type<"site" | "remote">()
.default("site")
.default("site"),
domainId: varchar("domainId").references(() => domains.domainId, {
onDelete: "set null"
}),
subdomain: varchar("subdomain"),
fullDomain: varchar("fullDomain")
});
export const networks = pgTable("networks", {
networkId: serial("networkId").primaryKey(),
niceId: text("niceId"),
name: text("name"),
scope: varchar("scope")
.$type<"global" | "resource">()
.notNull()
.default("global"),
orgId: varchar("orgId")
.references(() => orgs.orgId, {
onDelete: "cascade"
})
.notNull()
});
export const siteNetworks = pgTable("siteNetworks", {
siteId: integer("siteId")
.notNull()
.references(() => sites.siteId, {
onDelete: "cascade"
}),
networkId: integer("networkId")
.notNull()
.references(() => networks.networkId, { onDelete: "cascade" })
});
export const clientSiteResources = pgTable("clientSiteResources", {
@@ -994,6 +1044,7 @@ export const requestAuditLog = pgTable(
actor: text("actor"),
actorId: text("actorId"),
resourceId: integer("resourceId"),
siteResourceId: integer("siteResourceId"),
ip: text("ip"),
location: text("location"),
userAgent: text("userAgent"),
@@ -1041,6 +1092,20 @@ export const roundTripMessageTracker = pgTable("roundTripMessageTracker", {
complete: boolean("complete").notNull().default(false)
});
export const statusHistory = pgTable("statusHistory", {
id: serial("id").primaryKey(),
entityType: varchar("entityType").notNull(),
entityId: integer("entityId").notNull(),
orgId: varchar("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
status: varchar("status").notNull(),
timestamp: integer("timestamp").notNull(),
}, (table) => [
index("idx_statusHistory_entity").on(table.entityType, table.entityId, table.timestamp),
index("idx_statusHistory_org_timestamp").on(table.orgId, table.timestamp),
]);
export type Org = InferSelectModel<typeof orgs>;
export type User = InferSelectModel<typeof users>;
export type Site = InferSelectModel<typeof sites>;
@@ -1080,6 +1145,7 @@ export type ResourceWhitelist = InferSelectModel<typeof resourceWhitelist>;
export type VersionMigration = InferSelectModel<typeof versionMigrations>;
export type ResourceRule = InferSelectModel<typeof resourceRules>;
export type Domain = InferSelectModel<typeof domains>;
export type DnsRecord = InferSelectModel<typeof dnsRecords>;
export type SupporterKey = InferSelectModel<typeof supporterKey>;
export type Idp = InferSelectModel<typeof idp>;
export type ApiKey = InferSelectModel<typeof apiKeys>;
@@ -1106,3 +1172,5 @@ export type RequestAuditLog = InferSelectModel<typeof requestAuditLog>;
export type RoundTripMessageTracker = InferSelectModel<
typeof roundTripMessageTracker
>;
export type Network = InferSelectModel<typeof networks>;
export type StatusHistory = InferSelectModel<typeof statusHistory>;
+92
View File
@@ -13,9 +13,12 @@ import {
domains,
exitNodes,
orgs,
resources,
roles,
sessions,
siteResources,
sites,
targetHealthCheck,
users
} from "./schema";
@@ -455,6 +458,94 @@ export const eventStreamingCursors = sqliteTable(
]
);
export const alertRules = sqliteTable("alertRules", {
alertRuleId: integer("alertRuleId").primaryKey({ autoIncrement: true }),
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
name: text("name").notNull(),
eventType: text("eventType")
.$type<
| "site_online"
| "site_offline"
| "site_toggle"
| "health_check_healthy"
| "health_check_unhealthy"
| "health_check_toggle"
| "resource_healthy"
| "resource_unhealthy"
| "resource_toggle"
>()
.notNull(),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
cooldownSeconds: integer("cooldownSeconds").notNull().default(300),
allSites: integer("allSites", { mode: "boolean" }).notNull().default(false),
allHealthChecks: integer("allHealthChecks", { mode: "boolean" }).notNull().default(false),
allResources: integer("allResources", { mode: "boolean" }).notNull().default(false),
lastTriggeredAt: integer("lastTriggeredAt"),
createdAt: integer("createdAt").notNull(),
updatedAt: integer("updatedAt").notNull()
});
export const alertSites = sqliteTable("alertSites", {
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
siteId: integer("siteId")
.notNull()
.references(() => sites.siteId, { onDelete: "cascade" })
});
export const alertHealthChecks = sqliteTable("alertHealthChecks", {
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
healthCheckId: integer("healthCheckId")
.notNull()
.references(() => targetHealthCheck.targetHealthCheckId, {
onDelete: "cascade"
})
});
export const alertResources = sqliteTable("alertResources", {
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" })
});
export const alertEmailActions = sqliteTable("alertEmailActions", {
emailActionId: integer("emailActionId").primaryKey({ autoIncrement: true }),
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
lastSentAt: integer("lastSentAt")
});
export const alertEmailRecipients = sqliteTable("alertEmailRecipients", {
recipientId: integer("recipientId").primaryKey({ autoIncrement: true }),
emailActionId: integer("emailActionId")
.notNull()
.references(() => alertEmailActions.emailActionId, { onDelete: "cascade" }),
userId: text("userId").references(() => users.userId, { onDelete: "cascade" }),
roleId: integer("roleId").references(() => roles.roleId, { onDelete: "cascade" }),
email: text("email")
});
export const alertWebhookActions = sqliteTable("alertWebhookActions", {
webhookActionId: integer("webhookActionId").primaryKey({ autoIncrement: true }),
alertRuleId: integer("alertRuleId")
.notNull()
.references(() => alertRules.alertRuleId, { onDelete: "cascade" }),
webhookUrl: text("webhookUrl").notNull(),
config: text("config"), // encrypted JSON with auth config (authType, credentials)
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
lastSentAt: integer("lastSentAt")
});
export type Approval = InferSelectModel<typeof approvals>;
export type Limit = InferSelectModel<typeof limits>;
export type Account = InferSelectModel<typeof account>;
@@ -486,3 +577,4 @@ export type EventStreamingDestination = InferSelectModel<
export type EventStreamingCursor = InferSelectModel<
typeof eventStreamingCursors
>;
export type AlertResources = InferSelectModel<typeof alertResources>;
+75 -11
View File
@@ -54,7 +54,9 @@ export const orgs = sqliteTable("orgs", {
settingsLogRetentionDaysAction: integer("settingsLogRetentionDaysAction") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0),
settingsLogRetentionDaysConnection: integer("settingsLogRetentionDaysConnection") // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
settingsLogRetentionDaysConnection: integer(
"settingsLogRetentionDaysConnection"
) // where 0 = dont keep logs and -1 = keep forever and 9001 = end of the following year
.notNull()
.default(0),
sshCaPrivateKey: text("sshCaPrivateKey"), // Encrypted SSH CA private key (PEM format)
@@ -92,6 +94,9 @@ export const sites = sqliteTable("sites", {
exitNodeId: integer("exitNode").references(() => exitNodes.exitNodeId, {
onDelete: "set null"
}),
networkId: integer("networkId").references(() => networks.networkId, {
onDelete: "set null"
}),
name: text("name").notNull(),
pubKey: text("pubKey"),
subnet: text("subnet"),
@@ -204,9 +209,15 @@ export const targetHealthCheck = sqliteTable("targetHealthCheck", {
targetHealthCheckId: integer("targetHealthCheckId").primaryKey({
autoIncrement: true
}),
targetId: integer("targetId")
.notNull()
.references(() => targets.targetId, { onDelete: "cascade" }),
targetId: integer("targetId").references(() => targets.targetId, {
onDelete: "cascade"
}),
orgId: text("orgId")
.references(() => orgs.orgId, {
onDelete: "cascade"
})
.notNull(),
name: text("name"),
hcEnabled: integer("hcEnabled", { mode: "boolean" })
.notNull()
.default(false),
@@ -227,7 +238,9 @@ export const targetHealthCheck = sqliteTable("targetHealthCheck", {
hcHealth: text("hcHealth")
.$type<"unknown" | "healthy" | "unhealthy">()
.default("unknown"), // "unknown", "healthy", "unhealthy"
hcTlsServerName: text("hcTlsServerName")
hcTlsServerName: text("hcTlsServerName"),
hcHealthyThreshold: integer("hcHealthyThreshold").default(1),
hcUnhealthyThreshold: integer("hcUnhealthyThreshold").default(1)
});
export const exitNodes = sqliteTable("exitNodes", {
@@ -250,16 +263,21 @@ export const siteResources = sqliteTable("siteResources", {
siteResourceId: integer("siteResourceId").primaryKey({
autoIncrement: true
}),
siteId: integer("siteId")
.notNull()
.references(() => sites.siteId, { onDelete: "cascade" }),
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
networkId: integer("networkId").references(() => networks.networkId, {
onDelete: "set null"
}),
defaultNetworkId: integer("defaultNetworkId").references(
() => networks.networkId,
{ onDelete: "restrict" }
),
niceId: text("niceId").notNull(),
name: text("name").notNull(),
mode: text("mode").$type<"host" | "cidr">().notNull(), // "host" | "cidr" | "port"
protocol: text("protocol"), // only for port mode
ssl: integer("ssl", { mode: "boolean" }).notNull().default(false),
mode: text("mode").$type<"host" | "cidr" | "http">().notNull(), // "host" | "cidr" | "http"
scheme: text("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
proxyPort: integer("proxyPort"), // only for port mode
destinationPort: integer("destinationPort"), // only for port mode
destination: text("destination").notNull(), // ip, cidr, hostname
@@ -274,7 +292,36 @@ export const siteResources = sqliteTable("siteResources", {
authDaemonPort: integer("authDaemonPort").default(22123),
authDaemonMode: text("authDaemonMode")
.$type<"site" | "remote">()
.default("site")
.default("site"),
domainId: text("domainId").references(() => domains.domainId, {
onDelete: "set null"
}),
subdomain: text("subdomain"),
fullDomain: text("fullDomain")
});
export const networks = sqliteTable("networks", {
networkId: integer("networkId").primaryKey({ autoIncrement: true }),
niceId: text("niceId"),
name: text("name"),
scope: text("scope")
.$type<"global" | "resource">()
.notNull()
.default("global"),
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" })
});
export const siteNetworks = sqliteTable("siteNetworks", {
siteId: integer("siteId")
.notNull()
.references(() => sites.siteId, {
onDelete: "cascade"
}),
networkId: integer("networkId")
.notNull()
.references(() => networks.networkId, { onDelete: "cascade" })
});
export const clientSiteResources = sqliteTable("clientSiteResources", {
@@ -1096,6 +1143,7 @@ export const requestAuditLog = sqliteTable(
actor: text("actor"),
actorId: text("actorId"),
resourceId: integer("resourceId"),
siteResourceId: integer("siteResourceId"),
ip: text("ip"),
location: text("location"),
userAgent: text("userAgent"),
@@ -1143,6 +1191,20 @@ export const roundTripMessageTracker = sqliteTable("roundTripMessageTracker", {
complete: integer("complete", { mode: "boolean" }).notNull().default(false)
});
export const statusHistory = sqliteTable("statusHistory", {
id: integer("id").primaryKey({ autoIncrement: true }),
entityType: text("entityType").notNull(), // "site" | "healthCheck"
entityId: integer("entityId").notNull(), // siteId or targetHealthCheckId
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
status: text("status").notNull(), // "online"/"offline" for sites; "healthy"/"unhealthy"/"unknown" for healthChecks
timestamp: integer("timestamp").notNull(), // unix epoch seconds
}, (table) => [
index("idx_statusHistory_entity").on(table.entityType, table.entityId, table.timestamp),
index("idx_statusHistory_org_timestamp").on(table.orgId, table.timestamp),
]);
export type Org = InferSelectModel<typeof orgs>;
export type User = InferSelectModel<typeof users>;
export type Site = InferSelectModel<typeof sites>;
@@ -1195,6 +1257,7 @@ export type ApiKey = InferSelectModel<typeof apiKeys>;
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
export type SiteResource = InferSelectModel<typeof siteResources>;
export type Network = InferSelectModel<typeof networks>;
export type OrgDomains = InferSelectModel<typeof orgDomains>;
export type SetupToken = InferSelectModel<typeof setupTokens>;
export type HostMeta = InferSelectModel<typeof hostMeta>;
@@ -1209,3 +1272,4 @@ export type DeviceWebAuthCode = InferSelectModel<typeof deviceWebAuthCodes>;
export type RoundTripMessageTracker = InferSelectModel<
typeof roundTripMessageTracker
>;
export type StatusHistory = InferSelectModel<typeof statusHistory>;
@@ -0,0 +1,201 @@
import React from "react";
import { Body, Head, Html, Preview, Tailwind } from "@react-email/components";
import { themeColors } from "./lib/theme";
import {
EmailContainer,
EmailFooter,
EmailGreeting,
EmailHeading,
EmailInfoSection,
EmailLetterHead,
EmailSignature,
EmailText
} from "./components/Email";
export type AlertEventType =
| "site_online"
| "site_offline"
| "site_toggle"
| "health_check_healthy"
| "health_check_unhealthy"
| "health_check_toggle"
| "resource_healthy"
| "resource_unhealthy"
| "resource_toggle";
interface Props {
eventType: AlertEventType;
orgId: string;
data: Record<string, unknown>;
}
function getEventMeta(eventType: AlertEventType): {
heading: string;
previewText: string;
summary: string;
statusLabel: string;
statusColor: string;
} {
switch (eventType) {
case "site_online":
return {
heading: "Site Back Online",
previewText: "A site in your organization is back online.",
summary:
"Good news a site in your organization has come back online and is now reachable.",
statusLabel: "Online",
statusColor: "#16a34a"
};
case "site_offline":
return {
heading: "Site Offline",
previewText: "A site in your organization has gone offline.",
summary:
"A site in your organization has gone offline and is no longer reachable. Please investigate as soon as possible.",
statusLabel: "Offline",
statusColor: "#dc2626"
};
case "site_toggle":
return {
heading: "Site Status Changed",
previewText: "A site in your organization has changed status.",
summary:
"A site in your organization has changed status. Please review the details below and take action if needed.",
statusLabel: "Status Changed",
statusColor: "#f59e0b"
};
case "health_check_healthy":
return {
heading: "Health Check Recovered",
previewText:
"A health check in your organization is now healthy.",
summary:
"A health check in your organization has recovered and is now reporting a healthy status.",
statusLabel: "Healthy",
statusColor: "#16a34a"
};
case "health_check_unhealthy":
return {
heading: "Health Check Failing",
previewText:
"A health check in your organization is not healthy.",
summary:
"A health check in your organization is currently failing. Please review the details below and take action if needed.",
statusLabel: "Not Healthy",
statusColor: "#dc2626"
};
case "health_check_toggle":
return {
heading: "Health Check Status Changed",
previewText:
"A health check in your organization has changed status.",
summary:
"A health check in your organization has changed status. Please review the details below and take action if needed.",
statusLabel: "Status Changed",
statusColor: "#f59e0b"
};
case "resource_healthy":
return {
heading: "Resource Healthy",
previewText: "A resource in your organization is now healthy.",
summary:
"A resource in your organization has recovered and is now reporting a healthy status.",
statusLabel: "Healthy",
statusColor: "#16a34a"
};
case "resource_unhealthy":
return {
heading: "Resource Unhealthy",
previewText: "A resource in your organization is not healthy.",
summary:
"A resource in your organization is currently unhealthy. Please review the details below and take action if needed.",
statusLabel: "Unhealthy",
statusColor: "#dc2626"
};
case "resource_toggle":
return {
heading: "Resource Status Changed",
previewText:
"A resource in your organization has changed status.",
summary:
"A resource in your organization has changed status. Please review the details below and take action if needed.",
statusLabel: "Status Changed",
statusColor: "#f59e0b"
};
default:
return {
heading: "Alert Notification",
previewText: "An alert event has occurred in your organization.",
summary:
"An alert event has occurred in your organization. Please review the details below and take action if needed.",
statusLabel: "Alert",
statusColor: "#f59e0b"
};
}
}
function formatDataItems(
data: Record<string, unknown>
): { label: string; value: React.ReactNode }[] {
return Object.entries(data)
.filter(([key]) => key !== "orgId")
.map(([key, value]) => ({
label: key
.replace(/([A-Z])/g, " $1")
.replace(/^./, (s) => s.toUpperCase())
.trim(),
value: String(value ?? "-")
}));
}
export const AlertNotification = ({ eventType, orgId, data }: Props) => {
const meta = getEventMeta(eventType);
const dataItems = formatDataItems(data);
const allItems: { label: string; value: React.ReactNode }[] = [
{ label: "Organization", value: orgId },
{ label: "Status", value: (
<span style={{ color: meta.statusColor, fontWeight: 600 }}>
{meta.statusLabel}
</span>
)},
{ label: "Time", value: new Date().toUTCString() },
...dataItems
];
return (
<Html>
<Head />
<Preview>{meta.previewText}</Preview>
<Tailwind config={themeColors}>
<Body className="font-sans bg-gray-50">
<EmailContainer>
<EmailLetterHead />
<EmailHeading>{meta.heading}</EmailHeading>
<EmailGreeting>Hi there,</EmailGreeting>
<EmailText>{meta.summary}</EmailText>
<EmailInfoSection
title="Event Details"
items={allItems}
/>
<EmailText>
Log in to your dashboard to view more details and
manage your alert rules.
</EmailText>
<EmailFooter>
<EmailSignature />
</EmailFooter>
</EmailContainer>
</Body>
</Tailwind>
</Html>
);
};
export default AlertNotification;
@@ -32,7 +32,7 @@ export const EnterpriseEditionKeyGenerated = ({
}: EnterpriseEditionKeyGeneratedProps) => {
const previewText = personalUseOnly
? "Your Enterprise Edition key for personal use is ready"
: "Thank you for your purchase your Enterprise Edition key is ready";
: "Thank you for your purchase - your Enterprise Edition key is ready";
return (
<Html>
+2
View File
@@ -22,6 +22,7 @@ import { TraefikConfigManager } from "@server/lib/traefik/TraefikConfigManager";
import { initCleanup } from "#dynamic/cleanup";
import license from "#dynamic/license/license";
import { initLogCleanupInterval } from "@server/lib/cleanupLogs";
import { initAcmeCertSync } from "#dynamic/lib/acmeCertSync";
import { fetchServerIp } from "@server/lib/serverIpService";
async function startServers() {
@@ -39,6 +40,7 @@ async function startServers() {
initTelemetryClient();
initLogCleanupInterval();
initAcmeCertSync();
// Start all servers
const apiServer = createApiServer();
+3
View File
@@ -0,0 +1,3 @@
export function initAcmeCertSync(): void {
// stub
}
@@ -0,0 +1,19 @@
// stub
export async function fireHealthCheckHealthyAlert(
orgId: string,
healthCheckId: number,
healthCheckName?: string,
extra?: Record<string, unknown>
): Promise<void> {
return;
}
export async function fireHealthCheckNotHealthyAlert(
orgId: string,
healthCheckId: number,
healthCheckName?: string,
extra?: Record<string, unknown>
): Promise<void> {
return;
}
+19
View File
@@ -0,0 +1,19 @@
// stub
export async function fireSiteOnlineAlert(
orgId: string,
siteId: number,
siteName?: string,
extra?: Record<string, unknown>
): Promise<void> {
return;
}
export async function fireSiteOfflineAlert(
orgId: string,
siteId: number,
siteName?: string,
extra?: Record<string, unknown>
): Promise<void> {
return;
}
+2
View File
@@ -0,0 +1,2 @@
export * from "./events/siteEvents";
export * from "./events/healthCheckEvents";
+2 -2
View File
@@ -9,8 +9,8 @@ export type LicensePriceSet = {
export const licensePriceSet: LicensePriceSet = {
// Free license matches the freeLimitSet
[LicenseId.SMALL_LICENSE]: "price_1SxKHiD3Ee2Ir7WmvtEh17A8",
[LicenseId.BIG_LICENSE]: "price_1SxKHiD3Ee2Ir7WmMUiP0H6Y"
[LicenseId.SMALL_LICENSE]: "price_1TMJzmD3Ee2Ir7Wm05NlGImT",
[LicenseId.BIG_LICENSE]: "price_1TMJzzD3Ee2Ir7WmzJw9TerS"
};
export const licensePriceSetSandbox: LicensePriceSet = {
+10 -2
View File
@@ -19,7 +19,11 @@ export enum TierFeature {
SshPam = "sshPam",
FullRbac = "fullRbac",
SiteProvisioningKeys = "siteProvisioningKeys", // handle downgrade by revoking keys if needed
SIEM = "siem" // handle downgrade by disabling SIEM integrations
SIEM = "siem", // handle downgrade by disabling SIEM integrations
HTTPPrivateResources = "httpPrivateResources", // handle downgrade by disabling HTTP private resources
DomainNamespaces = "domainNamespaces", // handle downgrade by removing custom domain namespaces
StandaloneHealthChecks = "standaloneHealthChecks",
AlertingRules = "alertingRules"
}
export const tierMatrix: Record<TierFeature, Tier[]> = {
@@ -56,5 +60,9 @@ export const tierMatrix: Record<TierFeature, Tier[]> = {
[TierFeature.SshPam]: ["tier1", "tier3", "enterprise"],
[TierFeature.FullRbac]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.SiteProvisioningKeys]: ["tier3", "enterprise"],
[TierFeature.SIEM]: ["enterprise"]
[TierFeature.SIEM]: ["enterprise"],
[TierFeature.HTTPPrivateResources]: ["tier3", "enterprise"],
[TierFeature.DomainNamespaces]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.StandaloneHealthChecks]: ["tier2", "tier3", "enterprise"],
[TierFeature.AlertingRules]: ["tier2", "tier3", "enterprise"]
};
+32 -24
View File
@@ -121,8 +121,8 @@ export async function applyBlueprint({
for (const result of clientResourcesResults) {
if (
result.oldSiteResource &&
result.oldSiteResource.siteId !=
result.newSiteResource.siteId
JSON.stringify(result.newSites?.sort()) !==
JSON.stringify(result.oldSites?.sort())
) {
// query existing associations
const existingRoleIds = await trx
@@ -222,38 +222,46 @@ export async function applyBlueprint({
trx
);
} else {
const [newSite] = await trx
.select()
.from(sites)
.innerJoin(newts, eq(sites.siteId, newts.siteId))
.where(
and(
eq(sites.siteId, result.newSiteResource.siteId),
eq(sites.orgId, orgId),
eq(sites.type, "newt"),
isNotNull(sites.pubKey)
let good = true;
for (const newSite of result.newSites) {
const [site] = await trx
.select()
.from(sites)
.innerJoin(newts, eq(sites.siteId, newts.siteId))
.where(
and(
eq(sites.siteId, newSite.siteId),
eq(sites.orgId, orgId),
eq(sites.type, "newt"),
isNotNull(sites.pubKey)
)
)
)
.limit(1);
.limit(1);
if (!site) {
logger.debug(
`No newt sites found for client resource ${result.newSiteResource.siteResourceId}, skipping target update`
);
good = false;
break;
}
if (!newSite) {
logger.debug(
`No newt site found for client resource ${result.newSiteResource.siteResourceId}, skipping target update`
`Updating client resource ${result.newSiteResource.siteResourceId} on site ${newSite.siteId}`
);
continue;
}
logger.debug(
`Updating client resource ${result.newSiteResource.siteResourceId} on site ${newSite.sites.siteId}`
);
if (!good) {
continue;
}
await handleMessagingForUpdatedSiteResource(
result.oldSiteResource,
result.newSiteResource,
{
siteId: newSite.sites.siteId,
orgId: newSite.sites.orgId
},
result.newSites.map((site) => ({
siteId: site.siteId,
orgId: result.newSiteResource.orgId
})),
trx
);
}
+221 -37
View File
@@ -1,24 +1,104 @@
import {
clients,
clientSiteResources,
domains,
orgDomains,
roles,
roleSiteResources,
Site,
SiteResource,
siteNetworks,
siteResources,
Transaction,
userOrgs,
users,
userSiteResources
userSiteResources,
networks
} from "@server/db";
import { sites } from "@server/db";
import { eq, and, ne, inArray, or } from "drizzle-orm";
import { eq, and, ne, inArray, or, isNotNull } from "drizzle-orm";
import { Config } from "./types";
import logger from "@server/logger";
import { getNextAvailableAliasAddress } from "../ip";
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
async function getDomainForSiteResource(
siteResourceId: number | undefined,
fullDomain: string,
orgId: string,
trx: Transaction
): Promise<{ subdomain: string | null; domainId: string }> {
const [fullDomainExists] = await trx
.select({ siteResourceId: siteResources.siteResourceId })
.from(siteResources)
.where(
and(
eq(siteResources.fullDomain, fullDomain),
eq(siteResources.orgId, orgId),
siteResourceId
? ne(siteResources.siteResourceId, siteResourceId)
: isNotNull(siteResources.siteResourceId)
)
)
.limit(1);
if (fullDomainExists) {
throw new Error(
`Site resource already exists with domain: ${fullDomain} in org ${orgId}`
);
}
const possibleDomains = await trx
.select()
.from(domains)
.innerJoin(orgDomains, eq(domains.domainId, orgDomains.domainId))
.where(and(eq(orgDomains.orgId, orgId), eq(domains.verified, true)))
.execute();
if (possibleDomains.length === 0) {
throw new Error(
`Domain not found for full-domain: ${fullDomain} in org ${orgId}`
);
}
const validDomains = possibleDomains.filter((domain) => {
if (domain.domains.type == "ns" || domain.domains.type == "wildcard") {
return (
fullDomain === domain.domains.baseDomain ||
fullDomain.endsWith(`.${domain.domains.baseDomain}`)
);
} else if (domain.domains.type == "cname") {
return fullDomain === domain.domains.baseDomain;
}
});
if (validDomains.length === 0) {
throw new Error(
`Domain not found for full-domain: ${fullDomain} in org ${orgId}`
);
}
const domainSelection = validDomains[0].domains;
const baseDomain = domainSelection.baseDomain;
let subdomain: string | null = null;
if (fullDomain !== baseDomain) {
subdomain = fullDomain.replace(`.${baseDomain}`, "");
}
await createCertificate(domainSelection.domainId, fullDomain, trx);
return {
subdomain,
domainId: domainSelection.domainId
};
}
export type ClientResourcesResults = {
newSiteResource: SiteResource;
oldSiteResource?: SiteResource;
newSites: { siteId: number }[];
oldSites: { siteId: number }[];
}[];
export async function updateClientResources(
@@ -43,53 +123,104 @@ export async function updateClientResources(
)
.limit(1);
const resourceSiteId = resourceData.site;
let site;
const existingSiteIds = existingResource?.networkId
? await trx
.select({ siteId: sites.siteId })
.from(siteNetworks)
.where(eq(siteNetworks.networkId, existingResource.networkId))
: [];
if (resourceSiteId) {
// Look up site by niceId
[site] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
eq(sites.niceId, resourceSiteId),
eq(sites.orgId, orgId)
let allSites: { siteId: number }[] = [];
if (resourceData.site) {
let siteSingle;
const resourceSiteId = resourceData.site;
if (resourceSiteId) {
// Look up site by niceId
[siteSingle] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
eq(sites.niceId, resourceSiteId),
eq(sites.orgId, orgId)
)
)
)
.limit(1);
} else if (siteId) {
// Use the provided siteId directly, but verify it belongs to the org
[site] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(and(eq(sites.siteId, siteId), eq(sites.orgId, orgId)))
.limit(1);
} else {
throw new Error(`Target site is required`);
.limit(1);
} else if (siteId) {
// Use the provided siteId directly, but verify it belongs to the org
[siteSingle] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(eq(sites.siteId, siteId), eq(sites.orgId, orgId))
)
.limit(1);
} else {
throw new Error(`Target site is required`);
}
if (!siteSingle) {
throw new Error(
`Site not found: ${resourceSiteId} in org ${orgId}`
);
}
allSites.push(siteSingle);
}
if (!site) {
throw new Error(
`Site not found: ${resourceSiteId} in org ${orgId}`
);
if (resourceData.sites) {
for (const siteNiceId of resourceData.sites) {
const [site] = await trx
.select({ siteId: sites.siteId })
.from(sites)
.where(
and(
eq(sites.niceId, siteNiceId),
eq(sites.orgId, orgId)
)
)
.limit(1);
if (!site) {
throw new Error(
`Site not found: ${siteId} in org ${orgId}`
);
}
allSites.push(site);
}
}
if (existingResource) {
let domainInfo:
| { subdomain: string | null; domainId: string }
| undefined;
if (resourceData["full-domain"] && resourceData.mode === "http") {
domainInfo = await getDomainForSiteResource(
existingResource.siteResourceId,
resourceData["full-domain"],
orgId,
trx
);
}
// Update existing resource
const [updatedResource] = await trx
.update(siteResources)
.set({
name: resourceData.name || resourceNiceId,
siteId: site.siteId,
mode: resourceData.mode,
ssl: resourceData.ssl,
scheme: resourceData.scheme,
destination: resourceData.destination,
destinationPort: resourceData["destination-port"],
enabled: true, // hardcoded for now
// enabled: resourceData.enabled ?? true,
alias: resourceData.alias || null,
disableIcmp: resourceData["disable-icmp"],
tcpPortRangeString: resourceData["tcp-ports"],
udpPortRangeString: resourceData["udp-ports"]
udpPortRangeString: resourceData["udp-ports"],
fullDomain: resourceData["full-domain"] || null,
subdomain: domainInfo ? domainInfo.subdomain : null,
domainId: domainInfo ? domainInfo.domainId : null
})
.where(
eq(
@@ -100,7 +231,21 @@ export async function updateClientResources(
.returning();
const siteResourceId = existingResource.siteResourceId;
const orgId = existingResource.orgId;
if (updatedResource.networkId) {
await trx
.delete(siteNetworks)
.where(
eq(siteNetworks.networkId, updatedResource.networkId)
);
for (const site of allSites) {
await trx.insert(siteNetworks).values({
siteId: site.siteId,
networkId: updatedResource.networkId
});
}
}
await trx
.delete(clientSiteResources)
@@ -204,37 +349,72 @@ export async function updateClientResources(
results.push({
newSiteResource: updatedResource,
oldSiteResource: existingResource
oldSiteResource: existingResource,
newSites: allSites,
oldSites: existingSiteIds
});
} else {
let aliasAddress: string | null = null;
if (resourceData.mode == "host") {
// we can only have an alias on a host
if (resourceData.mode === "host" || resourceData.mode === "http") {
aliasAddress = await getNextAvailableAliasAddress(orgId);
}
let domainInfo:
| { subdomain: string | null; domainId: string }
| undefined;
if (resourceData["full-domain"] && resourceData.mode === "http") {
domainInfo = await getDomainForSiteResource(
undefined,
resourceData["full-domain"],
orgId,
trx
);
}
const [network] = await trx
.insert(networks)
.values({
scope: "resource",
orgId: orgId
})
.returning();
// Create new resource
const [newResource] = await trx
.insert(siteResources)
.values({
orgId: orgId,
siteId: site.siteId,
niceId: resourceNiceId,
networkId: network.networkId,
defaultNetworkId: network.networkId,
name: resourceData.name || resourceNiceId,
mode: resourceData.mode,
ssl: resourceData.ssl,
scheme: resourceData.scheme,
destination: resourceData.destination,
destinationPort: resourceData["destination-port"],
enabled: true, // hardcoded for now
// enabled: resourceData.enabled ?? true,
alias: resourceData.alias || null,
aliasAddress: aliasAddress,
disableIcmp: resourceData["disable-icmp"],
tcpPortRangeString: resourceData["tcp-ports"],
udpPortRangeString: resourceData["udp-ports"]
udpPortRangeString: resourceData["udp-ports"],
fullDomain: resourceData["full-domain"] || null,
subdomain: domainInfo ? domainInfo.subdomain : null,
domainId: domainInfo ? domainInfo.domainId : null
})
.returning();
const siteResourceId = newResource.siteResourceId;
for (const site of allSites) {
await trx.insert(siteNetworks).values({
siteId: site.siteId,
networkId: network.networkId
});
}
const [adminRole] = await trx
.select()
.from(roles)
@@ -324,7 +504,11 @@ export async function updateClientResources(
`Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}`
);
results.push({ newSiteResource: newResource });
results.push({
newSiteResource: newResource,
newSites: allSites,
oldSites: existingSiteIds
});
}
}
+11 -3
View File
@@ -140,7 +140,9 @@ export async function updateProxyResources(
const [newHealthcheck] = await trx
.insert(targetHealthCheck)
.values({
name: `${targetData.hostname}:${targetData.port}`,
targetId: newTarget.targetId,
orgId: orgId,
hcEnabled: healthcheckData?.enabled || false,
hcPath: healthcheckData?.path,
hcScheme: healthcheckData?.scheme,
@@ -158,7 +160,9 @@ export async function updateProxyResources(
healthcheckData?.["follow-redirects"],
hcMethod: healthcheckData?.method,
hcStatus: healthcheckData?.status,
hcHealth: "unknown"
hcHealth: "unknown",
hcHealthyThreshold: healthcheckData?.["healthy-threshold"],
hcUnhealthyThreshold: healthcheckData?.["unhealthy-threshold"]
})
.returning();
@@ -522,7 +526,9 @@ export async function updateProxyResources(
healthcheckData?.followRedirects ||
healthcheckData?.["follow-redirects"],
hcMethod: healthcheckData?.method,
hcStatus: healthcheckData?.status
hcStatus: healthcheckData?.status,
hcHealthyThreshold: healthcheckData?.["healthy-threshold"],
hcUnhealthyThreshold: healthcheckData?.["unhealthy-threshold"]
})
.where(
eq(
@@ -1081,6 +1087,8 @@ function checkIfHealthcheckChanged(
JSON.stringify(incoming.hcHeaders)
)
return true;
if (existing.hcHealthyThreshold !== incoming.hcHealthyThreshold) return true;
if (existing.hcUnhealthyThreshold !== incoming.hcUnhealthyThreshold) return true;
return false;
}
@@ -1100,7 +1108,7 @@ function checkIfTargetChanged(
return false;
}
async function getDomain(
export async function getDomain(
resourceId: number | undefined,
fullDomain: string,
orgId: string,
+46 -6
View File
@@ -12,7 +12,7 @@ export const TargetHealthCheckSchema = z.object({
hostname: z.string(),
port: z.int().min(1).max(65535),
enabled: z.boolean().optional().default(true),
path: z.string().optional().default("/"),
path: z.string().optional(),
scheme: z.string().optional(),
mode: z.string().default("http"),
interval: z.int().default(30),
@@ -26,8 +26,10 @@ export const TargetHealthCheckSchema = z.object({
.default(null),
"follow-redirects": z.boolean().default(true),
followRedirects: z.boolean().optional(), // deprecated alias
method: z.string().default("GET"),
status: z.int().optional()
method: z.string().optional(),
status: z.int().optional(),
"healthy-threshold": z.int().min(1).optional().default(1),
"unhealthy-threshold": z.int().min(1).optional().default(1)
});
// Schema for individual target within a resource
@@ -164,6 +166,7 @@ export const ResourceSchema = z
name: z.string().optional(),
protocol: z.enum(["http", "tcp", "udp"]).optional(),
ssl: z.boolean().optional(),
scheme: z.enum(["http", "https"]).optional(),
"full-domain": z.string().optional(),
"proxy-port": z.int().min(1).max(65535).optional(),
enabled: z.boolean().optional(),
@@ -325,16 +328,20 @@ export function isTargetsOnlyResource(resource: any): boolean {
export const ClientResourceSchema = z
.object({
name: z.string().min(1).max(255),
mode: z.enum(["host", "cidr"]),
site: z.string(),
mode: z.enum(["host", "cidr", "http"]),
site: z.string(), // DEPRECATED IN FAVOR OF sites
sites: z.array(z.string()).optional().default([]),
// protocol: z.enum(["tcp", "udp"]).optional(),
// proxyPort: z.int().positive().optional(),
// destinationPort: z.int().positive().optional(),
"destination-port": z.int().positive().optional(),
destination: z.string().min(1),
// enabled: z.boolean().default(true),
"tcp-ports": portRangeStringSchema.optional().default("*"),
"udp-ports": portRangeStringSchema.optional().default("*"),
"disable-icmp": z.boolean().optional().default(false),
"full-domain": z.string().optional(),
ssl: z.boolean().optional(),
scheme: z.enum(["http", "https"]).optional().nullable(),
alias: z
.string()
.regex(
@@ -477,6 +484,39 @@ export const ConfigSchema = z
});
}
// Enforce the full-domain uniqueness across client-resources in the same stack
const clientFullDomainMap = new Map<string, string[]>();
Object.entries(config["client-resources"]).forEach(
([resourceKey, resource]) => {
const fullDomain = resource["full-domain"];
if (fullDomain) {
if (!clientFullDomainMap.has(fullDomain)) {
clientFullDomainMap.set(fullDomain, []);
}
clientFullDomainMap.get(fullDomain)!.push(resourceKey);
}
}
);
const clientFullDomainDuplicates = Array.from(
clientFullDomainMap.entries()
)
.filter(([_, resourceKeys]) => resourceKeys.length > 1)
.map(
([fullDomain, resourceKeys]) =>
`'${fullDomain}' used by resources: ${resourceKeys.join(", ")}`
)
.join("; ");
if (clientFullDomainDuplicates.length !== 0) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["client-resources"],
message: `Duplicate 'full-domain' values found: ${clientFullDomainDuplicates}`
});
}
// Enforce proxy-port uniqueness within proxy-resources per protocol
const protocolPortMap = new Map<string, string[]>();
-39
View File
@@ -1,39 +0,0 @@
import crypto from "crypto";
export function encryptData(data: string, key: Buffer): string {
const algorithm = "aes-256-gcm";
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(data, "utf8", "hex");
encrypted += cipher.final("hex");
const authTag = cipher.getAuthTag();
// Combine IV, auth tag, and encrypted data
return iv.toString("hex") + ":" + authTag.toString("hex") + ":" + encrypted;
}
// Helper function to decrypt data (you'll need this to read certificates)
export function decryptData(encryptedData: string, key: Buffer): string {
const algorithm = "aes-256-gcm";
const parts = encryptedData.split(":");
if (parts.length !== 3) {
throw new Error("Invalid encrypted data format");
}
const iv = Buffer.from(parts[0], "hex");
const authTag = Buffer.from(parts[1], "hex");
const encrypted = parts[2];
const decipher = crypto.createDecipheriv(algorithm, key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
}
// openssl rand -hex 32 > config/encryption.key
+119 -47
View File
@@ -5,6 +5,7 @@ import config from "@server/lib/config";
import z from "zod";
import logger from "@server/logger";
import semver from "semver";
import { getValidCertificatesForDomains } from "#dynamic/lib/certificates";
interface IPRange {
start: bigint;
@@ -477,9 +478,9 @@ export type Alias = { alias: string | null; aliasAddress: string | null };
export function generateAliasConfig(allSiteResources: SiteResource[]): Alias[] {
return allSiteResources
.filter((sr) => sr.alias && sr.aliasAddress && sr.mode == "host")
.filter((sr) => sr.aliasAddress && ((sr.alias && sr.mode == "host") || (sr.fullDomain && sr.mode == "http")))
.map((sr) => ({
alias: sr.alias,
alias: sr.alias || sr.fullDomain,
aliasAddress: sr.aliasAddress
}));
}
@@ -582,16 +583,26 @@ export type SubnetProxyTargetV2 = {
protocol: "tcp" | "udp";
}[];
resourceId?: number;
protocol?: "http" | "https"; // if set, this target only applies to the specified protocol
httpTargets?: HTTPTarget[];
tlsCert?: string;
tlsKey?: string;
};
export function generateSubnetProxyTargetV2(
export type HTTPTarget = {
destAddr: string; // must be an IP or hostname
destPort: number;
scheme: "http" | "https";
};
export async function generateSubnetProxyTargetV2(
siteResource: SiteResource,
clients: {
clientId: number;
pubKey: string | null;
subnet: string | null;
}[]
): SubnetProxyTargetV2 | undefined {
): Promise<SubnetProxyTargetV2[] | undefined> {
if (clients.length === 0) {
logger.debug(
`No clients have access to site resource ${siteResource.siteResourceId}, skipping target generation.`
@@ -599,7 +610,7 @@ export function generateSubnetProxyTargetV2(
return;
}
let target: SubnetProxyTargetV2 | null = null;
let targets: SubnetProxyTargetV2[] = [];
const portRange = [
...parsePortRangeString(siteResource.tcpPortRangeString, "tcp"),
@@ -614,52 +625,115 @@ export function generateSubnetProxyTargetV2(
if (ipSchema.safeParse(destination).success) {
destination = `${destination}/32`;
target = {
targets.push({
sourcePrefixes: [],
destPrefix: destination,
portRange,
disableIcmp,
resourceId: siteResource.siteResourceId,
};
resourceId: siteResource.siteResourceId
});
}
if (siteResource.alias && siteResource.aliasAddress) {
// also push a match for the alias address
target = {
targets.push({
sourcePrefixes: [],
destPrefix: `${siteResource.aliasAddress}/32`,
rewriteTo: destination,
portRange,
disableIcmp,
resourceId: siteResource.siteResourceId,
};
resourceId: siteResource.siteResourceId
});
}
} else if (siteResource.mode == "cidr") {
target = {
targets.push({
sourcePrefixes: [],
destPrefix: siteResource.destination,
portRange,
disableIcmp,
resourceId: siteResource.siteResourceId
});
} else if (siteResource.mode == "http") {
let destination = siteResource.destination;
// check if this is a valid ip
const ipSchema = z.union([z.ipv4(), z.ipv6()]);
if (ipSchema.safeParse(destination).success) {
destination = `${destination}/32`;
}
if (
!siteResource.aliasAddress ||
!siteResource.destinationPort ||
!siteResource.scheme ||
!siteResource.fullDomain
) {
logger.debug(
`Site resource ${siteResource.siteResourceId} is in HTTP mode but is missing alias or alias address or destinationPort or scheme, skipping alias target generation.`
);
return;
}
// also push a match for the alias address
let tlsCert: string | undefined;
let tlsKey: string | undefined;
if (siteResource.ssl && siteResource.fullDomain) {
try {
const certs = await getValidCertificatesForDomains(
new Set([siteResource.fullDomain]),
true
);
if (certs.length > 0 && certs[0].certFile && certs[0].keyFile) {
tlsCert = certs[0].certFile;
tlsKey = certs[0].keyFile;
} else {
logger.warn(
`No valid certificate found for SSL site resource ${siteResource.siteResourceId} with domain ${siteResource.fullDomain}`
);
}
} catch (err) {
logger.error(
`Failed to retrieve certificate for site resource ${siteResource.siteResourceId} domain ${siteResource.fullDomain}: ${err}`
);
}
}
targets.push({
sourcePrefixes: [],
destPrefix: `${siteResource.aliasAddress}/32`,
rewriteTo: destination,
portRange,
disableIcmp,
resourceId: siteResource.siteResourceId,
};
protocol: siteResource.ssl ? "https" : "http",
httpTargets: [
{
destAddr: siteResource.destination,
destPort: siteResource.destinationPort,
scheme: siteResource.scheme
}
],
...(tlsCert && tlsKey ? { tlsCert, tlsKey } : {})
});
}
if (!target) {
if (targets.length == 0) {
return;
}
for (const clientSite of clients) {
if (!clientSite.subnet) {
logger.debug(
`Client ${clientSite.clientId} has no subnet, skipping for site resource ${siteResource.siteResourceId}.`
);
continue;
for (const target of targets) {
for (const clientSite of clients) {
if (!clientSite.subnet) {
logger.debug(
`Client ${clientSite.clientId} has no subnet, skipping for site resource ${siteResource.siteResourceId}.`
);
continue;
}
const clientPrefix = `${clientSite.subnet.split("/")[0]}/32`;
// add client prefix to source prefixes
target.sourcePrefixes.push(clientPrefix);
}
const clientPrefix = `${clientSite.subnet.split("/")[0]}/32`;
// add client prefix to source prefixes
target.sourcePrefixes.push(clientPrefix);
}
// print a nice representation of the targets
@@ -667,36 +741,34 @@ export function generateSubnetProxyTargetV2(
// `Generated subnet proxy targets for: ${JSON.stringify(targets, null, 2)}`
// );
return target;
return targets;
}
/**
* Converts a SubnetProxyTargetV2 to an array of SubnetProxyTarget (v1)
* by expanding each source prefix into its own target entry.
* @param targetV2 - The v2 target to convert
* @returns Array of v1 SubnetProxyTarget objects
*/
export function convertSubnetProxyTargetsV2ToV1(
targetsV2: SubnetProxyTargetV2[]
): SubnetProxyTarget[] {
return targetsV2.flatMap((targetV2) =>
targetV2.sourcePrefixes.map((sourcePrefix) => ({
sourcePrefix,
destPrefix: targetV2.destPrefix,
...(targetV2.disableIcmp !== undefined && {
disableIcmp: targetV2.disableIcmp
}),
...(targetV2.rewriteTo !== undefined && {
rewriteTo: targetV2.rewriteTo
}),
...(targetV2.portRange !== undefined && {
portRange: targetV2.portRange
})
}))
);
}
export function convertSubnetProxyTargetsV2ToV1(
targetsV2: SubnetProxyTargetV2[]
): SubnetProxyTarget[] {
return targetsV2.flatMap((targetV2) =>
targetV2.sourcePrefixes.map((sourcePrefix) => ({
sourcePrefix,
destPrefix: targetV2.destPrefix,
...(targetV2.disableIcmp !== undefined && {
disableIcmp: targetV2.disableIcmp
}),
...(targetV2.rewriteTo !== undefined && {
rewriteTo: targetV2.rewriteTo
}),
...(targetV2.portRange !== undefined && {
portRange: targetV2.portRange
})
}))
);
}
// Custom schema for validating port range strings
// Format: "80,443,8000-9000" or "*" for all ports, or empty string
+2
View File
@@ -1,3 +1,5 @@
// Normalizes
/**
* Normalizes a post-authentication path for safe use when building redirect URLs.
* Returns a path that starts with / and does not allow open redirects (no //, no :).

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