Skip to content

Commit

Permalink
feat(new tool): pdf signature checker (#745)
Browse files Browse the repository at this point in the history
  • Loading branch information
CorentinTh committed Nov 12, 2023
1 parent 205e360 commit 4781920
Show file tree
Hide file tree
Showing 20 changed files with 448 additions and 21 deletions.
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
}
}
}

1 comment on commit 4781920

@vercel
Copy link

@vercel vercel bot commented on 4781920 Nov 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.