/// <summary> /// <see cref="MS.Internal.Documents.Application.IDocumentController"/> /// </summary> bool IDocumentController.Rebind(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Source; Stream clear = ciphered; if (doc.IsRebindNeeded) { if (doc.SourcePackage != null) { CloseEnvelope(doc.SourcePackage); doc.SourcePackage = null; } EncryptedPackageEnvelope envelope = null; PackageProperties properties = null; bool isSourceProtected = doc.IsSourceProtected(); if (isSourceProtected) { envelope = OpenEnvelopeOnStream(ciphered); doc.SourcePackage = envelope; properties = new SuppressedProperties(envelope); } DocumentProperties.Current.SetRightsManagedProperties(properties); DocumentRightsManagementManager.Current.SetEncryptedPackage(envelope); if (isSourceProtected) { clear = DocumentRightsManagementManager.Current.DecryptPackage(); if (clear != null) { clear = new RightsManagementSuppressedStream( clear, DocumentRightsManagementManager.Current.HasPermissionToEdit); // Reset the position of the stream since GetPackageStream will // create a package and move the stream pointer somewhere else clear.Position = 0; } else { Trace.SafeWrite( Trace.Rights, "You do not have rights for the current document."); return(false); } } doc.SourceProxy.Target = clear; } return(true); }
/// <summary> /// <see cref="MS.Internal.Documents.Application.IDocumentController"/> /// </summary> bool IDocumentController.SaveCommit(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok if (doc.DestinationPackage != null) { CloseEnvelope(doc.DestinationPackage); doc.DestinationPackage = null; Trace.SafeWrite(Trace.File, "Destination EncryptedPackageEnvelope closed."); } return(true); }
/// <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); }
//-------------------------------------------------------------------------- // IDocumentController Members //-------------------------------------------------------------------------- /// <summary> /// <see cref="MS.Internal.Documents.Application.IDocumentController"/> /// </summary> bool IDocumentController.EnableEdit(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Workspace; Stream clear = ciphered; bool canEdit = DocumentRightsManagementManager.Current.HasPermissionToEdit; EncryptedPackageEnvelope encryptedPackage = null; // If editing the document is allowed (i.e. the document is either // not RM protected, or the user has permission to edit it), create // a temporary editing file if (canEdit) { try { encryptedPackage = _provider.Value.EncryptPackage(ciphered); if (encryptedPackage != null) { clear = DecryptEnvelopeAndSuppressStream( encryptedPackage, canEdit); doc.WorkspacePackage = encryptedPackage; } } catch (RightsManagementException exception) { RightsManagementErrorHandler.HandleOrRethrowException( RightsManagementOperation.Other, exception); // Bail out return(true); } if (encryptedPackage != null) { Trace.SafeWrite( Trace.Rights, "Editing package is RM protected."); } else { Trace.SafeWrite( Trace.Rights, "Editing package is unprotected."); } doc.WorkspaceProxy = new StreamProxy(clear); } else { Trace.SafeWrite( Trace.Rights, "Did not create editing package because user does not have permission to edit."); } return(canEdit); }
/// <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); }
/// <summary> /// <see cref="MS.Internal.Documents.Application.IDocumentController"/> /// </summary> bool IDocumentController.Open(Document document) { RightsDocument doc = (RightsDocument)document; // see class remarks on why this is ok Stream ciphered = doc.Dependency.Source; Stream clear = ciphered; bool isSourceProtected = doc.IsSourceProtected(); if (isSourceProtected) { // Do not catch exceptions here - there can be no mitigation EncryptedPackageEnvelope envelope = OpenEnvelopeOnStream(ciphered); PackageProperties properties = new SuppressedProperties(envelope); doc.SourcePackage = envelope; DocumentProperties.Current.SetRightsManagedProperties(properties); } RightsManagementProvider provider = new RightsManagementProvider(doc.SourcePackage); _provider.Value = provider; try { DocumentRightsManagementManager.Initialize(provider); DocumentRightsManagementManager.Current.PublishLicenseChange += new EventHandler(delegate(object sender, EventArgs args) { Trace.SafeWrite( Trace.Rights, "Disabling file copy for current document."); doc.IsFileCopySafe = false; DocumentManager.CreateDefault().EnableEdit(null); }); if (isSourceProtected) { clear = DocumentRightsManagementManager.Current.DecryptPackage(); if (clear != null) { clear = new RightsManagementSuppressedStream( clear, DocumentRightsManagementManager.Current.HasPermissionToEdit); // Reset the position of the stream since GetPackageStream will // create a package and move the stream pointer somewhere else clear.Position = 0; } else { Trace.SafeWrite( Trace.Rights, "You do not have rights for the current document."); return(false); } } } catch { // If anything failed here, we cannot use the provider any longer, // so we can dispose it provider.Dispose(); _provider.Value = null; throw; } if (clear != null) { doc.SourceProxy = new StreamProxy(clear); } else { // If decryption failed, we can no longer do anything with the // provider instance or the current RM manager provider.Dispose(); _provider.Value = null; } return(true); }