mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-16 06:28:27 +02:00
117 lines
4.2 KiB
Swift
117 lines
4.2 KiB
Swift
//
|
|
/*
|
|
* Copyright (c) 2022 BWI GmbH
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import Foundation
|
|
import SwiftJWT
|
|
|
|
struct ServerTokenClaims: Claims {
|
|
let issuer: String
|
|
let sub: String
|
|
let exp: Date?
|
|
let iat: Date?
|
|
let jti: String
|
|
let version: Int
|
|
}
|
|
|
|
// verifies if a selected homeserver is valid to be used with bundesmessenger
|
|
struct ServerTokenVerificator {
|
|
|
|
// takes a token and the selected server url, returns true if token is valid for at least one public key in the subfolder publickeys. Additionally the token needs to be valid (inside the valid timestamp) and contain a matching homeserver
|
|
func verifyToken( baseURL: String, tokens: [String] ) -> Bool {
|
|
let publicKeys = publicKeys(folder: Bundle.main.resourcePath! + "/publickeys" )
|
|
|
|
let homeServerURL = baseURL.replacingOccurrences(of: "https://", with: "")
|
|
|
|
for key in publicKeys {
|
|
guard let keyData = key.data(using: .utf8) else {
|
|
continue
|
|
}
|
|
|
|
// only one public key needs to be fine
|
|
let jwtVerifier = JWTVerifier.ps512(publicKey: keyData)
|
|
do {
|
|
for token in tokens {
|
|
let verified = JWT<ServerTokenClaims>.verify(token, using: jwtVerifier)
|
|
let verifiedJWT = try JWT<ServerTokenClaims>(jwtString: token, verifier: jwtVerifier)
|
|
let validated = verifiedJWT.validateClaims()
|
|
let matchingHomeServer = verifiedJWT.claims.sub == homeServerURL
|
|
if verified && (validated == .success) && matchingHomeServer {
|
|
return true
|
|
}
|
|
}
|
|
} catch {
|
|
// counts like an unverified Token
|
|
}
|
|
}
|
|
|
|
// no public key was able to verify the token
|
|
return false
|
|
}
|
|
|
|
// fetch the current token from the new endpoint,
|
|
func fetchToken( baseURL: String ) async -> [String]? {
|
|
let path = "/_bum/client/v1/verify"
|
|
|
|
guard let url = URL(string: baseURL + path), let safeURL = url.ensureHTTPS() else {
|
|
return nil
|
|
}
|
|
|
|
do {
|
|
let config = URLSessionConfiguration.default
|
|
config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
|
|
let session : URLSession = URLSession(configuration: config)
|
|
|
|
let (data, _) = try await session.data(from: safeURL)
|
|
|
|
let fetchedStrings = try JSONDecoder().decode([String].self, from: data)
|
|
|
|
return fetchedStrings
|
|
} catch (let error) {
|
|
if let error = error as? URLError, error.code == .notConnectedToInternet {
|
|
return nil
|
|
}
|
|
return [String]()
|
|
}
|
|
}
|
|
|
|
// reads the current public key folder into a string array of public keys
|
|
private func publicKeys(folder: String) -> [String] {
|
|
var keys: [String] = []
|
|
|
|
let fm = FileManager.default
|
|
|
|
do {
|
|
let items = try fm.contentsOfDirectory(atPath: folder)
|
|
|
|
for item in items {
|
|
let fileUrl = URL(fileURLWithPath: folder + "/" + item)
|
|
|
|
do {
|
|
let key = try String(contentsOf: fileUrl, encoding: .utf8)
|
|
keys.append(key)
|
|
} catch {
|
|
// invalid files do not count as public keys and are just not inserted into the array
|
|
}
|
|
}
|
|
} catch {
|
|
// should not happen but in this case there are no public keys == no verification
|
|
}
|
|
|
|
return keys
|
|
}
|
|
}
|