Skip to content

Commit

Permalink
feat: signing options rework, some rewritten code
Browse files Browse the repository at this point in the history
feat: all sources section
feat: better sorting options
  • Loading branch information
khcrysalis committed Oct 27, 2024
1 parent df18939 commit 9a6c604
Show file tree
Hide file tree
Showing 34 changed files with 1,482 additions and 1,382 deletions.
20 changes: 6 additions & 14 deletions Shared/Data/UserDefaults/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ enum Preferences {
// Default repo is from the repository
static var defaultRepos: Bool

@Storage(key: "Feather.automaticInstall", defaultValue: true)
static var automaticInstall: Bool

@Storage(key: "Feather.userIntefacerStyle", defaultValue: UIUserInterfaceStyle.unspecified.rawValue)
static var preferredInterfaceStyle: Int

Expand All @@ -42,19 +39,9 @@ enum Preferences {
// random string
static var pPQCheckString: String

@Storage(key: "Feather.fuckOffPpqcheckDetection", defaultValue: true)
static var isFuckingPPqcheckDetectionOff: Bool

@Storage(key: "Feather.autoInstallAfterSign", defaultValue: false)
static var autoInstallAfterSign: Bool

@Storage(key: "Feather.CertificateTitleAppIDtoTeamID", defaultValue: false)
static var certificateTitleAppIDtoTeamID: Bool

@Storage(key: "Feather.idWhitelist", defaultValue: ["kh.crysalis.feather", "kh.crysalis.feather2"])
// Unused
static var idWhitelist: [String]

@Storage(key: "Feather.AppDescriptionAppearence", defaultValue: 0)
// 0 == Default appearence
// 1 == Replace subtitle with localizedDescription
Expand All @@ -65,12 +52,17 @@ enum Preferences {
/// Preferred language
static var preferredLanguageCode: String?


@Storage(key: "Feather.Beta", defaultValue: false)
//
static var beta: Bool

@CodableStorage(key: "SortOption", defaultValue: SortOption.default)
static var currentSortOption: SortOption

@Storage(key: "SortOptionAscending", defaultValue: true)
static var currentSortOptionAscending: Bool
}

// MARK: - Callbacks
fileprivate extension Preferences {
static func preferredLangChangedCallback(newValue: String?) {
Expand Down
27 changes: 8 additions & 19 deletions Shared/Design/SectionIcons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,18 @@ import Nuke

class SectionIcons {
@available(iOS 13.0, *)
static public func sectionIcon(to cell: UITableViewCell, with symbolName: String, gradientColors: [UIColor]) {
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 14, weight: .medium)
static public func sectionIcon(to cell: UITableViewCell, with symbolName: String, backgroundColor: UIColor) {
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 16, weight: .medium)
guard let symbolImage = UIImage(systemName: symbolName, withConfiguration: symbolConfig)?.withTintColor(.white, renderingMode: .alwaysOriginal) else {
return
}
let imageSize = CGSize(width: 42, height: 42)

let insetAmount: CGFloat = 5
let imageSize = CGSize(width: 52, height: 52)
let insetAmount: CGFloat = 7
let scaledSymbolSize = symbolImage.size.aspectFit(in: imageSize, insetBy: insetAmount)

let coloredBackgroundImage = UIGraphicsImageRenderer(size: imageSize).image { context in
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(origin: .zero, size: imageSize)
gradientLayer.colors = gradientColors.map { $0.cgColor }
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)

gradientLayer.render(in: context.cgContext)

// Optionally add rounded corners to the gradient background
let path = UIBezierPath(roundedRect: CGRect(origin: .zero, size: imageSize), cornerRadius: 10)
context.cgContext.addPath(path.cgPath)
context.cgContext.clip()
backgroundColor.setFill()
UIBezierPath(roundedRect: CGRect(origin: .zero, size: imageSize), cornerRadius: 7).fill()
}

let mergedImage = UIGraphicsImageRenderer(size: imageSize).image { context in
Expand All @@ -48,9 +37,9 @@ class SectionIcons {
}

cell.imageView?.image = mergedImage
cell.imageView?.layer.cornerRadius = 10
cell.imageView?.layer.cornerCurve = .continuous
cell.imageView?.layer.cornerRadius = 12
cell.imageView?.clipsToBounds = true
cell.imageView?.layer.borderWidth = 1
cell.imageView?.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.3).cgColor
}

Expand Down
116 changes: 45 additions & 71 deletions Shared/Signing/AppSigner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,7 @@ import UIKit
import AlertKit
import CoreData

struct AppSigningOptions {
var name: String?
var version: String?
var bundleId: String?
var iconURL: UIImage?

var uuid: String
var toInject: [URL]?
var removeInjectPaths: [String]?

var removePlugins: Bool?
var forceFileSharing: Bool?
var removeSupportedDevices: Bool?
var removeURLScheme: Bool?
var forceProMotion: Bool?

var forceForceFullScreen: Bool?
var forceiTunesFileSharing: Bool?
var forceMinimumVersion: String?
var forceLightDarkAppearence: String?
var forceTryToLocalize: Bool?

var removeProvisioningFile: Bool?
var removeWatchPlaceHolder: Bool?

var certificate: Certificate?
}

func signInitialApp(options: AppSigningOptions, appPath: URL, completion: @escaping (Result<(URL, NSManagedObject), Error>) -> Void) {
func signInitialApp(bundle: BundleOptions, mainOptions: SigningMainDataWrapper, signingOptions: SigningDataWrapper, appPath: URL, completion: @escaping (Result<(URL, NSManagedObject), Error>) -> Void) {
UIApplication.shared.isIdleTimerDisabled = true
DispatchQueue(label: "Signing").async {
let fileManager = FileManager.default
Expand All @@ -50,13 +22,15 @@ func signInitialApp(options: AppSigningOptions, appPath: URL, completion: @escap

do {
Debug.shared.log(message: "============================================")
Debug.shared.log(message: "\(options)")
Debug.shared.log(message: "\(mainOptions.mainOptions)")
Debug.shared.log(message: "============================================")
Debug.shared.log(message: "\(signingOptions.signingOptions)")
Debug.shared.log(message: "============================================")
try fileManager.createDirectory(at: tmpDir, withIntermediateDirectories: true)
try fileManager.copyItem(at: appPath, to: tmpDirApp)

if let info = NSDictionary(contentsOf: tmpDirApp.appendingPathComponent("Info.plist"))!.mutableCopy() as? NSMutableDictionary {
try updateInfoPlist(infoDict: info, options: options, icon: options.iconURL, app: tmpDirApp)
try updateInfoPlist(infoDict: info, main: mainOptions, options: signingOptions, icon: mainOptions.mainOptions.iconURL, app: tmpDirApp)

if let iconsDict = info["CFBundleIcons"] as? [String: Any],
let primaryIconsDict = iconsDict["CFBundlePrimaryIcon"] as? [String: Any],
Expand All @@ -66,26 +40,26 @@ func signInitialApp(options: AppSigningOptions, appPath: URL, completion: @escap
}
}

let handler = TweakHandler(urls: options.toInject ?? [], app: tmpDirApp)
let handler = TweakHandler(urls: signingOptions.signingOptions.toInject, app: tmpDirApp)
try handler.getInputFiles()

if let removeInjectPaths = options.removeInjectPaths, !removeInjectPaths.isEmpty {
if let appexe = try TweakHandler.findExecutable(at: tmpDirApp) {
_ = uninstallDylibs(filePath: appexe.path, dylibPaths: removeInjectPaths)
if !mainOptions.mainOptions.removeInjectPaths.isEmpty {
if let appexe = try? TweakHandler.findExecutable(at: tmpDirApp) {
_ = uninstallDylibs(filePath: appexe.path, dylibPaths: mainOptions.mainOptions.removeInjectPaths)
}
}

try updatePlugIns(options: options, app: tmpDirApp)
try removeDumbAssPlaceHolderExtension(options: options, app: tmpDirApp)
try updatePlugIns(options: signingOptions, app: tmpDirApp)
try removeDumbAssPlaceHolderExtension(options: signingOptions, app: tmpDirApp)
try updateMobileProvision(app: tmpDirApp)

let certPath = try CoreDataManager.shared.getCertifcatePath(source: options.certificate)
let provisionPath = certPath.appendingPathComponent("\(options.certificate?.provisionPath ?? "")").path
let p12Path = certPath.appendingPathComponent("\(options.certificate?.p12Path ?? "")").path
let certPath = try CoreDataManager.shared.getCertifcatePath(source: mainOptions.mainOptions.certificate)
let provisionPath = certPath.appendingPathComponent("\(mainOptions.mainOptions.certificate?.provisionPath ?? "")").path
let p12Path = certPath.appendingPathComponent("\(mainOptions.mainOptions.certificate?.p12Path ?? "")").path

Debug.shared.log(message: "🦋 Start Signing 🦋")

try signAppWithZSign(tmpDirApp: tmpDirApp, certPaths: (provisionPath, p12Path), password: options.certificate?.password ?? "", options: options)
try signAppWithZSign(tmpDirApp: tmpDirApp, certPaths: (provisionPath, p12Path), password: mainOptions.mainOptions.certificate?.password ?? "", main: mainOptions, options: signingOptions)

Debug.shared.log(message: "🦋 End Signing 🦋")

Expand All @@ -98,14 +72,14 @@ func signInitialApp(options: AppSigningOptions, appPath: URL, completion: @escap
var signedAppObject: NSManagedObject? = nil

CoreDataManager.shared.addToSignedApps(
version: options.version!,
name: options.name!,
bundleidentifier: options.bundleId!,
version: (mainOptions.mainOptions.version ?? bundle.version)!,
name: (mainOptions.mainOptions.name ?? bundle.name)!,
bundleidentifier: (mainOptions.mainOptions.bundleId ?? bundle.bundleId)!,
iconURL: iconURL,
uuid: signedUUID,
appPath: appPath.lastPathComponent,
timeToLive: options.certificate?.certData?.expirationDate ?? Date(),
teamName: options.certificate?.certData?.name ?? ""
timeToLive: mainOptions.mainOptions.certificate?.certData?.expirationDate ?? Date(),
teamName: mainOptions.mainOptions.certificate?.certData?.name ?? ""
) { result in


Expand All @@ -118,7 +92,7 @@ func signInitialApp(options: AppSigningOptions, appPath: URL, completion: @escap
}
}

Debug.shared.log(message: String.localized("SUCCESS_SIGNED", arguments: "\(options.name ?? String.localized("UNKNOWN"))"), type: .success)
Debug.shared.log(message: String.localized("SUCCESS_SIGNED", arguments: "\((mainOptions.mainOptions.name ?? bundle.name) ?? String.localized("UNKNOWN"))"), type: .success)
Debug.shared.log(message: "============================================")

UIApplication.shared.isIdleTimerDisabled = false
Expand Down Expand Up @@ -146,7 +120,7 @@ func resignApp(certificate: Certificate, appPath: URL, completion: @escaping (Bo
Debug.shared.log(message: "============================================")
Debug.shared.log(message: "🦋 Start Resigning 🦋")

try signAppWithZSign(tmpDirApp: appPath, certPaths: (provisionPath, p12Path), password: certificate.password ?? "", options: nil)
try signAppWithZSign(tmpDirApp: appPath, certPaths: (provisionPath, p12Path), password: certificate.password ?? "")

Debug.shared.log(message: "🦋 End Resigning 🦋")
DispatchQueue.main.async {
Expand All @@ -162,15 +136,15 @@ func resignApp(certificate: Certificate, appPath: URL, completion: @escaping (Bo
}
}

private func signAppWithZSign(tmpDirApp: URL, certPaths: (provisionPath: String, p12Path: String), password: String, options: AppSigningOptions?) throws {
private func signAppWithZSign(tmpDirApp: URL, certPaths: (provisionPath: String, p12Path: String), password: String, main: SigningMainDataWrapper? = nil, options: SigningDataWrapper? = nil) throws {
if zsign(tmpDirApp.path,
certPaths.provisionPath,
certPaths.p12Path,
password,
options?.bundleId ?? "",
options?.name ?? "",
options?.version ?? "",
options?.removeProvisioningFile ?? false
main?.mainOptions.bundleId ?? "",
main?.mainOptions.name ?? "",
main?.mainOptions.version ?? "",
options?.signingOptions.removeProvisioningFile ?? false
) != 0 {
throw NSError(domain: "AppSigningErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: String.localized("ERROR_ZSIGN_FAILED")])
}
Expand Down Expand Up @@ -220,8 +194,8 @@ func uninstallDylibs(filePath: String, dylibPaths: [String]) -> Bool {
}


func updatePlugIns(options: AppSigningOptions, app: URL) throws {
if options.removePlugins! {
func updatePlugIns(options: SigningDataWrapper, app: URL) throws {
if options.signingOptions.removePlugins {
let filemanager = FileManager.default
let path = app.appendingPathComponent("PlugIns")
if filemanager.fileExists(atPath: path.path) {
Expand All @@ -237,8 +211,8 @@ func updatePlugIns(options: AppSigningOptions, app: URL) throws {
}
}

func removeDumbAssPlaceHolderExtension(options: AppSigningOptions, app: URL) throws {
if options.removeWatchPlaceHolder! {
func removeDumbAssPlaceHolderExtension(options: SigningDataWrapper, app: URL) throws {
if options.signingOptions.removeWatchPlaceHolder {
let filemanager = FileManager.default
let path = app.appendingPathComponent("com.apple.WatchPlaceholder")
if filemanager.fileExists(atPath: path.path) {
Expand All @@ -254,16 +228,16 @@ func removeDumbAssPlaceHolderExtension(options: AppSigningOptions, app: URL) thr
}
}

func updateInfoPlist(infoDict: NSMutableDictionary, options: AppSigningOptions, icon: UIImage?, app: URL) throws {
if (options.iconURL != nil) {
func updateInfoPlist(infoDict: NSMutableDictionary, main: SigningMainDataWrapper, options: SigningDataWrapper, icon: UIImage?, app: URL) throws {
if (main.mainOptions.iconURL != nil) {

let imageSizes = [
(width: 120, height: 120, name: "[email protected]"),
(width: 152, height: 152, name: "FRIcon76x76@2x~ipad.png")
]

for imageSize in imageSizes {
let resizedImage = options.iconURL!.resize(imageSize.width, imageSize.height)
let resizedImage = main.mainOptions.iconURL!.resize(imageSize.width, imageSize.height)
let imageData = resizedImage.pngData()
let fileURL = app.appendingPathComponent(imageSize.name)

Expand Down Expand Up @@ -297,24 +271,24 @@ func updateInfoPlist(infoDict: NSMutableDictionary, options: AppSigningOptions,
Debug.shared.log(message: "updateInfoPlist.updateicon: Does not include an icon, skipping!")
}

if options.forceTryToLocalize! {
if options.signingOptions.forceTryToLocalize && (main.mainOptions.name != nil) {
if let displayName = infoDict.value(forKey: "CFBundleDisplayName") as? String {
if displayName != options.name {
updateLocalizedInfoPlist(in: app, newDisplayName: options.name!)
if displayName != main.mainOptions.name {
updateLocalizedInfoPlist(in: app, newDisplayName: main.mainOptions.name!)
}
} else {
Debug.shared.log(message: "updateInfoPlist.displayName: CFBundleDisplayName not found, skipping!")
}
}

if options.forceFileSharing! { infoDict.setObject(true, forKey: "UISupportsDocumentBrowser" as NSCopying) }
if options.forceiTunesFileSharing! { infoDict.setObject(true, forKey: "UIFileSharingEnabled" as NSCopying) }
if options.removeSupportedDevices! { infoDict.removeObject(forKey: "UISupportedDevices") }
if options.removeURLScheme! { infoDict.removeObject(forKey: "CFBundleURLTypes") }
if options.forceProMotion! { infoDict.setObject(true, forKey: "CADisableMinimumFrameDurationOnPhone" as NSCopying)}
if options.forceForceFullScreen! { infoDict.setObject(true, forKey: "UIRequiresFullScreen" as NSCopying) }
if options.forceMinimumVersion! != "Automatic" { infoDict.setObject(options.forceMinimumVersion!, forKey: "MinimumOSVersion" as NSCopying) }
if options.forceLightDarkAppearence! != "Automatic" { infoDict.setObject(options.forceLightDarkAppearence!, forKey: "UIUserInterfaceStyle" as NSCopying)}
if options.signingOptions.forceFileSharing { infoDict.setObject(true, forKey: "UISupportsDocumentBrowser" as NSCopying) }
if options.signingOptions.forceiTunesFileSharing { infoDict.setObject(true, forKey: "UIFileSharingEnabled" as NSCopying) }
if options.signingOptions.removeSupportedDevices { infoDict.removeObject(forKey: "UISupportedDevices") }
if options.signingOptions.removeURLScheme { infoDict.removeObject(forKey: "CFBundleURLTypes") }
if options.signingOptions.forceProMotion { infoDict.setObject(true, forKey: "CADisableMinimumFrameDurationOnPhone" as NSCopying)}
if options.signingOptions.forceForceFullScreen { infoDict.setObject(true, forKey: "UIRequiresFullScreen" as NSCopying) }
if options.signingOptions.forceMinimumVersion != "Automatic" { infoDict.setObject(options.signingOptions.forceMinimumVersion, forKey: "MinimumOSVersion" as NSCopying) }
if options.signingOptions.forceLightDarkAppearence != "Automatic" { infoDict.setObject(options.signingOptions.forceLightDarkAppearence, forKey: "UIUserInterfaceStyle" as NSCopying)}
try infoDict.write(to: app.appendingPathComponent("Info.plist"))
}

Expand Down
15 changes: 8 additions & 7 deletions Shared/Signing/TweakHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ class TweakHandler {

let fileManager = FileManager.default

private var urls: [URL]
private var urls: [String]
private let app: URL
private var urlsToInject: [URL] = []
private var directoriesToCheck: [URL] = []

init(urls: [URL], app: URL) {
init(urls: [String], app: URL) {
self.urls = urls
self.app = app
}
Expand All @@ -38,7 +38,7 @@ class TweakHandler {
let frameworksPath = app.appendingPathComponent("Frameworks").appendingPathComponent("CydiaSubstrate.framework")
if !fileManager.fileExists(atPath: frameworksPath.path) {
if let ellekitURL = Bundle.main.url(forResource: "ellekit", withExtension: "deb") {
self.urls.insert(ellekitURL, at: 0)
self.urls.insert(ellekitURL.absoluteString, at: 0)
} else {
Debug.shared.log(message: "Error: ellekit.deb not found in the app bundle ⁉️", type: .error)
return
Expand All @@ -55,13 +55,14 @@ class TweakHandler {
// it will extract then add a url, if theres no url, i.e.
// you haven't added a deb, it will skip
for url in urls {
switch url.pathExtension.lowercased() {
let urlf = URL(string: url)
switch urlf!.pathExtension.lowercased() {
case "dylib":
try handleDylib(at: url)
try handleDylib(at: urlf!)
case "deb":
try handleDeb(at: url, baseTmpDir: baseTmpDir)
try handleDeb(at: urlf!, baseTmpDir: baseTmpDir)
default:
Debug.shared.log(message: "Unsupported file type: \(url.lastPathComponent), skipping.")
Debug.shared.log(message: "Unsupported file type: \(urlf!.lastPathComponent), skipping.")
}
}

Expand Down
Loading

0 comments on commit 9a6c604

Please sign in to comment.