feat: add support for AWS Signature auth type (#4142)
Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com> Co-authored-by: nivedin <nivedinp@gmail.com>
This commit is contained in:
@@ -32,68 +32,14 @@
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="!isRootCollection"
|
||||
label="Inherit"
|
||||
:icon="authName === 'Inherit' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'Inherit'"
|
||||
v-for="item in authTypes"
|
||||
:key="item.key"
|
||||
:label="item.label"
|
||||
:icon="item.key === authType ? IconCircleDot : IconCircle"
|
||||
:active="item.key === authType"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'inherit'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="None"
|
||||
:icon="authName === 'None' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'None'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'none'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="Basic Auth"
|
||||
:icon="authName === 'Basic Auth' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'Basic Auth'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'basic'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="Bearer Token"
|
||||
:icon="authName === 'Bearer' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'Bearer'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'bearer'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="OAuth 2.0"
|
||||
:icon="authName === 'OAuth 2.0' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'OAuth 2.0'"
|
||||
@click="
|
||||
() => {
|
||||
selectOAuth2AuthType()
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="API key"
|
||||
:icon="authName === 'API key' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'API key'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'api-key'
|
||||
item.handler ? item.handler() : (auth.authType = item.key)
|
||||
hide()
|
||||
}
|
||||
"
|
||||
@@ -168,13 +114,17 @@
|
||||
</div>
|
||||
<div v-if="auth.authType === 'inherit'" class="p-4">
|
||||
<span v-if="inheritedProperties?.auth">
|
||||
Inherited
|
||||
{{ getAuthName(inheritedProperties.auth.inheritedAuth.authType) }}
|
||||
from Parent Collection {{ inheritedProperties?.auth.parentName }}
|
||||
{{
|
||||
t("authorization.inherited_from", {
|
||||
auth: getAuthName(
|
||||
inheritedProperties.auth.inheritedAuth.authType
|
||||
),
|
||||
collection: inheritedProperties?.auth.parentName,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<span v-else>
|
||||
Please save this request in any collection to inherit the
|
||||
authorization
|
||||
{{ t("authorization.save_to_inherit") }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="auth.authType === 'bearer'">
|
||||
@@ -194,11 +144,14 @@
|
||||
placeholder="Token"
|
||||
/>
|
||||
</div>
|
||||
<HttpOAuth2Authorization v-model="auth" source="GraphQL" />
|
||||
<HttpAuthorizationOAuth2 v-model="auth" source="GraphQL" />
|
||||
</div>
|
||||
<div v-if="auth.authType === 'api-key'">
|
||||
<HttpAuthorizationApiKey v-model="auth" />
|
||||
</div>
|
||||
<div v-if="auth.authType === 'aws-signature'">
|
||||
<HttpAuthorizationAWSSign v-model="auth" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="z-[9] sticky top-upperTertiaryStickyFold h-full min-w-[12rem] max-w-1/3 flex-shrink-0 overflow-auto overflow-x-auto bg-primary p-4"
|
||||
@@ -237,6 +190,12 @@ import IconTrash2 from "~icons/lucide/trash-2"
|
||||
|
||||
import { getDefaultAuthCodeOauthFlowParams } from "~/services/oauth/flows/authCode"
|
||||
|
||||
type AuthType = {
|
||||
key: HoppGQLAuth["authType"]
|
||||
label: string
|
||||
handler?: () => void
|
||||
}
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const colorMode = useColorMode()
|
||||
@@ -263,26 +222,6 @@ onMounted(() => {
|
||||
|
||||
const auth = useVModel(props, "modelValue", emit)
|
||||
|
||||
const AUTH_KEY_NAME = {
|
||||
basic: "Basic Auth",
|
||||
bearer: "Bearer",
|
||||
"oauth-2": "OAuth 2.0",
|
||||
"api-key": "API key",
|
||||
none: "None",
|
||||
inherit: "Inherit",
|
||||
} as const
|
||||
|
||||
const authType = pluckRef(auth, "authType")
|
||||
|
||||
const authName = computed(() =>
|
||||
AUTH_KEY_NAME[authType.value] ? AUTH_KEY_NAME[authType.value] : "None"
|
||||
)
|
||||
|
||||
const getAuthName = (type: HoppGQLAuth["authType"] | undefined) => {
|
||||
if (!type) return "None"
|
||||
return AUTH_KEY_NAME[type] ? AUTH_KEY_NAME[type] : "None"
|
||||
}
|
||||
|
||||
const selectOAuth2AuthType = () => {
|
||||
const defaultGrantTypeInfo: HoppGQLAuthOAuth2["grantTypeInfo"] = {
|
||||
...getDefaultAuthCodeOauthFlowParams(),
|
||||
@@ -307,6 +246,59 @@ const selectOAuth2AuthType = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const authTypes: AuthType[] = [
|
||||
{
|
||||
key: "inherit",
|
||||
label: "Inherit",
|
||||
},
|
||||
{
|
||||
key: "none",
|
||||
label: "None",
|
||||
},
|
||||
{
|
||||
key: "basic",
|
||||
label: "Basic Auth",
|
||||
},
|
||||
{
|
||||
key: "bearer",
|
||||
label: "Bearer",
|
||||
},
|
||||
{
|
||||
key: "oauth-2",
|
||||
label: "OAuth 2.0",
|
||||
handler: selectOAuth2AuthType,
|
||||
},
|
||||
{
|
||||
key: "api-key",
|
||||
label: "API Key",
|
||||
},
|
||||
{
|
||||
key: "aws-signature",
|
||||
label: "AWS Signature",
|
||||
},
|
||||
]
|
||||
|
||||
const AUTH_KEY_NAME: Record<HoppGQLAuth["authType"], string> = {
|
||||
basic: "Basic Auth",
|
||||
bearer: "Bearer",
|
||||
"oauth-2": "OAuth 2.0",
|
||||
"api-key": "API key",
|
||||
none: "None",
|
||||
inherit: "Inherit",
|
||||
"aws-signature": "AWS Signature",
|
||||
}
|
||||
|
||||
const authType = pluckRef(auth, "authType")
|
||||
|
||||
const authName = computed(() =>
|
||||
AUTH_KEY_NAME[authType.value] ? AUTH_KEY_NAME[authType.value] : "None"
|
||||
)
|
||||
|
||||
const getAuthName = (type: HoppGQLAuth["authType"] | undefined) => {
|
||||
if (!type) return "None"
|
||||
return AUTH_KEY_NAME[type] ? AUTH_KEY_NAME[type] : "None"
|
||||
}
|
||||
|
||||
const authActive = pluckRef(auth, "authActive")
|
||||
|
||||
const clearContent = () => {
|
||||
|
||||
@@ -231,26 +231,25 @@ import { useColorMode } from "@composables/theming"
|
||||
import { useToast } from "@composables/toast"
|
||||
import {
|
||||
GQLHeader,
|
||||
HoppGQLAuth,
|
||||
HoppGQLRequest,
|
||||
parseRawKeyValueEntriesE,
|
||||
rawKeyValueEntriesToString,
|
||||
RawKeyValueEntry,
|
||||
} from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { computedAsync, useVModel } from "@vueuse/core"
|
||||
import { AwsV4Signer } from "aws4fetch"
|
||||
import * as A from "fp-ts/Array"
|
||||
import * as E from "fp-ts/Either"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as RA from "fp-ts/ReadonlyArray"
|
||||
import { flow, pipe } from "fp-ts/function"
|
||||
import { clone, cloneDeep, isEqual } from "lodash-es"
|
||||
import { computed, reactive, ref, toRef, watch } from "vue"
|
||||
import { reactive, ref, toRef, watch } from "vue"
|
||||
import draggable from "vuedraggable-es"
|
||||
|
||||
import { useNestedSetting } from "~/composables/settings"
|
||||
import { throwError } from "~/helpers/functional/error"
|
||||
import { objRemoveKey } from "~/helpers/functional/object"
|
||||
import { HoppGQLHeader } from "~/helpers/graphql"
|
||||
import { commonHeaders } from "~/helpers/headers"
|
||||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||
import { toggleNestedSetting } from "~/newstore/settings"
|
||||
@@ -524,7 +523,7 @@ const clearContent = () => {
|
||||
bulkHeaders.value = ""
|
||||
}
|
||||
|
||||
const getComputedAuthHeaders = (
|
||||
const getComputedAuthHeaders = async (
|
||||
req?: HoppGQLRequest,
|
||||
auth?: HoppGQLRequest["auth"]
|
||||
) => {
|
||||
@@ -537,7 +536,7 @@ const getComputedAuthHeaders = (
|
||||
|
||||
if (!request.auth || !request.auth.authActive) return []
|
||||
|
||||
const headers: HoppGQLHeader[] = []
|
||||
const headers: GQLHeader[] = []
|
||||
|
||||
// TODO: Support a better b64 implementation than btoa ?
|
||||
if (request.auth.authType === "basic") {
|
||||
@@ -548,6 +547,7 @@ const getComputedAuthHeaders = (
|
||||
active: true,
|
||||
key: "Authorization",
|
||||
value: `Basic ${btoa(`${username}:${password}`)}`,
|
||||
description: "",
|
||||
})
|
||||
} else if (
|
||||
request.auth.authType === "bearer" ||
|
||||
@@ -563,6 +563,7 @@ const getComputedAuthHeaders = (
|
||||
active: true,
|
||||
key: "Authorization",
|
||||
value: `Bearer ${token}`,
|
||||
description: "",
|
||||
})
|
||||
} else if (request.auth.authType === "api-key") {
|
||||
const { key, addTo } = request.auth
|
||||
@@ -572,6 +573,35 @@ const getComputedAuthHeaders = (
|
||||
active: true,
|
||||
key,
|
||||
value: request.auth.value ?? "",
|
||||
description: "",
|
||||
})
|
||||
}
|
||||
} else if (request.auth.authType === "aws-signature") {
|
||||
const { addTo } = request.auth
|
||||
if (addTo === "HEADERS") {
|
||||
const currentDate = new Date()
|
||||
const amzDate = currentDate.toISOString().replace(/[:-]|\.\d{3}/g, "")
|
||||
|
||||
const { url } = req as HoppGQLRequest
|
||||
|
||||
const signer = new AwsV4Signer({
|
||||
datetime: amzDate,
|
||||
accessKeyId: request.auth.accessKey,
|
||||
secretAccessKey: request.auth.secretKey,
|
||||
region: request.auth.region ?? "us-east-1",
|
||||
service: request.auth.serviceName,
|
||||
url,
|
||||
})
|
||||
|
||||
const sign = await signer.sign()
|
||||
|
||||
sign.headers.forEach((x, k) => {
|
||||
headers.push({
|
||||
active: true,
|
||||
key: k,
|
||||
value: x,
|
||||
description: "",
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -579,23 +609,23 @@ const getComputedAuthHeaders = (
|
||||
return headers
|
||||
}
|
||||
|
||||
const getComputedHeaders = (req: HoppGQLRequest) => {
|
||||
const getComputedHeaders = async (req: HoppGQLRequest) => {
|
||||
return [
|
||||
...getComputedAuthHeaders(req).map((header) => ({
|
||||
...(await getComputedAuthHeaders(req)).map((header) => ({
|
||||
source: "auth" as const,
|
||||
header,
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
const computedHeaders = computed(() =>
|
||||
getComputedHeaders(request.value).map((header, index) => ({
|
||||
const computedHeaders = computedAsync(async () =>
|
||||
(await getComputedHeaders(request.value)).map((header, index) => ({
|
||||
id: `header-${index}`,
|
||||
...header,
|
||||
}))
|
||||
)
|
||||
|
||||
const inheritedProperties = computed(() => {
|
||||
const inheritedProperties = computedAsync(async () => {
|
||||
if (!props.inheritedProperties?.auth || !props.inheritedProperties.headers)
|
||||
return []
|
||||
|
||||
@@ -642,10 +672,10 @@ const inheritedProperties = computed(() => {
|
||||
}
|
||||
}[]
|
||||
|
||||
const computedAuthHeader = getComputedAuthHeaders(
|
||||
const [computedAuthHeader] = await getComputedAuthHeaders(
|
||||
request.value,
|
||||
props.inheritedProperties.auth.inheritedAuth as HoppGQLAuth
|
||||
)[0]
|
||||
props.inheritedProperties.auth.inheritedAuth
|
||||
)
|
||||
|
||||
if (
|
||||
computedAuthHeader &&
|
||||
|
||||
@@ -1,58 +1,56 @@
|
||||
<template>
|
||||
<div class="h-full">
|
||||
<HoppSmartTabs
|
||||
v-model="selectedOptionTab"
|
||||
styles="sticky top-0 bg-primary z-10 border-b-0"
|
||||
:render-inactive-tabs="true"
|
||||
<HoppSmartTabs
|
||||
v-model="selectedOptionTab"
|
||||
styles="sticky bg-primary top-0 z-10 border-b-0"
|
||||
:render-inactive-tabs="true"
|
||||
>
|
||||
<HoppSmartTab
|
||||
:id="'query'"
|
||||
:label="`${t('tab.query')}`"
|
||||
:indicator="request.query && request.query.length > 0 ? true : false"
|
||||
>
|
||||
<HoppSmartTab
|
||||
:id="'query'"
|
||||
:label="`${t('tab.query')}`"
|
||||
:indicator="request.query && request.query.length > 0 ? true : false"
|
||||
>
|
||||
<GraphqlQuery
|
||||
v-model="request.query"
|
||||
@run-query="runQuery"
|
||||
@save-request="saveRequest"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab
|
||||
:id="'variables'"
|
||||
:label="`${t('tab.variables')}`"
|
||||
:indicator="
|
||||
request.variables && request.variables.length > 0 ? true : false
|
||||
"
|
||||
>
|
||||
<GraphqlVariable
|
||||
v-model="request.variables"
|
||||
@run-query="runQuery"
|
||||
@save-request="saveRequest"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab
|
||||
:id="'headers'"
|
||||
:label="`${t('tab.headers')}`"
|
||||
:info="activeGQLHeadersCount === 0 ? null : `${activeGQLHeadersCount}`"
|
||||
>
|
||||
<GraphqlHeaders
|
||||
v-model="request"
|
||||
:inherited-properties="inheritedProperties"
|
||||
@change-tab="changeOptionTab"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab :id="'authorization'" :label="`${t('tab.authorization')}`">
|
||||
<GraphqlAuthorization
|
||||
v-model="request.auth"
|
||||
:inherited-properties="inheritedProperties"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
</HoppSmartTabs>
|
||||
<CollectionsSaveRequest
|
||||
mode="graphql"
|
||||
:show="showSaveRequestModal"
|
||||
@hide-modal="hideRequestModal"
|
||||
/>
|
||||
</div>
|
||||
<GraphqlQuery
|
||||
v-model="request.query"
|
||||
@run-query="runQuery"
|
||||
@save-request="saveRequest"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab
|
||||
:id="'variables'"
|
||||
:label="`${t('tab.variables')}`"
|
||||
:indicator="
|
||||
request.variables && request.variables.length > 0 ? true : false
|
||||
"
|
||||
>
|
||||
<GraphqlVariable
|
||||
v-model="request.variables"
|
||||
@run-query="runQuery"
|
||||
@save-request="saveRequest"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab
|
||||
:id="'headers'"
|
||||
:label="`${t('tab.headers')}`"
|
||||
:info="activeGQLHeadersCount === 0 ? null : `${activeGQLHeadersCount}`"
|
||||
>
|
||||
<GraphqlHeaders
|
||||
v-model="request"
|
||||
:inherited-properties="inheritedProperties"
|
||||
@change-tab="changeOptionTab"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
<HoppSmartTab :id="'authorization'" :label="`${t('tab.authorization')}`">
|
||||
<GraphqlAuthorization
|
||||
v-model="request.auth"
|
||||
:inherited-properties="inheritedProperties"
|
||||
/>
|
||||
</HoppSmartTab>
|
||||
</HoppSmartTabs>
|
||||
<CollectionsSaveRequest
|
||||
mode="graphql"
|
||||
:show="showSaveRequestModal"
|
||||
@hide-modal="hideRequestModal"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -32,68 +32,14 @@
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="!isRootCollection"
|
||||
label="Inherit"
|
||||
:icon="authName === 'Inherit' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'Inherit'"
|
||||
v-for="item in authTypes"
|
||||
:key="item.key"
|
||||
:label="item.label"
|
||||
:icon="item.key === authType ? IconCircleDot : IconCircle"
|
||||
:active="item.key === authType"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'inherit'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="None"
|
||||
:icon="authName === 'None' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'None'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'none'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="Basic Auth"
|
||||
:icon="authName === 'Basic Auth' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'Basic Auth'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'basic'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="Bearer Token"
|
||||
:icon="authName === 'Bearer' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'Bearer'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'bearer'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="OAuth 2.0"
|
||||
:icon="authName === 'OAuth 2.0' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'OAuth 2.0'"
|
||||
@click="
|
||||
() => {
|
||||
selectOAuth2AuthType()
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
label="API key"
|
||||
:icon="authName === 'API key' ? IconCircleDot : IconCircle"
|
||||
:active="authName === 'API key'"
|
||||
@click="
|
||||
() => {
|
||||
auth.authType = 'api-key'
|
||||
item.handler ? item.handler() : (auth.authType = item.key)
|
||||
hide()
|
||||
}
|
||||
"
|
||||
@@ -174,6 +120,7 @@
|
||||
placeholder="Token"
|
||||
:auto-complete-env="true"
|
||||
:envs="envs"
|
||||
class="px-4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -189,7 +136,7 @@
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<HttpOAuth2Authorization
|
||||
<HttpAuthorizationOAuth2
|
||||
v-model="auth"
|
||||
:is-collection-property="isCollectionProperty"
|
||||
:envs="envs"
|
||||
@@ -199,6 +146,9 @@
|
||||
<div v-if="auth.authType === 'api-key'">
|
||||
<HttpAuthorizationApiKey v-model="auth" :envs="envs" />
|
||||
</div>
|
||||
<div v-if="auth.authType === 'aws-signature'">
|
||||
<HttpAuthorizationAWSSign v-model="auth" :envs="envs" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="z-[9] sticky top-upperTertiaryStickyFold h-full min-w-[12rem] max-w-1/3 flex-shrink-0 overflow-auto overflow-x-auto bg-primary p-4"
|
||||
@@ -272,26 +222,52 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const AUTH_KEY_NAME = {
|
||||
basic: "Basic Auth",
|
||||
bearer: "Bearer",
|
||||
"oauth-2": "OAuth 2.0",
|
||||
"api-key": "API key",
|
||||
none: "None",
|
||||
inherit: "Inherit",
|
||||
} as const
|
||||
|
||||
const authType = pluckRef(auth, "authType")
|
||||
const authName = computed(() =>
|
||||
AUTH_KEY_NAME[authType.value] ? AUTH_KEY_NAME[authType.value] : "None"
|
||||
)
|
||||
|
||||
const getAuthName = (type: HoppRESTAuth["authType"] | undefined) => {
|
||||
if (!type) return "None"
|
||||
return AUTH_KEY_NAME[type] ? AUTH_KEY_NAME[type] : "None"
|
||||
type AuthType = {
|
||||
key: HoppRESTAuth["authType"]
|
||||
label: string
|
||||
handler?: () => void
|
||||
}
|
||||
|
||||
const selectOAuth2AuthType = () => {
|
||||
const authTypes: AuthType[] = [
|
||||
{
|
||||
key: "inherit",
|
||||
label: "Inherit",
|
||||
},
|
||||
{
|
||||
key: "none",
|
||||
label: "None",
|
||||
},
|
||||
{
|
||||
key: "basic",
|
||||
label: "Basic Auth",
|
||||
},
|
||||
{
|
||||
key: "bearer",
|
||||
label: "Bearer",
|
||||
},
|
||||
{
|
||||
key: "oauth-2",
|
||||
label: "OAuth 2.0",
|
||||
handler: selectOAuth2AuthType,
|
||||
},
|
||||
{
|
||||
key: "api-key",
|
||||
label: "API Key",
|
||||
},
|
||||
{
|
||||
key: "aws-signature",
|
||||
label: "AWS Signature",
|
||||
},
|
||||
]
|
||||
|
||||
const authType = pluckRef(auth, "authType")
|
||||
const getAuthName = (type: HoppRESTAuth["authType"] | undefined) => {
|
||||
if (!type) return "None"
|
||||
return authTypes.find((a) => a.key === type)?.label || "None"
|
||||
}
|
||||
const authName = computed(() => getAuthName(authType.value))
|
||||
|
||||
function selectOAuth2AuthType() {
|
||||
const defaultGrantTypeInfo: HoppRESTAuthOAuth2["grantTypeInfo"] = {
|
||||
...getDefaultAuthCodeOauthFlowParams(),
|
||||
grantType: "AUTHORIZATION_CODE",
|
||||
|
||||
@@ -253,17 +253,17 @@ import {
|
||||
rawKeyValueEntriesToString,
|
||||
RawKeyValueEntry,
|
||||
} from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { useService } from "dioc/vue"
|
||||
import * as A from "fp-ts/Array"
|
||||
import * as E from "fp-ts/Either"
|
||||
import { flow, pipe } from "fp-ts/function"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as RA from "fp-ts/ReadonlyArray"
|
||||
import { cloneDeep, isEqual } from "lodash-es"
|
||||
import { computed, reactive, ref, toRef, watch } from "vue"
|
||||
import { reactive, ref, toRef, watch } from "vue"
|
||||
import draggable from "vuedraggable-es"
|
||||
|
||||
import { computedAsync, useVModel } from "@vueuse/core"
|
||||
import { useService } from "dioc/vue"
|
||||
import { useNestedSetting } from "~/composables/settings"
|
||||
import linter from "~/helpers/editor/linting/rawKeyValue"
|
||||
import { throwError } from "~/helpers/functional/error"
|
||||
@@ -545,16 +545,18 @@ const clearContent = () => {
|
||||
|
||||
const aggregateEnvs = useReadonlyStream(aggregateEnvs$, getAggregateEnvs())
|
||||
|
||||
const computedHeaders = computed(() =>
|
||||
getComputedHeaders(request.value, aggregateEnvs.value, false).map(
|
||||
(header, index) => ({
|
||||
id: `header-${index}`,
|
||||
...header,
|
||||
})
|
||||
)
|
||||
const computedHeaders = computedAsync(
|
||||
async () =>
|
||||
(await getComputedHeaders(request.value, aggregateEnvs.value, false)).map(
|
||||
(header, index) => ({
|
||||
id: `header-${index}`,
|
||||
...header,
|
||||
})
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
const inheritedProperties = computed(() => {
|
||||
const inheritedProperties = computedAsync(async () => {
|
||||
if (!props.inheritedProperties?.auth || !props.inheritedProperties.headers)
|
||||
return []
|
||||
|
||||
@@ -601,12 +603,12 @@ const inheritedProperties = computed(() => {
|
||||
}
|
||||
}[]
|
||||
|
||||
const computedAuthHeader = getComputedAuthHeaders(
|
||||
const [computedAuthHeader] = await getComputedAuthHeaders(
|
||||
aggregateEnvs.value,
|
||||
request.value,
|
||||
props.inheritedProperties.auth.inheritedAuth,
|
||||
false
|
||||
)[0]
|
||||
)
|
||||
|
||||
if (
|
||||
computedAuthHeader &&
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.issuer"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Issuer"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.audience"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Audience"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.keyId"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Key ID"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center border-b border-dividerLight">
|
||||
<span class="flex items-center">
|
||||
<label class="ml-4 text-secondaryLight"> Algorithm </label>
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => authTippyActions.focus()"
|
||||
>
|
||||
<HoppSmartSelectWrapper>
|
||||
<HoppButtonSecondary
|
||||
:label="auth.algorithm"
|
||||
class="ml-2 rounded-none pr-8"
|
||||
/>
|
||||
</HoppSmartSelectWrapper>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="authTippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-for="alg in algorithms"
|
||||
:key="alg"
|
||||
:icon="auth.algorithm === alg ? IconCircleDot : IconCircle"
|
||||
:active="auth.algorithm === alg"
|
||||
:label="alg"
|
||||
@click="
|
||||
() => {
|
||||
auth.algorithm = alg
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 border-b border-dividerLight items-center">
|
||||
<label class="ml-4 text-secondaryLight"> Private Key </label>
|
||||
<label :for="`attachment`" class="p-0">
|
||||
<input
|
||||
:id="`attachment`"
|
||||
:name="`attachment`"
|
||||
type="file"
|
||||
multiple
|
||||
class="cursor-pointer p-1 text-tiny text-secondaryLight transition file:mr-2 file:cursor-pointer file:rounded file:border-0 file:bg-primaryLight file:px-4 file:py-1 file:text-tiny file:text-secondary file:transition hover:text-secondaryDark hover:file:bg-primaryDark hover:file:text-secondaryDark"
|
||||
@change="setPrivateKey($event)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<pre>
|
||||
{{ auth.privateKey }}
|
||||
</pre>
|
||||
|
||||
<!-- advanced config -->
|
||||
|
||||
<div>
|
||||
<!-- label as advanced config here -->
|
||||
<div class="p-4">
|
||||
<label class="text-secondaryLight"> Optional Configuration </label>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight h-[300px]">
|
||||
<label class="ml-4 text-secondaryLight"> Additional Claims </label>
|
||||
<div class="h-full relative">
|
||||
<div ref="claimsRef" class="absolute inset-0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.subject"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Subject"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.expiresIn"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Expires In"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
import IconCircleDot from "~icons/lucide/circle-dot"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { HoppRESTAuthASAP } from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { ref } from "vue"
|
||||
import { AggregateEnvironment } from "~/newstore/environments"
|
||||
import { useCodemirror } from "~/composables/codemirror"
|
||||
import { reactive } from "vue"
|
||||
import { Ref } from "vue"
|
||||
import { getEditorLangForMimeType } from "~/helpers/editorutils"
|
||||
import JSONLinter from "~/helpers/editor/linting/json"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: HoppRESTAuthASAP
|
||||
envs?: AggregateEnvironment[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: HoppRESTAuthASAP): void
|
||||
}>()
|
||||
|
||||
const auth = useVModel(props, "modelValue", emit)
|
||||
|
||||
const claimsRef = ref<any | null>(null)
|
||||
const codemirrorValue: Ref<string | undefined> =
|
||||
typeof auth.value.additionalClaims === "string"
|
||||
? ref(auth.value.additionalClaims)
|
||||
: ref(undefined)
|
||||
|
||||
useCodemirror(
|
||||
claimsRef,
|
||||
codemirrorValue,
|
||||
reactive({
|
||||
extendedEditorConfig: {
|
||||
mode: getEditorLangForMimeType("application/json"),
|
||||
placeholder: t("request.raw_body").toString(),
|
||||
},
|
||||
linter: JSONLinter,
|
||||
completer: null,
|
||||
environmentHighlights: true,
|
||||
})
|
||||
)
|
||||
|
||||
const algorithms: HoppRESTAuthASAP["algorithm"][] = [
|
||||
"RS256",
|
||||
"RS384",
|
||||
"RS512",
|
||||
"PS256",
|
||||
"PS384",
|
||||
"PS512",
|
||||
"ES256",
|
||||
"ES384",
|
||||
"ES512",
|
||||
]
|
||||
|
||||
const setPrivateKey = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement
|
||||
const file = target.files?.[0]
|
||||
if (!file) return
|
||||
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
const result = e.target?.result
|
||||
if (typeof result !== "string") return
|
||||
|
||||
auth.value.privateKey = result
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}
|
||||
|
||||
const authTippyActions = ref<any | null>(null)
|
||||
</script>
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.accessKey"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.aws_signature.access_key')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.secretKey"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.aws_signature.secret_key')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- advanced config -->
|
||||
|
||||
<div class="flex flex-col divide-y divide-dividerLight">
|
||||
<!-- label as advanced config here -->
|
||||
<div class="p-4 flex flex-col space-y-1">
|
||||
<label class="">
|
||||
{{ t("authorization.aws_signature.advance_config") }}
|
||||
</label>
|
||||
<p class="text-secondaryLight">
|
||||
{{ t("authorization.aws_signature.advance_config_description") }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-1">
|
||||
<SmartEnvInput
|
||||
v-model="auth.region"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.aws_signature.aws_region')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1">
|
||||
<SmartEnvInput
|
||||
v-model="auth.serviceName"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.aws_signature.service_name')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1">
|
||||
<SmartEnvInput
|
||||
v-model="auth.serviceToken"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.aws_signature.service_token')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center !border-b border-dividerLight">
|
||||
<span class="flex items-center">
|
||||
<label class="ml-4 text-secondaryLight">
|
||||
{{ t("authorization.pass_key_by") }}
|
||||
</label>
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => authTippyActions.focus()"
|
||||
>
|
||||
<HoppSmartSelectWrapper>
|
||||
<HoppButtonSecondary
|
||||
:label="
|
||||
auth.addTo
|
||||
? auth.addTo === 'HEADERS'
|
||||
? t('authorization.pass_by_headers_label')
|
||||
: t('authorization.pass_by_query_params_label')
|
||||
: t('state.none')
|
||||
"
|
||||
class="ml-2 rounded-none pr-8"
|
||||
/>
|
||||
</HoppSmartSelectWrapper>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="authTippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
:icon="auth.addTo === 'HEADERS' ? IconCircleDot : IconCircle"
|
||||
:active="auth.addTo === 'HEADERS'"
|
||||
:label="t('authorization.pass_by_headers_label')"
|
||||
@click="
|
||||
() => {
|
||||
auth.addTo = 'HEADERS'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="
|
||||
auth.addTo === 'QUERY_PARAMS' ? IconCircleDot : IconCircle
|
||||
"
|
||||
:active="auth.addTo === 'QUERY_PARAMS'"
|
||||
:label="t('authorization.pass_by_query_params_label')"
|
||||
@click="
|
||||
() => {
|
||||
auth.addTo = 'QUERY_PARAMS'
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
import IconCircleDot from "~icons/lucide/circle-dot"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { HoppRESTAuthAWSSignature } from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { AggregateEnvironment } from "~/newstore/environments"
|
||||
import { ref } from "vue"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: HoppRESTAuthAWSSignature
|
||||
envs?: AggregateEnvironment[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: HoppRESTAuthAWSSignature): void
|
||||
}>()
|
||||
|
||||
const auth = useVModel(props, "modelValue", emit)
|
||||
|
||||
const authTippyActions = ref<any | null>(null)
|
||||
</script>
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.accessToken"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Access Token"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.clientToken"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Client Token"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.clientSecret"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Client Secret"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- advanced config -->
|
||||
|
||||
<div>
|
||||
<!-- label as advanced config here -->
|
||||
<div class="p-4">
|
||||
<label class="text-secondaryLight"> Advanced Configuration </label>
|
||||
<p>
|
||||
Hoppscotch automatically assigns default values to certain fields if no
|
||||
explicit value is provided.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.nonce"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Nonce"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.timestamp"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Timestamp"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.host"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Host"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.headersToSign"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Headers to Sign"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.maxBody"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Max Body Size"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppRESTAuthAkamaiEdgeGrid } from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { AggregateEnvironment } from "~/newstore/environments"
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: HoppRESTAuthAkamaiEdgeGrid
|
||||
envs?: AggregateEnvironment[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: HoppRESTAuthAkamaiEdgeGrid): void
|
||||
}>()
|
||||
|
||||
const auth = useVModel(props, "modelValue", emit)
|
||||
</script>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.authId"
|
||||
:auto-complete-env="true"
|
||||
placeholder="HAWK Auth ID"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.authKey"
|
||||
:auto-complete-env="true"
|
||||
placeholder="HAWK Auth Key"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center border-b border-dividerLight">
|
||||
<span class="flex items-center">
|
||||
<label class="ml-4 text-secondaryLight"> Algorithm </label>
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => authTippyActions.focus()"
|
||||
>
|
||||
<HoppSmartSelectWrapper>
|
||||
<HoppButtonSecondary
|
||||
:label="auth.algorithm"
|
||||
class="ml-2 rounded-none pr-8"
|
||||
/>
|
||||
</HoppSmartSelectWrapper>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="authTippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-for="alg in algorithms"
|
||||
:key="alg"
|
||||
:icon="auth.algorithm === alg ? IconCircleDot : IconCircle"
|
||||
:active="auth.algorithm === alg"
|
||||
:label="alg"
|
||||
@click="
|
||||
() => {
|
||||
auth.algorithm = alg
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- advanced config -->
|
||||
|
||||
<div>
|
||||
<!-- label as advanced config here -->
|
||||
<div class="p-4">
|
||||
<label class="text-secondaryLight"> Optional Config </label>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.user"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.username')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.nonce"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Nonce"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.ext"
|
||||
:auto-complete-env="true"
|
||||
placeholder="ext"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.app"
|
||||
:auto-complete-env="true"
|
||||
placeholder="app"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.dlg"
|
||||
:auto-complete-env="true"
|
||||
placeholder="dlg"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.timestamp"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Timestamp"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-4 mt-6">
|
||||
<HoppSmartCheckbox
|
||||
:on="auth.includePayloadHash"
|
||||
@change="auth.includePayloadHash = !auth.includePayloadHash"
|
||||
>
|
||||
Include Payload Hash
|
||||
</HoppSmartCheckbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
import IconCircleDot from "~icons/lucide/circle-dot"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { HoppRESTAuthHAWK } from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { ref } from "vue"
|
||||
import { AggregateEnvironment } from "~/newstore/environments"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: HoppRESTAuthHAWK
|
||||
envs?: AggregateEnvironment[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: HoppRESTAuthHAWK): void
|
||||
}>()
|
||||
|
||||
const auth = useVModel(props, "modelValue", emit)
|
||||
|
||||
const algorithms: HoppRESTAuthHAWK["algorithm"][] = ["sha256", "sha1"]
|
||||
|
||||
const authTippyActions = ref<any | null>(null)
|
||||
</script>
|
||||
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.username"
|
||||
:auto-complete-env="true"
|
||||
:placeholder="t('authorization.username')"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<input
|
||||
v-model="auth.password"
|
||||
name="password"
|
||||
:placeholder="t('authorization.password')"
|
||||
class="flex flex-1 bg-transparent px-4 py-2"
|
||||
type="password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- advanced config -->
|
||||
|
||||
<div>
|
||||
<!-- label as advanced config here -->
|
||||
<div class="p-4">
|
||||
<label class="text-secondaryLight"> Advanced Configuration </label>
|
||||
<p>
|
||||
Hoppscotch automatically assigns default values to certain fields if no
|
||||
explicit value is provided.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.domain"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Domain"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-1 border-b border-dividerLight">
|
||||
<SmartEnvInput
|
||||
v-model="auth.workstation"
|
||||
:auto-complete-env="true"
|
||||
placeholder="Workstation"
|
||||
:envs="envs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="px-4 mt-6">
|
||||
<HoppSmartCheckbox
|
||||
:on="auth.retryingRequest"
|
||||
@change="auth.retryingRequest = !auth.retryingRequest"
|
||||
>
|
||||
Disable Retrying Requset
|
||||
</HoppSmartCheckbox>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { HoppRESTAuthNTLM } from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { AggregateEnvironment } from "~/newstore/environments"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: HoppRESTAuthNTLM
|
||||
envs?: AggregateEnvironment[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: HoppRESTAuthNTLM): void
|
||||
}>()
|
||||
|
||||
const auth = useVModel(props, "modelValue", emit)
|
||||
</script>
|
||||
@@ -182,11 +182,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
HoppGQLAuthOAuth2,
|
||||
HoppRESTAuthOAuth2,
|
||||
parseTemplateStringE,
|
||||
} from "@hoppscotch/data"
|
||||
import { HoppGQLAuthOAuth2, HoppRESTAuthOAuth2 } from "@hoppscotch/data"
|
||||
import { useService } from "dioc/vue"
|
||||
import * as E from "fp-ts/Either"
|
||||
import { Ref, computed, ref } from "vue"
|
||||
@@ -194,7 +190,7 @@ import { z } from "zod"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import { refWithCallbackOnChange } from "~/composables/ref"
|
||||
import { useToast } from "~/composables/toast"
|
||||
import { getCombinedEnvVariables } from "~/helpers/preRequest"
|
||||
import { replaceTemplateStringsInObjectValues } from "~/helpers/auth"
|
||||
import { AggregateEnvironment } from "~/newstore/environments"
|
||||
import authCode, {
|
||||
AuthCodeOauthFlowParams,
|
||||
@@ -1057,55 +1053,6 @@ const generateOAuthToken = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const replaceTemplateStringsInObjectValues = <
|
||||
T extends Record<string, unknown>,
|
||||
>(
|
||||
obj: T
|
||||
) => {
|
||||
const envs = getCombinedEnvVariables()
|
||||
|
||||
const requestVariables =
|
||||
props.source === "REST"
|
||||
? restTabsService.currentActiveTab.value.document.request.requestVariables.map(
|
||||
({ key, value }) => ({
|
||||
key,
|
||||
value,
|
||||
secret: false,
|
||||
})
|
||||
)
|
||||
: []
|
||||
|
||||
// Ensure request variables are prioritized by removing any selected/global environment variables with the same key
|
||||
const selectedEnvVars = envs.selected.filter(
|
||||
({ key }) =>
|
||||
!requestVariables.some(({ key: reqVarKey }) => reqVarKey === key)
|
||||
)
|
||||
const globalEnvVars = envs.global.filter(
|
||||
({ key }) =>
|
||||
!requestVariables.some(({ key: reqVarKey }) => reqVarKey === key)
|
||||
)
|
||||
|
||||
const envVars = [...selectedEnvVars, ...globalEnvVars, ...requestVariables]
|
||||
|
||||
const newObj: Partial<T> = {}
|
||||
|
||||
for (const key in obj) {
|
||||
const val = obj[key]
|
||||
|
||||
if (typeof val === "string") {
|
||||
const parseResult = parseTemplateStringE(val, envVars)
|
||||
|
||||
newObj[key] = E.isRight(parseResult)
|
||||
? (parseResult.right as T[typeof key])
|
||||
: (val as T[typeof key])
|
||||
} else {
|
||||
newObj[key] = val
|
||||
}
|
||||
}
|
||||
|
||||
return newObj as T
|
||||
}
|
||||
|
||||
const grantTypeTippyActions = ref<HTMLElement | null>(null)
|
||||
const pkceTippyActions = ref<HTMLElement | null>(null)
|
||||
const authTippyActions = ref<HTMLElement | null>(null)
|
||||
Reference in New Issue
Block a user