From 41dcbe8ba094db1689c4d5349cf6115cfbdfd959 Mon Sep 17 00:00:00 2001 From: Daniel Radtke Date: Sat, 14 Nov 2015 22:36:06 -0600 Subject: [PATCH] 1.0b9 * Log to a file * Added the ability to view log * Click the status label to open a finder window to the output file location * Added placeholder messages to the text fields * Added link to the GitHub project in the Help menu * Feeling generous? Buy me a drink (Donate in the menu bar) --- AppSigner/AppDelegate.swift | 13 ++++- AppSigner/Base.lproj/Main.storyboard | 70 +++++++++++++++++------- AppSigner/Info.plist | 2 +- AppSigner/ViewController.swift | 53 +++++++++++------- Log.swift | 32 +++++++++++ NSMenuLink.swift | 14 +++++ ProvisioningProfile.swift | 12 ++-- iOS App Signer.xcodeproj/project.pbxproj | 8 +++ 8 files changed, 155 insertions(+), 49 deletions(-) create mode 100644 Log.swift create mode 100644 NSMenuLink.swift diff --git a/AppSigner/AppDelegate.swift b/AppSigner/AppDelegate.swift index e186653..b278b9f 100644 --- a/AppSigner/AppDelegate.swift +++ b/AppSigner/AppDelegate.swift @@ -11,20 +11,27 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - - + let fileManager = NSFileManager.defaultManager() + + func applicationDidFinishLaunching(aNotification: NSNotification) { // Insert code here to initialize your application } func applicationWillTerminate(aNotification: NSNotification) { // Insert code here to tear down your application + try? fileManager.removeItemAtPath(Log.logName) } func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool { return true } - + @IBAction func nsMenuLinkClick(sender: NSMenuLink) { + NSWorkspace.sharedWorkspace().openURL(NSURL(string: sender.url!)!) + } + @IBAction func viewLog(sender: AnyObject) { + NSWorkspace.sharedWorkspace().openFile(Log.logName) + } } diff --git a/AppSigner/Base.lproj/Main.storyboard b/AppSigner/Base.lproj/Main.storyboard index 7db9287..a66cdf1 100644 --- a/AppSigner/Base.lproj/Main.storyboard +++ b/AppSigner/Base.lproj/Main.storyboard @@ -1,7 +1,8 @@ - + - + + @@ -21,13 +22,6 @@ - - - - - - - @@ -54,12 +48,30 @@ - + + + + + + + + + + + + + - + - + + + + + + + @@ -68,9 +80,12 @@ - + + + + - + @@ -82,7 +97,7 @@ - + @@ -110,7 +125,7 @@ - + @@ -127,7 +142,7 @@ - + @@ -230,7 +245,7 @@ - + @@ -243,7 +258,7 @@ - + @@ -258,10 +273,25 @@ + + @@ -285,11 +315,13 @@ + + diff --git a/AppSigner/Info.plist b/AppSigner/Info.plist index b0e6f09..132c244 100644 --- a/AppSigner/Info.plist +++ b/AppSigner/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0b8 + 1.0b9 CFBundleSignature ???? CFBundleVersion diff --git a/AppSigner/ViewController.swift b/AppSigner/ViewController.swift index 30f5ee3..8348310 100644 --- a/AppSigner/ViewController.swift +++ b/AppSigner/ViewController.swift @@ -35,6 +35,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe let defaults = NSUserDefaults() let fileManager = NSFileManager.defaultManager() let bundleID = NSBundle.mainBundle().bundleIdentifier + let delegate = NSApplication.sharedApplication().delegate as! AppDelegate let arPath = "/usr/bin/ar" let mktempPath = "/usr/bin/mktemp" let tarPath = "/usr/bin/tar" @@ -54,7 +55,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe populateCodesigningCerts() if let defaultCert = defaults.stringForKey("signingCertificate") { if codesigningCerts.contains(defaultCert) { - NSLog("Loaded Codesigning Certificate from Defaults: \(defaultCert)") + Log.write("Loaded Codesigning Certificate from Defaults: \(defaultCert)") CodesigningCertsPopup.selectItemWithTitle(defaultCert) } } @@ -63,7 +64,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe } func setStatus(status: String){ - NSLog(status) + Log.write(status) StatusLabel.stringValue = status } @@ -190,7 +191,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe try fileManager.removeItemAtPath(tempFolder) } catch let error as NSError { setStatus("Unable to delete temp folder") - NSLog(error.localizedDescription) + Log.write(error.localizedDescription) } controlsEnabled(true) } @@ -218,7 +219,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe try fileManager.moveItemAtURL(location, toURL: NSURL(fileURLWithPath: downloadPath)) } catch let error as NSError { setStatus("Unable to move downloaded file") - NSLog(error.localizedDescription) + Log.write(error.localizedDescription) } } downloading = false @@ -252,6 +253,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe func signingThread(){ + //MARK: Set up variables var warnings = 0 var inputFile = InputFileText.stringValue @@ -292,9 +294,9 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe let payloadDirectory = workingDirectory.stringByAppendingPathComponent("Payload/") let entitlementsPlist = tempFolder.stringByAppendingPathComponent("entitlements.plist") - NSLog("Temp folder: \(tempFolder)") - NSLog("Working directory: \(workingDirectory)") - NSLog("Payload directory: \(payloadDirectory)") + Log.write("Temp folder: \(tempFolder)") + Log.write("Working directory: \(workingDirectory)") + Log.write("Payload directory: \(payloadDirectory)") //MARK: Download file downloading = false @@ -336,7 +338,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe try fileManager.createDirectoryAtPath(workingDirectory, withIntermediateDirectories: true, attributes: nil) setStatus("Extracting deb file") let debTask = NSTask().execute(arPath, workingDirectory: debPath, arguments: ["-x", inputFile]) - NSLog(debTask.output) + Log.write(debTask.output) if debTask.status != 0 { setStatus("Error processing deb file") cleanup(tempFolder); return @@ -349,7 +351,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe setStatus("Unpacking data.\(tarFormat)") let tarTask = NSTask().execute(tarPath, workingDirectory: debPath, arguments: ["-xf",dataPath]) - NSLog(tarTask.output) + Log.write(tarTask.output) if tarTask.status == 0 { tarUnpacked = true } @@ -441,7 +443,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe if codesignTask.status != 0 { setStatus("Error codesigning \(shortName)") warnings++ - NSLog(codesignTask.output) + Log.write(codesignTask.output) } } return output @@ -464,7 +466,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe let useAppBundleProfile = (provisioningFile == nil && fileManager.fileExistsAtPath(appBundleProvisioningFilePath)) //MARK: Delete CFBundleResourceSpecification from Info.plist - NSLog(NSTask().execute(defaultsPath, workingDirectory: nil, arguments: ["delete",appBundleInfoPlist,"CFBundleResourceSpecification"]).output) + Log.write(NSTask().execute(defaultsPath, workingDirectory: nil, arguments: ["delete",appBundleInfoPlist,"CFBundleResourceSpecification"]).output) //MARK: Copy Provisioning Profile if provisioningFile != nil { @@ -474,7 +476,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe try fileManager.removeItemAtPath(appBundleProvisioningFilePath) } catch let error as NSError { setStatus("Error deleting embedded.mobileprovision") - NSLog(error.localizedDescription) + Log.write(error.localizedDescription) cleanup(tempFolder); return } } @@ -483,7 +485,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe try fileManager.copyItemAtPath(provisioningFile!, toPath: appBundleProvisioningFilePath) } catch let error as NSError { setStatus("Error copying provisioning profile") - NSLog(error.localizedDescription) + Log.write(error.localizedDescription) cleanup(tempFolder); return } } @@ -494,9 +496,9 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe if let profile = ProvisioningProfile(filename: useAppBundleProfile ? appBundleProvisioningFilePath : provisioningFile!){ if let entitlements = profile.getEntitlementsPlist() { - NSLog("-----------------------") - NSLog("\(entitlements)") - NSLog("-----------------------") + Log.write("-----------------------") + Log.write("\(entitlements)") + Log.write("-----------------------") do { try entitlements.writeToFile(entitlementsPlist, atomically: false, encoding: NSUTF8StringEncoding) setStatus("Saved entitlements to \(entitlementsPlist)") @@ -524,7 +526,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe let IDChangeTask = NSTask().execute(defaultsPath, workingDirectory: nil, arguments: ["write",appBundleInfoPlist,"CFBundleIdentifier", newApplicationID]) if IDChangeTask.status != 0 { setStatus("Error changing App ID") - NSLog(IDChangeTask.output) + Log.write(IDChangeTask.output) cleanup(tempFolder); return } } @@ -535,7 +537,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe let displayNameChangeTask = NSTask().execute(defaultsPath, workingDirectory: nil, arguments: ["write",appBundleInfoPlist,"CFBundleDisplayName", newDisplayName]) if displayNameChangeTask.status != 0 { setStatus("Error changing display name") - NSLog(displayNameChangeTask.output) + Log.write(displayNameChangeTask.output) cleanup(tempFolder); return } } @@ -549,7 +551,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe } } catch let error as NSError { setStatus("Error listing files in payload directory") - NSLog(error.localizedDescription) + Log.write(error.localizedDescription) cleanup(tempFolder); return } @@ -560,7 +562,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe try fileManager.removeItemAtPath(outputFile!) } catch let error as NSError { setStatus("Error deleting output file") - NSLog(error.localizedDescription) + Log.write(error.localizedDescription) cleanup(tempFolder); return } } @@ -630,7 +632,7 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe } } @IBAction func chooseSigningCertificate(sender: NSPopUpButton) { - NSLog("Set Codesigning Certificate Default to: \(sender.stringValue)") + Log.write("Set Codesigning Certificate Default to: \(sender.stringValue)") defaults.setValue(sender.selectedItem?.title, forKey: "signingCertificate") } @@ -639,5 +641,14 @@ class ViewController: NSViewController, NSURLSessionDataDelegate, NSURLSessionDe startSigning() //NSThread.detachNewThreadSelector(Selector("signingThread"), toTarget: self, withObject: nil) } + + @IBAction func statusLabelClick(sender: NSButton) { + if let outputFile = self.outputFile { + if fileManager.fileExistsAtPath(outputFile) { + NSWorkspace.sharedWorkspace().activateFileViewerSelectingURLs([NSURL(fileURLWithPath: outputFile)]) + } + } + } + } diff --git a/Log.swift b/Log.swift new file mode 100644 index 0000000..3d676f7 --- /dev/null +++ b/Log.swift @@ -0,0 +1,32 @@ +// +// Log.swift +// iOS App Signer +// +// Created by Daniel Radtke on 11/14/15. +// Copyright © 2015 Daniel Radtke. All rights reserved. +// + +import Foundation +class Log { + static let mainBundle = NSBundle.mainBundle() + static let bundleID = mainBundle.bundleIdentifier + static let bundleName = mainBundle.infoDictionary!["CFBundleName"] + static let bundleVersion = mainBundle.infoDictionary!["CFBundleShortVersionString"] + static let tempDirectory = NSTemporaryDirectory() + static var logName = Log.tempDirectory.stringByAppendingPathComponent("\(Log.bundleID!)-\(NSDate().timeIntervalSince1970).log") + + static func write(value:String) { + let formatter = NSDateFormatter() + formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + + + if let outputStream = NSOutputStream(toFileAtPath: logName, append: true) { + outputStream.open() + let text = "\(formatter.stringFromDate(NSDate())) \(value)\n" + let data = text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! + outputStream.write(UnsafePointer(data.bytes), maxLength: data.length) + outputStream.close() + } + NSLog(value) + } +} \ No newline at end of file diff --git a/NSMenuLink.swift b/NSMenuLink.swift new file mode 100644 index 0000000..9db7e4a --- /dev/null +++ b/NSMenuLink.swift @@ -0,0 +1,14 @@ +// +// NSMenuLink.swift +// iOS App Signer +// +// Created by Daniel Radtke on 11/14/15. +// Copyright © 2015 Daniel Radtke. All rights reserved. +// + +import Foundation +import AppKit + +class NSMenuLink: NSMenuItem { + @IBInspectable var url: String? +} \ No newline at end of file diff --git a/ProvisioningProfile.swift b/ProvisioningProfile.swift index 0ea2639..cefdc2a 100644 --- a/ProvisioningProfile.swift +++ b/ProvisioningProfile.swift @@ -7,12 +7,14 @@ // import Foundation +import AppKit struct ProvisioningProfile { var filename: String, expires: NSDate, appID: String, teamID: String, entitlements: AnyObject? + private let delegate = NSApplication.sharedApplication().delegate as! AppDelegate static func getProfiles() -> [ProvisioningProfile] { var output: [ProvisioningProfile] = [] @@ -54,15 +56,15 @@ struct ProvisioningProfile { self.teamID = teamIdentifier self.entitlements = entitlements } else { - NSLog("Error processing \(filename.lastPathComponent)") + Log.write("Error processing \(filename.lastPathComponent)") return nil } } else { - NSLog("Error parsing \(filename.lastPathComponent)") + Log.write("Error parsing \(filename.lastPathComponent)") return nil } } else { - NSLog("Error reading \(filename.lastPathComponent)") + Log.write("Error reading \(filename.lastPathComponent)") return nil } } @@ -72,8 +74,8 @@ struct ProvisioningProfile { let plistData = try NSPropertyListSerialization.dataWithPropertyList(self.entitlements!, format: .XMLFormat_v1_0, options: 0) return NSString(data: plistData, encoding: NSUTF8StringEncoding) } catch let error as NSError { - NSLog("Error reading entitlements from \(filename.lastPathComponent)") - NSLog(error.localizedDescription) + Log.write("Error reading entitlements from \(filename.lastPathComponent)") + Log.write(error.localizedDescription) return nil } } diff --git a/iOS App Signer.xcodeproj/project.pbxproj b/iOS App Signer.xcodeproj/project.pbxproj index 9017406..c1eaa00 100644 --- a/iOS App Signer.xcodeproj/project.pbxproj +++ b/iOS App Signer.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 652408D31BE743D4006FA4C6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 652408D11BE743D4006FA4C6 /* Main.storyboard */; }; 652408DE1BE743D4006FA4C6 /* AppSignerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652408DD1BE743D4006FA4C6 /* AppSignerTests.swift */; }; 652408E91BE743D4006FA4C6 /* AppSignerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652408E81BE743D4006FA4C6 /* AppSignerUITests.swift */; }; + 65311EAE1BF8259000516EFD /* NSMenuLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65311EAD1BF8259000516EFD /* NSMenuLink.swift */; }; + 65311EB01BF835F100516EFD /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65311EAF1BF835F100516EFD /* Log.swift */; }; 655FFF9D1BE9B3E300D43AD8 /* NSTask-execute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 655FFF9C1BE9B3E300D43AD8 /* NSTask-execute.swift */; }; 655FFF9F1BE9BA9D00D43AD8 /* StringByAppendingPathComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 655FFF9E1BE9BA9D00D43AD8 /* StringByAppendingPathComponent.swift */; }; 655FFFA21BEAD93600D43AD8 /* ProvisioningProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 655FFFA11BEAD93600D43AD8 /* ProvisioningProfile.swift */; }; @@ -50,6 +52,8 @@ 652408E41BE743D4006FA4C6 /* iOS App Signer.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "iOS App Signer.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 652408E81BE743D4006FA4C6 /* AppSignerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSignerUITests.swift; sourceTree = ""; }; 652408EA1BE743D4006FA4C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 65311EAD1BF8259000516EFD /* NSMenuLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMenuLink.swift; sourceTree = ""; }; + 65311EAF1BF835F100516EFD /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; 655FFF9C1BE9B3E300D43AD8 /* NSTask-execute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTask-execute.swift"; sourceTree = ""; }; 655FFF9E1BE9BA9D00D43AD8 /* StringByAppendingPathComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringByAppendingPathComponent.swift; sourceTree = ""; }; 655FFFA11BEAD93600D43AD8 /* ProvisioningProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProvisioningProfile.swift; sourceTree = ""; }; @@ -141,6 +145,8 @@ isa = PBXGroup; children = ( 655FFFA11BEAD93600D43AD8 /* ProvisioningProfile.swift */, + 65311EAD1BF8259000516EFD /* NSMenuLink.swift */, + 65311EAF1BF835F100516EFD /* Log.swift */, ); name = Classes; sourceTree = ""; @@ -289,8 +295,10 @@ buildActionMask = 2147483647; files = ( 652408CE1BE743D4006FA4C6 /* ViewController.swift in Sources */, + 65311EB01BF835F100516EFD /* Log.swift in Sources */, 655FFF9F1BE9BA9D00D43AD8 /* StringByAppendingPathComponent.swift in Sources */, 652408CC1BE743D4006FA4C6 /* AppDelegate.swift in Sources */, + 65311EAE1BF8259000516EFD /* NSMenuLink.swift in Sources */, 655FFF9D1BE9B3E300D43AD8 /* NSTask-execute.swift in Sources */, 655FFFA21BEAD93600D43AD8 /* ProvisioningProfile.swift in Sources */, );