Merge d0582b3142 into b47d132839
This commit is contained in:
commit
f6bfd2f850
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -33,6 +33,7 @@ declare module '@vue/runtime-core' {
|
||||
CCollapse: typeof import('./src/ui/c-collapse/c-collapse.vue')['default']
|
||||
'CCollapse.demo': typeof import('./src/ui/c-collapse/c-collapse.demo.vue')['default']
|
||||
CDiffEditor: typeof import('./src/ui/c-diff-editor/c-diff-editor.vue')['default']
|
||||
CertificateKeyParser: typeof import('./src/tools/certificate-key-parser/certificate-key-parser.vue')['default']
|
||||
CFileUpload: typeof import('./src/ui/c-file-upload/c-file-upload.vue')['default']
|
||||
'CFileUpload.demo': typeof import('./src/ui/c-file-upload/c-file-upload.demo.vue')['default']
|
||||
ChmodCalculator: typeof import('./src/tools/chmod-calculator/chmod-calculator.vue')['default']
|
||||
|
||||
@ -69,7 +69,7 @@
|
||||
"highlight.js": "^11.7.0",
|
||||
"iarna-toml-esm": "^3.0.5",
|
||||
"ibantools": "^4.3.3",
|
||||
"js-base64": "^3.7.6",
|
||||
"js-base64": "^3.7.7",
|
||||
"json5": "^2.2.3",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"libphonenumber-js": "^1.10.28",
|
||||
@ -82,6 +82,7 @@
|
||||
"naive-ui": "^2.35.0",
|
||||
"netmask": "^2.0.2",
|
||||
"node-forge": "^1.3.1",
|
||||
"openpgp": "^5.11.1",
|
||||
"oui-data": "^1.0.10",
|
||||
"pdf-signature-reader": "^1.4.2",
|
||||
"pinia": "^2.0.34",
|
||||
@ -89,6 +90,7 @@
|
||||
"qrcode": "^1.5.1",
|
||||
"randexp": "^0.5.3",
|
||||
"sql-formatter": "^13.0.0",
|
||||
"sshpk": "^1.18.0",
|
||||
"ua-parser-js": "^1.0.35",
|
||||
"ulid": "^2.3.0",
|
||||
"unicode-emoji-json": "^0.4.0",
|
||||
@ -121,6 +123,7 @@
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/node-forge": "^1.3.2",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/sshpk": "^1.17.4",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@unocss/eslint-config": "^0.57.0",
|
||||
@ -142,6 +145,7 @@
|
||||
"unplugin-icons": "^0.17.0",
|
||||
"unplugin-vue-components": "^0.25.0",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-node-polyfills": "^0.21.0",
|
||||
"vite-plugin-pwa": "^0.16.0",
|
||||
"vite-plugin-vue-markdown": "^0.23.5",
|
||||
"vite-svg-loader": "^4.0.0",
|
||||
|
||||
732
pnpm-lock.yaml
generated
732
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -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()">
|
||||
|
||||
@ -17,6 +17,7 @@ const props = withDefaults(
|
||||
language?: string
|
||||
copyPlacement?: 'top-right' | 'bottom-right' | 'outside' | 'none'
|
||||
copyMessage?: string
|
||||
wordWrap?: boolean
|
||||
}>(),
|
||||
{
|
||||
followHeightOf: null,
|
||||
@ -49,7 +50,7 @@ const tooltipText = computed(() => isJustCopied.value ? 'Copied!' : copyMessage.
|
||||
:style="height ? `min-height: ${height - 40 /* card padding */ + 10 /* negative margin compensation */}px` : ''"
|
||||
>
|
||||
<n-config-provider :hljs="hljs">
|
||||
<n-code :code="value" :language="language" :trim="false" data-test-id="area-content" />
|
||||
<n-code :code="value" :language="language" :word-wrap="wordWrap" :trim="false" data-test-id="area-content" />
|
||||
</n-config-provider>
|
||||
</n-scrollbar>
|
||||
<div absolute right-10px top-10px>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { extension as getExtensionFromMimeType, extension as getMimeTypeFromExtension } from 'mime-types';
|
||||
import type { Ref } from 'vue';
|
||||
import type { MaybeRef, Ref } from 'vue';
|
||||
import _ from 'lodash';
|
||||
import { get } from '@vueuse/core';
|
||||
|
||||
export {
|
||||
getMimeTypeFromBase64,
|
||||
@ -75,21 +76,11 @@ function downloadFromBase64({ sourceValue, filename, extension, fileMimeType }:
|
||||
}
|
||||
|
||||
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> }) {
|
||||
{ source: MaybeRef<string>; filename?: MaybeRef<string>; extension?: MaybeRef<string> }) {
|
||||
return {
|
||||
download() {
|
||||
downloadFromBase64({ sourceValue: source.value, filename: filename?.value, extension: extension?.value });
|
||||
downloadFromBase64({ sourceValue: get(source), filename: get(filename), extension: get(extension) });
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -116,3 +107,13 @@ function previewImageFromBase64(base64String: string): HTMLImageElement {
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
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 });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
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[],
|
||||
};
|
||||
}
|
||||
}
|
||||
120
src/tools/certificate-key-parser/certificate-key-parser.vue
Normal file
120
src/tools/certificate-key-parser/certificate-key-parser.vue
Normal file
@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { Buffer } from 'node:buffer';
|
||||
|
||||
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('');
|
||||
const fileInput = ref() as Ref<Buffer>;
|
||||
const inputType = ref<'file' | 'content'>('file');
|
||||
|
||||
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 (_) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
const parsedSections = computedAsync<LabelValue[]>(async () => {
|
||||
const inputContent = inputKeyOrCertificate.value;
|
||||
const file = fileInput.value;
|
||||
let inputKeyOrCertificateValue: string | Buffer = '';
|
||||
if (inputType.value === 'file' && file) {
|
||||
inputKeyOrCertificateValue = file;
|
||||
}
|
||||
else if (inputType.value === 'content' && inputContent) {
|
||||
inputKeyOrCertificateValue = inputContent;
|
||||
}
|
||||
const { values, certificateX509DER: certPEM } = await getKeyOrCertificateInfosAsync(inputKeyOrCertificateValue, passphrase.value);
|
||||
certificateX509DER.value = certPEM || '';
|
||||
return values;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-card>
|
||||
<n-radio-group v-model:value="inputType" name="radiogroup" mb-2 flex justify-center>
|
||||
<n-space>
|
||||
<n-radio
|
||||
value="file"
|
||||
label="File"
|
||||
/>
|
||||
<n-radio
|
||||
value="content"
|
||||
label="Content"
|
||||
/>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
|
||||
<c-file-upload
|
||||
v-if="inputType === 'file'"
|
||||
title="Drag and drop a Certificate file here, or click to select a Certificate file"
|
||||
@file-upload="onUpload"
|
||||
/>
|
||||
|
||||
<c-input-text
|
||||
v-if="inputType === 'content'"
|
||||
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"
|
||||
data-test-id="input"
|
||||
/>
|
||||
</c-card>
|
||||
|
||||
<c-input-text
|
||||
v-model:value="passphrase"
|
||||
label="Passphrase (for encrypted keys):"
|
||||
placeholder="Passphrase (for encrypted keys)..."
|
||||
type="password"
|
||||
data-test-id="pass"
|
||||
/>
|
||||
|
||||
<n-divider />
|
||||
|
||||
<input-copyable
|
||||
v-for="{ label, value, multiline } of parsedSections"
|
||||
:key="label"
|
||||
:label="label"
|
||||
:data-test-id="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'),
|
||||
});
|
||||
@ -6,6 +6,7 @@ import { tool as emailNormalizer } from './email-normalizer';
|
||||
import { tool as asciiTextDrawer } from './ascii-text-drawer';
|
||||
|
||||
import { tool as textToUnicode } from './text-to-unicode';
|
||||
import { tool as certificateKeyParser } from './certificate-key-parser';
|
||||
import { tool as safelinkDecoder } from './safelink-decoder';
|
||||
import { tool as xmlToJson } from './xml-to-json';
|
||||
import { tool as jsonToXml } from './json-to-xml';
|
||||
@ -91,7 +92,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',
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { URL, fileURLToPath } from 'node:url';
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||
|
||||
import VueI18n from '@intlify/unplugin-vue-i18n/vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
@ -97,6 +98,7 @@ export default defineConfig({
|
||||
resolvers: [NaiveUiResolver(), IconsResolver({ prefix: 'icon' })],
|
||||
}),
|
||||
Unocss(),
|
||||
nodePolyfills(),
|
||||
],
|
||||
base: baseUrl,
|
||||
resolve: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user