Fetching identities from keychain
This commit is contained in:
parent
d093d9662e
commit
7f67752566
@ -20,6 +20,10 @@
|
|||||||
7AF0C51C29EF43CD008D4084 /* TreeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C51B29EF43CD008D4084 /* TreeItem.swift */; };
|
7AF0C51C29EF43CD008D4084 /* TreeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C51B29EF43CD008D4084 /* TreeItem.swift */; };
|
||||||
7AF0C53B29F72151008D4084 /* PlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C53A29F72151008D4084 /* PlistView.swift */; };
|
7AF0C53B29F72151008D4084 /* PlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C53A29F72151008D4084 /* PlistView.swift */; };
|
||||||
7AF0C53D29F9B7FE008D4084 /* Quarantine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C53C29F9B7FE008D4084 /* Quarantine.swift */; };
|
7AF0C53D29F9B7FE008D4084 /* Quarantine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C53C29F9B7FE008D4084 /* Quarantine.swift */; };
|
||||||
|
7AF0C53F29FFB765008D4084 /* SignView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C53E29FFB765008D4084 /* SignView.swift */; };
|
||||||
|
7AF0C54229FFBDB0008D4084 /* SignViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C54129FFBDB0008D4084 /* SignViewModel.swift */; };
|
||||||
|
7AF0C54529FFCAD8008D4084 /* SecError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C54429FFCAD8008D4084 /* SecError.swift */; };
|
||||||
|
7AF0C54729FFCC66008D4084 /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C54629FFCC66008D4084 /* Identity.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -38,6 +42,10 @@
|
|||||||
7AF0C51B29EF43CD008D4084 /* TreeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeItem.swift; sourceTree = "<group>"; };
|
7AF0C51B29EF43CD008D4084 /* TreeItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeItem.swift; sourceTree = "<group>"; };
|
||||||
7AF0C53A29F72151008D4084 /* PlistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlistView.swift; sourceTree = "<group>"; };
|
7AF0C53A29F72151008D4084 /* PlistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlistView.swift; sourceTree = "<group>"; };
|
||||||
7AF0C53C29F9B7FE008D4084 /* Quarantine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Quarantine.swift; sourceTree = "<group>"; };
|
7AF0C53C29F9B7FE008D4084 /* Quarantine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Quarantine.swift; sourceTree = "<group>"; };
|
||||||
|
7AF0C53E29FFB765008D4084 /* SignView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignView.swift; sourceTree = "<group>"; };
|
||||||
|
7AF0C54129FFBDB0008D4084 /* SignViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
7AF0C54429FFCAD8008D4084 /* SecError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecError.swift; sourceTree = "<group>"; };
|
||||||
|
7AF0C54629FFCC66008D4084 /* Identity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Identity.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -63,6 +71,7 @@
|
|||||||
7A064BE529DE17A800C5D978 /* Views */ = {
|
7A064BE529DE17A800C5D978 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
7AF0C54029FFBD93008D4084 /* Sign */,
|
||||||
7AF0C51929EF43C2008D4084 /* OutlineView.swift */,
|
7AF0C51929EF43C2008D4084 /* OutlineView.swift */,
|
||||||
7A064BE829DE18C700C5D978 /* SignInfoView.swift */,
|
7A064BE829DE18C700C5D978 /* SignInfoView.swift */,
|
||||||
7AF0C53A29F72151008D4084 /* PlistView.swift */,
|
7AF0C53A29F72151008D4084 /* PlistView.swift */,
|
||||||
@ -89,14 +98,12 @@
|
|||||||
7A72231129DCABE400503F78 /* reSign */ = {
|
7A72231129DCABE400503F78 /* reSign */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
7AF0C54329FFCABA008D4084 /* Security */,
|
||||||
7AF0C51629EDCF3B008D4084 /* Extensions */,
|
7AF0C51629EDCF3B008D4084 /* Extensions */,
|
||||||
7A064BE529DE17A800C5D978 /* Views */,
|
7A064BE529DE17A800C5D978 /* Views */,
|
||||||
7A064BE129DE0FA900C5D978 /* Models */,
|
7A064BE129DE0FA900C5D978 /* Models */,
|
||||||
7A72231229DCABE400503F78 /* reSignApp.swift */,
|
7A72231229DCABE400503F78 /* reSignApp.swift */,
|
||||||
7A72231429DCABE400503F78 /* ContentView.swift */,
|
7A72231429DCABE400503F78 /* ContentView.swift */,
|
||||||
7A064BEA29DF5BB800C5D978 /* AppPackage.swift */,
|
|
||||||
7A064BEC29E2C91D00C5D978 /* Certificate.swift */,
|
|
||||||
7AF0C53C29F9B7FE008D4084 /* Quarantine.swift */,
|
|
||||||
7A72231629DCABE500503F78 /* Assets.xcassets */,
|
7A72231629DCABE500503F78 /* Assets.xcassets */,
|
||||||
7A72231B29DCABE500503F78 /* reSign.entitlements */,
|
7A72231B29DCABE500503F78 /* reSign.entitlements */,
|
||||||
7A72231829DCABE500503F78 /* Preview Content */,
|
7A72231829DCABE500503F78 /* Preview Content */,
|
||||||
@ -120,6 +127,27 @@
|
|||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
7AF0C54029FFBD93008D4084 /* Sign */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
7AF0C53E29FFB765008D4084 /* SignView.swift */,
|
||||||
|
7AF0C54129FFBDB0008D4084 /* SignViewModel.swift */,
|
||||||
|
);
|
||||||
|
path = Sign;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
7AF0C54329FFCABA008D4084 /* Security */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
7AF0C53C29F9B7FE008D4084 /* Quarantine.swift */,
|
||||||
|
7A064BEC29E2C91D00C5D978 /* Certificate.swift */,
|
||||||
|
7A064BEA29DF5BB800C5D978 /* AppPackage.swift */,
|
||||||
|
7AF0C54429FFCAD8008D4084 /* SecError.swift */,
|
||||||
|
7AF0C54629FFCC66008D4084 /* Identity.swift */,
|
||||||
|
);
|
||||||
|
path = Security;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -196,9 +224,13 @@
|
|||||||
7AF0C51829EDCF59008D4084 /* URL+ExtendedAttributes.swift in Sources */,
|
7AF0C51829EDCF59008D4084 /* URL+ExtendedAttributes.swift in Sources */,
|
||||||
7A064BEB29DF5BB800C5D978 /* AppPackage.swift in Sources */,
|
7A064BEB29DF5BB800C5D978 /* AppPackage.swift in Sources */,
|
||||||
7A064BE929DE18C700C5D978 /* SignInfoView.swift in Sources */,
|
7A064BE929DE18C700C5D978 /* SignInfoView.swift in Sources */,
|
||||||
|
7AF0C54229FFBDB0008D4084 /* SignViewModel.swift in Sources */,
|
||||||
|
7AF0C54729FFCC66008D4084 /* Identity.swift in Sources */,
|
||||||
7A064BED29E2C91D00C5D978 /* Certificate.swift in Sources */,
|
7A064BED29E2C91D00C5D978 /* Certificate.swift in Sources */,
|
||||||
7A72231329DCABE400503F78 /* reSignApp.swift in Sources */,
|
7A72231329DCABE400503F78 /* reSignApp.swift in Sources */,
|
||||||
7AF0C53D29F9B7FE008D4084 /* Quarantine.swift in Sources */,
|
7AF0C53D29F9B7FE008D4084 /* Quarantine.swift in Sources */,
|
||||||
|
7AF0C54529FFCAD8008D4084 /* SecError.swift in Sources */,
|
||||||
|
7AF0C53F29FFB765008D4084 /* SignView.swift in Sources */,
|
||||||
7A064BE429DE107000C5D978 /* Category.swift in Sources */,
|
7A064BE429DE107000C5D978 /* Category.swift in Sources */,
|
||||||
7AF0C51A29EF43C2008D4084 /* OutlineView.swift in Sources */,
|
7AF0C51A29EF43C2008D4084 /* OutlineView.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -43,22 +43,22 @@ struct ContentView: View {
|
|||||||
Button {
|
Button {
|
||||||
openClicked()
|
openClicked()
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "doc")
|
Image(systemName: "plus")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} detail: {
|
} detail: {
|
||||||
if appPackage == nil {
|
if let appPackage {
|
||||||
EmptyView()
|
|
||||||
} else {
|
|
||||||
switch selection?.type {
|
switch selection?.type {
|
||||||
case .signInfo: SignInfoView(appPackage: appPackage!)
|
case .signInfo: SignInfoView(appPackage: appPackage)
|
||||||
case .infoPlist: PlistView(infoPlist: appPackage!.infoPlist)
|
case .infoPlist: PlistView(infoPlist: appPackage.infoPlist)
|
||||||
case .entitlements: PlistView(infoPlist: appPackage!.entitlements)
|
case .entitlements: PlistView(infoPlist: appPackage.entitlements)
|
||||||
case .resign: Text("ReSign")
|
case .resign: SignView(url: appPackage.url)
|
||||||
default: EmptyView()
|
default: EmptyView()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(appPackage?.name ?? "")
|
.navigationTitle(appPackage?.name ?? "")
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
//
|
|
||||||
// Quarantine.swift
|
|
||||||
// reSign
|
|
||||||
//
|
|
||||||
// Created by Мустафаев Селим Мустафаевич on 26.04.2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class Quarantine {
|
|
||||||
|
|
||||||
var flags: Int
|
|
||||||
var date: Date
|
|
||||||
var agent: String
|
|
||||||
var uuid: String
|
|
||||||
|
|
||||||
init?(url: URL) {
|
|
||||||
guard let data = try? url.extendedAttribute(forName: "com.apple.quarantine"),
|
|
||||||
let stringData = String(data: data, encoding: .utf8)
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let parts = stringData.split(separator: ";")
|
|
||||||
|
|
||||||
self.flags = Int(parts[0]) ?? 0
|
|
||||||
self.date = Date(timeIntervalSince1970: TimeInterval(UInt32(parts[1], radix: 16) ?? 0))
|
|
||||||
self.agent = String(parts[2])
|
|
||||||
self.uuid = String(parts[3])
|
|
||||||
|
|
||||||
print(parts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -8,24 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import Security
|
import Security
|
||||||
|
|
||||||
enum SecError: LocalizedError {
|
|
||||||
|
|
||||||
case custom(message: String)
|
|
||||||
case staticCodeNil
|
|
||||||
case designatedRequirementsError
|
|
||||||
case certReadError
|
|
||||||
|
|
||||||
var errorDescription: String? {
|
|
||||||
switch self {
|
|
||||||
case .custom(let message): return message
|
|
||||||
case .staticCodeNil: return "Failed to initialize SecStaticCode"
|
|
||||||
case .designatedRequirementsError: return "Failed to copy designated requirements"
|
|
||||||
case .certReadError: return "Error reading certificate"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AppPackage {
|
class AppPackage {
|
||||||
|
|
||||||
public let url: URL
|
public let url: URL
|
||||||
@ -62,22 +44,11 @@ class AppPackage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.apple.com/documentation/security/1394686-seccopyerrormessagestring
|
|
||||||
func checkResult(_ status: OSStatus) throws {
|
|
||||||
if status != 0 {
|
|
||||||
if let message = SecCopyErrorMessageString(status, nil) {
|
|
||||||
throw SecError.custom(message: message as String)
|
|
||||||
} else {
|
|
||||||
throw NSError(domain: NSOSStatusErrorDomain, code: Int(status))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAppInfo() throws {
|
func getAppInfo() throws {
|
||||||
|
|
||||||
var staticCode: SecStaticCode? = nil
|
var staticCode: SecStaticCode? = nil
|
||||||
var status = SecStaticCodeCreateWithPath(url as CFURL, [], &staticCode)
|
var status = SecStaticCodeCreateWithPath(url as CFURL, [], &staticCode)
|
||||||
try checkResult(status)
|
try SecError.check(status)
|
||||||
|
|
||||||
guard let staticCode else {
|
guard let staticCode else {
|
||||||
throw SecError.staticCodeNil
|
throw SecError.staticCodeNil
|
||||||
@ -90,7 +61,7 @@ class AppPackage {
|
|||||||
]
|
]
|
||||||
|
|
||||||
status = SecCodeCopySigningInformation(staticCode, signInfoFlags, &signingInfo)
|
status = SecCodeCopySigningInformation(staticCode, signInfoFlags, &signingInfo)
|
||||||
try checkResult(status)
|
try SecError.check(status)
|
||||||
|
|
||||||
if let signingInfo = signingInfo as? [String: Any] {
|
if let signingInfo = signingInfo as? [String: Any] {
|
||||||
|
|
||||||
@ -137,12 +108,11 @@ class AppPackage {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let pReqStr: UnsafeMutablePointer<CFString?> = .allocate(capacity: 1)
|
var reqStr: CFString?
|
||||||
defer { pReqStr.deallocate() }
|
let status = SecRequirementCopyString(reqAny as! SecRequirement, [], &reqStr)
|
||||||
let status = SecRequirementCopyString(reqAny as! SecRequirement, [], pReqStr)
|
try SecError.check(status)
|
||||||
try checkResult(status)
|
|
||||||
|
|
||||||
if let reqStr = pReqStr.pointee as? String {
|
if let reqStr = reqStr as? String {
|
||||||
return reqStr
|
return reqStr
|
||||||
}
|
}
|
||||||
|
|
||||||
37
reSign/Security/Identity.swift
Normal file
37
reSign/Security/Identity.swift
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Identity.swift
|
||||||
|
// reSign
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 01.05.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class Identity {
|
||||||
|
|
||||||
|
let identity: SecIdentity
|
||||||
|
let certificate: Certificate
|
||||||
|
|
||||||
|
var name: String {
|
||||||
|
certificate.commonName
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ identity: SecIdentity) throws {
|
||||||
|
|
||||||
|
self.identity = identity
|
||||||
|
self.certificate = try Identity.readCert(from: identity)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func readCert(from identity: SecIdentity) throws -> Certificate {
|
||||||
|
|
||||||
|
var cert: SecCertificate?
|
||||||
|
let result = SecIdentityCopyCertificate(identity, &cert)
|
||||||
|
try SecError.check(result)
|
||||||
|
|
||||||
|
if let cert {
|
||||||
|
return try Certificate(cert)
|
||||||
|
} else {
|
||||||
|
throw SecError.certReadError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
reSign/Security/Quarantine.swift
Normal file
56
reSign/Security/Quarantine.swift
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// Quarantine.swift
|
||||||
|
// reSign
|
||||||
|
//
|
||||||
|
// Created by Мустафаев Селим Мустафаевич on 26.04.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct QuarantineFlags: OptionSet {
|
||||||
|
|
||||||
|
let rawValue: UInt32
|
||||||
|
|
||||||
|
static let download = QuarantineFlags(rawValue: 1 << 0)
|
||||||
|
static let sandbox = QuarantineFlags(rawValue: 1 << 1)
|
||||||
|
static let hard = QuarantineFlags(rawValue: 1 << 2)
|
||||||
|
static let userApproved = QuarantineFlags(rawValue: 1 << 6)
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
var options: [String] = []
|
||||||
|
|
||||||
|
if contains(.download) { options.append("download") }
|
||||||
|
if contains(.sandbox) { options.append("sandbox") }
|
||||||
|
if contains(.hard) { options.append("hard") }
|
||||||
|
if contains(.userApproved) { options.append("userApproved") }
|
||||||
|
|
||||||
|
return options.joined(separator: " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Quarantine {
|
||||||
|
|
||||||
|
var flagsStr: String
|
||||||
|
var flags: QuarantineFlags
|
||||||
|
var date: Date
|
||||||
|
var agent: String
|
||||||
|
var uuid: String
|
||||||
|
|
||||||
|
init?(url: URL) {
|
||||||
|
guard let data = try? url.extendedAttribute(forName: "com.apple.quarantine"),
|
||||||
|
let stringData = String(data: data, encoding: .utf8)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let parts = stringData.split(separator: ";")
|
||||||
|
|
||||||
|
self.flagsStr = String(parts[0])
|
||||||
|
self.flags = QuarantineFlags(rawValue: UInt32(parts[0], radix: 16) ?? 0)
|
||||||
|
self.date = Date(timeIntervalSince1970: TimeInterval(UInt32(parts[1], radix: 16) ?? 0))
|
||||||
|
self.agent = String(parts[2])
|
||||||
|
self.uuid = String(parts[3])
|
||||||
|
|
||||||
|
print(parts)
|
||||||
|
}
|
||||||
|
}
|
||||||
36
reSign/Security/SecError.swift
Normal file
36
reSign/Security/SecError.swift
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// SecError.swift
|
||||||
|
// reSign
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 01.05.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum SecError: LocalizedError {
|
||||||
|
|
||||||
|
case custom(message: String)
|
||||||
|
case staticCodeNil
|
||||||
|
case designatedRequirementsError
|
||||||
|
case certReadError
|
||||||
|
|
||||||
|
var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .custom(let message): return message
|
||||||
|
case .staticCodeNil: return "Failed to initialize SecStaticCode"
|
||||||
|
case .designatedRequirementsError: return "Failed to copy designated requirements"
|
||||||
|
case .certReadError: return "Error reading certificate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://developer.apple.com/documentation/security/1394686-seccopyerrormessagestring
|
||||||
|
static func check(_ status: OSStatus) throws {
|
||||||
|
if status != errSecSuccess {
|
||||||
|
if let message = SecCopyErrorMessageString(status, nil) {
|
||||||
|
throw SecError.custom(message: message as String)
|
||||||
|
} else {
|
||||||
|
throw NSError(domain: NSOSStatusErrorDomain, code: Int(status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
reSign/Views/Sign/SignView.swift
Normal file
25
reSign/Views/Sign/SignView.swift
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// SignView.swift
|
||||||
|
// reSign
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 01.05.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SignView: View {
|
||||||
|
|
||||||
|
let url: URL
|
||||||
|
|
||||||
|
@StateObject var viewModel = SignViewModel()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Text("Hello, World!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SignView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
SignView(url: URL(filePath: ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
40
reSign/Views/Sign/SignViewModel.swift
Normal file
40
reSign/Views/Sign/SignViewModel.swift
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// SignViewModel.swift
|
||||||
|
// reSign
|
||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 01.05.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class SignViewModel: ObservableObject {
|
||||||
|
|
||||||
|
@Published var signingIdentities: [String] = []
|
||||||
|
|
||||||
|
init() {
|
||||||
|
do {
|
||||||
|
self.signingIdentities = try readSigningIdentities()
|
||||||
|
for identity in signingIdentities {
|
||||||
|
print(identity)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("SignViewModel init error: ", error.localizedDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readSigningIdentities() throws -> [String] {
|
||||||
|
var copyResult: CFTypeRef? = nil
|
||||||
|
let result = SecItemCopyMatching([kSecClass: kSecClassIdentity,
|
||||||
|
kSecAttrCanSign: true,
|
||||||
|
kSecAttrCanVerify: true,
|
||||||
|
kSecAttrCanEncrypt: true,
|
||||||
|
kSecMatchLimit: kSecMatchLimitAll,
|
||||||
|
kSecReturnRef: true] as NSDictionary, ©Result)
|
||||||
|
|
||||||
|
if result == errSecSuccess, let secIdentities = copyResult as? [SecIdentity] {
|
||||||
|
return try secIdentities.map(Identity.init).map(\.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -91,7 +91,7 @@ struct SignInfoView: View {
|
|||||||
|
|
||||||
if let quarantine = appPackage.quarantine {
|
if let quarantine = appPackage.quarantine {
|
||||||
Section("Quarantine") {
|
Section("Quarantine") {
|
||||||
FormTextItem(name: "Flags", value: quarantine.flags)
|
FormTextItem(name: "Flags", value: "\(quarantine.flagsStr) (\(quarantine.flags.description))")
|
||||||
FormTextItem(name: "Date", date: quarantine.date)
|
FormTextItem(name: "Date", date: quarantine.date)
|
||||||
FormTextItem(name: "Agent", value: quarantine.agent)
|
FormTextItem(name: "Agent", value: quarantine.agent)
|
||||||
FormTextItem(name: "UUID", value: quarantine.uuid)
|
FormTextItem(name: "UUID", value: quarantine.uuid)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user