From 7cacc370155494f88c9f4d0c81a34429130db8fb Mon Sep 17 00:00:00 2001 From: Jolyn Date: Sun, 21 Sep 2025 23:56:11 -0600 Subject: [PATCH 1/2] Skip redacting URLs printed to console when browser not available --- lib/utils/display.js | 6 +++++- lib/utils/format.js | 7 +++++-- lib/utils/open-url.js | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/utils/display.js b/lib/utils/display.js index 67a3b98c0417a..a90d891b3cd4a 100644 --- a/lib/utils/display.js +++ b/lib/utils/display.js @@ -259,7 +259,11 @@ class Display { // Write formatted and (non-)colorized output to streams #write (stream, options, ...args) { const colors = stream === this.#stdout ? this.#stdoutColor : this.#stderrColor - const value = formatWithOptions({ colors, ...options }, ...args) + const skipRedact = args.length > 0 ? args[args.length - 1]?.skipRedact : false + if (skipRedact) { + args = args.slice(0, args.length - 1) + } + const value = formatWithOptions({ colors, ...options, skipRedact }, ...args) this.#progress.write(() => stream.write(value)) } diff --git a/lib/utils/format.js b/lib/utils/format.js index 9216c7918678a..5bb06605ed28d 100644 --- a/lib/utils/format.js +++ b/lib/utils/format.js @@ -41,9 +41,12 @@ function STRIP_C01 (str) { return result } -const formatWithOptions = ({ prefix: prefixes = [], eol = '\n', ...options }, ...args) => { +const formatWithOptions = ({ prefix: prefixes = [], eol = '\n', skipRedact = false, ...options }, ...args) => { const prefix = prefixes.filter(p => p != null).join(' ') - const formatted = redactLog(STRIP_C01(baseFormatWithOptions(options, ...args))) + let formatted = STRIP_C01(baseFormatWithOptions(options, ...args)) + if (!skipRedact) { + formatted = redactLog(formatted) + } // Splitting could be changed to only `\n` once we are sure we only emit unix newlines. // The eol param to this function will put the correct newlines in place for the returned string. const lines = formatted.split(/\r?\n/) diff --git a/lib/utils/open-url.js b/lib/utils/open-url.js index 632dcc79949d6..627d3c797f3fd 100644 --- a/lib/utils/open-url.js +++ b/lib/utils/open-url.js @@ -16,9 +16,9 @@ const assertValidUrl = (url) => { const outputMsg = (json, title, url) => { if (json) { - output.buffer({ title, url }) + output.buffer({ title, url }, { skipRedact: true }) } else { - output.standard(`${title}:\n${url}`) + output.standard(`${title}:\n${url}`, { skipRedact: true }) } } From f95d4b3aba131961fe25262b0a1cc0195d261260 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 30 Sep 2025 13:25:23 -0700 Subject: [PATCH 2/2] fixup: use META to skip redaction when prompting for a url opener --- lib/utils/display.js | 10 +++------- lib/utils/format.js | 4 ++-- lib/utils/open-url.js | 7 ++++--- mock-registry/lib/index.js | 2 +- test/lib/commands/login.js | 3 ++- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/utils/display.js b/lib/utils/display.js index a90d891b3cd4a..da86d20ac2fee 100644 --- a/lib/utils/display.js +++ b/lib/utils/display.js @@ -259,11 +259,7 @@ class Display { // Write formatted and (non-)colorized output to streams #write (stream, options, ...args) { const colors = stream === this.#stdout ? this.#stdoutColor : this.#stderrColor - const skipRedact = args.length > 0 ? args[args.length - 1]?.skipRedact : false - if (skipRedact) { - args = args.slice(0, args.length - 1) - } - const value = formatWithOptions({ colors, ...options, skipRedact }, ...args) + const value = formatWithOptions({ colors, ...options }, ...args) this.#progress.write(() => stream.write(value)) } @@ -374,11 +370,11 @@ class Display { #writeOutput (level, meta, ...args) { switch (level) { case output.KEYS.standard: - this.#write(this.#stdout, {}, ...args) + this.#write(this.#stdout, meta, ...args) break case output.KEYS.error: - this.#write(this.#stderr, {}, ...args) + this.#write(this.#stderr, meta, ...args) break } } diff --git a/lib/utils/format.js b/lib/utils/format.js index 5bb06605ed28d..3161abd7ea4de 100644 --- a/lib/utils/format.js +++ b/lib/utils/format.js @@ -41,10 +41,10 @@ function STRIP_C01 (str) { return result } -const formatWithOptions = ({ prefix: prefixes = [], eol = '\n', skipRedact = false, ...options }, ...args) => { +const formatWithOptions = ({ prefix: prefixes = [], eol = '\n', redact = true, ...options }, ...args) => { const prefix = prefixes.filter(p => p != null).join(' ') let formatted = STRIP_C01(baseFormatWithOptions(options, ...args)) - if (!skipRedact) { + if (redact) { formatted = redactLog(formatted) } // Splitting could be changed to only `\n` once we are sure we only emit unix newlines. diff --git a/lib/utils/open-url.js b/lib/utils/open-url.js index 627d3c797f3fd..9aa04b1382277 100644 --- a/lib/utils/open-url.js +++ b/lib/utils/open-url.js @@ -1,5 +1,5 @@ const { open } = require('@npmcli/promise-spawn') -const { output, input } = require('proc-log') +const { output, input, META } = require('proc-log') const { URL } = require('node:url') const readline = require('node:readline/promises') const { once } = require('node:events') @@ -16,9 +16,10 @@ const assertValidUrl = (url) => { const outputMsg = (json, title, url) => { if (json) { - output.buffer({ title, url }, { skipRedact: true }) + output.buffer({ title, url }) } else { - output.standard(`${title}:\n${url}`, { skipRedact: true }) + // These urls are sometimes specifically login urls so we have to turn off redaction to standard output + output.standard(`${title}:\n${url}`, { [META]: true, redact: false }) } } diff --git a/mock-registry/lib/index.js b/mock-registry/lib/index.js index 31ae2679c0e98..2096d5e219fd8 100644 --- a/mock-registry/lib/index.js +++ b/mock-registry/lib/index.js @@ -284,7 +284,7 @@ class MockRegistry { weblogin ({ token = 'npm_default-test-token' }) { const doneUrl = new URL('/npm-cli-test/done', this.origin).href - const loginUrl = new URL('/npm-cli-test/login', this.origin).href + const loginUrl = new URL('/npm-cli-test/login/cli/00000000-0000-0000-0000-000000000000', this.origin).href this.nock = this.nock .post(this.fullPath('/-/v1/login'), () => { return true diff --git a/test/lib/commands/login.js b/test/lib/commands/login.js index a55637f9e00e2..55568edd09f9d 100644 --- a/test/lib/commands/login.js +++ b/test/lib/commands/login.js @@ -119,7 +119,7 @@ t.test('legacy', t => { t.test('web', t => { t.test('basic login', async t => { - const { npm, registry, login, rc } = await mockLogin(t, { + const { outputs, npm, registry, login, rc } = await mockLogin(t, { config: { 'auth-type': 'web' }, }) registry.weblogin({ token: 'npm_test-token' }) @@ -128,6 +128,7 @@ t.test('web', t => { t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', }) + t.match(outputs[0], '/npm-cli-test/login/cli/00000000-0000-0000-0000-000000000000') }) t.test('server error', async t => { const { registry, login } = await mockLogin(t, {