Skip to content

Commit 752279f

Browse files
refactor(vue3): migrate CertificateContent to script setup ts
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent ad31f0a commit 752279f

1 file changed

Lines changed: 163 additions & 153 deletions

File tree

src/views/ReadCertificate/CertificateContent.vue

Lines changed: 163 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,10 @@
127127
</div>
128128
</template>
129129

130-
<script>
130+
<script setup lang="ts">
131131
132132
import { t } from '@nextcloud/l10n'
133+
import { computed } from 'vue'
133134
134135
import { selectCustonOption } from '../../helpers/certification'
135136
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
@@ -146,161 +147,170 @@ import {
146147
mdiShieldOff,
147148
} from '@mdi/js'
148149
149-
export default {
150+
defineOptions({
150151
name: 'CertificateContent',
151-
components: {
152-
NcSettingsSection,
153-
NcNoteCard,
154-
NcChip,
155-
NcIconSvgWrapper,
156-
},
157-
props: {
158-
certificate: {
159-
type: Object,
160-
default: () => {},
161-
required: false,
162-
},
163-
index: {
164-
type: String,
165-
default: '0',
166-
},
167-
},
168-
data() {
169-
return {
170-
mdiCheckCircle,
171-
mdiCancel,
172-
mdiAlertCircleOutline,
173-
mdiHelpCircle,
174-
mdiShieldCheck,
175-
mdiShieldAlert,
176-
mdiShieldOff,
177-
EXPIRATION_WARNING_DAYS: 30,
152+
})
153+
154+
type PurposeEntry = [boolean, boolean, string]
155+
type CertificateMap = Record<string, unknown>
156+
type CertificateData = {
157+
subject?: Record<string, unknown>
158+
issuer?: Record<string, unknown>
159+
purposes?: Record<string, PurposeEntry>
160+
extracerts?: CertificateData[]
161+
valid_from?: string
162+
valid_to?: string
163+
validTo_time_t?: number
164+
version?: number
165+
hash?: string
166+
signatureTypeLN?: string
167+
serialNumber?: string
168+
serialNumberHex?: string
169+
name?: string
170+
extensions?: Record<string, unknown>
171+
crl_validation?: string
172+
}
173+
174+
const props = withDefaults(defineProps<{
175+
certificate?: CertificateData
176+
index?: string
177+
}>(), {
178+
certificate: () => ({}),
179+
index: '0',
180+
})
181+
182+
const EXPIRATION_WARNING_DAYS = 30
183+
184+
const validityStatusMap = computed(() => ({
185+
unknown: { text: t('libresign', 'Unknown'), variant: 'tertiary', icon: mdiHelpCircle },
186+
expired: { text: t('libresign', 'Expired'), variant: 'error', icon: mdiCancel },
187+
expiring: { text: t('libresign', 'Expires Soon'), variant: 'warning', icon: mdiAlertCircleOutline },
188+
valid: { text: t('libresign', 'Valid'), variant: 'success', icon: mdiCheckCircle },
189+
}))
190+
191+
const crlStatusMap = computed(() => ({
192+
valid: { text: t('libresign', 'Valid (Not Revoked)'), variant: 'success', icon: mdiShieldCheck },
193+
revoked: { text: t('libresign', 'Revoked'), variant: 'error', icon: mdiShieldOff },
194+
missing: { text: t('libresign', 'No CRL Information'), variant: 'warning', icon: mdiShieldAlert },
195+
no_urls: { text: t('libresign', 'No CRL URLs Found'), variant: 'warning', icon: mdiShieldAlert },
196+
urls_inaccessible: { text: t('libresign', 'CRL URLs Inaccessible'), variant: 'tertiary', icon: mdiHelpCircle },
197+
validation_failed: { text: t('libresign', 'CRL Validation Failed'), variant: 'tertiary', icon: mdiHelpCircle },
198+
validation_error: { text: t('libresign', 'CRL Validation Error'), variant: 'tertiary', icon: mdiHelpCircle },
199+
}))
200+
201+
const shouldShowPurposes = computed(() => Boolean(
202+
props.certificate.purposes
203+
&& Object.keys(props.certificate.purposes).length
204+
&& props.index === '0',
205+
))
206+
207+
const certificateValidityStatus = computed(() => validityStatusMap.value[getValidityStatus()])
208+
const crlValidationStatus = computed(() => crlStatusMap.value[props.certificate.crl_validation ?? ''] || {
209+
text: t('libresign', 'Unknown Status'),
210+
variant: 'tertiary',
211+
icon: mdiHelpCircle,
212+
})
213+
214+
function orderList(data: CertificateMap = {}) {
215+
const sorted: CertificateMap = {}
216+
;['CN', 'OU', 'O'].forEach(element => {
217+
if (data[element]) {
218+
sorted[element] = data[element]
178219
}
179-
},
180-
computed: {
181-
shouldShowPurposes() {
182-
return this.certificate.purposes &&
183-
Object.keys(this.certificate.purposes).length &&
184-
this.index === '0'
185-
},
186-
validityStatusMap() {
187-
return {
188-
unknown: { text: this.t('libresign', 'Unknown'), variant: 'tertiary', icon: this.mdiHelpCircle },
189-
expired: { text: this.t('libresign', 'Expired'), variant: 'error', icon: this.mdiCancel },
190-
expiring: { text: this.t('libresign', 'Expires Soon'), variant: 'warning', icon: this.mdiAlertCircleOutline },
191-
valid: { text: this.t('libresign', 'Valid'), variant: 'success', icon: this.mdiCheckCircle }
192-
}
193-
},
194-
crlStatusMap() {
195-
return {
196-
valid: { text: this.t('libresign', 'Valid (Not Revoked)'), variant: 'success', icon: this.mdiShieldCheck },
197-
revoked: { text: this.t('libresign', 'Revoked'), variant: 'error', icon: this.mdiShieldOff },
198-
missing: { text: this.t('libresign', 'No CRL Information'), variant: 'warning', icon: this.mdiShieldAlert },
199-
no_urls: { text: this.t('libresign', 'No CRL URLs Found'), variant: 'warning', icon: this.mdiShieldAlert },
200-
urls_inaccessible: { text: this.t('libresign', 'CRL URLs Inaccessible'), variant: 'tertiary', icon: this.mdiHelpCircle },
201-
validation_failed: { text: this.t('libresign', 'CRL Validation Failed'), variant: 'tertiary', icon: this.mdiHelpCircle },
202-
validation_error: { text: this.t('libresign', 'CRL Validation Error'), variant: 'tertiary', icon: this.mdiHelpCircle }
203-
}
204-
},
205-
certificateValidityStatus() {
206-
return this.validityStatusMap[this.getValidityStatus()]
207-
},
208-
crlValidationStatus() {
209-
return this.crlStatusMap[this.certificate.crl_validation] || {
210-
text: this.t('libresign', 'Unknown Status'),
211-
variant: 'tertiary',
212-
icon: this.mdiHelpCircle
213-
}
214-
},
215-
},
216-
methods: {
217-
t,
218-
orderList(data) {
219-
const sorted = {};
220-
['CN', 'OU', 'O'].forEach(element => {
221-
if (data[element]) {
222-
sorted[element] = data[element]
223-
}
224-
})
225-
Object.keys(data).forEach((key) => {
226-
if (!sorted[key]) {
227-
sorted[key] = data[key]
228-
}
229-
})
230-
return sorted
231-
},
232-
getLabelFromId(id) {
233-
const option = selectCustonOption(id)
234-
if (option.isSome()) {
235-
return this.camelCaseToTitleCase(option.unwrap().label)
236-
}
237-
return this.camelCaseToTitleCase(id)
238-
},
239-
camelCaseToTitleCase(text) {
240-
if (text.includes(' ')) {
241-
return text.replace(/^./, str => str.toUpperCase())
242-
}
243-
244-
return text
245-
// Handle acronyms (consecutive uppercase letters)
246-
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
247-
// Add space before uppercase letters that follow lowercase
248-
.replace(/([a-z])([A-Z])/g, '$1 $2')
249-
// Capitalize first letter
250-
.replace(/^./, str => str.toUpperCase())
251-
.trim()
252-
},
253-
formatPurposeName(purpose) {
254-
const purposeNames = {
255-
'sslclient': this.t('libresign', 'SSL Client'),
256-
'sslserver': this.t('libresign', 'SSL Server'),
257-
'nssslserver': this.t('libresign', 'Netscape SSL Server'),
258-
'smimesign': this.t('libresign', 'S/MIME Signing'),
259-
'smimeencrypt': this.t('libresign', 'S/MIME Encryption'),
260-
'crlsign': this.t('libresign', 'CRL Signing'),
261-
'any': this.t('libresign', 'Any Purpose'),
262-
'ocsphelper': this.t('libresign', 'OCSP Helper'),
263-
'timestampsign': this.t('libresign', 'Timestamp Signing'),
264-
'codesign': this.t('libresign', 'Code Signing'),
265-
}
266-
return purposeNames[purpose] || purpose
267-
},
268-
getChainCertificateLabel(index, certificate) {
269-
if (index === 0) {
270-
return this.t('libresign', 'Intermediate Certificate')
271-
}
272-
if (certificate.subject && certificate.issuer &&
273-
JSON.stringify(certificate.subject) === JSON.stringify(certificate.issuer)) {
274-
return this.t('libresign', 'Root Certificate (CA)')
275-
}
276-
return this.t('libresign', 'Certificate {number}', { number: index + 1 })
277-
},
278-
getValidityStatus() {
279-
if (!this.certificate.validTo_time_t) {
280-
return 'unknown'
281-
}
282-
283-
const now = new Date()
284-
const expirationDate = this.unixTimestampToDate(this.certificate.validTo_time_t)
285-
286-
if (expirationDate <= now) {
287-
return 'expired'
288-
}
289-
290-
const warningDate = new Date()
291-
warningDate.setDate(now.getDate() + this.EXPIRATION_WARNING_DAYS)
292-
293-
if (expirationDate <= warningDate) {
294-
return 'expiring'
295-
}
296-
297-
return 'valid'
298-
},
299-
unixTimestampToDate(unixTimestamp) {
300-
return new Date(unixTimestamp * 1000)
301-
},
302-
},
220+
})
221+
Object.keys(data).forEach((key) => {
222+
if (!sorted[key]) {
223+
sorted[key] = data[key]
224+
}
225+
})
226+
return sorted
303227
}
228+
229+
function getLabelFromId(id: string) {
230+
const option = selectCustonOption(id)
231+
if (option.isSome()) {
232+
return camelCaseToTitleCase(option.unwrap().label)
233+
}
234+
return camelCaseToTitleCase(id)
235+
}
236+
237+
function camelCaseToTitleCase(text: string) {
238+
if (text.includes(' ')) {
239+
return text.replace(/^./, str => str.toUpperCase())
240+
}
241+
242+
return text
243+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
244+
.replace(/([a-z])([A-Z])/g, '$1 $2')
245+
.replace(/^./, str => str.toUpperCase())
246+
.trim()
247+
}
248+
249+
function formatPurposeName(purpose: string) {
250+
const purposeNames: Record<string, string> = {
251+
sslclient: t('libresign', 'SSL Client'),
252+
sslserver: t('libresign', 'SSL Server'),
253+
nssslserver: t('libresign', 'Netscape SSL Server'),
254+
smimesign: t('libresign', 'S/MIME Signing'),
255+
smimeencrypt: t('libresign', 'S/MIME Encryption'),
256+
crlsign: t('libresign', 'CRL Signing'),
257+
any: t('libresign', 'Any Purpose'),
258+
ocsphelper: t('libresign', 'OCSP Helper'),
259+
timestampsign: t('libresign', 'Timestamp Signing'),
260+
codesign: t('libresign', 'Code Signing'),
261+
}
262+
return purposeNames[purpose] || purpose
263+
}
264+
265+
function getChainCertificateLabel(index: number, certificate: CertificateData) {
266+
if (index === 0) {
267+
return t('libresign', 'Intermediate Certificate')
268+
}
269+
if (certificate.subject && certificate.issuer
270+
&& JSON.stringify(certificate.subject) === JSON.stringify(certificate.issuer)) {
271+
return t('libresign', 'Root Certificate (CA)')
272+
}
273+
return t('libresign', 'Certificate {number}', { number: index + 1 })
274+
}
275+
276+
function getValidityStatus() {
277+
if (!props.certificate.validTo_time_t) {
278+
return 'unknown'
279+
}
280+
281+
const now = new Date()
282+
const expirationDate = unixTimestampToDate(props.certificate.validTo_time_t)
283+
if (expirationDate <= now) {
284+
return 'expired'
285+
}
286+
287+
const warningDate = new Date()
288+
warningDate.setDate(now.getDate() + EXPIRATION_WARNING_DAYS)
289+
if (expirationDate <= warningDate) {
290+
return 'expiring'
291+
}
292+
293+
return 'valid'
294+
}
295+
296+
function unixTimestampToDate(unixTimestamp: number) {
297+
return new Date(unixTimestamp * 1000)
298+
}
299+
300+
defineExpose({
301+
shouldShowPurposes,
302+
validityStatusMap,
303+
crlStatusMap,
304+
certificateValidityStatus,
305+
crlValidationStatus,
306+
orderList,
307+
getLabelFromId,
308+
camelCaseToTitleCase,
309+
formatPurposeName,
310+
getChainCertificateLabel,
311+
getValidityStatus,
312+
unixTimestampToDate,
313+
})
304314
</script>
305315

306316
<style lang="scss" scoped>

0 commit comments

Comments
 (0)