@pnpm/network.web-auth 1101.1.1 → 1101.2.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/lib/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { generateQrCode } from './generateQrCode.js';
2
2
  export { pollForWebAuthToken, type PollForWebAuthTokenParams, type WebAuthContext, type WebAuthFetchOptions, type WebAuthFetchResponse, type WebAuthFetchResponseHeaders, } from './pollForWebAuthToken.js';
3
3
  export { promptBrowserOpen, type PromptBrowserOpenContext, type PromptBrowserOpenParams, type PromptBrowserOpenReadlineInterface, } from './promptBrowserOpen.js';
4
4
  export { WebAuthTimeoutError } from './WebAuthTimeoutError.js';
5
- export { isOtpError, type OtpContext, type OtpEnquirer, type OtpHandlingParams, OtpNonInteractiveError, type OtpProcess, OtpSecondChallengeError, SyntheticOtpError, withOtpHandling, } from './withOtpHandling.js';
5
+ export { canonicalHttpUrl, isOtpError, type OtpContext, type OtpEnquirer, type OtpHandlingParams, OtpNonInteractiveError, type OtpProcess, OtpSecondChallengeError, SyntheticOtpError, withOtpHandling, } from './withOtpHandling.js';
package/lib/index.js CHANGED
@@ -2,5 +2,5 @@ export { generateQrCode } from './generateQrCode.js';
2
2
  export { pollForWebAuthToken, } from './pollForWebAuthToken.js';
3
3
  export { promptBrowserOpen, } from './promptBrowserOpen.js';
4
4
  export { WebAuthTimeoutError } from './WebAuthTimeoutError.js';
5
- export { isOtpError, OtpNonInteractiveError, OtpSecondChallengeError, SyntheticOtpError, withOtpHandling, } from './withOtpHandling.js';
5
+ export { canonicalHttpUrl, isOtpError, OtpNonInteractiveError, OtpSecondChallengeError, SyntheticOtpError, withOtpHandling, } from './withOtpHandling.js';
6
6
  //# sourceMappingURL=index.js.map
@@ -69,8 +69,23 @@ export declare class SyntheticOtpError extends Error implements OtpError {
69
69
  static fromUnknownBody(globalWarn: OtpContext['globalWarn'], body: unknown): SyntheticOtpError;
70
70
  }
71
71
  export declare class OtpNonInteractiveError extends PnpmError {
72
- constructor();
72
+ readonly authUrl?: string;
73
+ readonly doneUrl?: string;
74
+ constructor(body?: OtpErrorBody);
73
75
  }
76
+ /**
77
+ * Returns the canonical serialization of an `http:`/`https:` URL with any
78
+ * userinfo (`user:pass@`) stripped, or `undefined` for a non-string, an
79
+ * unparsable URL, or any other scheme.
80
+ *
81
+ * These URLs come from the registry and get displayed, opened in a browser,
82
+ * and emitted in parseable error output: the scheme restriction keeps a
83
+ * malicious registry from injecting e.g. a `javascript:` URL into something
84
+ * that opens it, and stripping userinfo keeps credential-shaped data out of
85
+ * logs (the capability tokens automation needs live in the path/query, which
86
+ * are preserved).
87
+ */
88
+ export declare function canonicalHttpUrl(value: unknown): string | undefined;
74
89
  export declare class OtpSecondChallengeError extends PnpmError {
75
90
  constructor();
76
91
  }
@@ -30,19 +30,21 @@ export async function withOtpHandling({ context, fetchOptions, operation, }) {
30
30
  if (!isOtpError(error))
31
31
  throw error;
32
32
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
33
- throw new OtpNonInteractiveError();
33
+ throw new OtpNonInteractiveError(error.body);
34
34
  }
35
35
  let otp;
36
- if (error.body?.authUrl && error.body?.doneUrl) {
37
- const qrCode = generateQrCode(error.body.authUrl);
38
- globalInfo(`Authenticate your account at:\n${error.body.authUrl}\n\n${qrCode}`);
36
+ const authUrl = canonicalHttpUrl(error.body?.authUrl);
37
+ const doneUrl = canonicalHttpUrl(error.body?.doneUrl);
38
+ if (authUrl != null && doneUrl != null) {
39
+ const qrCode = generateQrCode(authUrl);
40
+ globalInfo(`Authenticate your account at:\n${authUrl}\n\n${qrCode}`);
39
41
  const pollPromise = pollForWebAuthToken({
40
42
  context,
41
- doneUrl: error.body.doneUrl,
43
+ doneUrl,
42
44
  fetchOptions,
43
45
  });
44
46
  otp = await promptBrowserOpen({
45
- authUrl: error.body.authUrl,
47
+ authUrl,
46
48
  context,
47
49
  pollPromise,
48
50
  });
@@ -113,10 +115,47 @@ export class SyntheticOtpError extends Error {
113
115
  }
114
116
  }
115
117
  export class OtpNonInteractiveError extends PnpmError {
116
- constructor() {
118
+ authUrl;
119
+ doneUrl;
120
+ constructor(body) {
117
121
  super('OTP_NON_INTERACTIVE', 'The registry requires additional authentication, but pnpm is not running in an interactive terminal', {
118
122
  hint: 'Re-run this command in an interactive terminal to complete authentication, or provide the --otp option if you are using a classic one-time password (OTP)',
119
123
  });
124
+ const authUrl = canonicalHttpUrl(body?.authUrl);
125
+ if (authUrl != null) {
126
+ this.authUrl = authUrl;
127
+ }
128
+ const doneUrl = canonicalHttpUrl(body?.doneUrl);
129
+ if (doneUrl != null) {
130
+ this.doneUrl = doneUrl;
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * Returns the canonical serialization of an `http:`/`https:` URL with any
136
+ * userinfo (`user:pass@`) stripped, or `undefined` for a non-string, an
137
+ * unparsable URL, or any other scheme.
138
+ *
139
+ * These URLs come from the registry and get displayed, opened in a browser,
140
+ * and emitted in parseable error output: the scheme restriction keeps a
141
+ * malicious registry from injecting e.g. a `javascript:` URL into something
142
+ * that opens it, and stripping userinfo keeps credential-shaped data out of
143
+ * logs (the capability tokens automation needs live in the path/query, which
144
+ * are preserved).
145
+ */
146
+ export function canonicalHttpUrl(value) {
147
+ if (typeof value !== 'string')
148
+ return undefined;
149
+ try {
150
+ const url = new URL(value);
151
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
152
+ return undefined;
153
+ url.username = '';
154
+ url.password = '';
155
+ return url.href;
156
+ }
157
+ catch {
158
+ return undefined;
120
159
  }
121
160
  }
122
161
  export class OtpSecondChallengeError extends PnpmError {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/network.web-auth",
3
- "version": "1101.1.1",
3
+ "version": "1101.2.0",
4
4
  "description": "Web-based authentication flow with QR code display and token polling",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -11,9 +11,9 @@
11
11
  "funding": "https://opencollective.com/pnpm",
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "https://github.com/pnpm/pnpm/tree/main/network/web-auth"
14
+ "url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/network/web-auth"
15
15
  },
16
- "homepage": "https://github.com/pnpm/pnpm/tree/main/network/web-auth#readme",
16
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/network/web-auth#readme",
17
17
  "bugs": {
18
18
  "url": "https://github.com/pnpm/pnpm/issues"
19
19
  },
@@ -30,12 +30,12 @@
30
30
  "dependencies": {
31
31
  "open": "^11.0.0",
32
32
  "qrcode-terminal": "^0.12.0",
33
- "@pnpm/error": "1100.0.0"
33
+ "@pnpm/error": "1100.0.1"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@jest/globals": "30.4.1",
37
37
  "@types/qrcode-terminal": "^0.12.2",
38
- "@pnpm/network.web-auth": "1101.1.1"
38
+ "@pnpm/network.web-auth": "1101.2.0"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">=22.13"