Skip to content

Commit 8522ba7

Browse files
committed
feat: auto-generation of certificate paths and names #1442
1 parent 6a82654 commit 8522ba7

File tree

2 files changed

+98
-8
lines changed

2 files changed

+98
-8
lines changed

app/src/views/certificate/components/CertificateContentEditor.vue

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import type { Cert } from '@/api/cert'
33
import { CopyOutlined, InboxOutlined } from '@ant-design/icons-vue'
44
import { useClipboard } from '@vueuse/core'
5+
import config from '@/api/config'
56
import CodeEditor from '@/components/CodeEditor'
67
import CertificateFileUpload from './CertificateFileUpload.vue'
78
@@ -20,6 +21,85 @@ const data = defineModel<Cert>('data', { required: true })
2021
2122
const { copy } = useClipboard()
2223
24+
// Lazy load nginx config base path
25+
const nginxBasePath = ref<string>('')
26+
const basePathLoaded = ref(false)
27+
28+
async function loadNginxBasePath() {
29+
if (basePathLoaded.value)
30+
return
31+
32+
try {
33+
const res = await config.get_base_path()
34+
nginxBasePath.value = res.base_path
35+
basePathLoaded.value = true
36+
}
37+
catch (error) {
38+
console.error('Failed to load nginx base path:', error)
39+
message.warning($gettext('Failed to load nginx configuration path'))
40+
}
41+
}
42+
43+
// Generate slug from name or filename
44+
function generateSlug(text: string): string {
45+
let result = text
46+
.toLowerCase()
47+
.replace(/\s+/g, '_') // Replace spaces with underscores
48+
.replace(/[^a-z0-9_./-]/g, '') // Remove invalid characters
49+
50+
// Remove leading dots
51+
while (result.startsWith('.')) {
52+
result = result.slice(1)
53+
}
54+
55+
// Remove trailing dots
56+
while (result.endsWith('.')) {
57+
result = result.slice(0, -1)
58+
}
59+
60+
return result
61+
}
62+
63+
// Auto-generate certificate paths and name
64+
async function autoGeneratePaths(fileName: string, _type: 'certificate' | 'key') {
65+
// Only generate paths in add mode
66+
if (data.value.id)
67+
return
68+
69+
await loadNginxBasePath()
70+
71+
if (!nginxBasePath.value)
72+
return
73+
74+
// Extract base name from filename (remove extension)
75+
const baseName = fileName.replace(/\.(crt|pem|cer|cert|key|private)$/i, '')
76+
77+
// Auto-fill name if empty
78+
if (!data.value.name) {
79+
data.value.name = baseName
80+
}
81+
82+
// Generate directory name from cert name or filename
83+
const slug = data.value.name
84+
? generateSlug(data.value.name)
85+
: generateSlug(baseName)
86+
87+
if (!slug)
88+
return
89+
90+
const certDir = `${nginxBasePath.value}/ssl/${slug}`
91+
92+
// Auto-fill certificate path if empty
93+
if (!data.value.ssl_certificate_path) {
94+
data.value.ssl_certificate_path = `${certDir}/fullchain.cer`
95+
}
96+
97+
// Auto-fill key path if empty
98+
if (!data.value.ssl_certificate_key_path) {
99+
data.value.ssl_certificate_key_path = `${certDir}/private.key`
100+
}
101+
}
102+
23103
async function copyToClipboard(text: string, label: string) {
24104
if (!text) {
25105
message.warning($gettext('Nothing to copy'))
@@ -40,13 +120,23 @@ const isDragOverCert = ref(false)
40120
const isDragOverKey = ref(false)
41121
42122
// Handle certificate file upload
43-
function handleCertificateUpload(content: string) {
123+
function handleCertificateUpload(content: string, fileName?: string) {
44124
data.value.ssl_certificate = content
125+
126+
// Auto-generate paths if in add mode
127+
if (fileName) {
128+
autoGeneratePaths(fileName, 'certificate')
129+
}
45130
}
46131
47132
// Handle private key file upload
48-
function handlePrivateKeyUpload(content: string) {
133+
function handlePrivateKeyUpload(content: string, fileName?: string) {
49134
data.value.ssl_certificate_key = content
135+
136+
// Auto-generate paths if in add mode
137+
if (fileName) {
138+
autoGeneratePaths(fileName, 'key')
139+
}
50140
}
51141
52142
// Drag and drop handlers
@@ -95,10 +185,10 @@ function handleDrop(e: DragEvent, type: 'certificate' | 'key') {
95185
reader.onload = e => {
96186
const content = e.target?.result as string
97187
if (type === 'certificate') {
98-
handleCertificateUpload(content)
188+
handleCertificateUpload(content, file.name)
99189
}
100190
else {
101-
handlePrivateKeyUpload(content)
191+
handlePrivateKeyUpload(content, file.name)
102192
}
103193
}
104194
reader.readAsText(file)
@@ -131,7 +221,7 @@ function handleDrop(e: DragEvent, type: 'certificate' | 'key') {
131221
<CertificateFileUpload
132222
v-if="!readonly"
133223
type="certificate"
134-
@upload="handleCertificateUpload"
224+
@upload="(content, fileName) => handleCertificateUpload(content, fileName)"
135225
/>
136226

137227
<div
@@ -192,7 +282,7 @@ function handleDrop(e: DragEvent, type: 'certificate' | 'key') {
192282
<CertificateFileUpload
193283
v-if="!readonly"
194284
type="key"
195-
@upload="handlePrivateKeyUpload"
285+
@upload="(content, fileName) => handlePrivateKeyUpload(content, fileName)"
196286
/>
197287

198288
<div

app/src/views/certificate/components/CertificateFileUpload.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const props = withDefaults(defineProps<Props>(), {
1111
})
1212
1313
const emit = defineEmits<{
14-
upload: [content: string]
14+
upload: [content: string, fileName: string]
1515
}>()
1616
1717
const { message } = App.useApp()
@@ -96,7 +96,7 @@ async function handleFileUpload(file: File) {
9696
}
9797
}
9898
99-
emit('upload', content)
99+
emit('upload', content, file.name)
100100
message.success($gettext('File uploaded successfully'))
101101
}
102102
catch (error) {

0 commit comments

Comments
 (0)