Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(new tool): pdf signature checker #745

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ declare module '@vue/runtime-core' {
'CButtonsSelect.demo': typeof import('./src/ui/c-buttons-select/c-buttons-select.demo.vue')['default']
CCard: typeof import('./src/ui/c-card/c-card.vue')['default']
'CCard.demo': typeof import('./src/ui/c-card/c-card.demo.vue')['default']
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']
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']
Chronometer: typeof import('./src/tools/chronometer/chronometer.vue')['default']
CInputText: typeof import('./src/ui/c-input-text/c-input-text.vue')['default']
Expand All @@ -41,6 +45,8 @@ declare module '@vue/runtime-core' {
'CLink.demo': typeof import('./src/ui/c-link/c-link.demo.vue')['default']
CModal: typeof import('./src/ui/c-modal/c-modal.vue')['default']
'CModal.demo': typeof import('./src/ui/c-modal/c-modal.demo.vue')['default']
CModalValue: typeof import('./src/ui/c-modal-value/c-modal-value.vue')['default']
'CModalValue.demo': typeof import('./src/ui/c-modal-value/c-modal-value.demo.vue')['default']
CollapsibleToolMenu: typeof import('./src/components/CollapsibleToolMenu.vue')['default']
ColorConverter: typeof import('./src/tools/color-converter/color-converter.vue')['default']
ColoredCard: typeof import('./src/components/ColoredCard.vue')['default']
Expand Down Expand Up @@ -83,6 +89,7 @@ declare module '@vue/runtime-core' {
'IconMdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
'IconMdi:kettleSteamOutline': typeof import('~icons/mdi/kettle-steam-outline')['default']
IconMdiArrowDown: typeof import('~icons/mdi/arrow-down')['default']
IconMdiArrowRight: typeof import('~icons/mdi/arrow-right')['default']
IconMdiArrowRightBottom: typeof import('~icons/mdi/arrow-right-bottom')['default']
IconMdiCamera: typeof import('~icons/mdi/camera')['default']
IconMdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
Expand All @@ -100,6 +107,7 @@ declare module '@vue/runtime-core' {
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
IconMdiSearch: typeof import('~icons/mdi/search')['default']
IconMdiTranslate: typeof import('~icons/mdi/translate')['default']
IconMdiTriangleDown: typeof import('~icons/mdi/triangle-down')['default']
IconMdiVideo: typeof import('~icons/mdi/video')['default']
InputCopyable: typeof import('./src/components/InputCopyable.vue')['default']
IntegerBaseConverter: typeof import('./src/tools/integer-base-converter/integer-base-converter.vue')['default']
Expand Down Expand Up @@ -165,6 +173,8 @@ declare module '@vue/runtime-core' {
NUploadDragger: typeof import('naive-ui')['NUploadDragger']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default']
PdfSignatureChecker: typeof import('./src/tools/pdf-signature-checker/pdf-signature-checker.vue')['default']
PdfSignatureDetails: typeof import('./src/tools/pdf-signature-checker/components/pdf-signature-details.vue')['default']
PercentageCalculator: typeof import('./src/tools/percentage-calculator/percentage-calculator.vue')['default']
PhoneParserAndFormatter: typeof import('./src/tools/phone-parser-and-formatter/phone-parser-and-formatter.vue')['default']
QrCodeGenerator: typeof import('./src/tools/qr-code-generator/qr-code-generator.vue')['default']
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"netmask": "^2.0.2",
"node-forge": "^1.3.1",
"oui": "^12.0.52",
"pdf-signature-reader": "^1.4.2",
"pinia": "^2.0.34",
"plausible-tracker": "^0.3.8",
"qrcode": "^1.5.1",
Expand Down
29 changes: 17 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/shims.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ declare module 'unicode-emoji-json' {
}>;

export default emoji;
}

declare module 'pdf-signature-reader' {
const verifySignature: (pdf: ArrayBuffer) => ({signatures: SignatureInfo[]});

export default verifySignature;
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ const ibanExamples = [
<div>
<c-input-text v-model:value="rawIban" placeholder="Enter an IBAN to check for validity..." test-id="iban-input" />

<c-key-value-list :items="ibanInfo" my-5 data-test-id="iban-info" />
<c-card v-if="ibanInfo.length > 0" mt-5>
<c-key-value-list :items="ibanInfo" data-test-id="iban-info" />
</c-card>

<c-card title="Valid IBAN examples">
<c-card title="Valid IBAN examples" mt-5>
<div v-for="iban in ibanExamples" :key="iban">
<c-text-copyable :value="iban" font-mono :displayed-value="friendlyFormatIBAN(iban)" />
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
import { tool as textToBinary } from './text-to-binary';
Expand Down Expand Up @@ -78,7 +79,7 @@ import { tool as xmlFormatter } from './xml-formatter';
export const toolsByCategory: ToolCategory[] = [
{
name: 'Crypto',
components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser],
components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker],
},
{
name: 'Converter',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<script setup lang="ts">
import type { SignatureInfo } from '../pdf-signature-checker.types';

const props = defineProps<{ signature: SignatureInfo }>();
const { signature } = toRefs(props);

const tableHeaders = {
validityPeriod: 'Validity period',
issuedBy: 'Issued by',
issuedTo: 'Issued to',
pemCertificate: 'PEM certificate',
};

const certs = computed(() => signature.value.meta.certs.map((certificate, index) => ({
...certificate,
validityPeriod: {
notBefore: new Date(certificate.validityPeriod.notBefore).toLocaleString(),
notAfter: new Date(certificate.validityPeriod.notAfter).toLocaleString(),
},
certificateName: `Certificate ${index + 1}`,
})),
);
</script>

<template>
<div flex flex-col gap-2>
<c-table :data="certs" :headers="tableHeaders">
<template #validityPeriod="{ value }">
<c-key-value-list
:items="[{
label: 'Not before',
value: value.notBefore,
}, {
label: 'Not after',
value: value.notAfter,
}]"
/>
</template>

<template #issuedBy="{ value }">
<c-key-value-list
:items="[{
label: 'Common name',
value: value.commonName,
}, {
label: 'Organization name',
value: value.organizationName,
}, {
label: 'Country name',
value: value.countryName,
}, {
label: 'Locality name',
value: value.localityName,
}, {
label: 'Organizational unit name',
value: value.organizationalUnitName,
}, {
label: 'State or province name',
value: value.stateOrProvinceName,
}]"
/>
</template>

<template #issuedTo="{ value }">
<c-key-value-list
:items="[{
label: 'Common name',
value: value.commonName,
}, {
label: 'Organization name',
value: value.organizationName,
}, {
label: 'Country name',
value: value.countryName,
}, {
label: 'Locality name',
value: value.localityName,
}, {
label: 'Organizational unit name',
value: value.organizationalUnitName,
}, {
label: 'State or province name',
value: value.stateOrProvinceName,
}]"
/>
</template>

<template #pemCertificate="{ value }">
<c-modal-value :value="value" label="View PEM cert">
<template #value>
<div break-all text-xs>
{{ value }}
</div>
</template>
</c-modal-value>
</template>
</c-table>
</div>
</template>
12 changes: 12 additions & 0 deletions src/tools/pdf-signature-checker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineTool } from '../tool';
import FileCertIcon from '~icons/mdi/file-certificate-outline';

export const tool = defineTool({
name: 'PDF signature checker',
path: '/pdf-signature-checker',
description: 'Verify the signatures of a PDF file. A signed PDF file contains one or more signatures that may be used to determine whether the contents of the file have been altered since the file was signed.',
keywords: ['pdf', 'signature', 'checker', 'verify', 'validate', 'sign'],
component: () => import('./pdf-signature-checker.vue'),
icon: FileCertIcon,
createdAt: new Date('2023-12-09'),
});
11 changes: 11 additions & 0 deletions src/tools/pdf-signature-checker/pdf-signature-checker.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { expect, test } from '@playwright/test';

test.describe('Tool - Pdf signature checker', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/pdf-signature-checker');
});

test('Has correct title', async ({ page }) => {
await expect(page).toHaveTitle('PDF signature checker - IT Tools');
});
});
39 changes: 39 additions & 0 deletions src/tools/pdf-signature-checker/pdf-signature-checker.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export interface SignatureInfo {
verified: boolean
authenticity: boolean
integrity: boolean
expired: boolean
meta: {
certs: {
clientCertificate?: boolean
issuedBy: {
commonName: string
organizationalUnitName?: string
organizationName: string
countryName?: string
localityName?: string
stateOrProvinceName?: string
}
issuedTo: {
commonName: string
serialNumber?: string
organizationalUnitName?: string
organizationName: string
countryName?: string
localityName?: string
stateOrProvinceName?: string
}
validityPeriod: {
notBefore: string
notAfter: string
}
pemCertificate: string
}[]
signatureMeta: {
reason: string
contactInfo: string | null
location: string
name: string | null
}
}
}
Loading