/* * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography.X509Certificates; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Configuration.DataFormats; using SafeExamBrowser.Configuration.Contracts; using SafeExamBrowser.Configuration.Contracts.Cryptography; using SafeExamBrowser.Configuration.Contracts.DataCompression; using SafeExamBrowser.Configuration.Contracts.DataFormats; using SafeExamBrowser.Logging.Contracts; namespace SafeExamBrowser.Configuration.UnitTests.DataFormats { [TestClass] public class BinarySerializerTests { private Mock<IDataCompressor> compressor; private Mock<ILogger> logger; private Mock<IPasswordEncryption> passwordEncryption; private Mock<IPublicKeyEncryption> publicKeyEncryption; private Mock<IPublicKeyEncryption> symmetricEncryption; private Mock<IDataSerializer> xmlSerializer; private SerializeResult xmlResult; private BinarySerializer sut; [TestInitialize] public void Initialize() { compressor = new Mock<IDataCompressor>(); logger = new Mock<ILogger>(); passwordEncryption = new Mock<IPasswordEncryption>(); publicKeyEncryption = new Mock<IPublicKeyEncryption>(); symmetricEncryption = new Mock<IPublicKeyEncryption>(); xmlResult = new SerializeResult { Data = new MemoryStream(), Status = SaveStatus.Success }; xmlSerializer = new Mock<IDataSerializer>(); compressor.Setup(c => c.Compress(It.IsAny<Stream>())).Returns(new MemoryStream()); xmlSerializer.Setup(x => x.TrySerialize(It.IsAny<IDictionary<string, object>>(), It.IsAny<EncryptionParameters>())).Returns(xmlResult); sut = new BinarySerializer(compressor.Object, logger.Object, passwordEncryption.Object, publicKeyEncryption.Object, symmetricEncryption.Object, xmlSerializer.Object); } [TestMethod] public void MustOnlySupportBinaryFormat() { var values = Enum.GetValues(typeof(FormatType)); foreach (var value in values) { if (value is FormatType format && format != FormatType.Binary) { Assert.IsFalse(sut.CanSerialize(format)); } } Assert.IsTrue(sut.CanSerialize(FormatType.Binary)); } [TestMethod] public void MustCorrectlySerializePlainDataBlock() { var data = new Dictionary<string, object>(); var result = sut.TrySerialize(data); compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2)); xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once); passwordEncryption.VerifyNoOtherCalls(); publicKeyEncryption.VerifyNoOtherCalls(); symmetricEncryption.VerifyNoOtherCalls(); Assert.AreEqual(SaveStatus.Success, result.Status); } [TestMethod] public void MustCorrectlySerializePasswordBlock() { var encrypted = new MemoryStream() as Stream; var data = new Dictionary<string, object>(); var encryption = new PasswordParameters { Password = "blubb" }; passwordEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<string>(), out encrypted)).Returns(SaveStatus.Success); var result = sut.TrySerialize(data, encryption); compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2)); passwordEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.Is<string>(s => s == encryption.Password), out encrypted), Times.Once); xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once); publicKeyEncryption.VerifyNoOtherCalls(); symmetricEncryption.VerifyNoOtherCalls(); Assert.AreEqual(SaveStatus.Success, result.Status); } [TestMethod] public void MustCorrectlySerializePublicKeyBlock() { var encrypted = new MemoryStream() as Stream; var data = new Dictionary<string, object>(); var encryption = new PublicKeyParameters { InnerEncryption = new PasswordParameters { Password = "test" }, SymmetricEncryption = false }; passwordEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<string>(), out encrypted)).Returns(SaveStatus.Success); publicKeyEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted)).Returns(SaveStatus.Success); var result = sut.TrySerialize(data, encryption); compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2)); passwordEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.Is<string>(s => s == encryption.InnerEncryption.Password), out encrypted), Times.Once); publicKeyEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted), Times.Once); xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once); symmetricEncryption.VerifyNoOtherCalls(); Assert.AreEqual(SaveStatus.Success, result.Status); } [TestMethod] public void MustCorrectlySerializePublicKeySymmetricBlock() { var encrypted = new MemoryStream() as Stream; var data = new Dictionary<string, object>(); var encryption = new PublicKeyParameters { SymmetricEncryption = true }; symmetricEncryption.Setup(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted)).Returns(SaveStatus.Success); var result = sut.TrySerialize(data, encryption); compressor.Verify(c => c.Compress(It.IsAny<Stream>()), Times.Exactly(2)); symmetricEncryption.Verify(p => p.Encrypt(It.IsAny<Stream>(), It.IsAny<X509Certificate2>(), out encrypted), Times.Once); xmlSerializer.Verify(x => x.TrySerialize(It.Is<IDictionary<string, object>>(d => d == data), It.Is<EncryptionParameters>(e => e == null)), Times.Once); passwordEncryption.VerifyNoOtherCalls(); publicKeyEncryption.VerifyNoOtherCalls(); Assert.AreEqual(SaveStatus.Success, result.Status); } } }