// // System.swift // Befund // // Created by Irakli Abetschkhrischwili on 21.05.22. // Copyright © 2022 MVZ Dr. Stein und Kollegen. All rights reserved. import Foundation import UIKit import CoreImage.CIFilterBuiltins extension Core { public struct System { /** * Returns application directory path */ public static func ApplicationDirectoryPath() -> String { return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] } /** * Returns settings path */ public static func SettingsPath() -> String { return ApplicationDirectoryPath() + "/settings.plist" } /** * Returns storage directory path */ public static func StorageDirectoryPath() -> String? { var result: String? = ApplicationDirectoryPath() + "/storage" let fileManager = FileManager.default do { var isDir:ObjCBool = true if(!fileManager.fileExists(atPath: result!, isDirectory: &isDir)) { try fileManager.createDirectory(atPath: result!, withIntermediateDirectories: true) } if(!fileManager.fileExists(atPath: result!, isDirectory: &isDir)) { result = nil } } catch { result = nil Log.Critical(err: error, namespace: "Core.System", method: "StorageDirectoryPath") } return result } /** * Returns encrypted storage directory path */ public static func EncryptedStorageDirectoryPath() -> String? { var result: String? = nil do { let storagePath = StorageDirectoryPath() if(storagePath != nil) { result = storagePath! + "/encrypted" let fileManager = FileManager.default var isDir:ObjCBool = true if(!fileManager.fileExists(atPath: result!, isDirectory: &isDir)) { try fileManager.createDirectory(atPath: result!, withIntermediateDirectories: true) } if(!fileManager.fileExists(atPath: result!, isDirectory: &isDir)) { result = nil } } } catch { result = nil Log.Critical(err: error, namespace: "Core.System", method: "EncryptedStorageDirectoryPath") } return result } /** * Returns databases directory path */ public static func DatabaseDirectoryPath() -> String? { var result: String? = ApplicationDirectoryPath() + "/databases" let fileManager = FileManager.default do { var isDir:ObjCBool = true if(!fileManager.fileExists(atPath: result!, isDirectory: &isDir)) { try fileManager.createDirectory(atPath: result!, withIntermediateDirectories: true) } if(!fileManager.fileExists(atPath: result!, isDirectory: &isDir)) { result = nil } } catch { result = nil Log.Critical(err: error, namespace: "Core.System", method: "DatabaseDirectoryPath") } return result } /** * Returns logs database path */ public static func LogsDatabasePath() -> String? { var result: String? = nil let dbDirectory = DatabaseDirectoryPath() if(dbDirectory != nil) { result = dbDirectory! + "/logs.db" } return result } /** * Returns results database path */ public static func ResultsDatabasePath() -> String? { var result: String? = nil let dbDirectory = DatabaseDirectoryPath() if(dbDirectory != nil) { result = dbDirectory! + "/results.db" } return result } /** * Checks if file exists * * @param atPath - filepath that should be checked if exists */ public static func FileExists(atPath: String) -> Bool { let fileManager = FileManager.default return fileManager.fileExists(atPath: atPath) } /** * Deletes file at the path * * @param atPath - file that should be deleted */ public static func DeleteFile(atPath: String) -> Bool { var result = false do { let fileManager = FileManager.default try fileManager.removeItem(atPath: atPath) result = !FileExists(atPath: atPath) } catch { Log.Critical(err: error, namespace: "Core.System", method: "DeleteFile(string)") } return result } /** * Writes content to the file * * @param filename - filename where the content should be written * @param data - data of content */ public static func WriteToStorage(filename: String, data: Data) -> Bool { var result = false do { let storageDirectory = StorageDirectoryPath() if(storageDirectory != nil) { let filePath = storageDirectory! + "/" + filename let fileURL = URL.init(fileURLWithPath: filePath) try data.write(to: fileURL) result = true } } catch { Log.Critical(err: error, namespace: "Core.System", method: "WriteToStorage(string, data)") } return result } /** * Writes content to the encrypted storage * * @param filename - filename where the content should be written * @param data - data of content */ public static func WriteToEncryptedStorage(filename: String, data: Data) -> Bool { var result = false do { let storageDirectory = EncryptedStorageDirectoryPath() if(storageDirectory != nil) { let filePath = storageDirectory! + "/" + filename let fileURL = URL.init(fileURLWithPath: filePath) if(FileExists(atPath: filePath)) { DeleteFile(atPath: filePath) } try data.write(to: fileURL) result = true } } catch { Log.Critical(err: error, namespace: "Core.System", method: "WriteToEncryptedStorage(string, data)") } return result } /** * Reads content of file * * @param filename - filename */ public static func ReadFromStorage(filename: String) -> Data? { var result: Data? = nil do { let storageDirectory = StorageDirectoryPath() if(storageDirectory != nil) { let fileAtPath = storageDirectory! + "/" + filename if(FileExists(atPath: fileAtPath)) { let fileURL = URL.init(fileURLWithPath: fileAtPath) result = try Data(contentsOf: fileURL) } } } catch { Log.Critical(err: error, namespace: "Core.System", method: "ReadFromStorage(string)") } return result } public static func GetPathForStorageFile(filename: String) -> String? { var result: String? = nil let storageDirectory = StorageDirectoryPath() if(storageDirectory != nil) { let fileAtPath = storageDirectory! + "/" + filename if(FileExists(atPath: fileAtPath)) { result = fileAtPath } } return result } /** * Returns url of storage file * *@param filename - filename */ public static func GetURLForStorageFile(filename: String) -> URL? { return URL.init(fileURLWithPath: GetPathForStorageFile(filename: filename)!) } /** * Reads content of encrypted file * * @param filename - encrypted filename */ public static func ReadFromEncryptedStorage(filename: String) -> Data? { var result: Data? = nil do { let storageDirectory = EncryptedStorageDirectoryPath() if(storageDirectory != nil) { let fileAtPath = storageDirectory! + "/" + filename if(FileExists(atPath: fileAtPath)) { let fileURL = URL.init(fileURLWithPath: fileAtPath) result = try Data(contentsOf: fileURL) } } } catch { Log.Critical(err: error, namespace: "Core.System", method: "ReadFromEncryptedStorage(string)") } return result } /** * Returns url of encrypted file * * @param filename - filenaname */ public static func GetURLForStorageEncryptedFile(filename: String) -> URL? { var result: URL? = nil let fileAtPath = GetPathForStorageEncryptedFile(filename: filename) if(FileExists(atPath: fileAtPath!)) { result = URL.init(fileURLWithPath: fileAtPath!) } return result } public static func GetPathForStorageEncryptedFile(filename: String) -> String? { var result: String? = nil let storageDirectory = EncryptedStorageDirectoryPath() if(storageDirectory != nil) { result = storageDirectory! + "/" + filename } return result } /** * Returns device object */ public static func GetDevice() -> Core.Models.System.Device { var result = Core.Models.System.Device() result.udid = UIDevice.current.identifierForVendor?.uuidString result.name = UIDevice.current.name result.model = UIDevice.current.model result.manufacturer = "Apple" result.os = UIDevice.current.systemVersion return result } /** * Returns storage info */ public static func GetStorageInfo() -> Core.Models.System.StorageInfo? { var result: Core.Models.System.StorageInfo? = nil do { let fileManager = FileManager.default let attributes = try fileManager.attributesOfFileSystem(forPath: ApplicationDirectoryPath()) let fileSystemSizeInBytes = attributes[.systemSize] as? UInt64 let freeFileSystemSizeInBytes = attributes[.systemFreeSize] as? UInt64 if(fileSystemSizeInBytes != nil && freeFileSystemSizeInBytes != nil) { result = Core.Models.System.StorageInfo() result!.total = (Double)(fileSystemSizeInBytes! / 1000000000) result!.free = (Double)(freeFileSystemSizeInBytes! / 1000000000) result!.used = (result!.total - result!.free) } } catch { Log.Critical(err: error, namespace: "Core.System", method: "GetStorageInfo") } return result } /** * Returns file creation date * * @param atPath - filename */ public static func GetFileCreationDate(atPath: String) -> Date? { var result: Date? = nil do { if(FileExists(atPath: atPath)) { let fileManager = FileManager.default let attributes = try fileManager.attributesOfItem(atPath: atPath) result = attributes[.modificationDate] as? Date } } catch { Log.Critical(err: error, namespace: "Core.System", method: "GetFileCreationDate(string)") } return result } public static func GetOEGDFiles() -> [String] { var result: [String] = [] let storagePath = Core.System.StorageDirectoryPath() ?? "" if (storagePath.count>0) { let fileManager = FileManager.default do{ let files = try fileManager.contentsOfDirectory(atPath: storagePath) for oneFile in files{ if(oneFile.range(of: ".oegd") != nil) { result.append(oneFile) } } } catch let err{ Core.Log.Error(err: err, namespace: "Core.System", method: "GetOEGDFiles") } } return result } public static func GetEncryptedFiles() -> [String] { var result: [String] = [] let storagePath = Core.System.EncryptedStorageDirectoryPath() ?? "" if (storagePath.count>0) { let fileManager = FileManager.default do{ result = try fileManager.contentsOfDirectory(atPath: storagePath) } catch let err{ Core.Log.Error(err: err, namespace: "Core.System", method: "GetEncryptedFiles") } } return result } public static func DeleteAllFiles() -> Bool { //delete all decrypted files var files = GetEncryptedFiles() if(files.count > 0) { for oneFile in files { DeleteFile(atPath: oneFile) } } //delete all OEGD files files = GetOEGDFiles() if(files.count > 0) { for oneFile in files { DeleteFile(atPath: oneFile) } } //delete log and resuld databases let curPath = DatabaseDirectoryPath() ?? "" if (curPath.count > 0) { DeleteFile(atPath: curPath + "/logs.db") DeleteFile(atPath: curPath + "/results.db") } //delete settings-file return DeleteFile(atPath: SettingsPath()) } public static func GenerateQRCode(content: String) -> UIImage { let context = CIContext() let data = Data(content.utf8) let filter = CIFilter.qrCodeGenerator() filter.setValue(data, forKey: "inpuMessage") if let outputImage = filter.outputImage { if let cgimg = context.createCGImage(outputImage, from: outputImage.extent){ return UIImage(cgImage: cgimg) } } return UIImage(systemName: "xmark.circle") ?? UIImage() } } }