Initial commit: Uruk Prize Platform architecture, backend core, mobile app, gateway caller & deployment pipeline
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
import CommonCrypto
|
||||
import Security
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
private let CHANNEL = "iq.urukprize.uruk_prize/device_fingerprint"
|
||||
private let KEYCHAIN_KEY = "iq.urukprize.device_persistent_id"
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
|
||||
let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
|
||||
|
||||
channel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch call.method {
|
||||
case "getHardwareFingerprint":
|
||||
let rawData = self.getHardwareDetails()
|
||||
let hashed = self.sha256(data: rawData)
|
||||
result(hashed)
|
||||
case "getDeviceModel":
|
||||
result(self.getDeviceModel())
|
||||
case "getHardwareRawData":
|
||||
result(self.getHardwareDetails())
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
})
|
||||
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
private func getHardwareDetails() -> String {
|
||||
let vendorId = UIDevice.current.identifierForVendor?.uuidString ?? "UNKNOWN_IDFV"
|
||||
let model = getDeviceModel()
|
||||
let systemName = UIDevice.current.systemName
|
||||
let systemVersion = UIDevice.current.systemVersion
|
||||
let persistentKey = getOrCreatePersistentKeychainId()
|
||||
|
||||
return "idfv=\(vendorId);keychain_id=\(persistentKey);model=\(model);sys=\(systemName)_\(systemVersion)"
|
||||
}
|
||||
|
||||
private func getDeviceModel() -> String {
|
||||
var systemInfo = utsname()
|
||||
uname(&systemInfo)
|
||||
let machineMirror = Mirror(reflecting: systemInfo.machine)
|
||||
let identifier = machineMirror.children.reduce("") { identifier, element in
|
||||
guard let value = element.value as? Int8, value != 0 else { return identifier }
|
||||
return identifier + String(UnicodeScalar(UInt8(value)))
|
||||
}
|
||||
return identifier
|
||||
}
|
||||
|
||||
private func getOrCreatePersistentKeychainId() -> String {
|
||||
let tag = KEYCHAIN_KEY.data(using: .utf8)!
|
||||
|
||||
// Query Keychain
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassKey,
|
||||
kSecAttrApplicationTag as String: tag,
|
||||
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
|
||||
kSecReturnData as String: true
|
||||
]
|
||||
|
||||
var item: CFTypeRef?
|
||||
let status = SecItemCopyMatching(query as CFDictionary, &item)
|
||||
if status == errSecSuccess, let existingData = item as? Data, let string = String(data: existingData, encoding: .utf8) {
|
||||
return string
|
||||
}
|
||||
|
||||
// Generate new persistent UUID and save to Keychain
|
||||
let newId = UUID().uuidString
|
||||
let newIdData = newId.data(using: .utf8)!
|
||||
|
||||
let addQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassKey,
|
||||
kSecAttrApplicationTag as String: tag,
|
||||
kSecValueData as String: newIdData,
|
||||
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
||||
]
|
||||
SecItemAdd(addQuery as CFDictionary, nil)
|
||||
return newId
|
||||
}
|
||||
|
||||
private func sha256(data: String) -> String {
|
||||
guard let inputData = data.data(using: .utf8) else { return "" }
|
||||
var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
inputData.withUnsafeBytes {
|
||||
_ = CC_SHA256($0.baseAddress, CC_LONG(inputData.count), &digest)
|
||||
}
|
||||
return digest.map { String(format: "%02hhx", $0) }.joined()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user