Browse Source

fix: environment variable not working on auth (#4829)

Nivedin 1 week ago
parent
commit
6ce0fb8897
1 changed files with 184 additions and 165 deletions
  1. 184 165
      packages/hoppscotch-kernel/src/relay/impl/web/v/1.ts

+ 184 - 165
packages/hoppscotch-kernel/src/relay/impl/web/v/1.ts

@@ -9,20 +9,22 @@ import {
   type RelayV1,
   type StatusCode,
   body,
-} from '@relay/v/1'
-import type { VersionedAPI } from '@type/versioning'
+} from "@relay/v/1"
+import type { VersionedAPI } from "@type/versioning"
 
-import { AwsV4Signer } from 'aws4fetch'
-import axios, { AxiosRequestConfig } from 'axios'
+import { AwsV4Signer } from "aws4fetch"
+import axios, { AxiosRequestConfig } from "axios"
 
-import * as E from 'fp-ts/Either'
-import * as R from 'fp-ts/Record'
-import { pipe } from 'fp-ts/function'
+import * as E from "fp-ts/Either"
+import * as R from "fp-ts/Record"
+import { pipe } from "fp-ts/function"
 
 const isStatusCode = (status: number): status is StatusCode =>
   status >= 100 && status < 600
 
-const normalizeHeaders = (headers: Record<string, any>): Record<string, string> =>
+const normalizeHeaders = (
+  headers: Record<string, any>
+): Record<string, string> =>
   pipe(
     headers,
     R.filterWithIndex((_, v) => v !== undefined),
@@ -32,39 +34,30 @@ const normalizeHeaders = (headers: Record<string, any>): Record<string, string>
 export const implementation: VersionedAPI<RelayV1> = {
   version: { major: 1, minor: 0, patch: 0 },
   api: {
-    id: 'axios',
+    id: "axios",
     capabilities: {
       method: new Set([
-        'GET',
-        'POST',
-        'PUT',
-        'DELETE',
-        'PATCH',
-        'HEAD',
-        'OPTIONS'
-      ]),
-      header: new Set([
-        'stringvalue',
-        'arrayvalue',
-        'multivalue'
+        "GET",
+        "POST",
+        "PUT",
+        "DELETE",
+        "PATCH",
+        "HEAD",
+        "OPTIONS",
       ]),
+      header: new Set(["stringvalue", "arrayvalue", "multivalue"]),
       content: new Set([
-        'text',
-        'json',
-        'xml',
-        'form',
-        'urlencoded',
-        'compression'
-      ]),
-      auth: new Set([
-        'basic',
-        'bearer',
-        'apikey',
-        'aws'
+        "text",
+        "json",
+        "xml",
+        "form",
+        "urlencoded",
+        "compression",
       ]),
+      auth: new Set(["basic", "bearer", "apikey", "aws"]),
       security: new Set([]),
       proxy: new Set([]),
-      advanced: new Set([])
+      advanced: new Set([]),
     },
 
     canHandle(request: RelayRequest) {
@@ -73,16 +66,19 @@ export const implementation: VersionedAPI<RelayV1> = {
           kind: "unsupported_feature",
           feature: "method",
           message: `Method ${request.method} is not supported`,
-          relay: "axios"
+          relay: "axios",
         })
       }
 
-      if (request.content && !this.capabilities.content.has(request.content.kind)) {
+      if (
+        request.content &&
+        !this.capabilities.content.has(request.content.kind)
+      ) {
         return E.left({
           kind: "unsupported_feature",
           feature: "content",
           message: `Content type ${request.content.kind} is not supported`,
-          relay: "axios"
+          relay: "axios",
         })
       }
 
@@ -91,7 +87,7 @@ export const implementation: VersionedAPI<RelayV1> = {
           kind: "unsupported_feature",
           feature: "authentication",
           message: `Authentication type ${request.auth.kind} is not supported`,
-          relay: "axios"
+          relay: "axios",
         })
       }
 
@@ -100,7 +96,7 @@ export const implementation: VersionedAPI<RelayV1> = {
           kind: "unsupported_feature",
           feature: "security",
           message: "Client certificates are not supported",
-          relay: "axios"
+          relay: "axios",
         })
       }
 
@@ -109,7 +105,7 @@ export const implementation: VersionedAPI<RelayV1> = {
           kind: "unsupported_feature",
           feature: "proxy",
           message: "Proxy is not supported",
-          relay: "axios"
+          relay: "axios",
         })
       }
 
@@ -121,150 +117,173 @@ export const implementation: VersionedAPI<RelayV1> = {
       const emitter: RelayEventEmitter<RelayRequestEvents> = {
         on: () => () => {},
         once: () => () => {},
-        off: () => {}
+        off: () => {},
       }
 
-      const response: Promise<E.Either<RelayError, RelayResponse>> = (async () => {
-        try {
-          const startTime = Date.now()
-          const config: AxiosRequestConfig = {
-            url: request.url,
-            method: request.method,
-            headers: request.headers,
-            params: request.params,
-            data: request.content?.content,
-            maxRedirects: request.meta?.options?.maxRedirects,
-            timeout: request.meta?.options?.timeout,
-            decompress: request.meta?.options?.decompress ?? true,
-            validateStatus: null,
-            cancelToken: cancelTokenSource.token,
-            responseType: 'arraybuffer'
-          }
-
-          if (request.auth) {
-            switch (request.auth.kind) {
-              case 'basic':
-                config.auth = {
-                  username: request.auth.username,
-                  password: request.auth.password
-                }
-                break
-              case 'bearer':
-                config.headers = {
-                  ...config.headers,
-                  Authorization: `Bearer ${request.auth.token}`
-                }
-                break
-              case 'apikey':
-                if (request.auth.in === 'header') {
-                  config.headers = {
-                    ...config.headers,
-                    [request.auth.key]: request.auth.value
-                  }
-                } else {
-                  config.params = {
-                    ...config.params,
-                    [request.auth.key]: request.auth.value
-                  }
-                }
-                break
-              case 'aws': {
-                const { accessKey, secretKey, region, service, sessionToken, in: location } = request.auth
-                const signer = new AwsV4Signer({
-                  url: request.url,
-                  method: request.method,
-                  accessKeyId: accessKey,
-                  secretAccessKey: secretKey,
-                  region,
-                  service,
-                  sessionToken,
-                  datetime: new Date().toISOString().replace(/[:-]|\.\d{3}/g, ""),
-                  signQuery: false
-                })
-                const signed = await signer.sign()
-                if (location === "query") {
-                  config.url = signed.url.toString()
-                } else {
-                  const headers: Record<string, string> = {}
-                  signed.headers.forEach((value, key) => {
-                    headers[key] = value
-                  })
-                  config.headers = {
-                    ...config.headers,
-                    ...headers
-                  }
-                }
-                break
-              }
+      const response: Promise<E.Either<RelayError, RelayResponse>> =
+        (async () => {
+          try {
+            const startTime = Date.now()
+            const config: AxiosRequestConfig = {
+              url: request.url,
+              method: request.method,
+              headers: request.headers,
+              params: request.params,
+              data: request.content?.content,
+              maxRedirects: request.meta?.options?.maxRedirects,
+              timeout: request.meta?.options?.timeout,
+              decompress: request.meta?.options?.decompress ?? true,
+              validateStatus: null,
+              cancelToken: cancelTokenSource.token,
+              responseType: "arraybuffer",
             }
-          }
 
-          const axiosResponse = await axios(config)
-          const endTime = Date.now()
+            // The following code is temporarily commented out because the auth has been pre-processed in EffectiveURL.ts and added in header
+            // and preprocessing here will cause the environment variables not parsed since the auth object only has the raw value
 
-          if (!isStatusCode(axiosResponse.status)) {
-            return E.left({
-              kind: 'version',
-              message: `Invalid status code: ${axiosResponse.status}`
-            })
-          }
+            // if (request.auth) {
+            //   switch (request.auth.kind) {
+            //     case "basic":
+            //       config.auth = {
+            //         username: request.auth.username,
+            //         password: request.auth.password,
+            //       }
+            //       break
+            //     case "bearer":
+            //       config.headers = {
+            //         ...config.headers,
+            //         Authorization: `Bearer ${request.auth.token}`,
+            //       }
+            //       break
+            //     case "apikey":
+            //       if (request.auth.in === "header") {
+            //         config.headers = {
+            //           ...config.headers,
+            //           [request.auth.key]: request.auth.value,
+            //         }
+            //       } else {
+            //         config.params = {
+            //           ...config.params,
+            //           [request.auth.key]: request.auth.value,
+            //         }
+            //       }
+            //       break
+            //     case "aws": {
+            //       const {
+            //         accessKey,
+            //         secretKey,
+            //         region,
+            //         service,
+            //         sessionToken,
+            //         in: location,
+            //       } = request.auth
+            //       const signer = new AwsV4Signer({
+            //         url: request.url,
+            //         method: request.method,
+            //         accessKeyId: accessKey,
+            //         secretAccessKey: secretKey,
+            //         region,
+            //         service,
+            //         sessionToken,
+            //         datetime: new Date()
+            //           .toISOString()
+            //           .replace(/[:-]|\.\d{3}/g, ""),
+            //         signQuery: false,
+            //       })
+            //       const signed = await signer.sign()
+            //       if (location === "query") {
+            //         config.url = signed.url.toString()
+            //       } else {
+            //         const headers: Record<string, string> = {}
+            //         signed.headers.forEach((value, key) => {
+            //           headers[key] = value
+            //         })
+            //         config.headers = {
+            //           ...config.headers,
+            //           ...headers,
+            //         }
+            //       }
+            //       break
+            //     }
+            //   }
+            // }
+
+            const axiosResponse = await axios(config)
+            const endTime = Date.now()
+
+            if (!isStatusCode(axiosResponse.status)) {
+              return E.left({
+                kind: "version",
+                message: `Invalid status code: ${axiosResponse.status}`,
+              })
+            }
 
-          const normalizedHeaders = normalizeHeaders(axiosResponse.headers)
-          const contentType = normalizedHeaders['content-type'] || normalizedHeaders['Content-Type'] || normalizedHeaders['CONTENT-TYPE']
+            const normalizedHeaders = normalizeHeaders(axiosResponse.headers)
+            const contentType =
+              normalizedHeaders["content-type"] ||
+              normalizedHeaders["Content-Type"] ||
+              normalizedHeaders["CONTENT-TYPE"]
 
-          const response: RelayResponse = {
-            id: request.id,
-            status: axiosResponse.status,
-            statusText: axiosResponse.statusText,
-            version: request.version,
-            headers: normalizedHeaders,
-            body: body.body(axiosResponse.data, contentType),
-            meta: {
-              timing: {
-                start: startTime,
-                end: endTime,
+            const response: RelayResponse = {
+              id: request.id,
+              status: axiosResponse.status,
+              statusText: axiosResponse.statusText,
+              version: request.version,
+              headers: normalizedHeaders,
+              body: body.body(axiosResponse.data, contentType),
+              meta: {
+                timing: {
+                  start: startTime,
+                  end: endTime,
+                },
+                size: {
+                  headers: JSON.stringify(axiosResponse.headers).length,
+                  body: axiosResponse.data?.length ?? 0,
+                  total:
+                    JSON.stringify(axiosResponse.headers).length +
+                    (axiosResponse.data?.length ?? 0),
+                },
               },
-              size: {
-                headers: JSON.stringify(axiosResponse.headers).length,
-                body: axiosResponse.data?.length ?? 0,
-                total: JSON.stringify(axiosResponse.headers).length + (axiosResponse.data?.length ?? 0)
-              }
             }
-          }
 
-          return E.right(response)
-        } catch (error) {
-          if (axios.isCancel(error)) {
-            return E.left({ kind: 'abort', message: 'Request cancelled' })
-          }
+            return E.right(response)
+          } catch (error) {
+            if (axios.isCancel(error)) {
+              return E.left({ kind: "abort", message: "Request cancelled" })
+            }
 
-          if (axios.isAxiosError(error)) {
-            if (error.code === 'ECONNABORTED') {
+            if (axios.isAxiosError(error)) {
+              if (error.code === "ECONNABORTED") {
+                return E.left({
+                  kind: "timeout",
+                  message: "Request timed out",
+                  phase: "response",
+                })
+              }
               return E.left({
-                kind: 'timeout',
-                message: 'Request timed out',
-                phase: 'response'
+                kind: "network",
+                message: error.message,
               })
             }
+
             return E.left({
-              kind: 'network',
-              message: error.message
+              kind: "network",
+              message:
+                error instanceof Error
+                  ? error.message
+                  : "Unknown error occurred",
+              cause: error,
             })
           }
-
-          return E.left({
-            kind: 'network',
-            message: error instanceof Error ? error.message : 'Unknown error occurred',
-            cause: error
-          })
-        }
-      })()
+        })()
 
       return {
-        cancel: async () => { cancelTokenSource.cancel() },
+        cancel: async () => {
+          cancelTokenSource.cancel()
+        },
         emitter,
-        response
+        response,
       }
-    }
-  }
+    },
+  },
 }