Displaying Info.plist and entitlements

This commit is contained in:
Selim Mustafaev 2023-04-25 01:45:30 +03:00
parent c02cb61aea
commit 07ece653e9
7 changed files with 344 additions and 5 deletions

View File

@ -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;
};

View File

@ -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] ?? [:]
}
}

View File

@ -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()
}

View 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))])
}
}

View 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 ?? ""
}
}

View 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
}
}

View 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: [:])
}
}