refactor: auth
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
171
components/http/Auth.vue
Normal file
171
components/http/Auth.vue
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex flex-1 p-2 items-center justify-between">
|
||||||
|
<tippy
|
||||||
|
ref="authTypeOptions"
|
||||||
|
interactive
|
||||||
|
trigger="click"
|
||||||
|
theme="popover"
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="select-wrapper">
|
||||||
|
<ButtonSecondary
|
||||||
|
class="pr-8"
|
||||||
|
:label="`${$t('authentication')}: ${authType}`"
|
||||||
|
outline
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<SmartItem
|
||||||
|
label="None"
|
||||||
|
@click.native="
|
||||||
|
authType = 'none'
|
||||||
|
$refs.authTypeOptions.tippy().hide()
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<SmartItem
|
||||||
|
label="Basic"
|
||||||
|
@click.native="
|
||||||
|
authType = 'basic'
|
||||||
|
$refs.authTypeOptions.tippy().hide()
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<SmartItem
|
||||||
|
label="Bearer"
|
||||||
|
@click.native="
|
||||||
|
authType = 'bearer'
|
||||||
|
$refs.authTypeOptions.tippy().hide()
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</tippy>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="$t('clear')"
|
||||||
|
icon="clear_all"
|
||||||
|
@click.native="clearContent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="authType === 'basic'" class="space-y-2 p-2">
|
||||||
|
<div class="flex relative">
|
||||||
|
<input
|
||||||
|
id="http_basic_user"
|
||||||
|
v-model="basicUsername"
|
||||||
|
class="input floating-input"
|
||||||
|
placeholder=" "
|
||||||
|
name="http_basic_user"
|
||||||
|
/>
|
||||||
|
<label for="http_basic_user">
|
||||||
|
{{ $t("username") }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex relative">
|
||||||
|
<input
|
||||||
|
id="http_basic_passwd"
|
||||||
|
v-model="basicPassword"
|
||||||
|
class="input floating-input"
|
||||||
|
placeholder=" "
|
||||||
|
name="http_basic_passwd"
|
||||||
|
:type="passwordFieldType"
|
||||||
|
/>
|
||||||
|
<label for="http_basic_passwd">
|
||||||
|
{{ $t("password") }}
|
||||||
|
</label>
|
||||||
|
<ButtonSecondary
|
||||||
|
:icon="passwordFieldType === 'text' ? 'visibility' : 'visibility_off'"
|
||||||
|
outline
|
||||||
|
class="ml-2"
|
||||||
|
@click.native="switchVisibility"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="authType === 'bearer'" class="space-y-2 p-2">
|
||||||
|
<div class="flex relative">
|
||||||
|
<input
|
||||||
|
id="bearer_token"
|
||||||
|
v-model="bearerToken"
|
||||||
|
class="input floating-input"
|
||||||
|
placeholder=" "
|
||||||
|
name="bearer_token"
|
||||||
|
/>
|
||||||
|
<label for="bearer_token"> Token </label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <button
|
||||||
|
v-if="authType === 'OAuth 2.0'"
|
||||||
|
v-tooltip.bottom="$t('use_token')"
|
||||||
|
class="icon button"
|
||||||
|
@click="showTokenListModal = !showTokenListModal"
|
||||||
|
>
|
||||||
|
<i class="material-icons">open_in_new</i>
|
||||||
|
</button> -->
|
||||||
|
<!-- <button
|
||||||
|
v-if="authType === 'OAuth 2.0'"
|
||||||
|
v-tooltip.bottom="$t('get_token')"
|
||||||
|
class="icon button"
|
||||||
|
@click="showTokenRequest = !showTokenRequest"
|
||||||
|
>
|
||||||
|
<i class="material-icons">vpn_key</i>
|
||||||
|
</button> -->
|
||||||
|
<!-- <SmartToggle
|
||||||
|
:on="!URL_EXCLUDES.auth"
|
||||||
|
@change="setExclude('auth', !$event)"
|
||||||
|
>
|
||||||
|
{{ $t("include_in_url") }}
|
||||||
|
</SmartToggle> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, Ref, ref } from "@nuxtjs/composition-api"
|
||||||
|
import {
|
||||||
|
HoppRESTAuthBasic,
|
||||||
|
HoppRESTAuthBearer,
|
||||||
|
} from "~/helpers/types/HoppRESTAuth"
|
||||||
|
import { pluckRef, useStream } from "~/helpers/utils/composables"
|
||||||
|
import { restAuth$, setRESTAuth } from "~/newstore/RESTSession"
|
||||||
|
import { useSetting } from "~/newstore/settings"
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const auth = useStream(restAuth$, { authType: "none" }, setRESTAuth)
|
||||||
|
|
||||||
|
const authType = pluckRef(auth, "authType")
|
||||||
|
|
||||||
|
const basicUsername = pluckRef(auth as Ref<HoppRESTAuthBasic>, "username")
|
||||||
|
const basicPassword = pluckRef(auth as Ref<HoppRESTAuthBasic>, "password")
|
||||||
|
|
||||||
|
const bearerToken = pluckRef(auth as Ref<HoppRESTAuthBearer>, "token")
|
||||||
|
|
||||||
|
const URLExcludes = useSetting("URL_EXCLUDES")
|
||||||
|
|
||||||
|
const passwordFieldType = ref("text")
|
||||||
|
|
||||||
|
const clearContent = () => {
|
||||||
|
auth.value = {
|
||||||
|
authType: "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchVisibility = () => {
|
||||||
|
if (passwordFieldType.value === "text")
|
||||||
|
passwordFieldType.value = "password"
|
||||||
|
else passwordFieldType.value = "text"
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
auth,
|
||||||
|
authType,
|
||||||
|
basicUsername,
|
||||||
|
basicPassword,
|
||||||
|
bearerToken,
|
||||||
|
URLExcludes,
|
||||||
|
passwordFieldType,
|
||||||
|
clearContent,
|
||||||
|
switchVisibility,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
{{ $t("request.choose_language") }}
|
{{ $t("request.choose_language") }}
|
||||||
</label>
|
</label>
|
||||||
<div class="flex flex-1">
|
<div class="flex flex-1">
|
||||||
<span class="select-wrapper">
|
|
||||||
<tippy
|
<tippy
|
||||||
ref="options"
|
ref="options"
|
||||||
interactive
|
interactive
|
||||||
@@ -19,21 +18,12 @@
|
|||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<span
|
<span class="select-wrapper">
|
||||||
class="
|
<ButtonSecondary
|
||||||
bg-primaryLight
|
:label="codegens.find((x) => x.id === codegenType).name"
|
||||||
border border-dividerLight
|
outline
|
||||||
rounded
|
class="w-full"
|
||||||
cursor-pointer
|
/>
|
||||||
flex
|
|
||||||
font-semibold
|
|
||||||
w-full
|
|
||||||
py-2
|
|
||||||
px-4
|
|
||||||
focus:outline-none
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ codegens.find((x) => x.id === codegenType).name }}
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<SmartItem
|
<SmartItem
|
||||||
@@ -48,7 +38,6 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</tippy>
|
</tippy>
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 justify-between">
|
<div class="flex flex-1 justify-between">
|
||||||
<label for="generatedCode" class="font-semibold px-4 pt-4 pb-4">
|
<label for="generatedCode" class="font-semibold px-4 pt-4 pb-4">
|
||||||
@@ -120,6 +109,7 @@ export default defineComponent({
|
|||||||
const path = urlObj.pathname
|
const path = urlObj.pathname
|
||||||
|
|
||||||
// TODO: Solidify
|
// TODO: Solidify
|
||||||
|
// TODO: Implement updated auth stuff
|
||||||
return codegens
|
return codegens
|
||||||
.find((x) => x.id === this.codegenType)!
|
.find((x) => x.id === this.codegenType)!
|
||||||
.generator({
|
.generator({
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ export default defineComponent({
|
|||||||
headers,
|
headers,
|
||||||
preRequestScript: "",
|
preRequestScript: "",
|
||||||
testScript: "",
|
testScript: "",
|
||||||
|
auth: {
|
||||||
|
authType: "none",
|
||||||
|
},
|
||||||
body: {
|
body: {
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
body: "",
|
body: "",
|
||||||
|
|||||||
21
helpers/types/HoppRESTAuth.ts
Normal file
21
helpers/types/HoppRESTAuth.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export type HoppRESTAuthNone = {
|
||||||
|
authType: "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HoppRESTAuthBasic = {
|
||||||
|
authType: "basic"
|
||||||
|
|
||||||
|
username: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HoppRESTAuthBearer = {
|
||||||
|
authType: "bearer"
|
||||||
|
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HoppRESTAuth =
|
||||||
|
| HoppRESTAuthNone
|
||||||
|
| HoppRESTAuthBasic
|
||||||
|
| HoppRESTAuthBearer
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ValidContentTypes } from "../utils/contenttypes"
|
import { ValidContentTypes } from "../utils/contenttypes"
|
||||||
|
import { HoppRESTAuth } from "./HoppRESTAuth"
|
||||||
|
|
||||||
export const RESTReqSchemaVersion = "1"
|
export const RESTReqSchemaVersion = "1"
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ export interface HoppRESTRequest {
|
|||||||
preRequestScript: string
|
preRequestScript: string
|
||||||
testScript: string
|
testScript: string
|
||||||
|
|
||||||
|
auth: HoppRESTAuth
|
||||||
|
|
||||||
body: HoppRESTReqBody
|
body: HoppRESTReqBody
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +92,8 @@ export function translateToNewRequest(x: any): HoppRESTRequest {
|
|||||||
|
|
||||||
const body = parseRequestBody(x)
|
const body = parseRequestBody(x)
|
||||||
|
|
||||||
|
const auth = parseOldAuth(x)
|
||||||
|
|
||||||
const result: HoppRESTRequest = {
|
const result: HoppRESTRequest = {
|
||||||
name,
|
name,
|
||||||
endpoint,
|
endpoint,
|
||||||
@@ -98,9 +103,32 @@ export function translateToNewRequest(x: any): HoppRESTRequest {
|
|||||||
preRequestScript,
|
preRequestScript,
|
||||||
testScript,
|
testScript,
|
||||||
body,
|
body,
|
||||||
|
auth,
|
||||||
v: RESTReqSchemaVersion,
|
v: RESTReqSchemaVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseOldAuth(x: any): HoppRESTAuth {
|
||||||
|
if (!x.auth || x.auth === "None")
|
||||||
|
return {
|
||||||
|
authType: "none",
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.auth === "Basic Auth")
|
||||||
|
return {
|
||||||
|
authType: "basic",
|
||||||
|
username: x.httpUser,
|
||||||
|
password: x.httpPassword,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x.auth === "Bearer Token")
|
||||||
|
return {
|
||||||
|
authType: "bearer",
|
||||||
|
token: x.bearerToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
return { authType: "none" }
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,13 +27,7 @@ export function getEffectiveRESTRequest(
|
|||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
environment: Environment
|
environment: Environment
|
||||||
): EffectiveHoppRESTRequest {
|
): EffectiveHoppRESTRequest {
|
||||||
return {
|
const effectiveFinalHeaders = request.headers
|
||||||
...request,
|
|
||||||
effectiveFinalURL: parseTemplateString(
|
|
||||||
request.endpoint,
|
|
||||||
environment.variables
|
|
||||||
),
|
|
||||||
effectiveFinalHeaders: request.headers
|
|
||||||
.filter(
|
.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.key !== "" && // Remove empty keys
|
x.key !== "" && // Remove empty keys
|
||||||
@@ -44,7 +38,33 @@ export function getEffectiveRESTRequest(
|
|||||||
active: true,
|
active: true,
|
||||||
key: parseTemplateString(x.key, environment.variables),
|
key: parseTemplateString(x.key, environment.variables),
|
||||||
value: parseTemplateString(x.value, environment.variables),
|
value: parseTemplateString(x.value, environment.variables),
|
||||||
})),
|
}))
|
||||||
|
|
||||||
|
// Authentication
|
||||||
|
// TODO: Support a better b64 implementation than btoa ?
|
||||||
|
if (request.auth.authType === "basic") {
|
||||||
|
effectiveFinalHeaders.push({
|
||||||
|
active: true,
|
||||||
|
key: "Authorization",
|
||||||
|
value: `Basic ${btoa(
|
||||||
|
`${request.auth.username}:${request.auth.password}`
|
||||||
|
)}`,
|
||||||
|
})
|
||||||
|
} else if (request.auth.authType === "bearer") {
|
||||||
|
effectiveFinalHeaders.push({
|
||||||
|
active: true,
|
||||||
|
key: "Authorization",
|
||||||
|
value: `Bearer ${request.auth.token}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...request,
|
||||||
|
effectiveFinalURL: parseTemplateString(
|
||||||
|
request.endpoint,
|
||||||
|
environment.variables
|
||||||
|
),
|
||||||
|
effectiveFinalHeaders,
|
||||||
effectiveFinalParams: request.params
|
effectiveFinalParams: request.params
|
||||||
.filter(
|
.filter(
|
||||||
(x) =>
|
(x) =>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||||
import { useStream } from "~/helpers/utils/composables"
|
import { useStream } from "~/helpers/utils/composables"
|
||||||
import { HoppTestResult } from "~/helpers/types/HoppTestResult"
|
import { HoppTestResult } from "~/helpers/types/HoppTestResult"
|
||||||
|
import { HoppRESTAuth } from "~/helpers/types/HoppRESTAuth"
|
||||||
|
|
||||||
function getParamsInURL(url: string): { key: string; value: string }[] {
|
function getParamsInURL(url: string): { key: string; value: string }[] {
|
||||||
const result: { key: string; value: string }[] = []
|
const result: { key: string; value: string }[] = []
|
||||||
@@ -126,6 +127,9 @@ const defaultRESTRequest: HoppRESTRequest = {
|
|||||||
params: [],
|
params: [],
|
||||||
headers: [],
|
headers: [],
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
auth: {
|
||||||
|
authType: "none",
|
||||||
|
},
|
||||||
preRequestScript: "// pw.env.set('variable', 'value');",
|
preRequestScript: "// pw.env.set('variable', 'value');",
|
||||||
testScript: "// pw.expect('variable').toBe('value');",
|
testScript: "// pw.expect('variable').toBe('value');",
|
||||||
body: {
|
body: {
|
||||||
@@ -327,6 +331,14 @@ const dispatchers = defineDispatchers({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setAuth(curr: RESTSession, { newAuth }: { newAuth: HoppRESTAuth }) {
|
||||||
|
return {
|
||||||
|
request: {
|
||||||
|
...curr.request,
|
||||||
|
auth: newAuth,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
setPreRequestScript(curr: RESTSession, { newScript }: { newScript: string }) {
|
setPreRequestScript(curr: RESTSession, { newScript }: { newScript: string }) {
|
||||||
return {
|
return {
|
||||||
request: {
|
request: {
|
||||||
@@ -508,6 +520,15 @@ export function deleteAllRESTHeaders() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setRESTAuth(newAuth: HoppRESTAuth) {
|
||||||
|
restSessionStore.dispatch({
|
||||||
|
dispatcher: "setAuth",
|
||||||
|
payload: {
|
||||||
|
newAuth,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function setRESTPreRequestScript(newScript: string) {
|
export function setRESTPreRequestScript(newScript: string) {
|
||||||
restSessionStore.dispatch({
|
restSessionStore.dispatch({
|
||||||
dispatcher: "setPreRequestScript",
|
dispatcher: "setPreRequestScript",
|
||||||
@@ -598,6 +619,8 @@ export const restActiveHeadersCount$ = restHeaders$.pipe(
|
|||||||
map((params) => params.filter((x) => x.active).length)
|
map((params) => params.filter((x) => x.active).length)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const restAuth$ = restRequest$.pipe(pluck("auth"))
|
||||||
|
|
||||||
export const restPreRequestScript$ = restSessionStore.subject$.pipe(
|
export const restPreRequestScript$ = restSessionStore.subject$.pipe(
|
||||||
pluck("request", "preRequestScript"),
|
pluck("request", "preRequestScript"),
|
||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab :id="'authentication'" :label="$t('authentication')">
|
<SmartTab :id="'authentication'" :label="$t('authentication')">
|
||||||
<!-- TODO: Implement -->
|
<HttpAuth />
|
||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab
|
<SmartTab
|
||||||
|
|||||||
Reference in New Issue
Block a user