feat(new tool): Certificate/Key Parser and infos
Parse Certificate and Keys (Public, Private, Signature, Fingerprint...) and displays infos Fix #671
This commit is contained in:
		
							parent
							
								
									e073b2babf
								
							
						
					
					
						commit
						ce8199e338
					
				| @ -62,6 +62,7 @@ | ||||
|     "highlight.js": "^11.7.0", | ||||
|     "iarna-toml-esm": "^3.0.5", | ||||
|     "ibantools": "^4.3.3", | ||||
|     "js-base64": "^3.7.7", | ||||
|     "json5": "^2.2.3", | ||||
|     "jwt-decode": "^3.1.2", | ||||
|     "libphonenumber-js": "^1.10.28", | ||||
|  | ||||
							
								
								
									
										19
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										19
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -86,6 +86,9 @@ dependencies: | ||||
|   ibantools: | ||||
|     specifier: ^4.3.3 | ||||
|     version: 4.3.3 | ||||
|   js-base64: | ||||
|     specifier: ^3.7.7 | ||||
|     version: 3.7.7 | ||||
|   json5: | ||||
|     specifier: ^2.2.3 | ||||
|     version: 2.2.3 | ||||
| @ -3378,7 +3381,7 @@ packages: | ||||
|     dependencies: | ||||
|       '@unhead/dom': 0.5.1 | ||||
|       '@unhead/schema': 0.5.1 | ||||
|       '@vueuse/shared': 10.7.2(vue@3.3.4) | ||||
|       '@vueuse/shared': 10.9.0(vue@3.3.4) | ||||
|       unhead: 0.5.1 | ||||
|       vue: 3.3.4 | ||||
|     transitivePeerDependencies: | ||||
| @ -4020,10 +4023,10 @@ packages: | ||||
|       - vue | ||||
|     dev: false | ||||
| 
 | ||||
|   /@vueuse/shared@10.7.2(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==} | ||||
|   /@vueuse/shared@10.9.0(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==} | ||||
|     dependencies: | ||||
|       vue-demi: 0.14.6(vue@3.3.4) | ||||
|       vue-demi: 0.14.7(vue@3.3.4) | ||||
|     transitivePeerDependencies: | ||||
|       - '@vue/composition-api' | ||||
|       - vue | ||||
| @ -6795,6 +6798,10 @@ packages: | ||||
|     hasBin: true | ||||
|     dev: true | ||||
| 
 | ||||
|   /js-base64@3.7.7: | ||||
|     resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /js-beautify@1.14.6: | ||||
|     resolution: {integrity: sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==} | ||||
|     engines: {node: '>=10'} | ||||
| @ -9752,8 +9759,8 @@ packages: | ||||
|       vue: 3.3.4 | ||||
|     dev: false | ||||
| 
 | ||||
|   /vue-demi@0.14.6(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} | ||||
|   /vue-demi@0.14.7(vue@3.3.4): | ||||
|     resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==} | ||||
|     engines: {node: '>=12'} | ||||
|     hasBin: true | ||||
|     requiresBuild: true | ||||
|  | ||||
| @ -2,7 +2,12 @@ | ||||
| import { useVModel } from '@vueuse/core'; | ||||
| import { useCopy } from '@/composable/copy'; | ||||
| 
 | ||||
| const props = defineProps<{ value: string }>(); | ||||
| const props = defineProps<{ | ||||
|   value: string | ||||
|   multiline?: boolean | ||||
|   rows?: number | string | ||||
|   autosize?: boolean | ||||
| }>(); | ||||
| const emit = defineEmits(['update:value']); | ||||
| 
 | ||||
| const value = useVModel(props, 'value', emit); | ||||
| @ -11,7 +16,12 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : 'Copy to cli | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <c-input-text v-model:value="value"> | ||||
|   <c-input-text | ||||
|     v-model:value="value" | ||||
|     :multiline="multiline" | ||||
|     :rows="rows" | ||||
|     :autosize="autosize" | ||||
|   > | ||||
|     <template #suffix> | ||||
|       <c-tooltip :tooltip="tooltipText"> | ||||
|         <c-button circle variant="text" size="small" @click="copy()"> | ||||
|  | ||||
| @ -1,8 +1,13 @@ | ||||
| import { extension as getExtensionFromMime } from 'mime-types'; | ||||
| import { extension as getExtensionFromMimeType, extension as getMimeTypeFromExtension } from 'mime-types'; | ||||
| import type { Ref } from 'vue'; | ||||
| import _ from 'lodash'; | ||||
| 
 | ||||
| export { getMimeTypeFromBase64, useDownloadFileFromBase64 }; | ||||
| export { | ||||
|   getMimeTypeFromBase64, | ||||
|   getMimeTypeFromExtension, getExtensionFromMimeType, | ||||
|   useDownloadFileFromBase64, useDownloadFileFromBase64Refs, | ||||
|   previewImageFromBase64, | ||||
| }; | ||||
| 
 | ||||
| const commonMimeTypesSignatures = { | ||||
|   'JVBERi0': 'application/pdf', | ||||
| @ -36,30 +41,78 @@ function getFileExtensionFromMimeType({ | ||||
|   defaultExtension?: string | ||||
| }) { | ||||
|   if (mimeType) { | ||||
|     return getExtensionFromMime(mimeType) ?? defaultExtension; | ||||
|     return getExtensionFromMimeType(mimeType) ?? defaultExtension; | ||||
|   } | ||||
| 
 | ||||
|   return defaultExtension; | ||||
| } | ||||
| 
 | ||||
| function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) { | ||||
|   return { | ||||
|     download() { | ||||
|       if (source.value === '') { | ||||
| function downloadFromBase64({ sourceValue, filename, extension, fileMimeType }: | ||||
| { sourceValue: string; filename?: string; extension?: string; fileMimeType?: string }) { | ||||
|   if (sourceValue === '') { | ||||
|     throw new Error('Base64 string is empty'); | ||||
|   } | ||||
| 
 | ||||
|       const { mimeType } = getMimeTypeFromBase64({ base64String: source.value }); | ||||
|       const base64String = mimeType | ||||
|         ? source.value | ||||
|         : `data:text/plain;base64,${source.value}`; | ||||
|   const defaultExtension = extension ?? 'txt'; | ||||
|   const { mimeType } = getMimeTypeFromBase64({ base64String: sourceValue }); | ||||
|   let base64String = sourceValue; | ||||
|   if (!mimeType) { | ||||
|     const targetMimeType = fileMimeType ?? getMimeTypeFromExtension(defaultExtension); | ||||
|     base64String = `data:${targetMimeType};base64,${sourceValue}`; | ||||
|   } | ||||
| 
 | ||||
|       const cleanFileName = filename ?? `file.${getFileExtensionFromMimeType({ mimeType })}`; | ||||
|   const cleanExtension = extension ?? getFileExtensionFromMimeType( | ||||
|     { mimeType, defaultExtension }); | ||||
|   let cleanFileName = filename ?? `file.${cleanExtension}`; | ||||
|   if (extension && !cleanFileName.endsWith(`.${extension}`)) { | ||||
|     cleanFileName = `${cleanFileName}.${cleanExtension}`; | ||||
|   } | ||||
| 
 | ||||
|   const a = document.createElement('a'); | ||||
|   a.href = base64String; | ||||
|   a.download = cleanFileName; | ||||
|   a.click(); | ||||
| } | ||||
| 
 | ||||
| function useDownloadFileFromBase64( | ||||
|   { source, filename, extension, fileMimeType }: | ||||
|   { source: Ref<string>; filename?: string; extension?: string; fileMimeType?: string }) { | ||||
|   return { | ||||
|     download() { | ||||
|       downloadFromBase64({ sourceValue: source.value, filename, extension, fileMimeType }); | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function useDownloadFileFromBase64Refs( | ||||
|   { source, filename, extension }: | ||||
|   { source: Ref<string>; filename?: Ref<string>; extension?: Ref<string> }) { | ||||
|   return { | ||||
|     download() { | ||||
|       downloadFromBase64({ sourceValue: source.value, filename: filename?.value, extension: extension?.value }); | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function previewImageFromBase64(base64String: string): HTMLImageElement { | ||||
|   if (base64String === '') { | ||||
|     throw new Error('Base64 string is empty'); | ||||
|   } | ||||
| 
 | ||||
|   const img = document.createElement('img'); | ||||
|   img.src = base64String; | ||||
| 
 | ||||
|   const container = document.createElement('div'); | ||||
|   container.appendChild(img); | ||||
| 
 | ||||
|   const previewContainer = document.getElementById('previewContainer'); | ||||
|   if (previewContainer) { | ||||
|     previewContainer.innerHTML = ''; | ||||
|     previewContainer.appendChild(container); | ||||
|   } | ||||
|   else { | ||||
|     throw new Error('Preview container element not found'); | ||||
|   } | ||||
| 
 | ||||
|   return img; | ||||
| } | ||||
|  | ||||
							
								
								
									
										354
									
								
								src/tools/certificate-key-parser/certificate-key-parser.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								src/tools/certificate-key-parser/certificate-key-parser.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,354 @@ | ||||
| <script setup lang="ts"> | ||||
| import { Buffer } from 'node:buffer'; | ||||
| import { | ||||
|   parseCertificate, parseFingerprint, | ||||
|   parseKey, | ||||
|   parsePrivateKey, | ||||
|   parseSignature, | ||||
| } from 'sshpk'; | ||||
| import type { | ||||
|   AlgorithmType, | ||||
|   Certificate, | ||||
|   CertificateFormat, | ||||
|   Fingerprint, | ||||
|   Key, | ||||
|   PrivateKey, Signature, SignatureFormatType, | ||||
| } from 'sshpk'; | ||||
| import { Base64 } from 'js-base64'; | ||||
| import { useDownloadFileFromBase64 } from '@/composable/downloadBase64'; | ||||
| 
 | ||||
| function buf2Hex(buffer: ArrayBuffer) { // buffer is an ArrayBuffer | ||||
|   return [...new Uint8Array(buffer)] | ||||
|     .map(x => x.toString(16).padStart(2, '0')) | ||||
|     .join(''); | ||||
| } | ||||
| 
 | ||||
| const inputKeyOrCertificate = ref(''); | ||||
| const passphrase = ref(''); | ||||
| const fileInput = ref() as Ref<Buffer>; | ||||
| 
 | ||||
| async function onUpload(file: File) { | ||||
|   if (file) { | ||||
|     fileInput.value = Buffer.from(await file.arrayBuffer()); | ||||
|     inputKeyOrCertificate.value = ''; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const certificateX509DER = ref(''); | ||||
| const { download: downloadX509DER } = useDownloadFileFromBase64( | ||||
|   { | ||||
|     source: certificateX509DER, | ||||
|     extension: 'der', | ||||
|   }); | ||||
| 
 | ||||
| function downloadX509DERFile() { | ||||
|   if (certificateX509DER.value === '') { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   try { | ||||
|     downloadX509DER(); | ||||
|   } | ||||
|   catch (_) { | ||||
|     // | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| interface LabelValue { | ||||
|   label: string | ||||
|   value: string | ||||
|   multiline?: boolean | ||||
| } | ||||
| const parsedSections = computed<LabelValue[]>(() => { | ||||
|   try { | ||||
|     certificateX509DER.value = ''; | ||||
|     const onErrorReturnErrorMessage = (func: () => any) => { | ||||
|       try { | ||||
|         return func(); | ||||
|       } | ||||
|       catch (e: any) { | ||||
|         return e.toString(); | ||||
|       } | ||||
|     }; | ||||
|     const canParse = (value: string | Buffer, parseFunction: (value: string | Buffer) => any) => { | ||||
|       try { | ||||
|         return parseFunction(value); | ||||
|       } | ||||
|       catch { | ||||
|         return null; | ||||
|       } | ||||
|     }; | ||||
|     const inputKeyOrCertificateValue | ||||
|       = inputKeyOrCertificate.value !== '' | ||||
|         ? inputKeyOrCertificate.value | ||||
|         : fileInput.value; | ||||
|     const publicKey = canParse(inputKeyOrCertificateValue, parseKey) as Key; | ||||
|     if (publicKey) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'Public Key', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Key Type: ', | ||||
|           value: publicKey.type, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Size: ', | ||||
|           value: publicKey.size, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Comment: ', | ||||
|           value: publicKey.comment, | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Curve: ', | ||||
|           value: publicKey.curve ?? 'none', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (sha256): ', | ||||
|           value: onErrorReturnErrorMessage(() => publicKey.fingerprint('sha256')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (sha512): ', | ||||
|           value: onErrorReturnErrorMessage(() => publicKey.fingerprint('sha512')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|       ] as LabelValue[]; | ||||
|     } | ||||
| 
 | ||||
|     const privateKey = canParse(inputKeyOrCertificateValue, | ||||
|       value => parsePrivateKey(value, 'auto', { passphrase: passphrase.value })) as PrivateKey; | ||||
|     if (privateKey) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'Private Key', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Key Type: ', | ||||
|           value: privateKey.type, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Size: ', | ||||
|           value: privateKey.size, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Comment: ', | ||||
|           value: privateKey.comment, | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Curve: ', | ||||
|           value: privateKey.curve, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (sha256): ', | ||||
|           value: onErrorReturnErrorMessage(() => privateKey.fingerprint('sha256')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (sha512): ', | ||||
|           value: onErrorReturnErrorMessage(() => privateKey.fingerprint('sha512')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|       ] as LabelValue[]; | ||||
|     } | ||||
| 
 | ||||
|     const cert = canParse(inputKeyOrCertificateValue, (value) => { | ||||
|       for (const format of ['openssh', 'pem', 'x509']) { | ||||
|         try { | ||||
|           return parseCertificate(value, format as CertificateFormat); | ||||
|         } | ||||
|         catch {} | ||||
|       } | ||||
|       return null; | ||||
|     }) as Certificate; | ||||
|     if (cert) { | ||||
|       try { | ||||
|         certificateX509DER.value = Base64.fromUint8Array(cert.toBuffer('x509')); | ||||
|       } | ||||
|       catch {} | ||||
| 
 | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'Certificate', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subjects: ', | ||||
|           value: cert.subjects.map(s => s.toString()).join('\n'), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Issuer: ', | ||||
|           value: cert.issuer.toString(), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subject Key: ', | ||||
|           value: onErrorReturnErrorMessage(() => cert.subjectKey?.toString('ssh')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subject Key Type: ', | ||||
|           value: cert.subjectKey?.type, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subject Size: ', | ||||
|           value: cert.subjectKey?.size, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subject Comment: ', | ||||
|           value: cert.subjectKey?.comment, | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subject Curve: ', | ||||
|           value: cert.subjectKey?.curve ?? 'none', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Issuer Key: ', | ||||
|           value: onErrorReturnErrorMessage(() => cert.issuerKey?.toString('ssh')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Serial: ', | ||||
|           value: buf2Hex(cert.serial), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Purposes: ', | ||||
|           value: cert.purposes?.join(', '), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Extensions: ', | ||||
|           value: JSON.stringify(cert.getExtensions(), null, 2), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (sha256): ', | ||||
|           value: onErrorReturnErrorMessage(() => cert.fingerprint('sha256')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (sha512): ', | ||||
|           value: onErrorReturnErrorMessage(() => cert.fingerprint('sha512')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Certificate (pem): ', | ||||
|           value: onErrorReturnErrorMessage(() => cert.toString('pem')), | ||||
|           multiline: true, | ||||
|         }, | ||||
|       ] as LabelValue[]; | ||||
|     } | ||||
| 
 | ||||
|     const fingerprint = canParse(inputKeyOrCertificateValue, value => parseFingerprint(value.toString())) as Fingerprint; | ||||
|     if (fingerprint) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'Fingerprint', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (hex): ', | ||||
|           value: fingerprint.toString('hex'), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (base64): ', | ||||
|           value: fingerprint.toString('base64'), | ||||
|         }, | ||||
|       ] as LabelValue[]; | ||||
|     } | ||||
| 
 | ||||
|     const signature = canParse(inputKeyOrCertificateValue, (value) => { | ||||
|       // | ||||
|       for (const algo of ['dsa', 'rsa', 'ecdsa', 'ed25519']) { | ||||
|         for (const format of ['asn1', 'ssh', 'raw']) { | ||||
|           try { | ||||
|             return parseSignature(value, algo as AlgorithmType, format as SignatureFormatType); | ||||
|           } | ||||
|           catch {} | ||||
|         } | ||||
|       } | ||||
|       return null; | ||||
|     }) as Signature; | ||||
|     if (signature) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'Signature', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (asn1): ', | ||||
|           value: signature.toString('asn1'), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint (ssh): ', | ||||
|           value: signature.toString('ssh'), | ||||
|         }, | ||||
|       ] as LabelValue[]; | ||||
|     } | ||||
| 
 | ||||
|     return [ | ||||
|       { | ||||
|         label: 'Type: ', | ||||
|         value: 'Unknown format or invalid passphrase', | ||||
|       }]; | ||||
|   } | ||||
|   catch (e: any) { | ||||
|     return [ | ||||
|       { | ||||
|         label: 'Error: ', | ||||
|         value: e.toString(), | ||||
|       }] as LabelValue[]; | ||||
|   } | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div> | ||||
|     <c-card> | ||||
|       <c-file-upload title="Drag and drop a Certificate file here, or click to select a Certificate file" @file-upload="onUpload" /> | ||||
|       <p>-OR-</p> | ||||
|       <c-input-text | ||||
|         v-model:value="inputKeyOrCertificate" | ||||
|         label="Paste your Public Key / Private Key / Signature / Fingerprint / Certificate:" | ||||
|         placeholder="Your Public Key / Private Key / Signature / Fingerprint / Certificate..." | ||||
|         multiline | ||||
|         rows="8" | ||||
|       /> | ||||
|     </c-card> | ||||
| 
 | ||||
|     <c-input-text | ||||
|       v-model:value="passphrase" | ||||
|       label="Passphrase (for encrypted keys):" | ||||
|       placeholder="Passphrase (for encrypted keys)..." | ||||
|       type="password" | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| 
 | ||||
|     <input-copyable | ||||
|       v-for="{ label, value, multiline } of parsedSections" | ||||
|       :key="label" | ||||
|       :label="label" | ||||
|       label-position="left" | ||||
|       label-width="100px" | ||||
|       label-align="right" | ||||
| 
 | ||||
|       autosize mb-2 | ||||
|       :multiline="multiline" | ||||
|       :value="value" | ||||
|       placeholder="Not Set" | ||||
|     /> | ||||
| 
 | ||||
|     <div v-if="certificateX509DER !== ''" flex justify-center> | ||||
|       <c-button @click="downloadX509DERFile()"> | ||||
|         Download X509 DER certificate | ||||
|       </c-button> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
							
								
								
									
										12
									
								
								src/tools/certificate-key-parser/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/tools/certificate-key-parser/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| import { FileCertificate } from '@vicons/tabler'; | ||||
| import { defineTool } from '../tool'; | ||||
| 
 | ||||
| export const tool = defineTool({ | ||||
|   name: 'Certificate/Key parser', | ||||
|   path: '/certificate-key-parser', | ||||
|   description: 'Parse Key and Certificate', | ||||
|   keywords: ['certificate', 'key', 'parser'], | ||||
|   component: () => import('./certificate-key-parser.vue'), | ||||
|   icon: FileCertificate, | ||||
|   createdAt: new Date('2024-02-22'), | ||||
| }); | ||||
| @ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter'; | ||||
| import { tool as base64StringConverter } from './base64-string-converter'; | ||||
| import { tool as basicAuthGenerator } from './basic-auth-generator'; | ||||
| import { tool as textToUnicode } from './text-to-unicode'; | ||||
| import { tool as certificateKeyParser } from './certificate-key-parser'; | ||||
| import { tool as pdfSignatureChecker } from './pdf-signature-checker'; | ||||
| import { tool as numeronymGenerator } from './numeronym-generator'; | ||||
| import { tool as macAddressGenerator } from './mac-address-generator'; | ||||
| @ -81,7 +82,20 @@ import { tool as yamlViewer } from './yaml-viewer'; | ||||
| export const toolsByCategory: ToolCategory[] = [ | ||||
|   { | ||||
|     name: 'Crypto', | ||||
|     components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker], | ||||
|     components: [ | ||||
|       tokenGenerator, | ||||
|       hashText, | ||||
|       bcrypt, | ||||
|       uuidGenerator, | ||||
|       ulidGenerator, | ||||
|       cypher, | ||||
|       bip39, | ||||
|       hmacGenerator, | ||||
|       rsaKeyPairGenerator, | ||||
|       certificateKeyParser, | ||||
|       passwordStrengthAnalyser, | ||||
|       pdfSignatureChecker, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     name: 'Converter', | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user