/// <summary> /// <see cref="MS.Internal.Documents.Application.IDocumentController"/> /// </summary> /// <remarks> /// This method severely breaks encapsulating the chain, however it does /// so because the requirement breaks encapsulation and the original design /// of the class only consider streams not properties. The requirement is /// that as we transition to/from a protected document we copy properties /// between the layers. It was least risk to compromise the design here /// then extend it. /// </remarks> bool IDocumentController.SavePreperation(Document document) { // we don't have to check packageDoc for because we are only responsible // for PackageDocuments PackageDocument packageDoc = (PackageDocument)document; RightsDocument rightsDoc = document.Dependency as RightsDocument; if (rightsDoc != null) { bool isDestinationProtected = rightsDoc.IsDestinationProtected(); bool isSourceProtected = rightsDoc.IsSourceProtected(); // the only time we don't need to copy properties is when // neither source nor destination is protected as OPC properties // are copied as parts // if the source was protected and the destination is not // then we need to copy properties to the package if (isSourceProtected && !isDestinationProtected) { DocumentProperties.Copy( new SuppressedProperties(rightsDoc.SourcePackage), packageDoc.Package.PackageProperties); } // if the source was not protected and the destination is // then we need to copy properties from the package to the envelope if (!isSourceProtected && isDestinationProtected) { DocumentProperties.Copy( packageDoc.Package.PackageProperties, new SuppressedProperties(rightsDoc.DestinationPackage)); } // if they were both protected we need to copy properties // from the old envelope to the new if (isDestinationProtected && isSourceProtected) { DocumentProperties.Copy( new SuppressedProperties(rightsDoc.SourcePackage), new SuppressedProperties(rightsDoc.DestinationPackage)); } } return(true); }
/// <summary> /// <see cref="MS.Internal.Documents.Application.IDocumentController"/> /// </summary> bool IDocumentController.SavePreperation(Document document) { bool handled = false; RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Destination; Stream clear = ciphered; // We protect the actual decrypted content (if necessary) using the // RightsManagementSuppressedStream that prevents callers from writing // to it. This still allows us to save an acquired use license back to // the package even if the user does not have the permissions to modify // the document itself. It also means that there is no need to check if // the user has permission to save before starting the operation. // If we are encrypted and the destination stream is identical to the // source stream, there is no need to create a new envelope. Instead we // can simply open the envelope on the destination stream, which // already contains the complete encrypted envelope that was the source // file. // // It doesn't actually matter to this class why the flag was set, but // we know the destination is identical to the source in two situations: // 1) The source and the destination are the same file, and since the // publish license didn't change there is no need to write to a // temporary file first // 2) The destination file was copied directly from the source file. if (doc.IsDestinationProtected() && doc.IsDestinationIdenticalToSource) { // we can't reuse protections because EncryptedPackage caches the // original permissions for the stream (if we re-open the package r/w // the Encrypted package will still be r/o) doc.DestinationPackage = OpenEnvelopeOnStream( doc.Dependency.Destination); doc.DestinationPackage.RightsManagementInformation.CryptoProvider = doc.SourcePackage.RightsManagementInformation.CryptoProvider; clear = DecryptEnvelopeAndSuppressStream( doc.DestinationPackage, DocumentRightsManagementManager.Current.HasPermissionToEdit); doc.DestinationProxy = new StreamProxy(clear); // save the use license in case the user acquired one _provider.Value.SaveUseLicense(doc.DestinationPackage); handled = true; Trace.SafeWrite( Trace.Rights, "Reused CryptoProvider as underlying stream is the same."); } else // we are not protected and/or the RM protections have changed { bool canEdit = DocumentRightsManagementManager.Current.HasPermissionToEdit; // canEdit should always be true here - either the document is not // protected, or the protections have been changed. In the latter // case, the user has to have Owner permissions to change the // protections, and that of course includes Edit permissions. Invariant.Assert( canEdit, "Cannot save with changes if Edit permission was not granted."); EncryptedPackageEnvelope encryptedPackage = _provider.Value.EncryptPackage(ciphered); // the destination is intended to be encrypted when a non-null // value is returned if (encryptedPackage != null) { clear = DecryptEnvelopeAndSuppressStream( encryptedPackage, canEdit); doc.DestinationPackage = encryptedPackage; } Trace.SafeWriteIf( encryptedPackage == null, Trace.Rights, "Destination package is unprotected."); doc.DestinationProxy = new StreamProxy(clear); // If the destination file is not identical to the source file, we // need to copy the (possibly decrypted) source stream to the // destination here. if (!doc.IsDestinationIdenticalToSource) { StreamHelper.CopyStream(doc.Source, doc.Destination); doc.DestinationProxy.Flush(); Trace.SafeWrite( Trace.Rights, "Copied Source contents to Destination."); } handled = true; } return(handled); }