1<template> 2 <div> 3 <b-modal 4 id="generate-csr" 5 ref="modal" 6 size="lg" 7 no-stacking 8 :title="$t('pageCertificates.modal.generateACertificateSigningRequest')" 9 @ok="onOkGenerateCsrModal" 10 @cancel="resetForm" 11 @hidden="$v.$reset()" 12 > 13 <b-form id="generate-csr-form" novalidate> 14 <b-container fluid> 15 <b-row> 16 <b-col lg="9"> 17 <b-row> 18 <b-col lg="6"> 19 <b-form-group 20 :label="$t('pageCertificates.modal.certificateType')" 21 label-for="certificate-type" 22 > 23 <b-form-select 24 id="certificate-type" 25 v-model="form.certificateType" 26 data-test-id="modalGenerateCsr-select-certificateType" 27 :options="certificateOptions" 28 :state="getValidationState($v.form.certificateType)" 29 @input="$v.form.certificateType.$touch()" 30 > 31 <template #first> 32 <b-form-select-option :value="null" disabled> 33 {{ $t('global.form.selectAnOption') }} 34 </b-form-select-option> 35 </template> 36 </b-form-select> 37 <b-form-invalid-feedback role="alert"> 38 {{ $t('global.form.fieldRequired') }} 39 </b-form-invalid-feedback> 40 </b-form-group> 41 </b-col> 42 <b-col lg="6"> 43 <b-form-group 44 :label="$t('pageCertificates.modal.country')" 45 label-for="country" 46 > 47 <b-form-select 48 id="country" 49 v-model="form.country" 50 data-test-id="modalGenerateCsr-select-country" 51 :options="countryOptions" 52 :state="getValidationState($v.form.country)" 53 @input="$v.form.country.$touch()" 54 > 55 <template #first> 56 <b-form-select-option :value="null" disabled> 57 {{ $t('global.form.selectAnOption') }} 58 </b-form-select-option> 59 </template> 60 </b-form-select> 61 <b-form-invalid-feedback role="alert"> 62 {{ $t('global.form.fieldRequired') }} 63 </b-form-invalid-feedback> 64 </b-form-group> 65 </b-col> 66 </b-row> 67 <b-row> 68 <b-col lg="6"> 69 <b-form-group 70 :label="$t('pageCertificates.modal.state')" 71 label-for="state" 72 > 73 <b-form-input 74 id="state" 75 v-model="form.state" 76 type="text" 77 data-test-id="modalGenerateCsr-input-state" 78 :state="getValidationState($v.form.state)" 79 /> 80 <b-form-invalid-feedback role="alert"> 81 {{ $t('global.form.fieldRequired') }} 82 </b-form-invalid-feedback> 83 </b-form-group> 84 </b-col> 85 <b-col lg="6"> 86 <b-form-group 87 :label="$t('pageCertificates.modal.city')" 88 label-for="city" 89 > 90 <b-form-input 91 id="city" 92 v-model="form.city" 93 type="text" 94 data-test-id="modalGenerateCsr-input-city" 95 :state="getValidationState($v.form.city)" 96 /> 97 <b-form-invalid-feedback role="alert"> 98 {{ $t('global.form.fieldRequired') }} 99 </b-form-invalid-feedback> 100 </b-form-group> 101 </b-col> 102 </b-row> 103 <b-row> 104 <b-col lg="6"> 105 <b-form-group 106 :label="$t('pageCertificates.modal.companyName')" 107 label-for="company-name" 108 > 109 <b-form-input 110 id="company-name" 111 v-model="form.companyName" 112 type="text" 113 data-test-id="modalGenerateCsr-input-companyName" 114 :state="getValidationState($v.form.companyName)" 115 /> 116 <b-form-invalid-feedback role="alert"> 117 {{ $t('global.form.fieldRequired') }} 118 </b-form-invalid-feedback> 119 </b-form-group> 120 </b-col> 121 <b-col lg="6"> 122 <b-form-group 123 :label="$t('pageCertificates.modal.companyUnit')" 124 label-for="company-unit" 125 > 126 <b-form-input 127 id="company-unit" 128 v-model="form.companyUnit" 129 type="text" 130 data-test-id="modalGenerateCsr-input-companyUnit" 131 :state="getValidationState($v.form.companyUnit)" 132 /> 133 <b-form-invalid-feedback role="alert"> 134 {{ $t('global.form.fieldRequired') }} 135 </b-form-invalid-feedback> 136 </b-form-group> 137 </b-col> 138 </b-row> 139 <b-row> 140 <b-col lg="6"> 141 <b-form-group 142 :label="$t('pageCertificates.modal.commonName')" 143 label-for="common-name" 144 > 145 <b-form-input 146 id="common-name" 147 v-model="form.commonName" 148 type="text" 149 data-test-id="modalGenerateCsr-input-commonName" 150 :state="getValidationState($v.form.commonName)" 151 /> 152 <b-form-invalid-feedback role="alert"> 153 {{ $t('global.form.fieldRequired') }} 154 </b-form-invalid-feedback> 155 </b-form-group> 156 </b-col> 157 <b-col lg="6"> 158 <b-form-group label-for="contact-person"> 159 <template #label> 160 {{ $t('pageCertificates.modal.contactPerson') }} - 161 <span class="form-text d-inline"> 162 {{ $t('global.form.optional') }} 163 </span> 164 </template> 165 <b-form-input 166 id="contact-person" 167 v-model="form.contactPerson" 168 type="text" 169 data-test-id="modalGenerateCsr-input-contactPerson" 170 /> 171 </b-form-group> 172 </b-col> 173 </b-row> 174 <b-row> 175 <b-col lg="6"> 176 <b-form-group label-for="email-address"> 177 <template #label> 178 {{ $t('pageCertificates.modal.emailAddress') }} - 179 <span class="form-text d-inline"> 180 {{ $t('global.form.optional') }} 181 </span> 182 </template> 183 <b-form-input 184 id="email-address" 185 v-model="form.emailAddress" 186 type="text" 187 data-test-id="modalGenerateCsr-input-emailAddress" 188 /> 189 </b-form-group> 190 </b-col> 191 </b-row> 192 <b-row> 193 <b-col lg="12"> 194 <b-form-group label-for="alternate-name"> 195 <template #label> 196 {{ $t('pageCertificates.modal.alternateName') }} - 197 <span class="form-text d-inline"> 198 {{ $t('global.form.optional') }} 199 </span> 200 </template> 201 <b-form-text id="alternate-name-help-block"> 202 {{ $t('pageCertificates.modal.alternateNameHelperText') }} 203 </b-form-text> 204 <b-form-tags 205 v-model="form.alternateName" 206 :remove-on-delete="true" 207 :tag-pills="true" 208 input-id="alternate-name" 209 size="lg" 210 separator=" " 211 :input-attrs="{ 212 'aria-describedby': 'alternate-name-help-block', 213 }" 214 :duplicate-tag-text=" 215 $t('pageCertificates.modal.duplicateAlternateName') 216 " 217 placeholder="" 218 data-test-id="modalGenerateCsr-input-alternateName" 219 > 220 <template #add-button-text> 221 <icon-add /> {{ $t('global.action.add') }} 222 </template> 223 </b-form-tags> 224 </b-form-group> 225 </b-col> 226 </b-row> 227 </b-col> 228 <b-col lg="3"> 229 <b-row> 230 <b-col lg="12"> 231 <p class="col-form-label"> 232 {{ $t('pageCertificates.modal.privateKey') }} 233 </p> 234 <b-form-group 235 :label="$t('pageCertificates.modal.keyPairAlgorithm')" 236 label-for="key-pair-algorithm" 237 > 238 <b-form-select 239 id="key-pair-algorithm" 240 v-model="form.keyPairAlgorithm" 241 data-test-id="modalGenerateCsr-select-keyPairAlgorithm" 242 :options="keyPairAlgorithmOptions" 243 :state="getValidationState($v.form.keyPairAlgorithm)" 244 @input="$v.form.keyPairAlgorithm.$touch()" 245 > 246 <template #first> 247 <b-form-select-option :value="null" disabled> 248 {{ $t('global.form.selectAnOption') }} 249 </b-form-select-option> 250 </template> 251 </b-form-select> 252 <b-form-invalid-feedback role="alert"> 253 {{ $t('global.form.fieldRequired') }} 254 </b-form-invalid-feedback> 255 </b-form-group> 256 </b-col> 257 </b-row> 258 <b-row> 259 <b-col lg="12"> 260 <template v-if="$v.form.keyPairAlgorithm.$model === 'EC'"> 261 <b-form-group 262 :label="$t('pageCertificates.modal.keyCurveId')" 263 label-for="key-curve-id" 264 > 265 <b-form-select 266 id="key-curve-id" 267 v-model="form.keyCurveId" 268 data-test-id="modalGenerateCsr-select-keyCurveId" 269 :options="keyCurveIdOptions" 270 :state="getValidationState($v.form.keyCurveId)" 271 @input="$v.form.keyCurveId.$touch()" 272 > 273 <template #first> 274 <b-form-select-option :value="null" disabled> 275 {{ $t('global.form.selectAnOption') }} 276 </b-form-select-option> 277 </template> 278 </b-form-select> 279 <b-form-invalid-feedback role="alert"> 280 {{ $t('global.form.fieldRequired') }} 281 </b-form-invalid-feedback> 282 </b-form-group> 283 </template> 284 <template v-if="$v.form.keyPairAlgorithm.$model === 'RSA'"> 285 <b-form-group 286 :label="$t('pageCertificates.modal.keyBitLength')" 287 label-for="key-bit-length" 288 > 289 <b-form-select 290 id="key-bit-length" 291 v-model="form.keyBitLength" 292 data-test-id="modalGenerateCsr-select-keyBitLength" 293 :options="keyBitLengthOptions" 294 :state="getValidationState($v.form.keyBitLength)" 295 @input="$v.form.keyBitLength.$touch()" 296 > 297 <template #first> 298 <b-form-select-option :value="null" disabled> 299 {{ $t('global.form.selectAnOption') }} 300 </b-form-select-option> 301 </template> 302 </b-form-select> 303 <b-form-invalid-feedback role="alert"> 304 {{ $t('global.form.fieldRequired') }} 305 </b-form-invalid-feedback> 306 </b-form-group> 307 </template> 308 </b-col> 309 </b-row> 310 </b-col> 311 </b-row> 312 </b-container> 313 </b-form> 314 <template #modal-footer="{ ok, cancel }"> 315 <b-button variant="secondary" @click="cancel()"> 316 {{ $t('global.action.cancel') }} 317 </b-button> 318 <b-button 319 form="generate-csr-form" 320 type="submit" 321 variant="primary" 322 data-test-id="modalGenerateCsr-button-ok" 323 @click="ok()" 324 > 325 {{ $t('pageCertificates.generateCsr') }} 326 </b-button> 327 </template> 328 </b-modal> 329 <b-modal 330 id="csr-string" 331 no-stacking 332 size="lg" 333 :title="$t('pageCertificates.modal.certificateSigningRequest')" 334 @hidden="onHiddenCsrStringModal" 335 > 336 {{ csrString }} 337 <template #modal-footer> 338 <b-btn variant="secondary" @click="copyCsrString"> 339 <template v-if="csrStringCopied"> 340 <icon-checkmark /> 341 {{ $t('global.status.copied') }} 342 </template> 343 <template v-else> 344 {{ $t('global.action.copy') }} 345 </template> 346 </b-btn> 347 <a 348 :href=" 349 `data:application/json;charset=utf-8,` + 350 encodeURIComponent(`${csrString}`) 351 " 352 download="certificate.csr" 353 class="btn btn-primary" 354 > 355 {{ $t('global.action.download') }} 356 </a> 357 </template> 358 </b-modal> 359 </div> 360</template> 361 362<script> 363import IconAdd from '@carbon/icons-vue/es/add--alt/20'; 364import IconCheckmark from '@carbon/icons-vue/es/checkmark/20'; 365 366import { required, requiredIf } from 'vuelidate/lib/validators'; 367 368import { COUNTRY_LIST } from './CsrCountryCodes'; 369import BVToastMixin from '@/components/Mixins/BVToastMixin'; 370import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js'; 371 372export default { 373 name: 'ModalGenerateCsr', 374 components: { IconAdd, IconCheckmark }, 375 mixins: [BVToastMixin, VuelidateMixin], 376 data() { 377 return { 378 form: { 379 certificateType: null, 380 country: null, 381 state: null, 382 city: null, 383 companyName: null, 384 companyUnit: null, 385 commonName: null, 386 contactPerson: null, 387 emailAddress: null, 388 alternateName: [], 389 keyPairAlgorithm: null, 390 keyCurveId: null, 391 keyBitLength: null, 392 }, 393 countryOptions: COUNTRY_LIST.map((country) => ({ 394 text: country.label, 395 value: country.code, 396 })), 397 keyPairAlgorithmOptions: ['EC', 'RSA'], 398 keyCurveIdOptions: ['prime256v1', 'secp521r1', 'secp384r1'], 399 keyBitLengthOptions: [2048], 400 csrString: '', 401 csrStringCopied: false, 402 }; 403 }, 404 computed: { 405 certificateTypes() { 406 return this.$store.getters['certificates/certificateTypes']; 407 }, 408 certificateOptions() { 409 return this.certificateTypes.reduce((arr, cert) => { 410 if (cert.type === 'TrustStore Certificate') return arr; 411 arr.push({ 412 text: cert.label, 413 value: cert.type, 414 }); 415 return arr; 416 }, []); 417 }, 418 }, 419 validations: { 420 form: { 421 certificateType: { required }, 422 country: { required }, 423 state: { required }, 424 city: { required }, 425 companyName: { required }, 426 companyUnit: { required }, 427 commonName: { required }, 428 contactPerson: {}, 429 emailAddress: {}, 430 alternateName: {}, 431 keyPairAlgorithm: { required }, 432 keyCurveId: { 433 reuired: requiredIf(function (form) { 434 return form.keyPairAlgorithm === 'EC'; 435 }), 436 }, 437 keyBitLength: { 438 reuired: requiredIf(function (form) { 439 return form.keyPairAlgorithm === 'RSA'; 440 }), 441 }, 442 }, 443 }, 444 methods: { 445 handleSubmit() { 446 this.$v.$touch(); 447 if (this.$v.$invalid) return; 448 this.$store 449 .dispatch('certificates/generateCsr', this.form) 450 .then(({ data: { CSRString } }) => { 451 this.csrString = CSRString; 452 this.$bvModal.show('csr-string'); 453 this.$v.$reset(); 454 }); 455 }, 456 resetForm() { 457 for (let key of Object.keys(this.form)) { 458 if (key === 'alternateName') { 459 this.form[key] = []; 460 } else { 461 this.form[key] = null; 462 } 463 } 464 }, 465 onOkGenerateCsrModal(bvModalEvt) { 466 // prevent modal close 467 bvModalEvt.preventDefault(); 468 this.handleSubmit(); 469 }, 470 onHiddenCsrStringModal() { 471 this.csrString = ''; 472 this.resetForm(); 473 }, 474 copyCsrString(bvModalEvt) { 475 // prevent modal close 476 bvModalEvt.preventDefault(); 477 navigator.clipboard.writeText(this.csrString).then(() => { 478 // Show copied text for 5 seconds 479 this.csrStringCopied = true; 480 setTimeout(() => { 481 this.csrStringCopied = false; 482 }, 5000 /*5 seconds*/); 483 }); 484 }, 485 }, 486}; 487</script> 488