@heroku-cli/command
Advanced tools
@@ -6,2 +6,4 @@ import { HTTP, HTTPError, HTTPRequestOptions } from '@heroku/http-call'; | ||
| import { ParticleboardClient } from './particleboard-client.js'; | ||
| export declare const ALLOWED_HEROKU_DOMAINS: readonly string[]; | ||
| export declare const LOCALHOST_DOMAINS: readonly string[]; | ||
| export declare namespace APIClient { | ||
@@ -8,0 +10,0 @@ interface Options extends HTTPRequestOptions { |
+18
-1
@@ -14,2 +14,4 @@ import { HTTP, HTTPError } from '@heroku/http-call'; | ||
| const netrc = new Netrc(); | ||
| export const ALLOWED_HEROKU_DOMAINS = Object.freeze(['heroku.com', 'herokai.com', 'herokuspace.com', 'herokudev.com']); | ||
| export const LOCALHOST_DOMAINS = Object.freeze(['localhost', '127.0.0.1']); | ||
| export class HerokuAPIError extends Errors.CLIError { | ||
@@ -118,2 +120,3 @@ body; | ||
| } | ||
| // eslint-disable-next-line complexity | ||
| static async request(url, opts = {}, retries = 3) { | ||
@@ -136,3 +139,17 @@ opts.headers = opts.headers || {}; | ||
| if (!Object.keys(opts.headers).some(h => h.toLowerCase() === 'authorization')) { | ||
| opts.headers.authorization = `Bearer ${self.auth}`; | ||
| // Handle both relative and absolute URLs for validation | ||
| let targetUrl; | ||
| try { | ||
| // Try absolute URL first | ||
| targetUrl = new URL(url); | ||
| } | ||
| catch { | ||
| // If that fails, assume it's relative and prepend the API base URL | ||
| targetUrl = new URL(url, vars.apiUrl); | ||
| } | ||
| const isHerokuApi = ALLOWED_HEROKU_DOMAINS.some(domain => targetUrl.hostname.endsWith(`.${domain}`)); | ||
| const isLocalhost = LOCALHOST_DOMAINS.includes(targetUrl.hostname); | ||
| if (isHerokuApi || isLocalhost) { | ||
| opts.headers.authorization = `Bearer ${self.auth}`; | ||
| } | ||
| } | ||
@@ -139,0 +156,0 @@ this.configDelinquency(url, opts); |
+1
-0
@@ -12,3 +12,4 @@ export declare class Vars { | ||
| get particleboardUrl(): string; | ||
| private isValidHerokuHost; | ||
| } | ||
| export declare const vars: Vars; |
+13
-1
@@ -0,2 +1,4 @@ | ||
| import { ux } from '@oclif/core'; | ||
| import * as url from 'node:url'; | ||
| import { ALLOWED_HEROKU_DOMAINS, LOCALHOST_DOMAINS } from './api-client.js'; | ||
| export class Vars { | ||
@@ -37,3 +39,8 @@ get apiHost() { | ||
| get host() { | ||
| return this.envHost || 'heroku.com'; | ||
| const { envHost } = this; | ||
| if (envHost && !this.isValidHerokuHost(envHost)) { | ||
| ux.warn(`Invalid HEROKU_HOST '${envHost}' - using default`); | ||
| return 'heroku.com'; | ||
| } | ||
| return envHost || 'heroku.com'; | ||
| } | ||
@@ -59,3 +66,8 @@ get httpGitHost() { | ||
| } | ||
| isValidHerokuHost(host) { | ||
| // Remove protocol if present | ||
| const cleanHost = host.replace(/^https?:\/\//, ''); | ||
| return ALLOWED_HEROKU_DOMAINS.some(domain => cleanHost.endsWith(`.${domain}`)) || LOCALHOST_DOMAINS.some(domain => cleanHost.includes(domain)); | ||
| } | ||
| } | ||
| export const vars = new Vars(); |
+1
-1
| { | ||
| "name": "@heroku-cli/command", | ||
| "description": "base class for Heroku CLI commands", | ||
| "version": "12.0.2", | ||
| "version": "12.1.0", | ||
| "author": "Heroku", | ||
@@ -6,0 +6,0 @@ "bugs": "https://github.com/heroku/heroku-cli-command/issues", |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 17 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 17 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
75217
2.39%1592
2.05%28
-3.45%