Displaying Info.plist and entitlements
This commit is contained in:
parent
c02cb61aea
commit
07ece653e9
@ -15,6 +15,10 @@
|
||||
7A72231529DCABE400503F78 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A72231429DCABE400503F78 /* ContentView.swift */; };
|
||||
7A72231729DCABE500503F78 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A72231629DCABE500503F78 /* Assets.xcassets */; };
|
||||
7A72231A29DCABE500503F78 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7A72231929DCABE500503F78 /* Preview Assets.xcassets */; };
|
||||
7AF0C51829EDCF59008D4084 /* URL+ExtendedAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C51729EDCF59008D4084 /* URL+ExtendedAttributes.swift */; };
|
||||
7AF0C51A29EF43C2008D4084 /* OutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C51929EF43C2008D4084 /* OutlineView.swift */; };
|
||||
7AF0C51C29EF43CD008D4084 /* TreeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C51B29EF43CD008D4084 /* TreeItem.swift */; };
|
||||
7AF0C53B29F72151008D4084 /* PlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF0C53A29F72151008D4084 /* PlistView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -28,6 +32,10 @@
|
||||
7A72231629DCABE500503F78 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
7A72231929DCABE500503F78 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
7A72231B29DCABE500503F78 /* reSign.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = reSign.entitlements; sourceTree = "<group>"; };
|
||||
7AF0C51729EDCF59008D4084 /* URL+ExtendedAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+ExtendedAttributes.swift"; sourceTree = "<group>"; };
|
||||
7AF0C51929EF43C2008D4084 /* OutlineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutlineView.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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -44,6 +52,7 @@
|
||||
7A064BE129DE0FA900C5D978 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AF0C51B29EF43CD008D4084 /* TreeItem.swift */,
|
||||
7A064BE329DE107000C5D978 /* Category.swift */,
|
||||
);
|
||||
path = Models;
|
||||
@ -52,7 +61,9 @@
|
||||
7A064BE529DE17A800C5D978 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AF0C51929EF43C2008D4084 /* OutlineView.swift */,
|
||||
7A064BE829DE18C700C5D978 /* SignInfoView.swift */,
|
||||
7AF0C53A29F72151008D4084 /* PlistView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -76,6 +87,7 @@
|
||||
7A72231129DCABE400503F78 /* reSign */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AF0C51629EDCF3B008D4084 /* Extensions */,
|
||||
7A064BE529DE17A800C5D978 /* Views */,
|
||||
7A064BE129DE0FA900C5D978 /* Models */,
|
||||
7A72231229DCABE400503F78 /* reSignApp.swift */,
|
||||
@ -97,6 +109,14 @@
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7AF0C51629EDCF3B008D4084 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AF0C51729EDCF59008D4084 /* URL+ExtendedAttributes.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -168,11 +188,15 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7A72231529DCABE400503F78 /* ContentView.swift in Sources */,
|
||||
7AF0C53B29F72151008D4084 /* PlistView.swift in Sources */,
|
||||
7AF0C51C29EF43CD008D4084 /* TreeItem.swift in Sources */,
|
||||
7AF0C51829EDCF59008D4084 /* URL+ExtendedAttributes.swift in Sources */,
|
||||
7A064BEB29DF5BB800C5D978 /* AppPackage.swift in Sources */,
|
||||
7A064BE929DE18C700C5D978 /* SignInfoView.swift in Sources */,
|
||||
7A064BED29E2C91D00C5D978 /* Certificate.swift in Sources */,
|
||||
7A72231329DCABE400503F78 /* reSignApp.swift in Sources */,
|
||||
7A064BE429DE107000C5D978 /* Category.swift in Sources */,
|
||||
7AF0C51A29EF43C2008D4084 /* OutlineView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@ -46,6 +46,8 @@ class AppPackage {
|
||||
var designatedRequirements: String?
|
||||
var implicitRequirements: String?
|
||||
var certificates: [Certificate]?
|
||||
var infoPlist: [String: Any] = [:]
|
||||
var entitlements: [String: Any] = [:]
|
||||
|
||||
init(url: URL) {
|
||||
|
||||
@ -105,9 +107,8 @@ class AppPackage {
|
||||
designatedRequirements = try getRequirements(from: signingInfo, key: kSecCodeInfoDesignatedRequirement)
|
||||
implicitRequirements = try getRequirements(from: signingInfo, key: kSecCodeInfoImplicitDesignatedRequirement)
|
||||
certificates = try getCertificates(from: signingInfo)
|
||||
|
||||
let infoPlist = signingInfo[kSecCodeInfoPList as String]
|
||||
print(infoPlist)
|
||||
infoPlist = signingInfo[kSecCodeInfoPList as String] as? [String: Any] ?? [:]
|
||||
entitlements = signingInfo[kSecCodeInfoEntitlementsDict as String] as? [String: Any] ?? [:]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -54,8 +54,8 @@ struct ContentView: View {
|
||||
} else {
|
||||
switch selection?.type {
|
||||
case .signInfo: SignInfoView(appPackage: appPackage!)
|
||||
case .infoPlist: Text("Info.plist")
|
||||
case .entitlements: Text("Entitlements")
|
||||
case .infoPlist: PlistView(infoPlist: appPackage!.infoPlist)
|
||||
case .entitlements: PlistView(infoPlist: appPackage!.entitlements)
|
||||
case .resign: Text("ReSign")
|
||||
default: EmptyView()
|
||||
}
|
||||
|
||||
93
reSign/Extensions/URL+ExtendedAttributes.swift
Normal file
93
reSign/Extensions/URL+ExtendedAttributes.swift
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// URL+ExtendedAttributes.swift
|
||||
// reSign
|
||||
//
|
||||
// Created by Selim Mustafaev on 17.04.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension URL {
|
||||
|
||||
/// Get extended attribute.
|
||||
func extendedAttribute(forName name: String) throws -> Data? {
|
||||
|
||||
let data = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> Data? in
|
||||
|
||||
// Determine attribute size:
|
||||
let length = getxattr(fileSystemPath, name, nil, 0, 0, 0)
|
||||
|
||||
guard length >= 0 else {
|
||||
if length == ENOATTR {
|
||||
return nil
|
||||
} else {
|
||||
throw URL.posixError(errno)
|
||||
}
|
||||
}
|
||||
|
||||
// Create buffer with required size:
|
||||
var data = Data(count: length)
|
||||
|
||||
// Retrieve attribute:
|
||||
let result = data.withUnsafeMutableBytes { [count = data.count] in
|
||||
getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0)
|
||||
}
|
||||
guard result >= 0 else { throw URL.posixError(errno) }
|
||||
return data
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
/// Set extended attribute.
|
||||
func setExtendedAttribute(data: Data, forName name: String) throws {
|
||||
|
||||
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
|
||||
let result = data.withUnsafeBytes {
|
||||
setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0)
|
||||
}
|
||||
guard result >= 0 else { throw URL.posixError(errno) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove extended attribute.
|
||||
func removeExtendedAttribute(forName name: String) throws {
|
||||
|
||||
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
|
||||
let result = removexattr(fileSystemPath, name, 0)
|
||||
guard result >= 0 else { throw URL.posixError(errno) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Get list of all extended attributes.
|
||||
func listExtendedAttributes() throws -> [String] {
|
||||
|
||||
let list = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in
|
||||
let length = listxattr(fileSystemPath, nil, 0, 0)
|
||||
guard length >= 0 else { throw URL.posixError(errno) }
|
||||
|
||||
// Create buffer with required size:
|
||||
var namebuf = Array<CChar>(repeating: 0, count: length)
|
||||
|
||||
// Retrieve attribute list:
|
||||
let result = listxattr(fileSystemPath, &namebuf, namebuf.count, 0)
|
||||
guard result >= 0 else { throw URL.posixError(errno) }
|
||||
|
||||
// Extract attribute names:
|
||||
let list = namebuf.split(separator: 0).compactMap {
|
||||
$0.withUnsafeBufferPointer {
|
||||
$0.withMemoryRebound(to: UInt8.self) {
|
||||
String(bytes: $0, encoding: .utf8)
|
||||
}
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/// Helper function to create an NSError from a Unix errno.
|
||||
private static func posixError(_ err: Int32) -> NSError {
|
||||
return NSError(domain: NSPOSIXErrorDomain, code: Int(err),
|
||||
userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))])
|
||||
}
|
||||
}
|
||||
89
reSign/Models/TreeItem.swift
Normal file
89
reSign/Models/TreeItem.swift
Normal file
@ -0,0 +1,89 @@
|
||||
//
|
||||
// TreeItem.swift
|
||||
// OutlineTest
|
||||
//
|
||||
// Created by Мустафаев Селим Мустафаевич on 11.04.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum DictValue: CustomStringConvertible {
|
||||
|
||||
case string(value: String)
|
||||
case number(value: Int)
|
||||
case bool(value: Bool)
|
||||
case array(value: [DictNode])
|
||||
case dictionary(value: [DictNode])
|
||||
case unknown
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .string(let value): return value
|
||||
case .number(let value): return String(value)
|
||||
case .bool(let value): return value ? "True" : "False"
|
||||
case .array(let value): return "\(value.count) item(s)"
|
||||
case .dictionary(let value): return "\(value.count) item(s)"
|
||||
case .unknown: return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
var type: String {
|
||||
switch self {
|
||||
case .string: return "String"
|
||||
case .number: return "Number"
|
||||
case .bool: return "Boolean"
|
||||
case .array: return "Array"
|
||||
case .dictionary: return "Dictionary"
|
||||
case .unknown: return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
var isReal: Bool {
|
||||
switch self {
|
||||
case .string, .number, .bool: return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DictNode: Identifiable {
|
||||
|
||||
var name: String?
|
||||
var value: DictValue?
|
||||
var children: [DictNode] = []
|
||||
|
||||
init(name: String?, value: Any?) {
|
||||
|
||||
self.name = name
|
||||
|
||||
switch value {
|
||||
case let stringVal as String:
|
||||
self.value = .string(value: stringVal)
|
||||
case let numVal as Int:
|
||||
self.value = .number(value: numVal)
|
||||
case let boolVal as Bool:
|
||||
self.value = .bool(value: boolVal)
|
||||
case let dict as [String: Any]:
|
||||
self.children = dict.map { DictNode(name: $0.key, value: $0.value) }
|
||||
self.value = .dictionary(value: self.children)
|
||||
case let array as [Any]:
|
||||
self.children = array.enumerated().map { (index, element) in
|
||||
DictNode(name: "Item \(index)", value: element)
|
||||
}
|
||||
self.value = .array(value: self.children)
|
||||
default:
|
||||
self.value = .unknown
|
||||
}
|
||||
}
|
||||
|
||||
init(dict: [String: Any]) {
|
||||
|
||||
self.name = "Root"
|
||||
self.children = dict.map { DictNode(name: $0.key, value: $0.value) }
|
||||
}
|
||||
|
||||
|
||||
var id: String {
|
||||
name ?? ""
|
||||
}
|
||||
}
|
||||
109
reSign/Views/OutlineView.swift
Normal file
109
reSign/Views/OutlineView.swift
Normal file
@ -0,0 +1,109 @@
|
||||
//
|
||||
// OutlineView.swift
|
||||
// OutlineTest
|
||||
//
|
||||
// Created by Мустафаев Селим Мустафаевич on 12.04.2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct OutlineView: NSViewRepresentable {
|
||||
|
||||
|
||||
let datasource: OutlineViewDataSource
|
||||
|
||||
init(rootNode: DictNode) {
|
||||
self.datasource = OutlineViewDataSource(data: rootNode)
|
||||
}
|
||||
|
||||
func makeNSView(context: Context) -> some NSView {
|
||||
let view = NSOutlineView()
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.dataSource = datasource
|
||||
view.delegate = datasource
|
||||
view.usesAlternatingRowBackgroundColors = true
|
||||
view.addTableColumn(createColumn(id: "Key", minWidth: 250))
|
||||
view.addTableColumn(createColumn(id: "Type", minWidth: 30))
|
||||
view.addTableColumn(createColumn(id: "Value", minWidth: 150))
|
||||
|
||||
let scroll = NSScrollView()
|
||||
scroll.documentView = view
|
||||
scroll.hasHorizontalScroller = false
|
||||
scroll.hasVerticalScroller = true
|
||||
|
||||
return scroll
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: NSViewType, context: Context) {
|
||||
|
||||
}
|
||||
|
||||
func createColumn(id: String, minWidth: CGFloat) -> NSTableColumn {
|
||||
let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: id))
|
||||
column.title = id
|
||||
column.minWidth = minWidth
|
||||
return column
|
||||
}
|
||||
}
|
||||
|
||||
@objc class OutlineViewDataSource: NSObject, NSOutlineViewDataSource, NSOutlineViewDelegate {
|
||||
|
||||
let data: DictNode
|
||||
|
||||
init(data: DictNode) {
|
||||
self.data = data
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
||||
guard let item = item as? DictNode else {
|
||||
return data.children[index]
|
||||
}
|
||||
|
||||
return item.children[index]
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
||||
guard let item = item as? DictNode else {
|
||||
return data.children.count
|
||||
}
|
||||
|
||||
return item.children.count
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
||||
guard let item = item as? DictNode else {
|
||||
return false
|
||||
}
|
||||
|
||||
return !item.children.isEmpty
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
||||
guard let item = item as? DictNode else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let value: String
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "Key": value = item.name ?? ""
|
||||
case "Type": value = item.value?.type ?? ""
|
||||
case "Value": value = item.value?.description ?? ""
|
||||
default: value = ""
|
||||
}
|
||||
|
||||
let shouldDeEmphasize = item.value?.isReal != true
|
||||
&& tableColumn?.identifier.rawValue == "Value"
|
||||
|
||||
let text = NSTextField(labelWithString: value)
|
||||
text.textColor = shouldDeEmphasize ? .secondaryLabelColor : .labelColor
|
||||
let cell = NSTableCellView()
|
||||
cell.addSubview(text)
|
||||
text.drawsBackground = false
|
||||
text.isBordered = false
|
||||
text.translatesAutoresizingMaskIntoConstraints = false
|
||||
cell.addConstraint(NSLayoutConstraint(item: text, attribute: .centerY, relatedBy: .equal, toItem: cell, attribute: .centerY, multiplier: 1, constant: 0))
|
||||
cell.addConstraint(NSLayoutConstraint(item: text, attribute: .left, relatedBy: .equal, toItem: cell, attribute: .left, multiplier: 1, constant: 13))
|
||||
cell.addConstraint(NSLayoutConstraint(item: text, attribute: .right, relatedBy: .equal, toItem: cell, attribute: .right, multiplier: 1, constant: -13))
|
||||
return cell
|
||||
}
|
||||
}
|
||||
23
reSign/Views/PlistView.swift
Normal file
23
reSign/Views/PlistView.swift
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// PlistView.swift
|
||||
// reSign
|
||||
//
|
||||
// Created by Selim Mustafaev on 24.04.2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct PlistView: View {
|
||||
|
||||
var infoPlist: [String: Any]
|
||||
|
||||
var body: some View {
|
||||
OutlineView(rootNode: DictNode(dict: infoPlist))
|
||||
}
|
||||
}
|
||||
|
||||
struct InfoPlistView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PlistView(infoPlist: [:])
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user