/// <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);
        }
Beispiel #3
0
        /// <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);
        }