fix: secret variables being populated as undefined on code snippets (#4180)
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
"@hoppscotch/js-sandbox": "workspace:^",
|
||||
"@hoppscotch/ui": "0.2.0",
|
||||
"@hoppscotch/vue-toasted": "0.1.0",
|
||||
"@hoppscotch/httpsnippet": "3.0.6",
|
||||
"@lezer/highlight": "1.2.0",
|
||||
"@unhead/vue": "1.8.8",
|
||||
"@urql/core": "4.2.0",
|
||||
@@ -58,7 +59,6 @@
|
||||
"graphql": "16.8.1",
|
||||
"graphql-language-service-interface": "2.10.2",
|
||||
"graphql-tag": "2.12.6",
|
||||
"httpsnippet": "3.0.1",
|
||||
"insomnia-importers": "3.6.0",
|
||||
"io-ts": "2.2.20",
|
||||
"js-yaml": "4.1.0",
|
||||
|
||||
@@ -178,7 +178,7 @@ const requestCode = computed(() => {
|
||||
...aggregateEnvs,
|
||||
],
|
||||
}
|
||||
const effectiveRequest = getEffectiveRESTRequest(request.value, env)
|
||||
const effectiveRequest = getEffectiveRESTRequest(request.value, env, true)
|
||||
|
||||
const result = generateCode(
|
||||
codegenType.value,
|
||||
|
||||
@@ -126,7 +126,7 @@ export const parseCurlCommand = (curlCommand: string) => {
|
||||
hasBodyBeenParsed = true
|
||||
}
|
||||
|
||||
const urlString = concatParams(urlObject, danglingParams)
|
||||
const urlString = decodeURIComponent(concatParams(urlObject, danglingParams))
|
||||
|
||||
let multipartUploads: Record<string, string> = pipe(
|
||||
O.of(parsedArguments),
|
||||
|
||||
@@ -53,7 +53,7 @@ const parseURL = (urlText: string | number) =>
|
||||
u
|
||||
.toString()
|
||||
.replace(/^'|'$/g, "")
|
||||
.replaceAll(/[^a-zA-Z0-9_\-./?&=:@%+#,;()'\s]/g, "")
|
||||
.replaceAll(/[^a-zA-Z0-9_\-./?&=:@%+#,;()'<>\s]/g, "")
|
||||
),
|
||||
O.filter((u) => u.length > 0),
|
||||
O.chain((u) =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HTTPSnippet } from "httpsnippet"
|
||||
import { HTTPSnippet } from "@hoppscotch/httpsnippet"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as E from "fp-ts/Either"
|
||||
|
||||
@@ -69,10 +69,10 @@ export const getComputedAuthHeaders = (
|
||||
// TODO: Support a better b64 implementation than btoa ?
|
||||
if (request.auth.authType === "basic") {
|
||||
const username = parse
|
||||
? parseTemplateString(request.auth.username, envVars)
|
||||
? parseTemplateString(request.auth.username, envVars, false, true)
|
||||
: request.auth.username
|
||||
const password = parse
|
||||
? parseTemplateString(request.auth.password, envVars)
|
||||
? parseTemplateString(request.auth.password, envVars, false, true)
|
||||
: request.auth.password
|
||||
|
||||
headers.push({
|
||||
@@ -92,16 +92,18 @@ export const getComputedAuthHeaders = (
|
||||
headers.push({
|
||||
active: true,
|
||||
key: "Authorization",
|
||||
value: `Bearer ${parse ? parseTemplateString(token, envVars) : token}`,
|
||||
value: `Bearer ${
|
||||
parse ? parseTemplateString(token, envVars, false, true) : token
|
||||
}`,
|
||||
})
|
||||
} else if (request.auth.authType === "api-key") {
|
||||
const { key, addTo } = request.auth
|
||||
if (addTo === "HEADERS" && key) {
|
||||
headers.push({
|
||||
active: true,
|
||||
key: parseTemplateString(key, envVars),
|
||||
key: parseTemplateString(key, envVars, false, true),
|
||||
value: parse
|
||||
? parseTemplateString(request.auth.value ?? "", envVars)
|
||||
? parseTemplateString(request.auth.value ?? "", envVars, false, true)
|
||||
: request.auth.value ?? "",
|
||||
})
|
||||
}
|
||||
@@ -215,8 +217,8 @@ export const getComputedParams = (
|
||||
source: "auth" as const,
|
||||
param: {
|
||||
active: true,
|
||||
key: parseTemplateString(req.auth.key, envVars),
|
||||
value: parseTemplateString(req.auth.value, envVars),
|
||||
key: parseTemplateString(req.auth.key, envVars, false, true),
|
||||
value: parseTemplateString(req.auth.value, envVars, false, true),
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -230,7 +232,7 @@ export const getComputedParams = (
|
||||
param: {
|
||||
active: true,
|
||||
key: "access_token",
|
||||
value: parseTemplateString(grantTypeInfo.token, envVars),
|
||||
value: parseTemplateString(grantTypeInfo.token, envVars, false, true),
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -244,6 +246,11 @@ export const resolvesEnvsInBody = (
|
||||
if (!body.contentType) return body
|
||||
|
||||
if (body.contentType === "multipart/form-data") {
|
||||
if (!body.body)
|
||||
return {
|
||||
contentType: "",
|
||||
body: [],
|
||||
}
|
||||
return {
|
||||
contentType: "multipart/form-data",
|
||||
body: body.body.map(
|
||||
@@ -251,10 +258,10 @@ export const resolvesEnvsInBody = (
|
||||
<FormDataKeyValue>{
|
||||
active: entry.active,
|
||||
isFile: entry.isFile,
|
||||
key: parseTemplateString(entry.key, env.variables),
|
||||
key: parseTemplateString(entry.key, env.variables, false, true),
|
||||
value: entry.isFile
|
||||
? entry.value
|
||||
: parseTemplateString(entry.value, env.variables),
|
||||
: parseTemplateString(entry.value, env.variables, false, true),
|
||||
}
|
||||
),
|
||||
}
|
||||
@@ -262,13 +269,14 @@ export const resolvesEnvsInBody = (
|
||||
|
||||
return {
|
||||
contentType: body.contentType,
|
||||
body: parseTemplateString(body.body ?? "", env.variables),
|
||||
body: parseTemplateString(body.body ?? "", env.variables, false, true),
|
||||
}
|
||||
}
|
||||
|
||||
function getFinalBodyFromRequest(
|
||||
request: HoppRESTRequest,
|
||||
envVariables: Environment["variables"]
|
||||
envVariables: Environment["variables"],
|
||||
showKeyIfSecret = false
|
||||
): FormData | string | null {
|
||||
if (request.body.contentType === null) return null
|
||||
|
||||
@@ -289,8 +297,8 @@ function getFinalBodyFromRequest(
|
||||
* which will be resolved in further steps.
|
||||
*/
|
||||
A.map(({ key, value }) => [
|
||||
parseTemplateStringE(key, envVariables),
|
||||
parseTemplateStringE(value, envVariables),
|
||||
parseTemplateStringE(key, envVariables, false, showKeyIfSecret),
|
||||
parseTemplateStringE(value, envVariables, false, showKeyIfSecret),
|
||||
]),
|
||||
|
||||
/**
|
||||
@@ -349,12 +357,14 @@ function getFinalBodyFromRequest(
|
||||
*
|
||||
* @param request The request to source from
|
||||
* @param environment The environment to apply
|
||||
* @param showKeyIfSecret Whether to show the key if the value is a secret
|
||||
*
|
||||
* @returns An object with extra fields defining a complete request
|
||||
*/
|
||||
export function getEffectiveRESTRequest(
|
||||
request: HoppRESTRequest,
|
||||
environment: Environment
|
||||
environment: Environment,
|
||||
showKeyIfSecret = false
|
||||
): EffectiveHoppRESTRequest {
|
||||
const effectiveFinalHeaders = pipe(
|
||||
getComputedHeaders(request, environment.variables).map((h) => h.header),
|
||||
@@ -362,8 +372,18 @@ export function getEffectiveRESTRequest(
|
||||
A.filter((x) => x.active && x.key !== ""),
|
||||
A.map((x) => ({
|
||||
active: true,
|
||||
key: parseTemplateString(x.key, environment.variables),
|
||||
value: parseTemplateString(x.value, environment.variables),
|
||||
key: parseTemplateString(
|
||||
x.key,
|
||||
environment.variables,
|
||||
false,
|
||||
showKeyIfSecret
|
||||
),
|
||||
value: parseTemplateString(
|
||||
x.value,
|
||||
environment.variables,
|
||||
false,
|
||||
showKeyIfSecret
|
||||
),
|
||||
}))
|
||||
)
|
||||
|
||||
@@ -373,8 +393,18 @@ export function getEffectiveRESTRequest(
|
||||
A.filter((x) => x.active && x.key !== ""),
|
||||
A.map((x) => ({
|
||||
active: true,
|
||||
key: parseTemplateString(x.key, environment.variables),
|
||||
value: parseTemplateString(x.value, environment.variables),
|
||||
key: parseTemplateString(
|
||||
x.key,
|
||||
environment.variables,
|
||||
false,
|
||||
showKeyIfSecret
|
||||
),
|
||||
value: parseTemplateString(
|
||||
x.value,
|
||||
environment.variables,
|
||||
false,
|
||||
showKeyIfSecret
|
||||
),
|
||||
}))
|
||||
)
|
||||
|
||||
@@ -390,14 +420,17 @@ export function getEffectiveRESTRequest(
|
||||
|
||||
const effectiveFinalBody = getFinalBodyFromRequest(
|
||||
request,
|
||||
environment.variables
|
||||
environment.variables,
|
||||
showKeyIfSecret
|
||||
)
|
||||
|
||||
return {
|
||||
...request,
|
||||
effectiveFinalURL: parseTemplateString(
|
||||
request.endpoint,
|
||||
environment.variables
|
||||
environment.variables,
|
||||
false,
|
||||
showKeyIfSecret
|
||||
),
|
||||
effectiveFinalHeaders,
|
||||
effectiveFinalParams,
|
||||
|
||||
@@ -93,7 +93,8 @@ export function parseTemplateStringE(
|
||||
variables:
|
||||
| Environment["variables"]
|
||||
| { secret: true; value: string; key: string }[],
|
||||
maskValue = false
|
||||
maskValue = false,
|
||||
showKeyIfSecret = false
|
||||
) {
|
||||
if (!variables || !str) {
|
||||
return E.right(str)
|
||||
@@ -101,12 +102,22 @@ export function parseTemplateStringE(
|
||||
|
||||
let result = str
|
||||
let depth = 0
|
||||
let isSecret = false
|
||||
|
||||
while (result.match(REGEX_ENV_VAR) != null && depth <= ENV_MAX_EXPAND_LIMIT) {
|
||||
while (
|
||||
result.match(REGEX_ENV_VAR) != null &&
|
||||
depth <= ENV_MAX_EXPAND_LIMIT &&
|
||||
!isSecret
|
||||
) {
|
||||
result = decodeURI(encodeURI(result)).replace(REGEX_ENV_VAR, (_, p1) => {
|
||||
const variable = variables.find((x) => x && x.key === p1)
|
||||
|
||||
if (variable && "value" in variable) {
|
||||
// Show the key if it is a secret and explicitly specified
|
||||
if (variable.secret && showKeyIfSecret) {
|
||||
isSecret = true
|
||||
return `<<${p1}>>`
|
||||
}
|
||||
// Mask the value if it is a secret and explicitly specified
|
||||
if (variable.secret && maskValue) {
|
||||
return "*".repeat(
|
||||
@@ -144,10 +155,11 @@ export const parseTemplateString = (
|
||||
variables:
|
||||
| Environment["variables"]
|
||||
| { secret: true; value: string; key: string }[],
|
||||
maskValue = false
|
||||
maskValue = false,
|
||||
showKeyIfSecret = false
|
||||
) =>
|
||||
pipe(
|
||||
parseTemplateStringE(str, variables, maskValue),
|
||||
parseTemplateStringE(str, variables, maskValue, showKeyIfSecret),
|
||||
E.getOrElse(() => str)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user