Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add the ability to configure query params encoding for requests #4412

Merged
merged 12 commits into from
Oct 23, 2024
Prev Previous commit
Next Next commit
refactor: move preProcessRequest() function under `.../interceptors…
…/helpers`
  • Loading branch information
jamesgeorge007 committed Oct 23, 2024
commit 579830b082c4e8341fde4cc392c017b52b8d2a73
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { UIExtensionService } from "~/services/ui-extension.service"
import { x25519 } from "@noble/curves/ed25519"
import { base16 } from "@scure/base"
import { invokeAction } from "~/helpers/actions"
import { preProcessRequest } from "../browser"
import { preProcessRequest } from "../helpers"

type KeyValuePair = {
key: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,7 @@ import {
RequestRunResult,
} from "../../../services/interceptor.service"
import axios, { AxiosRequestConfig, CancelToken } from "axios"
import { cloneDeep } from "lodash-es"
import { useSetting } from "@composables/settings"

// Helper function to check if a string is already encoded
function isEncoded(value: string): boolean {
try {
return value !== decodeURIComponent(value)
} catch (e) {
return false // in case of malformed URI sequence
}
}

export const preProcessRequest = (
req: AxiosRequestConfig
): AxiosRequestConfig => {
const reqClone = cloneDeep(req)
const encodeMode = useSetting("ENCODE_MODE")

// If the parameters are URLSearchParams, inject them to URL instead
// This prevents issues of marshalling the URLSearchParams to the proxy
if (reqClone.params instanceof URLSearchParams) {
try {
const url = new URL(reqClone.url ?? "")

for (const [key, value] of reqClone.params.entries()) {
let finalValue = value
if (
encodeMode.value === "encode" ||
(encodeMode.value === "auto" &&
/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/.test(value))
) {
// Check if the value is already encoded (e.g., contains % symbols)
if (!isEncoded(value)) {
finalValue = encodeURIComponent(value)
}
}

// Set the parameter with the final value
url.searchParams.append(key, finalValue)
}

// decode the URL to prevent double encoding
reqClone.url = decodeURIComponent(url.toString())
} catch (e) {
// making this a non-empty block, so we can make the linter happy.
// we should probably use, allowEmptyCatch, or take the time to do something with the caught errors :)
}

reqClone.params = {}
}

return reqClone
}
import { preProcessRequest } from "./helpers"

async function runRequest(
req: AxiosRequestConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import SettingsExtension from "~/components/settings/Extension.vue"
import InterceptorsExtensionSubtitle from "~/components/interceptors/ExtensionSubtitle.vue"
import InterceptorsErrorPlaceholder from "~/components/interceptors/ErrorPlaceholder.vue"
import { until } from "@vueuse/core"
import { preProcessRequest } from "./browser"
import { preProcessRequest } from "./helpers"

export const defineSubscribableObject = <T extends object>(obj: T) => {
const proxyObject = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { AxiosRequestConfig } from "axios"
import { cloneDeep } from "lodash-es"
import { useSetting } from "~/composables/settings"

// Helper function to check if a string is already encoded
const isEncoded = (value: string) => {
try {
return value !== decodeURIComponent(value)
} catch (e) {
return false // in case of malformed URI sequence
}
}

export const preProcessRequest = (
req: AxiosRequestConfig
): AxiosRequestConfig => {
const reqClone = cloneDeep(req)
const encodeMode = useSetting("ENCODE_MODE")

// If the parameters are URLSearchParams, inject them to URL instead
// This prevents issues of marshalling the URLSearchParams to the proxy
if (reqClone.params instanceof URLSearchParams) {
try {
const url = new URL(reqClone.url ?? "")

for (const [key, value] of reqClone.params.entries()) {
let finalValue = value
if (
encodeMode.value === "encode" ||
(encodeMode.value === "auto" &&
/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/.test(value))
) {
// Check if the value is already encoded (e.g., contains % symbols)
if (!isEncoded(value)) {
finalValue = encodeURIComponent(value)
}
}

// Set the parameter with the final value
url.searchParams.append(key, finalValue)
}

// decode the URL to prevent double encoding
reqClone.url = decodeURIComponent(url.toString())
} catch (e) {
// making this a non-empty block, so we can make the linter happy.
// we should probably use, allowEmptyCatch, or take the time to do something with the caught errors :)
}

reqClone.params = {}
}

return reqClone
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Interceptor, RequestRunResult } from "~/services/interceptor.service"
import { AxiosRequestConfig, CancelToken } from "axios"
import * as E from "fp-ts/Either"
import { preProcessRequest } from "./browser"
import { preProcessRequest } from "./helpers"
import { v4 } from "uuid"
import axios from "axios"
import { settingsStore } from "~/newstore/settings"
Expand Down