feat: Certificate request form (#7)
* wip: first draft cert request * feat: form for cert request * fix: add missing fields * add app bar * Give alt names list more space * add missing rules
This commit is contained in:
parent
d98f60ab54
commit
f870fc1ac6
7 changed files with 196 additions and 0 deletions
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<v-app>
|
||||
<v-app-bar>
|
||||
<v-app-bar-nav-icon icon="mdi-home" to="/"/>
|
||||
</v-app-bar>
|
||||
<v-main>
|
||||
<router-view />
|
||||
</v-main>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
rounded="lg"
|
||||
title="Manage your certificates"
|
||||
variant="text"
|
||||
to="/cert-request"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
|
|
162
frontend/src/pages/cert-request.vue
Normal file
162
frontend/src/pages/cert-request.vue
Normal file
|
@ -0,0 +1,162 @@
|
|||
<template>
|
||||
<v-card class="ma-5">
|
||||
<v-card-title>Request a certificate</v-card-title>
|
||||
<v-card-item>
|
||||
<v-form v-model="valid">
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="subject.country"
|
||||
:rules="subject.countryRules"
|
||||
label="Country"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="subject.state"
|
||||
:counter="10"
|
||||
:rules="subject.stateRules"
|
||||
label="State"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="subject.city"
|
||||
:rules="subject.cityRules"
|
||||
label="City"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="subject.organization"
|
||||
:rules="subject.organizationRules"
|
||||
label="Organization"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="subject.orgUnit"
|
||||
:rules="subject.orgUnitRules"
|
||||
label="Organization Unit"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field
|
||||
v-model="subject.commonName"
|
||||
:counter="10"
|
||||
:rules="subject.commonNameRules"
|
||||
label="Common name"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field type="number" v-model="validity.duration" :rules="validity.durationRules" label="Duration for validity in Days"/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field label="Alternative Names" v-model="ui.altName">
|
||||
<template v-slot:append>
|
||||
<v-btn icon="mdi-plus" color="green" :disabled="!ui.altName" @click="addAltName"/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="8">
|
||||
<v-combobox
|
||||
v-model="subject.altNames"
|
||||
:items="subject.altNames"
|
||||
label="Alternative Names"
|
||||
multiple
|
||||
>
|
||||
<template v-slot:selection="data">
|
||||
<v-chip
|
||||
:key="JSON.stringify(data.item)"
|
||||
v-bind="data"
|
||||
size="small"
|
||||
>
|
||||
{{ data.item.title }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" md="12">
|
||||
<v-textarea v-model="trustingAuthority" label="Trusting Authority"/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-card-item>
|
||||
<v-card-actions>
|
||||
<v-col class="text-right">
|
||||
<v-btn :disabled="!valid" @click="requestCertificate" text="Request certificate" prepend-icon="mdi-certificate"/>
|
||||
</v-col>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Validated } from "@/types/util";
|
||||
import type { Certificate, Subject, Validity } from "@/types/certificate";
|
||||
|
||||
const requiredValidation = (fieldName: string) => {
|
||||
return (val: string) => {
|
||||
if (val) return true;
|
||||
return fieldName + " is required"
|
||||
}
|
||||
}
|
||||
|
||||
type SubjectInput = Partial<Validated<Subject>> & Required<Subject>;
|
||||
type ValidityInput = Validated<{duration: number}>;//Partial<Valid<Validity>> & Required<Validity>;
|
||||
type UiInput = {
|
||||
altName: string;
|
||||
}
|
||||
|
||||
export default {
|
||||
data: (): {valid: boolean, subject: SubjectInput; validity: ValidityInput; trustingAuthority: string; ui: UiInput} => ({
|
||||
valid: false,
|
||||
subject: {
|
||||
country: '',
|
||||
countryRules: [requiredValidation("Country")],
|
||||
state: '',
|
||||
city: '',
|
||||
organization: '',
|
||||
orgUnit: '',
|
||||
commonName: '',
|
||||
commonNameRules: [requiredValidation("Common Name")],
|
||||
altNames: [],
|
||||
},
|
||||
validity: {
|
||||
duration: undefined as unknown as number,
|
||||
durationRules: [
|
||||
requiredValidation("Validity duration"),
|
||||
]
|
||||
},
|
||||
trustingAuthority: '',
|
||||
ui: {
|
||||
altName: '',
|
||||
},
|
||||
}),
|
||||
methods: {
|
||||
addAltName() {
|
||||
this.subject.altNames.push(this.ui.altName)
|
||||
this.ui.altName = ''
|
||||
},
|
||||
requestCertificate(): Certificate {
|
||||
throw new Error("Not supported yet");
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
25
frontend/src/types/certificate.d.ts
vendored
Normal file
25
frontend/src/types/certificate.d.ts
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
export interface Subject {
|
||||
commonName: string;
|
||||
organization: string;
|
||||
orgUnit: string;
|
||||
country: string;
|
||||
state: string;
|
||||
city: string
|
||||
altNames: string[];
|
||||
}
|
||||
|
||||
export interface Validity {
|
||||
from: Date;
|
||||
to: Date;
|
||||
}
|
||||
|
||||
export interface Extensions {
|
||||
|
||||
}
|
||||
|
||||
export interface Certificate {
|
||||
issuer: Subject;
|
||||
validity: Validity;
|
||||
subject: Subject;
|
||||
extensions: Extensions;
|
||||
}
|
3
frontend/src/types/util.d.ts
vendored
Normal file
3
frontend/src/types/util.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
export type Validated<T> = {
|
||||
[K in keyof T as `${K}Rules`]: ((val: string) => true | string)[]
|
||||
} & T;
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"files": [],
|
||||
"include": ["./typed-router.d.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
|
|
1
frontend/typed-router.d.ts
vendored
1
frontend/typed-router.d.ts
vendored
|
@ -19,5 +19,6 @@ declare module 'vue-router/auto-routes' {
|
|||
*/
|
||||
export interface RouteNamedMap {
|
||||
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
|
||||
'/cert-request': RouteRecordInfo<'/cert-request', '/cert-request', Record<never, never>, Record<never, never>>,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue