feat: add JWT Support to MDM and refacture (MESSENGER-6162)

This commit is contained in:
Frank Rotermund
2024-07-25 12:51:43 +02:00
parent bb60e8f85d
commit dc6c9f8fc4
9 changed files with 53 additions and 88 deletions

View File

@@ -76,12 +76,12 @@ extension UserDefaults
}
}
private func checkUrlSavety(_ serverUrl: String) -> Bool {
private func checkUrlSavety(_ serverUrl: String) async -> Bool {
if BWIBuildSettings.shared.bwiEnableLoginProtection {
let protectionService = LoginProtectionService()
protectionService.hashes = BWIBuildSettings.shared.bwiHashes
return protectionService.isValid(serverUrl)
return await protectionService.isValid(serverUrl)
} else {
return true
}
@@ -112,11 +112,13 @@ extension UserDefaults
func registerForAppConfig() {
NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: nil, queue: OperationQueue.main) { [self] (note) in
handleAppConfig()
Task {
await handleAppConfig()
}
}
}
func handleAppConfig() {
func handleAppConfig() async {
if let dict = UserDefaults.standard.dictionary(forKey: configKey) {
// only compute if serverURL has not changed (this may need to be changed on Adminportal integration
if !isSameConfig(dict: dict) {
@@ -125,22 +127,22 @@ extension UserDefaults
if let serverUrl = dict[serverUrlKey] as? String {
if serverUrl.count == 0 {
config.serverUrl = nil
} else if checkUrlSavety(serverUrl) {
} else if await checkUrlSavety(serverUrl) {
config.serverUrl = serverUrl
}
}
if let contentScannerUrl = dict[contentScannerKey] as? String {
if checkUrlSavety(contentScannerUrl) {
if await checkUrlSavety(contentScannerUrl) {
config.contentScannerUrl = contentScannerUrl
}
}
if let pusherUrl = dict[pusherUrlKey] as? String {
if checkUrlSavety(pusherUrl) {
if await checkUrlSavety(pusherUrl) {
config.pusherUrl = pusherUrl
}
}
if let permalinkUrl = dict[permalinkUrlKey] as? String {
if checkUrlSavety(permalinkUrl) {
if await checkUrlSavety(permalinkUrl) {
config.permalinkUrl = permalinkUrl
}
}

View File

@@ -21,15 +21,36 @@ import CryptoKit
@objcMembers class LoginProtectionService : NSObject {
var hashes: [String]?
@objc func isValid(_ urlString: String) -> Bool {
guard let hashes = hashes else {
return false
@objc func isValid(_ homeserverAddress: String) async -> Bool {
// bwi #6162 a homeserveraddress is valid when there is either
// a) no homeserver protection (bwm)
// b) tokenized protection and there is a valid token
// c) hashed protection and there is a valid hash (this will be disabled soon)
// d) b) && c) can be combined for now
var validHomeserver = false
if BWIBuildSettings.shared.bwiEnableTokenizedLoginProtection {
let tokenVerificator = ServerTokenVerificator()
let token = await tokenVerificator.fetchToken(baseURL: homeserverAddress)
if let token = token {
validHomeserver = tokenVerificator.verifyToken(baseURL: homeserverAddress, token: token)
}
}
let string = self.normalizeLoginUrl(urlString)
let hashedString = self.hashedString(string)
if BWIBuildSettings.shared.bwiEnableLoginProtection && !validHomeserver {
if let hashes = hashes {
let string = self.normalizeLoginUrl(homeserverAddress)
let hashedString = self.hashedString(string)
validHomeserver = hashes.contains(hashedString)
}
}
return hashes.contains(hashedString)
return validHomeserver
}
private func normalizeLoginUrl(_ urlString: String) -> String {

View File

@@ -16,40 +16,8 @@
*/
import Foundation
/*
let publicKey: Data = publicKeyStr.data(using: .utf8)!
struct MyClaims: Claims {
let version: Int
let hostname: String
}
let signedJWT = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJob3N0bmFtZSI6ImJ3aS5kZSJ9.bondtDczLlOHlHLLZj1C9tn60LqBpIhFNaUy6nYL6CVVwWGIv8EIxYWMTx-MP9OSjj-aeMcy0tmDqSz6nbdbgvUJvkB6r-ByH7fTsVj6OtEEs8mWnqHBOFBwTy9tv5vSTfjFX7PBSko2OK3HQrZkFSkfr-xZoOIc_PxblUnec2hClxVq7ImJnIAW1HCh85DMz2c-MiEHd7wQwBcgwWKWmAY9X6uS25WWhQcPH9i0-QMEQNjXGJp-_wM10KJuuOMDx7QdmcX78QgcOyP-G64cA36NL4-6Aby5EnJUDX-uzFbM_ZERgPVmjfzHoZarFCHSK6-fTBg_MQuDF-O2OOdM6Q"
let jwtVerifier = JWTVerifier.rs256(publicKey: publicKey)
do {
let verified = JWT<MyClaims>.verify(signedJWT, using: jwtVerifier)
let newJWT = try JWT<MyClaims>(jwtString: signedJWT, verifier: jwtVerifier)
print(newJWT.claims)
} catch let error {
print(error.localizedDescription)
}
*/
import SwiftJWT
/*
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
*/
struct ServerTokenClaims: Claims {
let issuer: String
let sub: String
@@ -83,12 +51,13 @@ struct ServerTokenVerificator {
if verified && (validated == .success) && matchingHomeServer {
return true
}
} catch let error {
} catch {
// counts like an unverified Token
}
}
return true
// no public key was able to verify the token
return false
}
// fetch the current token from the new endpoint,
@@ -104,7 +73,7 @@ struct ServerTokenVerificator {
config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
let session : URLSession = URLSession(configuration: config)
let (data, response) = try await session.data(from: url)
let (data, _) = try await session.data(from: url)
// the token may have additional endlines
if let str = String(data: data, encoding: .utf8) {