From a0052e8395b7f63dd94654ed59dbb551e210f49d Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sat, 21 Mar 2020 17:52:51 -0700 Subject: [PATCH] Richer notifications (#68) --- SecretAgent/Notifier.swift | 25 +++++++++++++++++++++++-- SecretAgent/Untitled.png | Bin 0 -> 2669 bytes Secretive.xcodeproj/project.pbxproj | 4 ++++ Secretive/AppDelegate.swift | 3 ++- Secretive/Views/SetupView.swift | 14 +++++++------- 5 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 SecretAgent/Untitled.png diff --git a/SecretAgent/Notifier.swift b/SecretAgent/Notifier.swift index 1f12f98..ace969d 100644 --- a/SecretAgent/Notifier.swift +++ b/SecretAgent/Notifier.swift @@ -2,6 +2,7 @@ import Foundation import SecretKit import SecretAgentKit import UserNotifications +import AppKit class Notifier { @@ -14,14 +15,34 @@ class Notifier { func notify(accessTo secret: AnySecret, by provenance: SigningRequestProvenance) { let notificationCenter = UNUserNotificationCenter.current() let notificationContent = UNMutableNotificationContent() - notificationContent.title = "Signed Request" - notificationContent.body = "\(secret.name) was used to sign a request from \(provenance.origin.name)." + notificationContent.title = "Signed Request from \(provenance.origin.name)" + notificationContent.subtitle = secret.name + if let iconURL = iconURL(for: provenance), let attachment = try? UNNotificationAttachment(identifier: "icon", url: iconURL, options: nil) { + notificationContent.attachments = [attachment] + } let request = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: nil) notificationCenter.add(request, withCompletionHandler: nil) } } +extension Notifier { + + func iconURL(for provenance: SigningRequestProvenance) -> URL? { + do { + if let app = NSRunningApplication(processIdentifier: provenance.origin.pid), let icon = app.icon?.tiffRepresentation { + let temporaryURL = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("\(UUID().uuidString).png")) + let bitmap = NSBitmapImageRep(data: icon) + try bitmap?.representation(using: .png, properties: [:])?.write(to: temporaryURL) + return temporaryURL + } + } catch { + } + return nil + } + +} + extension Notifier: SigningWitness { func speakNowOrForeverHoldYourPeace(forAccessTo secret: AnySecret, by provenance: SigningRequestProvenance) throws { diff --git a/SecretAgent/Untitled.png b/SecretAgent/Untitled.png new file mode 100644 index 0000000000000000000000000000000000000000..c562de707afd632ccadd75339064c114819e0e6a GIT binary patch literal 2669 zcmb_e2Un9>6An!Rh*XUt(us>wq%6G?4QObJ(v^@<14PA;AV@%h5I}Kh3P=!E1eY2h zM3y2_f(5J)q?aHdy$A_H;7gX>fAF0%_r5cC&YAb#nR)Jgh)xbrQDGTj001CrXA8Lq z0Ps*ax+?GhXYOpop5lD?1FY<=0045D$PQe9V;lOp+4ny#KB6P@eMrrvp^E&egOoPAs8uJBXDFj%P6+o8%GzN=$2}LONs+_6q`sJ0(>k zI`1l8QTMTVJ?iYLeBQU$LMgd9#alfPqFzb{x$qw*V+EqB#>};b*-Pb&rMVA=4r?Z7 zbg4~?=Ah9rvl%npj5gm;TIw;xRwgkPn8XpwI?36A+5lK`j&1<0DT)~eE3{51+A!7& zlMv^T5Rcn4j7tG&c_d4##as|gTz<7T+Puqv-P%%8;N^%jZ2U{{g>0SVuByV6e**$| zh#r7Li`?L`K!`5K(i=0o@68XfBXYrgI0_dc5)xFL_<`Ao0yWPV;RG+q6*fij6)duE2;HAVI;jW!P* z(eOa_5a#(g?|?~vc$Wr?7! z1$%MNZ~n-#2BLBKFBkoYg}prr7!0NfOaJEM-57yky!}JDYv#dx#(c4T9=$$v$Ujvr zSK}K--TUv}47MXAS1LUE4jhsVB*+y@YmhM5MNZ0#2X=;9MV*-{(URR1i#xP zdh|?d*88l}kBaRwXw%&}2$P6~>)#_8XhC2G{3FRMJoJ-AD0`({tg`v@pU}qjrXG^n z(Bqf70Uts*dAZppvwbq0r|7t=;hO^pCYU881^z}s_211DHYKzw*{WT7Ubiq%Yhq>d ziH%|RzaHZ)zVPTnKP7_$4{Y>Dwzj-Un*6>4u)-`4jmz z-QnQ_StDPdu5|)tp5DXhY~I*v9)N;#eT2UOx} zyf4}ZR-2=kA$@;c4!fJm*1gz&ne5wn5I#`jmm+0Ug{P;ixb1ARRuQh6HunyOt$8=! zrffr`b6CgqLjs4WXe!t~msKVZ0@Cp4C4vN3d&S?)_g8tgL~lKzy0k<`wqIyJ%Bf!a z0&A7AIf5N)KnOLHX&o4K&-(7jOc)FIEZ+oMpM3aqj8j$&c4;`MGX-Q&nc$?%fO|EB z&+I-m6$CCT%@X7#d_LkVe{-vTI-jRqy$fypIZ_vNslVQpzWq$p?U0P#8==VN+Z#_} z*U!X3?=WbhjK?5z+SdnYLS{n=8BYtq?{1a!jtp`0W$p>7>b zMUT~UP|^U(Fr+~iso5Hyzpx__IXZsBD&2=ja`%96+!-7yP0sA*wtSRw_jJyq-kTe9 zm$9WTFD^O^KYk3oFXM-zm*40z)A~}zBs)TgDw2>;4(v3`si=NU>SjW0hk@z2)KAJ7 z?KT|Fw*YbYl*@H%XaPY|$oauh?Y8HR1#)#pa=f8+acuZ;5fZo0W(?^dk4DJng9I3ICxDLiP$?5Q~CQasHMUxW7 z%r|m(FazLQM4xm;BDwNdw_B~s5B{oT${FiI9Of!ZTw7MxKlOFoC-8Uo^`ChK0du`@ z%un`6uqPK^=@5nTTFFsqnu;98kOg`N%>bz)U;U%Ipm2RDMxavuv;t`OmJ@7m1A<(dUIrZ2nrV)6MfvwQq}Z5Tq6k{?ijVG=%_x~(}9 zFDT|U`L-lAaYM6G0N&9KH`6Grl2*8#si<6Q6@Nez9=}oQb2T3?t9m~3dQO2#vw|1F zZ&mY0!Lwu5L?mod;v|wF?f#Xa>qs(}LW$z$hNoM5+HQ(pPgenQ+yeAtQA;t;U`(shZ@@=QG3EcO}w@kqp4E~GW4vE}{! VQv+ZVu>>yXvpeemskHXF`#+|7(o6sV literal 0 HcmV?d00001 diff --git a/Secretive.xcodeproj/project.pbxproj b/Secretive.xcodeproj/project.pbxproj index 6878c8b..866bef1 100644 --- a/Secretive.xcodeproj/project.pbxproj +++ b/Secretive.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617DD123FCEFA90099B055 /* PreviewStore.swift */; }; 506772C72424784600034DED /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 506772C62424784600034DED /* Credits.rtf */; }; 506772C92425BB8500034DED /* NoStoresView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506772C82425BB8500034DED /* NoStoresView.swift */; }; + 506772CB2426CCC200034DED /* Untitled.png in Resources */ = {isa = PBXBuildFile; fileRef = 506772CA2426CCC200034DED /* Untitled.png */; }; 5068389E241471CD00F55094 /* SecretStoreList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5068389D241471CD00F55094 /* SecretStoreList.swift */; }; 506838A12415EA5600F55094 /* AnySecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A02415EA5600F55094 /* AnySecret.swift */; }; 506838A32415EA5D00F55094 /* AnySecretStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506838A22415EA5D00F55094 /* AnySecretStore.swift */; }; @@ -203,6 +204,7 @@ 50617DD123FCEFA90099B055 /* PreviewStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewStore.swift; sourceTree = ""; }; 506772C62424784600034DED /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = ""; }; 506772C82425BB8500034DED /* NoStoresView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoStoresView.swift; sourceTree = ""; }; + 506772CA2426CCC200034DED /* Untitled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Untitled.png; sourceTree = ""; }; 5068389D241471CD00F55094 /* SecretStoreList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretStoreList.swift; sourceTree = ""; }; 506838A02415EA5600F55094 /* AnySecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecret.swift; sourceTree = ""; }; 506838A22415EA5D00F55094 /* AnySecretStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnySecretStore.swift; sourceTree = ""; }; @@ -507,6 +509,7 @@ children = ( 50020BAF24064869003D4025 /* AppDelegate.swift */, 5018F54E24064786002EB505 /* Notifier.swift */, + 506772CA2426CCC200034DED /* Untitled.png */, 50A3B79024026B7600D209EA /* Assets.xcassets */, 50A3B79524026B7600D209EA /* Main.storyboard */, 50A3B79824026B7600D209EA /* Info.plist */, @@ -790,6 +793,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 506772CB2426CCC200034DED /* Untitled.png in Resources */, 50A3B79724026B7600D209EA /* Main.storyboard in Resources */, 50A3B79424026B7600D209EA /* Preview Assets.xcassets in Resources */, 50A3B79124026B7600D209EA /* Assets.xcassets in Resources */, diff --git a/Secretive/AppDelegate.swift b/Secretive/AppDelegate.swift index 2e6096c..18dc39e 100644 --- a/Secretive/AppDelegate.swift +++ b/Secretive/AppDelegate.swift @@ -66,7 +66,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { @IBAction func runSetup(sender: AnyObject?) { let setupWindow = NSWindow( - contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), + contentRect: NSRect(x: 0, y: 0, width: 00, height: 00), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false) let setupView = SetupView() { success in @@ -74,6 +74,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.agentStatusChecker.check() } setupWindow.contentView = NSHostingView(rootView: setupView) + setupWindow.setContentSize(setupWindow.contentView!.fittingSize) window.beginSheet(setupWindow, completionHandler: nil) } diff --git a/Secretive/Views/SetupView.swift b/Secretive/Views/SetupView.swift index 7e2600e..fd24ed3 100644 --- a/Secretive/Views/SetupView.swift +++ b/Secretive/Views/SetupView.swift @@ -9,12 +9,12 @@ struct SetupView: View { var body: some View { Form { SetupStepView(text: "Secretive needs to install a helper app to sign requests when the main app isn't running. This app is called \"SecretAgent\" and you might see it in Activity Manager from time to time.", - index: 1, - nestedView: nil, - actionText: "Install") { + index: 1, + nestedView: nil, + actionText: "Install") { self.installLaunchAgent() } - SetupStepView(text: "You need to add a line to your shell config (.bashrc or .zshrc) telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.", + SetupStepView(text: "Add this line to your shell config (.bashrc or .zshrc) telling SSH to talk to SecretAgent when it wants to authenticate. Drag this into your config file.", index: 2, nestedView: SetupStepCommandView(text: Constants.socketPrompt), actionText: "Added") { @@ -22,9 +22,9 @@ struct SetupView: View { } HStack { Spacer() - Button(action: { self.completion?(true) }) { - Text("Finish") - } + Button(action: { self.completion?(true) }) { + Text("Finish") + } .padding() } }