fix: refactor and unit test
This commit is contained in:
		
							parent
							
								
									c10302b138
								
							
						
					
					
						commit
						ddd3f6ed09
					
				
							
								
								
									
										333
									
								
								src/tools/certificate-key-parser/certificate-key-parser.infos.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								src/tools/certificate-key-parser/certificate-key-parser.infos.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,333 @@ | ||||
| import type { | ||||
|   Certificate, | ||||
|   Fingerprint, | ||||
|   Key, | ||||
|   PrivateKey, Signature, | ||||
| } from 'sshpk'; | ||||
| import type * as openpgp from 'openpgp'; | ||||
| import * as forge from 'node-forge'; | ||||
| 
 | ||||
| export interface LabelValue { | ||||
|   label: string | ||||
|   value: string | ||||
|   multiline?: boolean | ||||
| } | ||||
| 
 | ||||
| function onErrorReturnErrorMessage(func: () => any) { | ||||
|   try { | ||||
|     return func(); | ||||
|   } | ||||
|   catch (e: any) { | ||||
|     return e.toString(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function buf2Hex(buffer: ArrayBuffer) { // buffer is an ArrayBuffer
 | ||||
|   return [...new Uint8Array(buffer)] | ||||
|     .map(x => x.toString(16).padStart(2, '0')) | ||||
|     .join(''); | ||||
| } | ||||
| 
 | ||||
| export function getPublicKeyLabelValues(publicKey: Key) { | ||||
|   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[]; | ||||
| } | ||||
| 
 | ||||
| export function getPrivateKeyLabelValues(privateKey: 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[]; | ||||
| } | ||||
| 
 | ||||
| export function getCertificateLabelValues(cert: Certificate) { | ||||
|   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[]; | ||||
| } | ||||
| 
 | ||||
| export async function getPGPPublicKeyLabelValuesAsync(pgpPublicKey: openpgp.Key) { | ||||
|   return [ | ||||
|     { | ||||
|       label: 'Type:', | ||||
|       value: 'PGP Public Key', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Creation Time:', | ||||
|       value: pgpPublicKey.getCreationTime().toString(), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Expiration Time:', | ||||
|       value: (await pgpPublicKey.getExpirationTime())?.toString() || '', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Algorithm Info:', | ||||
|       value: JSON.stringify(pgpPublicKey.getAlgorithmInfo()), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Fingerprint:', | ||||
|       value: pgpPublicKey.getFingerprint(), | ||||
|     }, | ||||
|     { | ||||
|       label: 'User ID(s):', | ||||
|       value: pgpPublicKey.getUserIDs().join(', '), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Key ID(s):', | ||||
|       value: pgpPublicKey.getKeyIDs().map(k => k.toHex()).join(' ; '), | ||||
|     }, | ||||
|   ] as LabelValue[]; | ||||
| } | ||||
| 
 | ||||
| export async function getPGPPrivateKeyLabelValuesAsync(pgpPrivateKey: openpgp.Key) { | ||||
|   return [ | ||||
|     { | ||||
|       label: 'Type:', | ||||
|       value: 'PGP Private Key', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Creation Time:', | ||||
|       value: pgpPrivateKey.getCreationTime().toString(), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Expiration Time:', | ||||
|       value: (await pgpPrivateKey.getExpirationTime())?.toString() || '', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Algorithm Info:', | ||||
|       value: JSON.stringify(pgpPrivateKey.getAlgorithmInfo()), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Fingerprint:', | ||||
|       value: pgpPrivateKey.getFingerprint(), | ||||
|     }, | ||||
|     { | ||||
|       label: 'User ID(s):', | ||||
|       value: pgpPrivateKey.getUserIDs().join(', '), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Key ID(s):', | ||||
|       value: pgpPrivateKey.getKeyIDs().map(k => k.toHex()).join(' ; '), | ||||
|     }, | ||||
|   ] as LabelValue[]; | ||||
| } | ||||
| 
 | ||||
| export function getCSRLabelValues(csr: forge.pki.Certificate) { | ||||
|   return [ | ||||
|     { | ||||
|       label: 'Type:', | ||||
|       value: 'Certificate Signing Request', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Subject:', | ||||
|       value: csr.subject?.attributes?.map(a => JSON.stringify(a, null, 2)).join('\n'), | ||||
|       multiline: true, | ||||
|     }, | ||||
|     { | ||||
|       label: 'Issuer:', | ||||
|       value: csr.issuer?.toString(), | ||||
|       multiline: true, | ||||
|     }, | ||||
|     { | ||||
|       label: 'Validity:', | ||||
|       value: JSON.stringify(csr.validity, null, 2), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Signature:', | ||||
|       value: csr.signature, | ||||
|     }, | ||||
|     { | ||||
|       label: 'Signature Oid:', | ||||
|       value: csr.signatureOid?.toString(), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Signature parameters:', | ||||
|       value: JSON.stringify(csr.signatureParameters, null, 2), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Signing info:', | ||||
|       value: JSON.stringify(csr.siginfo, null, 2), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Serial:', | ||||
|       value: csr.serialNumber?.toString(), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Extensions:', | ||||
|       value: JSON.stringify(csr.extensions, null, 2), | ||||
|       multiline: true, | ||||
|     }, | ||||
|     { | ||||
|       label: 'Public Key:', | ||||
|       value: onErrorReturnErrorMessage(() => forge.pki.publicKeyToPem(csr.publicKey)), | ||||
|       multiline: true, | ||||
|     }, | ||||
|     { | ||||
|       label: 'Public Key Fingerprint:', | ||||
|       value: onErrorReturnErrorMessage(() => forge.pki.getPublicKeyFingerprint(csr.publicKey)?.toHex()), | ||||
|       multiline: true, | ||||
|     }, | ||||
|   ] as LabelValue[]; | ||||
| } | ||||
| 
 | ||||
| export function getFingerprintLabelValues(fingerprint: Fingerprint) { | ||||
|   return [ | ||||
|     { | ||||
|       label: 'Type:', | ||||
|       value: 'Fingerprint', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Fingerprint (hex):', | ||||
|       value: fingerprint.toString('hex'), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Fingerprint (base64):', | ||||
|       value: fingerprint.toString('base64'), | ||||
|     }, | ||||
|   ] as LabelValue[]; | ||||
| } | ||||
| 
 | ||||
| export function getSignatureLabelValues(signature: Signature) { | ||||
|   return [ | ||||
|     { | ||||
|       label: 'Type:', | ||||
|       value: 'Signature', | ||||
|     }, | ||||
|     { | ||||
|       label: 'Fingerprint (asn1):', | ||||
|       value: signature.toString('asn1'), | ||||
|     }, | ||||
|     { | ||||
|       label: 'Fingerprint (ssh):', | ||||
|       value: signature.toString('ssh'), | ||||
|     }, | ||||
|   ] as LabelValue[]; | ||||
| } | ||||
| @ -0,0 +1,201 @@ | ||||
| import { describe, expect, it } from 'vitest'; | ||||
| import { getKeyOrCertificateInfosAsync } from './certificate-key-parser.service'; | ||||
| 
 | ||||
| const encryptedPrivateKey = /* NOSONAR */ `-----BEGIN ENCRYPTED PRIVATE KEY-----
 | ||||
| MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQILjmiBkdY16UCAggA | ||||
| MB0GCWCGSAFlAwQBAgQQ+sYf2MO9hoZ4F5+LdE2vRgSCBNC6CLgqMJ6fKS3YnMMJ | ||||
| yc3/iuqRniP/11OllTmOr94/2dl6Xk8TndBqhAacYizxgNCHiPP+NEmwtPqbbE+a | ||||
| boNqEh0m8NUegxc3qGzon8cJgobgvpw7eml4K1OjgxCw58Y1VQixSKpdHEC1E1o6 | ||||
| RBBwK5bIld97GEi4VPuqYoYvffcD5cDsj9HxqvEWGTXDtu/nKEA0cVe7wI8t1CtR | ||||
| /kaFoCyYOFu9RE0YprcWT1GpYTHR3TE7+lXYR8vPGdMCMgww1mLCXDAz1G4Y5+1K | ||||
| WAmiVn3uQqgR9rU/upaM01oOz5LJWtgi5gDV8zX0r41i8pYYQNvGiSvvw1pQJB5Q | ||||
| sFyuVNU6hOCQ+zLssfmxnhRpgM3hn07gV+LFAg+ly6WQsl9W6m8WpJ7SgLeByb7g | ||||
| teT+ml7wTuFZIiPbqD3Pq0grRZir3n3NuphUk9YwR2jN4hHXEDiQ9f4D4SY41RT3 | ||||
| lW7roK+oM1K3N4cDin+WyGiFFLyWrwrlXWmHN5A3pOf+0rQUooZdUTGSU0N9v9Ho | ||||
| 17x/+aDAeCMEl7y0GfEoglNxCjoVj70E9oJL21amziZAUOXobhuzeb0dWJmAtXoj | ||||
| wETYW6QH8m80eEyvKfkLsQ2Sd360ILhRJtyN1HFJAQbsC3C0VYiqA3kjN4S1Zfeg | ||||
| 08/odqdi0a7GSTm/h+iT3rimXXS2TLfSYIzI14LZDCeCz33tX13WQrhGPbYEJBHX | ||||
| PKc1ws0HHBwdpM8d+liPHm+Czt2/sbcGCNBWSPWWZpL+uzeh9HQYEUoefk88JCPD | ||||
| xQlANh8BCzq0L1pYNZdOYVNb0fT1XluuP8xtIePsNHIsKRURDlCjaEAY41DwXmTp | ||||
| DFRd41BLFZztX5jtMGw4lb3RplcaaRhxCEF51hRJQdb5HMpn4cr2Hqy5UP+ke2vV | ||||
| 0DVRi0jp7Mkp/+qdEEotWT1AxSeYoiW7j/GwlC8tqAC9NoMmcHAuOGF5fHshxz/L | ||||
| lnWSHiPjfLezpfryBwb5D4+3/TFEzc8gPsco/Ip7qU1+wMObTLs9Nq1ROW/aClYU | ||||
| A/a5DyCQUHaHyYRse/BLTXxr2gsMCm7qaTdCy+pZcL1f+YEISHtITuA38eGfQzTX | ||||
| cX/k75t7+mKW4nKBBT/SZbBT27gEeZpAn8ORaMixedBQZmoFHLKNlrf+F+fBFfhp | ||||
| J4NFeBFnEpa3YrPVgLTJY6yN0gummIC8GA7EpggdAcNTbp5EU+IHlHhExhzr+W+f | ||||
| YCOdD4Zt6LMZjAlpId2APn9NMscpwT59K/61n1CjElpWPwfTW2hyto7/1q0fIgwK | ||||
| z2E615qLFJa+EFR8hTFz0wjNUOCrDgS7K7STQbGaFfjmAe2LUFZhTm86u6K0fnUY | ||||
| sNJeDSnvDYEQD1MUiezD06MmzdEHqJHNKztoahqPsQIktH84RGdc1oTPMS4PLwLM | ||||
| JJmEHqLF7I8T6L+BvMp2LhZTrx3g1qU4wZRC5Rys7J5WR5E+v8XttEcViEO4Lrdr | ||||
| wNRoroHuXLw4nOzM58DS5cHGliw4BeErQ6XC0aan2EM789Us3Hrx0zerfIOyUdBe | ||||
| N39sh8X4jo7YHMBH3yqVsAIU3e8c2Z2rayP7+AyUncAfff9EH3BNpIkQIG3xsqh1 | ||||
| oimmuNBEFKy1F1rSP3NQvwcZVw== | ||||
| -----END ENCRYPTED PRIVATE KEY----- | ||||
|     `;
 | ||||
| const openSSHPrivateKey = /* NOSONAR */ `-----BEGIN OPENSSH PRIVATE KEY-----
 | ||||
| b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn | ||||
| NhAAAAAwEAAQAAAQEA4r66AJdnJBwsKDyTr4QizQYMVhaFtcBcMcVuJHbKW/DtG985oA2V | ||||
| hJRfcBz8MKNS9iTLRkgq4yoTVCIi5FDVU4EnQbLMoLfN2og6PpgSSL59bPUvYoenp6RS1i | ||||
| R606eVakH/J6IIiadHMWBrLjCiChf5U/bvuSkUQWi0YLH9hI6Nw+S9MdwzBofshZZdww9Y | ||||
| 4udrWEVdfGrxWv5gjlaquxYZAnfaYCI0Pgh9v1nEALFufOVi1onUZaxduyvsLoQnXiwP2c | ||||
| fWXsBYmjfViTTADTvHTLCF9IH+6heGk2WJkosgiajmMlc+1U7Xs+r5ZJ0ikt0ioydPN8Hi | ||||
| LnVih6lENwAAA7hrsy+Ha7MvhwAAAAdzc2gtcnNhAAABAQDivroAl2ckHCwoPJOvhCLNBg | ||||
| xWFoW1wFwxxW4kdspb8O0b3zmgDZWElF9wHPwwo1L2JMtGSCrjKhNUIiLkUNVTgSdBssyg | ||||
| t83aiDo+mBJIvn1s9S9ih6enpFLWJHrTp5VqQf8nogiJp0cxYGsuMKIKF/lT9u+5KRRBaL | ||||
| Rgsf2Ejo3D5L0x3DMGh+yFll3DD1ji52tYRV18avFa/mCOVqq7FhkCd9pgIjQ+CH2/WcQA | ||||
| sW585WLWidRlrF27K+wuhCdeLA/Zx9ZewFiaN9WJNMANO8dMsIX0gf7qF4aTZYmSiyCJqO | ||||
| YyVz7VTtez6vlknSKS3SKjJ083weIudWKHqUQ3AAAAAwEAAQAAAQBmKTj0+0JlaqwalPCV | ||||
| rBth9M+qGgu0kC753dJ6a2tRcYPjgvgbvQMY8SDvCqA16eB/NqS/zdRE9bgvuBGwfRsgvJ | ||||
| hLaZv47de6FpbnjOzwCaPJa88lvak0Rz1rbpRIuMEBVyr3WHIwU0YoYSDpdtALbDHSOvhX | ||||
| nMKblelvh8KJ7jelix2R3llvcYexKdS66zzP7nPj5x8d1FDo2cxqWsy2aQxMlbZGTd3ujQ | ||||
| ABzZGvI3L0tJRf4sPph/eLS28/teAExp5Uo9DuehqgU33iAYOaO2vZGqQJxBbaVtiarVK1 | ||||
| kRQLBrhieMIUJ9XHSwDn74VHWtBNfocTSPe6vbVMjLpBAAAAgGBTluv8WHqG1JTauYNjBI | ||||
| EhSKL96MrIZR+fytEg3gcxitPnpQiPTP6XHXpQ7fxVk25bYvCj4QNi00jW6kBR46Zh90NI | ||||
| nKgYvxdYoA5A7L6JvvByy00SbLssiM7kf3ByT/4EA8S911Q4cks8lKrwEUw+UzqTBR6QdG | ||||
| JyZQQcUJa+AAAAgQDyIYjECyG91/X+zFYcecW+wWyLBzyEvOxFlRd4tZnvWknQTdtFqTlN | ||||
| orTT+un1ygKe0DkfwXSbbjE69+xxlMtPQ2X6wd2mUruvtyBv1R8Kfj+doY5lFUfCEKj88u | ||||
| ck1+Ol1K+KDnvlYZVnb5eCvMxmEMqyD+eTQ2EcNAJtjNmuDQAAAIEA77uU45tseIe9E6OZ | ||||
| Hum2bUxQmqkpjrNCECiTJR99NUx+22sBZwrMAt3QzBwgSogQhLKAw+keEUG6zAl7UA6Lsc | ||||
| vJdDllY2vYMRW9LZ1XNCxvl0i6QUsT8l9hwA9GuMQN1m6NRU+cnEU87KIXVBb+DRyZwo21 | ||||
| 4WRkAc1Ru/KtrlMAAAAAAQID | ||||
| -----END OPENSSH PRIVATE KEY-----       | ||||
|     `;
 | ||||
| 
 | ||||
| const formatsData = [ | ||||
|   { | ||||
|     input: ` | ||||
| -----BEGIN PGP PUBLIC KEY BLOCK----- | ||||
| 
 | ||||
| xjMEZkHgaRYJKwYBBAHaRw8BAQdAdCmEzdpkjMzOoNkzgDFk/CHd+6uYAWkZ | ||||
| BPbjEzTJWtfNAMKMBBAWCgA+BYJmQeBpBAsJBwgJkEDKj7jnGr9wAxUICgQW | ||||
| AAIBAhkBApsDAh4BFiEExfkkog7+aHz7TqepQMqPuOcav3AAAJaaAQCayvFQ | ||||
| jxFbC7oOzX+8wOV8gmXVXXqI5dtLQYY3SeyqmwD/ftVwwe6Prl0vVFyLB/5y | ||||
| lIpAti8AK1Lv8hIezzOx4QDOOARmQeBpEgorBgEEAZdVAQUBAQdA2jU3Rmt7 | ||||
| nMFvqyjgKdVjK5o2CQI2vJiSzn8cfV1piEgDAQgHwngEGBYKACoFgmZB4GkJ | ||||
| kEDKj7jnGr9wApsMFiEExfkkog7+aHz7TqepQMqPuOcav3AAABI0AQCMW4Hg | ||||
| FuIaZk9LVQsUmNknj4a70fzwDYWUYvq0C1iy/QD+KXvLKfcmky5OXJA7RsRV | ||||
| SN2a4SE4c8FH22uyirzyUww= | ||||
| =w51K | ||||
| -----END PGP PUBLIC KEY BLOCK-----       | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'PGP Public Key', | ||||
|   }, | ||||
|   { | ||||
|     // NOSONAR
 | ||||
|     input: ` | ||||
| -----BEGIN PGP PRIVATE KEY BLOCK----- | ||||
| 
 | ||||
| xVgEZkHgaRYJKwYBBAHaRw8BAQdAdCmEzdpkjMzOoNkzgDFk/CHd+6uYAWkZ | ||||
| BPbjEzTJWtcAAQDXcDgEziqd9ZO/OpoyblRRxAOgPq2y8zTitwTz+ixX7RCe | ||||
| zQDCjAQQFgoAPgWCZkHgaQQLCQcICZBAyo+45xq/cAMVCAoEFgACAQIZAQKb | ||||
| AwIeARYhBMX5JKIO/mh8+06nqUDKj7jnGr9wAACWmgEAmsrxUI8RWwu6Ds1/ | ||||
| vMDlfIJl1V16iOXbS0GGN0nsqpsA/37VcMHuj65dL1Rciwf+cpSKQLYvACtS | ||||
| 7/ISHs8zseEAx10EZkHgaRIKKwYBBAGXVQEFAQEHQNo1N0Zre5zBb6so4CnV | ||||
| YyuaNgkCNryYks5/HH1daYhIAwEIBwAA/2PxYHVWBmkLD9eiFDLJ0EtspWQ+ | ||||
| JKui86xylduxQWngEIrCeAQYFgoAKgWCZkHgaQmQQMqPuOcav3ACmwwWIQTF | ||||
| +SSiDv5ofPtOp6lAyo+45xq/cAAAEjQBAIxbgeAW4hpmT0tVCxSY2SePhrvR | ||||
| /PANhZRi+rQLWLL9AP4pe8sp9yaTLk5ckDtGxFVI3ZrhIThzwUfba7KKvPJT | ||||
| DA== | ||||
| =hSgY | ||||
| -----END PGP PRIVATE KEY BLOCK-----       | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'PGP Private Key', | ||||
|   }, | ||||
|   { | ||||
|     input: ` | ||||
| -----BEGIN CERTIFICATE REQUEST----- | ||||
| MIIClTCCAX0CAQAwUDERMA8GA1UEAxMIdGVzdC5jb20xDzANBgNVBAYTBkZyYW5j | ||||
| ZTELMAkGA1UECBMCRlIxDjAMBgNVBAcTBVBhcmlzMQ0wCwYDVQQKEwRUZXN0MIIB | ||||
| IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIUCiMFffkHGuAhwTaW84uh7 | ||||
| /03KcfQAZB/bZKqLaxtcBGryTB1gHFSsl3uFlW+tIcjsboWnQ2JB0J1Z5Fp4a6IA | ||||
| /62S6GTo6dAd9f73TR+P2vQghZOtiCoc7CN2KlosIx/EWMcMjq+CBzLRjjOOR8tX | ||||
| Yn4ZAhPInO1ZGPMEpfEEfn44aJFRGaMy4KEU+RpTzFKFW6bialvKC3yGPegQ4wcz | ||||
| AqvyUc9WUwG53HYLSJHldg8tZnpiJBNUh8mXiIiw51MFJ4Q9RVnz9vuoHgC6FmUv | ||||
| qlg/R4gjGGfjDhAIUtz+Y98Dl+xfLmD+EzY7KQ1ur412BvQ8rXankNGLA2ea+wID | ||||
| AQABoAAwDQYJKoZIhvcNAQEFBQADggEBABdtkhFSwgaXZWTcKrz6oarvuaQkrjvs | ||||
| Nk9lUs1h/dfhJpnE3iZA0CuNp5PVQRdC2g+/37r21/udjNFdrX1Rm6/ldG0b2xDu | ||||
| nQYZcLpIVB0fZ2TB+FHthmGw175I2niWIfNJQhIqnWJXi8unkGTMP2cD6j3axtMi | ||||
| K8MUVPhWmL11ojEXItG35AU79G6GhFxel9wIByqsXreCUyOcrpYCHy2Fv85ivdE1 | ||||
| JyEQ2tE/f+cKwNg4yJNFoCoHSSFRn61F12J4m2nwpQ77VfD66oVkWtk/gYMrwx0d | ||||
| 4FlJNs+NtZDlcM7fJLNo7YsMdne7hl4aL6WG96kdWdxYEt/2dl3WXbY= | ||||
| -----END CERTIFICATE REQUEST----- | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'Certificate Signing Request', | ||||
|   }, | ||||
|   { | ||||
|     input: ` | ||||
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDivroAl2ckHCwoPJOvhCLNBgxWFoW1wFwxxW4kdspb8O0b3zmgDZWElF9wHPwwo1L2JMtGSCrjKhNUIiLkUNVTgSdBssygt83aiDo+mBJIvn1s9S9ih6enpFLWJHrTp5VqQf8nogiJp0cxYGsuMKIKF/lT9u+5KRRBaLRgsf2Ejo3D5L0x3DMGh+yFll3DD1ji52tYRV18avFa/mCOVqq7FhkCd9pgIjQ+CH2/WcQAsW585WLWidRlrF27K+wuhCdeLA/Zx9ZewFiaN9WJNMANO8dMsIX0gf7qF4aTZYmSiyCJqOYyVz7VTtez6vlknSKS3SKjJ083weIudWKHqUQ3 | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'Public Key', | ||||
|     title: 'ssh-rsa Public Key', | ||||
|   }, | ||||
|   { | ||||
|     input: openSSHPrivateKey, | ||||
|     pass: '', | ||||
|     type: 'Private Key', | ||||
|     title: 'Unencrypted Private Key', | ||||
|   }, | ||||
|   { | ||||
|     input: ` | ||||
| SHA256:qflg623OemnYEHDwUafq+XuMoB0UdJ+Ks44kHcWxDyM | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'Fingerprint', | ||||
|   }, | ||||
|   { | ||||
|     input: ` | ||||
| -----BEGIN CERTIFICATE----- | ||||
| MIIDQDCCAiigAwIBAgIJK59gK0GUbZO3MA0GCSqGSIb3DQEBBQUAMFAxETAPBgNV | ||||
| BAMTCHRlc3QuY29tMQ8wDQYDVQQGEwZGcmFuY2UxCzAJBgNVBAgTAkZSMQ4wDAYD | ||||
| VQQHEwVQYXJpczENMAsGA1UEChMEVGVzdDAeFw0yNDA1MTMwOTQ4MTVaFw0yNTA1 | ||||
| MTMwOTQ4MTVaMFAxETAPBgNVBAMTCHRlc3QuY29tMQ8wDQYDVQQGEwZGcmFuY2Ux | ||||
| CzAJBgNVBAgTAkZSMQ4wDAYDVQQHEwVQYXJpczENMAsGA1UEChMEVGVzdDCCASIw | ||||
| DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMKrE3C9tUtmvHZkIwEBf1h5N7KC | ||||
| FoXowfNZxKK7SHWcnQjBdv0ziqsU+GmcUqUD1GymMcBweqw4TQVg0a/UwdYIUTuQ | ||||
| GXGx4ULCXKHv/NfmVSWcMsOZHAR4m/yEzTB/ZjKMSrqnIWyOdusDMRn4VRoAtrKO | ||||
| /FM+SDJ6wvnJ/jNoZJXktq9avYduEi+heNekIF6NYM9clzm9Ff3Evf89KuigBcsu | ||||
| rgL+S8PjotCwxMgzOWV4/paeeQluqYeU94prWIASS/D3elH7qFTAUnafBICFN2zs | ||||
| XWY6ZFCR8QrDI5F/8KELq/3BaLQBxpIi9SmADLWqnPOu+6H5rzr2YV8LaxMCAwEA | ||||
| AaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAvQwDQYJKoZIhvcNAQEFBQAD | ||||
| ggEBAKhrUNnWe0VmgefvfwsAqrbk0Z6PwaibIl/l5I9oh1qM01J9BFHpvomhcLxu | ||||
| cmIpD6nAqtkNyvsXtFAnZG3WNaf45yyd153wSa0QnrNo2GRH9quktm4DaRIIP7qq | ||||
| EdtApYCeT16LvAGYUH3ubCdom8w6DkukLg8qMrXMywSZlx85jlJfifPvMKsJmm/a | ||||
| QAq1H3cYaaj0DocF1rCP+hLzvsuM7UwS2JOK8Mw49kYPBTbCVmRDOE1rhlDIO8Kw | ||||
| V7CCFr4NXsyRlM0TpKdspOmxJiyxmk6DoVgp9PeqfoyDAC9TJU0VJ6A2x+AfjK4O | ||||
| Wg6xDXMx6dk6Rhh8yqGrmx05QM8= | ||||
| -----END CERTIFICATE----- | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'Certificate', | ||||
|   }, | ||||
|   { | ||||
|     input: ` | ||||
| c6:b9:73:b8:68:49:33:ad:27:51:bb:6c:16:e7:9c:da:dd:e3:92:15 | ||||
|     `,
 | ||||
|     pass: '', | ||||
|     type: 'Fingerprint', | ||||
|     title: 'HEX Fingerprint', | ||||
|   }, | ||||
|   { | ||||
|     input: encryptedPrivateKey, | ||||
|     pass: 'test', | ||||
|     type: 'Private Key', | ||||
|     title: 'Encrypted Private Key', | ||||
|   }, | ||||
| ]; | ||||
| 
 | ||||
| describe('certificate-key-parser', () => { | ||||
|   for (const format of formatsData) { | ||||
|     const { input, pass, type, title } = format; | ||||
|     it(`Parse '${title ?? type}' format with right type (${type})`, async () => { | ||||
|       const { values } = await getKeyOrCertificateInfosAsync(input, pass); | ||||
|       const result_type = values.find(v => v.label === 'Type:')?.value; | ||||
| 
 | ||||
|       expect(result_type).toBe(type); | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
| @ -0,0 +1,129 @@ | ||||
| import type { 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 * as openpgp from 'openpgp'; | ||||
| import * as forge from 'node-forge'; | ||||
| import { type LabelValue, getCSRLabelValues, getCertificateLabelValues, getFingerprintLabelValues, getPGPPrivateKeyLabelValuesAsync, getPGPPublicKeyLabelValuesAsync, getPrivateKeyLabelValues, getPublicKeyLabelValues, getSignatureLabelValues } from './certificate-key-parser.infos'; | ||||
| 
 | ||||
| export async function getKeyOrCertificateInfosAsync(keyOrCertificateValue: string | Buffer, passphrase: string) { | ||||
|   try { | ||||
|     const canParse = (value: string | Buffer, parseFunction: (value: string | Buffer) => any) => { | ||||
|       try { | ||||
|         return parseFunction(value); | ||||
|       } | ||||
|       catch { | ||||
|         return null; | ||||
|       } | ||||
|     }; | ||||
|     const canParseAsync = async (value: string | Buffer, parseFunction: (value: string | Buffer) => Promise<any>) => { | ||||
|       try { | ||||
|         return await parseFunction(value); | ||||
|       } | ||||
|       catch { | ||||
|         return null; | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     const inputKeyOrCertificateValue = (typeof keyOrCertificateValue === 'string' ? keyOrCertificateValue?.trim() : keyOrCertificateValue); | ||||
| 
 | ||||
|     const privateKey = canParse(inputKeyOrCertificateValue, | ||||
|       value => parsePrivateKey(value, 'auto', { passphrase })) as PrivateKey; | ||||
|     if (privateKey) { | ||||
|       return { | ||||
|         values: getPrivateKeyLabelValues(privateKey), | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     const publicKey = canParse(inputKeyOrCertificateValue, parseKey) as Key; | ||||
|     if (publicKey) { | ||||
|       return { values: getPublicKeyLabelValues(publicKey) }; | ||||
|     } | ||||
| 
 | ||||
|     const pgpPrivateKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readPrivateKey({ armoredKey: value.toString() })) as openpgp.Key; | ||||
|     if (pgpPrivateKey) { | ||||
|       return { values: await getPGPPrivateKeyLabelValuesAsync(pgpPrivateKey) }; | ||||
|     } | ||||
| 
 | ||||
|     const pgpPublicKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readKey({ armoredKey: value.toString() })) as openpgp.Key; | ||||
|     if (pgpPublicKey) { | ||||
|       return { values: await getPGPPublicKeyLabelValuesAsync(pgpPublicKey) }; | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|       let certificateX509DER = ''; | ||||
|       try { | ||||
|         certificateX509DER = Base64.fromUint8Array(cert.toBuffer('x509')); | ||||
|       } | ||||
|       catch {} | ||||
| 
 | ||||
|       return { values: getCertificateLabelValues(cert), certificateX509DER }; | ||||
|     } | ||||
| 
 | ||||
|     const csr = canParse(inputKeyOrCertificateValue, (value) => { | ||||
|       return forge.pki.certificationRequestFromPem(value.toString(), false, false); | ||||
|     }) as forge.pki.Certificate; | ||||
|     if (csr) { | ||||
|       return { values: getCSRLabelValues(csr) }; | ||||
|     } | ||||
| 
 | ||||
|     const fingerprint = canParse(inputKeyOrCertificateValue, value => parseFingerprint(value.toString())) as Fingerprint; | ||||
|     if (fingerprint) { | ||||
|       return { values: getFingerprintLabelValues(fingerprint) }; | ||||
|     } | ||||
| 
 | ||||
|     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 { values: getSignatureLabelValues(signature) }; | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|       values: [ | ||||
|         { | ||||
|           label: 'Type:', | ||||
|           value: 'Unknown format or invalid passphrase', | ||||
|         }], | ||||
|     }; | ||||
|   } | ||||
|   catch (e: any) { | ||||
|     return { | ||||
|       values: [ | ||||
|         { | ||||
|           label: 'Error:', | ||||
|           value: e.toString(), | ||||
|         }] as LabelValue[], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -1,29 +1,9 @@ | ||||
| <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 * as openpgp from 'openpgp'; | ||||
| import * as forge from 'node-forge'; | ||||
| 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(''); | ||||
| } | ||||
| import { getKeyOrCertificateInfosAsync } from './certificate-key-parser.service'; | ||||
| import { type LabelValue } from './certificate-key-parser.infos'; | ||||
| import { useDownloadFileFromBase64 } from '@/composable/downloadBase64'; | ||||
| 
 | ||||
| const inputKeyOrCertificate = ref(''); | ||||
| const passphrase = ref(''); | ||||
| @ -56,394 +36,15 @@ function downloadX509DERFile() { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| interface LabelValue { | ||||
|   label: string | ||||
|   value: string | ||||
|   multiline?: boolean | ||||
| } | ||||
| const parsedSections = computedAsync<LabelValue[]>(async () => { | ||||
|   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 canParseAsync = async (value: string | Buffer, parseFunction: (value: string | Buffer) => Promise<any>) => { | ||||
|       try { | ||||
|         return await parseFunction(value); | ||||
|       } | ||||
|       catch { | ||||
|         return null; | ||||
|       } | ||||
|     }; | ||||
|     const inputKeyOrCertificateValue | ||||
|   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 csr = canParse(inputKeyOrCertificateValue, (value) => { | ||||
|       return forge.pki.certificationRequestFromPem(value.toString(), true, false); | ||||
|     }) as forge.pki.Certificate; | ||||
|     if (csr) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'Certificate Signing Request', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Subject: ', | ||||
|           value: csr.subject.attributes.map(a => JSON.stringify(a, null, 2)).join('\n'), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Issuer: ', | ||||
|           value: csr.issuer?.toString(), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Validity: ', | ||||
|           value: JSON.stringify(csr.validity, null, 2), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Signature: ', | ||||
|           value: csr.signature, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Signature Oid: ', | ||||
|           value: csr.signatureOid?.toString(), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Signature parameters: ', | ||||
|           value: JSON.stringify(csr.signatureParameters, null, 2), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Signing info: ', | ||||
|           value: JSON.stringify(csr.siginfo, null, 2), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Serial: ', | ||||
|           value: csr.serialNumber?.toString(), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Extensions: ', | ||||
|           value: JSON.stringify(csr.extensions, null, 2), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Public Key: ', | ||||
|           value: onErrorReturnErrorMessage(() => forge.pki.publicKeyToPem(csr.publicKey)), | ||||
|           multiline: true, | ||||
|         }, | ||||
|         { | ||||
|           label: 'Public Key Fingerprint:', | ||||
|           value: onErrorReturnErrorMessage(() => forge.pki.getPublicKeyFingerprint(csr.publicKey)?.toHex()), | ||||
|           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 pgpPrivateKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readPrivateKey({ armoredKey: value.toString() })) as openpgp.Key; | ||||
|     if (pgpPrivateKey) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'PGP Private Key', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Creation Time: ', | ||||
|           value: pgpPrivateKey.getCreationTime().toString(), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Expiration Time: ', | ||||
|           value: (await pgpPrivateKey.getExpirationTime())?.toString() || '', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Algorithm Info: ', | ||||
|           value: JSON.stringify(pgpPrivateKey.getAlgorithmInfo()), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint: ', | ||||
|           value: pgpPrivateKey.getFingerprint(), | ||||
|         }, | ||||
|         { | ||||
|           label: 'User ID(s): ', | ||||
|           value: pgpPrivateKey.getUserIDs().join(', '), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Key ID(s): ', | ||||
|           value: pgpPrivateKey.getKeyIDs().map(k => k.toHex()).join(' ; '), | ||||
|         }, | ||||
|       ] as LabelValue[]; | ||||
|     } | ||||
| 
 | ||||
|     const pgpPublicKey = await canParseAsync(inputKeyOrCertificateValue, value => openpgp.readKey({ armoredKey: value.toString() })) as openpgp.Key; | ||||
|     if (pgpPublicKey) { | ||||
|       return [ | ||||
|         { | ||||
|           label: 'Type: ', | ||||
|           value: 'PGP Public Key', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Creation Time: ', | ||||
|           value: pgpPublicKey.getCreationTime().toString(), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Expiration Time: ', | ||||
|           value: (await pgpPublicKey.getExpirationTime())?.toString() || '', | ||||
|         }, | ||||
|         { | ||||
|           label: 'Algorithm Info: ', | ||||
|           value: JSON.stringify(pgpPublicKey.getAlgorithmInfo()), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Fingerprint: ', | ||||
|           value: pgpPublicKey.getFingerprint(), | ||||
|         }, | ||||
|         { | ||||
|           label: 'User ID(s): ', | ||||
|           value: pgpPublicKey.getUserIDs().join(', '), | ||||
|         }, | ||||
|         { | ||||
|           label: 'Key ID(s): ', | ||||
|           value: pgpPublicKey.getKeyIDs().map(k => k.toHex()).join(' ; '), | ||||
|         }, | ||||
|       ] 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[]; | ||||
|   } | ||||
|   const { values, certificateX509DER: certPEM } = await getKeyOrCertificateInfosAsync(inputKeyOrCertificateValue, passphrase.value); | ||||
|   certificateX509DER.value = certPEM || ''; | ||||
|   return values; | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| @ -465,6 +66,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => { | ||||
|         placeholder="Your Public Key / Private Key / Signature / Fingerprint / Certificate..." | ||||
|         multiline | ||||
|         rows="8" | ||||
|         data-test-id="input" | ||||
|       /> | ||||
|     </c-card> | ||||
| 
 | ||||
| @ -473,6 +75,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => { | ||||
|       label="Passphrase (for encrypted keys):" | ||||
|       placeholder="Passphrase (for encrypted keys)..." | ||||
|       type="password" | ||||
|       data-test-id="pass" | ||||
|     /> | ||||
| 
 | ||||
|     <n-divider /> | ||||
| @ -481,6 +84,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => { | ||||
|       v-for="{ label, value, multiline } of parsedSections" | ||||
|       :key="label" | ||||
|       :label="label" | ||||
|       :data-test-id="label" | ||||
|       label-position="left" | ||||
|       label-width="100px" | ||||
|       label-align="right" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user