Vydané zdroje
Stáhnout zdroje ZIP
CH-J Server Manager
Procházejte adresáře a soubory konkrétního vydání aplikace.
Zdroje jsou zveřejněny pod CH-J Proprietary Software License 1.14. Jejich dostupnost nemění licenční podmínky ani neposkytuje další oprávnění.
1
import Foundation2
import Security3
import LocalAuthentication5
struct Failure: Error { let code: String }6
let service = "de.ch-j.servermanager.vault.biometry.v1"7
func fail(_ code: String) throws -> Never { throw Failure(code: code) }8
func authenticate(_ reason: String) throws {9
let context = LAContext()10
context.localizedFallbackTitle = "" // Master-password fallback is in the application.11
let semaphore = DispatchSemaphore(value: 0)12
var accepted = false13
var failure: Error?14
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { ok, error in15
accepted = ok; failure = error; semaphore.signal()16
}17
if semaphore.wait(timeout: .now() + 60) == .timedOut { context.invalidate(); try fail("BIOMETRIC_TIMEOUT") }18
if !accepted {19
let code = (failure as? LAError)?.code20
if code == .userCancel || code == .appCancel || code == .systemCancel { try fail("BIOMETRIC_CANCELLED") }21
if code == .biometryLockout { try fail("BIOMETRIC_DEVICE_UNAVAILABLE") }22
try fail("BIOMETRIC_FAILED")23
}24
}25
func keychainFailure(_ status: OSStatus) throws -> Never {26
if status == errSecUserCanceled { try fail("BIOMETRIC_CANCELLED") }27
if status == errSecItemNotFound { try fail("BIOMETRIC_ENROLLMENT_INVALIDATED") }28
if status == errSecNotAvailable || status == errSecInteractionNotAllowed { try fail("BIOMETRIC_DEVICE_UNAVAILABLE") }29
try fail("BIOMETRIC_CREDENTIAL_FAILED")30
}31
func run() throws -> [String: Any] {32
let input = FileHandle.standardInput.readDataToEndOfFile()33
guard input.count <= 4096, let request = try JSONSerialization.jsonObject(with: input) as? [String: Any], let op = request["op"] as? String else { try fail("BIOMETRIC_FAILED") }34
let reason = request["reason"] as? String ?? "Unlock CH-J Server Manager"35
if op == "status" {36
let context = LAContext(); var error: NSError?37
let available = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)38
let code = available ? "BIOMETRIC_AVAILABLE" : error?.code == LAError.biometryNotEnrolled.rawValue ? "BIOMETRIC_NO_ENROLLMENT" : error?.code == LAError.biometryLockout.rawValue ? "BIOMETRIC_DEVICE_UNAVAILABLE" : "BIOMETRIC_UNAVAILABLE"39
return ["ok": true, "available": available, "code": code]40
}41
if op == "authenticate" { try authenticate(reason); return ["ok": true] }42
guard let entry = request["entryId"] as? String, entry.count == 64, entry.allSatisfy({ $0.isHexDigit && !$0.isUppercase }) else { try fail("BIOMETRIC_FAILED") }43
var query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: entry]44
if op == "remove" {45
let status = SecItemDelete(query as CFDictionary)46
if status != errSecSuccess && status != errSecItemNotFound { try keychainFailure(status) }47
return ["ok": true]48
}49
if op == "store" {50
guard let encoded = request["key"] as? String, var key = Data(base64Encoded: encoded), key.count == 32 else { try fail("BIOMETRIC_INVALID_KEY") }51
defer { key.resetBytes(in: 0..<key.count) }52
var error: Unmanaged<CFError>?53
guard let access = SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, .biometryCurrentSet, &error) else { try fail("BIOMETRIC_UNAVAILABLE") }54
query[kSecAttrAccessControl as String] = access55
query[kSecValueData as String] = key56
query[kSecAttrSynchronizable as String] = false57
let status = SecItemAdd(query as CFDictionary, nil)58
if status != errSecSuccess { try keychainFailure(status) }59
return ["ok": true]60
}61
if op == "retrieve" {62
let context = LAContext(); context.localizedFallbackTitle = ""63
context.touchIDAuthenticationAllowableReuseDuration = 064
context.localizedReason = reason65
query[kSecUseAuthenticationContext as String] = context66
query[kSecReturnData as String] = true67
query[kSecMatchLimit as String] = kSecMatchLimitOne68
var result: CFTypeRef?69
let status = SecItemCopyMatching(query as CFDictionary, &result)70
if status != errSecSuccess { try keychainFailure(status) }71
guard var key = result as? Data, key.count == 32 else { try fail("BIOMETRIC_INVALID_KEY") }72
defer { key.resetBytes(in: 0..<key.count) }73
return ["ok": true, "key": key.base64EncodedString()]74
}75
try fail("BIOMETRIC_FAILED")76
}77
do {78
let value = try run()79
FileHandle.standardOutput.write(try JSONSerialization.data(withJSONObject: value)); exit(0)80
} catch {81
let code = (error as? Failure)?.code ?? "BIOMETRIC_FAILED"82
let result = ["ok": false, "code": code] as [String: Any]83
if let data = try? JSONSerialization.data(withJSONObject: result) { FileHandle.standardOutput.write(data) }84
exit(1)85
}SHA-256: 2cbf9359dcf0d0ecad2f5558854d052d73a7f47dfd397510ed49f9cb4abba0f9
SHA-256 archivu: 5ac91caf4fa32a6fdb114f2430deed486fbe7489d5eea343d1f034169fafb5e0