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: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
mkdir -p $TSL_FILES_DIRECTORY

# SPM packages must exist and need at least 1 file. Mock files are generated in 'Run tests' step
for module in CommonsLib ConfigLib CryptoLib IdCardLib LibdigidocLib MobileIdLib SmartIdLib UtilsLib; do
for module in CommonsLib ConfigLib WebEidLib CryptoLib IdCardLib LibdigidocLib MobileIdLib SmartIdLib UtilsLib; do
mock_dir="Modules/${module}/Tests/Mocks/Generated"
mkdir -p "$mock_dir"
echo "// Placeholder for generated mocks" > "${mock_dir}/__placeholder.swift"
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ xcuserdata
buildServer.json
RIADigiDoc/Supporting files/GoogleService-Info.plist

#AASA
apple-app-site-association
# AASA
apple-app-site-association
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2017 - 2026 Riigi Infosüsteemi Amet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

import CryptoObjCWrapper

public struct OpenLdapSearchResult: Sendable {
public var addressees: [Addressee]
public var tooManyResults: Bool
}
20 changes: 13 additions & 7 deletions Modules/CryptoLib/Sources/CryptoSwift/Ldap/OpenLdap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,7 @@ final public class OpenLdap: OpenLdapProtocol, Loggable {
}
}

@MainActor public func search(identityCode: String) async -> (
addressees: [Addressee],
tooManyResults: Bool
) {
@MainActor public func search(identityCode: String) async -> OpenLdapSearchResult {
var filePath: String?
if let ldapCertFilePath = await self.ldapConfiguration.ldapCertsPath() {
if fileManager.fileExists(atPath: ldapCertFilePath) {
Expand Down Expand Up @@ -114,7 +111,10 @@ final public class OpenLdap: OpenLdapProtocol, Loggable {
tooManyResults = true
}
}
return (result, tooManyResults)
return OpenLdapSearchResult(
addressees: result,
tooManyResults: tooManyResults
)
} else {
if let ldapCorpURL = await self.ldapConfiguration.getLdapCorpURL() {
OpenLdap.logger().info("Searching with corporation keyword from LDAP")
Expand All @@ -123,9 +123,15 @@ final public class OpenLdap: OpenLdapProtocol, Loggable {
url: ldapCorpURL,
certificatePath: filePath
)
return (addresses, found >= 50)
return OpenLdapSearchResult(
addressees: addresses,
tooManyResults: found >= 50
)
} else {
return ([], false)
return OpenLdapSearchResult(
addressees: [],
tooManyResults: false
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,5 @@ import CryptoObjCWrapper

/// @mockable
public protocol OpenLdapProtocol: Sendable {
@MainActor func search(identityCode: String) async -> (
addressees: [Addressee],
tooManyResults: Bool
)
@MainActor func search(identityCode: String) async -> OpenLdapSearchResult
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@ public class TestCertificateUtil {

public init() {}

public static func getSampleCertificate() -> Data {
// swiftlint:disable line_length
let cert = """
// swiftlint:disable line_length
private static let cert = """
MIIEwjCCA6qgAwIBAgIUeYCoFyEHBfraNnsp4BCgKyVYfywwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAkVFMRIwEAYDVQQIDAlUZXN0U3RhdGUxETAPBgNVBAcMCFRlc3RDaXR5MRkwFwYDVQQKDBBUZXN0T3JnYW5pemF0aW9uMSMwIQYDVQQLDBpUZXN0T3JnYW5pemF0aW9uYWxVbml0TmFtZTEXMBUGA1UEAwwOVGVzdENvbW1vbk5hbWUxIzAhBgkqhkiG9w0BCQEWFHRlc3RAZW1haWwudGVzdGVtYWlsMB4XDTI1MDEzMTE3MDIxMloXDTI3MDUwNjE3MDIxMlowgcwxCzAJBgNVBAYTAkVFMRUwEwYDVQQIDAxTdWJqZWN0U3RhdGUxFDASBgNVBAcMC1N1YmplY3RDaXR5MSAwHgYDVQQKDBdTdWJqZWN0T3JnYW5pemF0aW9uTmFtZTEmMCQGA1UECwwdU3ViamVjdE9yZ2FuaXphdGlvbmFsVW5pdE5hbWUxGjAYBgNVBAMMEVN1YmplY3RDb21tb25OYW1lMSowKAYJKoZIhvcNAQkBFht0ZXN0c3ViamVjdEBlbWFpbC50ZXN0ZW1haWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjOB/5LMTY7HaIDQtPI0rNszyO1GwNepf2Ol6XayOJOP3V8Y3bC3pcUobnlfXfphTqoNznYKLuV2Tz9bzALI1HCK9TsiAFA9DAJqEII+BhhK0Ei5LlaHwOSHWPBt5Tn8SYvPt37hcIz/fQrRR7Ezbxj8ukW6NV7LMcVr2rsRRFnvPNCkeEjGy7mpzJP2U7Ya4yiBaQpodlcLlYws9QnMrwwnPV5NpPTJ+ko6WwKKeqcuxOUkH1j3lJb5MdNaUtLjHVW++EpeYGRn9Ibz1xda9MgBFT4JMGhgjLx7CYUWt+DD4kcL5N5dpDGs52eRzG/tnOck3zrWHlO3Vf6QWrDX6zAgMBAAGjgbMwgbAwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwQQYDVR0RBDowOIIYc3ViamVjdC50ZXN0c3ViamVjdC50ZXN0ghx3d3cuc3ViamVjdC50ZXN0c3ViamVjdC50ZXN0MB0GA1UdDgQWBBTWjQtDdX0TrwKP/Tzgtp5x9fKXYjAfBgNVHSMEGDAWgBRxc4NGP1MWIHuIeGrjDN3udJThpzANBgkqhkiG9w0BAQsFAAOCAQEAcK2rdOzhWo6mnlYTjgbZdyCk1nKs4/jvmbx4MfTy/tKMq+OImEvC8TUg2myUzxL284p0WCCVWoALo2hwsYeYLSblfnDAsj90RMZQlDyA7rIEqrfXugqamj+hPLwPoEyZKipTkImT0mAGqakE63BkiP+SSEwveZ8YUr0XG369gHyaP8zv6XTqDkQYHx7kJQCHI87+wN+3XPIiYN5sqrf0Z147w/LO8a+XkOCD5JvTbAZB6sLI9dCvoeifd34l9JhDnlnb4SjnszC2k5gx78CNM1pF9jATS3A7mdz+TyttG4ks/i5/Mor416foXurIEh1oZTKOoxppMowq73c66rrH1g==
"""
// swiftlint:enable line_length
// swiftlint:enable line_length

public static func getSampleCertificate() -> Data {
return Data(base64Encoded: cert) ?? Data()
}

public static func getSampleCertificateString() -> String {
return cert
}

public static func getSampleCertificateWithHeaders() -> Data? {
let certString = """
-----BEGIN CERTIFICATE-----
Expand Down
2 changes: 1 addition & 1 deletion Modules/UtilsLib/Sources/UtilsLib/System/SystemUtil.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public struct SystemUtil: Loggable {
var systemInfo = utsname()
uname(&systemInfo)
let identifier = withUnsafeBytes(of: &systemInfo.machine) { raw in
String(cString: raw.bindMemory(to: CChar.self).baseAddress!)
String(bytes: raw.prefix { $0 != 0 }, encoding: .utf8) ?? ""
}
return identifier.lowercased()
}
Expand Down
60 changes: 60 additions & 0 deletions Modules/WebEidLib/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// swift-tools-version: 6.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "WebEidLib",
platforms: [.iOS(.v18)],
products: [
.library(
name: "WebEidLib",
targets: ["WebEidLib"]
),
.library(name: "WebEidLibMocks", targets: ["WebEidLibMocks"])
],
dependencies: [
.package(url: "https://github.com/filom/ASN1Decoder", exact: .init(1, 10, 0)),
.package(url: "https://github.com/hmlongco/Factory", exact: .init(3, 3, 2)),
.package(url: "https://github.com/Alamofire/Alamofire.git", exact: .init(5, 12, 0)),
.package(path: "../UtilsLib"),
.package(path: "../CommonsLib"),
.package(path: "../Test/CommonsTestShared")
],
targets: [
.target(
name: "WebEidLib",
dependencies: [
"Alamofire",
"ASN1Decoder",
"UtilsLib",
"CommonsLib",
.product(name: "FactoryKit", package: "Factory")
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency"),
.enableUpcomingFeature("SendableByDefault"),
.enableUpcomingFeature("NonisolatedNonsendingByDefault"),
.enableUpcomingFeature("InferIsolatedConformances")
]
),
.target(
name: "WebEidLibMocks",
dependencies: ["WebEidLib"],
path: "Tests/Mocks/Generated"
),
.testTarget(
name: "WebEidLibTests",
dependencies: [
"WebEidLib",
"WebEidLibMocks",
"UtilsLib",
"CommonsLib",
"CommonsTestShared",
.product(name: "UtilsLibMocks", package: "utilslib"),
.product(name: "CommonsLibMocks", package: "commonslib"),
.product(name: "FactoryTesting", package: "Factory")
]
)
]
)
35 changes: 35 additions & 0 deletions Modules/WebEidLib/Sources/WebEidLib/DI/WebEidLibContainer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2017 - 2026 Riigi Infosüsteemi Amet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

import Foundation
import FactoryKit

extension Container {
public var webEidAuthService: Factory<WebEidAuthServiceProtocol> {
self {
WebEidAuthService()
}
}

public var webEidSignService: Factory<WebEidSignServiceProtocol> {
self {
WebEidSignService()
}
}
}
87 changes: 87 additions & 0 deletions Modules/WebEidLib/Sources/WebEidLib/Error/WebEidError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2017 - 2026 Riigi Infosüsteemi Amet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

import Foundation
// swiftlint:disable identifier_name
public enum WebEidErrorCode: String, Codable, Sendable {
case ERR_WEBEID_MOBILE_INVALID_REQUEST
case ERR_WEBEID_MOBILE_UNKNOWN_ERROR
case ERR_WEBEID_USER_CANCELLED
}
// swiftlint:enable identifier_name
public struct WebEidException: Error, LocalizedError, Sendable {
public let code: WebEidErrorCode
public let message: String
public let responseUri: String

public var errorDescription: String? {
"\(code.rawValue): \(message) (responseUri: \(responseUri))"
}
}

enum WebEidBuilderError: Error, LocalizedError, Sendable {
case invalidCertificate
case missingPublicKey
case invalidJSON
case invalidBase64

var errorDescription: String? {
switch self {
case .invalidCertificate: return "Invalid X.509 certificate"
case .missingPublicKey: return "Certificate public key is missing"
case .invalidJSON: return "Failed to serialize auth token JSON"
case .invalidBase64: return "Invalid Base64"
}
}
}

enum WebEidAlgorithmUtilError: Error, LocalizedError, Sendable, Equatable {
case unsupportedKeyType
case unsupportedECKeyLength(Int)
case invalidBase64
case invalidCertificate
case unsupportedHashFunction(String)

var errorDescription: String? {
switch self {
case .unsupportedKeyType:
return "Unsupported key type"
case .unsupportedECKeyLength(let bits):
return "Unsupported EC key length: \(bits)"
case .invalidBase64:
return "Invalid Base64"
case .invalidCertificate:
return "Invalid X.509 certificate"
case .unsupportedHashFunction(let hashFunction):
return "Unsupported hash function: \(hashFunction)"
}
}
}

enum WebEidResponseUtilError: Error, LocalizedError {
case invalidResponseURI
case couldNotBuildURL

var errorDescription: String? {
switch self {
case .invalidResponseURI: return "Invalid response URI"
case .couldNotBuildURL: return "Could not build response URL"
}
}
}
39 changes: 39 additions & 0 deletions Modules/WebEidLib/Sources/WebEidLib/Extension/JSONCodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2017 - 2025 Riigi Infosüsteemi Amet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

import Foundation

// MARK: - Shared JSON helpers

protocol JSONCodable: Codable {}

extension JSONCodable {
/// Decode from raw JSON Data
static func from(jsonData: Data, decoder: JSONDecoder = JSONDecoder()) throws -> Self {
try decoder.decode(Self.self, from: jsonData)
}

/// Encode to JSON Data
func toJSONData(pretty: Bool = false, encoder: JSONEncoder = JSONEncoder()) throws -> Data {
if pretty {
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
}
return try encoder.encode(self)
}
}
Loading
Loading