@astralyn/sash 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +184 -0
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/THIRD_PARTY_NOTICES.md +54 -0
- package/dist/api.js +103 -0
- package/dist/browser.js +25 -0
- package/dist/cli-errors.js +15 -0
- package/dist/cli.js +122 -0
- package/dist/commands/lifecycle.js +50 -0
- package/dist/commands/logs.js +54 -0
- package/dist/commands/shared.js +8 -0
- package/dist/commands/status.js +39 -0
- package/dist/commands/update.js +5 -0
- package/dist/commands/upgrade.js +43 -0
- package/dist/commands/web.js +33 -0
- package/dist/contracts.js +412 -0
- package/dist/core-config-validation.js +72 -0
- package/dist/core-install-record.js +55 -0
- package/dist/core-install-transaction.js +114 -0
- package/dist/core-update-coordination.js +105 -0
- package/dist/core-update-service.js +245 -0
- package/dist/core-update.js +804 -0
- package/dist/core-version.js +18 -0
- package/dist/core.js +206 -0
- package/dist/daemon/app.js +157 -0
- package/dist/daemon/context.js +40 -0
- package/dist/daemon/entry.js +67 -0
- package/dist/daemon/errors.js +47 -0
- package/dist/daemon/handlers/core.js +17 -0
- package/dist/daemon/handlers/daemon.js +66 -0
- package/dist/daemon/handlers/profiles.js +57 -0
- package/dist/daemon/handlers/proxy.js +12 -0
- package/dist/daemon/handlers/settings.js +48 -0
- package/dist/daemon/router.js +312 -0
- package/dist/daemon/scheduler.js +33 -0
- package/dist/daemon/server.js +121 -0
- package/dist/daemon-auth.js +71 -0
- package/dist/daemon-client.js +55 -0
- package/dist/daemon-entry.js +13 -0
- package/dist/daemon-http.js +93 -0
- package/dist/daemon-lifecycle.js +378 -0
- package/dist/daemon-proxy.js +176 -0
- package/dist/daemon-static.js +106 -0
- package/dist/daemon.js +3 -0
- package/dist/error-utils.js +14 -0
- package/dist/fs-atomic.js +123 -0
- package/dist/github.js +187 -0
- package/dist/http.js +282 -0
- package/dist/json-shape.js +17 -0
- package/dist/log-follow.js +280 -0
- package/dist/log.js +17 -0
- package/dist/managed-state-transaction.js +377 -0
- package/dist/mihomo-config.js +334 -0
- package/dist/node-version-guard.js +8 -0
- package/dist/offline-mutation.js +58 -0
- package/dist/paths.js +57 -0
- package/dist/process.js +572 -0
- package/dist/profile-migration.js +101 -0
- package/dist/profile-service.js +667 -0
- package/dist/profiles.js +182 -0
- package/dist/runtime-lifecycle.js +205 -0
- package/dist/runtime-owner.js +87 -0
- package/dist/runtime-recovery.js +31 -0
- package/dist/sash-client.js +163 -0
- package/dist/settings-service.js +242 -0
- package/dist/settings.js +314 -0
- package/dist/state-lock.js +331 -0
- package/dist/status.js +279 -0
- package/dist/supervisor.js +301 -0
- package/dist/sysproxy/common.js +99 -0
- package/dist/sysproxy/darwin.js +287 -0
- package/dist/sysproxy/factory.js +71 -0
- package/dist/sysproxy/gnome.js +181 -0
- package/dist/sysproxy/legacy.js +58 -0
- package/dist/sysproxy/snapshot.js +284 -0
- package/dist/sysproxy/types.js +24 -0
- package/dist/sysproxy/windows.js +216 -0
- package/dist/sysproxy.js +8 -0
- package/dist/system-proxy-manager.js +460 -0
- package/dist/tun-guidance.js +11 -0
- package/dist/ui/assets/05129d5ad91a6181d272cc3d031363d6-DJkDXMrK.woff2 +0 -0
- package/dist/ui/assets/0526ebf94418638dfd5b6cd9b06c07d4-BzWe4Lji.woff2 +0 -0
- package/dist/ui/assets/053f2647a78f659f6f8a3ae8436bd265-BocXYDl5.woff2 +0 -0
- package/dist/ui/assets/078f666863424d3fd2d98e3ea528704c-DQ_QCvOt.woff2 +0 -0
- package/dist/ui/assets/07f3ff379663ffa0222c12f241421dd9-Cma7oDlr.woff2 +0 -0
- package/dist/ui/assets/08427b8d865853bbd7c439321b26495f-CJmC8fWx.woff2 +0 -0
- package/dist/ui/assets/095224e4db29d40c54098da02b266b0a-DjsP0nQn.woff2 +0 -0
- package/dist/ui/assets/0ada18ca45940b08accde5c61ee871e3-E1BZD3RX.woff2 +0 -0
- package/dist/ui/assets/0be242294f7d791af850c6df38ac78a0-2cL6Ntwf.woff2 +0 -0
- package/dist/ui/assets/0bf18c938d0c27cce06c39f855405fdb-CruLZZZJ.woff2 +0 -0
- package/dist/ui/assets/0cfb3e9f4edf60839c37dc83e6f75ea3-DzAtRHvi.woff2 +0 -0
- package/dist/ui/assets/0fbbd340d0467dfe3101d58846f30cb0-gtFcO250.woff2 +0 -0
- package/dist/ui/assets/1063fa2dc7334d1f383e30824e016eae-B7U-kD-0.woff2 +0 -0
- package/dist/ui/assets/109e26e62ddc85d946e699464afbece7-BLnUjAEV.woff2 +0 -0
- package/dist/ui/assets/12a443b0ae9748a993b5395f8fad412b-Btjff2Lz.woff2 +0 -0
- package/dist/ui/assets/135c4621de7a4d85d852e03d416f13ee-DdSuW36e.woff2 +0 -0
- package/dist/ui/assets/13aa415469ee761c968749b1c0c56ec6-Dwe-Wa_w.woff2 +0 -0
- package/dist/ui/assets/1435b1ad447bd9c0e8bc52035c9dcfa8-C05ldXtw.woff2 +0 -0
- package/dist/ui/assets/175e0915aa874e7446b79b6bc9b00721-Dp0-l77L.woff2 +0 -0
- package/dist/ui/assets/1876e7d02187f006e2b7f769391c3089-CNjpRdap.woff2 +0 -0
- package/dist/ui/assets/1886dc284b3b845e3b5fe04aa2107276-Bh_wHwL1.woff2 +0 -0
- package/dist/ui/assets/19a3dda6611aaf5d787403bd1159fe15-zoEBvdpA.woff2 +0 -0
- package/dist/ui/assets/1afa74e14da193125e45d4783d358a4f-BgjSTENX.woff2 +0 -0
- package/dist/ui/assets/1cd26a6a6d784720b4a43053e9058bcf-TAP3dvNi.woff2 +0 -0
- package/dist/ui/assets/1ce19bddc3beab385a863b1e05685678-BCdXitZw.woff2 +0 -0
- package/dist/ui/assets/1d3459ac6578c80502bdb876a4824a93-CSwdnEGP.woff2 +0 -0
- package/dist/ui/assets/1d479e364dab4af01c539f0a6a7ac036-ZFI-djGt.woff2 +0 -0
- package/dist/ui/assets/1dcea2408d17fcec4197adce50f8b32d-CnK2xXR-.woff2 +0 -0
- package/dist/ui/assets/1e855385699999e24a33f7df8aed0489-DGFHkDVQ.woff2 +0 -0
- package/dist/ui/assets/1f55944b8f7972580e3029694462a6b0-CB7ogVJ9.woff2 +0 -0
- package/dist/ui/assets/1f96eda70929089762dc3c4feb33f9c8-DtSQ6YOf.woff2 +0 -0
- package/dist/ui/assets/1fb275532caadc746455881b31da27c4-BHFTsg74.woff2 +0 -0
- package/dist/ui/assets/20e679bdc00d06f802ea71fd9154b284-D9gRjq_v.woff2 +0 -0
- package/dist/ui/assets/25aff66c4a9f8cb801cbd525f4a923e4-Dgi87hP7.woff2 +0 -0
- package/dist/ui/assets/28e6700380b023b23e77f2d75aee624f-b19D855Q.woff2 +0 -0
- package/dist/ui/assets/2a1c50aa9cd99ce3a0197f5d49948e63-DrztdXCB.woff2 +0 -0
- package/dist/ui/assets/2b4e0ae0bf3af610b97717dfd66a012d-CBoapvha.woff2 +0 -0
- package/dist/ui/assets/2be2b7a672b616bc2f07059a67bfaad8-BUR0aNML.woff2 +0 -0
- package/dist/ui/assets/2e0a358ada78ea98ec8ba86002a27eac-DvgbSr9v.woff2 +0 -0
- package/dist/ui/assets/2e1cf63a2a22a50516c49b1dc521ea8a-CmltIxig.woff2 +0 -0
- package/dist/ui/assets/2e4481801925fcb6573c4337c73f15d7-DYOoCk-m.woff2 +0 -0
- package/dist/ui/assets/2fe5e634c568cd874f94d24b8f02bfd1-DcEHY35G.woff2 +0 -0
- package/dist/ui/assets/309c33f63f29887fb557115aa24d4bb5-CUgqrXIj.woff2 +0 -0
- package/dist/ui/assets/3158f45c959e1b346b0bbd6f3193dbf0-kimcClqp.woff2 +0 -0
- package/dist/ui/assets/316adbc8037a36f8d804637b053bbe5e-CjbZmJf9.woff2 +0 -0
- package/dist/ui/assets/319e9631bc29fc7235b70fc9aac43cd9-IV6yZuHZ.woff2 +0 -0
- package/dist/ui/assets/32054f9bb88d9431b1cdf023f770e614-CYrpCgqK.woff2 +0 -0
- package/dist/ui/assets/3245fa1aac6338c1d9d04befb7c346f8-CzvPhVPA.woff2 +0 -0
- package/dist/ui/assets/326c730f98afa476057957f2743c81e2-GPHJ3Fpu.woff2 +0 -0
- package/dist/ui/assets/33885558dc783bf9bae6c5d4668fef07-D33us0yR.woff2 +0 -0
- package/dist/ui/assets/33cd11f5e61556e4618801c8231f2744-CoR_Tv3X.woff2 +0 -0
- package/dist/ui/assets/34a170749cb7e6c5851acc510882af6b-BCZwsihk.woff2 +0 -0
- package/dist/ui/assets/3538de2d387591258d7e9908aad803b9-CewOkERZ.woff2 +0 -0
- package/dist/ui/assets/38d7b029c036080067a2e94211098171-CettR5Qv.woff2 +0 -0
- package/dist/ui/assets/393f47efeefc9f9e9cca83eb10a82c69-Brhz4z1y.woff2 +0 -0
- package/dist/ui/assets/396a51f2b274d01f6ba606a94f3e5fe2-DgRk-jtI.woff2 +0 -0
- package/dist/ui/assets/3991bf955d4c925e84b4a6542760d4d5-II4HtRkQ.woff2 +0 -0
- package/dist/ui/assets/39b6cb6ae8d1ea0e9832b88d2c21ef99-CbJm-q6b.woff2 +0 -0
- package/dist/ui/assets/3a1133157fbd259f1a51aaa9f8418a26-3FmUjjvi.woff2 +0 -0
- package/dist/ui/assets/3a34cff07dca7a65ed2486be19229290-B7ml2yBN.woff2 +0 -0
- package/dist/ui/assets/3c339dd7c27e6b8a06eea431733e076f-dGQqXaEj.woff2 +0 -0
- package/dist/ui/assets/3d074ea67f60953b816ce7cf5d87a980-B5VkPOmg.woff2 +0 -0
- package/dist/ui/assets/3d38f54dcf4a9f4a50165d5849becf71-CVDtFSZn.woff2 +0 -0
- package/dist/ui/assets/3e3fc9a19a27f94e4ff1b815b55b2671-Ci736GLi.woff2 +0 -0
- package/dist/ui/assets/3e8abb1f606f29e2f0a8a8a6b702d263-C5sOSf5L.woff2 +0 -0
- package/dist/ui/assets/3f0ab4e1cd99bdbfdf9acbc8f4bcb9ce-0DcdTLxV.woff2 +0 -0
- package/dist/ui/assets/3f30c0482650345c981d66920f56ab61-CTD2CsZI.woff2 +0 -0
- package/dist/ui/assets/41a9aa12ad9a60758b304c1a998fb781-BTQUDLf1.woff2 +0 -0
- package/dist/ui/assets/424010b2bc5cee540b92b28da49b61bf-DT8upW2M.woff2 +0 -0
- package/dist/ui/assets/42fbdafff2d44b76c6665d51bb2cee9d-_UrojhXD.woff2 +0 -0
- package/dist/ui/assets/4341db13c311b3cb0eaaf6b4c71b89e5-CzjA7MzG.woff2 +0 -0
- package/dist/ui/assets/434db5a796128131fde78d4389d14b71-AeNdWKua.woff2 +0 -0
- package/dist/ui/assets/43cb51fc70a15274d49e2d956c5ec3b4-BQbufd96.woff2 +0 -0
- package/dist/ui/assets/43e79de1c7815f21efbc966ff96fcbd6-DlCQvOsQ.woff2 +0 -0
- package/dist/ui/assets/43faf6a8a3cde1088bd5f7c830890a89-SvDzF3nA.woff2 +0 -0
- package/dist/ui/assets/44731ae21d7690ce538d0f8242755833-CEmu9Z88.woff2 +0 -0
- package/dist/ui/assets/45324b2a64cc0c0db797d5c09e239d34-BuFudtvM.woff2 +0 -0
- package/dist/ui/assets/4584df05d00aa75ae6e1f850fdc9df1d-GNHt6xwM.woff2 +0 -0
- package/dist/ui/assets/48d539539e98481fb511a761031c59fd-Cd9gdi8B.woff2 +0 -0
- package/dist/ui/assets/49a1fb9fc6a35796b2e0d3539088ede8-CD1cRDOy.woff2 +0 -0
- package/dist/ui/assets/4bec02eb0c2371e59bfb7d41a141ea1e-CmBnNPo0.woff2 +0 -0
- package/dist/ui/assets/4c5a81ef5683f6fbf9935e640de804e7-B4wQxzVs.woff2 +0 -0
- package/dist/ui/assets/4f11c9c75e86214b7f69ddee3a9f8076-DHsQ2xpE.woff2 +0 -0
- package/dist/ui/assets/50434b8ff88e27101d1c67ba953ee873-PH_hIqxu.woff2 +0 -0
- package/dist/ui/assets/5107fd5153d52c6a3f8d43ff214dd6c2-ls3eo5Qd.woff2 +0 -0
- package/dist/ui/assets/520cb7d3683dee99e767650efc0aa5b1-Lkd4z-9S.woff2 +0 -0
- package/dist/ui/assets/5455087df2f091b7bf3d38c5a102a2e7-QNkiOxwe.woff2 +0 -0
- package/dist/ui/assets/556450fdf0978d329cf8277e3b71dcdb-CtypGAPw.woff2 +0 -0
- package/dist/ui/assets/5a1b5c1b71cad50c51a79a7f4825e6e6-DQA407Ec.woff2 +0 -0
- package/dist/ui/assets/5ba02e809d2ef4f7639178e7a7d654c0-Dty0omtl.woff2 +0 -0
- package/dist/ui/assets/5bd654afe48e094f95e5142e4eaadc75-D9pUq71R.woff2 +0 -0
- package/dist/ui/assets/5c4c3ca0a3f4115879a61a96d02e3efc-RcVLBj31.woff2 +0 -0
- package/dist/ui/assets/5c737d740638e8d764f12c1e5c1cd144-D2Npjq-N.woff2 +0 -0
- package/dist/ui/assets/5e78019102102aa5741aa591313fd5b5-V7Azrw-2.woff2 +0 -0
- package/dist/ui/assets/6287cacac64e1849941f7b7d7e6316c5-DzkbPOID.woff2 +0 -0
- package/dist/ui/assets/643df7194160d54edc48d16d76e5ba74-BKmmIRjw.woff2 +0 -0
- package/dist/ui/assets/65d3b214c69ff6786fd1cab06f8394b7-B0cRUJAr.woff2 +0 -0
- package/dist/ui/assets/6698103c11bfe260d44fcf00c6d8b623-DVWYOeyb.woff2 +0 -0
- package/dist/ui/assets/692e07b3a609a8f1a21c15c45631f348-DJW5LcZH.woff2 +0 -0
- package/dist/ui/assets/694e87456af181279c2bfd551aa3c6e3-Cu7kRuJB.woff2 +0 -0
- package/dist/ui/assets/6b88066bdc7a6e8bc823128dbd0f6f3b-BG38UZSq.woff2 +0 -0
- package/dist/ui/assets/6d6f36f15381826d113832bfdd41b021-Bgh7YPiq.woff2 +0 -0
- package/dist/ui/assets/6e22361162bd0a5cd189ca3c98d23d52-DqnptHqF.woff2 +0 -0
- package/dist/ui/assets/6e884dd501b8da24ecd37425a9b3d51d-BVNqra8s.woff2 +0 -0
- package/dist/ui/assets/71200dbc7497fbafa28db5cfeae74acb-B6xMqoC6.woff2 +0 -0
- package/dist/ui/assets/72a85441a9757146440e3985f3b02075-CzTSlCPZ.woff2 +0 -0
- package/dist/ui/assets/7472d7e02045dea3ff288eac850e38eb-CboJEy4X.woff2 +0 -0
- package/dist/ui/assets/795ffa953bea666763ae79ac88aa7e5a-C6UsoDmi.woff2 +0 -0
- package/dist/ui/assets/7aa8647d6c52d249169b73417aa8e444-kJejhQ0-.woff2 +0 -0
- package/dist/ui/assets/7be6b794fc233ccd8b5769496301313a-Ba2iZC0a.woff2 +0 -0
- package/dist/ui/assets/7c0748f04d52086809c9f551c5aaded7-DSzO_ybF.woff2 +0 -0
- package/dist/ui/assets/7c858bb53a7652227fab8cf9753d3e1f-Bi9fbvIF.woff2 +0 -0
- package/dist/ui/assets/7e7026091b4e6061b05963bdb3a7f944-CrmRDJpc.woff2 +0 -0
- package/dist/ui/assets/7f80369a7479d568ab8bf492000282bd-CqcI5ZOp.woff2 +0 -0
- package/dist/ui/assets/834ce2f2571aaa26e47a618c4ad55e58-DZfWJrxo.woff2 +0 -0
- package/dist/ui/assets/834faab602d9c795341bc7dfd6578fe5-B1VeBVWh.woff2 +0 -0
- package/dist/ui/assets/8513a8eea35b460a047a16a87c36f8bb-H259w_6b.woff2 +0 -0
- package/dist/ui/assets/8699e8a36465bf46671dc28ce24e188c-YlkPpQ6h.woff2 +0 -0
- package/dist/ui/assets/86ae8881eae9eac7e9c0182c8ce6c627-Ch2r3LNs.woff2 +0 -0
- package/dist/ui/assets/86b3ae1be58d76f7147793f09264451b-CpgTfcn-.woff2 +0 -0
- package/dist/ui/assets/8769f8d7d45adcfcbd3f80460d22720d-DV_yqcTo.woff2 +0 -0
- package/dist/ui/assets/87bb0ceea9f5515490c832bdf6ebf641-CJpxd8e6.woff2 +0 -0
- package/dist/ui/assets/8928b9a50b5efbaaafa039674a3c7301-C-42WRD6.woff2 +0 -0
- package/dist/ui/assets/899f2c2a36cbeac473a7caeeaabc46b1-xrIcXJXU.woff2 +0 -0
- package/dist/ui/assets/8a075d4043e6bf66740808b492186438-Dq0346Qm.woff2 +0 -0
- package/dist/ui/assets/8b86676936792154c53205ab5d90b797-BGH_CGsg.woff2 +0 -0
- package/dist/ui/assets/8c63ca479653200a0e12f428242e1171-CsBTcPwY.woff2 +0 -0
- package/dist/ui/assets/8c9c7ff8342f5fed60e73c4a7ad67325-CGSYpt52.woff2 +0 -0
- package/dist/ui/assets/8ca655fcc5d9cf33d49815e231f3f356-b8PyEeZg.woff2 +0 -0
- package/dist/ui/assets/8e96f0f9385ef826f900587d0fc18b3d-D7GIG6Uq.woff2 +0 -0
- package/dist/ui/assets/8ea917252cf2c1e664f06ee5badffeea-CDZ1AFr0.woff2 +0 -0
- package/dist/ui/assets/8f42f890fc37e292017446af85af2745-Qx6oGI0z.woff2 +0 -0
- package/dist/ui/assets/8f9589e71c53bb753749a9c412f15c01-BVR5mPJl.woff2 +0 -0
- package/dist/ui/assets/90e70b52a3cc2491bbb2b4c0caf0ae7e-BdwPu67j.woff2 +0 -0
- package/dist/ui/assets/92ac4ca42fe050c1e680c585551abd9c-CXLyuj7l.woff2 +0 -0
- package/dist/ui/assets/92c12bb794c491930fd06f3f97299807-u_0ognJ0.woff2 +0 -0
- package/dist/ui/assets/92f0b4d2bb274a801aac10fc34c1e0cc-DFHB6dyu.woff2 +0 -0
- package/dist/ui/assets/93247aebd628367f5518eafdb2770ce9-o1N4zvTO.woff2 +0 -0
- package/dist/ui/assets/940446ea160995af66a9ee223cc3d4d1-C-_7aPYO.woff2 +0 -0
- package/dist/ui/assets/94be430de618453b6ae27bd366827ba2-1YYf1n5N.woff2 +0 -0
- package/dist/ui/assets/98cd7d62095e466e55885b34f63c86f1-z33YCk0X.woff2 +0 -0
- package/dist/ui/assets/99049fd5cec5894cafe2a1e5e13d1e03-DNrg8nIk.woff2 +0 -0
- package/dist/ui/assets/99e2752b7351aaa7681b4d91db80e89a-b3hi7miY.woff2 +0 -0
- package/dist/ui/assets/9d1b670cbfd64716ac685dea26237d95-DAZ9U6es.woff2 +0 -0
- package/dist/ui/assets/CodeEditorModal-6m0TJWyF.css +1 -0
- package/dist/ui/assets/CodeEditorModal-CFEnWsyh.js +14 -0
- package/dist/ui/assets/ConnectionsView-DHo6yvU6.css +1 -0
- package/dist/ui/assets/ConnectionsView-DNGmZBSU.js +1 -0
- package/dist/ui/assets/LogsView-BoeE92VF.css +1 -0
- package/dist/ui/assets/LogsView-fSiaxQ13.js +1 -0
- package/dist/ui/assets/PaginationFooter-B3kHzRfB.js +1 -0
- package/dist/ui/assets/PaginationFooter-BNkpcNoB.css +1 -0
- package/dist/ui/assets/ProfileEditorDialog-BydoZthX.js +1 -0
- package/dist/ui/assets/ProfilesView-Btc1DOxE.js +2 -0
- package/dist/ui/assets/ProfilesView-ByqdFNHN.css +1 -0
- package/dist/ui/assets/RulesView-CHyynVqA.css +1 -0
- package/dist/ui/assets/RulesView-D9vZBiJ1.js +1 -0
- package/dist/ui/assets/SettingsFileDialog-CNFEAVs4.js +1 -0
- package/dist/ui/assets/SettingsView-BlDhZkXQ.js +2 -0
- package/dist/ui/assets/SettingsView-CngS3vBM.css +1 -0
- package/dist/ui/assets/a0f2d41645a113d821e7ff0891daad1e-XK0rDAci.woff2 +0 -0
- package/dist/ui/assets/a1d1345d8407dd6169f39c28ff6b1708-Bn7hMmv8.woff2 +0 -0
- package/dist/ui/assets/a29f51b4ebb6776e43e7492a036be28e-CrAKKz8u.woff2 +0 -0
- package/dist/ui/assets/a3252ac86b2c4e88bfb9baecabcad817-qnA_3LNE.woff2 +0 -0
- package/dist/ui/assets/a3d63a61e7eb2bb497dbc2da65bd0873-BRMJAm0m.woff2 +0 -0
- package/dist/ui/assets/a45eea933252dbe3529f30a0323c2661-D4kBOrXR.woff2 +0 -0
- package/dist/ui/assets/a4886c4ebed8c8b1f8a87b5b491a39aa-CBQdRqpF.woff2 +0 -0
- package/dist/ui/assets/a50b4ab745c7676d9d3ceb3c0a023a3d-CW990pgI.woff2 +0 -0
- package/dist/ui/assets/a5851ae4d7e58996d8bd681f80d4727c-BBytdb0t.woff2 +0 -0
- package/dist/ui/assets/a5cdaa96bf7d1db6c671432f9ab7bccb-slKJjgfX.woff2 +0 -0
- package/dist/ui/assets/a640dd2e962cf72c7fcf76234c973303-CUCWUDBY.woff2 +0 -0
- package/dist/ui/assets/a67e457bbd366aef5104ce743a2cf6d4-DkE8fLlE.woff2 +0 -0
- package/dist/ui/assets/a6c3f2257315d45aa212bd2e86a02852-CxDbXnZV.woff2 +0 -0
- package/dist/ui/assets/a73399a40a5f81fb7314b8b9a10cd221-DRAvJPKI.woff2 +0 -0
- package/dist/ui/assets/a73a64b0941803d9d807b9ec082df641-BbPpPyy5.woff2 +0 -0
- package/dist/ui/assets/a73d1a0a1dfd4f4234f7a0649ece4da4-BHeqktY9.woff2 +0 -0
- package/dist/ui/assets/a740044e77a400a450e71fcdea55523f-Co5hpBNK.woff2 +0 -0
- package/dist/ui/assets/a7669b29f404662c179c71b87e67c8d2-CVnuBgHy.woff2 +0 -0
- package/dist/ui/assets/a964a4def15811e91b05a91740a1cf37-CzcDfCRn.woff2 +0 -0
- package/dist/ui/assets/aac3f69132da164921fda75d2d90bfb7-B6rUZQ4_.woff2 +0 -0
- package/dist/ui/assets/aacd263c3bb4ba163a4d5079c159680a-DtrDLFlk.woff2 +0 -0
- package/dist/ui/assets/ac62ec881ded2cdb450e542b396e24d0-CRlVJvPa.woff2 +0 -0
- package/dist/ui/assets/aebcb9b7d4b174ab5a4b911206f24036-BuleSpgP.woff2 +0 -0
- package/dist/ui/assets/af70712dadc05c7b18d248996a5ab0a9-gCZSZGzb.woff2 +0 -0
- package/dist/ui/assets/afbd3a8a4cfaa4561b7848c28bc6c4f8-DgnqceEw.woff2 +0 -0
- package/dist/ui/assets/b02d3867e6e2ea921d2845b44c4a5a31-C9v4FrqD.woff2 +0 -0
- package/dist/ui/assets/b1b22825b930688403337d4fd7bbba62-vmMs2pJf.woff2 +0 -0
- package/dist/ui/assets/b3206c979bfb28d12d7ad6df58e74b9f-X1PqLaCR.woff2 +0 -0
- package/dist/ui/assets/b6280e42d4f11dcab70594f9d6774936-CtezImLG.woff2 +0 -0
- package/dist/ui/assets/b71b8cd1a70405c3dbc0e7a44055ca9a-Cd6cIOEr.woff2 +0 -0
- package/dist/ui/assets/b9198c4f220a4ca075f8daa4db529e50-Bgc7zlEt.woff2 +0 -0
- package/dist/ui/assets/baad304a58d7d42d0af29235c5e9490b-BQZYwARB.woff2 +0 -0
- package/dist/ui/assets/bb99e34f8784cc44f0eeadbe735dd238-UHFYI827.woff2 +0 -0
- package/dist/ui/assets/bc1cb0f523c8a2ff566a047aeddf90fd-BSlXQn97.woff2 +0 -0
- package/dist/ui/assets/bd3171e975d62612e50148bf38b2158f-CtZKzCzQ.woff2 +0 -0
- package/dist/ui/assets/be10640c403263dd5917ad65c4d453a6-B-rbuuja.woff2 +0 -0
- package/dist/ui/assets/be764e101e78b50b749aa1414d4810a7-yIPaQQih.woff2 +0 -0
- package/dist/ui/assets/bfa682a7f5f12945b41230c35eb859f6-CzagcI5f.woff2 +0 -0
- package/dist/ui/assets/bfa9753ed26f2e1f81ab7020167bd1a0-C6ZNQQ2p.woff2 +0 -0
- package/dist/ui/assets/branding/sash-cat.png +0 -0
- package/dist/ui/assets/c0e78c6ad709b19ce437677c91033489-BtwtlApg.woff2 +0 -0
- package/dist/ui/assets/c5a59409c610cc8c265d1691eb3f71eb-DmI_ky2X.woff2 +0 -0
- package/dist/ui/assets/c5ff66a1a57f2a29424e8de5d4ef3756-C9pOsaV1.woff2 +0 -0
- package/dist/ui/assets/c607bdee84a0e5b69721367ccc0c9c31-eoHbdXeg.woff2 +0 -0
- package/dist/ui/assets/c8095033941d18db730496eb4c863757-DoexTYks.woff2 +0 -0
- package/dist/ui/assets/c8295519e16f4cf3a350e9729f07653a-C8bAtIO_.woff2 +0 -0
- package/dist/ui/assets/c91f9c9f4db81afeba37c8e73afb0bfd-BGIl2iKW.woff2 +0 -0
- package/dist/ui/assets/c9ad9caa4afdd40766add91d321b0350-HfuiRq1k.woff2 +0 -0
- package/dist/ui/assets/cc4f271c90f9ea5157db9c0a4edc976b-MAjuDvHE.woff2 +0 -0
- package/dist/ui/assets/cdf7c3d96ba172214d7e1e9fe5e6ba8b-CUx4fWQE.woff2 +0 -0
- package/dist/ui/assets/cf70d5821ea7c3ca34653169ac763606-CE0T0Svc.woff2 +0 -0
- package/dist/ui/assets/d0d5efe92496b1ceea38e180b0ac97d3-7G71Z6v3.woff2 +0 -0
- package/dist/ui/assets/d1977142eceb878b06440375e64c4372-mr-7LWm-.woff2 +0 -0
- package/dist/ui/assets/d42feb13392b4dd9214c61b61a6e5ae8-DjnKADf_.woff2 +0 -0
- package/dist/ui/assets/d46a696ec6a077c6873fc39043c3c082-C62E-13k.woff2 +0 -0
- package/dist/ui/assets/d4c0bbf1605a8a9c36fff5a2ead81bb5-C2F6tzOj.woff2 +0 -0
- package/dist/ui/assets/d918d4e47697b7c752ea223e0d0d4c81-twovU2ty.woff2 +0 -0
- package/dist/ui/assets/d988c05da0b5624267dd825fedd133d1-Bgbc9SVH.woff2 +0 -0
- package/dist/ui/assets/da3a071df79531f4f033b7c8499651d0-0tgZJL_N.woff2 +0 -0
- package/dist/ui/assets/da8eba4acbf93048645043006de1c5f0-Ce0dmHn_.woff2 +0 -0
- package/dist/ui/assets/dc3f16892e20a85a8fcad2d3097e622b-8PRrFPJt.woff2 +0 -0
- package/dist/ui/assets/dd5f808ec691f911483a2eb60b5049bd-BhVupSbT.woff2 +0 -0
- package/dist/ui/assets/e2b04534cc697a76afd70e885119cb8c-DO303iCb.woff2 +0 -0
- package/dist/ui/assets/e307280eb2fb7809adee14ff0d247d32-DHMLXvSs.woff2 +0 -0
- package/dist/ui/assets/e3b484bec850c669094f713570870b3a-BI_9kRw8.woff2 +0 -0
- package/dist/ui/assets/e7b1d196949b7530cbda0ad956fbb2cc-i2m2Id0q.woff2 +0 -0
- package/dist/ui/assets/e7c2e5fb387880508811cadc2926e13a-BfROXX4U.woff2 +0 -0
- package/dist/ui/assets/e8a5fe283c8b9e173097bee0b5757ab6-BvfjDjYP.woff2 +0 -0
- package/dist/ui/assets/e8e3465d48435612e9c3509be3984188-BeUPU5-9.woff2 +0 -0
- package/dist/ui/assets/e93903f4604b007fc1b7134a74f5c534-B1M4h46T.woff2 +0 -0
- package/dist/ui/assets/eb0994906efd969102d522b6d8b3aff2-i9SHU5CJ.woff2 +0 -0
- package/dist/ui/assets/eb32eee23ceadd3fc4eb5763d3573f57-B3h9kgf3.woff2 +0 -0
- package/dist/ui/assets/ebadbc005027fb3e2b1c2d15be38c66b-qVQSBwBu.woff2 +0 -0
- package/dist/ui/assets/ecbbb464ff6934b5012cf33c80c7a907-CBEPqZfS.woff2 +0 -0
- package/dist/ui/assets/ed79ac25c014b6434f22fe1e2549bc26-mWhz7hkU.woff2 +0 -0
- package/dist/ui/assets/eed64f40443554cb9f65edaca176abb0-Cqw29XTm.woff2 +0 -0
- package/dist/ui/assets/efc749471476cce09e12e7038c757950-BhSWPf1Q.woff2 +0 -0
- package/dist/ui/assets/f2a7c2cb375662aa93d8f31116d39c20-D1zsMYCW.woff2 +0 -0
- package/dist/ui/assets/f5ba0fb4332ccceadc481e47134023d3-CAKMPiu5.woff2 +0 -0
- package/dist/ui/assets/f6326eb5031e18478aa4588598f96965-Dj3uu55n.woff2 +0 -0
- package/dist/ui/assets/f8678cbaab9caef95e1986731dcbd92f-CnIuR3EN.woff2 +0 -0
- package/dist/ui/assets/f8d9d55e2a811e9839c9af5f8f2d62ac-DIUQRBsH.woff2 +0 -0
- package/dist/ui/assets/f98b117e363eb51f4d7c7d1056da7688-O9MtqjIW.woff2 +0 -0
- package/dist/ui/assets/f9ab5d9163148ceb211e5b4f15a3d8e0-Dtqse-AT.woff2 +0 -0
- package/dist/ui/assets/fa69ce224ff0a6c0ff97b10a829779c2-pX45dCNY.woff2 +0 -0
- package/dist/ui/assets/fc38d1da3930d39dd8e286f708105765-DmbOHwTI.woff2 +0 -0
- package/dist/ui/assets/fe03c1dfaffc1cad3521fe55f1541d6b-BW8aEqCj.woff2 +0 -0
- package/dist/ui/assets/fe0b2421eb4d1f4f8949c602871a317c-BsBLV6jH.woff2 +0 -0
- package/dist/ui/assets/fe9c75d0cb3d808023412d26dfc9d388-eXjcgUPI.woff2 +0 -0
- package/dist/ui/assets/index-B61V60w_.js +19 -0
- package/dist/ui/assets/index-bkyxJG8J.css +1 -0
- package/dist/ui/assets/theme-BNq4FkXS.js +1 -0
- package/dist/ui/index.html +52 -0
- package/dist/webui.js +21 -0
- package/docs/backend.md +260 -0
- package/docs/frontend.md +125 -0
- package/docs/remix-icon-license.txt +186 -0
- package/docs/usage.md +227 -0
- package/package.json +82 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { windowsSystemExecutable } from "../process.js";
|
|
2
|
+
import { formatHostPort, normalizeEnableOptions, parseProxyString, runCmd } from "./common.js";
|
|
3
|
+
import { windowsSnapshot } from "./snapshot.js";
|
|
4
|
+
import { DEFAULT_BYPASS_LIST, SYSTEM_PROXY_SNAPSHOT_VERSION } from "./types.js";
|
|
5
|
+
const WIN_REG_PATH = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
|
|
6
|
+
const REGISTRY_HEADERS = new Set([WIN_REG_PATH, WIN_REG_PATH.replace(/^HKCU/, "HKEY_CURRENT_USER")].map((header) => header.toLowerCase()));
|
|
7
|
+
const MANAGED_VALUE_LINE = /^[^\S\r\n]*(ProxyEnable|ProxyServer|ProxyOverride|AutoConfigURL|AutoDetect)[^\S\r\n]+(REG_[A-Z0-9_]+)(?:[^\S\r\n]+(.*))?[^\S\r\n]*$/i;
|
|
8
|
+
const MANAGED_VALUE_PREFIX = /^[^\S\r\n]*(?:ProxyEnable|ProxyServer|ProxyOverride|AutoConfigURL|AutoDetect)(?:[^\S\r\n]|$)/i;
|
|
9
|
+
const GENERIC_REGISTRY_VALUE_LINE = /^[^\S\r\n]*.+?[^\S\r\n]+REG_[A-Z0-9_]+(?:[^\S\r\n]+.*)?[^\S\r\n]*$/i;
|
|
10
|
+
export function formatWindowsBypass(list = DEFAULT_BYPASS_LIST) {
|
|
11
|
+
return list.join(";");
|
|
12
|
+
}
|
|
13
|
+
function emptyWindowsRegistryProxyValues() {
|
|
14
|
+
return {
|
|
15
|
+
proxyEnable: null,
|
|
16
|
+
proxyServer: null,
|
|
17
|
+
proxyOverride: null,
|
|
18
|
+
autoConfigUrl: null,
|
|
19
|
+
autoDetect: null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function setWindowsRegistryProxyValue(values, seen, name, type, rawValue) {
|
|
23
|
+
if (seen.has(name)) {
|
|
24
|
+
throw new Error(`Invalid Windows registry output: duplicate ${name} value`);
|
|
25
|
+
}
|
|
26
|
+
seen.add(name);
|
|
27
|
+
if (name === "proxyenable" || name === "autodetect") {
|
|
28
|
+
if (type !== "REG_DWORD") {
|
|
29
|
+
throw new Error(`Invalid Windows registry output: ${name} must be REG_DWORD`);
|
|
30
|
+
}
|
|
31
|
+
const text = rawValue.trim();
|
|
32
|
+
if (!/^(?:0x[0-9a-f]+|\d+)$/i.test(text)) {
|
|
33
|
+
throw new Error(`Invalid Windows registry output: ${name} has an invalid DWORD value`);
|
|
34
|
+
}
|
|
35
|
+
const value = Number.parseInt(text, text.toLowerCase().startsWith("0x") ? 16 : 10);
|
|
36
|
+
if (!Number.isInteger(value) || value < 0 || value > 0xffff_ffff) {
|
|
37
|
+
throw new Error(`Invalid Windows registry output: ${name} is outside DWORD range`);
|
|
38
|
+
}
|
|
39
|
+
if (name === "proxyenable")
|
|
40
|
+
values.proxyEnable = value;
|
|
41
|
+
else
|
|
42
|
+
values.autoDetect = value;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (type !== "REG_SZ") {
|
|
46
|
+
throw new Error(`Invalid Windows registry output: ${name} must be REG_SZ`);
|
|
47
|
+
}
|
|
48
|
+
const value = parseProxyString(rawValue.replace(/\r$/, ""), name);
|
|
49
|
+
if (name === "proxyserver") {
|
|
50
|
+
values.proxyServer = value;
|
|
51
|
+
}
|
|
52
|
+
else if (name === "proxyoverride") {
|
|
53
|
+
values.proxyOverride = value;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
values.autoConfigUrl = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function parseManagedWindowsRegistryValue(line, values, seen) {
|
|
60
|
+
const match = line.match(MANAGED_VALUE_LINE);
|
|
61
|
+
if (!match)
|
|
62
|
+
return false;
|
|
63
|
+
const name = match[1]?.toLowerCase();
|
|
64
|
+
const type = match[2]?.toUpperCase();
|
|
65
|
+
if (!name || !type) {
|
|
66
|
+
throw new Error("Invalid Windows registry output: malformed managed value");
|
|
67
|
+
}
|
|
68
|
+
setWindowsRegistryProxyValue(values, seen, name, type, match[3] ?? "");
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
export function parseWindowsRegistryProxyValues(output) {
|
|
72
|
+
const lines = output.split(/\r\n?|\n/);
|
|
73
|
+
let headerIndex = 0;
|
|
74
|
+
while (headerIndex < lines.length && (lines[headerIndex] ?? "").trim().length === 0) {
|
|
75
|
+
headerIndex++;
|
|
76
|
+
}
|
|
77
|
+
if (!REGISTRY_HEADERS.has((lines[headerIndex] ?? "").trim().toLowerCase())) {
|
|
78
|
+
throw new Error("Invalid Windows registry output: missing Internet Settings registry header");
|
|
79
|
+
}
|
|
80
|
+
const values = emptyWindowsRegistryProxyValues();
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
const headerText = (lines[headerIndex] ?? "").trim().toLowerCase();
|
|
83
|
+
for (let index = headerIndex + 1; index < lines.length; index++) {
|
|
84
|
+
const line = lines[index] ?? "";
|
|
85
|
+
if (line.trim().length === 0)
|
|
86
|
+
continue;
|
|
87
|
+
if (!line.startsWith(" ") && !line.startsWith("\t")) {
|
|
88
|
+
if (line.trim().toLowerCase().startsWith(`${headerText}\\`))
|
|
89
|
+
break;
|
|
90
|
+
throw new Error("Invalid Windows registry output: unexpected line in registry response");
|
|
91
|
+
}
|
|
92
|
+
if (parseManagedWindowsRegistryValue(line, values, seen))
|
|
93
|
+
continue;
|
|
94
|
+
if (MANAGED_VALUE_PREFIX.test(line)) {
|
|
95
|
+
throw new Error("Invalid Windows registry output: malformed managed value");
|
|
96
|
+
}
|
|
97
|
+
if (!GENERIC_REGISTRY_VALUE_LINE.test(line)) {
|
|
98
|
+
throw new Error("Invalid Windows registry output: unexpected line in registry response");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (seen.size === 0) {
|
|
102
|
+
throw new Error("Invalid Windows registry output: missing managed proxy values");
|
|
103
|
+
}
|
|
104
|
+
return values;
|
|
105
|
+
}
|
|
106
|
+
export async function captureWindowsSnapshot(run = runCmd) {
|
|
107
|
+
const values = parseWindowsRegistryProxyValues(await run("reg.exe", ["query", WIN_REG_PATH]));
|
|
108
|
+
return {
|
|
109
|
+
version: SYSTEM_PROXY_SNAPSHOT_VERSION,
|
|
110
|
+
platform: "win32",
|
|
111
|
+
proxyEnable: values.proxyEnable,
|
|
112
|
+
proxyServer: values.proxyServer,
|
|
113
|
+
proxyOverride: values.proxyOverride,
|
|
114
|
+
autoConfigUrl: values.autoConfigUrl,
|
|
115
|
+
autoDetect: values.autoDetect,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function refreshWindowsWinINet(run) {
|
|
119
|
+
const script = [
|
|
120
|
+
'$signature = @"',
|
|
121
|
+
'[DllImport("wininet.dll", SetLastError = true)]',
|
|
122
|
+
"public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);",
|
|
123
|
+
'"@',
|
|
124
|
+
"$type = Add-Type -MemberDefinition $signature -Name WinINet -Namespace Interop -PassThru -ErrorAction SilentlyContinue",
|
|
125
|
+
"if ($type) {",
|
|
126
|
+
" [Interop.WinINet]::InternetSetOption([IntPtr]::Zero, 39, [IntPtr]::Zero, 0) | Out-Null",
|
|
127
|
+
" [Interop.WinINet]::InternetSetOption([IntPtr]::Zero, 37, [IntPtr]::Zero, 0) | Out-Null",
|
|
128
|
+
"}",
|
|
129
|
+
].join("\n");
|
|
130
|
+
try {
|
|
131
|
+
await run(windowsSystemExecutable("WindowsPowerShell/v1.0/powershell.exe"), [
|
|
132
|
+
"-NoProfile",
|
|
133
|
+
"-NonInteractive",
|
|
134
|
+
"-Command",
|
|
135
|
+
script,
|
|
136
|
+
]);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function windowsSnapshotValue(snapshot, name) {
|
|
142
|
+
switch (name) {
|
|
143
|
+
case "ProxyEnable":
|
|
144
|
+
return snapshot.proxyEnable;
|
|
145
|
+
case "ProxyServer":
|
|
146
|
+
return snapshot.proxyServer;
|
|
147
|
+
case "ProxyOverride":
|
|
148
|
+
return snapshot.proxyOverride;
|
|
149
|
+
case "AutoConfigURL":
|
|
150
|
+
return snapshot.autoConfigUrl;
|
|
151
|
+
case "AutoDetect":
|
|
152
|
+
return snapshot.autoDetect;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function deleteWindowsValue(name, run) {
|
|
156
|
+
try {
|
|
157
|
+
await run("reg.exe", ["delete", WIN_REG_PATH, "/v", name, "/f"]);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const current = await captureWindowsSnapshot(run);
|
|
161
|
+
if (windowsSnapshotValue(current, name) !== null)
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function applyWindowsValue(name, type, value, run) {
|
|
166
|
+
if (value === null) {
|
|
167
|
+
await deleteWindowsValue(name, run);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
await run("reg.exe", ["add", WIN_REG_PATH, "/v", name, "/t", type, "/d", String(value), "/f"]);
|
|
171
|
+
}
|
|
172
|
+
export async function applyWindowsSnapshot(value, run = runCmd) {
|
|
173
|
+
const snapshot = windowsSnapshot(value);
|
|
174
|
+
try {
|
|
175
|
+
await applyWindowsValue("AutoConfigURL", "REG_SZ", snapshot.autoConfigUrl, run);
|
|
176
|
+
await applyWindowsValue("ProxyServer", "REG_SZ", snapshot.proxyServer, run);
|
|
177
|
+
await applyWindowsValue("ProxyOverride", "REG_SZ", snapshot.proxyOverride, run);
|
|
178
|
+
await applyWindowsValue("ProxyEnable", "REG_DWORD", snapshot.proxyEnable, run);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await refreshWindowsWinINet(run);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export function createWindowsTarget(original, opts) {
|
|
185
|
+
windowsSnapshot(original);
|
|
186
|
+
const normalized = normalizeEnableOptions(opts);
|
|
187
|
+
return {
|
|
188
|
+
version: SYSTEM_PROXY_SNAPSHOT_VERSION,
|
|
189
|
+
platform: "win32",
|
|
190
|
+
proxyEnable: 1,
|
|
191
|
+
proxyServer: formatHostPort(normalized.host, normalized.port),
|
|
192
|
+
proxyOverride: formatWindowsBypass(normalized.bypass),
|
|
193
|
+
autoConfigUrl: null,
|
|
194
|
+
autoDetect: null,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
export function windowsState(value) {
|
|
198
|
+
const snapshot = windowsSnapshot(value);
|
|
199
|
+
const enabled = snapshot.proxyEnable === 1;
|
|
200
|
+
if (enabled) {
|
|
201
|
+
return snapshot.proxyServer
|
|
202
|
+
? { supported: true, enabled: true, server: snapshot.proxyServer }
|
|
203
|
+
: { supported: true, enabled: true, details: "manual proxy has no server" };
|
|
204
|
+
}
|
|
205
|
+
if (snapshot.autoConfigUrl || snapshot.autoDetect === 1) {
|
|
206
|
+
return {
|
|
207
|
+
supported: true,
|
|
208
|
+
enabled: true,
|
|
209
|
+
...(snapshot.autoConfigUrl ? { server: snapshot.autoConfigUrl } : {}),
|
|
210
|
+
details: snapshot.autoConfigUrl
|
|
211
|
+
? "automatic proxy configuration is enabled"
|
|
212
|
+
: "automatic proxy detection is enabled",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return { supported: true, enabled: false };
|
|
216
|
+
}
|
package/dist/sysproxy.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { isSystemProxySupported } from "./sysproxy/common.js";
|
|
2
|
+
export { parseDarwinAutoProxySetting, parseDarwinProxySetting, parseDarwinServices, } from "./sysproxy/darwin.js";
|
|
3
|
+
export { createSystemProxyBackend } from "./sysproxy/factory.js";
|
|
4
|
+
export { parseGSettingsPort, parseGSettingsString } from "./sysproxy/gnome.js";
|
|
5
|
+
export { createLegacyProxyCleanup, disableLegacySystemProxyIfOwned, } from "./sysproxy/legacy.js";
|
|
6
|
+
export { isSystemProxySnapshot, parseSystemProxySnapshot } from "./sysproxy/snapshot.js";
|
|
7
|
+
export { DEFAULT_BYPASS_LIST, SYSTEM_PROXY_SNAPSHOT_VERSION } from "./sysproxy/types.js";
|
|
8
|
+
export { formatWindowsBypass, parseWindowsRegistryProxyValues, } from "./sysproxy/windows.js";
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { errnoCode, errorMessage } from "./error-utils.js";
|
|
3
|
+
import { atomicWriteFileSync } from "./fs-atomic.js";
|
|
4
|
+
import { hasExactOwnKeys, isCanonicalIsoTimestamp, isPlainObject } from "./json-shape.js";
|
|
5
|
+
import { sashLayout } from "./paths.js";
|
|
6
|
+
import { withStateLock } from "./state-lock.js";
|
|
7
|
+
import { createSystemProxyBackend, isSystemProxySupported, parseSystemProxySnapshot, } from "./sysproxy.js";
|
|
8
|
+
const MAX_JOURNAL_BYTES = 256 * 1024;
|
|
9
|
+
function journalError(message) {
|
|
10
|
+
return new Error(`Invalid system proxy journal: ${message}`);
|
|
11
|
+
}
|
|
12
|
+
function hasExactKeys(value, keys) {
|
|
13
|
+
if (!isPlainObject(value))
|
|
14
|
+
throw journalError("root must be a plain object");
|
|
15
|
+
if (!hasExactOwnKeys(value, keys))
|
|
16
|
+
throw journalError("root has unexpected fields");
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function sameDarwinServiceCollection(a, b) {
|
|
20
|
+
if (a.platform !== "darwin" || b.platform !== "darwin")
|
|
21
|
+
return false;
|
|
22
|
+
if (a.services.length !== b.services.length)
|
|
23
|
+
return false;
|
|
24
|
+
return a.services.every((service, index) => service.service === b.services[index]?.service);
|
|
25
|
+
}
|
|
26
|
+
function journalSnapshotsHaveSameStructure(original, target) {
|
|
27
|
+
if (original.platform !== target.platform)
|
|
28
|
+
return false;
|
|
29
|
+
if (original.platform === "darwin" && target.platform === "darwin") {
|
|
30
|
+
return sameDarwinServiceCollection(original, target);
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
function parseCreatedAt(value) {
|
|
35
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 128) {
|
|
36
|
+
throw journalError("createdAt must be a non-empty ISO timestamp");
|
|
37
|
+
}
|
|
38
|
+
if (!isCanonicalIsoTimestamp(value)) {
|
|
39
|
+
throw journalError("createdAt must be a canonical ISO timestamp");
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
export function parseSystemProxyJournal(value) {
|
|
44
|
+
const record = hasExactKeys(value, [
|
|
45
|
+
"schemaVersion",
|
|
46
|
+
"phase",
|
|
47
|
+
"ownerPid",
|
|
48
|
+
"createdAt",
|
|
49
|
+
"original",
|
|
50
|
+
"target",
|
|
51
|
+
]);
|
|
52
|
+
if (record.schemaVersion !== 1 && record.schemaVersion !== 2) {
|
|
53
|
+
throw journalError("schemaVersion must be 1 or 2");
|
|
54
|
+
}
|
|
55
|
+
if (record.phase !== "prepared" &&
|
|
56
|
+
record.phase !== "applied" &&
|
|
57
|
+
!(record.schemaVersion === 2 && record.phase === "restoring")) {
|
|
58
|
+
throw journalError("phase must be prepared, applied, or restoring");
|
|
59
|
+
}
|
|
60
|
+
if (typeof record.ownerPid !== "number" ||
|
|
61
|
+
!Number.isSafeInteger(record.ownerPid) ||
|
|
62
|
+
record.ownerPid <= 0) {
|
|
63
|
+
throw journalError("ownerPid must be a positive integer");
|
|
64
|
+
}
|
|
65
|
+
let original;
|
|
66
|
+
let target;
|
|
67
|
+
try {
|
|
68
|
+
original = parseSystemProxySnapshot(record.original);
|
|
69
|
+
target = parseSystemProxySnapshot(record.target);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
throw journalError(errorMessage(err));
|
|
73
|
+
}
|
|
74
|
+
if (!journalSnapshotsHaveSameStructure(original, target)) {
|
|
75
|
+
throw journalError("original and target have different platform structures");
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
schemaVersion: 2,
|
|
79
|
+
phase: record.phase,
|
|
80
|
+
ownerPid: record.ownerPid,
|
|
81
|
+
createdAt: parseCreatedAt(record.createdAt),
|
|
82
|
+
original,
|
|
83
|
+
target,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function sameJournal(a, b) {
|
|
87
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
88
|
+
}
|
|
89
|
+
function sameJournalOwnership(a, b) {
|
|
90
|
+
return (a.schemaVersion === b.schemaVersion &&
|
|
91
|
+
a.ownerPid === b.ownerPid &&
|
|
92
|
+
a.createdAt === b.createdAt &&
|
|
93
|
+
JSON.stringify(a.original) === JSON.stringify(b.original) &&
|
|
94
|
+
JSON.stringify(a.target) === JSON.stringify(b.target));
|
|
95
|
+
}
|
|
96
|
+
function combinedError(primary, recovery) {
|
|
97
|
+
return new Error(`${errorMessage(primary)}; conditional restoration failed: ${errorMessage(recovery)}`);
|
|
98
|
+
}
|
|
99
|
+
export class SystemProxyManager {
|
|
100
|
+
layout;
|
|
101
|
+
backend;
|
|
102
|
+
operationLockFile;
|
|
103
|
+
operationQueue = Promise.resolve();
|
|
104
|
+
inspectionGeneration = 0;
|
|
105
|
+
inspectionCache;
|
|
106
|
+
inspectionInFlight;
|
|
107
|
+
constructor(options = {}, ...unexpected) {
|
|
108
|
+
if (typeof options !== "object" ||
|
|
109
|
+
options === null ||
|
|
110
|
+
Array.isArray(options) ||
|
|
111
|
+
unexpected.length > 0 ||
|
|
112
|
+
"systemProxyStateFile" in options) {
|
|
113
|
+
throw new Error("SystemProxyManager requires an options object with layout and backend fields");
|
|
114
|
+
}
|
|
115
|
+
this.layout = options.layout ?? sashLayout();
|
|
116
|
+
this.backend = options.backend ?? createSystemProxyBackend();
|
|
117
|
+
if (!this.layout.systemProxyStateFile) {
|
|
118
|
+
throw new Error("System proxy journal requires a systemProxyStateFile path");
|
|
119
|
+
}
|
|
120
|
+
this.operationLockFile = `${this.layout.systemProxyStateFile}.lock`;
|
|
121
|
+
}
|
|
122
|
+
apply(opts) {
|
|
123
|
+
this.invalidateInspection();
|
|
124
|
+
return this.enqueue(async () => {
|
|
125
|
+
try {
|
|
126
|
+
await withStateLock(this.operationLockFile, { purpose: "apply system proxy", timeoutMs: 30_000 }, () => this.applyUnlocked(opts));
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
this.invalidateInspection();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
release() {
|
|
134
|
+
this.invalidateInspection();
|
|
135
|
+
return this.enqueue(async () => {
|
|
136
|
+
try {
|
|
137
|
+
await withStateLock(this.operationLockFile, { purpose: "restore system proxy", timeoutMs: 30_000 }, () => this.recoverUnlocked());
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
this.invalidateInspection();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
inspect(fresh = false) {
|
|
145
|
+
const generation = this.inspectionGeneration;
|
|
146
|
+
if (!fresh &&
|
|
147
|
+
this.inspectionCache?.generation === generation &&
|
|
148
|
+
this.inspectionCache.expiresAt > Date.now()) {
|
|
149
|
+
return Promise.resolve(this.inspectionCache.inspection);
|
|
150
|
+
}
|
|
151
|
+
if (this.inspectionInFlight?.generation === generation) {
|
|
152
|
+
return this.inspectionInFlight.promise;
|
|
153
|
+
}
|
|
154
|
+
const promise = this.enqueue(async () => {
|
|
155
|
+
const result = await this.inspectUncached();
|
|
156
|
+
if (result.journalStable && this.inspectionGeneration === generation) {
|
|
157
|
+
this.inspectionCache = {
|
|
158
|
+
generation,
|
|
159
|
+
expiresAt: Date.now() + 3000,
|
|
160
|
+
inspection: result.inspection,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return result.inspection;
|
|
164
|
+
});
|
|
165
|
+
this.inspectionInFlight = { generation, promise };
|
|
166
|
+
const clearInFlight = () => {
|
|
167
|
+
if (this.inspectionInFlight?.generation === generation &&
|
|
168
|
+
this.inspectionInFlight.promise === promise) {
|
|
169
|
+
this.inspectionInFlight = undefined;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
void promise.then(clearInFlight, clearInFlight);
|
|
173
|
+
return promise;
|
|
174
|
+
}
|
|
175
|
+
async isApplied() {
|
|
176
|
+
return (await this.inspect()).applied;
|
|
177
|
+
}
|
|
178
|
+
async getState() {
|
|
179
|
+
return (await this.inspect()).state;
|
|
180
|
+
}
|
|
181
|
+
invalidateInspection() {
|
|
182
|
+
this.inspectionGeneration += 1;
|
|
183
|
+
this.inspectionCache = undefined;
|
|
184
|
+
}
|
|
185
|
+
observeJournal() {
|
|
186
|
+
try {
|
|
187
|
+
return { kind: "read", journal: this.readJournal() };
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
return { kind: "error", error };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
sameJournalObservation(left, right) {
|
|
194
|
+
if (left.kind === "error" || right.kind === "error") {
|
|
195
|
+
return (left.kind === "error" &&
|
|
196
|
+
right.kind === "error" &&
|
|
197
|
+
errorMessage(left.error) === errorMessage(right.error));
|
|
198
|
+
}
|
|
199
|
+
if (!left.journal || !right.journal)
|
|
200
|
+
return left.journal === right.journal;
|
|
201
|
+
return sameJournal(left.journal, right.journal);
|
|
202
|
+
}
|
|
203
|
+
inspectionMessages(before, after, captureError) {
|
|
204
|
+
const messages = [];
|
|
205
|
+
const add = (error) => {
|
|
206
|
+
const message = errorMessage(error) || "unknown error";
|
|
207
|
+
if (!messages.includes(message))
|
|
208
|
+
messages.push(message);
|
|
209
|
+
};
|
|
210
|
+
if (before.kind === "error")
|
|
211
|
+
add(before.error);
|
|
212
|
+
if (after.kind === "error")
|
|
213
|
+
add(after.error);
|
|
214
|
+
if (!this.sameJournalObservation(before, after)) {
|
|
215
|
+
add(new Error("System proxy journal changed during inspection"));
|
|
216
|
+
}
|
|
217
|
+
if (captureError)
|
|
218
|
+
add(captureError.error);
|
|
219
|
+
return messages;
|
|
220
|
+
}
|
|
221
|
+
async inspectAttempt() {
|
|
222
|
+
const before = this.observeJournal();
|
|
223
|
+
let current;
|
|
224
|
+
let state;
|
|
225
|
+
try {
|
|
226
|
+
current = await this.captureCurrent();
|
|
227
|
+
state = this.backend.state(current);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const after = this.observeJournal();
|
|
231
|
+
const messages = this.inspectionMessages(before, after, { caught: true, error });
|
|
232
|
+
const queryError = messages.join("; ");
|
|
233
|
+
return {
|
|
234
|
+
journalStable: this.sameJournalObservation(before, after),
|
|
235
|
+
inspection: {
|
|
236
|
+
applied: false,
|
|
237
|
+
state: {
|
|
238
|
+
supported: this.backend.supported ?? isSystemProxySupported(),
|
|
239
|
+
enabled: false,
|
|
240
|
+
details: queryError,
|
|
241
|
+
},
|
|
242
|
+
appliedKnown: false,
|
|
243
|
+
stateKnown: false,
|
|
244
|
+
queryError,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const after = this.observeJournal();
|
|
249
|
+
const journalStable = this.sameJournalObservation(before, after);
|
|
250
|
+
const messages = this.inspectionMessages(before, after);
|
|
251
|
+
if (messages.length > 0) {
|
|
252
|
+
state.details = [state.details, ...messages].filter(Boolean).join("; ");
|
|
253
|
+
}
|
|
254
|
+
const journal = journalStable && before.kind === "read" && after.kind === "read" ? after.journal : undefined;
|
|
255
|
+
const appliedKnown = journalStable && messages.length === 0;
|
|
256
|
+
const queryError = messages.join("; ");
|
|
257
|
+
return {
|
|
258
|
+
journalStable,
|
|
259
|
+
inspection: {
|
|
260
|
+
applied: appliedKnown &&
|
|
261
|
+
journal?.phase === "applied" &&
|
|
262
|
+
this.backend.equivalent(current, journal.target),
|
|
263
|
+
state,
|
|
264
|
+
appliedKnown,
|
|
265
|
+
stateKnown: true,
|
|
266
|
+
...(queryError ? { queryError } : {}),
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
async inspectUncached() {
|
|
271
|
+
const first = await this.inspectAttempt();
|
|
272
|
+
return first.journalStable ? first : this.inspectAttempt();
|
|
273
|
+
}
|
|
274
|
+
enqueue(operation) {
|
|
275
|
+
const next = this.operationQueue.then(operation, operation);
|
|
276
|
+
this.operationQueue = next.then(() => undefined, () => undefined);
|
|
277
|
+
return next;
|
|
278
|
+
}
|
|
279
|
+
readJournal() {
|
|
280
|
+
const file = this.layout.systemProxyStateFile;
|
|
281
|
+
let stats;
|
|
282
|
+
try {
|
|
283
|
+
stats = fs.lstatSync(file);
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
if (errnoCode(err) === "ENOENT")
|
|
287
|
+
return undefined;
|
|
288
|
+
throw new Error(`Could not inspect system proxy journal ${file}: ${errorMessage(err)}`);
|
|
289
|
+
}
|
|
290
|
+
if (!stats.isFile()) {
|
|
291
|
+
throw new Error(`System proxy journal is not a regular file: ${file}`);
|
|
292
|
+
}
|
|
293
|
+
if (stats.size > MAX_JOURNAL_BYTES) {
|
|
294
|
+
throw new Error(`System proxy journal is too large: ${file}`);
|
|
295
|
+
}
|
|
296
|
+
let text;
|
|
297
|
+
try {
|
|
298
|
+
text = fs.readFileSync(file, "utf8");
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (errnoCode(err) === "ENOENT")
|
|
302
|
+
return undefined;
|
|
303
|
+
throw new Error(`Could not read system proxy journal ${file}: ${errorMessage(err)}`);
|
|
304
|
+
}
|
|
305
|
+
let document;
|
|
306
|
+
try {
|
|
307
|
+
document = JSON.parse(text);
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
throw new Error(`System proxy journal is invalid: ${file}: ${errorMessage(err)}`);
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
return parseSystemProxyJournal(document);
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
throw new Error(`System proxy journal is invalid: ${file}: ${errorMessage(err)}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
writeNewJournal(journal) {
|
|
320
|
+
const existing = this.readJournal();
|
|
321
|
+
if (existing) {
|
|
322
|
+
throw new Error(`System proxy journal already exists: ${this.layout.systemProxyStateFile}`);
|
|
323
|
+
}
|
|
324
|
+
const canonical = parseSystemProxyJournal(journal);
|
|
325
|
+
this.writeJournal(canonical);
|
|
326
|
+
}
|
|
327
|
+
writeJournal(journal) {
|
|
328
|
+
const text = `${JSON.stringify(journal, null, 2)}\n`;
|
|
329
|
+
if (Buffer.byteLength(text) > MAX_JOURNAL_BYTES) {
|
|
330
|
+
throw new Error(`System proxy journal exceeds its size limit: ${this.layout.systemProxyStateFile}`);
|
|
331
|
+
}
|
|
332
|
+
atomicWriteFileSync(this.layout.systemProxyStateFile, text, 0o600);
|
|
333
|
+
}
|
|
334
|
+
replaceJournal(expected, next) {
|
|
335
|
+
const existing = this.readJournal();
|
|
336
|
+
if (!existing || !sameJournal(existing, expected)) {
|
|
337
|
+
throw new Error(`System proxy journal changed while applying: ${this.layout.systemProxyStateFile}`);
|
|
338
|
+
}
|
|
339
|
+
const canonical = parseSystemProxyJournal(next);
|
|
340
|
+
this.writeJournal(canonical);
|
|
341
|
+
}
|
|
342
|
+
clearJournal(expected) {
|
|
343
|
+
const existing = this.readJournal();
|
|
344
|
+
if (!existing || !sameJournalOwnership(existing, expected)) {
|
|
345
|
+
throw new Error(`System proxy journal changed while restoring: ${this.layout.systemProxyStateFile}`);
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
fs.unlinkSync(this.layout.systemProxyStateFile);
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
if (errnoCode(err) === "ENOENT") {
|
|
352
|
+
throw new Error(`System proxy journal changed while restoring: ${this.layout.systemProxyStateFile}`);
|
|
353
|
+
}
|
|
354
|
+
throw new Error(`Could not remove system proxy journal: ${errorMessage(err)}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async captureCurrent() {
|
|
358
|
+
return parseSystemProxySnapshot(await this.backend.capture());
|
|
359
|
+
}
|
|
360
|
+
async applyUnlocked(opts) {
|
|
361
|
+
const previous = this.readJournal();
|
|
362
|
+
if (previous) {
|
|
363
|
+
const desiredTarget = parseSystemProxySnapshot(this.backend.createTarget(previous.original, opts));
|
|
364
|
+
const current = await this.captureCurrent();
|
|
365
|
+
if (previous.phase === "applied" &&
|
|
366
|
+
this.backend.equivalent(previous.target, desiredTarget) &&
|
|
367
|
+
this.backend.equivalent(current, previous.target)) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
await this.restoreJournal(previous);
|
|
371
|
+
}
|
|
372
|
+
const original = await this.captureCurrent();
|
|
373
|
+
const target = parseSystemProxySnapshot(this.backend.createTarget(original, opts));
|
|
374
|
+
if (!journalSnapshotsHaveSameStructure(original, target)) {
|
|
375
|
+
throw new Error("System proxy backend produced a target with a different platform structure");
|
|
376
|
+
}
|
|
377
|
+
const prepared = {
|
|
378
|
+
schemaVersion: 2,
|
|
379
|
+
phase: "prepared",
|
|
380
|
+
ownerPid: process.pid,
|
|
381
|
+
createdAt: new Date().toISOString(),
|
|
382
|
+
original,
|
|
383
|
+
target,
|
|
384
|
+
};
|
|
385
|
+
this.writeNewJournal(prepared);
|
|
386
|
+
const beforeApply = await this.captureCurrent();
|
|
387
|
+
if (!this.backend.equivalent(beforeApply, original)) {
|
|
388
|
+
this.clearJournal(prepared);
|
|
389
|
+
throw new Error("System proxy settings changed while Sash was preparing ownership; refusing to overwrite them");
|
|
390
|
+
}
|
|
391
|
+
let activeJournal = prepared;
|
|
392
|
+
try {
|
|
393
|
+
await this.backend.apply(target);
|
|
394
|
+
const current = await this.captureCurrent();
|
|
395
|
+
if (!this.backend.equivalent(current, target)) {
|
|
396
|
+
throw new Error("System proxy target verification failed after apply");
|
|
397
|
+
}
|
|
398
|
+
const applied = { ...prepared, phase: "applied" };
|
|
399
|
+
this.replaceJournal(prepared, applied);
|
|
400
|
+
activeJournal = applied;
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
try {
|
|
404
|
+
await this.restoreJournal(activeJournal);
|
|
405
|
+
}
|
|
406
|
+
catch (restoreErr) {
|
|
407
|
+
throw combinedError(err, restoreErr);
|
|
408
|
+
}
|
|
409
|
+
throw err;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
async recoverUnlocked() {
|
|
413
|
+
const journal = this.readJournal();
|
|
414
|
+
if (!journal)
|
|
415
|
+
return;
|
|
416
|
+
await this.restoreJournal(journal);
|
|
417
|
+
}
|
|
418
|
+
async restoreJournal(journal) {
|
|
419
|
+
const current = await this.captureCurrent();
|
|
420
|
+
if (this.backend.equivalent(current, journal.original)) {
|
|
421
|
+
this.clearJournal(journal);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const canRestore = this.backend.equivalent(current, journal.target) ||
|
|
425
|
+
((journal.phase === "prepared" || journal.phase === "restoring") &&
|
|
426
|
+
this.backend.compatible(current, journal.original, journal.target));
|
|
427
|
+
if (!canRestore) {
|
|
428
|
+
throw new Error("System proxy journal refuses to restore because current settings were modified outside Sash");
|
|
429
|
+
}
|
|
430
|
+
const restoring = journal.phase === "restoring" ? journal : { ...journal, phase: "restoring" };
|
|
431
|
+
if (restoring !== journal)
|
|
432
|
+
this.replaceJournal(journal, restoring);
|
|
433
|
+
let applyResult = {
|
|
434
|
+
ok: true,
|
|
435
|
+
};
|
|
436
|
+
try {
|
|
437
|
+
await this.backend.apply(restoring.original);
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
applyResult = { ok: false, error };
|
|
441
|
+
}
|
|
442
|
+
let restored;
|
|
443
|
+
try {
|
|
444
|
+
restored = await this.captureCurrent();
|
|
445
|
+
}
|
|
446
|
+
catch (err) {
|
|
447
|
+
const verificationError = new Error(`Could not verify system proxy restoration: ${errorMessage(err)}`);
|
|
448
|
+
throw applyResult.ok
|
|
449
|
+
? verificationError
|
|
450
|
+
: combinedError(applyResult.error, verificationError);
|
|
451
|
+
}
|
|
452
|
+
if (!this.backend.equivalent(restored, restoring.original)) {
|
|
453
|
+
const verificationError = new Error("System proxy restoration verification failed");
|
|
454
|
+
throw applyResult.ok
|
|
455
|
+
? verificationError
|
|
456
|
+
: combinedError(applyResult.error, verificationError);
|
|
457
|
+
}
|
|
458
|
+
this.clearJournal(restoring);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function quotePosix(value) {
|
|
2
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
3
|
+
}
|
|
4
|
+
export function tunPrivilegeGuidance(context, options) {
|
|
5
|
+
const platform = options.platform ?? process.platform;
|
|
6
|
+
const prepare = context === "activation-rolled-back" ? 'Run "sash config set tun on" first. ' : "";
|
|
7
|
+
if (platform === "win32") {
|
|
8
|
+
return `${prepare}Open PowerShell as Administrator and run "sash restart". If SASH_HOME was explicitly customized, set the same value in that shell first. If Sash was already elevated, inspect the Core error log.`;
|
|
9
|
+
}
|
|
10
|
+
return `${prepare}Restart Sash with root privileges using the same data directory: sudo env SASH_HOME=${quotePosix(options.root)} "$(command -v sash)" restart. If Sash was already elevated, inspect the Core error log.`;
|
|
11
|
+
}
|