33 - SPDX-License-Identifier: AGPL-3.0-or-later
44-->
55<template >
6- <table v-if =" Object.keys(certificate).length" >
7- <tr >
8- <th colspan =" 2" >
9- {{ t('libresign', 'Owner of certificate') }}
10- </th >
11- </tr >
12- <tr v-for =" (value, customName) in orderList(certificate.subject)" :key =" customName" >
13- <td >{{ getLabelFromId(customName) }}</td >
14- <td >{{ Array.isArray(value) ? value.join(', ') : value }}</td >
15- </tr >
16- <tr v-if =" index !== 0" >
17- <th colspan =" 2" >
18- {{ t('libresign', 'Issuer of certificate') }}
19- </th >
20- </tr >
21- <tr v-for =" (value, customName) in orderList(certificate.issuer)" :key =" value" >
22- <td >{{ getLabelFromId(customName) }}</td >
23- <td >{{ value }}</td >
24- </tr >
25- <tr v-if =" certificate.extracerts" >
26- <th colspan =" 2" >
27- {{ t('libresign', 'Certificate chain:') }}
28- </th >
29- </tr >
30- <tr v-for =" (extra, key) in certificate.extracerts"
31- :key =" `extracerts-${key}`"
32- class =" certificate-chain" >
33- <td >
34- {{ key }}
35- </td >
36- <td >
37- <CertificateContent :certificate =" extra" :index =" index + '_' + key" />
38- </td >
39- </tr >
40- <tr >
41- <td >{{ t('libresign', 'Certificate valid from:') }}</td >
42- <td >{{ certificate.valid_from }}</td >
43- </tr >
44- <tr >
45- <td >{{ t('libresign', 'Certificate valid to:') }}</td >
46- <td >{{ certificate.valid_to }}</td >
47- </tr >
48- <tr >
49- <th colspan =" 2" >
50- {{ t('libresign', 'Extra information') }}
51- </th >
52- </tr >
53- <tr >
54- <td >Name</td >
55- <td >{{ certificate.name }}</td >
56- </tr >
57- <tr v-for =" (value, name) in certificate.extensions" :key =" name" >
58- <td >{{ name }}</td >
59- <td >{{ value }}</td >
60- </tr >
61- </table >
6+ <div v-if =" Object.keys(certificate).length" class =" certificate-content" >
7+ <!-- Owner Section -->
8+ <NcSettingsSection :name =" t('libresign', 'Owner of certificate')" >
9+ <div class =" certificate-fields" >
10+ <div v-for =" (value, customName) in orderList(certificate.subject)"
11+ :key =" customName"
12+ class =" certificate-field" >
13+ <span class =" field-label" >{{ getLabelFromId(customName) }}</span >
14+ <span class =" field-value" >{{ Array.isArray(value) ? value.join(', ') : value }}</span >
15+ </div >
16+ </div >
17+ </NcSettingsSection >
18+
19+ <NcSettingsSection v-if =" index !== 0"
20+ :name =" t('libresign', 'Issuer of certificate')" >
21+ <div class =" certificate-fields" >
22+ <div v-for =" (value, customName) in orderList(certificate.issuer)"
23+ :key =" value"
24+ class =" certificate-field" >
25+ <span class =" field-label" >{{ getLabelFromId(customName) }}</span >
26+ <span class =" field-value" >{{ value }}</span >
27+ </div >
28+ </div >
29+ </NcSettingsSection >
30+
31+ <NcSettingsSection v-if =" certificate.extracerts && index === '0'"
32+ :name =" t('libresign', 'Certificate chain')" >
33+ <div class =" certificate-chain-container" >
34+ <div v-for =" (extra, key) in certificate.extracerts"
35+ :key =" `extracerts-${key}`"
36+ class =" chain-certificate" >
37+ <h4 class =" chain-title" >
38+ {{ getChainCertificateLabel(key, extra) }}
39+ </h4 >
40+ <CertificateContent :certificate =" extra" :index =" index + '_' + key" />
41+ </div >
42+ </div >
43+ </NcSettingsSection >
44+
45+ <NcSettingsSection :name =" t('libresign', 'Certificate Information')" >
46+ <div class =" certificate-fields" >
47+ <div v-if =" index === '0'" class =" certificate-field" >
48+ <span class =" field-label" >{{ t('libresign', 'Valid from') }}</span >
49+ <span class =" field-value" >{{ certificate.valid_from }}</span >
50+ </div >
51+ <div v-if =" index === '0'" class =" certificate-field" >
52+ <span class =" field-label" >{{ t('libresign', 'Valid to') }}</span >
53+ <span class =" field-value" >{{ certificate.valid_to }}</span >
54+ </div >
55+ <div v-if =" certificate.version !== undefined" class =" certificate-field" >
56+ <span class =" field-label" >{{ t('libresign', 'Version') }}</span >
57+ <span class =" field-value" >{{ certificate.version + 1 }}</span >
58+ </div >
59+ <div v-if =" certificate.hash" class =" certificate-field" >
60+ <span class =" field-label" >{{ t('libresign', 'Fingerprint') }}</span >
61+ <span class =" field-value" >{{ certificate.hash }}</span >
62+ </div >
63+ <div v-if =" certificate.signatureTypeLN" class =" certificate-field" >
64+ <span class =" field-label" >{{ t('libresign', 'Signature algorithm') }}</span >
65+ <span class =" field-value" >{{ certificate.signatureTypeLN }}</span >
66+ </div >
67+ <div v-if =" certificate.serialNumber" class =" certificate-field" >
68+ <span class =" field-label" >{{ t('libresign', 'Serial number') }}</span >
69+ <span class =" field-value" >{{ certificate.serialNumber }}</span >
70+ </div >
71+ </div >
72+ </NcSettingsSection >
73+
74+ <NcSettingsSection v-if =" index === '0'"
75+ :name =" t('libresign', 'Technical Details')" >
76+ <div class =" certificate-fields" >
77+ <div class =" certificate-field" >
78+ <span class =" field-label" >Name</span >
79+ <span class =" field-value" >{{ certificate.name }}</span >
80+ </div >
81+ <div v-for =" (value, name) in certificate.extensions"
82+ :key =" name"
83+ class =" certificate-field" >
84+ <span class =" field-label" >{{ name }}</span >
85+ <span class =" field-value" >{{ value }}</span >
86+ </div >
87+ </div >
88+ </NcSettingsSection >
89+
90+ <NcSettingsSection v-if =" certificate.purposes && Object.keys(certificate.purposes).length && index === '0'"
91+ :name =" t('libresign', 'Certificate purposes')" >
92+ <div class =" purposes-grid" >
93+ <div v-for =" (purpose, purposeIndex) in certificate.purposes"
94+ :key =" purposeIndex"
95+ class =" purpose-item"
96+ :class =" { 'purpose-allowed': purpose[0], 'purpose-denied': !purpose[0] }" >
97+ <div class =" purpose-name" >{{ formatPurposeName(purpose[2]) }}</div >
98+ <div class =" purpose-status" >
99+ <span v-if =" purpose[0]" class =" status-allowed" >✓ {{ t('libresign', 'Allowed') }}</span >
100+ <span v-else class =" status-denied" >✗ {{ t('libresign', 'Not allowed') }}</span >
101+ <span v-if =" purpose[1]" class =" ca-badge" >CA</span >
102+ </div >
103+ </div >
104+ </div >
105+ </NcSettingsSection >
106+ </div >
62107</template >
63108
64109<script >
65110
66- // import CertificateContent from './CertificateContent.vue'
67111import { selectCustonOption } from ' ../../helpers/certification.js'
112+ import NcSettingsSection from ' @nextcloud/vue/dist/Components/NcSettingsSection.js'
68113
69114export default {
70115 name: ' CertificateContent' ,
116+ components: {
117+ NcSettingsSection,
118+ },
71119 props: {
72120 certificate: {
73121 type: Object ,
@@ -79,6 +127,9 @@ export default {
79127 default: ' 0' ,
80128 },
81129 },
130+ data () {
131+ return {}
132+ },
82133 methods: {
83134 orderList (data ) {
84135 const sorted = {};
@@ -102,34 +153,139 @@ export default {
102153 return id
103154 }
104155 },
156+ formatPurposeName (purpose ) {
157+ const purposeNames = {
158+ ' sslclient' : this .t (' libresign' , ' SSL Client' ),
159+ ' sslserver' : this .t (' libresign' , ' SSL Server' ),
160+ ' nssslserver' : this .t (' libresign' , ' Netscape SSL Server' ),
161+ ' smimesign' : this .t (' libresign' , ' S/MIME Signing' ),
162+ ' smimeencrypt' : this .t (' libresign' , ' S/MIME Encryption' ),
163+ ' crlsign' : this .t (' libresign' , ' CRL Signing' ),
164+ ' any' : this .t (' libresign' , ' Any Purpose' ),
165+ ' ocsphelper' : this .t (' libresign' , ' OCSP Helper' ),
166+ ' timestampsign' : this .t (' libresign' , ' Timestamp Signing' ),
167+ ' codesign' : this .t (' libresign' , ' Code Signing' ),
168+ }
169+ return purposeNames[purpose] || purpose
170+ },
171+ getChainCertificateLabel (index , certificate ) {
172+ if (index === 0 ) {
173+ return this .t (' libresign' , ' Intermediate Certificate' )
174+ }
175+ if (certificate .subject && certificate .issuer &&
176+ JSON .stringify (certificate .subject ) === JSON .stringify (certificate .issuer )) {
177+ return this .t (' libresign' , ' Root Certificate (CA)' )
178+ }
179+ return this .t (' libresign' , ' Certificate {number}' , { number: index + 1 })
180+ },
105181 },
106182}
107183 </script >
184+
108185<style lang="scss" scoped>
109- table {
110- width : 100% ;
111- white-space : unset ;
186+ .certificate-content {
187+ max-width : 900px ;
188+ }
189+
190+ .certificate-field {
191+ display : flex ;
192+ flex-direction : column ;
193+ padding : 12px 0 ;
194+ border-bottom : 1px solid var (--color-border-dark );
195+ gap : 4px ;
196+
197+ & :last-child {
198+ border-bottom : none ;
199+ }
200+
201+ @media (min-width : 768px ) {
202+ flex-direction : row ;
203+ gap : 16px ;
204+ }
112205}
113206
114- td {
115- padding : 5px ;
116- border-bottom : 1px solid var (--color-border );
207+ .field-label {
208+ font-size : 12px ;
209+ color : var (--color-text-maxcontrast );
210+ font-weight : 500 ;
211+
212+ @media (min-width : 768px ) {
213+ min-width : 140px ;
214+ text-align : right ;
215+ padding-right : 16px ;
216+ border-right : 1px solid var (--color-border-dark );
217+ }
117218}
118219
119- td :nth-child (2 ) {
220+ .field-value {
221+ color : var (--color-main-text );
120222 word-break : break-all ;
223+ flex : 1 ;
224+ }
225+
226+ .chain-certificate {
227+ background : var (--color-background-hover );
228+ border-radius : var (--border-radius );
229+ margin-bottom : 16px ;
230+
231+ .chain-title {
232+ background : var (--color-background-dark );
233+ padding : 12px 16px ;
234+ font-weight : 600 ;
235+ border-radius : var (--border-radius ) var (--border-radius ) 0 0 ;
236+ }
237+
238+ .certificate-content {
239+ padding : 16px ;
240+ }
241+ }
242+
243+ .purposes-grid {
244+ display : grid ;
245+ grid-template-columns : repeat (auto-fit , minmax (280px , 1fr ));
246+ gap : 12px ;
121247}
122248
123- th {
249+ .purpose-item {
250+ background : var (--color-background-hover );
251+ border : 1px solid var (--color-border );
252+ border-radius : var (--border-radius );
253+ padding : 12px ;
254+
255+ & .purpose-allowed {
256+ border-left : 4px solid var (--color-success );
257+ }
258+
259+ & .purpose-denied {
260+ border-left : 4px solid var (--color-error );
261+ }
262+ }
263+
264+ .purpose-status {
265+ display : flex ;
266+ align-items : center ;
267+ gap : 8px ;
268+ font-size : 12px ;
269+ margin-top : 4px ;
270+ }
271+
272+ .status-allowed {
273+ color : var (--color-success );
124274 font-weight : bold ;
125275}
126276
127- tr :last-child td {
128- border-bottom : none ;
277+ .status-denied {
278+ color : var (--color-error );
279+ font-weight : bold ;
129280}
130281
131- td :first-child , th :first-child {
132- opacity : .5 ;
133- word-break : normal ;
282+ .ca-badge {
283+ background : var (--color-warning );
284+ color : white ;
285+ padding : 2px 6px ;
286+ border-radius : 10px ;
287+ font-size : 10px ;
288+ font-weight : bold ;
289+ text-transform : uppercase ;
134290}
135291 </style >
0 commit comments