@wtfalch/desktop 0.1.0 → 0.1.2
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/README.md +9 -6
- package/package.json +1 -1
- package/src/access.mjs +34 -0
- package/src/shell.mjs +13 -3
package/README.md
CHANGED
|
@@ -97,15 +97,18 @@ Cloudflare Access answers a request without a `CF_Authorization` cookie with a
|
|
|
97
97
|
redirect to `*.cloudflareaccess.com`. The cookie lives in the company partition,
|
|
98
98
|
so:
|
|
99
99
|
|
|
100
|
-
1. Every request the shell makes to the origin after the window exists
|
|
101
|
-
|
|
102
|
-
`credentials: 'include'` (`partitionFetcher`).
|
|
103
|
-
|
|
100
|
+
1. Every request the shell makes to the origin after the window exists goes
|
|
101
|
+
through that partition. The redeem and logout use its `session.fetch` with
|
|
102
|
+
`credentials: 'include'` (`partitionFetcher`). The Access probe uses
|
|
103
|
+
`net.request` on the same session with its cookies (`manualRedirectFetcher`),
|
|
104
|
+
because `session.fetch` rejects a `redirect: 'manual'` request that meets a
|
|
105
|
+
3xx with "Redirect was cancelled" (Electron 44.4.5), which would read Access's
|
|
106
|
+
own 302 as offline. Global `fetch` is never used for them; `DesktopLogin` has
|
|
107
|
+
no default fetcher.
|
|
104
108
|
2. With `accessProbePath: '/api/health'`, before the system-browser sign-in starts (and
|
|
105
109
|
before a stored company loads) the shell asks the origin through the
|
|
106
110
|
partition with `redirect: 'manual'`, deciding from status and `Location`
|
|
107
|
-
only (
|
|
108
|
-
read). A non-3xx answer, or a 3xx back to the origin itself, is a pass; a 3xx
|
|
111
|
+
only (the `redirect` event names the target before anything is followed). A non-3xx answer, or a 3xx back to the origin itself, is a pass; a 3xx
|
|
109
112
|
to any other host (Access, or an identity provider) is not. A network failure
|
|
110
113
|
is not an Access answer: the window shows the "Could not reach" screen with
|
|
111
114
|
Try again. When Access wants a login, the window shows the origin so the person passes
|
package/package.json
CHANGED
package/src/access.mjs
CHANGED
|
@@ -51,6 +51,40 @@ export function accessNavigation(value, origin) {
|
|
|
51
51
|
export const partitionFetcher = (partition) => (url, init) =>
|
|
52
52
|
partition.fetch(url, { ...init, credentials: 'include' });
|
|
53
53
|
|
|
54
|
+
// The probe's fetcher. Electron's session.fetch rejects a `redirect: 'manual'`
|
|
55
|
+
// request that meets a 3xx with "Redirect was cancelled" (Electron 44.4.5), so
|
|
56
|
+
// Access's own 302 would read as offline. net.request on the same partition
|
|
57
|
+
// session names the target in its 'redirect' event instead, before anything is
|
|
58
|
+
// followed. `request` is net.request bound to the partition, injected so this
|
|
59
|
+
// module stays plain Node.
|
|
60
|
+
export const manualRedirectFetcher =
|
|
61
|
+
(request) =>
|
|
62
|
+
(url, init = {}) =>
|
|
63
|
+
new Promise((resolve, reject) => {
|
|
64
|
+
const req = request({
|
|
65
|
+
url,
|
|
66
|
+
method: init.method ?? 'GET',
|
|
67
|
+
redirect: 'manual',
|
|
68
|
+
useSessionCookies: true,
|
|
69
|
+
});
|
|
70
|
+
const answer = (status, location) => {
|
|
71
|
+
req.abort();
|
|
72
|
+
resolve({ status, headers: new Headers(location ? { location } : {}) });
|
|
73
|
+
};
|
|
74
|
+
req.on('redirect', (status, _method, location) => answer(status, location));
|
|
75
|
+
req.on('response', (response) => answer(response.statusCode));
|
|
76
|
+
req.on('error', reject);
|
|
77
|
+
init.signal?.addEventListener(
|
|
78
|
+
'abort',
|
|
79
|
+
() => {
|
|
80
|
+
req.abort();
|
|
81
|
+
reject(init.signal.reason);
|
|
82
|
+
},
|
|
83
|
+
{ once: true },
|
|
84
|
+
);
|
|
85
|
+
req.end();
|
|
86
|
+
});
|
|
87
|
+
|
|
54
88
|
// Asks the origin, through the partition, whether Access lets this person in:
|
|
55
89
|
// 'passed', 'access' (still being sent to log in) or 'offline' (the request
|
|
56
90
|
// itself failed, so Access cannot be judged).
|
package/src/shell.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
4
4
|
// Main process only; loaded by startShell() so that importing the package
|
|
5
5
|
// outside Electron (tests, check scripts) never imports 'electron'.
|
|
6
6
|
import {
|
|
7
|
+
net,
|
|
7
8
|
BrowserWindow,
|
|
8
9
|
Menu,
|
|
9
10
|
WebContentsView,
|
|
@@ -16,7 +17,13 @@ import {
|
|
|
16
17
|
shell,
|
|
17
18
|
} from 'electron';
|
|
18
19
|
import updaterPkg from 'electron-updater';
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
accessNavigation,
|
|
22
|
+
manualRedirectFetcher,
|
|
23
|
+
partitionFetcher,
|
|
24
|
+
probeAccess,
|
|
25
|
+
waitForAccess,
|
|
26
|
+
} from './access.mjs';
|
|
20
27
|
import {
|
|
21
28
|
forgetCompany,
|
|
22
29
|
loadCompany,
|
|
@@ -228,8 +235,11 @@ export function run(config) {
|
|
|
228
235
|
// polls through the partition until the origin answers for itself.
|
|
229
236
|
const passAccess = async (found) => {
|
|
230
237
|
if (config.accessProbePath === null) return 'passed';
|
|
231
|
-
const { partition
|
|
232
|
-
const
|
|
238
|
+
const { partition } = context(found.origin);
|
|
239
|
+
const probeFetcher = manualRedirectFetcher((options) =>
|
|
240
|
+
net.request({ ...options, session: partition }),
|
|
241
|
+
);
|
|
242
|
+
const probe = () => probeAccess(probeFetcher, found.origin, config.accessProbePath);
|
|
233
243
|
// Set before the first await so a second request cannot open a second gate.
|
|
234
244
|
const mine = { cancelled: false };
|
|
235
245
|
gate = mine;
|