@moxxy/plugin-oauth 0.37.1 → 0.37.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/dist/open-browser.d.ts +6 -11
- package/dist/open-browser.d.ts.map +1 -1
- package/dist/open-browser.js +12 -19
- package/dist/open-browser.js.map +1 -1
- package/package.json +5 -5
- package/src/open-browser.test.ts +13 -13
- package/src/open-browser.ts +13 -20
package/dist/open-browser.d.ts
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Open a URL in the user's default browser. Platform-specific:
|
|
3
3
|
* macOS → `open <url>`
|
|
4
4
|
* Linux → `xdg-open <url>`
|
|
5
|
-
* Win32 → `
|
|
6
|
-
* verbatim — see {@link browserOpenCommand})
|
|
5
|
+
* Win32 → `explorer.exe <url>`
|
|
7
6
|
*
|
|
8
7
|
* Returns once the helper process is spawned — it does NOT wait for the
|
|
9
8
|
* browser itself, since the user's flow continues asynchronously via
|
|
@@ -13,20 +12,16 @@
|
|
|
13
12
|
export declare function openInBrowser(url: string): Promise<void>;
|
|
14
13
|
/**
|
|
15
14
|
* Resolve the platform's "open this URL in the default browser" command.
|
|
16
|
-
* Exported + `platform`-parameterized so
|
|
15
|
+
* Exported + `platform`-parameterized so each platform can be unit-tested
|
|
17
16
|
* without actually spawning a browser.
|
|
18
17
|
*
|
|
19
|
-
* Windows
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* the URL in double quotes makes cmd treat it as one literal token; passing the
|
|
24
|
-
* args verbatim (`windowsVerbatimArguments`) stops Node from re-quoting and
|
|
25
|
-
* undoing that. The empty `""` is the required `start` window-title placeholder.
|
|
18
|
+
* Windows deliberately launches Explorer directly rather than interpolating a
|
|
19
|
+
* library-provided OAuth URL into `cmd.exe /c start`. `spawn` passes the URL as
|
|
20
|
+
* one argv entry, so `&`, `|`, `<`, `>` and `^` remain URL data rather than
|
|
21
|
+
* shell metacharacters.
|
|
26
22
|
*/
|
|
27
23
|
export declare function browserOpenCommand(url: string, platform?: NodeJS.Platform): {
|
|
28
24
|
cmd: string;
|
|
29
25
|
args: string[];
|
|
30
|
-
verbatim?: boolean;
|
|
31
26
|
};
|
|
32
27
|
//# sourceMappingURL=open-browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../src/open-browser.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../src/open-browser.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAWjC"}
|
package/dist/open-browser.js
CHANGED
|
@@ -3,8 +3,7 @@ import { spawn } from 'node:child_process';
|
|
|
3
3
|
* Open a URL in the user's default browser. Platform-specific:
|
|
4
4
|
* macOS → `open <url>`
|
|
5
5
|
* Linux → `xdg-open <url>`
|
|
6
|
-
* Win32 → `
|
|
7
|
-
* verbatim — see {@link browserOpenCommand})
|
|
6
|
+
* Win32 → `explorer.exe <url>`
|
|
8
7
|
*
|
|
9
8
|
* Returns once the helper process is spawned — it does NOT wait for the
|
|
10
9
|
* browser itself, since the user's flow continues asynchronously via
|
|
@@ -12,14 +11,11 @@ import { spawn } from 'node:child_process';
|
|
|
12
11
|
* so the caller can print it for the user to paste manually.
|
|
13
12
|
*/
|
|
14
13
|
export async function openInBrowser(url) {
|
|
15
|
-
const { cmd, args
|
|
14
|
+
const { cmd, args } = browserOpenCommand(url);
|
|
16
15
|
await new Promise((resolve, reject) => {
|
|
17
16
|
const child = spawn(cmd, args, {
|
|
18
17
|
stdio: 'ignore',
|
|
19
18
|
detached: true,
|
|
20
|
-
// Windows only: keep cmd.exe from re-quoting our already-quoted URL,
|
|
21
|
-
// which would otherwise break the `&` escaping (see below).
|
|
22
|
-
...(verbatim ? { windowsVerbatimArguments: true } : {}),
|
|
23
19
|
});
|
|
24
20
|
// Settle exactly once. An early spawn `error` rejects AND clears the pending
|
|
25
21
|
// 50ms timer (else it would fire a stray resolve later and hold a live timer
|
|
@@ -56,26 +52,23 @@ export async function openInBrowser(url) {
|
|
|
56
52
|
}
|
|
57
53
|
/**
|
|
58
54
|
* Resolve the platform's "open this URL in the default browser" command.
|
|
59
|
-
* Exported + `platform`-parameterized so
|
|
55
|
+
* Exported + `platform`-parameterized so each platform can be unit-tested
|
|
60
56
|
* without actually spawning a browser.
|
|
61
57
|
*
|
|
62
|
-
* Windows
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* the URL in double quotes makes cmd treat it as one literal token; passing the
|
|
67
|
-
* args verbatim (`windowsVerbatimArguments`) stops Node from re-quoting and
|
|
68
|
-
* undoing that. The empty `""` is the required `start` window-title placeholder.
|
|
58
|
+
* Windows deliberately launches Explorer directly rather than interpolating a
|
|
59
|
+
* library-provided OAuth URL into `cmd.exe /c start`. `spawn` passes the URL as
|
|
60
|
+
* one argv entry, so `&`, `|`, `<`, `>` and `^` remain URL data rather than
|
|
61
|
+
* shell metacharacters.
|
|
69
62
|
*/
|
|
70
63
|
export function browserOpenCommand(url, platform = process.platform) {
|
|
64
|
+
const parsed = new URL(url);
|
|
65
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
66
|
+
throw new Error(`refusing to open non-http OAuth URL: ${parsed.protocol}`);
|
|
67
|
+
}
|
|
71
68
|
if (platform === 'darwin')
|
|
72
69
|
return { cmd: 'open', args: [url] };
|
|
73
70
|
if (platform === 'win32') {
|
|
74
|
-
return {
|
|
75
|
-
cmd: process.env.ComSpec || 'cmd.exe',
|
|
76
|
-
args: ['/c', 'start', '""', `"${url}"`],
|
|
77
|
-
verbatim: true,
|
|
78
|
-
};
|
|
71
|
+
return { cmd: 'explorer.exe', args: [url] };
|
|
79
72
|
}
|
|
80
73
|
// Linux + everything else assumes a Freedesktop-compliant `xdg-open`.
|
|
81
74
|
return { cmd: 'xdg-open', args: [url] };
|
package/dist/open-browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-browser.js","sourceRoot":"","sources":["../src/open-browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C
|
|
1
|
+
{"version":3,"file":"open-browser.js","sourceRoot":"","sources":["../src/open-browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YAC7B,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,6EAA6E;QAC7E,6EAA6E;QAC7E,4EAA4E;QAC5E,4EAA4E;QAC5E,6EAA6E;QAC7E,0EAA0E;QAC1E,6BAA6B;QAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,OAAO,GAAG,CAAC,GAAU,EAAQ,EAAE;YACnC,IAAI,OAAO;gBAAE,OAAO,CAAC,gDAAgD;YACrE,OAAO,GAAG,IAAI,CAAC;YACf,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,qEAAqE;QACrE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QAChB,6EAA6E;QAC7E,8EAA8E;QAC9E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3B,+DAA+D;QAC/D,uCAAuC;QACvC,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,iEAAiE;QACjE,6DAA6D;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,wCAAwC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/D,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9C,CAAC;IACD,sEAAsE;IACtE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;AAC1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moxxy/plugin-oauth",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.2",
|
|
4
4
|
"description": "Generic OAuth 2.0 + PKCE client. Loopback callback server, vault-backed token storage, refresh helpers. Bundled skills for Google Workspace + arbitrary providers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"moxxy",
|
|
@@ -54,15 +54,15 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"zod": "^3.25.76",
|
|
57
|
-
"@moxxy/
|
|
58
|
-
"@moxxy/
|
|
57
|
+
"@moxxy/sdk": "0.37.2",
|
|
58
|
+
"@moxxy/plugin-vault": "0.37.2"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/node": "^22.10.0",
|
|
62
62
|
"typescript": "^5.7.3",
|
|
63
63
|
"vitest": "^3.2.6",
|
|
64
|
-
"@moxxy/
|
|
65
|
-
"@moxxy/
|
|
64
|
+
"@moxxy/tsconfig": "0.0.0",
|
|
65
|
+
"@moxxy/vitest-preset": "0.0.0"
|
|
66
66
|
},
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "tsc -p tsconfig.json",
|
package/src/open-browser.test.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { browserOpenCommand } from './open-browser';
|
|
3
3
|
|
|
4
|
-
// A realistic OAuth authorize URL
|
|
5
|
-
//
|
|
4
|
+
// A realistic OAuth authorize URL with shell metacharacters that must remain a
|
|
5
|
+
// single argv value on every platform.
|
|
6
6
|
const AUTH_URL =
|
|
7
7
|
'https://auth.openai.com/oauth/authorize?client_id=app_x&redirect_uri=http%3A%2F%2Flocalhost%3A1455%2Fauth%2Fcallback&response_type=code&scope=openid+profile&code_challenge=abc123&state=deadbeef';
|
|
8
8
|
|
|
@@ -15,16 +15,16 @@ describe('browserOpenCommand', () => {
|
|
|
15
15
|
expect(browserOpenCommand(AUTH_URL, 'linux')).toEqual({ cmd: 'xdg-open', args: [AUTH_URL] });
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it('Windows
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
expect(
|
|
27
|
-
expect(
|
|
28
|
-
expect(
|
|
18
|
+
it('Windows bypasses the shell and passes the complete URL to Explorer', () => {
|
|
19
|
+
expect(browserOpenCommand(AUTH_URL, 'win32')).toEqual({
|
|
20
|
+
cmd: 'explorer.exe',
|
|
21
|
+
args: [AUTH_URL],
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('rejects non-web schemes and switch-shaped input before spawning', () => {
|
|
26
|
+
expect(() => browserOpenCommand('file:///tmp/token', 'win32')).toThrow('non-http');
|
|
27
|
+
expect(() => browserOpenCommand('javascript:alert(1)', 'win32')).toThrow('non-http');
|
|
28
|
+
expect(() => browserOpenCommand('/select,C:\\secrets', 'win32')).toThrow();
|
|
29
29
|
});
|
|
30
30
|
});
|
package/src/open-browser.ts
CHANGED
|
@@ -4,8 +4,7 @@ import { spawn } from 'node:child_process';
|
|
|
4
4
|
* Open a URL in the user's default browser. Platform-specific:
|
|
5
5
|
* macOS → `open <url>`
|
|
6
6
|
* Linux → `xdg-open <url>`
|
|
7
|
-
* Win32 → `
|
|
8
|
-
* verbatim — see {@link browserOpenCommand})
|
|
7
|
+
* Win32 → `explorer.exe <url>`
|
|
9
8
|
*
|
|
10
9
|
* Returns once the helper process is spawned — it does NOT wait for the
|
|
11
10
|
* browser itself, since the user's flow continues asynchronously via
|
|
@@ -13,14 +12,11 @@ import { spawn } from 'node:child_process';
|
|
|
13
12
|
* so the caller can print it for the user to paste manually.
|
|
14
13
|
*/
|
|
15
14
|
export async function openInBrowser(url: string): Promise<void> {
|
|
16
|
-
const { cmd, args
|
|
15
|
+
const { cmd, args } = browserOpenCommand(url);
|
|
17
16
|
await new Promise<void>((resolve, reject) => {
|
|
18
17
|
const child = spawn(cmd, args, {
|
|
19
18
|
stdio: 'ignore',
|
|
20
19
|
detached: true,
|
|
21
|
-
// Windows only: keep cmd.exe from re-quoting our already-quoted URL,
|
|
22
|
-
// which would otherwise break the `&` escaping (see below).
|
|
23
|
-
...(verbatim ? { windowsVerbatimArguments: true } : {}),
|
|
24
20
|
});
|
|
25
21
|
// Settle exactly once. An early spawn `error` rejects AND clears the pending
|
|
26
22
|
// 50ms timer (else it would fire a stray resolve later and hold a live timer
|
|
@@ -56,28 +52,25 @@ export async function openInBrowser(url: string): Promise<void> {
|
|
|
56
52
|
|
|
57
53
|
/**
|
|
58
54
|
* Resolve the platform's "open this URL in the default browser" command.
|
|
59
|
-
* Exported + `platform`-parameterized so
|
|
55
|
+
* Exported + `platform`-parameterized so each platform can be unit-tested
|
|
60
56
|
* without actually spawning a browser.
|
|
61
57
|
*
|
|
62
|
-
* Windows
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* the URL in double quotes makes cmd treat it as one literal token; passing the
|
|
67
|
-
* args verbatim (`windowsVerbatimArguments`) stops Node from re-quoting and
|
|
68
|
-
* undoing that. The empty `""` is the required `start` window-title placeholder.
|
|
58
|
+
* Windows deliberately launches Explorer directly rather than interpolating a
|
|
59
|
+
* library-provided OAuth URL into `cmd.exe /c start`. `spawn` passes the URL as
|
|
60
|
+
* one argv entry, so `&`, `|`, `<`, `>` and `^` remain URL data rather than
|
|
61
|
+
* shell metacharacters.
|
|
69
62
|
*/
|
|
70
63
|
export function browserOpenCommand(
|
|
71
64
|
url: string,
|
|
72
65
|
platform: NodeJS.Platform = process.platform,
|
|
73
|
-
): { cmd: string; args: string[]
|
|
66
|
+
): { cmd: string; args: string[] } {
|
|
67
|
+
const parsed = new URL(url);
|
|
68
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
69
|
+
throw new Error(`refusing to open non-http OAuth URL: ${parsed.protocol}`);
|
|
70
|
+
}
|
|
74
71
|
if (platform === 'darwin') return { cmd: 'open', args: [url] };
|
|
75
72
|
if (platform === 'win32') {
|
|
76
|
-
return {
|
|
77
|
-
cmd: process.env.ComSpec || 'cmd.exe',
|
|
78
|
-
args: ['/c', 'start', '""', `"${url}"`],
|
|
79
|
-
verbatim: true,
|
|
80
|
-
};
|
|
73
|
+
return { cmd: 'explorer.exe', args: [url] };
|
|
81
74
|
}
|
|
82
75
|
// Linux + everything else assumes a Freedesktop-compliant `xdg-open`.
|
|
83
76
|
return { cmd: 'xdg-open', args: [url] };
|