mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 05:47:10 -04:00
feat(new tool): PDF Encrypt
PDF Encrypter
This commit is contained in:
parent
23b4dc84c8
commit
1b82da5b4b
8 changed files with 1584 additions and 150 deletions
|
@ -5,6 +5,8 @@ module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
extends: ['@antfu', './.eslintrc-auto-import.json', '@unocss'],
|
extends: ['@antfu', './.eslintrc-auto-import.json', '@unocss'],
|
||||||
|
|
||||||
|
ignorePatterns: ['src/libs/*'],
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
'curly': ['error', 'all'],
|
'curly': ['error', 'all'],
|
||||||
'@typescript-eslint/semi': ['error', 'always'],
|
'@typescript-eslint/semi': ['error', 'always'],
|
||||||
|
|
|
@ -41,8 +41,8 @@
|
||||||
"@tiptap/pm": "2.1.6",
|
"@tiptap/pm": "2.1.6",
|
||||||
"@tiptap/starter-kit": "2.1.6",
|
"@tiptap/starter-kit": "2.1.6",
|
||||||
"@tiptap/vue-3": "2.0.3",
|
"@tiptap/vue-3": "2.0.3",
|
||||||
"@types/figlet": "^1.5.8",
|
|
||||||
"@types/emscripten": "^1.39.10",
|
"@types/emscripten": "^1.39.10",
|
||||||
|
"@types/figlet": "^1.5.8",
|
||||||
"@vicons/material": "^0.12.0",
|
"@vicons/material": "^0.12.0",
|
||||||
"@vicons/tabler": "^0.12.0",
|
"@vicons/tabler": "^0.12.0",
|
||||||
"@vueuse/core": "^10.3.0",
|
"@vueuse/core": "^10.3.0",
|
||||||
|
@ -65,6 +65,7 @@
|
||||||
"highlight.js": "^11.7.0",
|
"highlight.js": "^11.7.0",
|
||||||
"iarna-toml-esm": "^3.0.5",
|
"iarna-toml-esm": "^3.0.5",
|
||||||
"ibantools": "^4.3.3",
|
"ibantools": "^4.3.3",
|
||||||
|
"js-base64": "^3.7.7",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"libphonenumber-js": "^1.10.28",
|
"libphonenumber-js": "^1.10.28",
|
||||||
|
|
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
|
@ -23,6 +23,9 @@ dependencies:
|
||||||
'@tiptap/vue-3':
|
'@tiptap/vue-3':
|
||||||
specifier: 2.0.3
|
specifier: 2.0.3
|
||||||
version: 2.0.3(@tiptap/core@2.1.12)(@tiptap/pm@2.1.6)(vue@3.3.4)
|
version: 2.0.3(@tiptap/core@2.1.12)(@tiptap/pm@2.1.6)(vue@3.3.4)
|
||||||
|
'@types/emscripten':
|
||||||
|
specifier: ^1.39.10
|
||||||
|
version: 1.39.10
|
||||||
'@types/figlet':
|
'@types/figlet':
|
||||||
specifier: ^1.5.8
|
specifier: ^1.5.8
|
||||||
version: 1.5.8
|
version: 1.5.8
|
||||||
|
@ -92,6 +95,9 @@ dependencies:
|
||||||
ibantools:
|
ibantools:
|
||||||
specifier: ^4.3.3
|
specifier: ^4.3.3
|
||||||
version: 4.3.3
|
version: 4.3.3
|
||||||
|
js-base64:
|
||||||
|
specifier: ^3.7.7
|
||||||
|
version: 3.7.7
|
||||||
json5:
|
json5:
|
||||||
specifier: ^2.2.3
|
specifier: ^2.2.3
|
||||||
version: 2.2.3
|
version: 2.2.3
|
||||||
|
@ -2901,6 +2907,10 @@ packages:
|
||||||
'@types/trusted-types': 2.0.3
|
'@types/trusted-types': 2.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/emscripten@1.39.10:
|
||||||
|
resolution: {integrity: sha512-TB/6hBkYQJxsZHSqyeuO1Jt0AB/bW6G7rHt9g7lML7SOF6lbgcHvw/Lr+69iqN0qxgXLhWKScAon73JNnptuDw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/estree@0.0.39:
|
/@types/estree@0.0.39:
|
||||||
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
|
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -3351,7 +3361,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@unhead/dom': 0.5.1
|
'@unhead/dom': 0.5.1
|
||||||
'@unhead/schema': 0.5.1
|
'@unhead/schema': 0.5.1
|
||||||
'@vueuse/shared': 10.7.2(vue@3.3.4)
|
'@vueuse/shared': 10.9.0(vue@3.3.4)
|
||||||
unhead: 0.5.1
|
unhead: 0.5.1
|
||||||
vue: 3.3.4
|
vue: 3.3.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -3993,10 +4003,10 @@ packages:
|
||||||
- vue
|
- vue
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vueuse/shared@10.7.2(vue@3.3.4):
|
/@vueuse/shared@10.9.0(vue@3.3.4):
|
||||||
resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==}
|
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
vue-demi: 0.14.6(vue@3.3.4)
|
vue-demi: 0.14.7(vue@3.3.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
- vue
|
- vue
|
||||||
|
@ -6472,6 +6482,10 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/js-base64@3.7.7:
|
||||||
|
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/js-beautify@1.14.6:
|
/js-beautify@1.14.6:
|
||||||
resolution: {integrity: sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==}
|
resolution: {integrity: sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -9151,8 +9165,8 @@ packages:
|
||||||
vue: 3.3.4
|
vue: 3.3.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vue-demi@0.14.6(vue@3.3.4):
|
/vue-demi@0.14.7(vue@3.3.4):
|
||||||
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
|
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import { extension as getExtensionFromMime } from 'mime-types';
|
import { extension as getExtensionFromMimeType, extension as getMimeTypeFromExtension } from 'mime-types';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
export { getMimeTypeFromBase64, useDownloadFileFromBase64 };
|
export {
|
||||||
|
getMimeTypeFromBase64,
|
||||||
|
getMimeTypeFromExtension, getExtensionFromMimeType,
|
||||||
|
useDownloadFileFromBase64, useDownloadFileFromBase64Refs,
|
||||||
|
};
|
||||||
|
|
||||||
const commonMimeTypesSignatures = {
|
const commonMimeTypesSignatures = {
|
||||||
'JVBERi0': 'application/pdf',
|
'JVBERi0': 'application/pdf',
|
||||||
|
@ -36,30 +40,55 @@ function getFileExtensionFromMimeType({
|
||||||
defaultExtension?: string
|
defaultExtension?: string
|
||||||
}) {
|
}) {
|
||||||
if (mimeType) {
|
if (mimeType) {
|
||||||
return getExtensionFromMime(mimeType) ?? defaultExtension;
|
return getExtensionFromMimeType(mimeType) ?? defaultExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultExtension;
|
return defaultExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useDownloadFileFromBase64({ source, filename }: { source: Ref<string>; filename?: string }) {
|
function downloadFromBase64({ sourceValue, filename, extension, fileMimeType }:
|
||||||
return {
|
{ sourceValue: string; filename?: string; extension?: string; fileMimeType?: string }) {
|
||||||
download() {
|
if (sourceValue === '') {
|
||||||
if (source.value === '') {
|
|
||||||
throw new Error('Base64 string is empty');
|
throw new Error('Base64 string is empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { mimeType } = getMimeTypeFromBase64({ base64String: source.value });
|
const defaultExtension = extension ?? 'txt';
|
||||||
const base64String = mimeType
|
const { mimeType } = getMimeTypeFromBase64({ base64String: sourceValue });
|
||||||
? source.value
|
let base64String = sourceValue;
|
||||||
: `data:text/plain;base64,${source.value}`;
|
if (!mimeType) {
|
||||||
|
const targetMimeType = fileMimeType ?? getMimeTypeFromExtension(defaultExtension);
|
||||||
|
base64String = `data:${targetMimeType};base64,${sourceValue}`;
|
||||||
|
}
|
||||||
|
|
||||||
const cleanFileName = filename ?? `file.${getFileExtensionFromMimeType({ mimeType })}`;
|
const cleanExtension = extension ?? getFileExtensionFromMimeType(
|
||||||
|
{ mimeType, defaultExtension });
|
||||||
|
let cleanFileName = filename ?? `file.${cleanExtension}`;
|
||||||
|
if (extension && !cleanFileName.endsWith(`.${extension}`)) {
|
||||||
|
cleanFileName = `${cleanFileName}.${cleanExtension}`;
|
||||||
|
}
|
||||||
|
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = base64String;
|
a.href = base64String;
|
||||||
a.download = cleanFileName;
|
a.download = cleanFileName;
|
||||||
a.click();
|
a.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
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> }) {
|
||||||
|
return {
|
||||||
|
download() {
|
||||||
|
downloadFromBase64({ sourceValue: source.value, filename: filename?.value, extension: extension?.value });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -80,12 +80,26 @@ import { tool as urlParser } from './url-parser';
|
||||||
import { tool as uuidGenerator } from './uuid-generator';
|
import { tool as uuidGenerator } from './uuid-generator';
|
||||||
import { tool as macAddressLookup } from './mac-address-lookup';
|
import { tool as macAddressLookup } from './mac-address-lookup';
|
||||||
import { tool as xmlFormatter } from './xml-formatter';
|
import { tool as xmlFormatter } from './xml-formatter';
|
||||||
|
import { tool as pdfEncrypt } from './pdf-encrypt';
|
||||||
import { tool as yamlViewer } from './yaml-viewer';
|
import { tool as yamlViewer } from './yaml-viewer';
|
||||||
|
|
||||||
export const toolsByCategory: ToolCategory[] = [
|
export const toolsByCategory: ToolCategory[] = [
|
||||||
{
|
{
|
||||||
name: 'Crypto',
|
name: 'Crypto',
|
||||||
components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker],
|
components: [
|
||||||
|
tokenGenerator,
|
||||||
|
hashText,
|
||||||
|
bcrypt,
|
||||||
|
uuidGenerator,
|
||||||
|
ulidGenerator,
|
||||||
|
cypher,
|
||||||
|
bip39,
|
||||||
|
hmacGenerator,
|
||||||
|
rsaKeyPairGenerator,
|
||||||
|
passwordStrengthAnalyser,
|
||||||
|
pdfSignatureChecker,
|
||||||
|
pdfEncrypt,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Converter',
|
name: 'Converter',
|
||||||
|
|
12
src/tools/pdf-encrypt/index.ts
Normal file
12
src/tools/pdf-encrypt/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Lock } from '@vicons/tabler';
|
||||||
|
import { defineTool } from '../tool';
|
||||||
|
|
||||||
|
export const tool = defineTool({
|
||||||
|
name: 'Pdf Encrypt',
|
||||||
|
path: '/pdf-encrypt',
|
||||||
|
description: 'Encrypt and add protection to a PDF File',
|
||||||
|
keywords: ['pdf', 'encrypt'],
|
||||||
|
component: () => import('./pdf-encrypt.vue'),
|
||||||
|
icon: Lock,
|
||||||
|
createdAt: new Date('2024-01-09'),
|
||||||
|
});
|
194
src/tools/pdf-encrypt/pdf-encrypt.vue
Normal file
194
src/tools/pdf-encrypt/pdf-encrypt.vue
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Base64 } from 'js-base64';
|
||||||
|
import createQPDFModule from '@/libs/qpdf/qpdf';
|
||||||
|
import { useDownloadFileFromBase64Refs } from '@/composable/downloadBase64';
|
||||||
|
|
||||||
|
const status = ref<'idle' | 'done' | 'error' | 'processing'>('idle');
|
||||||
|
const file = ref<File | null>(null);
|
||||||
|
|
||||||
|
const restrictAccessibility = useStorage('pdf-encrypt:accessibility', false);
|
||||||
|
const restrictAnnotate = useStorage('pdf-encrypt:annotate', false);
|
||||||
|
const restrictAssemble = useStorage('pdf-encrypt:assemble', false);
|
||||||
|
const restrictExtract = useStorage('pdf-encrypt:extract', false);
|
||||||
|
const restrictForm = useStorage('pdf-encrypt:form', false);
|
||||||
|
const restrictModifyOther = useStorage('pdf-encrypt:modoth', false);
|
||||||
|
const clearTextMetadata = useStorage('pdf-encrypt:clearmeta', false);
|
||||||
|
const restrictModify = useStorage('pdf-encrypt:mod', 'all');
|
||||||
|
const restrictPrint = useStorage('pdf-encrypt:print', 'full');
|
||||||
|
const userPassword = ref('');
|
||||||
|
const ownerPassword = ref('');
|
||||||
|
|
||||||
|
const base64OutputPDF = ref('');
|
||||||
|
const fileName = ref('');
|
||||||
|
const fileExtension = ref('pdf');
|
||||||
|
const { download } = useDownloadFileFromBase64Refs(
|
||||||
|
{
|
||||||
|
source: base64OutputPDF,
|
||||||
|
filename: fileName,
|
||||||
|
extension: fileExtension,
|
||||||
|
});
|
||||||
|
|
||||||
|
function onFileUploaded(uploadedFile: File) {
|
||||||
|
file.value = uploadedFile;
|
||||||
|
fileName.value = `encrypted_${file.value.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onProcessClicked() {
|
||||||
|
if (!file.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fileBuffer = await file.value.arrayBuffer();
|
||||||
|
|
||||||
|
status.value = 'processing';
|
||||||
|
try {
|
||||||
|
const options = [
|
||||||
|
'--encrypt',
|
||||||
|
];
|
||||||
|
options.push(`${userPassword.value}`);
|
||||||
|
options.push(`${ownerPassword.value}`);
|
||||||
|
options.push('128');
|
||||||
|
options.push('--use-aes=y');
|
||||||
|
options.push(`--accessibility=${(restrictAccessibility.value ? 'n' : 'y')}`);
|
||||||
|
options.push(`--annotate=${(restrictAnnotate.value ? 'n' : 'y')}`);
|
||||||
|
options.push(`--assemble=${(restrictAssemble.value ? 'n' : 'y')}`);
|
||||||
|
options.push(`--extract=${(restrictExtract.value ? 'n' : 'y')}`);
|
||||||
|
options.push(`--form=${(restrictForm.value ? 'n' : 'y')}`);
|
||||||
|
options.push(`--modify-other=${(restrictModifyOther.value ? 'n' : 'y')}`);
|
||||||
|
options.push(`--modify=${(restrictModify.value)}`);
|
||||||
|
options.push(`--print=${(restrictPrint.value)}`);
|
||||||
|
if (clearTextMetadata.value) {
|
||||||
|
options.push('--cleartext-metadata');
|
||||||
|
}
|
||||||
|
options.push('--');
|
||||||
|
options.push('in.pdf');
|
||||||
|
options.push('out.pdf');
|
||||||
|
const outPdfBuffer = await callMainWithInOutPdf(fileBuffer,
|
||||||
|
options, 0);
|
||||||
|
base64OutputPDF.value = `data:application/pdf;base64,${Base64.fromUint8Array(outPdfBuffer)}`;
|
||||||
|
status.value = 'done';
|
||||||
|
|
||||||
|
download();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
status.value = 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function callMainWithInOutPdf(data: ArrayBuffer, args: string[], expected_exitcode: number) {
|
||||||
|
const mod = await createQPDFModule();
|
||||||
|
mod.FS.writeFile('in.pdf', new Uint8Array(data));
|
||||||
|
const ret = mod.callMain(args);
|
||||||
|
if (expected_exitcode !== ret) {
|
||||||
|
throw new Error('Process run failed');
|
||||||
|
}
|
||||||
|
return mod.FS.readFile('out.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
const printRestrictionOptions = [{ value: 'none', label: 'Disallow printing' },
|
||||||
|
{ value: 'low', label: 'Allow only low-resolution printing' },
|
||||||
|
{ value: 'full', label: 'Allow full printing' },
|
||||||
|
];
|
||||||
|
const modificationRestrictionOptions = [
|
||||||
|
{ value: 'none', label: 'Allow no modifications' },
|
||||||
|
{ value: 'assembly', label: 'Allow document assembly only' },
|
||||||
|
{ value: 'form', label: 'Allow document assembly only + filling in form fields and signing' },
|
||||||
|
{ value: 'annotate', label: 'Allow document assembly only + filling in form fields and signing + commenting and modifying forms' },
|
||||||
|
{ value: 'all', label: 'Allow full document modification' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div style="flex: 0 0 100%">
|
||||||
|
<div mx-auto max-w-600px>
|
||||||
|
<c-file-upload
|
||||||
|
title="Drag and drop a PDF file here, or click to select a file"
|
||||||
|
accept=".pdf"
|
||||||
|
@file-upload="onFileUploaded"
|
||||||
|
/>
|
||||||
|
<div mt-2 text-center>
|
||||||
|
<strong>Output file:</strong> {{ fileName }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<c-card title="Permissions" mb-3 mt-3>
|
||||||
|
<n-space>
|
||||||
|
<n-checkbox v-model:checked="restrictAccessibility">
|
||||||
|
Restrict accessibility (usually ignored)
|
||||||
|
</n-checkbox>
|
||||||
|
<n-checkbox v-model:checked="restrictAnnotate">
|
||||||
|
Restrict commenting/filling form fields
|
||||||
|
</n-checkbox>
|
||||||
|
<n-checkbox v-model:checked="restrictAssemble">
|
||||||
|
Restrict document assembly
|
||||||
|
</n-checkbox>
|
||||||
|
<n-checkbox v-model:checked="restrictExtract">
|
||||||
|
Restrict text/graphic extraction
|
||||||
|
</n-checkbox>
|
||||||
|
<n-checkbox v-model:checked="restrictForm">
|
||||||
|
Restrict filling form fields
|
||||||
|
</n-checkbox>
|
||||||
|
<n-checkbox v-model:checked="restrictModifyOther">
|
||||||
|
Restrict other modifications
|
||||||
|
</n-checkbox>
|
||||||
|
<n-checkbox v-model:checked="clearTextMetadata">
|
||||||
|
Prevent encryption of metadata
|
||||||
|
</n-checkbox>
|
||||||
|
</n-space>
|
||||||
|
<c-select
|
||||||
|
v-model:value="restrictModify"
|
||||||
|
:options="modificationRestrictionOptions"
|
||||||
|
label="Control modify access by level"
|
||||||
|
mt-3
|
||||||
|
/>
|
||||||
|
<c-select
|
||||||
|
v-model:value="restrictPrint"
|
||||||
|
:options="printRestrictionOptions"
|
||||||
|
label="Control printing access"
|
||||||
|
mt-3
|
||||||
|
/>
|
||||||
|
</c-card>
|
||||||
|
<n-form-item
|
||||||
|
label="Owner password:"
|
||||||
|
label-placement="left"
|
||||||
|
mb-1
|
||||||
|
>
|
||||||
|
<n-input
|
||||||
|
:value="ownerPassword"
|
||||||
|
type="password"
|
||||||
|
placeholder="Owner password (optional)"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
|
||||||
|
<n-form-item
|
||||||
|
label="User password:"
|
||||||
|
label-placement="left"
|
||||||
|
mb-1
|
||||||
|
>
|
||||||
|
<n-input
|
||||||
|
:value="userPassword"
|
||||||
|
type="password"
|
||||||
|
placeholder="User password (optional)"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
|
||||||
|
<div mt-3 flex justify-center>
|
||||||
|
<c-button :disabled="!file" @click="onProcessClicked()">
|
||||||
|
Encrypt PDF
|
||||||
|
</c-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<n-divider />
|
||||||
|
|
||||||
|
<div mt-3 flex justify-center>
|
||||||
|
<c-alert v-if="status === 'error'" type="error">
|
||||||
|
An error occured processing {{ fileName }}
|
||||||
|
</c-alert>
|
||||||
|
<n-spin
|
||||||
|
v-if="status === 'processing'"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
Loading…
Add table
Add a link
Reference in a new issue