//
//  Exploit.swift
//  TrollInstallerX
//
//  Created by Alfie on 22/03/2024.
//

import Foundation

enum ExploitType {
    case kernel
    case ppl
    case cow
}

struct ExploitVersion {
    let minimumVersion: Version
    let maximumVersion: Version
}

struct Exploit {
    let name: String
    let type: ExploitType
    
    let supported: [ExploitVersion]
    
    let initialise: (@convention(c) () -> Bool)?
    let deinitialise: (@convention(c) () -> Bool)?
    
    let unsandbox: (@convention(c) () -> Bool)?
    
    let overwrite: (@convention(c) (_ file: String, _ data: Data) -> Bool)?
    
    init(name: String, type: ExploitType, supported: [ExploitVersion],
         initialise: (@convention(c) () -> Bool)? = nil,
         deinitialise: (@convention(c) () -> Bool)? = nil,
         unsandbox: (@convention(c) () -> Bool)? = nil,
         overwrite: (@convention(c) (_ file: String, _ data: Data) -> Bool)? = nil
    ) {
        self.name = name
        self.type = type
        self.supported = supported
        self.initialise = initialise
        self.deinitialise = deinitialise
        self.unsandbox = unsandbox
        self.overwrite = overwrite
        
    }
    
    func supports(_ device: Device) -> Bool {
        for versions in self.supported {
            if device.version >= versions.minimumVersion
                && device.version < versions.maximumVersion {
                return true
            }
        }
        return false
    }
}

struct KernelExploit {
    let name: String
    let type: ExploitType
    
    let supported: [ExploitVersion]
    
    let initialise: (@convention(c) () -> Bool)
    let deinitialise: (@convention(c) () -> Bool)
    
    let supports17Betas: Bool
    
    init(name: String, type: ExploitType, supported: [ExploitVersion],
         initialise: (@convention(c) () -> Bool),
         deinitialise: (@convention(c) () -> Bool),
         supports17Betas: Bool = false
    ) {
        self.name = name
        self.type = type
        self.supported = supported
        self.initialise = initialise
        self.deinitialise = deinitialise
        self.supports17Betas = supports17Betas
        
    }
    
    func supports(_ device: Device) -> Bool {
        for versions in self.supported {
            if (device.version >= versions.minimumVersion
                && device.version <= versions.maximumVersion)
                || (device.isOnSupported17Beta && self.supports17Betas) {
                return true
            }
        }
        return false
    }
}

typealias PPLBypass = KernelExploit

struct CoWExploit {
    let name: String
    let type: ExploitType
    
    let supported: [ExploitVersion]
    
    init(name: String, type: ExploitType, supported: [ExploitVersion]
    ) {
        self.name = name
        self.type = type
        self.supported = supported
        
    }
    
    func supports(_ device: Device) -> Bool {
        for versions in self.supported {
            if device.version >= versions.minimumVersion
                && device.version < versions.maximumVersion {
                return true
            }
        }
        return false
    }
}

/*
 Kernel exploits
 */

// physpuppet
let physpuppet = KernelExploit(
    name: "physpuppet",
    type: .kernel,
    supported: [
        ExploitVersion(minimumVersion: Version("14.0"), maximumVersion: Version("15.7.3")),
        ExploitVersion(minimumVersion: Version("16.0"), maximumVersion: Version("16.3.1"))
    ],
    initialise: krw_init_physpuppet,
    deinitialise: krw_deinit)

// smith
let smith = KernelExploit(
    name: "smith",
    type: .kernel,
    supported: [
        ExploitVersion(minimumVersion: Version("16.0"), maximumVersion: Version("16.5"))
    ],
    initialise: krw_init_smith,
    deinitialise: krw_deinit)

// landa
let landa = KernelExploit(
    name: "landa",
    type: .kernel,
    supported: [
        ExploitVersion(minimumVersion: Version("14.0"), maximumVersion: Version("16.6.1"))
    ],
    initialise: krw_init_landa,
    deinitialise: krw_deinit,
    supports17Betas: true)


/*
 PPL bypass
 */

// dmaFail
let dmaFail = PPLBypass(
    name: "dmaFail",
    type: .ppl,
    supported: [
        ExploitVersion(minimumVersion: Version("15.2"), maximumVersion: Version("16.5.1"))
    ],
    initialise: PPLRW_init,
    deinitialise: PPLRW_deinit)

/*
 CoW exploit
 */

// MacDirtyCow
let MacDirtyCow = CoWExploit(
    name: "MacDirtyCow",
    type: .cow,
    supported: [
        ExploitVersion(minimumVersion: Version("15.0"),
                       maximumVersion: Version("15.7.1")),
        ExploitVersion(minimumVersion: Version("16.0"),
                       maximumVersion: Version("16.1.2"))
    ]
)
