├── .gitignore ├── DMG ├── LuLu.icns ├── background.png ├── background.psd └── createDMG.sh ├── LICENSE.md ├── LuLu ├── App │ ├── 3rd-party │ │ ├── OrderedDictionary.h │ │ └── OrderedDictionary.m │ ├── AboutWindowController.h │ ├── AboutWindowController.m │ ├── AddRuleWindowController.h │ ├── AddRuleWindowController.m │ ├── AlertWindowController.h │ ├── AlertWindowController.m │ ├── App.entitlements │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── Ancestry.imageset │ │ │ ├── Contents.json │ │ │ ├── parents any.pdf │ │ │ ├── parents dark.pdf │ │ │ └── parents light.pdf │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon_128x128.png │ │ │ ├── icon_128x128@2x.png │ │ │ ├── icon_16x16.png │ │ │ ├── icon_16x16@2x.png │ │ │ ├── icon_256x256.png │ │ │ ├── icon_256x256@2x.png │ │ │ ├── icon_32x32.png │ │ │ ├── icon_32x32@2x.png │ │ │ ├── icon_512x512.png │ │ │ └── icon_512x512@2x.png │ │ ├── Contents.json │ │ ├── Friends1Password.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsHuntress.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsJamf.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsKandji.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsKolide.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsMacPaw.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsMalwarebytes.imageset │ │ │ ├── Contents.json │ │ │ └── malwarebytes.png │ │ ├── FriendsPANW.imageset │ │ │ ├── Contents.json │ │ │ ├── darkMode.png │ │ │ └── lightMode.png │ │ ├── FriendsiVerify.imageset │ │ │ ├── Contents.json │ │ │ └── iVerify.png │ │ ├── Heart.imageset │ │ │ ├── Contents.json │ │ │ ├── heart_dark.pdf │ │ │ ├── heart_light-1.pdf │ │ │ └── heart_light.pdf │ │ ├── Icon.imageset │ │ │ ├── Contents.json │ │ │ ├── LoginItem Any.pdf │ │ │ ├── LoginItem Dark.pdf │ │ │ └── LoginItem Light.pdf │ │ ├── InstallAllow.imageset │ │ │ ├── Contents.json │ │ │ ├── allow.png │ │ │ ├── allow_es.png │ │ │ └── allow_ko.png │ │ ├── InstallApprove.imageset │ │ │ ├── Contents.json │ │ │ ├── approve.png │ │ │ ├── approve_es.png │ │ │ └── approve_ko.png │ │ ├── InstallApprove_OLD.imageset │ │ │ ├── Contents.json │ │ │ ├── approve.png │ │ │ └── approve_es.png │ │ ├── InstallAuth.imageset │ │ │ ├── Contents.json │ │ │ ├── auth.png │ │ │ ├── auth_es.png │ │ │ └── auth_ko.png │ │ ├── InstallBlocked.imageset │ │ │ ├── Contents.json │ │ │ ├── blocked.png │ │ │ ├── blocked_es.png │ │ │ └── blocked_ko.png │ │ ├── LuLuText.imageset │ │ │ ├── Contents.json │ │ │ ├── lulu_text-1.pdf │ │ │ ├── lulu_text-2.pdf │ │ │ └── lulu_text.pdf │ │ ├── PrefsList.imageset │ │ │ ├── Contents.json │ │ │ └── icon.png │ │ ├── PrefsMode.imageset │ │ │ ├── Contents.json │ │ │ ├── prefsMode Any.pdf │ │ │ ├── prefsMode Dark.pdf │ │ │ └── prefsMode Light.pdf │ │ ├── PrefsRules.imageset │ │ │ ├── Contents.json │ │ │ ├── prefsRules Any.pdf │ │ │ ├── prefsRules Dark.pdf │ │ │ └── prefsRules Light.pdf │ │ ├── PrefsUpdate.imageset │ │ │ ├── Contents.json │ │ │ ├── prefsUpdate Any.pdf │ │ │ ├── prefsUpdate Dark.pdf │ │ │ └── prefsUpdate Light.pdf │ │ ├── RulesAllow.imageset │ │ │ ├── Contents.json │ │ │ ├── rulesAllow Any.pdf │ │ │ ├── rulesAllow Dark.pdf │ │ │ └── rulesAllow Light.pdf │ │ ├── RulesBlock.imageset │ │ │ ├── Contents.json │ │ │ ├── block Any.pdf │ │ │ ├── block Dark.pdf │ │ │ └── block Light.pdf │ │ ├── RulesSystem.imageset │ │ │ ├── Contents.json │ │ │ ├── rulesSystem dark.pdf │ │ │ ├── rulesSystem light-1.pdf │ │ │ └── rulesSystem light.pdf │ │ ├── Signed.imageset │ │ │ ├── Contents.json │ │ │ ├── signed Any.pdf │ │ │ ├── signed Dark.pdf │ │ │ └── signed Light.pdf │ │ ├── SignedApple.imageset │ │ │ ├── Contents.json │ │ │ ├── signedApple Any.pdf │ │ │ ├── signedApple Dark.pdf │ │ │ └── signedApple Light.pdf │ │ ├── SignedUnknown.imageset │ │ │ ├── Contents.json │ │ │ ├── Unknown any.pdf │ │ │ ├── Unknown dark.pdf │ │ │ └── Unknown light.pdf │ │ ├── StatusActive.imageset │ │ │ ├── Contents.json │ │ │ └── LoginItem StatusBar Active.pdf │ │ ├── StatusInactive.imageset │ │ │ ├── Contents.json │ │ │ └── LoginItem StatusBar Inactive.pdf │ │ ├── Unsigned.imageset │ │ │ ├── Contents.json │ │ │ ├── unsigned Any.pdf │ │ │ ├── unsigned Dark.pdf │ │ │ └── unsigned Light.pdf │ │ ├── VTIcon.imageset │ │ │ ├── Contents.json │ │ │ ├── VT Any-1.pdf │ │ │ ├── VT Dark.pdf │ │ │ └── VT Light.pdf │ │ ├── allow.imageset │ │ │ ├── Contents.json │ │ │ ├── rulesAllow Any.pdf │ │ │ ├── rulesAllow Dark.pdf │ │ │ └── rulesAllow Light.pdf │ │ ├── block.imageset │ │ │ ├── Contents.json │ │ │ ├── block Any.pdf │ │ │ ├── block Dark.pdf │ │ │ └── block Light.pdf │ │ ├── refresh.imageset │ │ │ ├── Contents.json │ │ │ └── refresh.png │ │ ├── rulesRecent.imageset │ │ │ ├── Contents.json │ │ │ └── rulesRecent.png │ │ └── rulesUnknown.imageset │ │ │ ├── Contents.json │ │ │ └── rulesUnknown.png │ ├── Base.lproj │ │ ├── AboutWindow.xib │ │ ├── AddRule.xib │ │ ├── AlertWindow.xib │ │ ├── ItemPaths.xib │ │ ├── MainMenu.xib │ │ ├── Preferences.xib │ │ ├── Rules.xib │ │ ├── StartupWindowController.xib │ │ ├── StatusBarPopover.xib │ │ ├── UpdateWindow.xib │ │ └── Welcome.xib │ ├── Configure.h │ ├── Configure.m │ ├── Extension.h │ ├── Extension.m │ ├── Info.plist │ ├── InfoPlist.xcstrings │ ├── ItemPathsWindowController.h │ ├── ItemPathsWindowController.m │ ├── NSApplicationKeyEvents.h │ ├── NSApplicationKeyEvents.m │ ├── ParentsWindowController.h │ ├── ParentsWindowController.m │ ├── PrefsWindowController.h │ ├── PrefsWindowController.m │ ├── RuleRow.h │ ├── RuleRow.m │ ├── RuleRowCell.h │ ├── RuleRowCell.m │ ├── RulesMenuController.h │ ├── RulesMenuController.m │ ├── RulesTable.h │ ├── RulesTable.m │ ├── RulesWindowController.h │ ├── RulesWindowController.m │ ├── SigningInfoViewController.h │ ├── SigningInfoViewController.m │ ├── StartupWindowController.h │ ├── StartupWindowController.m │ ├── StatusBarItem.h │ ├── StatusBarItem.m │ ├── StatusBarPopoverController.h │ ├── StatusBarPopoverController.m │ ├── Update.h │ ├── Update.m │ ├── UpdateWindowController.h │ ├── UpdateWindowController.m │ ├── VirusTotal.h │ ├── VirusTotal.m │ ├── VirusTotalViewController.h │ ├── VirusTotalViewController.m │ ├── WelcomeWindowController.h │ ├── WelcomeWindowController.m │ ├── XPCDaemonClient.h │ ├── XPCDaemonClient.m │ ├── XPCUser.h │ ├── XPCUser.m │ ├── instructions.psd │ ├── main.m │ ├── mul.lproj │ │ ├── AboutWindow.xcstrings │ │ ├── AddRule.xcstrings │ │ ├── AlertWindow.xcstrings │ │ ├── ItemPaths.xcstrings │ │ ├── MainMenu.xcstrings │ │ ├── Preferences.xcstrings │ │ ├── Rules.xcstrings │ │ ├── StartupWindowController.xcstrings │ │ ├── StatusBarPopover.xcstrings │ │ ├── UpdateWindow.xcstrings │ │ └── Welcome.xcstrings │ └── patrons.txt ├── Extension │ ├── Alerts.h │ ├── Alerts.m │ ├── Binary.h │ ├── Binary.m │ ├── BlockOrAllowList.h │ ├── BlockOrAllowList.m │ ├── Extension.entitlements │ ├── FilterDataProvider.h │ ├── FilterDataProvider.m │ ├── GrayList.h │ ├── GrayList.m │ ├── Info.plist │ ├── Preferences.h │ ├── Preferences.m │ ├── Process.h │ ├── Process.m │ ├── Rules.h │ ├── Rules.m │ ├── XPCDaemon.h │ ├── XPCDaemon.m │ ├── XPCListener.h │ ├── XPCListener.m │ ├── XPCUserClient.h │ ├── XPCUserClient.m │ ├── main.h │ ├── main.m │ └── procInfo.h ├── LuLu.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ ├── Extension.xcscheme │ │ └── LuLu.xcscheme └── Shared │ ├── Localizable.xcstrings │ ├── Rule.h │ ├── Rule.m │ ├── XPCDaemonProto.h │ ├── XPCUserProto.h │ ├── consts.h │ ├── images │ ├── objectiveSeeLogo.png │ └── objectiveSeeText.png │ ├── signing.h │ ├── signing.m │ ├── utilities.h │ └── utilities.m ├── README.md ├── README_zh-Hans.md ├── README_zh-Hant.md └── lulu.xcworkspace ├── contents.xcworkspacedata └── xcshareddata └── IDEWorkspaceChecks.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## macOS 6 | .DS_Store 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | # Carthage 35 | # 36 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 37 | Carthage/Build 38 | Carthage/Checkouts 39 | DMG/Release/* 40 | DMG/LuLu.app 41 | DMG/*.dmg 42 | DMG/background.psd 43 | LuLu/Binaries/ 44 | -------------------------------------------------------------------------------- /DMG/LuLu.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/DMG/LuLu.icns -------------------------------------------------------------------------------- /DMG/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/DMG/background.png -------------------------------------------------------------------------------- /DMG/background.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/DMG/background.psd -------------------------------------------------------------------------------- /DMG/createDMG.sh: -------------------------------------------------------------------------------- 1 | VERSION="3.1.5" 2 | 3 | printf "\nCreating LuLu Disk Image...\n\n" 4 | 5 | create-dmg \ 6 | --volname "LuLu v$VERSION" \ 7 | --volicon "LuLu.icns" \ 8 | --background "background.png" \ 9 | --window-pos 200 120 \ 10 | --window-size 800 400 \ 11 | --icon-size 100 \ 12 | --icon "LuLu.app" 200 190 \ 13 | --hide-extension "LuLu.app" \ 14 | --app-drop-link 600 190 \ 15 | "LuLu_$VERSION.dmg" \ 16 | "Release/" 17 | 18 | printf "\nCode signing dmg...\n" 19 | 20 | codesign --force --sign "Developer ID Application: Objective-See, LLC (VBG97UB4TA)" LuLu_$VERSION.dmg 21 | 22 | printf "Done!\n" 23 | -------------------------------------------------------------------------------- /LuLu/App/3rd-party/OrderedDictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // OrderedDictionary.h 3 | // OrderedDictionary 4 | // 5 | // Created by Matt Gallagher on 19/12/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | @import Cocoa; 25 | 26 | @interface OrderedDictionary : NSMutableDictionary 27 | { 28 | NSMutableDictionary *dictionary; 29 | NSMutableArray *array; 30 | } 31 | 32 | /* METHODS */ 33 | -(void)reverse; 34 | -(id)keyAtIndex:(NSUInteger)anIndex; 35 | -(void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /LuLu/App/3rd-party/OrderedDictionary.m: -------------------------------------------------------------------------------- 1 | // 2 | // OrderedDictionary.m 3 | // OrderedDictionary 4 | // 5 | // Created by Matt Gallagher on 19/12/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // This software is provided 'as-is', without any express or implied 9 | // warranty. In no event will the authors be held liable for any damages 10 | // arising from the use of this software. Permission is granted to anyone to 11 | // use this software for any purpose, including commercial applications, and to 12 | // alter it and redistribute it freely, subject to the following restrictions: 13 | // 14 | // 1. The origin of this software must not be misrepresented; you must not 15 | // claim that you wrote the original software. If you use this software 16 | // in a product, an acknowledgment in the product documentation would be 17 | // appreciated but is not required. 18 | // 2. Altered source versions must be plainly marked as such, and must not be 19 | // misrepresented as being the original software. 20 | // 3. This notice may not be removed or altered from any source 21 | // distribution. 22 | // 23 | 24 | #import "Consts.h" 25 | #import "OrderedDictionary.h" 26 | 27 | 28 | NSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent) 29 | { 30 | NSString *objectString; 31 | if ([object isKindOfClass:[NSString class]]) 32 | { 33 | objectString = (NSString *)object; 34 | } 35 | else if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)]) 36 | { 37 | objectString = [(NSDictionary *)object descriptionWithLocale:locale indent:indent]; 38 | } 39 | else if ([object respondsToSelector:@selector(descriptionWithLocale:)]) 40 | { 41 | objectString = [(NSSet *)object descriptionWithLocale:locale]; 42 | } 43 | else 44 | { 45 | objectString = [object description]; 46 | } 47 | return objectString; 48 | } 49 | 50 | @implementation OrderedDictionary 51 | 52 | -(id)init 53 | { 54 | self = [super init]; 55 | if (self != nil) 56 | { 57 | dictionary = [NSMutableDictionary dictionary]; 58 | array = [NSMutableArray array]; 59 | } 60 | return self; 61 | } 62 | 63 | -(id)copy 64 | { 65 | return [self mutableCopy]; 66 | } 67 | 68 | -(id)mutableCopy 69 | { 70 | OrderedDictionary* copy = nil; 71 | 72 | copy = [[OrderedDictionary alloc] init]; 73 | copy->array = [array mutableCopy]; 74 | copy->dictionary = [dictionary mutableCopy]; 75 | 76 | return copy; 77 | } 78 | 79 | -(void)reverse 80 | { 81 | [array setArray:[[array reverseObjectEnumerator] allObjects]]; 82 | } 83 | 84 | -(void)setObject:(id)anObject forKey:(id)aKey 85 | { 86 | if(![dictionary objectForKey:aKey]) 87 | { 88 | // 89 | [array addObject:aKey]; 90 | } 91 | [dictionary setObject:anObject forKey:aKey]; 92 | } 93 | 94 | -(void)removeObjectForKey:(id)aKey 95 | { 96 | [dictionary removeObjectForKey:aKey]; 97 | [array removeObject:aKey]; 98 | } 99 | 100 | - (NSUInteger)count 101 | { 102 | return [dictionary count]; 103 | } 104 | 105 | -(id)objectForKey:(id)aKey 106 | { 107 | return [dictionary objectForKey:aKey]; 108 | } 109 | 110 | -(NSEnumerator *)keyEnumerator 111 | { 112 | return [array objectEnumerator]; 113 | } 114 | 115 | -(void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex 116 | { 117 | //remove old object 118 | if([dictionary objectForKey:aKey]) 119 | { 120 | //remove 121 | [self removeObjectForKey:aKey]; 122 | } 123 | 124 | //adding at end? 125 | // just append item 126 | if(array.count == anIndex) 127 | { 128 | //add 129 | [array addObject:aKey]; 130 | } 131 | //insert object 132 | else 133 | { 134 | //insert 135 | [array insertObject:aKey atIndex:anIndex]; 136 | } 137 | 138 | //add to dictionary 139 | [dictionary setObject:anObject forKey:aKey]; 140 | } 141 | 142 | -(id)keyAtIndex:(NSUInteger)anIndex 143 | { 144 | //object 145 | id item = nil; 146 | 147 | if((nil == array) || 148 | (anIndex >= array.count)) 149 | { 150 | //bail 151 | goto bail; 152 | } 153 | 154 | //extract item 155 | item = [array objectAtIndex:anIndex]; 156 | 157 | bail: 158 | 159 | return item; 160 | } 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /LuLu/App/AboutWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: AboutWindowController.h 3 | // project: lulu (main app) 4 | // description: 'about' window controller (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface AboutWindowController : NSWindowController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //version label/string 20 | @property (weak) IBOutlet NSTextField *versionLabel; 21 | 22 | //patrons 23 | @property (unsafe_unretained) IBOutlet NSTextView *patrons; 24 | 25 | /* METHODS */ 26 | 27 | //automatically invoked when user clicks any of the buttons 28 | // ->perform actions, such as loading patreon or products URL 29 | -(IBAction)buttonHandler:(id)sender; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /LuLu/App/AboutWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: AboutWindowController.m 3 | // project: lulu (main app) 4 | // description: 'about' window controller 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "consts.h" 11 | #import "utilities.h" 12 | #import "AboutWindowController.h" 13 | 14 | @implementation AboutWindowController 15 | 16 | @synthesize patrons; 17 | @synthesize versionLabel; 18 | 19 | //automatically called when nib is loaded 20 | // ->center window 21 | -(void)awakeFromNib 22 | { 23 | //center 24 | [self.window center]; 25 | } 26 | 27 | //automatically invoked when window is loaded 28 | // set to window to white, set app version, patrons, etc 29 | -(void)windowDidLoad 30 | { 31 | //version 32 | NSString* version = nil; 33 | 34 | //super 35 | [super windowDidLoad]; 36 | 37 | //not in dark mode? 38 | // make window white 39 | if(YES != isDarkMode()) 40 | { 41 | //make white 42 | self.window.backgroundColor = NSColor.whiteColor; 43 | } 44 | 45 | //grab app version 46 | version = getAppVersion(); 47 | if(nil == version) 48 | { 49 | //default 50 | version = NSLocalizedString(@"unknown", @"unknown"); 51 | } 52 | 53 | //set version sting 54 | self.versionLabel.stringValue = [NSString stringWithFormat:NSLocalizedString(@"Version: %@", @"Version: %@"), version]; 55 | 56 | //load patrons 57 | self.patrons.string = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"patrons" ofType:@"txt"] encoding:NSUTF8StringEncoding error:NULL]; 58 | if(nil == self.patrons.string) 59 | { 60 | //default 61 | self.patrons.string = NSLocalizedString(@"ERROR: failed to load patrons", @"ERROR: failed to load patrons"); 62 | } 63 | 64 | return; 65 | } 66 | 67 | //automatically invoked when window is closing 68 | // ->make window unmodal 69 | -(void)windowWillClose:(NSNotification *)notification 70 | { 71 | //make un-modal 72 | [[NSApplication sharedApplication] stopModal]; 73 | 74 | return; 75 | } 76 | 77 | //automatically invoked when user clicks any of the buttons 78 | // perform actions, such as loading patreon or products URL 79 | -(IBAction)buttonHandler:(id)sender 80 | { 81 | //support us button 82 | if(((NSButton*)sender).tag == BUTTON_SUPPORT_US) 83 | { 84 | //open URL 85 | // invokes user's default browser 86 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PATREON_URL]]; 87 | } 88 | 89 | //more info button 90 | else if(((NSButton*)sender).tag == BUTTON_MORE_INFO) 91 | { 92 | //open URL 93 | // invokes user's default browser 94 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; 95 | } 96 | 97 | return; 98 | } 99 | @end 100 | -------------------------------------------------------------------------------- /LuLu/App/AddRuleWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: AddRuleWindowController.h 3 | // project: lulu 4 | // description: 'add/edit rule' window controller (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | @import OSLog; 12 | 13 | #import "Rule.h" 14 | 15 | @interface AddRuleWindowController : NSWindowController 16 | 17 | /* PROPERTIES */ 18 | 19 | //app/binary icon 20 | @property (weak) IBOutlet NSImageView *icon; 21 | 22 | //path to app/binary 23 | @property (weak) IBOutlet NSTextField *path; 24 | 25 | //endpoint address 26 | @property (weak) IBOutlet NSTextField *endpointAddr; 27 | 28 | //but indicating endpoint addr is a regex 29 | @property (weak) IBOutlet NSButton *isEndpointAddrRegex; 30 | 31 | //endpoint port 32 | @property (weak) IBOutlet NSTextField *endpointPort; 33 | 34 | //'add' button 35 | @property (weak) IBOutlet NSButton *addButton; 36 | 37 | //block button 38 | @property (weak) IBOutlet NSButton *blockButton; 39 | 40 | //allow button 41 | @property (weak) IBOutlet NSButton *allowButton; 42 | 43 | //(existing) rule 44 | @property (nonatomic, retain)Rule* rule; 45 | 46 | //info (to create/update rule) 47 | @property(nonatomic, retain) NSDictionary* info; 48 | 49 | 50 | /* METHODS */ 51 | 52 | //'block'/'allow' button handler 53 | // just needed so buttons will toggle 54 | -(IBAction)radioButtonsHandler:(id)sender; 55 | 56 | //'browse' button handler 57 | // open a panel for user to select file 58 | -(IBAction)browseButtonHandler:(id)sender; 59 | 60 | //'cancel' button handler 61 | // returns NSModalResponseCancel 62 | -(IBAction)cancelButtonHandler:(id)sender; 63 | 64 | //'add' button handler 65 | // returns NSModalResponseOK 66 | -(IBAction)addButtonHandler:(id)sender; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /LuLu/App/AlertWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: AlertWindowController.h 3 | // project: lulu (login item) 4 | // description: window controller for main firewall alert (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | @import OSLog; 12 | 13 | #import "ParentsWindowController.h" 14 | #import "VirusTotalViewController.h" 15 | #import "SigningInfoViewController.h" 16 | 17 | @interface AlertWindowController : NSWindowController 18 | 19 | /* PROPERTIES */ 20 | 21 | //alert info 22 | @property(nonatomic, retain)NSDictionary* alert; 23 | 24 | //touch bar 25 | @property(nonatomic, retain)NSTouchBar* touchBar; 26 | 27 | //reply 28 | @property (nonatomic, copy)void(^reply)(NSDictionary*); 29 | 30 | 31 | /* TOP */ 32 | 33 | //process icon 34 | @property (weak) IBOutlet NSImageView *processIcon; 35 | 36 | //process name 37 | @property (weak) IBOutlet NSTextField *processName; 38 | 39 | //general alert message 40 | @property (unsafe_unretained) IBOutlet NSTextView *alertMessage; 41 | 42 | //signing info button 43 | @property (weak) IBOutlet NSButton *signingInfoButton; 44 | 45 | //signing info: popover 46 | @property (strong) IBOutlet NSPopover *signingInfoPopover; 47 | 48 | //virus total: button 49 | @property (weak) IBOutlet NSButton *virusTotalButton; 50 | 51 | //virus total: popover 52 | @property (strong) IBOutlet NSPopover *virusTotalPopover; 53 | 54 | //view controller for ancestry view/popover 55 | @property (weak) IBOutlet ParentsWindowController *ancestryViewController; 56 | 57 | //ancestry button 58 | @property (weak) IBOutlet NSButton *ancestryButton; 59 | 60 | //popover for ancestry 61 | @property (strong) IBOutlet NSPopover *ancestryPopover; 62 | 63 | //process ancestry 64 | @property (nonatomic, retain)NSMutableArray* processHierarchy; 65 | 66 | @property (weak) IBOutlet NSButton *allowButton; 67 | 68 | /* BOTTOM (DETAILS) */ 69 | 70 | //process id 71 | @property (weak) IBOutlet NSTextField *processID; 72 | 73 | //process args 74 | @property (weak) IBOutlet NSTextField *processArgs; 75 | 76 | //process path 77 | @property (unsafe_unretained) IBOutlet NSTextView *processPath; 78 | 79 | //ip address 80 | @property (weak) IBOutlet NSTextField *ipAddress; 81 | 82 | //port/protocol 83 | @property (weak) IBOutlet NSTextField *portProto; 84 | 85 | //reverse dns name 86 | @property (unsafe_unretained) IBOutlet NSTextView *reverseDNS; 87 | 88 | //ancestry view 89 | @property (strong) IBOutlet NSView *ancestryView; 90 | 91 | //outline view in ancestry popover 92 | @property (weak) IBOutlet NSOutlineView *ancestryOutline; 93 | 94 | //text cell for ancestry popover 95 | @property (weak) IBOutlet NSTextFieldCell *ancestryTextCell; 96 | 97 | //time stamp 98 | @property (weak) IBOutlet NSTextField *timeStamp; 99 | 100 | //action (rule) scope 101 | @property (weak) IBOutlet NSPopUpButton *actionScope; 102 | 103 | //rule durations 104 | @property (weak) IBOutlet NSButton *ruleDurationAlways; 105 | @property (weak) IBOutlet NSButton *ruleDurationProcess; 106 | @property (weak) IBOutlet NSButton *ruleDurationCustom; 107 | @property (weak) IBOutlet NSTextField *ruleDurationCustomAmount; 108 | 109 | //options view 110 | @property (weak) IBOutlet NSView *options; 111 | 112 | //show options button 113 | @property (weak) IBOutlet NSButton* showOptions; 114 | 115 | //endpoint (e.g. domain) 116 | @property(nonatomic, retain)NSString* endpoint; 117 | 118 | /* METHODS */ 119 | 120 | //open signing info popover 121 | -(void)openSigningInfoPopover; 122 | 123 | //button handler 124 | // ->block/allow, and then close 125 | -(IBAction)handleUserResponse:(id)sender; 126 | 127 | //set wrapping 128 | -(void)setWrapping:(NSTextView *)textView; 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /LuLu/App/App.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | content-filter-provider-systemextension 8 | 9 | com.apple.developer.system-extension.install 10 | 11 | com.apple.security.application-groups 12 | 13 | $(TeamIdentifierPrefix)com.objective-see.lulu 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /LuLu/App/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 8/1/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | @import Cocoa; 10 | @import OSLog; 11 | @import NetworkExtension; 12 | @import SystemExtensions; 13 | 14 | #import "StatusBarItem.h" 15 | #import "XPCDaemonClient.h" 16 | #import "AboutWindowController.h" 17 | #import "PrefsWindowController.h" 18 | #import "RulesWindowController.h" 19 | #import "UpdateWindowController.h" 20 | #import "StartupWindowController.h" 21 | #import "WelcomeWindowController.h" 22 | 23 | @interface AppDelegate : NSObject 24 | 25 | 26 | /* PROPERTIES */ 27 | 28 | //configure window controller 29 | @property(nonatomic, retain)StartupWindowController* startupWindowController; 30 | 31 | //uninstall (deactivation) request 32 | @property(nonatomic, retain)OSSystemExtensionRequest *uninstallRequest; 33 | 34 | //welcome view controller 35 | @property(nonatomic, retain)WelcomeWindowController* welcomeWindowController; 36 | 37 | //status bar menu 38 | @property(strong) IBOutlet NSMenu* statusMenu; 39 | 40 | //status bar menu controller 41 | @property(nonatomic, retain)StatusBarItem* statusBarItemController; 42 | 43 | //about window controller 44 | @property(nonatomic, retain)AboutWindowController* aboutWindowController; 45 | 46 | //preferences window controller 47 | @property(nonatomic, retain)PrefsWindowController* prefsWindowController; 48 | 49 | //rules window controller 50 | @property(nonatomic, retain)RulesWindowController* rulesWindowController; 51 | 52 | //update window controller 53 | @property(nonatomic, retain)UpdateWindowController* updateWindowController; 54 | 55 | /* METHODS */ 56 | 57 | //first launch? 58 | // check for install time(stamp) 59 | -(BOOL)isFirstTime; 60 | 61 | //finish up initializations 62 | -(void)completeInitialization:(NSDictionary*)initialPreferenes; 63 | 64 | //set app foreground/background 65 | // determined by the app's window count 66 | -(void)setActivationPolicy; 67 | 68 | //'rules' menu item handler 69 | // alloc and show rules window 70 | -(IBAction)showRules:(id)sender; 71 | 72 | //'preferences' menu item handler 73 | // alloc and show preferences window 74 | -(IBAction)showPreferences:(id)sender; 75 | 76 | //preferences changed 77 | // for now, just check status bar icon setting 78 | -(void)preferencesChanged:(NSDictionary*)preferences; 79 | 80 | //toggle (status) bar icon 81 | -(void)toggleIcon:(NSDictionary*)preferences; 82 | 83 | //quit 84 | -(IBAction)quit:(id)sender; 85 | 86 | //uninstall 87 | -(IBAction)uninstall:(id)sender; 88 | 89 | @end 90 | 91 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Ancestry.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "parents any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "parents light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "parents dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "template-rendering-intent" : "template", 34 | "preserves-vector-representation" : true 35 | } 36 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Ancestry.imageset/parents any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Ancestry.imageset/parents any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Ancestry.imageset/parents dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Ancestry.imageset/parents dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Ancestry.imageset/parents light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Ancestry.imageset/parents light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_16x16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon_16x16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon_32x32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon_32x32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon_128x128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon_128x128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon_256x256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon_256x256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon_512x512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon_512x512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Friends1Password.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Friends1Password.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Friends1Password.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Friends1Password.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Friends1Password.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsHuntress.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsHuntress.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsHuntress.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsHuntress.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsHuntress.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsJamf.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsJamf.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsJamf.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsJamf.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsJamf.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsKandji.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsKandji.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsKandji.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsKandji.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsKandji.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsKolide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsKolide.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsKolide.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsKolide.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsKolide.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsMacPaw.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "darkMode.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lightMode.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "darkMode.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsMacPaw.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsMacPaw.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsMacPaw.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsMacPaw.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsMalwarebytes.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "malwarebytes.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsMalwarebytes.imageset/malwarebytes.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsPANW.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "darkMode.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "lightMode.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "darkMode.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsPANW.imageset/darkMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsPANW.imageset/darkMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsPANW.imageset/lightMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsPANW.imageset/lightMode.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsiVerify.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "iVerify.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/FriendsiVerify.imageset/iVerify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/FriendsiVerify.imageset/iVerify.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Heart.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "heart_light-1.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "heart_light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "heart_dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Heart.imageset/heart_dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Heart.imageset/heart_dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Heart.imageset/heart_light-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Heart.imageset/heart_light-1.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Heart.imageset/heart_light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Heart.imageset/heart_light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "LoginItem Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "LoginItem Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "LoginItem Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Icon.imageset/LoginItem Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Icon.imageset/LoginItem Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Icon.imageset/LoginItem Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Icon.imageset/LoginItem Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Icon.imageset/LoginItem Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Icon.imageset/LoginItem Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAllow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "allow.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | }, 16 | { 17 | "filename" : "allow_es.png", 18 | "idiom" : "universal", 19 | "locale" : "es", 20 | "scale" : "1x" 21 | }, 22 | { 23 | "idiom" : "universal", 24 | "locale" : "es", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "locale" : "es", 30 | "scale" : "3x" 31 | }, 32 | { 33 | "filename" : "allow_ko.png", 34 | "idiom" : "universal", 35 | "locale" : "ko", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "universal", 40 | "locale" : "ko", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "locale" : "ko", 46 | "scale" : "3x" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | }, 53 | "properties" : { 54 | "localizable" : true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAllow.imageset/allow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallAllow.imageset/allow.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAllow.imageset/allow_es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallAllow.imageset/allow_es.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAllow.imageset/allow_ko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallAllow.imageset/allow_ko.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "approve.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | }, 16 | { 17 | "locale" : "es", 18 | "idiom" : "universal", 19 | "filename" : "approve_es.png", 20 | "scale" : "1x" 21 | }, 22 | { 23 | "idiom" : "universal", 24 | "locale" : "es", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "locale" : "es", 30 | "scale" : "3x" 31 | }, 32 | { 33 | "filename" : "approve_ko.png", 34 | "idiom" : "universal", 35 | "locale" : "ko", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "universal", 40 | "locale" : "ko", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "locale" : "ko", 46 | "scale" : "3x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | }, 53 | "properties" : { 54 | "localizable" : true 55 | } 56 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove.imageset/approve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallApprove.imageset/approve.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove.imageset/approve_es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallApprove.imageset/approve_es.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove.imageset/approve_ko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallApprove.imageset/approve_ko.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove_OLD.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "approve.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | }, 16 | { 17 | "locale" : "es", 18 | "idiom" : "universal", 19 | "filename" : "approve_es.png", 20 | "scale" : "1x" 21 | }, 22 | { 23 | "idiom" : "universal", 24 | "locale" : "es", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "locale" : "es", 30 | "scale" : "3x" 31 | } 32 | ], 33 | "info" : { 34 | "version" : 1, 35 | "author" : "xcode" 36 | }, 37 | "properties" : { 38 | "localizable" : true 39 | } 40 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove_OLD.imageset/approve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallApprove_OLD.imageset/approve.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallApprove_OLD.imageset/approve_es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallApprove_OLD.imageset/approve_es.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAuth.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "auth.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | }, 16 | { 17 | "locale" : "es", 18 | "idiom" : "universal", 19 | "filename" : "auth_es.png", 20 | "scale" : "1x" 21 | }, 22 | { 23 | "idiom" : "universal", 24 | "locale" : "es", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "locale" : "es", 30 | "scale" : "3x" 31 | }, 32 | { 33 | "filename" : "auth_ko.png", 34 | "idiom" : "universal", 35 | "locale" : "ko", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "universal", 40 | "locale" : "ko", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "locale" : "ko", 46 | "scale" : "3x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | }, 53 | "properties" : { 54 | "localizable" : true 55 | } 56 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAuth.imageset/auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallAuth.imageset/auth.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAuth.imageset/auth_es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallAuth.imageset/auth_es.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallAuth.imageset/auth_ko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallAuth.imageset/auth_ko.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallBlocked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "blocked.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | }, 16 | { 17 | "locale" : "es", 18 | "idiom" : "universal", 19 | "filename" : "blocked_es.png", 20 | "scale" : "1x" 21 | }, 22 | { 23 | "idiom" : "universal", 24 | "locale" : "es", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "locale" : "es", 30 | "scale" : "3x" 31 | }, 32 | { 33 | "filename" : "blocked_ko.png", 34 | "idiom" : "universal", 35 | "locale" : "ko", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "universal", 40 | "locale" : "ko", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "locale" : "ko", 46 | "scale" : "3x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | }, 53 | "properties" : { 54 | "localizable" : true 55 | } 56 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallBlocked.imageset/blocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallBlocked.imageset/blocked.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallBlocked.imageset/blocked_es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallBlocked.imageset/blocked_es.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/InstallBlocked.imageset/blocked_ko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/InstallBlocked.imageset/blocked_ko.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/LuLuText.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "lulu_text.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "lulu_text-1.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "lulu_text-2.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/LuLuText.imageset/lulu_text-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/LuLuText.imageset/lulu_text-1.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/LuLuText.imageset/lulu_text-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/LuLuText.imageset/lulu_text-2.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/LuLuText.imageset/lulu_text.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/LuLuText.imageset/lulu_text.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsList.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "icon.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "icon.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "icon.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsList.imageset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsList.imageset/icon.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsMode.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "prefsMode Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "prefsMode Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "prefsMode Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsMode.imageset/prefsMode Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsMode.imageset/prefsMode Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsMode.imageset/prefsMode Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsMode.imageset/prefsMode Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsMode.imageset/prefsMode Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsMode.imageset/prefsMode Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsRules.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "prefsRules Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "prefsRules Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "prefsRules Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsRules.imageset/prefsRules Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsRules.imageset/prefsRules Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsRules.imageset/prefsRules Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsRules.imageset/prefsRules Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsRules.imageset/prefsRules Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsRules.imageset/prefsRules Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsUpdate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "prefsUpdate Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "prefsUpdate Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "prefsUpdate Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsUpdate.imageset/prefsUpdate Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsUpdate.imageset/prefsUpdate Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsUpdate.imageset/prefsUpdate Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsUpdate.imageset/prefsUpdate Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/PrefsUpdate.imageset/prefsUpdate Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/PrefsUpdate.imageset/prefsUpdate Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesAllow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "rulesAllow Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "rulesAllow Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "rulesAllow Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesAllow.imageset/rulesAllow Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesAllow.imageset/rulesAllow Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesAllow.imageset/rulesAllow Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesAllow.imageset/rulesAllow Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesAllow.imageset/rulesAllow Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesAllow.imageset/rulesAllow Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesBlock.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "block Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "block Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "block Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesBlock.imageset/block Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesBlock.imageset/block Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesBlock.imageset/block Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesBlock.imageset/block Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesBlock.imageset/block Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesBlock.imageset/block Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesSystem.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "rulesSystem light.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "rulesSystem light-1.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "rulesSystem dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesSystem.imageset/rulesSystem dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesSystem.imageset/rulesSystem dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesSystem.imageset/rulesSystem light-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesSystem.imageset/rulesSystem light-1.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/RulesSystem.imageset/rulesSystem light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/RulesSystem.imageset/rulesSystem light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Signed.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "signed Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "signed Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "signed Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "template-rendering-intent" : "template", 34 | "preserves-vector-representation" : true 35 | } 36 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Signed.imageset/signed Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Signed.imageset/signed Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Signed.imageset/signed Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Signed.imageset/signed Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Signed.imageset/signed Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Signed.imageset/signed Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedApple.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "signedApple Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "signedApple Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "signedApple Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "template-rendering-intent" : "template", 34 | "preserves-vector-representation" : true 35 | } 36 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedApple.imageset/signedApple Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/SignedApple.imageset/signedApple Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedApple.imageset/signedApple Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/SignedApple.imageset/signedApple Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedApple.imageset/signedApple Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/SignedApple.imageset/signedApple Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedUnknown.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "Unknown any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "Unknown light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "Unknown dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "template-rendering-intent" : "template", 34 | "preserves-vector-representation" : true 35 | } 36 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedUnknown.imageset/Unknown any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/SignedUnknown.imageset/Unknown any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedUnknown.imageset/Unknown dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/SignedUnknown.imageset/Unknown dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/SignedUnknown.imageset/Unknown light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/SignedUnknown.imageset/Unknown light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/StatusActive.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "LoginItem StatusBar Active.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template", 14 | "preserves-vector-representation" : true 15 | } 16 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/StatusActive.imageset/LoginItem StatusBar Active.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/StatusActive.imageset/LoginItem StatusBar Active.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/StatusInactive.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "LoginItem StatusBar Inactive.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template", 14 | "preserves-vector-representation" : true 15 | } 16 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/StatusInactive.imageset/LoginItem StatusBar Inactive.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/StatusInactive.imageset/LoginItem StatusBar Inactive.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Unsigned.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "unsigned Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "unsigned Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "unsigned Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "template-rendering-intent" : "template", 34 | "preserves-vector-representation" : true 35 | } 36 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Unsigned.imageset/unsigned Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Unsigned.imageset/unsigned Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Unsigned.imageset/unsigned Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Unsigned.imageset/unsigned Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/Unsigned.imageset/unsigned Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/Unsigned.imageset/unsigned Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/VTIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "VT Light.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "VT Any-1.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "VT Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "template-rendering-intent" : "template", 34 | "preserves-vector-representation" : true 35 | } 36 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/VTIcon.imageset/VT Any-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/VTIcon.imageset/VT Any-1.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/VTIcon.imageset/VT Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/VTIcon.imageset/VT Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/VTIcon.imageset/VT Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/VTIcon.imageset/VT Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/allow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "rulesAllow Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "rulesAllow Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "rulesAllow Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/allow.imageset/rulesAllow Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/allow.imageset/rulesAllow Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/allow.imageset/rulesAllow Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/allow.imageset/rulesAllow Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/allow.imageset/rulesAllow Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/allow.imageset/rulesAllow Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/block.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "block Any.pdf" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "block Light.pdf", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "block Dark.pdf", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/block.imageset/block Any.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/block.imageset/block Any.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/block.imageset/block Dark.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/block.imageset/block Dark.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/block.imageset/block Light.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/block.imageset/block Light.pdf -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/refresh.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "refresh.png", 5 | "idiom" : "mac" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "light" 12 | } 13 | ], 14 | "filename" : "refresh.png", 15 | "idiom" : "mac" 16 | }, 17 | { 18 | "appearances" : [ 19 | { 20 | "appearance" : "luminosity", 21 | "value" : "dark" 22 | } 23 | ], 24 | "filename" : "refresh.png", 25 | "idiom" : "mac" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/refresh.imageset/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/refresh.imageset/refresh.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/rulesRecent.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "rulesRecent.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "rulesRecent.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "rulesRecent.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/rulesRecent.imageset/rulesRecent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/rulesRecent.imageset/rulesRecent.png -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/rulesUnknown.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "rulesUnknown.png" 6 | }, 7 | { 8 | "idiom" : "mac", 9 | "filename" : "rulesUnknown.png", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "mac", 19 | "filename" : "rulesUnknown.png", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | }, 32 | "properties" : { 33 | "preserves-vector-representation" : true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LuLu/App/Assets.xcassets/rulesUnknown.imageset/rulesUnknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/Assets.xcassets/rulesUnknown.imageset/rulesUnknown.png -------------------------------------------------------------------------------- /LuLu/App/Base.lproj/StatusBarPopover.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /LuLu/App/Base.lproj/UpdateWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /LuLu/App/Configure.h: -------------------------------------------------------------------------------- 1 | // 2 | // Configure.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 2/6/24. 6 | // Copyright © 2024 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef Configure_h 10 | #define Configure_h 11 | 12 | @import Foundation; 13 | 14 | @interface Configure : NSObject 15 | 16 | //quit 17 | -(void)quit; 18 | 19 | //install 20 | -(BOOL)install; 21 | 22 | //upgrade 23 | -(BOOL)upgrade; 24 | 25 | //uninstall 26 | -(BOOL)uninstall; 27 | 28 | @end 29 | 30 | #endif /* Configure_h */ 31 | -------------------------------------------------------------------------------- /LuLu/App/Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // Extension.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 9/11/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | @import OSLog; 10 | @import Foundation; 11 | @import NetworkExtension; 12 | @import SystemExtensions; 13 | 14 | typedef void(^replyBlockType)(BOOL); 15 | 16 | @interface Extension : NSObject 17 | 18 | /* PROPERTIES */ 19 | 20 | //reply 21 | @property(nonatomic, copy)replyBlockType replyBlock; 22 | 23 | 24 | /* METHODS */ 25 | 26 | //submit request to toggle extension 27 | -(void)toggleExtension:(NSUInteger)action reply:(replyBlockType)reply; 28 | 29 | //check if extension is running 30 | -(BOOL)isExtensionRunning; 31 | 32 | //activate/deactive network extension 33 | -(BOOL)toggleNetworkExtension:(NSUInteger)action; 34 | 35 | //get network extension's status 36 | -(BOOL)isNetworkExtensionEnabled; 37 | 38 | @end 39 | 40 | -------------------------------------------------------------------------------- /LuLu/App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | LSUIElement 26 | 27 | NSHumanReadableCopyright 28 | Copyright (c) 2020 Objective-See. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplicationKeyEvents 33 | NSSupportsAutomaticTermination 34 | 35 | NSSupportsSuddenTermination 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /LuLu/App/InfoPlist.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "CFBundleName" : { 5 | "comment" : "Bundle name", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "de" : { 9 | "stringUnit" : { 10 | "state" : "translated", 11 | "value" : "LuLu" 12 | } 13 | }, 14 | "en" : { 15 | "stringUnit" : { 16 | "state" : "new", 17 | "value" : "LuLu" 18 | } 19 | }, 20 | "es" : { 21 | "stringUnit" : { 22 | "state" : "translated", 23 | "value" : "LuLu" 24 | } 25 | }, 26 | "ko" : { 27 | "stringUnit" : { 28 | "state" : "translated", 29 | "value" : "LuLu" 30 | } 31 | }, 32 | "pt-BR" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "LuLu" 36 | } 37 | }, 38 | "tr" : { 39 | "stringUnit" : { 40 | "state" : "translated", 41 | "value" : "LuLu" 42 | } 43 | }, 44 | "zh-Hans" : { 45 | "stringUnit" : { 46 | "state" : "translated", 47 | "value" : "LuLu" 48 | } 49 | }, 50 | "zh-Hant" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "LuLu" 54 | } 55 | } 56 | } 57 | }, 58 | "NSHumanReadableCopyright" : { 59 | "comment" : "Copyright (human-readable)", 60 | "extractionState" : "extracted_with_value", 61 | "localizations" : { 62 | "de" : { 63 | "stringUnit" : { 64 | "state" : "translated", 65 | "value" : "Copyright (c) 2020 Objective-See. Alle Rechte vorbehalten." 66 | } 67 | }, 68 | "en" : { 69 | "stringUnit" : { 70 | "state" : "new", 71 | "value" : "Copyright (c) 2020 Objective-See. All rights reserved." 72 | } 73 | }, 74 | "es" : { 75 | "stringUnit" : { 76 | "state" : "translated", 77 | "value" : "Copyright (c) 2020 Objective-See. Todos los derechos reservados." 78 | } 79 | }, 80 | "ko" : { 81 | "stringUnit" : { 82 | "state" : "translated", 83 | "value" : "Copyright (c) 2020 Objective-See. 모든 권리 보유." 84 | } 85 | }, 86 | "pt-BR" : { 87 | "stringUnit" : { 88 | "state" : "translated", 89 | "value" : "Copyright (c) 2020 Objective-See. Todos os direitos reservados." 90 | } 91 | }, 92 | "tr" : { 93 | "stringUnit" : { 94 | "state" : "translated", 95 | "value" : "Telif hakkı © 2020 Objective-See. Tüm hakları saklıdır." 96 | } 97 | }, 98 | "zh-Hans" : { 99 | "stringUnit" : { 100 | "state" : "translated", 101 | "value" : "版权所有 (c) 2020 Objective-See. 保留一切权利。" 102 | } 103 | }, 104 | "zh-Hant" : { 105 | "stringUnit" : { 106 | "state" : "translated", 107 | "value" : "版權所有 (c) 2020 Objective-See. 保留一切權利。" 108 | } 109 | } 110 | } 111 | } 112 | }, 113 | "version" : "1.0" 114 | } -------------------------------------------------------------------------------- /LuLu/App/ItemPathsWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ItemPathsWindowController.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 9/19/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | @import Cocoa; 10 | @import OSLog; 11 | 12 | #import "Rule.h" 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @interface ItemPathsWindowController : NSWindowController 17 | 18 | //item's rules 19 | @property(nonatomic, retain)NSDictionary* item; 20 | 21 | //item paths 22 | @property (weak) IBOutlet NSTextField *itemPaths; 23 | 24 | //close button 25 | @property (weak) IBOutlet NSButton *closeButton; 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /LuLu/App/ItemPathsWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ItemPathsWindowController.m 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 9/19/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "consts.h" 10 | #import "signing.h" 11 | #import "utilities.h" 12 | #import "XPCDaemonClient.h" 13 | #import "ItemPathsWindowController.h" 14 | 15 | /* GLOBALS */ 16 | 17 | //log handle 18 | extern os_log_t logHandle; 19 | 20 | //xpc for daemon comms 21 | extern XPCDaemonClient* xpcDaemonClient; 22 | 23 | @implementation ItemPathsWindowController 24 | 25 | @synthesize item; 26 | 27 | //generate and show paths 28 | -(void)windowDidLoad { 29 | 30 | //super 31 | [super windowDidLoad]; 32 | 33 | //unique paths 34 | NSMutableSet* paths = nil; 35 | 36 | //dbg msg 37 | os_log_debug(logHandle, "method '%s' invoked", __PRETTY_FUNCTION__); 38 | 39 | paths = [self getPaths]; 40 | 41 | //each rule's path 42 | for(NSString* path in paths) 43 | { 44 | if(0 == self.itemPaths.stringValue.length) 45 | { 46 | self.itemPaths.stringValue = [NSString stringWithFormat:@"▪ %@", path]; 47 | } 48 | //otherwise 49 | // append to existing 50 | else 51 | { 52 | self.itemPaths.stringValue = [NSString stringWithFormat:@"%@\r\n▪ %@", self.itemPaths.stringValue, path]; 53 | } 54 | } 55 | 56 | //make close button first responder 57 | [self.window makeFirstResponder:self.closeButton]; 58 | 59 | return; 60 | } 61 | 62 | //get all unique paths for item 63 | // both from rules, but also from system (via bundle ID) 64 | -(NSMutableSet*)getPaths 65 | { 66 | //(first) rule 67 | Rule* rule = nil; 68 | 69 | //items 70 | NSArray* items = nil; 71 | 72 | //paths 73 | NSMutableSet* paths = nil; 74 | 75 | //item bundle id 76 | NSString* bundleID = nil; 77 | 78 | //signing info 79 | NSMutableDictionary* signingInfo = nil; 80 | 81 | //init 82 | paths = [NSMutableSet set]; 83 | 84 | //extract (first) rule 85 | rule = [self.item[KEY_RULES] firstObject]; 86 | 87 | //global rule? 88 | if(YES == rule.isGlobal.boolValue) 89 | { 90 | //set message 91 | [paths addObject:NSLocalizedString(@"Global Rules apply to all paths", @"Global Rules apply to all paths")]; 92 | 93 | //done 94 | goto bail; 95 | } 96 | 97 | //directory rule? 98 | else if(YES == rule.isDirectory.boolValue) 99 | { 100 | //set message 101 | [paths addObject:NSLocalizedString(@"Directory Rules apply to all items within the directory", @"Directory Rules apply to all items within the directory")]; 102 | 103 | //done 104 | goto bail; 105 | } 106 | 107 | //first add rule's path 108 | if(nil != rule.path) 109 | { 110 | //add 111 | [paths addObject:rule.path]; 112 | } 113 | 114 | //add any external paths 115 | [paths unionSet:item[KEY_PATHS]]; 116 | 117 | //grab bundle id 118 | bundleID = rule.csInfo[KEY_CS_ID]; 119 | 120 | //add other items on system 121 | // with same bundle id *and* cs info, as these will match 122 | if(nil != bundleID) 123 | { 124 | //get matching apps 125 | items = (__bridge NSArray *)(LSCopyApplicationURLsForBundleIdentifier((__bridge CFStringRef _Nonnull)(bundleID), nil)); 126 | 127 | //get each item's binary 128 | for(NSURL* item in items) 129 | { 130 | //path 131 | NSString* path = nil; 132 | 133 | //attempt to get path via bundle 134 | path = getBundleExecutable(item.path); 135 | 136 | //likely not bundle 137 | if(0 == path.length) 138 | { 139 | path = item.path; 140 | } 141 | 142 | //sanity check 143 | if(0 == path.length) 144 | { 145 | //skip 146 | continue; 147 | } 148 | 149 | //extract signing info and check 150 | // note: use item's path, to match rule 151 | signingInfo = extractSigningInfo(0, item.path, kSecCSDefaultFlags); 152 | if(YES != matchesCSInfo(self.item[KEY_CS_INFO], signingInfo)) 153 | { 154 | //dbg msg 155 | os_log_debug(logHandle, "rule's code signing info %{public}@ doesn't match item's %{public}@", self.item[KEY_CS_INFO], signingInfo); 156 | 157 | //skip 158 | continue; 159 | } 160 | 161 | //add 162 | [paths addObject:path]; 163 | } 164 | } 165 | 166 | bail: 167 | 168 | return paths; 169 | 170 | } 171 | 172 | //close 173 | -(IBAction)closeButtonHandler:(id)sender { 174 | 175 | //dbg msg 176 | os_log_debug(logHandle, "user clicked: %{public}@", ((NSButton*)sender).title); 177 | 178 | //close & return NSModalResponseCancel 179 | [self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK]; 180 | 181 | return; 182 | } 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /LuLu/App/NSApplicationKeyEvents.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: NSApplicationKeyEvents.h 3 | // project: LuLu 4 | // description: adds support for keyboard shortcuts (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2020 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface NSApplicationKeyEvents : NSApplication 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LuLu/App/NSApplicationKeyEvents.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: NSApplicationKeyEvents.h 3 | // project: LuLu 4 | // description: adds support for keyboard shortcuts (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2020 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "consts.h" 11 | #import "AppDelegate.h" 12 | #import "NSApplicationKeyEvents.h" 13 | 14 | @implementation NSApplicationKeyEvents 15 | 16 | //to enable copy/paste etc even though we don't have an 'Edit' menu 17 | // details: http://stackoverflow.com/questions/970707/cocoa-keyboard-shortcuts-in-dialog-without-an-edit-menu 18 | -(void)sendEvent:(NSEvent*)event 19 | { 20 | //only care about key down 21 | if(NSEventTypeKeyDown != event.type) 22 | { 23 | //bail 24 | goto bail; 25 | } 26 | 27 | //delete? 28 | // in Rules window/table, delete row 29 | if( (NSDeleteCharacter == [event.charactersIgnoringModifiers characterAtIndex:0]) && 30 | (YES == [event.window.identifier isEqualToString:@"Rules"]) && 31 | (YES == [event.window.firstResponder.className isEqualToString:@"RulesTable"]) ) 32 | { 33 | //delete rule 34 | [[((AppDelegate*)[[NSApplication sharedApplication] delegate]) rulesWindowController] deleteRule:nil]; 35 | return; 36 | } 37 | 38 | //otherwise 39 | // ...only care about key down + command 40 | if(NSEventModifierFlagCommand != (event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask)) 41 | { 42 | //bail 43 | goto bail; 44 | } 45 | 46 | //+c (copy) 47 | if(YES == [event.charactersIgnoringModifiers isEqualToString:@"c"]) 48 | { 49 | //copy 50 | if(YES == [self sendAction:@selector(copy:) to:nil from:self]) 51 | { 52 | return; 53 | } 54 | } 55 | 56 | //+v (paste) 57 | else if ([event.charactersIgnoringModifiers isEqualToString:@"v"]) 58 | { 59 | //paste 60 | if(YES == [self sendAction:@selector(paste:) to:nil from:self]) 61 | { 62 | return; 63 | } 64 | } 65 | 66 | //+x (cut) 67 | else if ([event.charactersIgnoringModifiers isEqualToString:@"x"]) 68 | { 69 | //cut 70 | if(YES == [self sendAction:@selector(cut:) to:nil from:self]) 71 | { 72 | return; 73 | } 74 | } 75 | 76 | //+a (select all) 77 | else if([event.charactersIgnoringModifiers isEqualToString:@"a"]) 78 | { 79 | //select 80 | if(YES == [self sendAction:@selector(selectAll:) to:nil from:self]) 81 | { 82 | return; 83 | } 84 | } 85 | 86 | //+h (hide window) 87 | else if([event.charactersIgnoringModifiers isEqualToString:@"h"]) 88 | { 89 | //hide 90 | if(YES == [self sendAction:@selector(hide:) to:nil from:self]) 91 | { 92 | return; 93 | } 94 | } 95 | 96 | //+m (minimize window) 97 | else if([event.charactersIgnoringModifiers isEqualToString:@"m"]) 98 | { 99 | //minimize 100 | [NSApplication.sharedApplication.keyWindow miniaturize:nil]; 101 | return; 102 | } 103 | 104 | //+w (close window) 105 | // unless its an alert ...need response! 106 | else if( ([event.charactersIgnoringModifiers isEqualToString:@"w"]) && 107 | (YES != [event.window.identifier isEqualToString:@"Alert"]) ) 108 | { 109 | //close 110 | [NSApplication.sharedApplication.keyWindow close]; 111 | return; 112 | } 113 | 114 | //+f (find, but only in rules window) 115 | else if( ([event.charactersIgnoringModifiers isEqualToString:@"f"]) && 116 | (YES == [event.window.identifier isEqualToString:@"Rules"]) ) 117 | { 118 | //iterate over all toolbar items 119 | // ...find rule search field, and select 120 | for(NSToolbarItem* item in NSApplication.sharedApplication.keyWindow.toolbar.items) 121 | { 122 | //not search field? skip 123 | if(RULE_SEARCH_FIELD != item.tag) continue; 124 | 125 | //and make it first responder 126 | [NSApplication.sharedApplication.keyWindow makeFirstResponder:item.view]; 127 | 128 | //done 129 | return; 130 | } 131 | } 132 | 133 | //+, (show preferences) 134 | else if([event.charactersIgnoringModifiers isEqualToString:@","]) 135 | { 136 | //show 137 | [((AppDelegate*)[[NSApplication sharedApplication] delegate]) showPreferences:nil]; 138 | return; 139 | } 140 | 141 | bail: 142 | 143 | //super 144 | [super sendEvent:event]; 145 | 146 | return; 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /LuLu/App/ParentsWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: ParentsWindowController.h 3 | // project: lulu (login item) 4 | // description: window controller for process heirachy (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface ParentsWindowController : NSViewController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //process hierarchy 20 | @property (nonatomic, retain)NSArray* processHierarchy; 21 | 22 | /* METHODS */ 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /LuLu/App/ParentsWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: ParentsWindowController.m 3 | // project: lulu (login item) 4 | // description: window controller for process heirachy 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "consts.h" 11 | #import "ParentsWindowController.h" 12 | 13 | @implementation ParentsWindowController 14 | 15 | //automatically invoked 16 | // return number of children, simply either 1, or 0 (for last item) 17 | -(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item 18 | { 19 | //# of kids 20 | // defaults to 1 21 | NSInteger kidCount = 1; 22 | 23 | //for last item 24 | // no more kids... 25 | if( (1 != self.processHierarchy.count) && 26 | ([((NSDictionary*)item)[KEY_INDEX] integerValue] == self.processHierarchy.count-1) ) 27 | { 28 | //no kids 29 | kidCount = 0; 30 | } 31 | 32 | return kidCount; 33 | } 34 | 35 | //automatically invoked to determine if item is expandable 36 | // always the case, except for the last item 37 | -(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item 38 | { 39 | //flag 40 | // ->defaults to yes 41 | BOOL isExpandable = YES; 42 | 43 | //for last item 44 | // no kids, so obv. no expandable 45 | if([((NSDictionary*)item)[KEY_INDEX] integerValue] == self.processHierarchy.count-1) 46 | { 47 | //last one 48 | isExpandable = NO; 49 | } 50 | 51 | return isExpandable; 52 | } 53 | 54 | //automatically invoked to get the child item 55 | -(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item 56 | { 57 | //item 58 | id itemForRow = nil; 59 | 60 | //item is nil for root 61 | // just provide root item 62 | if(nil == item) 63 | { 64 | //first item 65 | itemForRow = self.processHierarchy[0]; 66 | } 67 | 68 | //other items 69 | // return *their* child! 70 | else 71 | { 72 | //child at index 73 | itemForRow = self.processHierarchy[[((NSDictionary*)item)[KEY_INDEX] integerValue]+1]; 74 | } 75 | 76 | return itemForRow; 77 | } 78 | 79 | //automatically invoked to get the object for the row 80 | // return items name/pid 81 | -(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item 82 | { 83 | //row value 84 | NSString* rowValue = nil; 85 | 86 | //init string for row 87 | // process name + pid 88 | // note: if this format changes, also change row width calculation in AlertWindowController! 89 | rowValue = [NSString stringWithFormat:NSLocalizedString(@"%@ (pid: %@)",@"%@ (pid: %@)"), ((NSDictionary*)item)[KEY_PROCESS_NAME], ((NSDictionary*)item)[@"pid"]]; 90 | 91 | return rowValue; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /LuLu/App/PrefsWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: PrefsWindowController.h 3 | // project: lulu (main app) 4 | // description: preferences window controller (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | @import OSLog; 12 | 13 | #import "XPCDaemonClient.h" 14 | #import "UpdateWindowController.h" 15 | 16 | /* CONSTS */ 17 | 18 | //rules view 19 | #define TOOLBAR_RULES 0 20 | 21 | //modes view 22 | #define TOOLBAR_MODES 1 23 | 24 | //update view 25 | #define TOOLBAR_LISTS 2 26 | 27 | //update view 28 | #define TOOLBAR_UPDATE 3 29 | 30 | //to select, need string ID 31 | #define TOOLBAR_RULES_ID @"Rules" 32 | 33 | @interface PrefsWindowController : NSWindowController 34 | 35 | /* PROPERTIES */ 36 | 37 | //preferences 38 | @property(nonatomic, retain)NSDictionary* preferences; 39 | 40 | //toolbar 41 | @property (weak) IBOutlet NSToolbar* toolbar; 42 | 43 | //rules prefs view 44 | @property (weak) IBOutlet NSView* rulesView; 45 | 46 | //modes view 47 | @property (strong) IBOutlet NSView* modesView; 48 | 49 | //passive mode action ...allow or block? 50 | @property (weak) IBOutlet NSPopUpButton* passiveModeAction; 51 | 52 | //passive mode rules ...create, or not? 53 | @property (weak) IBOutlet NSPopUpButton* passiveModeRules; 54 | 55 | //(block/allow) lists view 56 | @property (strong) IBOutlet NSView *listsView; 57 | 58 | //allow list 59 | @property (weak) IBOutlet NSTextField *allowList; 60 | 61 | //select allow list button 62 | @property (weak) IBOutlet NSButton *selectAllowListButton; 63 | 64 | //block list 65 | @property (weak) IBOutlet NSTextField* blockList; 66 | 67 | //select block list button 68 | @property (weak) IBOutlet NSButton* selectBlockListButton; 69 | 70 | 71 | //update view 72 | @property (weak) IBOutlet NSView* updateView; 73 | 74 | //update button 75 | @property (weak) IBOutlet NSButton* updateButton; 76 | 77 | //update indicator (spinner) 78 | @property (weak) IBOutlet NSProgressIndicator* updateIndicator; 79 | 80 | //update label 81 | @property (weak) IBOutlet NSTextField* updateLabel; 82 | 83 | //update window controller 84 | @property(nonatomic, retain)UpdateWindowController* updateWindowController; 85 | 86 | /* METHODS */ 87 | 88 | //toolbar button handler 89 | -(IBAction)toolbarButtonHandler:(id)sender; 90 | 91 | //button handler for all preference buttons 92 | -(IBAction)togglePreference:(id)sender; 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /LuLu/App/RuleRow.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: RuleRow.h 3 | // project: lulu (main app) 4 | // description: row for 'rules' table (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface RuleRow : NSTableRowView 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LuLu/App/RuleRow.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: RuleRow.m 3 | // project: lulu (main app) 4 | // description: row for 'rules' table 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "RuleRow.h" 11 | 12 | @implementation RuleRow 13 | 14 | //custom row selection 15 | -(void)drawSelectionInRect:(NSRect)dirtyRect 16 | { 17 | //selection rect 18 | NSRect selectionRect = {0}; 19 | 20 | //selection path 21 | NSBezierPath* selectionPath = nil; 22 | 23 | //selection color 24 | NSColor* selectionColor = nil; 25 | 26 | //highlight selected rows 27 | if(self.selectionHighlightStyle != NSTableViewSelectionHighlightStyleNone) 28 | { 29 | //make selection rect 30 | selectionRect = NSInsetRect(self.bounds, 2.5, 2.5); 31 | 32 | //set color 33 | selectionColor = [NSColor unemphasizedSelectedContentBackgroundColor]; 34 | 35 | //set stroke 36 | [selectionColor setStroke]; 37 | 38 | //set fill 39 | [selectionColor setFill]; 40 | 41 | //create selection path 42 | // with rounded corners (5x5) 43 | selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:5 yRadius:5]; 44 | 45 | //fill 46 | [selectionPath fill]; 47 | 48 | //stroke 49 | [selectionPath stroke]; 50 | } 51 | 52 | return; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /LuLu/App/RuleRowCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: RuleRowCell.h 3 | // project: lulu (main app) 4 | // description: cell for 'rules' table (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface RuleRowCell : NSTableCellView 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LuLu/App/RuleRowCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: RuleRowCell.m 3 | // project: lulu (main app) 4 | // description: cell for 'rules' table 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "RuleRowCell.h" 11 | 12 | @implementation RuleRowCell 13 | 14 | //set background style 15 | -(void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle 16 | { 17 | //light 18 | [super setBackgroundStyle: NSBackgroundStyleRaised]; 19 | 20 | return; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /LuLu/App/RulesMenuController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RulesMenuController.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 1/30/24. 6 | // Copyright © 2024 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef RulesMenuController_h 10 | #define RulesMenuController_h 11 | 12 | @import Foundation; 13 | 14 | @interface RulesMenuController : NSObject 15 | 16 | /* METHODS */ 17 | 18 | -(void)addRule; 19 | -(void)showRules; 20 | -(void)exportRules; 21 | -(BOOL)importRules; 22 | -(NSInteger)cleanupRules; 23 | 24 | @end 25 | 26 | #endif /* RulesMenuController_h */ 27 | -------------------------------------------------------------------------------- /LuLu/App/RulesTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: RuleTable.h 3 | // project: lulu 4 | // description: subclass for rules table (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2020 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface RulesTable : NSOutlineView 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LuLu/App/RulesTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: RuleTable.m 3 | // project: lulu 4 | // description: subclass for rules table 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2020 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Rule.h" 11 | #import "consts.h" 12 | #import "utilities.h" 13 | #import "RulesTable.h" 14 | #import "RulesWindowController.h" 15 | 16 | @implementation RulesTable 17 | 18 | //override 19 | // create context/right click menu 20 | -(NSMenu*)menuForEvent:(NSEvent *)event 21 | { 22 | //item 23 | id item = nil; 24 | 25 | //selected row 26 | NSInteger selectedRow = -1; 27 | 28 | //menu 29 | NSMenu* menu = nil; 30 | 31 | //covert mouse click to selected row 32 | selectedRow = [self rowAtPoint:[self convertPoint:[event locationInWindow] fromView:nil]]; 33 | if(-1 == selectedRow) 34 | { 35 | //bail 36 | goto bail; 37 | } 38 | 39 | //make it selected 40 | [self selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO]; 41 | 42 | //get item 43 | item = [((RulesWindowController*)self.delegate).outlineView itemAtRow:selectedRow]; 44 | if(nil == item) 45 | { 46 | //bail 47 | goto bail; 48 | } 49 | 50 | //alloc menu 51 | menu = [[NSMenu alloc] init]; 52 | 53 | //set delegate 54 | // 'RulesWindowController' 55 | menu.delegate = (id)self.delegate; 56 | 57 | //don't auto enable 58 | menu.autoenablesItems = NO; 59 | 60 | //item row? 61 | // show paths 62 | if(YES == [item isKindOfClass:[NSArray class]]) 63 | { 64 | //add item 65 | [menu insertItemWithTitle:NSLocalizedString(@"→ Show path(s)", @"→ Show path(s)") action:NSSelectorFromString(@"rowMenuHandler:") keyEquivalent:@"" atIndex:0]; 66 | 67 | //set tag 68 | menu.itemArray.firstObject.tag = MENU_SHOW_PATHS; 69 | 70 | //enable 71 | menu.itemArray.lastObject.enabled = YES; 72 | 73 | //add delete 74 | [menu insertItemWithTitle:NSLocalizedString(@"→ Delete rule(s)", @"→ Delete rule(s)") action:NSSelectorFromString(@"rowMenuHandler:") keyEquivalent:@"" atIndex:1]; 75 | 76 | //set tag 77 | menu.itemArray.lastObject.tag = MENU_DELETE_RULE; 78 | 79 | //enable 80 | menu.itemArray.lastObject.enabled = YES; 81 | } 82 | 83 | //rule row 84 | else if(YES == [item isKindOfClass:[Rule class]]) 85 | { 86 | //set title 87 | [menu insertItemWithTitle:NSLocalizedString(@"→ Edit Rule", @"→ Edit Rule") action:NSSelectorFromString(@"rowMenuHandler:") keyEquivalent:@"" atIndex:0]; 88 | 89 | //set tag 90 | menu.itemArray.firstObject.tag = MENU_EDIT_RULE; 91 | 92 | //add delete 93 | [menu insertItemWithTitle:NSLocalizedString(@"→ Delete Rule", @"→ Delete Rule") action:NSSelectorFromString(@"rowMenuHandler:") keyEquivalent:@"" atIndex:1]; 94 | 95 | //set tag 96 | menu.itemArray.lastObject.tag = MENU_DELETE_RULE; 97 | 98 | //enable 99 | toggleMenu(menu, YES); 100 | } 101 | 102 | bail: 103 | 104 | return menu; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /LuLu/App/RulesWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: RulesWindowController.h 3 | // project: lulu (main app) 4 | // description: window controller for 'rules' table (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | @import OSLog; 12 | 13 | #import "Rule.h" 14 | #import "XPCDaemonClient.h" 15 | #import "AddRuleWindowController.h" 16 | #import "ItemPathsWindowController.h" 17 | 18 | #import "3rd-party/OrderedDictionary.h" 19 | 20 | /* CONSTS */ 21 | 22 | //id (tag) for detailed text in category table 23 | #define TABLE_ROW_NAME_TAG 100 24 | 25 | //id (tag) for detailed text 26 | #define TABLE_ROW_SUB_TEXT 101 27 | 28 | //id (tag) for delete button 29 | #define TABLE_ROW_DELETE_TAG 110 30 | 31 | //show path(s) 32 | #define MENU_SHOW_PATHS 0 33 | 34 | //edit rule(s) 35 | #define MENU_EDIT_RULE 1 36 | 37 | //delete rule(s) 38 | #define MENU_DELETE_RULE 2 39 | 40 | 41 | /* INTERFACE */ 42 | 43 | @interface RulesWindowController : NSWindowController 44 | 45 | /* PROPERTIES */ 46 | 47 | //(main) outline view 48 | @property (weak) IBOutlet NSOutlineView *outlineView; 49 | 50 | //observer for rules changed 51 | @property(nonatomic, retain)id rulesObserver; 52 | 53 | //loading rules overlay 54 | @property (weak) IBOutlet NSVisualEffectView* loadingRules; 55 | 56 | //loading rules spinner 57 | @property (weak) IBOutlet NSProgressIndicator* loadingRulesSpinner; 58 | 59 | //table items 60 | @property(nonatomic, retain)OrderedDictionary* rules; 61 | 62 | //rules view selector 63 | @property (weak) IBOutlet NSPopUpButton *rulesViewSelector; 64 | 65 | //table items 66 | // ...but filtered 67 | @property(nonatomic, retain)OrderedDictionary* rulesFiltered; 68 | 69 | //search box 70 | @property (weak) IBOutlet NSSearchField *filterBox; 71 | 72 | //top level view 73 | @property (weak) IBOutlet NSView *view; 74 | 75 | //window toolbar 76 | @property (weak) IBOutlet NSToolbar *toolbar; 77 | 78 | //selected index in rule view selector 79 | @property NSInteger selectedRuleView; 80 | 81 | //show item path(s) popup contoller 82 | @property(strong) ItemPathsWindowController *itemPathsWindowController; 83 | 84 | //panel for 'add rule' 85 | @property (weak) IBOutlet NSView *addRulePanel; 86 | 87 | //label for add rules button 88 | @property (weak) IBOutlet NSTextField *addRuleLabel; 89 | 90 | //button to add rules 91 | @property (weak) IBOutlet NSButton *addRuleButton; 92 | 93 | //add rules popup controller 94 | @property (strong) AddRuleWindowController *addRuleWindowController; 95 | 96 | //(last) added rule 97 | @property(nonatomic,retain)NSString* addedRule; 98 | 99 | //flag 100 | @property BOOL isAscending; 101 | 102 | /* METHODS */ 103 | 104 | //configure (UI) 105 | -(void)configure; 106 | 107 | //add a rule 108 | -(IBAction)addRule:(id)sender; 109 | 110 | //delete a rule 111 | -(IBAction)deleteRule:(id)sender; 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /LuLu/App/SigningInfoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: SigningInfoViewController 3 | // project: lulu (login item) 4 | // description: view controller for signing info popup (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | /* DEFINES */ 13 | 14 | //signing auths view 15 | #define SIGNING_AUTH_1 1 16 | 17 | @interface SigningInfoViewController : NSViewController 18 | { 19 | 20 | } 21 | 22 | /* METHODS */ 23 | 24 | 25 | /* PROPERTIES */ 26 | 27 | //alert info 28 | @property(nonatomic, retain)NSDictionary* alert; 29 | 30 | //signing icon 31 | @property (weak) IBOutlet NSImageView* icon; 32 | 33 | //main signing msg 34 | @property (weak) IBOutlet NSTextField* message; 35 | 36 | //details 37 | @property (weak) IBOutlet NSTextField* details; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LuLu/App/StartupWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: StartupWindowController.h 3 | // 4 | // created by Patrick Wardle 5 | // copyright (c) 2024 Objective-See. All rights reserved. 6 | // 7 | 8 | @import Cocoa; 9 | @import OSLog; 10 | 11 | @interface StartupWindowController : NSWindowController 12 | { 13 | 14 | } 15 | 16 | //version warning msg 17 | @property (weak) IBOutlet NSTextField *versionWarning; 18 | 19 | //activity indicator 20 | @property (weak) IBOutlet NSProgressIndicator *spinner; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /LuLu/App/StartupWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: StartupWindowController.m 3 | // 4 | // created by Patrick Wardle 5 | // copyright (c) 2024 Objective-See. All rights reserved. 6 | // 7 | 8 | #import "consts.h" 9 | #import "utilities.h" 10 | #import "AppDelegate.h" 11 | #import "StartupWindowController.h" 12 | 13 | /* GLOBALS */ 14 | 15 | //log handle 16 | extern os_log_t logHandle; 17 | 18 | @implementation StartupWindowController 19 | 20 | @synthesize spinner; 21 | 22 | //automatically called when nib is loaded 23 | -(void)awakeFromNib 24 | { 25 | //center 26 | [self.window center]; 27 | 28 | //start progress indicator 29 | [self.spinner startAnimation:nil]; 30 | 31 | //not in dark mode? 32 | // make window white 33 | if(YES != isDarkMode()) 34 | { 35 | //make white 36 | self.window.backgroundColor = NSColor.whiteColor; 37 | } 38 | 39 | //set transparency 40 | self.window.titlebarAppearsTransparent = YES; 41 | 42 | //need to display warning? 43 | [self displayVersionWarning]; 44 | 45 | //make it key window 46 | [self.window makeKeyAndOrderFront:self]; 47 | 48 | //activate 49 | if(@available(macOS 14.0, *)) { 50 | [NSApp activate]; 51 | } 52 | else 53 | { 54 | [NSApp activateIgnoringOtherApps:YES]; 55 | } 56 | 57 | //(re)make front 58 | [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; 59 | 60 | return; 61 | } 62 | 63 | //show version warning if on macOS 15, but less than 15.3 64 | -(void)displayVersionWarning 65 | { 66 | //get OS version 67 | NSOperatingSystemVersion version = NSProcessInfo.processInfo.operatingSystemVersion; 68 | 69 | //default hide 70 | self.versionWarning.hidden = YES; 71 | 72 | //macOS 15 73 | // but less than 15.3? ...warn 74 | if(version.majorVersion == 15 && version.minorVersion < 3) { 75 | 76 | //show warning 77 | self.versionWarning.hidden = NO; 78 | } 79 | 80 | return; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /LuLu/App/StatusBarItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: StatusBarMenu.h 3 | // project: lulu (login item) 4 | // description: menu handler for status bar icon (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | 11 | @import Cocoa; 12 | @import OSLog; 13 | 14 | #import "RulesMenuController.h" 15 | 16 | @interface StatusBarItem : NSObject 17 | { 18 | 19 | } 20 | 21 | //status item 22 | @property(nonatomic, strong, readwrite)NSStatusItem* statusItem; 23 | 24 | //rules (sub)menu handler 25 | @property(nonatomic, retain)RulesMenuController* rulesMenuController; 26 | 27 | //popover 28 | @property(retain, nonatomic)NSPopover* popover; 29 | 30 | //disabled flag 31 | @property BOOL isDisabled; 32 | 33 | 34 | /* METHODS */ 35 | 36 | //remove status item 37 | -(void)removeStatusItem; 38 | 39 | //init 40 | -(id)init:(NSMenu*)menu preferences:(NSDictionary*)preferences; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /LuLu/App/StatusBarPopoverController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: StatusBarPopoverController.h 3 | // project: lulu (login item) 4 | // description: popover for status bar (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface StatusBarPopoverController : NSViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LuLu/App/StatusBarPopoverController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: StatusBarPopoverController.m 3 | // project: lulu (login item) 4 | // description: popover for status bar 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "AppDelegate.h" 11 | #import "StatusBarPopoverController.h" 12 | 13 | @implementation StatusBarPopoverController 14 | 15 | //'close' button handler 16 | // simply dismiss/close popover 17 | -(IBAction)closePopover:(NSControl *)sender 18 | { 19 | //close 20 | [[[self view] window] close]; 21 | 22 | return; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /LuLu/App/Update.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: Update.h 3 | // project: lulu (shared) 4 | // description: checks for new versions of LuLu (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | 11 | #ifndef Update_h 12 | #define Update_h 13 | 14 | @import Cocoa; 15 | @import Foundation; 16 | 17 | @interface Update : NSObject 18 | 19 | //check for an update 20 | // will invoke app delegate method to update UI when check completes 21 | -(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler; 22 | 23 | @end 24 | 25 | 26 | #endif /* Update_h */ 27 | -------------------------------------------------------------------------------- /LuLu/App/UpdateWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: UpdateWindowController.m 3 | // project: lulu 4 | // description: window handler for update window/popup (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2020 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | 12 | @interface UpdateWindowController : NSWindowController 13 | { 14 | 15 | } 16 | 17 | /* PROPERTIES */ 18 | 19 | //version label/string 20 | @property(weak)IBOutlet NSTextField *infoLabel; 21 | 22 | //action button 23 | @property(weak)IBOutlet NSButton *actionButton; 24 | 25 | //label string 26 | @property(nonatomic, retain)NSString* infoLabelString; 27 | 28 | 29 | /* METHODS */ 30 | 31 | //save the main label 32 | -(void)configure:(NSString*)label; 33 | 34 | //invoked when user clicks button 35 | // ->trigger action such as opening product website, updating, etc 36 | -(IBAction)buttonHandler:(id)sender; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /LuLu/App/UpdateWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: UpdateWindowController.m 3 | // project: lulu 4 | // description: window handler for update window/popup 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2020 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "consts.h" 11 | #import "utilities.h" 12 | #import "AppDelegate.h" 13 | #import "UpdateWindowController.h" 14 | 15 | @implementation UpdateWindowController 16 | 17 | @synthesize infoLabel; 18 | @synthesize actionButton; 19 | @synthesize infoLabelString; 20 | 21 | //automatically called when nib is loaded 22 | -(void)awakeFromNib 23 | { 24 | //center 25 | [self.window center]; 26 | 27 | return; 28 | } 29 | 30 | //automatically invoked when window is loaded 31 | -(void)windowDidLoad 32 | { 33 | //super 34 | [super windowDidLoad]; 35 | 36 | //not in dark mode? 37 | // make window white 38 | if(YES != isDarkMode()) 39 | { 40 | //make white 41 | self.window.backgroundColor = NSColor.whiteColor; 42 | } 43 | 44 | //indicated title bar is transparent (too) 45 | self.window.titlebarAppearsTransparent = YES; 46 | 47 | //set main label 48 | self.infoLabel.stringValue = self.infoLabelString; 49 | 50 | //make button first responder 51 | // calling this without a timeout sometimes fails :/ 52 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ 53 | 54 | //make first responder 55 | [self.window makeFirstResponder:self.actionButton]; 56 | 57 | }); 58 | 59 | //make it key window 60 | [self.window makeKeyAndOrderFront:self]; 61 | 62 | //activate 63 | if(@available(macOS 14.0, *)) { 64 | [NSApp activate]; 65 | } 66 | else 67 | { 68 | [NSApp activateIgnoringOtherApps:YES]; 69 | } 70 | 71 | //(re)make front 72 | [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; 73 | 74 | return; 75 | } 76 | 77 | //automatically invoked when window is closing 78 | // ->make ourselves unmodal 79 | -(void)windowWillClose:(NSNotification *)notification 80 | { 81 | //make un-modal 82 | [[NSApplication sharedApplication] stopModal]; 83 | 84 | return; 85 | } 86 | 87 | //save the main label 88 | -(void)configure:(NSString*)label 89 | { 90 | //save label's string 91 | self.infoLabelString = label; 92 | 93 | return; 94 | } 95 | 96 | //invoked when user clicks button 97 | -(IBAction)buttonHandler:(id)sender 98 | { 99 | //open URL 100 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:PRODUCT_URL]]; 101 | 102 | //always close window 103 | [[self window] close]; 104 | 105 | return; 106 | } 107 | @end 108 | -------------------------------------------------------------------------------- /LuLu/App/VirusTotal.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: VirusTotal.h 3 | // project: lulu (login item) 4 | // description: interface to VirusTotal (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import OSLog; 11 | @import Foundation; 12 | 13 | //query url 14 | #define VT_QUERY_URL @"https://www.virustotal.com/partners/sysinternals/file-reports?apikey=" 15 | 16 | //(public) api key 17 | #define VT_API_KEY @"233f22e200ca5822bd91103043ccac138b910db79f29af5616a9afe8b6f215ad" 18 | 19 | //user agent 20 | #define VT_USER_AGENT @"VirusTotal" 21 | 22 | //results 23 | #define VT_RESULTS @"data" 24 | 25 | //results response code 26 | #define VT_RESULTS_RESPONSE @"response_code" 27 | 28 | //result url 29 | #define VT_RESULTS_URL @"permalink" 30 | 31 | //result hash 32 | #define VT_RESULT_HASH @"hash" 33 | 34 | //results positives 35 | #define VT_RESULTS_POSITIVES @"positives" 36 | 37 | //results total 38 | #define VT_RESULTS_TOTAL @"total" 39 | 40 | @interface VirusTotal : NSObject 41 | { 42 | 43 | } 44 | 45 | /* METHODS */ 46 | 47 | //thread function 48 | // runs in the background to get virus total info about items 49 | -(BOOL)queryVT:(NSMutableDictionary*)item; 50 | 51 | //make the (POST)query to VT 52 | -(NSDictionary*)postRequest:(NSURL*)url postData:(NSData*)postData; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /LuLu/App/VirusTotalViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: VirusTotalViewController.h 3 | // project: lulu (login item) 4 | // description: view controller for VirusTotal results popup (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Cocoa; 11 | @import OSLog; 12 | 13 | @interface VirusTotalViewController : NSViewController 14 | { 15 | 16 | } 17 | 18 | /* METHODS */ 19 | 20 | 21 | /* PROPERTIES */ 22 | 23 | //item name 24 | @property(nonatomic, retain)NSString* itemName; 25 | 26 | //item path 27 | @property(nonatomic, retain)NSString* itemPath; 28 | 29 | //progress indicator 30 | @property(weak)IBOutlet NSProgressIndicator *vtSpinner; 31 | 32 | //query msg 33 | @property (unsafe_unretained) IBOutlet NSTextView *message; 34 | 35 | 36 | @end 37 | 38 | -------------------------------------------------------------------------------- /LuLu/App/WelcomeWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LinkWindowController.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 1/25/18. 6 | // Copyright (c) 2018 Objective-See. All rights reserved. 7 | // 8 | 9 | @import Cocoa; 10 | @import OSLog; 11 | 12 | #import "XPCDaemonClient.h" 13 | 14 | @interface WelcomeWindowController : NSWindowController 15 | 16 | /* PROPERTIES */ 17 | 18 | //main view controller 19 | @property(nonatomic, retain)NSViewController* welcomeViewController; 20 | 21 | //welcome view 22 | @property (strong) IBOutlet NSView *welcomeView; 23 | 24 | //allow extension view 25 | @property (strong) IBOutlet NSView *allowExtensionView; 26 | 27 | //allow extension spinner 28 | @property (weak) IBOutlet NSProgressIndicator *allowExtActivityIndicator; 29 | 30 | //allow extension message 31 | @property (weak) IBOutlet NSTextField *allowExtMessage; 32 | 33 | //approve extension image 34 | @property (weak) IBOutlet NSImageView *approveExt; 35 | 36 | //approve extension message 37 | @property (weak) IBOutlet NSTextField *approveExtMessage; 38 | 39 | //config view 40 | @property (strong) IBOutlet NSView *configureView; 41 | 42 | //allow apple bins/apps 43 | @property (weak) IBOutlet NSButton *allowApple; 44 | 45 | //allow 3rd-party installed apps 46 | @property (weak) IBOutlet NSButton *allowInstalled; 47 | 48 | //allow dns traffic installed apps 49 | @property (weak) IBOutlet NSButton *allowDNS; 50 | 51 | //support view 52 | @property (strong) IBOutlet NSView *supportView; 53 | 54 | //preferences 55 | @property (nonatomic, retain)NSDictionary* preferences; 56 | 57 | /* METHODS */ 58 | 59 | //show a view 60 | // note: replaces old view and highlights specified responder 61 | -(void)showView:(NSView*)view firstResponder:(NSInteger)firstResponder; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /LuLu/App/XPCDaemonClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCDaemonClient.h 3 | // project: lulu (shared) 4 | // description: talk to daemon via XPC (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Foundation; 11 | 12 | #import "XPCDaemonProto.h" 13 | 14 | @interface XPCDaemonClient : NSObject 15 | { 16 | 17 | } 18 | 19 | //xpc connection to daemon 20 | @property (atomic, strong, readwrite)NSXPCConnection* daemon; 21 | 22 | //get preferences 23 | // note: synchronous 24 | -(NSDictionary*)getPreferences; 25 | 26 | //update (save) preferences 27 | // note: synchronous, as then returns latest preferences 28 | -(NSDictionary*)updatePreferences:(NSDictionary*)preferences; 29 | 30 | //get rules 31 | // note: synchronous 32 | -(NSDictionary*)getRules; 33 | 34 | //add rule 35 | -(void)addRule:(NSDictionary*)info; 36 | 37 | //delete rule 38 | -(void)deleteRule:(NSString*)key rule:(NSString*)uuid; 39 | 40 | //import rules 41 | -(BOOL)importRules:(NSData*)newRules; 42 | 43 | //cleanup rules 44 | -(NSInteger)cleanupRules; 45 | 46 | //uninstall 47 | -(BOOL)uninstall; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /LuLu/App/XPCUser.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCUser.h 3 | // project: lulu (login item) 4 | // description: user XPC methods (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | @import OSLog; 11 | @import Foundation; 12 | 13 | #import "XPCUserProto.h" 14 | 15 | @interface XPCUser : NSObject 16 | { 17 | 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /LuLu/App/instructions.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/App/instructions.psd -------------------------------------------------------------------------------- /LuLu/App/mul.lproj/ItemPaths.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "NhE-Zh-Scd.title" : { 5 | "comment" : "Class = \"NSTextFieldCell\"; title = \"Path(s):\"; ObjectID = \"NhE-Zh-Scd\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "de" : { 9 | "stringUnit" : { 10 | "state" : "translated", 11 | "value" : "Pfad(e):" 12 | } 13 | }, 14 | "en" : { 15 | "stringUnit" : { 16 | "state" : "new", 17 | "value" : "Path(s):" 18 | } 19 | }, 20 | "es" : { 21 | "stringUnit" : { 22 | "state" : "translated", 23 | "value" : "Ruta(s):" 24 | } 25 | }, 26 | "fr" : { 27 | "stringUnit" : { 28 | "state" : "translated", 29 | "value" : "Chemin(s) : " 30 | } 31 | }, 32 | "ko" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "경로:" 36 | } 37 | }, 38 | "pl" : { 39 | "stringUnit" : { 40 | "state" : "translated", 41 | "value" : "Ścieżka(i):" 42 | } 43 | }, 44 | "pt-BR" : { 45 | "stringUnit" : { 46 | "state" : "translated", 47 | "value" : "Caminho(s):" 48 | } 49 | }, 50 | "tr" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "Yollar:" 54 | } 55 | }, 56 | "uk" : { 57 | "stringUnit" : { 58 | "state" : "translated", 59 | "value" : "Шлях(и):" 60 | } 61 | }, 62 | "zh-Hans" : { 63 | "stringUnit" : { 64 | "state" : "translated", 65 | "value" : "路径:" 66 | } 67 | }, 68 | "zh-Hant" : { 69 | "stringUnit" : { 70 | "state" : "translated", 71 | "value" : "路徑:" 72 | } 73 | } 74 | } 75 | }, 76 | "ox8-oX-X3s.title" : { 77 | "comment" : "Class = \"NSButtonCell\"; title = \"Close\"; ObjectID = \"ox8-oX-X3s\";", 78 | "extractionState" : "extracted_with_value", 79 | "localizations" : { 80 | "de" : { 81 | "stringUnit" : { 82 | "state" : "translated", 83 | "value" : "Schließen" 84 | } 85 | }, 86 | "en" : { 87 | "stringUnit" : { 88 | "state" : "new", 89 | "value" : "Close" 90 | } 91 | }, 92 | "es" : { 93 | "stringUnit" : { 94 | "state" : "translated", 95 | "value" : "Cerrar" 96 | } 97 | }, 98 | "fr" : { 99 | "stringUnit" : { 100 | "state" : "translated", 101 | "value" : "Fermer" 102 | } 103 | }, 104 | "ko" : { 105 | "stringUnit" : { 106 | "state" : "translated", 107 | "value" : "닫기" 108 | } 109 | }, 110 | "pl" : { 111 | "stringUnit" : { 112 | "state" : "translated", 113 | "value" : "Zamknij" 114 | } 115 | }, 116 | "pt-BR" : { 117 | "stringUnit" : { 118 | "state" : "translated", 119 | "value" : "Fechar" 120 | } 121 | }, 122 | "tr" : { 123 | "stringUnit" : { 124 | "state" : "translated", 125 | "value" : "Kapat" 126 | } 127 | }, 128 | "uk" : { 129 | "stringUnit" : { 130 | "state" : "translated", 131 | "value" : "Закрити" 132 | } 133 | }, 134 | "zh-Hans" : { 135 | "stringUnit" : { 136 | "state" : "translated", 137 | "value" : "关闭" 138 | } 139 | }, 140 | "zh-Hant" : { 141 | "stringUnit" : { 142 | "state" : "translated", 143 | "value" : "關閉" 144 | } 145 | } 146 | } 147 | } 148 | }, 149 | "version" : "1.0" 150 | } -------------------------------------------------------------------------------- /LuLu/App/mul.lproj/UpdateWindow.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "F0z-JX-Cv5.title" : { 5 | "comment" : "Class = \"NSWindow\"; title = \"LuLu Update\"; ObjectID = \"F0z-JX-Cv5\";", 6 | "extractionState" : "extracted_with_value", 7 | "localizations" : { 8 | "de" : { 9 | "stringUnit" : { 10 | "state" : "translated", 11 | "value" : "LuLu Update" 12 | } 13 | }, 14 | "en" : { 15 | "stringUnit" : { 16 | "state" : "new", 17 | "value" : "LuLu Update" 18 | } 19 | }, 20 | "es" : { 21 | "stringUnit" : { 22 | "state" : "translated", 23 | "value" : "Actualizar LuLu" 24 | } 25 | }, 26 | "fr" : { 27 | "stringUnit" : { 28 | "state" : "translated", 29 | "value" : "Mise à jour de LuLu" 30 | } 31 | }, 32 | "ko" : { 33 | "stringUnit" : { 34 | "state" : "translated", 35 | "value" : "LuLu 업데이트" 36 | } 37 | }, 38 | "pl" : { 39 | "stringUnit" : { 40 | "state" : "translated", 41 | "value" : "Aktualizacja LuLu" 42 | } 43 | }, 44 | "pt-BR" : { 45 | "stringUnit" : { 46 | "state" : "translated", 47 | "value" : "Atualização LuLu" 48 | } 49 | }, 50 | "tr" : { 51 | "stringUnit" : { 52 | "state" : "translated", 53 | "value" : "LuLu’yu Güncelle" 54 | } 55 | }, 56 | "uk" : { 57 | "stringUnit" : { 58 | "state" : "translated", 59 | "value" : "Оновлення LuLu" 60 | } 61 | }, 62 | "zh-Hans" : { 63 | "stringUnit" : { 64 | "state" : "translated", 65 | "value" : "LuLu 更新" 66 | } 67 | }, 68 | "zh-Hant" : { 69 | "stringUnit" : { 70 | "state" : "translated", 71 | "value" : "LuLu 更新" 72 | } 73 | } 74 | } 75 | }, 76 | "nMV-1f-RyK.title" : { 77 | "comment" : "Class = \"NSButtonCell\"; title = \"Update\"; ObjectID = \"nMV-1f-RyK\";", 78 | "extractionState" : "extracted_with_value", 79 | "localizations" : { 80 | "de" : { 81 | "stringUnit" : { 82 | "state" : "translated", 83 | "value" : "Update" 84 | } 85 | }, 86 | "en" : { 87 | "stringUnit" : { 88 | "state" : "new", 89 | "value" : "Update" 90 | } 91 | }, 92 | "es" : { 93 | "stringUnit" : { 94 | "state" : "translated", 95 | "value" : "Actualizar" 96 | } 97 | }, 98 | "fr" : { 99 | "stringUnit" : { 100 | "state" : "translated", 101 | "value" : "Mettre à jour" 102 | } 103 | }, 104 | "ko" : { 105 | "stringUnit" : { 106 | "state" : "translated", 107 | "value" : "업데이트" 108 | } 109 | }, 110 | "pl" : { 111 | "stringUnit" : { 112 | "state" : "translated", 113 | "value" : "Aktualizuj" 114 | } 115 | }, 116 | "pt-BR" : { 117 | "stringUnit" : { 118 | "state" : "translated", 119 | "value" : "Atializar" 120 | } 121 | }, 122 | "tr" : { 123 | "stringUnit" : { 124 | "state" : "translated", 125 | "value" : "Güncelle" 126 | } 127 | }, 128 | "uk" : { 129 | "stringUnit" : { 130 | "state" : "translated", 131 | "value" : "Оновити" 132 | } 133 | }, 134 | "zh-Hans" : { 135 | "stringUnit" : { 136 | "state" : "translated", 137 | "value" : "更新" 138 | } 139 | }, 140 | "zh-Hant" : { 141 | "stringUnit" : { 142 | "state" : "translated", 143 | "value" : "更新" 144 | } 145 | } 146 | } 147 | } 148 | }, 149 | "version" : "1.0" 150 | } -------------------------------------------------------------------------------- /LuLu/App/patrons.txt: -------------------------------------------------------------------------------- 1 | Patrons (2^6+): 2 | Jan Koum, Matt Mullenweg, Christian Blümlein, Shain Singh, Andreas Fink, Nuno, Rabi Rob Thomas, Mikhail S. 3 | 4 | Friends of Objective-See: 5 | Kandji, Jamf, Mosyle, CleanMyMac X, Kolide, Palo Alto Networks, iVerify, MalwareBytes, SmugMug, Guardian Mobile Firewall, Halo Privacy, The Mitten Mac 6 | -------------------------------------------------------------------------------- /LuLu/Extension/Alerts.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: Alerts.h 3 | // project: lulu (launch daemon) 4 | // description: alert related logic/tracking (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | 11 | @import OSLog; 12 | @import Foundation; 13 | @import NetworkExtension; 14 | 15 | #import "Process.h" 16 | #import "XPCUserProto.h" 17 | #import "XPCUserClient.h" 18 | 19 | @interface Alerts : NSObject 20 | 21 | /* PROPERTIES */ 22 | 23 | //shown alerts 24 | @property(nonatomic, retain)NSMutableDictionary* shownAlerts; 25 | 26 | 27 | //xpc client for talking to user (login item) 28 | @property(nonatomic, retain)XPCUserClient* xpcUserClient; 29 | 30 | //console user 31 | @property(nonatomic, retain)NSString* consoleUser; 32 | 33 | /* METHODS */ 34 | 35 | //create an alert object 36 | -(NSMutableDictionary*)create:(NEFilterSocketFlow*)flow process:(Process*)process; 37 | 38 | //via XPC, send an alert 39 | -(BOOL)deliver:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply; 40 | 41 | //is related to a shown alert? 42 | // checks if path/signing info is same 43 | -(BOOL)isRelated:(Process*)process; 44 | 45 | //add an alert to 'shown' 46 | -(void)addShown:(NSDictionary*)alert; 47 | 48 | //remove an alert from 'shown' 49 | -(void)removeShown:(NSDictionary*)alert; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /LuLu/Extension/Alerts.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: Alerts.m 3 | // project: lulu (launch daemon) 4 | // description: alert related logic/tracking 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "consts.h" 11 | #import "Process.h" 12 | #import "Alerts.h" 13 | #import "utilities.h" 14 | 15 | /* GLOBALS */ 16 | 17 | //log handle 18 | extern os_log_t logHandle; 19 | 20 | @implementation Alerts 21 | 22 | @synthesize shownAlerts; 23 | @synthesize consoleUser; 24 | @synthesize xpcUserClient; 25 | 26 | //init 27 | -(id)init 28 | { 29 | //super 30 | self = [super init]; 31 | if(nil != self) 32 | { 33 | //alloc shown 34 | shownAlerts = [NSMutableDictionary dictionary]; 35 | 36 | //init user xpc client 37 | xpcUserClient = [[XPCUserClient alloc] init]; 38 | } 39 | 40 | return self; 41 | } 42 | 43 | //create an alert dictionary 44 | -(NSMutableDictionary*)create:(NEFilterSocketFlow*)flow process:(Process*)process 45 | { 46 | //event for alert 47 | NSMutableDictionary* alert = nil; 48 | 49 | //remote endpoint 50 | NWHostEndpoint* remoteEndpoint = nil; 51 | 52 | //alloc 53 | alert = [NSMutableDictionary dictionary]; 54 | 55 | //add uuid 56 | alert[KEY_UUID] = [[NSUUID UUID] UUIDString]; 57 | 58 | //add key 59 | alert[KEY_KEY] = process.key; 60 | 61 | //extract remote endpoint 62 | remoteEndpoint = (NWHostEndpoint*)flow.remoteEndpoint; 63 | 64 | //add pid 65 | alert[KEY_PROCESS_ID] = [NSNumber numberWithUnsignedInt:process.pid]; 66 | 67 | //add args 68 | if(0 != process.arguments.count) 69 | { 70 | //add 71 | alert[KEY_PROCESS_ARGS] = process.arguments; 72 | } 73 | 74 | //add path 75 | alert[KEY_PATH] = process.path; 76 | 77 | //add name 78 | alert[KEY_PROCESS_NAME] = process.name; 79 | 80 | //add process state 81 | if(YES == process.deleted) 82 | { 83 | //add 84 | alert[KEY_PROCESS_DELETED] = @YES; 85 | } 86 | 87 | //process ancestors? 88 | // ...only add if more than just self 89 | if(process.ancestors.count > 1) 90 | { 91 | //add 92 | alert[KEY_PROCESS_ANCESTORS] = process.ancestors; 93 | } 94 | 95 | //add (remote) ip 96 | alert[KEY_HOST] = remoteEndpoint.hostname; 97 | 98 | //add (remote) host 99 | // as string though, since XPC doesn't like NSURLs 100 | if(nil != flow.URL) 101 | { 102 | //add 103 | alert[KEY_URL] = flow.URL.absoluteString; 104 | } 105 | 106 | //add (remote) port 107 | alert[KEY_ENDPOINT_PORT] = remoteEndpoint.port; 108 | 109 | //add protocol 110 | alert[KEY_PROTOCOL] = [NSNumber numberWithInt:flow.socketProtocol]; 111 | 112 | //add signing info 113 | if(nil != process.csInfo) 114 | { 115 | //add 116 | alert[KEY_CS_INFO] = process.csInfo; 117 | } 118 | 119 | return alert; 120 | } 121 | 122 | //is related to a shown alert? 123 | // checks if path/signing info is same 124 | -(BOOL)isRelated:(Process*)process 125 | { 126 | //flag 127 | __block BOOL related = NO; 128 | 129 | //alert 130 | NSDictionary* alert = nil; 131 | 132 | //sync 133 | @synchronized(self.shownAlerts) 134 | { 135 | //grab alert 136 | // none, means its new 137 | alert = self.shownAlerts[process.key]; 138 | if(nil == alert) 139 | { 140 | //bail 141 | goto bail; 142 | } 143 | 144 | //related 145 | related = YES; 146 | 147 | }//sync 148 | 149 | bail: 150 | 151 | return related; 152 | } 153 | 154 | //add an alert to 'shown' 155 | -(void)addShown:(NSDictionary*)alert 156 | { 157 | //dbg msg 158 | os_log_debug(logHandle, "adding alert to 'shown': %{public}@ -> %{public}@", alert[KEY_KEY], alert); 159 | 160 | //add alert 161 | @synchronized(self.shownAlerts) 162 | { 163 | //add 164 | self.shownAlerts[alert[KEY_KEY]] = alert; 165 | } 166 | 167 | return; 168 | } 169 | 170 | //remove an alert from 'shown' 171 | -(void)removeShown:(NSDictionary*)alert 172 | { 173 | //dbg msg 174 | os_log_debug(logHandle, "removing alert from 'shown': %{public}@ -> %{public}@", alert[KEY_KEY], alert); 175 | 176 | //remove alert 177 | @synchronized(self.shownAlerts) 178 | { 179 | //remove 180 | [self.shownAlerts removeObjectForKey:alert[KEY_KEY]]; 181 | } 182 | 183 | return; 184 | } 185 | 186 | //via XPC, send an alert to the client (user) 187 | -(BOOL)deliver:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply 188 | { 189 | //flag 190 | BOOL delivered = NO; 191 | 192 | //dbg msg 193 | os_log_debug(logHandle, "delivering alert %{public}@", alert); 194 | 195 | //send via XPC to user 196 | if(YES != (delivered = [self.xpcUserClient deliverAlert:alert reply:reply])) 197 | { 198 | //err msg 199 | os_log_error(logHandle, "ERROR: failed to deliver alert to user (no client?)"); 200 | 201 | //bail 202 | goto bail; 203 | } 204 | 205 | bail: 206 | 207 | return delivered; 208 | } 209 | 210 | @end 211 | -------------------------------------------------------------------------------- /LuLu/Extension/Binary.h: -------------------------------------------------------------------------------- 1 | // 2 | // Binary.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 8/27/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef Binary_h 10 | #define Binary_h 11 | 12 | #import "Consts.h" 13 | #import "signing.h" 14 | #import "utilities.h" 15 | 16 | @import OSLog; 17 | @import CommonCrypto; 18 | 19 | @interface Binary : NSObject 20 | { 21 | 22 | } 23 | 24 | /* PROPERTIES */ 25 | 26 | //path 27 | @property(nonatomic, retain)NSString* _Nonnull path; 28 | 29 | //name 30 | @property(nonatomic, retain)NSString* _Nonnull name; 31 | 32 | //icon 33 | @property(nonatomic, retain)NSImage* _Nonnull icon; 34 | 35 | //file attributes 36 | @property(nonatomic, retain)NSDictionary* _Nullable attributes; 37 | 38 | //spotlight meta data 39 | @property(nonatomic, retain)NSDictionary* _Nullable metadata; 40 | 41 | //bundle 42 | // nil for non-apps 43 | @property(nonatomic, retain)NSBundle* _Nullable bundle; 44 | 45 | //signing info 46 | @property(nonatomic, retain)NSMutableDictionary* _Nonnull csInfo; 47 | 48 | //hash 49 | @property(nonatomic, retain)NSMutableString* _Nonnull sha256; 50 | 51 | /* METHODS */ 52 | 53 | //init w/ a path 54 | -(id _Nonnull)init:(NSString* _Nonnull)path; 55 | 56 | /* the following methods are rather CPU-intensive 57 | as such, if the proc monitoring is run with the 'goEasy' option, they aren't automatically invoked 58 | */ 59 | 60 | //get an icon for a process 61 | // for apps, this will be app's icon, otherwise just a standard system one 62 | -(void)getIcon; 63 | 64 | //generate signing info (statically) 65 | -(void)generateSigningInfo:(SecCSFlags)flags; 66 | 67 | @end 68 | 69 | #endif /* Binary_h */ 70 | -------------------------------------------------------------------------------- /LuLu/Extension/BlockOrAllowList.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlockOrAllowList.h 3 | // Extension 4 | // 5 | // Created by Patrick Wardle on 11/6/20. 6 | // Copyright © 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | @import Cocoa; 10 | @import OSLog; 11 | @import NetworkExtension; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface BlockOrAllowList : NSObject 16 | 17 | /* PROPERTIES */ 18 | 19 | //path 20 | @property(nonatomic, retain)NSString* path; 21 | 22 | //block list 23 | @property(nonatomic, retain)NSMutableSet* items; 24 | 25 | //modification time 26 | @property(nonatomic, retain)NSDate* lastModified; 27 | 28 | 29 | /* METHODS */ 30 | 31 | //init 32 | // with a path 33 | -(id)init:(NSString*)path; 34 | 35 | //(re)load from disk 36 | -(void)load:(NSString*)path; 37 | 38 | //should reload 39 | // checks file modification time 40 | -(BOOL)shouldReload; 41 | 42 | //check if flow matches item on block list 43 | -(BOOL)isMatch:(NEFilterSocketFlow*)flow; 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /LuLu/Extension/Extension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | content-filter-provider-systemextension 8 | 9 | com.apple.security.temporary-exception.files.absolute-path.read-write 10 | 11 | /private/var/db/mds/ 12 | 13 | com.apple.security.application-groups 14 | 15 | $(TeamIdentifierPrefix)com.objective-see.lulu 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LuLu/Extension/FilterDataProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // FilterDataProvider.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 8/1/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @import OSLog; 12 | @import NetworkExtension; 13 | 14 | #import "GrayList.h" 15 | 16 | @interface FilterDataProvider : NEFilterDataProvider 17 | 18 | /* PROPERTIES */ 19 | 20 | //(process) cache 21 | @property(atomic, retain)NSCache* cache; 22 | 23 | //graylist obj 24 | @property(nonatomic, retain)GrayList* grayList; 25 | 26 | //related flows 27 | @property(nonatomic, retain)NSMutableDictionary* relatedFlows; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /LuLu/Extension/GrayList.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: GrayList.h 3 | // project: lulu (launch daemon) 4 | // description: gray listed binaries (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import OSLog; 11 | @import Foundation; 12 | 13 | 14 | @interface GrayList : NSObject 15 | 16 | /* PROPERTIES */ 17 | 18 | //gray listed (apple) binaries 19 | @property(nonatomic, retain)NSMutableSet* graylistedBinaries; 20 | 21 | /* METHODS */ 22 | //determine if process is graylisted 23 | -(BOOL)isGrayListed:(Process*)process; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /LuLu/Extension/GrayList.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: GrayList.m 3 | // project: lulu (launch daemon) 4 | // description: gray listed binaries 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "consts.h" 11 | #import "Process.h" 12 | #import "GrayList.h" 13 | 14 | //apple system utils that aren't allowed by default 15 | // these may be abused by malware, so will make sure they trigger an alert 16 | NSString* const GRAYLISTED_BINARIES[] = 17 | { 18 | @"com.apple.nc", 19 | @"com.apple.ftp", 20 | @"com.apple.zsh", 21 | @"com.apple.ksh", 22 | @"com.apple.php", 23 | @"com.apple.scp", 24 | @"com.apple.ssh", 25 | @"com.apple.bash", 26 | @"com.apple.tcsh", 27 | @"com.apple.curl", 28 | @"com.apple.perl", 29 | @"com.apple.ruby", 30 | @"com.apple.sftp", 31 | @"com.tcltk.tclsh", 32 | @"com.apple.perl5", 33 | @"com.apple.whois", 34 | @"com.apple.python", 35 | @"com.apple.telnet", 36 | @"com.apple.openssh", 37 | @"com.apple.python2", 38 | @"com.apple.python3", 39 | @"org.python.python", 40 | @"com.apple.pythonw", 41 | @"com.apple.osascript", 42 | 43 | }; 44 | 45 | /* GLOBALS */ 46 | 47 | //log handle 48 | extern os_log_t logHandle; 49 | 50 | @implementation GrayList 51 | 52 | @synthesize graylistedBinaries; 53 | 54 | //init 55 | -(id)init 56 | { 57 | //init super 58 | self = [super init]; 59 | if(nil != self) 60 | { 61 | //init list (set) of gray listed binaries 62 | graylistedBinaries = [NSMutableSet set]; 63 | 64 | //add each to set 65 | for(NSUInteger i=0; i 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | LuLu 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright (c) 2020 Objective-See. All rights reserved. 27 | NSSystemExtensionUsageDescription 28 | 29 | NetworkExtension 30 | 31 | NEMachServiceName 32 | $(TeamIdentifierPrefix)com.objective-see.lulu 33 | NEProviderClasses 34 | 35 | com.apple.networkextension.filter-data 36 | FilterDataProvider 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /LuLu/Extension/Preferences.h: -------------------------------------------------------------------------------- 1 | // 2 | // Preferences.h 3 | // launchDaemon 4 | // 5 | // Created by Patrick Wardle on 2/22/18. 6 | // Copyright (c) 2018 Objective-See. All rights reserved. 7 | // 8 | 9 | @import OSLog; 10 | @import Foundation; 11 | 12 | @interface Preferences : NSObject 13 | 14 | /* PROPERTIES */ 15 | 16 | //preferences 17 | @property(nonatomic, retain)NSMutableDictionary* preferences; 18 | 19 | /* METHODS */ 20 | 21 | //load prefs from disk 22 | -(BOOL)load; 23 | 24 | //update prefs 25 | // saves and handles logic for specific prefs 26 | -(BOOL)update:(NSDictionary*)updates; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /LuLu/Extension/Preferences.m: -------------------------------------------------------------------------------- 1 | // 2 | // Preferences.m 3 | // launchDaemon 4 | // 5 | // Created by Patrick Wardle on 2/22/18. 6 | // Copyright (c) 2018 Objective-See. All rights reserved. 7 | // 8 | 9 | #import "consts.h" 10 | #import "BlockOrAllowList.h" 11 | #import "Preferences.h" 12 | 13 | /* GLOBALS */ 14 | 15 | //log handle 16 | extern os_log_t logHandle; 17 | 18 | //allow list 19 | extern BlockOrAllowList* allowList; 20 | 21 | //block list 22 | extern BlockOrAllowList* blockList; 23 | 24 | @implementation Preferences 25 | 26 | @synthesize preferences; 27 | 28 | //init 29 | // loads prefs 30 | -(id)init 31 | { 32 | //super 33 | self = [super init]; 34 | if(nil != self) 35 | { 36 | //prefs exist? 37 | // load them from disk 38 | if(YES == [[NSFileManager defaultManager] fileExistsAtPath:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE]]) 39 | { 40 | //load 41 | if(YES != [self load]) 42 | { 43 | //err msg 44 | os_log_error(logHandle, "ERROR: failed to loads preferences from %@", PREFS_FILE); 45 | 46 | //unset 47 | self = nil; 48 | 49 | //bail 50 | goto bail; 51 | } 52 | 53 | } 54 | //no prefs (yet) 55 | // just initialze empty dictionary 56 | else 57 | { 58 | //init 59 | preferences = [NSMutableDictionary dictionary]; 60 | } 61 | } 62 | 63 | bail: 64 | 65 | return self; 66 | } 67 | 68 | //load prefs from disk 69 | -(BOOL)load 70 | { 71 | //flag 72 | BOOL loaded = NO; 73 | 74 | //load 75 | preferences = [NSMutableDictionary dictionaryWithContentsOfFile:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE]]; 76 | if(nil == self.preferences) 77 | { 78 | //err msg 79 | os_log_error(logHandle, "ERROR: failed to load preference from %{public}@", PREFS_FILE); 80 | 81 | //bail 82 | goto bail; 83 | } 84 | 85 | //dbg msg 86 | os_log_debug(logHandle, "loaded preferences: %{public}@", self.preferences); 87 | 88 | //happy 89 | loaded = YES; 90 | 91 | bail: 92 | 93 | return loaded; 94 | } 95 | 96 | //update prefs 97 | // handles logic for specific prefs & then saves 98 | -(BOOL)update:(NSDictionary*)updates 99 | { 100 | //flag 101 | BOOL updated = NO; 102 | 103 | //allow list 104 | NSString* allowListPath = nil; 105 | 106 | //block list 107 | NSString* blockListPath = nil; 108 | 109 | //sync 110 | @synchronized (self) { 111 | 112 | //dbg msg 113 | os_log_debug(logHandle, "updating preferences (%{public}@)", updates); 114 | 115 | //add in (new) prefs 116 | [self.preferences addEntriesFromDictionary:updates]; 117 | 118 | //save 119 | if(YES != [self save]) 120 | { 121 | //err msg 122 | os_log_error(logHandle, "ERROR: failed to save preferences"); 123 | 124 | //bail 125 | goto bail; 126 | } 127 | 128 | //extract any allow list 129 | allowListPath = updates[PREF_ALLOW_LIST]; 130 | 131 | //extract any block list 132 | blockListPath = updates[PREF_BLOCK_LIST]; 133 | 134 | //(new) allow list? 135 | // now, trigger reload 136 | if(0 != [allowListPath length]) 137 | { 138 | //dbg msg 139 | os_log_debug(logHandle, "user specified new 'allow' list: %{public}@", allowListPath); 140 | 141 | //first time? 142 | if(nil == allowList) 143 | { 144 | //alloc/init/load block list 145 | allowList = [[BlockOrAllowList alloc] init:allowListPath]; 146 | } 147 | //otherwise just reload 148 | else 149 | { 150 | //(re)load 151 | [allowList load:allowListPath]; 152 | } 153 | } 154 | 155 | //(new) block list? 156 | // now, trigger reload 157 | if(0 != [blockListPath length]) 158 | { 159 | //dbg msg 160 | os_log_debug(logHandle, "user specified new 'block' list: %{public}@", blockListPath); 161 | 162 | //first time? 163 | if(nil == blockList) 164 | { 165 | //alloc/init/load block list 166 | blockList = [[BlockOrAllowList alloc] init:blockListPath]; 167 | } 168 | //otherwise just reload 169 | else 170 | { 171 | //(re)load 172 | [blockList load:blockListPath]; 173 | } 174 | } 175 | 176 | //happy 177 | updated = YES; 178 | 179 | } //sync 180 | 181 | bail: 182 | 183 | return updated; 184 | } 185 | 186 | //save to disk 187 | -(BOOL)save 188 | { 189 | //save 190 | return [self.preferences writeToFile:[INSTALL_DIRECTORY stringByAppendingPathComponent:PREFS_FILE] atomically:YES]; 191 | } 192 | 193 | @end 194 | -------------------------------------------------------------------------------- /LuLu/Extension/Process.h: -------------------------------------------------------------------------------- 1 | // 2 | // Process.h 3 | // LuLu 4 | // 5 | // Created by Patrick Wardle on 8/27/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | #ifndef Process_h 10 | #define Process_h 11 | 12 | @import OSLog; 13 | 14 | #import "Binary.h" 15 | 16 | @interface Process : NSObject 17 | 18 | /* PROPERTIES */ 19 | 20 | //pid 21 | @property pid_t pid; 22 | 23 | //user id 24 | @property uid_t uid; 25 | 26 | //type 27 | // used by process mon 28 | @property u_int16_t type; 29 | 30 | //exit code 31 | @property u_int32_t exit; 32 | 33 | //(self) deleted binary 34 | @property BOOL deleted; 35 | 36 | //name 37 | @property(nonatomic, retain)NSString* _Nullable name; 38 | 39 | //path 40 | @property(nonatomic, retain)NSString* _Nullable path; 41 | 42 | //args 43 | @property(nonatomic, retain)NSMutableArray* _Nullable arguments; 44 | 45 | //ancestors 46 | @property(nonatomic, retain)NSMutableArray* _Nullable ancestors; 47 | 48 | //signing info 49 | @property(nonatomic, retain)NSMutableDictionary* _Nullable csInfo; 50 | 51 | //key 52 | @property(nonatomic, retain)NSString* _Nonnull key; 53 | 54 | //Binary object 55 | // has path, hash, etc 56 | @property(nonatomic, retain)Binary* _Nonnull binary; 57 | 58 | //timestamp 59 | @property(nonatomic, retain)NSDate* _Nonnull timestamp; 60 | 61 | /* METHODS */ 62 | 63 | //init with a audit token 64 | // method will then (try) fill out rest of object 65 | -(id _Nullable)init:(audit_token_t* _Nonnull)token; 66 | 67 | @end 68 | 69 | #endif /* Process_h */ 70 | -------------------------------------------------------------------------------- /LuLu/Extension/Rules.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: Rules.h 3 | // project: LuLu (launch daemon) 4 | // description: handles rules & actions such as add/delete (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | 11 | #ifndef Rules_h 12 | #define Rules_h 13 | 14 | #import "Process.h" 15 | #import "XPCUserClient.h" 16 | 17 | @import OSLog; 18 | @import Foundation; 19 | @import NetworkExtension; 20 | 21 | @class Rule; 22 | 23 | 24 | @interface Rules : NSObject 25 | { 26 | 27 | } 28 | 29 | /* PROPERTIES */ 30 | 31 | //rules 32 | @property(nonatomic, retain)NSMutableDictionary* rules; 33 | 34 | //xpc client for talking to login item 35 | @property(nonatomic, retain)XPCUserClient* xpcUserClient; 36 | 37 | /* METHODS */ 38 | 39 | //prepare 40 | // first time? generate defaults rules 41 | // upgrade (v1.0)? convert to new format 42 | -(BOOL)prepare; 43 | 44 | //load from disk 45 | -(BOOL)load; 46 | 47 | //add a rule 48 | -(BOOL)add:(Rule*)rule save:(BOOL)save; 49 | 50 | //find (matching) rule 51 | -(Rule*)find:(Process*)process flow:(NEFilterSocketFlow*)flow csChange:(BOOL*)csChange; 52 | 53 | //delete rule 54 | -(BOOL)delete:(NSString*)key rule:(NSString*)uuid; 55 | 56 | //import rules 57 | -(BOOL)import:(NSData*)rules; 58 | 59 | //update an item's cs info 60 | // and also the cs info of all its rule 61 | -(void)updateCSInfo:(Process*)process; 62 | 63 | //cleanup rules 64 | -(NSUInteger)cleanup; 65 | 66 | @end 67 | 68 | #endif /* Rules_h */ 69 | -------------------------------------------------------------------------------- /LuLu/Extension/XPCDaemon.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCDaemon.h 3 | // project: lulu (launch daemon) 4 | // description: interface for XPC methods, invoked by user (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | @import OSLog; 11 | @import Foundation; 12 | 13 | #import "XPCDaemonProto.h" 14 | 15 | @interface XPCDaemon : NSObject 16 | { 17 | 18 | } 19 | 20 | /* PROPERTIES */ 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /LuLu/Extension/XPCListener.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCListener 3 | // project: lulu (launch daemon) 4 | // description: XPC listener for connections for user components (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | 11 | @import OSLog; 12 | @import Foundation; 13 | 14 | #import "XPCDaemonProto.h" 15 | 16 | //function def 17 | OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement); 18 | 19 | @interface XPCListener : NSObject 20 | { 21 | 22 | } 23 | 24 | /* PROPERTIES */ 25 | 26 | //XPC listener 27 | @property(nonatomic, retain)NSXPCListener* listener; 28 | 29 | //XPC connection for login item 30 | @property(weak)NSXPCConnection* client; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /LuLu/Extension/XPCUserClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCUserClient.h 3 | // project: lulu (launch daemon) 4 | // description: talk to the user, via XPC (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | @import OSLog; 11 | @import Foundation; 12 | 13 | #import "XPCUserProto.h" 14 | @interface XPCUserClient : NSObject 15 | { 16 | 17 | } 18 | 19 | /* PROPERTIES */ 20 | 21 | 22 | /* METHODS */ 23 | 24 | //deliver alert to user 25 | // note: this is synchronous, so errors can be detected 26 | -(BOOL)deliverAlert:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply; 27 | 28 | //inform user rules have changed 29 | -(void)rulesChanged; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /LuLu/Extension/XPCUserClient.m: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCUserClient.m 3 | // project: lulu (launch daemon) 4 | // description: talk to the user, via XPC (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Rules.h" 11 | #import "Alerts.h" 12 | #import "consts.h" 13 | #import "XPCListener.h" 14 | #import "XPCUserClient.h" 15 | 16 | /* GLOBALS */ 17 | 18 | //xpc connection 19 | extern XPCListener* xpcListener; 20 | 21 | //log handle 22 | extern os_log_t logHandle; 23 | 24 | @implementation XPCUserClient 25 | 26 | //deliver alert to user 27 | -(BOOL)deliverAlert:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply 28 | { 29 | //flag 30 | __block BOOL xpcError = NO; 31 | 32 | //sanity check 33 | // no client connection? 34 | if(nil == xpcListener.client) 35 | { 36 | //dbg msg 37 | os_log_debug(logHandle, "no client is connected, alert will not be delivered"); 38 | 39 | //set error 40 | xpcError = YES; 41 | 42 | //bail 43 | //goto bail; 44 | } 45 | else 46 | { 47 | //dbg msg 48 | os_log_debug(logHandle, "invoking user XPC method: 'alertShow:reply:'"); 49 | 50 | //send to user 51 | [[xpcListener.client remoteObjectProxyWithErrorHandler:^(NSError * proxyError) 52 | { 53 | //err msg 54 | os_log_error(logHandle, "ERROR: failed to execute daemon XPC method '%s' (error: %{public}@)", __PRETTY_FUNCTION__, proxyError); 55 | 56 | //set error 57 | xpcError = YES; 58 | 59 | }] alertShow:alert reply:^(NSDictionary* userReply) 60 | { 61 | //dbg msg 62 | os_log_debug(logHandle, "reply: %{public}@", alert); 63 | 64 | //respond 65 | reply(userReply); 66 | }]; 67 | } 68 | 69 | bail: 70 | 71 | return !xpcError; 72 | } 73 | 74 | //inform user rules have changed 75 | -(void)rulesChanged 76 | { 77 | //dbg msg 78 | os_log_debug(logHandle, "invoking user XPC method, '%s'", __PRETTY_FUNCTION__); 79 | 80 | //no client? 81 | // no need to do anything... 82 | if(nil == xpcListener.client) 83 | { 84 | //bail 85 | goto bail; 86 | } 87 | 88 | //send to user (login item) to display 89 | [[xpcListener.client remoteObjectProxyWithErrorHandler:^(NSError * proxyError) 90 | { 91 | //err msg 92 | os_log_error(logHandle, "ERROR: failed to execute 'rulesChanged' method on launch daemon (error: %{public}@)", proxyError); 93 | 94 | }] rulesChanged]; 95 | 96 | bail: 97 | 98 | return; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /LuLu/Extension/main.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: main.h 3 | // project: lulu (launch daemon) 4 | // description: main (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | #import "Rules.h" 11 | #import "Alerts.h" 12 | #import "consts.h" 13 | #import "utilities.h" 14 | #import "BlockOrAllowList.h" 15 | #import "Preferences.h" 16 | #import "XPCListener.h" 17 | 18 | #ifndef main_h 19 | #define main_h 20 | 21 | //GLOBALS 22 | 23 | //rules obj 24 | Rules* rules = nil; 25 | 26 | //alerts obj 27 | Alerts* alerts = nil; 28 | 29 | //allow list 30 | BlockOrAllowList* allowList = nil; 31 | 32 | //block list 33 | BlockOrAllowList* blockList = nil; 34 | 35 | //XPC listener obj 36 | XPCListener* xpcListener = nil; 37 | 38 | //prefs obj 39 | Preferences* preferences = nil; 40 | 41 | //dispatch source for SIGTERM 42 | dispatch_source_t dispatchSource = nil; 43 | 44 | /* FUNCTIONS */ 45 | 46 | //init a handler for SIGTERM 47 | // can perform actions such as disabling firewall and closing logging 48 | void register4Shutdown(void); 49 | 50 | //launch daemon should only be unloaded if box is shutting down 51 | // so handle things like telling kext to disable & unregister, de-init logging, etc 52 | void goodbye(void); 53 | 54 | 55 | #endif /* main_h */ 56 | -------------------------------------------------------------------------------- /LuLu/Extension/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Extension 4 | // 5 | // Created by Patrick Wardle on 8/1/20. 6 | // Copyright (c) 2020 Objective-See. All rights reserved. 7 | // 8 | 9 | //FOR LOGGING: 10 | // % log stream --level debug --predicate="subsystem='com.objective-see.lulu'" 11 | 12 | #import "main.h" 13 | 14 | @import OSLog; 15 | @import Foundation; 16 | @import NetworkExtension; 17 | 18 | /* GLOBALS */ 19 | 20 | //log handle 21 | os_log_t logHandle = nil; 22 | 23 | //main 24 | int main(int argc, char *argv[]) 25 | { 26 | //pool 27 | @autoreleasepool { 28 | 29 | //init log 30 | logHandle = os_log_create(BUNDLE_ID, "extension"); 31 | 32 | //dbg msg 33 | os_log_debug(logHandle, "started: %{public}@ (pid: %d / uid: %d)", NSProcessInfo.processInfo.arguments.firstObject, getpid(), getuid()); 34 | 35 | //start sysext 36 | // Apple notes, "call [this] as early as possible" 37 | [NEProvider startSystemExtensionMode]; 38 | 39 | //dbg msg 40 | os_log_debug(logHandle, "enabled extension ('startSystemExtensionMode' was called)"); 41 | 42 | //alloc/init/load prefs 43 | preferences = [[Preferences alloc] init]; 44 | 45 | //alloc/init alerts object 46 | alerts = [[Alerts alloc] init]; 47 | 48 | //alloc/init rules object 49 | rules = [[Rules alloc] init]; 50 | 51 | //alloc/init XPC comms object 52 | xpcListener = [[XPCListener alloc] init]; 53 | 54 | //dbg msg 55 | os_log_debug(logHandle, "created client XPC listener"); 56 | 57 | //need to create 58 | // create install directory? 59 | if(YES != [[NSFileManager defaultManager] fileExistsAtPath:INSTALL_DIRECTORY]) 60 | { 61 | //create it 62 | if(YES != [[NSFileManager defaultManager] createDirectoryAtPath:INSTALL_DIRECTORY withIntermediateDirectories:YES attributes:nil error:NULL]) 63 | { 64 | //err msg 65 | os_log_error(logHandle, "ERROR: failed to create install directory, %{public}@", INSTALL_DIRECTORY); 66 | 67 | //bail 68 | goto bail; 69 | } 70 | } 71 | 72 | //prep rules 73 | // first time? generate defaults rules 74 | // upgrade (v1.0)? convert to new format 75 | [rules prepare]; 76 | 77 | //load rules 78 | if(YES != [rules load]) 79 | { 80 | //err msg 81 | os_log_error(logHandle, "ERROR: failed to load rules from %{public}@", RULES_FILE); 82 | 83 | //bail 84 | goto bail; 85 | } 86 | 87 | //allow list? 88 | if(0 != preferences.preferences[PREF_USE_ALLOW_LIST]) 89 | { 90 | //dbg msg 91 | os_log_debug(logHandle, "init'ing allowing list"); 92 | 93 | //alloc/init/load allow list 94 | allowList = [[BlockOrAllowList alloc] init:preferences.preferences[PREF_ALLOW_LIST]]; 95 | } 96 | 97 | //block list? 98 | if(0 != preferences.preferences[PREF_USE_BLOCK_LIST]) 99 | { 100 | //dbg msg 101 | os_log_debug(logHandle, "init'ing block list"); 102 | 103 | //alloc/init/load block list 104 | blockList = [[BlockOrAllowList alloc] init:preferences.preferences[PREF_BLOCK_LIST]]; 105 | } 106 | 107 | }//pool 108 | 109 | dispatch_main(); 110 | 111 | bail: 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /LuLu/Extension/procInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // File: procInfo.h 3 | // Project: Proc Info 4 | // 5 | // Created by: Patrick Wardle 6 | // Copyright: 2017 Objective-See 7 | // License: Creative Commons Attribution-NonCommercial 4.0 International License 8 | // 9 | 10 | #ifndef procInfo_h 11 | #define procInfo_h 12 | 13 | #import 14 | #import 15 | #import 16 | 17 | /* CLASSES */ 18 | 19 | @class Binary; 20 | @class Process; 21 | 22 | /* DEFINES */ 23 | 24 | //from audit_kevents.h 25 | #define EVENT_EXIT 1 26 | #define EVENT_FORK 2 27 | #define EVENT_EXECVE 23 28 | #define EVENT_EXEC 27 29 | #define EVENT_SPAWN 43190 30 | 31 | //signers 32 | enum Signer{None, Apple, AppStore, DevID, AdHoc}; 33 | 34 | //signature status 35 | #define KEY_SIGNATURE_STATUS @"signatureStatus" 36 | 37 | //signer 38 | #define KEY_SIGNATURE_SIGNER @"signatureSigner" 39 | 40 | //signing auths 41 | #define KEY_SIGNATURE_AUTHORITIES @"signatureAuthorities" 42 | 43 | //code signing id 44 | #define KEY_SIGNATURE_IDENTIFIER @"signatureIdentifier" 45 | 46 | //entitlements 47 | #define KEY_SIGNATURE_ENTITLEMENTS @"signatureEntitlements" 48 | 49 | /* TYPEDEFS */ 50 | 51 | //block for library 52 | typedef void (^ProcessCallbackBlock)(Process* _Nonnull); 53 | 54 | /* OBJECT: PROCESS INFO */ 55 | 56 | @interface ProcInfo : NSObject 57 | 58 | //init w/ flag 59 | // flag dictates if CPU-intensive logic (code signing, etc) should be preformed 60 | -(id _Nullable)init:(BOOL)goEasy; 61 | 62 | //start monitoring 63 | -(void)start:(ProcessCallbackBlock _Nonnull )callback; 64 | 65 | //stop monitoring 66 | -(void)stop; 67 | 68 | //get list of running processes 69 | -(NSMutableArray* _Nonnull)currentProcesses; 70 | 71 | @end 72 | 73 | /* OBJECT: PROCESS */ 74 | 75 | @interface Process : NSObject 76 | 77 | /* PROPERTIES */ 78 | 79 | //pid 80 | @property pid_t pid; 81 | 82 | //ppid 83 | @property pid_t ppid; 84 | 85 | //user id 86 | @property uid_t uid; 87 | 88 | //type 89 | // used by process mon 90 | @property u_int16_t type; 91 | 92 | //exit code 93 | @property u_int32_t exit; 94 | 95 | //path 96 | @property(nonatomic, retain)NSString* _Nullable path; 97 | 98 | //args 99 | @property(nonatomic, retain)NSMutableArray* _Nonnull arguments; 100 | 101 | //ancestors 102 | @property(nonatomic, retain)NSMutableArray* _Nonnull ancestors; 103 | 104 | //signing info 105 | @property(nonatomic, retain)NSMutableDictionary* _Nonnull signingInfo; 106 | 107 | //Binary object 108 | // has path, hash, etc 109 | @property(nonatomic, retain)Binary* _Nonnull binary; 110 | 111 | //timestamp 112 | @property(nonatomic, retain)NSDate* _Nonnull timestamp; 113 | 114 | /* METHODS */ 115 | 116 | //init with a pid 117 | // method will then (try) fill out rest of object 118 | -(id _Nullable)init:(pid_t)processID; 119 | 120 | //generate signing info 121 | // also classifies if Apple/from App Store/etc. 122 | -(void)generateSigningInfo:(SecCSFlags)flags; 123 | 124 | //set process's path 125 | -(void)pathFromPid; 126 | 127 | //generate list of ancestors 128 | -(void)enumerateAncestors; 129 | 130 | //class method 131 | // get's parent of arbitrary process 132 | +(pid_t)getParentID:(pid_t)child; 133 | 134 | @end 135 | 136 | /* OBJECT: BINARY */ 137 | 138 | @interface Binary : NSObject 139 | { 140 | 141 | } 142 | 143 | /* PROPERTIES */ 144 | 145 | //path 146 | @property(nonatomic, retain)NSString* _Nonnull path; 147 | 148 | //name 149 | @property(nonatomic, retain)NSString* _Nonnull name; 150 | 151 | //icon 152 | @property(nonatomic, retain)NSImage* _Nonnull icon; 153 | 154 | //file attributes 155 | @property(nonatomic, retain)NSDictionary* _Nullable attributes; 156 | 157 | //spotlight meta data 158 | @property(nonatomic, retain)NSDictionary* _Nullable metadata; 159 | 160 | //bundle 161 | // nil for non-apps 162 | @property(nonatomic, retain)NSBundle* _Nullable bundle; 163 | 164 | //signing info 165 | @property(nonatomic, retain)NSDictionary* _Nonnull signingInfo; 166 | 167 | //hash 168 | @property(nonatomic, retain)NSMutableString* _Nonnull sha256; 169 | 170 | //identifier 171 | // either signing id or sha256 hash 172 | @property(nonatomic, retain)NSString* _Nonnull identifier; 173 | 174 | /* METHODS */ 175 | 176 | //init w/ a path 177 | -(id _Nonnull)init:(NSString* _Nonnull)path; 178 | 179 | /* the following methods are rather CPU-intensive 180 | as such, if the proc monitoring is run with the 'goEasy' option, they aren't automatically invoked 181 | */ 182 | 183 | //get an icon for a process 184 | // for apps, this will be app's icon, otherwise just a standard system one 185 | -(void)getIcon; 186 | 187 | //generate signing info (statically) 188 | -(void)generateSigningInfo:(SecCSFlags)flags; 189 | 190 | /* the following methods are not invoked automatically 191 | as such, if you code has to manually invoke them if you want this info 192 | */ 193 | 194 | //generate hash 195 | // algo: sha256 196 | -(void)generateHash; 197 | 198 | //generate id 199 | // either signing id, or sha256 hash 200 | -(void)generateIdentifier; 201 | 202 | @end 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /LuLu/LuLu.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 10 | 11 | 12 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LuLu/LuLu.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LuLu/LuLu.xcodeproj/xcshareddata/xcschemes/Extension.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 57 | 58 | 64 | 65 | 67 | 68 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /LuLu/LuLu.xcodeproj/xcshareddata/xcschemes/LuLu.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /LuLu/Shared/Rule.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: Rule.h 3 | // project: LuLu (shared) 4 | // description: Rule object (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #ifndef Rule_h 11 | #define Rule_h 12 | 13 | @import OSLog; 14 | @import Foundation; 15 | 16 | @interface Rule : NSObject 17 | { 18 | 19 | } 20 | 21 | /* PROPERTIES */ 22 | 23 | //uuid 24 | @property(nonatomic, retain)NSString* uuid; 25 | 26 | //key 27 | @property(nonatomic, retain)NSString* key; 28 | 29 | // PROCESS/BINARY INFO 30 | 31 | //rule pid 32 | // only set if rule's duration is set to process lifetime 33 | @property(nonatomic, retain)NSNumber* pid; 34 | 35 | //path 36 | @property(nonatomic, retain)NSString* path; 37 | 38 | //flag for global rule 39 | @property(nonatomic, retain)NSNumber* isGlobal; 40 | 41 | //flag for directory rule 42 | @property(nonatomic, retain)NSNumber* isDirectory; 43 | 44 | //name 45 | @property(nonatomic, retain)NSString* name; 46 | 47 | //signing info 48 | @property(nonatomic, retain)NSDictionary* csInfo; 49 | 50 | //remote ip or url 51 | @property(nonatomic, retain)NSString* endpointAddr; 52 | 53 | //remote host 54 | @property(nonatomic, retain)NSString* endpointHost; 55 | 56 | //flag for endpoint addr 57 | @property BOOL isEndpointAddrRegex; 58 | 59 | //remote port 60 | @property(nonatomic, retain)NSString* endpointPort; 61 | 62 | //type 63 | // default, user, etc 64 | @property(nonatomic, retain)NSNumber* type; 65 | 66 | //protocol 67 | @property(nonatomic, retain)NSNumber* protocol; 68 | 69 | // TIMESTAMPS 70 | 71 | //rule creation 72 | @property(nonatomic, retain)NSDate* creation; 73 | 74 | //rule expiration 75 | // only set if rule's duration is set to expire 76 | @property(nonatomic, retain)NSDate* expiration; 77 | 78 | 79 | // ACTION 80 | 81 | //action 82 | // allow / deny 83 | @property(nonatomic, retain)NSNumber* action; 84 | 85 | //action scope 86 | // process, endpoint, etc 87 | @property(nonatomic, retain)NSNumber* scope; 88 | 89 | 90 | /* METHODS */ 91 | 92 | //init method 93 | -(id)init:(NSDictionary*)info; 94 | 95 | //matches a string? 96 | -(BOOL)matchesString:(NSString*)match; 97 | 98 | //matches a(nother) rule? 99 | -(BOOL)isEqualToRule:(Rule *)rule; 100 | 101 | //is rule temp? 102 | -(BOOL)isTemporary; 103 | 104 | //covert to dictionary 105 | -(NSMutableString*)toJSON; 106 | 107 | //make a rule obj from a dictioanary 108 | -(id)initFromJSON:(NSDictionary*)info; 109 | 110 | @end 111 | 112 | #endif /* Rule_h */ 113 | -------------------------------------------------------------------------------- /LuLu/Shared/XPCDaemonProto.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCDaemonProtocol.h 3 | // project: LuLu (shared) 4 | // description: methods exported by the daemon 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Foundation; 11 | 12 | @protocol XPCDaemonProtocol 13 | 14 | //get preferences 15 | -(void)getPreferences:(void (^)(NSDictionary*))reply; 16 | 17 | //update preferences 18 | -(void)updatePreferences:(NSDictionary*)preferences reply:(void (^)(NSDictionary*))reply; 19 | 20 | //get rules 21 | -(void)getRules:(void (^)(NSData*))reply; 22 | 23 | //add rule 24 | -(void)addRule:(NSDictionary*)info; 25 | 26 | //delete rule 27 | -(void)deleteRule:(NSString*)key rule:(NSString*)uuid; 28 | 29 | //import rules 30 | -(void)importRules:(NSData*)newRules result:(void (^)(BOOL))reply; 31 | 32 | //cleanup rules 33 | -(void)cleanupRules:(void (^)(NSInteger))reply; 34 | 35 | //uninstall 36 | -(void)uninstall:(void (^)(BOOL))reply; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /LuLu/Shared/XPCUserProto.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: XPCUserProtocol 3 | // project: LuLu (shared) 4 | // description: protocol for talking to the user (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2018 Objective-See. All rights reserved. 8 | // 9 | 10 | @import Foundation; 11 | 12 | @protocol XPCUserProtocol 13 | 14 | //rules changed 15 | -(void)rulesChanged; 16 | 17 | //show an alert 18 | -(void)alertShow:(NSDictionary*)alert reply:(void (^)(NSDictionary*))reply; 19 | 20 | @end 21 | 22 | -------------------------------------------------------------------------------- /LuLu/Shared/images/objectiveSeeLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/Shared/images/objectiveSeeLogo.png -------------------------------------------------------------------------------- /LuLu/Shared/images/objectiveSeeText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/objective-see/LuLu/4e7a7501b9e389a29a6a0a41fc6b2d8a9f839043/LuLu/Shared/images/objectiveSeeText.png -------------------------------------------------------------------------------- /LuLu/Shared/signing.h: -------------------------------------------------------------------------------- 1 | // 2 | // File: Signing.h 3 | // Project: Proc Info 4 | // 5 | // Created by: Patrick Wardle 6 | // Copyright: 2017 Objective-See 7 | // 8 | 9 | #ifndef Signing_h 10 | #define Signing_h 11 | 12 | @import OSLog; 13 | @import Foundation; 14 | 15 | /* FUNCTIONS */ 16 | 17 | //get the signing info of a item 18 | // audit token: extract dynamic code signing info 19 | // path specified: generate static code signing info 20 | NSMutableDictionary* extractSigningInfo(audit_token_t* token, NSString* path, SecCSFlags flags); 21 | 22 | //determine who signed item 23 | NSNumber* extractSigner(SecStaticCodeRef code, SecCSFlags flags, BOOL isDynamic); 24 | 25 | //validate a requirement 26 | OSStatus validateRequirement(SecStaticCodeRef code, SecRequirementRef requirement, SecCSFlags flags, BOOL isDynamic); 27 | 28 | //extract (names) of signing auths 29 | NSMutableArray* extractSigningAuths(NSDictionary* signingDetails); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /LuLu/Shared/utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // file: utilities.h 3 | // project: lulu (shared) 4 | // description: various helper/utility functions (header) 5 | // 6 | // created by Patrick Wardle 7 | // copyright (c) 2017 Objective-See. All rights reserved. 8 | // 9 | 10 | #ifndef Utilities_h 11 | #define Utilities_h 12 | 13 | @import AppKit; 14 | @import Foundation; 15 | 16 | /* FUNCTIONS */ 17 | 18 | //give path to bundle 19 | // get full path to its binary 20 | NSString* getBundleExecutable(NSString* appPath); 21 | 22 | //get app's version 23 | // extracted from Info.plist 24 | NSString* getAppVersion(void); 25 | 26 | //get (true) parent 27 | NSDictionary* getRealParent(pid_t pid); 28 | 29 | //get name of logged in user 30 | NSString* getConsoleUser(void); 31 | 32 | //given a path to binary 33 | // parse it back up to find app's bundle 34 | NSBundle* findAppBundle(NSString* binaryPath); 35 | 36 | //get process's path 37 | NSString* getProcessPath(pid_t pid); 38 | 39 | //get process name 40 | // either via app bundle, or path 41 | NSString* getProcessName(pid_t pid, NSString* path); 42 | 43 | //get current working dir 44 | NSString* getProcessCWD(pid_t pid); 45 | 46 | //given a process path and user 47 | // return array of all matching pids 48 | NSMutableArray* getProcessIDs(NSString* processPath, int userID); 49 | 50 | //get parent pid 51 | pid_t getParent(int pid); 52 | 53 | //enable/disable a menu 54 | void toggleMenu(NSMenu* menu, BOOL shouldEnable); 55 | 56 | //toggle login item 57 | // either add (install) or remove (uninstall) 58 | BOOL toggleLoginItem(NSURL* loginItem, int toggleFlag); 59 | 60 | //get an icon for a process 61 | // for apps, this will be app's icon, otherwise just a standard system one 62 | NSImage* getIconForProcess(NSString* path); 63 | 64 | //wait until a window is non nil 65 | // then make it modal 66 | void makeModal(NSWindowController* windowController); 67 | 68 | //find all processes by name 69 | NSMutableArray* findProcesses(NSString* processName); 70 | 71 | //hash a file (sha256) 72 | NSMutableString* hashFile(NSString* filePath); 73 | 74 | //loads a framework 75 | // note: assumes is in 'Framework' dir 76 | NSBundle* loadFramework(NSString* name); 77 | 78 | //check if (full) dark mode 79 | // meaning, Mojave+ and dark mode enabled 80 | BOOL isDarkMode(void); 81 | 82 | //check if something is nil 83 | // if so, return a default ('unknown') value 84 | NSString* valueForStringItem(NSString* item); 85 | 86 | //grab date added 87 | // extracted via 'kMDItemDateAdded' 88 | NSDate* dateAdded(NSString* file); 89 | 90 | //show an alert 91 | NSModalResponse showAlert(NSAlertStyle style, NSString* messageText, NSString* informativeText, NSArray* buttons); 92 | 93 | //get audit token for pid 94 | NSData* tokenForPid(pid_t pid); 95 | 96 | //given an ip address 97 | // reverse resolves it 98 | NSArray* resolveAddress(NSString * address); 99 | 100 | //process alive? 101 | BOOL isAlive(pid_t processID); 102 | 103 | //check if app is an simulator app 104 | // for now check 'iPhoneSimulator' and 'AppleTVSimulator' 105 | BOOL isSimulatorApp(NSString* path); 106 | 107 | //was app launched by user 108 | BOOL launchedByUser(void); 109 | 110 | //fade out a window 111 | void fadeOut(NSWindow* window, float duration); 112 | 113 | //matches CS info? 114 | BOOL matchesCSInfo(NSDictionary* csInfo_1, NSDictionary* csInfo_2); 115 | 116 | //escape string 117 | NSString* toEscapedJSON(NSString* input); 118 | 119 | //convert date to absolute 120 | NSDate* absoluteDate(NSDate* date); 121 | 122 | //generate list of ancestors 123 | NSMutableArray* generateProcessHierarchy(pid_t child); 124 | 125 | //is process on internal drive? 126 | BOOL isInternalProcess(NSString *path); 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LuLu 2 | 3 | [简体中文](README_zh-Hans.md) | [正體中文](README_zh-Hant.md) 4 | 5 | LuLu is the free open-source macOS firewall: 6 | 7 |

8 | 9 | **Documentation:** \ 10 | Full details and usage instructions can be found [here](https://objective-see.com/products/lulu.html). 11 | 12 | **To Support:** \ 13 | ❤  Love this product and want to support it? Please check out my [patreon page](https://www.patreon.com/objective_see). 14 | 15 |

16 | 17 | 18 | 19 |

20 | -------------------------------------------------------------------------------- /README_zh-Hans.md: -------------------------------------------------------------------------------- 1 | # LuLu 2 | 3 | [English](README.md) | [正體中文](README_zh-Hant.md) 4 | 5 | LuLu 是免费的开源 macOS 防火墙: 6 | 7 |

8 | 9 | **文档:** \ 10 | 可[在此处](https://objective-see.com/products/lulu.html)找到完整的详细信息和使用说明。 11 | 12 | **支持:** \ 13 | ❤  喜欢这个产品并想支持它?请查看我的 [patreon 页面](https://www.patreon.com/objective_see). 14 | 15 |

16 | 17 | 18 | 19 |

20 | -------------------------------------------------------------------------------- /README_zh-Hant.md: -------------------------------------------------------------------------------- 1 | # LuLu 2 | 3 | [English](README.md) | [简体中文](README_zh-Hans.md) 4 | 5 | LuLu 是免費的開源 macOS 防火牆: 6 | 7 |

8 | 9 | ** 文件:** \ 10 | 可[在此處](https://objective-see.com/products/lulu.html)找到完整的詳細資訊和使用説明。 11 | 12 | **支持:** \ 13 | ❤  喜歡這個産品並想支持它?請查看我的 [patreon 頁面](https://www.patreon.com/objective_see). 14 | 15 |

16 | 17 | 18 | 19 |

20 | -------------------------------------------------------------------------------- /lulu.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lulu.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------