Add Client Certificate
This commit is contained in:
parent
8f3bb1a99b
commit
0672f56f10
|
@ -11,9 +11,18 @@ protocol RocketChatClientProtocol {
|
||||||
func sendRead(rid: String) -> AnyPublisher<ReadResponse, RocketChatError>
|
func sendRead(rid: String) -> AnyPublisher<ReadResponse, RocketChatError>
|
||||||
}
|
}
|
||||||
|
|
||||||
final class RocketChatClient {
|
final class RocketChatClient: NSObject {
|
||||||
private let server: Server
|
private let server: Server
|
||||||
|
|
||||||
|
private lazy var session = URLSession(
|
||||||
|
configuration: .default,
|
||||||
|
delegate: URLSesionClientCertificateHandling(
|
||||||
|
certificate: server.certificate,
|
||||||
|
password: server.password
|
||||||
|
),
|
||||||
|
delegateQueue: nil
|
||||||
|
)
|
||||||
|
|
||||||
init(server: Server) {
|
init(server: Server) {
|
||||||
self.server = server
|
self.server = server
|
||||||
}
|
}
|
||||||
|
@ -32,7 +41,7 @@ final class RocketChatClient {
|
||||||
urlRequest.httpMethod = request.method.rawValue
|
urlRequest.httpMethod = request.method.rawValue
|
||||||
urlRequest.httpBody = request.body
|
urlRequest.httpBody = request.body
|
||||||
|
|
||||||
return URLSession.shared.dataTaskPublisher(for: urlRequest)
|
return session.dataTaskPublisher(for: urlRequest)
|
||||||
.tryMap { (data, response) in
|
.tryMap { (data, response) in
|
||||||
guard let httpResponse = response as? HTTPURLResponse, 200...299 ~= httpResponse.statusCode else {
|
guard let httpResponse = response as? HTTPURLResponse, 200...299 ~= httpResponse.statusCode else {
|
||||||
throw RocketChatError.unauthorized
|
throw RocketChatError.unauthorized
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
// https://medium.com/@hamidptb/implementing-mtls-on-ios-using-urlsession-and-cloudflare-890b76aca66c
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class URLSesionClientCertificateHandling: NSObject, URLSessionDelegate {
|
||||||
|
private let certificate: Data?
|
||||||
|
private let password: String?
|
||||||
|
|
||||||
|
init(certificate: Data?, password: String?) {
|
||||||
|
self.certificate = certificate
|
||||||
|
self.password = password
|
||||||
|
}
|
||||||
|
|
||||||
|
public func urlSession(
|
||||||
|
_: URLSession,
|
||||||
|
didReceive challenge: URLAuthenticationChallenge,
|
||||||
|
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
||||||
|
) {
|
||||||
|
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate else {
|
||||||
|
completionHandler(.performDefaultHandling, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let credential = Credentials.urlCredential(certificate: certificate, password: password) else {
|
||||||
|
completionHandler(.performDefaultHandling, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
challenge.sender?.use(credential, for: challenge)
|
||||||
|
completionHandler(.useCredential, credential)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate typealias UserCertificate = (data: Data, password: String)
|
||||||
|
|
||||||
|
fileprivate final class Credentials {
|
||||||
|
static func urlCredential(certificate: Data?, password: String?) -> URLCredential? {
|
||||||
|
guard let certificate, let password else { return nil }
|
||||||
|
|
||||||
|
let p12Contents = PKCS12(pkcs12Data: certificate, password: password)
|
||||||
|
|
||||||
|
guard let identity = p12Contents.identity else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return URLCredential(identity: identity, certificates: nil, persistence: .none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate struct PKCS12 {
|
||||||
|
let label: String?
|
||||||
|
let keyID: NSData?
|
||||||
|
let trust: SecTrust?
|
||||||
|
let certChain: [SecTrust]?
|
||||||
|
let identity: SecIdentity?
|
||||||
|
|
||||||
|
public init(pkcs12Data: Data, password: String) {
|
||||||
|
let importPasswordOption: NSDictionary
|
||||||
|
= [kSecImportExportPassphrase as NSString: password]
|
||||||
|
var items: CFArray?
|
||||||
|
let secError: OSStatus
|
||||||
|
= SecPKCS12Import(pkcs12Data as NSData,
|
||||||
|
importPasswordOption, &items)
|
||||||
|
guard secError == errSecSuccess else {
|
||||||
|
if secError == errSecAuthFailed {
|
||||||
|
NSLog("Incorrect password?")
|
||||||
|
}
|
||||||
|
fatalError("Error trying to import PKCS12 data")
|
||||||
|
}
|
||||||
|
guard let theItemsCFArray = items else { fatalError() }
|
||||||
|
let theItemsNSArray: NSArray = theItemsCFArray as NSArray
|
||||||
|
guard let dictArray
|
||||||
|
= theItemsNSArray as? [[String: AnyObject]]
|
||||||
|
else {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
label = dictArray.element(for: kSecImportItemLabel)
|
||||||
|
keyID = dictArray.element(for: kSecImportItemKeyID)
|
||||||
|
trust = dictArray.element(for: kSecImportItemTrust)
|
||||||
|
certChain = dictArray.element(for: kSecImportItemCertChain)
|
||||||
|
identity = dictArray.element(for: kSecImportItemIdentity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate extension Array where Element == [String: AnyObject] {
|
||||||
|
func element<T>(for key: CFString) -> T? {
|
||||||
|
for dictElement in self {
|
||||||
|
if let value = dictElement[key as String] as? T {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -74,6 +74,8 @@ final class DefaultDatabase: ServersDatabase {
|
||||||
server.iconURL = updatedServer.iconURL
|
server.iconURL = updatedServer.iconURL
|
||||||
server.useRealName = updatedServer.useRealName
|
server.useRealName = updatedServer.useRealName
|
||||||
server.loggedUser = user(from: updatedServer.loggedUser)
|
server.loggedUser = user(from: updatedServer.loggedUser)
|
||||||
|
server.certificate = updatedServer.clientSSL?.certificate
|
||||||
|
server.password = updatedServer.clientSSL?.password
|
||||||
} else {
|
} else {
|
||||||
Server(
|
Server(
|
||||||
context: viewContext,
|
context: viewContext,
|
||||||
|
@ -81,7 +83,9 @@ final class DefaultDatabase: ServersDatabase {
|
||||||
name: updatedServer.name,
|
name: updatedServer.name,
|
||||||
url: updatedServer.url,
|
url: updatedServer.url,
|
||||||
useRealName: updatedServer.useRealName,
|
useRealName: updatedServer.useRealName,
|
||||||
loggedUser: user(from: updatedServer.loggedUser)
|
loggedUser: user(from: updatedServer.loggedUser),
|
||||||
|
certificate: updatedServer.clientSSL?.certificate,
|
||||||
|
password: updatedServer.clientSSL?.password
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
<relationship name="server" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Server" inverseName="loggedUser" inverseEntity="Server"/>
|
<relationship name="server" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Server" inverseName="loggedUser" inverseEntity="Server"/>
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="Server" representedClassName=".Server" syncable="YES">
|
<entity name="Server" representedClassName=".Server" syncable="YES">
|
||||||
|
<attribute name="certificate" optional="YES" attributeType="Binary"/>
|
||||||
<attribute name="iconURL" optional="YES" attributeType="URI"/>
|
<attribute name="iconURL" optional="YES" attributeType="URI"/>
|
||||||
<attribute name="name" optional="YES" attributeType="String"/>
|
<attribute name="name" optional="YES" attributeType="String"/>
|
||||||
|
<attribute name="password" optional="YES" attributeType="String"/>
|
||||||
<attribute name="updatedSince" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="updatedSince" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="url" optional="YES" attributeType="URI"/>
|
<attribute name="url" optional="YES" attributeType="URI"/>
|
||||||
<attribute name="useRealName" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
<attribute name="useRealName" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
|
|
|
@ -13,6 +13,8 @@ public final class Server: NSManagedObject {
|
||||||
@NSManaged public var url: URL
|
@NSManaged public var url: URL
|
||||||
@NSManaged public var useRealName: Bool
|
@NSManaged public var useRealName: Bool
|
||||||
@NSManaged public var loggedUser: LoggedUser
|
@NSManaged public var loggedUser: LoggedUser
|
||||||
|
@NSManaged public var certificate: Data?
|
||||||
|
@NSManaged public var password: String?
|
||||||
|
|
||||||
@available(*, unavailable)
|
@available(*, unavailable)
|
||||||
init() {
|
init() {
|
||||||
|
@ -36,7 +38,9 @@ public final class Server: NSManagedObject {
|
||||||
updatedSince: Date? = nil,
|
updatedSince: Date? = nil,
|
||||||
url: URL,
|
url: URL,
|
||||||
useRealName: Bool,
|
useRealName: Bool,
|
||||||
loggedUser: LoggedUser
|
loggedUser: LoggedUser,
|
||||||
|
certificate: Data? = nil,
|
||||||
|
password: String? = nil
|
||||||
) {
|
) {
|
||||||
let entity = NSEntityDescription.entity(forEntityName: "Server", in: context)!
|
let entity = NSEntityDescription.entity(forEntityName: "Server", in: context)!
|
||||||
super.init(entity: entity, insertInto: context)
|
super.init(entity: entity, insertInto: context)
|
||||||
|
@ -46,6 +50,8 @@ public final class Server: NSManagedObject {
|
||||||
self.url = url
|
self.url = url
|
||||||
self.useRealName = useRealName
|
self.useRealName = useRealName
|
||||||
self.loggedUser = loggedUser
|
self.loggedUser = loggedUser
|
||||||
|
self.certificate = certificate
|
||||||
|
self.password = password
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,9 @@
|
||||||
1E9A71692B59B6E100477BA2 /* MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71682B59B6E100477BA2 /* MessageSender.swift */; };
|
1E9A71692B59B6E100477BA2 /* MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71682B59B6E100477BA2 /* MessageSender.swift */; };
|
||||||
1E9A716F2B59CBCA00477BA2 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */; };
|
1E9A716F2B59CBCA00477BA2 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */; };
|
||||||
1E9A71712B59CC1300477BA2 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71702B59CC1300477BA2 /* Attachment.swift */; };
|
1E9A71712B59CC1300477BA2 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71702B59CC1300477BA2 /* Attachment.swift */; };
|
||||||
|
1E9A71742B59F36E00477BA2 /* ClientSSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71722B59F34E00477BA2 /* ClientSSL.swift */; };
|
||||||
|
1E9A71752B59F36E00477BA2 /* ClientSSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71722B59F34E00477BA2 /* ClientSSL.swift */; };
|
||||||
|
1E9A71772B59FCA900477BA2 /* URLSessionCertificateHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71762B59FCA900477BA2 /* URLSessionCertificateHandling.swift */; };
|
||||||
1EB375892B55DBFB00AEC3D7 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EB375882B55DBFB00AEC3D7 /* Server.swift */; };
|
1EB375892B55DBFB00AEC3D7 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EB375882B55DBFB00AEC3D7 /* Server.swift */; };
|
||||||
1EB8EF722510F1EE00F352B7 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EB8EF712510F1EE00F352B7 /* Storage.swift */; };
|
1EB8EF722510F1EE00F352B7 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EB8EF712510F1EE00F352B7 /* Storage.swift */; };
|
||||||
1EC6ACB722CB9FC300A41C61 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1EC6ACB522CB9FC300A41C61 /* MainInterface.storyboard */; };
|
1EC6ACB722CB9FC300A41C61 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1EC6ACB522CB9FC300A41C61 /* MainInterface.storyboard */; };
|
||||||
|
@ -398,6 +401,8 @@
|
||||||
1E9A71682B59B6E100477BA2 /* MessageSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSender.swift; sourceTree = "<group>"; };
|
1E9A71682B59B6E100477BA2 /* MessageSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSender.swift; sourceTree = "<group>"; };
|
||||||
1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = "<group>"; };
|
1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = "<group>"; };
|
||||||
1E9A71702B59CC1300477BA2 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = "<group>"; };
|
1E9A71702B59CC1300477BA2 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = "<group>"; };
|
||||||
|
1E9A71722B59F34E00477BA2 /* ClientSSL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientSSL.swift; sourceTree = "<group>"; };
|
||||||
|
1E9A71762B59FCA900477BA2 /* URLSessionCertificateHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionCertificateHandling.swift; sourceTree = "<group>"; };
|
||||||
1EB375882B55DBFB00AEC3D7 /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = "<group>"; };
|
1EB375882B55DBFB00AEC3D7 /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = "<group>"; };
|
||||||
1EB8EF712510F1EE00F352B7 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
|
1EB8EF712510F1EE00F352B7 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
|
||||||
1EC6ACB022CB9FC300A41C61 /* ShareRocketChatRN.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareRocketChatRN.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
1EC6ACB022CB9FC300A41C61 /* ShareRocketChatRN.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareRocketChatRN.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -593,6 +598,7 @@
|
||||||
1E29A2E92B585B070093C03C /* FailableDecodable.swift */,
|
1E29A2E92B585B070093C03C /* FailableDecodable.swift */,
|
||||||
1E29A2EA2B585B070093C03C /* HTTP */,
|
1E29A2EA2B585B070093C03C /* HTTP */,
|
||||||
1E29A2EE2B585B070093C03C /* RocketChatError.swift */,
|
1E29A2EE2B585B070093C03C /* RocketChatError.swift */,
|
||||||
|
1E9A71762B59FCA900477BA2 /* URLSessionCertificateHandling.swift */,
|
||||||
);
|
);
|
||||||
path = Client;
|
path = Client;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -699,6 +705,7 @@
|
||||||
1E470E822513A71E00E3DD1D /* RocketChat.swift */,
|
1E470E822513A71E00E3DD1D /* RocketChat.swift */,
|
||||||
1EB8EF712510F1EE00F352B7 /* Storage.swift */,
|
1EB8EF712510F1EE00F352B7 /* Storage.swift */,
|
||||||
1ED038A82B5090AD00C007D4 /* MMKV.swift */,
|
1ED038A82B5090AD00C007D4 /* MMKV.swift */,
|
||||||
|
1E9A71722B59F34E00477BA2 /* ClientSSL.swift */,
|
||||||
);
|
);
|
||||||
path = RocketChat;
|
path = RocketChat;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1797,6 +1804,7 @@
|
||||||
1E76CBD225152C730067298C /* Data+Extensions.swift in Sources */,
|
1E76CBD225152C730067298C /* Data+Extensions.swift in Sources */,
|
||||||
1E76CBD125152C710067298C /* Date+Extensions.swift in Sources */,
|
1E76CBD125152C710067298C /* Date+Extensions.swift in Sources */,
|
||||||
1E76CBD425152C790067298C /* Database.swift in Sources */,
|
1E76CBD425152C790067298C /* Database.swift in Sources */,
|
||||||
|
1E9A71742B59F36E00477BA2 /* ClientSSL.swift in Sources */,
|
||||||
1ED038AD2B50927B00C007D4 /* WatermelonDB+Extensions.swift in Sources */,
|
1ED038AD2B50927B00C007D4 /* WatermelonDB+Extensions.swift in Sources */,
|
||||||
1ED038A52B50900800C007D4 /* Bundle+Extensions.swift in Sources */,
|
1ED038A52B50900800C007D4 /* Bundle+Extensions.swift in Sources */,
|
||||||
1E76CBC325152A460067298C /* String+Extensions.swift in Sources */,
|
1E76CBC325152A460067298C /* String+Extensions.swift in Sources */,
|
||||||
|
@ -1870,6 +1878,7 @@
|
||||||
1E29A2FF2B585B070093C03C /* TokenAdapter.swift in Sources */,
|
1E29A2FF2B585B070093C03C /* TokenAdapter.swift in Sources */,
|
||||||
1E29A3052B585B070093C03C /* Request.swift in Sources */,
|
1E29A3052B585B070093C03C /* Request.swift in Sources */,
|
||||||
1E6436242B59998A009F0CE1 /* ExtensionDelegate.swift in Sources */,
|
1E6436242B59998A009F0CE1 /* ExtensionDelegate.swift in Sources */,
|
||||||
|
1E9A71772B59FCA900477BA2 /* URLSessionCertificateHandling.swift in Sources */,
|
||||||
1E29A2EF2B585B070093C03C /* RocketChatClient.swift in Sources */,
|
1E29A2EF2B585B070093C03C /* RocketChatClient.swift in Sources */,
|
||||||
1E29A2FB2B585B070093C03C /* MessagesRequest.swift in Sources */,
|
1E29A2FB2B585B070093C03C /* MessagesRequest.swift in Sources */,
|
||||||
1E29A31D2B5871B60093C03C /* Date+Extensions.swift in Sources */,
|
1E29A31D2B5871B60093C03C /* Date+Extensions.swift in Sources */,
|
||||||
|
@ -1955,6 +1964,7 @@
|
||||||
7AAB3E23257E6A6E00707CF6 /* Data+Extensions.swift in Sources */,
|
7AAB3E23257E6A6E00707CF6 /* Data+Extensions.swift in Sources */,
|
||||||
7AAB3E24257E6A6E00707CF6 /* Date+Extensions.swift in Sources */,
|
7AAB3E24257E6A6E00707CF6 /* Date+Extensions.swift in Sources */,
|
||||||
7AAB3E25257E6A6E00707CF6 /* Database.swift in Sources */,
|
7AAB3E25257E6A6E00707CF6 /* Database.swift in Sources */,
|
||||||
|
1E9A71752B59F36E00477BA2 /* ClientSSL.swift in Sources */,
|
||||||
1ED038AF2B50927B00C007D4 /* WatermelonDB+Extensions.swift in Sources */,
|
1ED038AF2B50927B00C007D4 /* WatermelonDB+Extensions.swift in Sources */,
|
||||||
1ED038A72B50900800C007D4 /* Bundle+Extensions.swift in Sources */,
|
1ED038A72B50900800C007D4 /* Bundle+Extensions.swift in Sources */,
|
||||||
7AAB3E26257E6A6E00707CF6 /* String+Extensions.swift in Sources */,
|
7AAB3E26257E6A6E00707CF6 /* String+Extensions.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct ClientSSL: Codable {
|
||||||
|
let path: String
|
||||||
|
let password: String
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MMKV {
|
||||||
|
func clientSSL(for url: URL) -> ClientSSL? {
|
||||||
|
guard let host = url.host else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let rawClientSSL = string(forKey: host) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let data = rawClientSSL.data(using: .utf8) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let clientSSL = try? JSONDecoder().decode(ClientSSL.self, from: data) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientSSL
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,12 +18,32 @@ final class WatchConnection: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func getClientSSL(from clientSSL: ClientSSL?) -> WatchMessage.Server.ClientSSL? {
|
||||||
|
guard let clientSSL else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard FileManager.default.fileExists(atPath: clientSSL.path) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let certificate = NSData(contentsOfFile: clientSSL.path) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return .init(
|
||||||
|
certificate: Data(referencing: certificate),
|
||||||
|
password: clientSSL.password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private func getMessage() -> WatchMessage {
|
private func getMessage() -> WatchMessage {
|
||||||
let serversQuery = database.query(raw: "select * from servers") as [DBServer]
|
let serversQuery = database.query(raw: "select * from servers") as [DBServer]
|
||||||
|
|
||||||
let servers = serversQuery.compactMap { item -> WatchMessage.Server? in
|
let servers = serversQuery.compactMap { item -> WatchMessage.Server? in
|
||||||
let userId = mmkv.userId(for: item.identifier)
|
let userId = mmkv.userId(for: item.identifier)
|
||||||
let userToken = mmkv.userToken(for: userId)
|
let userToken = mmkv.userToken(for: userId)
|
||||||
|
let clientSSL = mmkv.clientSSL(for: item.url)
|
||||||
|
|
||||||
let usersQuery = database.query(raw: "select * from users where token == ? limit 1", [userToken]) as [DBUser]
|
let usersQuery = database.query(raw: "select * from users where token == ? limit 1", [userToken]) as [DBUser]
|
||||||
|
|
||||||
|
@ -41,7 +61,8 @@ final class WatchConnection: NSObject {
|
||||||
token: userToken,
|
token: userToken,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
username: user.username
|
username: user.username
|
||||||
)
|
),
|
||||||
|
clientSSL: getClientSSL(from: clientSSL)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ struct WatchMessage: Codable {
|
||||||
let iconURL: URL
|
let iconURL: URL
|
||||||
let useRealName: Bool
|
let useRealName: Bool
|
||||||
let loggedUser: LoggedUser
|
let loggedUser: LoggedUser
|
||||||
|
let clientSSL: ClientSSL?
|
||||||
|
|
||||||
struct LoggedUser: Codable {
|
struct LoggedUser: Codable {
|
||||||
let id: String
|
let id: String
|
||||||
|
@ -16,5 +17,10 @@ struct WatchMessage: Codable {
|
||||||
let name: String
|
let name: String
|
||||||
let username: String
|
let username: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ClientSSL: Codable {
|
||||||
|
let certificate: Data
|
||||||
|
let password: String
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue