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-----
 | ||||||
|  | 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 | ||||||
|  | oimmuNBEFKy1F1rSP3NQvwcZVw== | ||||||
|  | -----END ENCRYPTED PRIVATE KEY----- | ||||||
|  |     `;
 | ||||||
|  | const openSSHPrivateKey = /* NOSONAR */ `-----BEGIN OPENSSH PRIVATE KEY-----
 | ||||||
|  | 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 | ||||||
|  | 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"> | <script setup lang="ts"> | ||||||
| import { Buffer } from 'node:buffer'; | 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 | import { getKeyOrCertificateInfosAsync } from './certificate-key-parser.service'; | ||||||
|   return [...new Uint8Array(buffer)] | import { type LabelValue } from './certificate-key-parser.infos'; | ||||||
|     .map(x => x.toString(16).padStart(2, '0')) | import { useDownloadFileFromBase64 } from '@/composable/downloadBase64'; | ||||||
|     .join(''); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| const inputKeyOrCertificate = ref(''); | const inputKeyOrCertificate = ref(''); | ||||||
| const passphrase = ref(''); | const passphrase = ref(''); | ||||||
| @ -56,394 +36,15 @@ function downloadX509DERFile() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface LabelValue { |  | ||||||
|   label: string |  | ||||||
|   value: string |  | ||||||
|   multiline?: boolean |  | ||||||
| } |  | ||||||
| const parsedSections = computedAsync<LabelValue[]>(async () => { | const parsedSections = computedAsync<LabelValue[]>(async () => { | ||||||
|   try { |   const inputKeyOrCertificateValue | ||||||
|     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 |  | ||||||
|       = inputKeyOrCertificate.value !== '' |       = inputKeyOrCertificate.value !== '' | ||||||
|         ? inputKeyOrCertificate.value |         ? inputKeyOrCertificate.value | ||||||
|         : fileInput.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, |   const { values, certificateX509DER: certPEM } = await getKeyOrCertificateInfosAsync(inputKeyOrCertificateValue, passphrase.value); | ||||||
|       value => parsePrivateKey(value, 'auto', { passphrase: passphrase.value })) as PrivateKey; |   certificateX509DER.value = certPEM || ''; | ||||||
|     if (privateKey) { |   return values; | ||||||
|       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[]; |  | ||||||
|   } |  | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| @ -465,6 +66,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => { | |||||||
|         placeholder="Your Public Key / Private Key / Signature / Fingerprint / Certificate..." |         placeholder="Your Public Key / Private Key / Signature / Fingerprint / Certificate..." | ||||||
|         multiline |         multiline | ||||||
|         rows="8" |         rows="8" | ||||||
|  |         data-test-id="input" | ||||||
|       /> |       /> | ||||||
|     </c-card> |     </c-card> | ||||||
| 
 | 
 | ||||||
| @ -473,6 +75,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => { | |||||||
|       label="Passphrase (for encrypted keys):" |       label="Passphrase (for encrypted keys):" | ||||||
|       placeholder="Passphrase (for encrypted keys)..." |       placeholder="Passphrase (for encrypted keys)..." | ||||||
|       type="password" |       type="password" | ||||||
|  |       data-test-id="pass" | ||||||
|     /> |     /> | ||||||
| 
 | 
 | ||||||
|     <n-divider /> |     <n-divider /> | ||||||
| @ -481,6 +84,7 @@ const parsedSections = computedAsync<LabelValue[]>(async () => { | |||||||
|       v-for="{ label, value, multiline } of parsedSections" |       v-for="{ label, value, multiline } of parsedSections" | ||||||
|       :key="label" |       :key="label" | ||||||
|       :label="label" |       :label="label" | ||||||
|  |       :data-test-id="label" | ||||||
|       label-position="left" |       label-position="left" | ||||||
|       label-width="100px" |       label-width="100px" | ||||||
|       label-align="right" |       label-align="right" | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user