💡 Plně funkční příklad je k dispozici na GitHubu:
compare-encrypted-pdf-and-word-documents-dotnet

Starý způsob byl bolestivý

Dvě revize smlouvy o dodávkách přistály ve vaší schránce. Obě jsou chráněny heslem, každá s jiným heslem, a někdo potřebuje označenou kopii, která ukazuje, co se změnilo. Knihovna pro porovnání, kterou máte, očekává vstup v prostém textu, takže do pipeline se přidá krok: dešifrovat oba soubory do dočasné složky, porovnat prosté kopie a pak nezapomenout je smazat. Tato dočasná složka se tak stane nejslabším článkem pracovního postupu, který existuje právě proto, že dokumenty jsou citlivé.

Existuje druhá verze stejného problému, kterou je snadnější přehlédnout. Některé týmy vynechají dočasnou složku a dešifrují do paměti, což řeší otázku úklidu, ale ne otázku formátu: API pro dešifrování se liší podle formátu, takže podpora šifrovaných tabulek po šifrovaných PDF znamená druhou integraci místo druhého řádku kódu.

Náklady nejsou hlavně v samotném volání dešifrování – jsou v tom, co je kolem něj. Kopie v prostém textu je třeba někam zapsat, vyčistit na každé cestě odchodu včetně těch neúspěšných a udržet mimo zálohy a výpisy pádů. Diff vytvořený tímto způsobem také přichází ve výchozím nastavení nechráněný, takže výstup ze dvou šifrovaných vstupů se stane jediným souborem v řetězci, který může kdokoli otevřít.

Skutečná cena objížďky dešifrování: dočasný adresář obsahující kopie dokumentů v prostém textu, které byly šifrovány z důvodu, s úklidem, který musí být správný na každé chybové cestě.

Existuje lepší způsob

Porovnání chráněné heslem je schopnost GroupDocs.Comparison pro .NET, která otevírá šifrované PDF, DOCX, XLSX a PPTX soubory přímo a rozhoduje, jaké heslo chrání výsledek porovnání. Žádný krok dešifrování, žádné mezilehlé prosté soubory: heslo cestuje s dokumentem do samotného porovnání jako vlastnost LoadOptions.

Než začneme, budete potřebovat:

  • .NET 8.0 SDK nebo novější
  • GroupDocs.Comparison 26.9.0 (dočasná licence)
  • Dva šifrované dokumenty stejného formátu a jejich hesla

Instalace jedním příkazem:

dotnet add package GroupDocs.Comparison

Nový způsob: Šifrované dokumenty přímo do porovnávače

Níže uvedený příklad porovnává dva šifrované PDF – zdroj se otevírá s 1234, cíl s 4321 – a zapíše jeden výstupní soubor se změnami sloučenými inline. Úmyslně různé hesla, protože právě tam se skrývá první chyba.

Krok 1 – Dejte každému dokumentu vlastní LoadOptions

Comparer drží jeden zdroj a libovolný počet cílů, a každý dokument nese svou vlastní ochranu. Heslo zdroje jde do konstruktoru; heslo každého cíle jde do jeho vlastního volání Add.

// Jeden LoadOptions na dokument – možnosti v konstruktoru odemknou
// jen zdroj a nikdy nedosáhnou na cíle.
using var comparer = new Comparer("source.pdf",
    new LoadOptions { Password = "1234" });
comparer.Add("target.pdf", new LoadOptions { Password = "4321" });

To je detail, který lidi nachytá. Předání jediného LoadOptions do konstruktoru a očekávání, že pokryje i cíle, je nejčastější způsob, jak to selže, a protože selhání nastává až později, neoznámí se vám, kde se podívat.

Krok 2 – Rozhodněte, co chrání výsledek

CompareOptions.PasswordSaveOption volí ochranu výstupu: None, Source, Target nebo User. Výchozí je None, což tiše převádí dva šifrované vstupy na jeden nechráněný výsledek.

// Inline označení a výsledek znovu použije heslo zdrojového dokumentu.
var options = new PdfCompareOptions
{
    DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
    PasswordSaveOption = PasswordSaveOption.Source
};

comparer.Compare("Result/1-pdf-inline.pdf", options);

Klíčové body:

  • PasswordSaveOption: Source znovu použije heslo zdroje na výstupu. Zvolte User s SaveOptions.Password, pokud chcete místo toho zadat nové heslo.
  • ComparisonDisplayMode: vnořeno v PdfCompareOptions, které také nabízí SideBySide a Interleaved. WordCompareOptions deklaruje vlastní výčtový typ se stejným názvem, ale s jinými hodnotami, takže samotný název se neshoduje – použijte plně kvalifikovaný název.

Krok 3 – Chraňte výstup vlastním heslem

Když diff putuje ke kontrolorům, kteří by neměli mít žádné z původních hesel, PasswordSaveOption.User vezme hodnotu z SaveOptions.Password místo opětovného použití vstupního hesla.

var compareOptions = new PdfCompareOptions
{
    DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
    PasswordSaveOption = PasswordSaveOption.User
};
var saveOptions = new SaveOptions { Password = "5678" };

comparer.Compare("Result/4-own-password.pdf", saveOptions, compareOptions);

Oba objekty jsou předány do tříargumentové přetížené metody Compare. Nastavení SaveOptions.Password samo o sobě nic nemění – aktivuje se až výčtová hodnota PasswordSaveOption. Výsledek tohoto volání se otevře s 5678 a odmítne 1234.

Proč můj try/catch kolem Compareru nechycuje špatné heslo?

Protože konstruktor nikdy neotevírá dokument. Pouze zaznamená cestu, a to samé dělá Add. Oba dokumenty jsou načteny až při volání Compare, a právě tam je vyhozena výjimka PasswordProtectedFileException s hláškou Password is missing. Špatné heslo se chová identicky: při konstrukci je tiše přijato a později při Compare odmítnuto.

Proto chraňte volání Compare, ne konstruktor. Našel jsem to pomalu, zabalením konstrukce do try a sledováním, jak šifrovaný soubor projde až do selhání o tři řádky později. Úložiště vypisuje každou fázi, což dělá pořadí zřejmým při první čtení:

using var comparer = new Comparer("source.pdf");   // úspěch
comparer.Add("target.pdf");                        // úspěch
comparer.Compare("Result/unreachable.pdf");        // zde vyhodí výjimku

Vedle‑vedle: Před vs. Po

Před (nejprve dešifrovat) Po (GroupDocs.Comparison)
Kroky pipeline Dešifrovat oba, porovnat, smazat dočasné kopie Porovnat
Prostý text na disku Dvě kopie, úklid na každé chybové cestě Žádné
Ochrana výsledku Samostatný krok přešifrování Jedna hodnota PasswordSaveOption
Podpora formátů Nástroje pro dešifrování podle formátu Jedno LoadOptions.Password pro PDF, DOCX, XLSX, PPTX
Požadovaný kód Pomocná funkce pro dešifrování + porovnání 4 řádky

Funkce porovnání se na šifrovaném vstupu nemění. Zobrazovací režimy, souhrnné stránky a detekce stylu se chovají přesně jako u prostých souborů, protože ochrana je řešena výhradně ve vrstvě načítání.

Toto vrstvení je to, co dělá podporu formátů levnou. LoadOptions.Password je prostá vlastnost typu string a stejná vlastnost odemyká PDF, DOCX, XLSX i PPTX – kód načítání v příkladu pro Word níže je znak po znaku stejný jako ten v příkladech pro PDF. Mění se jen třída možností a to jen proto, že každý formát nabízí jiné možnosti renderování. Přidání podpory šifrovaných tabulek do kódu, který už porovnává šifrované PDF, nic v načítací cestě nestojí.

Reálný příklad: Revize smluv mezi právnickými firmami

Právní tým dostává každou revizi smlouvy šifrovanou, přičemž heslo se mění při každé výměně, aby uniklé heslo neodhalilo celou historii. Kontrolní partner potřebuje jeden označený dokument na kolo a podle pravidel archivace nesmí označená kopie ležet nechráněně na sdíleném úložišti.

Dvě nastavení to pokrývají. Každý dokument je odemčen svým vlastním LoadOptions, takže rotace hesel nevyžaduje žádnou speciální logiku, a PasswordSaveOption.User dává každému distribuovanému diffu vlastní heslo – takové, které odemkne porovnání a nic víc.

// Revize Wordu, aby kontrolní partner mohl přijmout nebo odmítnout každou úpravu.
var options = new WordCompareOptions
{
    DisplayMode = WordCompareOptions.ComparisonDisplayMode.Revisions,
    PasswordSaveOption = PasswordSaveOption.Source
};

using var comparer = new Comparer("round3.docx",
    new LoadOptions { Password = "1234" });
comparer.Add("round4.docx", new LoadOptions { Password = "4321" });
comparer.Compare("Result/redline.docx", options);

Co dalšího můžete dělat s GroupDocs.Comparison?

  • Porovnat více než dva chráněné dokumenty: přidejte několik šifrovaných cílů do jednoho porovnání, pro formáty Word i prezentace.
  • Vytvořit nativní revize Wordu: WordCompareOptions.ComparisonDisplayMode.Revisions zapisuje změny, které recenzent může v Wordu přijmout nebo odmítnout.
  • Řídit načítání externích zdrojů: blokovat nebo povolit vzdálené odkazy, které dokument obsahuje, další ochrana pomocí LoadOptions.
  • Generovat souhrnnou stránku: GenerateSummaryPage přidá přehled změn do výstupního dokumentu.

Závěr

Objížďka dešifrování nebyla nikdy o samotném porovnání – šlo o knihovnu, která nedokázala přečíst to, co jste měli. Nastavení LoadOptions.Password pro každý dokument odstraňuje dočasnou složku, cesty úklidu i nechráněný diff na konci řetězce. Zbývají jen tři rozhodnutí: heslo pro každý dokument, explicitní PasswordSaveOption místo výchozího None a ošetření chyb kolem Compare, kde selhání skutečně nastává.

Připraven(a) automatizovat svůj dokumentový workflow?

Další zdroje