From 4b852bc77664ca9fd93a55611acf1ba658db6a15 Mon Sep 17 00:00:00 2001 From: Alexander Pliushchou Date: Fri, 16 Aug 2024 12:10:09 +0000 Subject: [PATCH 1/2] Add possibility to disable iText fingerprint DEVSIX-7903 Autoported commit. Original commit hash: [e06d553a9] --- .../actions/events/AddFingerPrintEventTest.cs | 48 +++++++++++++ .../itext/kernel/pdf/FingerPrintTest.cs | 7 ++ .../itext/kernel/pdf/TrailerTest.cs | 37 ++++++++++ .../actions/events/AddFingerPrintEvent.cs | 68 +++++++++++++++++++ .../kernel/logs/KernelLogMessageConstant.cs | 2 + .../itext/kernel/pdf/FingerPrint.cs | 20 +++++- .../itext/kernel/pdf/PdfXrefTable.cs | 28 +------- port-hash | 2 +- 8 files changed, 184 insertions(+), 28 deletions(-) create mode 100644 itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs create mode 100644 itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs diff --git a/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs new file mode 100644 index 0000000000..de52b0743a --- /dev/null +++ b/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs @@ -0,0 +1,48 @@ +using iText.Commons.Actions.Data; +using iText.IO.Source; +using iText.Kernel.Logs; +using iText.Kernel.Pdf; +using iText.Test; +using iText.Test.Attributes; + +namespace iText.Kernel.Actions.Events { + [NUnit.Framework.Category("UnitTest")] + public class AddFingerPrintEventTest : ExtendedITextTest { + [NUnit.Framework.Test] + public virtual void NullDocumentTest() { + AddFingerPrintEvent addFingerPrintEvent = new AddFingerPrintEvent(null); + NUnit.Framework.Assert.DoesNotThrow(() => addFingerPrintEvent.DoAction()); + } + + [NUnit.Framework.Test] + [LogMessage(KernelLogMessageConstant.FINGERPRINT_DISABLED_BUT_NO_REQUIRED_LICENCE)] + public virtual void DisableFingerPrintAGPLTest() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument doc = new PdfDocument(new PdfWriter(outputStream))) { + doc.GetFingerPrint().DisableFingerPrint(); + NUnit.Framework.Assert.DoesNotThrow(() => doc.Close()); + } + } + } + + [NUnit.Framework.Test] + public virtual void EnabledFingerPrintAGPLTest() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument doc = new PdfDocument(new PdfWriter(outputStream))) { + NUnit.Framework.Assert.DoesNotThrow(() => doc.Close()); + } + } + } + + [NUnit.Framework.Test] + public virtual void DisableFingerPrintNoProcessorForProductTest() { + using (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + using (PdfDocument doc = new PdfDocument(new PdfWriter(outputStream))) { + ProductData productData = new ProductData("public product name", "product name", "1", 2000, 2024); + doc.GetFingerPrint().RegisterProduct(productData); + NUnit.Framework.Assert.DoesNotThrow(() => doc.Close()); + } + } + } + } +} diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/FingerPrintTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/FingerPrintTest.cs index 87fd928b9e..d3f6e90ecf 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/FingerPrintTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/FingerPrintTest.cs @@ -53,5 +53,12 @@ public virtual void DuplicateTest() { fingerPrint.RegisterProduct(productData); NUnit.Framework.Assert.IsFalse(fingerPrint.RegisterProduct(duplicateProductData)); } + + [NUnit.Framework.Test] + public virtual void DisableFingerPrintTest() { + FingerPrint fingerPrint = new FingerPrint(); + fingerPrint.DisableFingerPrint(); + NUnit.Framework.Assert.IsFalse(fingerPrint.IsFingerPrintEnabled()); + } } } diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/TrailerTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/TrailerTest.cs index 6eefd9a09e..c122a28648 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/TrailerTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/TrailerTest.cs @@ -27,8 +27,10 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons.Utils; using iText.Kernel.Actions.Data; using iText.Kernel.Font; +using iText.Kernel.Logs; using iText.Kernel.Pdf.Canvas; using iText.Test; +using iText.Test.Attributes; namespace iText.Kernel.Pdf { [NUnit.Framework.Category("IntegrationTest")] @@ -137,6 +139,35 @@ public virtual void ExistingTrailerValuesWithStandardizedNameTest() { } } + [NUnit.Framework.Test] + public virtual void EnableFingerprintInAGPLModeTest() { + PdfDocument pdf = new PdfDocument(new PdfWriter(destinationFolder + "enableFingerprintInAGPLMode.pdf")); + pdf.RegisterProduct(this.productData); + PdfPage page = pdf.AddNewPage(); + PdfCanvas canvas = new PdfCanvas(page); + canvas.BeginText().SetFontAndSize(PdfFontFactory.CreateFont(), 12f).ShowText("Hello World").EndText(); + pdf.Close(); + NUnit.Framework.Assert.IsTrue(DoesTrailerContainFingerprint(new FileInfo(destinationFolder + "enableFingerprintInAGPLMode.pdf" + ), MessageFormatUtil.Format("%iText-{0}-{1}\n", productData.GetProductName(), productData.GetVersion() + ))); + } + + [NUnit.Framework.Test] + [LogMessage(KernelLogMessageConstant.FINGERPRINT_DISABLED_BUT_NO_REQUIRED_LICENCE)] + public virtual void TryDisablingFingerprintInAGPLModeTest() { + PdfDocument pdf = new PdfDocument(new PdfWriter(destinationFolder + "tryDisablingFingerprintInAGPLMode.pdf" + )); + pdf.RegisterProduct(this.productData); + PdfPage page = pdf.AddNewPage(); + PdfCanvas canvas = new PdfCanvas(page); + canvas.BeginText().SetFontAndSize(PdfFontFactory.CreateFont(), 12f).ShowText("Hello World").EndText(); + pdf.GetFingerPrint().DisableFingerPrint(); + pdf.Close(); + NUnit.Framework.Assert.IsTrue(DoesTrailerContainFingerprint(new FileInfo(destinationFolder + "tryDisablingFingerprintInAGPLMode.pdf" + ), MessageFormatUtil.Format("%iText-{0}-{1}\n", productData.GetProductName(), productData.GetVersion() + ))); + } + private bool DoesTrailerContainFingerprint(FileInfo file, String fingerPrint) { using (FileStream raf = FileUtil.GetRandomAccessFile(file)) { // put the pointer at the end of the file @@ -145,6 +176,9 @@ private bool DoesTrailerContainFingerprint(FileInfo file, String fingerPrint) { String coreProductData = "%iText-Core-" + ITextCoreProductData.GetInstance().GetVersion(); String templine = ""; while (!templine.Contains(coreProductData)) { + if (raf.Position <= 2) { + return false; + } templine = (char)raf.ReadByte() + templine; raf.Seek(raf.Position - 2); } @@ -152,6 +186,9 @@ private bool DoesTrailerContainFingerprint(FileInfo file, String fingerPrint) { char read = ' '; templine = ""; while (read != '%') { + if (raf.Position <= 2) { + return false; + } read = (char)raf.ReadByte(); templine = read + templine; raf.Seek(raf.Position - 2); diff --git a/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs b/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs new file mode 100644 index 0000000000..45a43ebb19 --- /dev/null +++ b/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using iText.Commons; +using iText.Commons.Actions; +using iText.Commons.Actions.Data; +using iText.Commons.Actions.Processors; +using iText.Commons.Utils; +using iText.Kernel.Actions.Data; +using iText.Kernel.Logs; +using iText.Kernel.Pdf; + +namespace iText.Kernel.Actions.Events { + /// This class is responsible for adding a fingerprint. + public sealed class AddFingerPrintEvent : AbstractITextConfigurationEvent { + private readonly WeakReference document; + + private static readonly ILogger LOGGER = ITextLogManager.GetLogger(typeof(iText.Kernel.Actions.Events.AddFingerPrintEvent + )); + + private const String AGPL_MODE = "AGPL"; + + /// Creates a new instance of the AddFingerPrintEvent. + /// document in which the fingerprint will be added + public AddFingerPrintEvent(PdfDocument document) + : base() { + this.document = new WeakReference(document); + } + + /// Adds fingerprint to the document. + protected internal override void DoAction() { + PdfDocument pdfDocument = (PdfDocument)document.Target; + if (pdfDocument == null) { + return; + } + FingerPrint fingerPrint = pdfDocument.GetFingerPrint(); + ICollection products = fingerPrint.GetProducts(); + //if fingerprint is disabled and all licence types isn't AGPL then no actions required + if (!fingerPrint.IsFingerPrintEnabled()) { + bool nonAGPLMode = true; + foreach (ProductData productData in products) { + ITextProductEventProcessor processor = GetActiveProcessor(productData.GetProductName()); + if (processor == null) { + continue; + } + if (AGPL_MODE.Equals(processor.GetUsageType())) { + nonAGPLMode = false; + break; + } + } + if (nonAGPLMode) { + return; + } + LOGGER.LogWarning(KernelLogMessageConstant.FINGERPRINT_DISABLED_BUT_NO_REQUIRED_LICENCE); + } + PdfWriter writer = pdfDocument.GetWriter(); + if (products.IsEmpty()) { + writer.WriteString(MessageFormatUtil.Format("%iText-{0}-no-registered-products\n", ITextCoreProductData.GetInstance + ().GetVersion())); + return; + } + foreach (ProductData productData in products) { + writer.WriteString(MessageFormatUtil.Format("%iText-{0}-{1}\n", productData.GetPublicProductName(), productData + .GetVersion())); + } + } + } +} diff --git a/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs b/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs index b7f484f675..95acea783b 100644 --- a/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs +++ b/itext/itext.kernel/itext/kernel/logs/KernelLogMessageConstant.cs @@ -94,6 +94,8 @@ public sealed class KernelLogMessageConstant { public const String DUPLICATE_ENTRIES_IN_ORDER_ARRAY_REMOVED = "Duplicated entries in order array are " + "removed"; + public const String FINGERPRINT_DISABLED_BUT_NO_REQUIRED_LICENCE = "Fingerprint disabling is only " + "available in non AGPL mode. Fingerprint will be added at the end of the document."; + private KernelLogMessageConstant() { } //Private constructor will prevent the instantiation of this class directly diff --git a/itext/itext.kernel/itext/kernel/pdf/FingerPrint.cs b/itext/itext.kernel/itext/kernel/pdf/FingerPrint.cs index 2fe36e1db1..d523054a3f 100644 --- a/itext/itext.kernel/itext/kernel/pdf/FingerPrint.cs +++ b/itext/itext.kernel/itext/kernel/pdf/FingerPrint.cs @@ -28,18 +28,34 @@ namespace iText.Kernel.Pdf { /// Data container for debugging information. /// /// Data container for debugging information. This class keeps a record of every registered product that - /// was involved in the creation of a certain PDF file. This information can then be used to log to the - /// logger or to the file. + /// was involved in the creation of a certain PDF file. /// public class FingerPrint { private ICollection productDataSet; + private bool fingerPrintEnabled = true; + /// Default constructor. /// Default constructor. Initializes the productDataSet. public FingerPrint() { this.productDataSet = new LinkedHashSet(); } + /// This method is used to disable iText fingerprint. + /// + /// This method is used to disable iText fingerprint. + /// IText fingerPrint can only be disabled if all products are in non AGPL mode. + /// + public virtual void DisableFingerPrint() { + fingerPrintEnabled = false; + } + + /// This method is used to check iText fingerprint state. + /// true if fingerprint will be added to the document + public virtual bool IsFingerPrintEnabled() { + return fingerPrintEnabled; + } + /// Registers a product to be added to the fingerprint or other debugging info. /// ProductData to be added /// true if the fingerprint did not already contain the specified element diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfXrefTable.cs b/itext/itext.kernel/itext/kernel/pdf/PdfXrefTable.cs index e4fef2114f..8efaf57f12 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfXrefTable.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfXrefTable.cs @@ -25,10 +25,10 @@ You should have received a copy of the GNU Affero General Public License using System.Text; using Microsoft.Extensions.Logging; using iText.Commons; -using iText.Commons.Actions.Data; +using iText.Commons.Actions; using iText.Commons.Utils; using iText.IO.Source; -using iText.Kernel.Actions.Data; +using iText.Kernel.Actions.Events; using iText.Kernel.Exceptions; namespace iText.Kernel.Pdf { @@ -184,28 +184,6 @@ public virtual PdfIndirectReference Get(int index) { return xref[index]; } - /// Convenience method to write the fingerprint preceding the trailer. - /// - /// Convenience method to write the fingerprint preceding the trailer. - /// The fingerprint contains information on iText products used in the generation or manipulation - /// of an outputted PDF file. - /// - /// pdfDocument to write the fingerprint to - protected internal static void WriteKeyInfo(PdfDocument document) { - PdfWriter writer = document.GetWriter(); - ICollection products = document.GetFingerPrint().GetProducts(); - if (products.IsEmpty()) { - writer.WriteString(MessageFormatUtil.Format("%iText-{0}-no-registered-products\n", ITextCoreProductData.GetInstance - ().GetVersion())); - } - else { - foreach (ProductData productData in products) { - writer.WriteString(MessageFormatUtil.Format("%iText-{0}-{1}\n", productData.GetPublicProductName(), productData - .GetVersion())); - } - } - } - /// Creates next available indirect reference. /// /// is the current @@ -400,7 +378,7 @@ protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, P writer.Write(document.GetTrailer()); writer.Write('\n'); } - WriteKeyInfo(document); + EventManager.GetInstance().OnEvent(new AddFingerPrintEvent(document)); writer.WriteString("startxref\n").WriteLong(startxref).WriteString("\n%%EOF\n"); xref = null; freeReferencesLinkedList.Clear(); diff --git a/port-hash b/port-hash index ee37ab397f..785a732783 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -d5b02fbcfb969e96fbe636524ab8f440426f99d7 +e06d553a9a845ec841f87f19bc5dc84ec652dcfc From 1febf6ac574e8fa00ef9993565aebca478a02b62 Mon Sep 17 00:00:00 2001 From: iText Software Date: Fri, 16 Aug 2024 12:11:59 +0000 Subject: [PATCH 2/2] Add missing copyright headers Autoported commit. Original commit hash: [c3c3b73f4] --- .../actions/events/AddFingerPrintEventTest.cs | 22 +++++++++++++++++++ .../actions/events/AddFingerPrintEvent.cs | 22 +++++++++++++++++++ port-hash | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs index de52b0743a..2df7ddd186 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/actions/events/AddFingerPrintEventTest.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using iText.Commons.Actions.Data; using iText.IO.Source; using iText.Kernel.Logs; diff --git a/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs b/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs index 45a43ebb19..224c7f6636 100644 --- a/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs +++ b/itext/itext.kernel/itext/kernel/actions/events/AddFingerPrintEvent.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ using System; using System.Collections.Generic; using Microsoft.Extensions.Logging; diff --git a/port-hash b/port-hash index 785a732783..5e3835c867 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -e06d553a9a845ec841f87f19bc5dc84ec652dcfc +c3c3b73f49c22e127f2047cf7b76862df3a75d75