From d74c3f4598860ed447ec682cd23edfc0acc01e81 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Wed, 20 Aug 2025 11:30:57 +0100 Subject: [PATCH] V2 remove cert (#4239) # Description of Changes --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- .../public/locales/en-GB/translation.json | 13 ++- .../public/locales/en-US/translation.json | 13 ++- .../RemoveCertificateSignSettings.tsx | 27 +++++++ .../src/data/useTranslatedToolRegistry.tsx | 7 +- .../useRemoveCertificateSignOperation.ts | 23 ++++++ .../useRemoveCertificateSignParameters.ts | 19 +++++ frontend/src/tools/RemoveCertificateSign.tsx | 80 +++++++++++++++++++ frontend/src/types/fileContext.ts | 3 +- 8 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx create mode 100644 frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts create mode 100644 frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts create mode 100644 frontend/src/tools/RemoveCertificateSign.tsx diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 13d686f88..a9d38b142 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -1268,7 +1268,18 @@ "title": "Remove Certificate Signature", "header": "Remove the digital certificate from the PDF", "selectPDF": "Select a PDF file:", - "submit": "Remove Signature" + "submit": "Remove Signature", + "description": "This tool will remove digital certificate signatures from your PDF document.", + "filenamePrefix": "unsigned", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred whilst removing certificate signatures." + }, + "results": { + "title": "Certificate Removal Results" + } }, "pageLayout": { "tags": "merge,composite,single-view,organize", diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json index eb5d2e04e..43fbd72f1 100644 --- a/frontend/public/locales/en-US/translation.json +++ b/frontend/public/locales/en-US/translation.json @@ -995,7 +995,18 @@ "title": "Remove Certificate Signature", "header": "Remove the digital certificate from the PDF", "selectPDF": "Select a PDF file:", - "submit": "Remove Signature" + "submit": "Remove Signature", + "description": "This tool will remove digital certificate signatures from your PDF document.", + "filenamePrefix": "unsigned", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred while removing certificate signatures." + }, + "results": { + "title": "Certificate Removal Results" + } }, "pageLayout": { "tags": "merge,composite,single-view,organize", diff --git a/frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx b/frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx new file mode 100644 index 000000000..f34e3f2e6 --- /dev/null +++ b/frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { RemoveCertificateSignParameters } from '../../../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters'; + +interface RemoveCertificateSignSettingsProps { + parameters: RemoveCertificateSignParameters; + onParameterChange: (parameter: K, value: RemoveCertificateSignParameters[K]) => void; + disabled?: boolean; +} + +const RemoveCertificateSignSettings: React.FC = ({ + parameters, + onParameterChange, // Unused - kept for interface consistency and future extensibility + disabled = false +}) => { + const { t } = useTranslation(); + + return ( +
+

+ {t('removeCertSign.description', 'This tool will remove digital certificate signatures from your PDF document.')} +

+
+ ); +}; + +export default RemoveCertificateSignSettings; \ No newline at end of file diff --git a/frontend/src/data/useTranslatedToolRegistry.tsx b/frontend/src/data/useTranslatedToolRegistry.tsx index 1a53cf651..364c54211 100644 --- a/frontend/src/data/useTranslatedToolRegistry.tsx +++ b/frontend/src/data/useTranslatedToolRegistry.tsx @@ -11,6 +11,7 @@ import RemovePassword from '../tools/RemovePassword'; import { SubcategoryId, ToolCategory, ToolRegistry } from './toolsTaxonomy'; import AddWatermark from '../tools/AddWatermark'; import Repair from '../tools/Repair'; +import RemoveCertificateSign from '../tools/RemoveCertificateSign'; // Hook to get the translated tool registry export function useFlatToolRegistry(): ToolRegistry { @@ -323,11 +324,13 @@ export function useFlatToolRegistry(): ToolRegistry { "remove-certificate-sign": { icon: remove_moderator, name: t("home.removeCertSign.title", "Remove Certificate Signatures"), - component: null, + component: RemoveCertificateSign, view: "security", description: t("home.removeCertSign.desc", "Remove digital signatures from PDF documents"), category: ToolCategory.STANDARD_TOOLS, - subcategory: SubcategoryId.REMOVAL + subcategory: SubcategoryId.REMOVAL, + maxFiles: -1, + endpoints: ["remove-certificate-sign"] }, diff --git a/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts new file mode 100644 index 000000000..5987944ec --- /dev/null +++ b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts @@ -0,0 +1,23 @@ +import { useTranslation } from 'react-i18next'; +import { useToolOperation } from '../shared/useToolOperation'; +import { createStandardErrorHandler } from '../../../utils/toolErrorHandler'; +import { RemoveCertificateSignParameters } from './useRemoveCertificateSignParameters'; + +export const useRemoveCertificateSignOperation = () => { + const { t } = useTranslation(); + + const buildFormData = (parameters: RemoveCertificateSignParameters, file: File): FormData => { + const formData = new FormData(); + formData.append("fileInput", file); + return formData; + }; + + return useToolOperation({ + operationType: 'removeCertificateSign', + endpoint: '/api/v1/security/remove-cert-sign', + buildFormData, + filePrefix: t('removeCertSign.filenamePrefix', 'unsigned') + '_', + multiFileEndpoint: false, + getErrorMessage: createStandardErrorHandler(t('removeCertSign.error.failed', 'An error occurred while removing certificate signatures.')) + }); +}; \ No newline at end of file diff --git a/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts new file mode 100644 index 000000000..59903ccfc --- /dev/null +++ b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts @@ -0,0 +1,19 @@ +import { BaseParameters } from '../../../types/parameters'; +import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters'; + +export interface RemoveCertificateSignParameters extends BaseParameters { + // Extends BaseParameters - ready for future parameter additions if needed +} + +export const defaultParameters: RemoveCertificateSignParameters = { + // No parameters needed +}; + +export type RemoveCertificateSignParametersHook = BaseParametersHook; + +export const useRemoveCertificateSignParameters = (): RemoveCertificateSignParametersHook => { + return useBaseParameters({ + defaultParameters, + endpointName: 'remove-certificate-sign', + }); +}; \ No newline at end of file diff --git a/frontend/src/tools/RemoveCertificateSign.tsx b/frontend/src/tools/RemoveCertificateSign.tsx new file mode 100644 index 000000000..e33675625 --- /dev/null +++ b/frontend/src/tools/RemoveCertificateSign.tsx @@ -0,0 +1,80 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useEndpointEnabled } from "../hooks/useEndpointConfig"; +import { useFileContext } from "../contexts/FileContext"; +import { useToolFileSelection } from "../contexts/FileSelectionContext"; + +import { createToolFlow } from "../components/tools/shared/createToolFlow"; + +import { useRemoveCertificateSignParameters } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters"; +import { useRemoveCertificateSignOperation } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation"; +import { BaseToolProps } from "../types/tool"; + +const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { + const { t } = useTranslation(); + const { setCurrentMode } = useFileContext(); + const { selectedFiles } = useToolFileSelection(); + + const removeCertificateSignParams = useRemoveCertificateSignParameters(); + const removeCertificateSignOperation = useRemoveCertificateSignOperation(); + + // Endpoint validation + const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(removeCertificateSignParams.getEndpointName()); + + useEffect(() => { + removeCertificateSignOperation.resetResults(); + onPreviewFile?.(null); + }, [removeCertificateSignParams.parameters]); + + const handleRemoveSignature = async () => { + try { + await removeCertificateSignOperation.executeOperation(removeCertificateSignParams.parameters, selectedFiles); + if (removeCertificateSignOperation.files && onComplete) { + onComplete(removeCertificateSignOperation.files); + } + } catch (error) { + if (onError) { + onError(error instanceof Error ? error.message : t("removeCertSign.error.failed", "Remove certificate signature operation failed")); + } + } + }; + + const handleThumbnailClick = (file: File) => { + onPreviewFile?.(file); + sessionStorage.setItem("previousMode", "removeCertificateSign"); + setCurrentMode("viewer"); + }; + + const handleSettingsReset = () => { + removeCertificateSignOperation.resetResults(); + onPreviewFile?.(null); + setCurrentMode("removeCertificateSign"); + }; + + const hasFiles = selectedFiles.length > 0; + const hasResults = removeCertificateSignOperation.files.length > 0 || removeCertificateSignOperation.downloadUrl !== null; + + return createToolFlow({ + files: { + selectedFiles, + isCollapsed: hasFiles || hasResults, + placeholder: t("removeCertSign.files.placeholder", "Select a PDF file in the main view to get started"), + }, + steps: [], + executeButton: { + text: t("removeCertSign.submit", "Remove Signature"), + isVisible: !hasResults, + loadingText: t("loading"), + onClick: handleRemoveSignature, + disabled: !removeCertificateSignParams.validateParameters() || !hasFiles || !endpointEnabled, + }, + review: { + isVisible: hasResults, + operation: removeCertificateSignOperation, + title: t("removeCertSign.results.title", "Certificate Removal Results"), + onFileClick: handleThumbnailClick, + }, + }); +}; + +export default RemoveCertificateSign; \ No newline at end of file diff --git a/frontend/src/types/fileContext.ts b/frontend/src/types/fileContext.ts index 1c513b523..b868bf0e6 100644 --- a/frontend/src/types/fileContext.ts +++ b/frontend/src/types/fileContext.ts @@ -19,7 +19,8 @@ export type ModeType = | 'changePermissions' | 'watermark' | 'removePassword' - | 'repair'; + | 'repair' + | 'removeCertificateSign'; export type ViewType = 'viewer' | 'pageEditor' | 'fileEditor';