Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Modules/CommonsLib/Sources/CommonsLib/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public struct Constants {
public static let SignatureContainers = [Asice, Asics, Ddoc, Bdoc, Adoc]
public static let SivaContainers = [Ddoc, Asics]
public static let UnsignableContainers = [Adoc, Ddoc, Asics]
public static let UnencryptableContainers = [Ddoc, Asics]

public static let Pdf = "application/pdf"

Expand Down Expand Up @@ -77,6 +78,7 @@ public struct Constants {
public static let CryptoContainers = [Cdoc, Cdoc2]

public static let UnsignableContainerExtensions = [Adoc, Ddoc] + AsicsContainers
public static let UnencryptableContainerExtensions = [Ddoc] + AsicsContainers
}

public struct Identifier {
Expand Down
5 changes: 3 additions & 2 deletions RIADigiDoc/Domain/Service/Siva/SivaService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ actor SivaService: SivaServiceProtocol {

guard let file = files.first else { return false }

let mimetype = await mimeTypeResolver.mimeType(url: file)
let mimetype = await mimeTypeResolver.mimeType(url: file).lowercased()

let isCades = await file.isCades(fileUtil: fileUtil)
let isXades = await file.isXades(fileUtil: fileUtil)
Expand All @@ -65,7 +65,8 @@ actor SivaService: SivaServiceProtocol {

func isTimestampedContainer(signedContainer: SignedContainerProtocol) async -> Bool {
let isOneDataFileInContainer = await signedContainer.getDataFiles().count == 1
let isAsicsMimeType = await signedContainer.getContainerMimetype() == Constants.MimeType.Asics
let isAsicsMimeType = await signedContainer.getContainerMimetype()
.lowercased() == Constants.MimeType.Asics
let isTimeStampTokenSignatureMethod = await signedContainer.getSignatures().first?.format == "TimeStampToken"

return isOneDataFileInContainer &&
Expand Down
18 changes: 5 additions & 13 deletions RIADigiDoc/UI/Component/Container/Signing/SigningView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ struct SigningView: View {

@State private var showingShareSheet = false
@State private var isSignButtonShown = false
@State private var isEncryptButtonShown = false
@State private var selectedDataFile: DataFileWrapper?

@State private var showSivaMessage = false
Expand Down Expand Up @@ -208,10 +207,10 @@ struct SigningView: View {
isEditContainerButtonShown: !isContainerSigned && !isNestedContainer,
isSaveButtonShown: true,
isSignButtonShown: false,
isEncryptButtonShown: !isContainerSigned && !isNestedContainer,
isEncryptButtonShown: !isContainerSigned && viewModel.canEncrypt,
isExtendSignaturesButtonShown: isExtendSignaturesButtonShown,
showLeftActionButton: isContainerSigned && isSignButtonShown,
showRightActionButton: isContainerSigned && !isNestedContainer,
showRightActionButton: isContainerSigned && viewModel.canEncrypt,
leftActionButtonName: languageSettings.localized("Add signature"),
rightActionButtonName: encryptLabel,
leftActionButtonAccessibilityLabel: signAccessibilityLabel.lowercased(),
Expand Down Expand Up @@ -267,7 +266,7 @@ struct SigningView: View {
)
.onChange(of: viewModel.isNestedContainer()) {
Task {
await updateSignAndEncryptButtonVisibility()
await updateSignButtonVisibility()
}
}

Expand Down Expand Up @@ -419,7 +418,7 @@ struct SigningView: View {
signedContainer: viewModel.signedContainer
)

await updateSignAndEncryptButtonVisibility()
await updateSignButtonVisibility()
}
}
.onDisappear {
Expand Down Expand Up @@ -565,22 +564,15 @@ struct SigningView: View {
}
}

private func updateSignAndEncryptButtonVisibility() async {
private func updateSignButtonVisibility() async {
let shouldShowSignButton = await viewModel
.isSignButtonShown(
signedContainer: viewModel.signedContainer,
isNestedContainer: isNestedContainer
)

let shouldShowEncryptButton = await viewModel
.isEncryptButtonShown(
signedContainer: viewModel.signedContainer,
isNestedContainer: isNestedContainer
)

await MainActor.run {
isSignButtonShown = shouldShowSignButton
isEncryptButtonShown = shouldShowEncryptButton
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public protocol SigningViewModelProtocol: Sendable {
func isNestedContainer() -> Bool
func isSivaConfirmationNeeded(dataFile: DataFileWrapper) async -> Bool
func isSignButtonShown(signedContainer: SignedContainerProtocol?, isNestedContainer: Bool) async -> Bool
func isEncryptButtonShown(signedContainer: SignedContainerProtocol?, isNestedContainer: Bool) async -> Bool
func isSignatureRemoveButtonShown() -> Bool
var isEncryptableContainer: Bool { get }
var canEncrypt: Bool { get }
func isTimestampedContainer() async -> Bool
func getContainerNotifications(container: SignedContainerProtocol) async -> [ContainerNotificationType]
func removeSignature(_ signature: SignatureWrapper) async
Expand Down
33 changes: 19 additions & 14 deletions RIADigiDoc/ViewModel/SigningViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,18 @@ class SigningViewModel: SigningViewModelProtocol, Loggable {

self.signedContainer = openedContainer

self.containerName = await openedContainer.getContainerName()
let name = await openedContainer.getContainerName()
let mimetype = await openedContainer.getContainerMimetype()

self.containerName = name
self.dataFiles = await openedContainer.getDataFiles()
self.signatures = await openedContainer.getSignatures()
self.timestamps = await openedContainer.getTimestamps()
self.containerMimetype = await openedContainer.getContainerMimetype()
self.containerMimetype = mimetype
self.containerURL = await openedContainer.getRawContainerFile()
self.isTimestampedContainer = await isTimestampedContainer()
self.isCadesContainer = await openedContainer.isCades()
self.isXadesContainer = await openedContainer.isXades()

self.containerNotifications = await getContainerNotifications(container: openedContainer)

SigningViewModel.logger().info("Signed container data loaded")
Expand Down Expand Up @@ -466,6 +468,17 @@ class SigningViewModel: SigningViewModelProtocol, Loggable {
}
}

var isEncryptableContainer: Bool {
guard signedContainer != nil else { return false }
return !Constants.MimeType.UnencryptableContainers.contains(containerMimetype.lowercased()) &&
!Constants.Extension.UnencryptableContainerExtensions
.contains((containerName as NSString).pathExtension.lowercased())
}

var canEncrypt: Bool {
!isNestedContainer() && isEncryptableContainer
}

func isNestedContainer() -> Bool {
return sharedContainerViewModel.isNestedContainer(
sharedContainerViewModel.currentContainer()
Expand Down Expand Up @@ -498,20 +511,12 @@ class SigningViewModel: SigningViewModelProtocol, Loggable {
let isEmptyFileInContainer = await signedContainer?.isEmptyFileInContainer() ?? false

return signedContainer != nil &&
(!Constants.MimeType.UnsignableContainers.contains(mimetype)) &&
(!Constants.Extension.UnsignableContainerExtensions.contains((name as NSString).pathExtension)) &&
(!Constants.MimeType.UnsignableContainers.contains(mimetype.lowercased())) &&
(!Constants.Extension.UnsignableContainerExtensions
.contains((name as NSString).pathExtension.lowercased())) &&
!isNestedContainer && !isEmptyFileInContainer && !isCadesContainer && !isXadesContainer
}

func isEncryptButtonShown(
signedContainer: SignedContainerProtocol?,
isNestedContainer: Bool,
) async -> Bool {
guard let container = signedContainer else { return false }
let isExistingContainer = await container.isExistingContainer()
return (isExistingContainer || isSigned()) && !isNestedContainer
}

func isSignatureRemoveButtonShown() -> Bool {
return !isNestedContainer() && !isCadesContainer && !isXadesContainer
}
Expand Down
49 changes: 49 additions & 0 deletions RIADigiDocTests/Domain/Service/Siva/SivaServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,39 @@ struct SivaServiceTests {
#expect(isSivaConfirmationNeeded)
}

@Test
func isSivaConfirmationNeeded_returnTrueForUppercaseAsicsMimetypeWrappingDdoc() async throws {
let wrappedDdoc = URL(fileURLWithPath: "/mock/path/wrapped.ddoc")
let mockContainer = try TestContainerUtil.createMockContainer(
with: [wrappedDdoc.lastPathComponent: "Test content"],
containerExtension: "asics")
defer { try? FileManager.default.removeItem(at: mockContainer) }

mockMimetypeResolver.mimeTypeHandler = { _ in Constants.MimeType.Asics.uppercased() }
mockFileUtil.getFileFromZipFileHandler = { _, name in
name.contains(".ddoc") ? wrappedDdoc : nil
}

let isSivaConfirmationNeeded = await service.isSivaConfirmationNeeded(files: [mockContainer])

#expect(isSivaConfirmationNeeded)
}

@Test
func isSivaConfirmationNeeded_returnTrueForUppercaseDdocMimetype() async throws {
let mockContainer = try TestContainerUtil.createMockContainer(
with: ["content.txt": "Test content"],
containerExtension: "ddoc")
defer { try? FileManager.default.removeItem(at: mockContainer) }

mockMimetypeResolver.mimeTypeHandler = { _ in Constants.MimeType.Ddoc.uppercased() }
mockFileUtil.getFileFromZipFileHandler = { _, _ in nil }

let isSivaConfirmationNeeded = await service.isSivaConfirmationNeeded(files: [mockContainer])

#expect(isSivaConfirmationNeeded)
}

@Test
func isSivaConfirmationNeeded_returnFalseForAsicsWrappingBdoc() async throws {
let mockContainer = try TestContainerUtil.createMockContainer(
Expand Down Expand Up @@ -130,6 +163,22 @@ struct SivaServiceTests {
#expect(mockSignedContainer.getSignaturesCallCount == 1)
}

@Test
func isTimestampedContainer_returnTrueWithUppercaseAsicsMimetype() async {
let mockSignedContainer = SignedContainerProtocolMock()
mockSignedContainer.getDataFilesHandler = {[
MockDataFileWrapper.mockDataFileWrapper()
]}
mockSignedContainer.getContainerMimetypeHandler = { Constants.MimeType.Asics.uppercased() }
mockSignedContainer.getSignaturesHandler = {[
MockSignatureWrapper.mockSignatureWrapper(format: "TimeStampToken")
]}

let isTimestampedContainer = await service.isTimestampedContainer(signedContainer: mockSignedContainer)

#expect(isTimestampedContainer)
}

@Test
func isTimestampedContainer_returnFalseWithMultipleDataFiles() async {
let mockSignedContainer = SignedContainerProtocolMock()
Expand Down
Loading
Loading