refactor: auth

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
liyasthomas
2021-08-12 09:56:05 +05:30
parent dad18aabcb
commit 971b35a252
8 changed files with 308 additions and 52 deletions

171
components/http/Auth.vue Normal file
View 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>

View File

@@ -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({

View File

@@ -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: "",

View 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

View File

@@ -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" }
}

View File

@@ -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) =>

View File

@@ -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()

View File

@@ -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