Skip to content

Commit

Permalink
Begin adding preferences
Browse files Browse the repository at this point in the history
  • Loading branch information
Johan Bloemberg committed Jan 5, 2019
1 parent 4822e8a commit 52ff4ef
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 25 deletions.
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ disabled_rules:
- todo
# conflicts with swiftformat's default
- trailing_comma
- function_body_length
excluded:
# ignore vendor files, will be removed in the future
- WireGuardStatusbar/INIParser.swift
Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,13 @@ ${build_dest}/WireGuardStatusbar.app: ${sources} | icons ${xcpretty}

# install and run the App /Application using the distributable .dmg
install: /Applications/WireGuardStatusbar.app
/Applications/WireGuardStatusbar.app: ${build_dest}/WireGuardStatusbar.app | WireGuardStatusbar.dmg
/Applications/WireGuardStatusbar.app: WireGuardStatusbar.dmg
-osascript -e 'tell application "WireGuardStatusbar" to quit'
-diskutil umount /Volumes/WireGuardStatusbar
-hdiutil detach -quiet /Volumes/WireGuardStatusbar/
hdiutil attach -quiet WireGuardStatusbar.dmg
cp -r /Volumes/WireGuardStatusbar/WireGuardStatusbar.app /Volumes/WireGuardStatusbar/Applications/
hdiutil detach -quiet /Volumes/WireGuardStatusbar/
touch $@
open "$@"

uninstall:
Expand Down
5 changes: 5 additions & 0 deletions Shared/Const.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ Please follow the instructions on:
and restart this Application afterwards.
"""

let defaultSettings = [
"showAllTunnelDetails": false,
"showConnectedTunnelDetails": true,
]
12 changes: 10 additions & 2 deletions UnitTests/AppTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,19 @@ class AppTests: XCTestCase {
XCTAssertEqual(menu.items[4].title, " Allowed IPs: 198.51.100.0/24")
}

func testMenuEnabledTunnelNoDetails() {
var tunnels = testTunnels
tunnels[0].interface = "utun1"

let menu = buildMenu(tunnels: tunnels, connectedTunnelDetails: false)
XCTAssertEqual(menu.items[1].title, "2 Invalid Config")
}

func testMenuDetails() {
var tunnels = testTunnels
tunnels[0].interface = "utun1"

let menu = buildMenu(tunnels: tunnels, details: true)
let menu = buildMenu(tunnels: tunnels, allTunnelDetails: true)
XCTAssertEqual(menu.items[0].title, "1 Tunnel Name")
XCTAssertEqual(menu.items[0].state, NSControl.StateValue.on)
XCTAssertEqual(menu.items[1].title, " Interface: utun1")
Expand All @@ -88,7 +96,7 @@ class AppTests: XCTestCase {
var tunnels = testTunnels
tunnels[1].interface = "utun1"

let menu = buildMenu(tunnels: tunnels, details: true)
let menu = buildMenu(tunnels: tunnels, allTunnelDetails: true)
let offset = 4
XCTAssertEqual(menu.items[0 + offset].title, "2 Invalid Config")
XCTAssertEqual(menu.items[0 + offset].state, NSControl.StateValue.on)
Expand Down
12 changes: 11 additions & 1 deletion WireGuardStatusbar.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 50;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -44,6 +44,9 @@
0456DA6521BB0C9000701CCE /* HelperProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0456DA6321BB0C9000701CCE /* HelperProtocol.swift */; };
0456DA6621BB0C9A00701CCE /* HelperProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0456DA6321BB0C9000701CCE /* HelperProtocol.swift */; };
0456DA6721BB0C9C00701CCE /* Const.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0456DA6221BB0C9000701CCE /* Const.swift */; };
0457E2FC21DFF1F600DD17A2 /* PreferencesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0457E2FA21DFF1F600DD17A2 /* PreferencesController.swift */; };
0457E2FD21DFF1F600DD17A2 /* PreferencesController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0457E2FB21DFF1F600DD17A2 /* PreferencesController.xib */; };
0457E2FE21DFF2D400DD17A2 /* PreferencesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0457E2FA21DFF1F600DD17A2 /* PreferencesController.swift */; };
0466E5B821C1AB2D00113B45 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04B4BE43211E1E010001213A /* AppDelegate.swift */; };
0466E5B921C1AB5700113B45 /* Const.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0456DA6221BB0C9000701CCE /* Const.swift */; };
0466E5BA21C1AB5700113B45 /* HelperProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0456DA6321BB0C9000701CCE /* HelperProtocol.swift */; };
Expand Down Expand Up @@ -124,6 +127,8 @@
04554CBB21C0515900A08A17 /* test-localhost.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "test-localhost.conf"; sourceTree = "<group>"; };
0456DA6221BB0C9000701CCE /* Const.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Const.swift; path = Shared/Const.swift; sourceTree = "<group>"; };
0456DA6321BB0C9000701CCE /* HelperProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HelperProtocol.swift; path = Shared/HelperProtocol.swift; sourceTree = "<group>"; };
0457E2FA21DFF1F600DD17A2 /* PreferencesController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesController.swift; sourceTree = "<group>"; };
0457E2FB21DFF1F600DD17A2 /* PreferencesController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferencesController.xib; sourceTree = "<group>"; };
047AE5D821DE7D390099ABF6 /* HelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelperTests.swift; sourceTree = "<group>"; };
0490167D21C04B3800299400 /* IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0490167F21C04B3900299400 /* IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -242,6 +247,8 @@
0401E29621C990FB0030E707 /* HelperXPC.swift */,
0401E29821C9913B0030E707 /* Tunnel.swift */,
0401E2AB21CD853B0030E707 /* Menu.swift */,
0457E2FA21DFF1F600DD17A2 /* PreferencesController.swift */,
0457E2FB21DFF1F600DD17A2 /* PreferencesController.xib */,
);
path = WireGuardStatusbar;
sourceTree = "<group>";
Expand Down Expand Up @@ -396,6 +403,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0457E2FD21DFF1F600DD17A2 /* PreferencesController.xib in Resources */,
04B4BE46211E1E030001213A /* Assets.xcassets in Resources */,
04B4BE49211E1E030001213A /* MainMenu.xib in Resources */,
04B2BD2E21BD5DC800CCAE2F /* README.md in Resources */,
Expand Down Expand Up @@ -492,6 +500,7 @@
0401E2AA21CD81210030E707 /* Types.swift in Sources */,
0401E2B321CD93370030E707 /* AppXPC.swift in Sources */,
0401E29B21C992C80030E707 /* Tunnel.swift in Sources */,
0457E2FE21DFF2D400DD17A2 /* PreferencesController.swift in Sources */,
0401E29D21C992EE0030E707 /* HelperXPC.swift in Sources */,
0401E2B221CD93340030E707 /* WireGuard.swift in Sources */,
0401E2B121CD92A80030E707 /* Helper.swift in Sources */,
Expand All @@ -508,6 +517,7 @@
0401E2A921CD811F0030E707 /* Types.swift in Sources */,
0456DA6421BB0C9000701CCE /* Const.swift in Sources */,
0401E29921C9913B0030E707 /* Tunnel.swift in Sources */,
0457E2FC21DFF1F600DD17A2 /* PreferencesController.swift in Sources */,
0401E2AC21CD853B0030E707 /* Menu.swift in Sources */,
0401E29721C990FB0030E707 /* HelperXPC.swift in Sources */,
0456DA6521BB0C9000701CCE /* HelperProtocol.swift in Sources */,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 32 additions & 7 deletions WireGuardStatusbar/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ extension NSImage.Name {

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, AppProtocol {
// don't load persistent defaults during development/ui-testing
#if DEBUG
let defaults = UserDefaults(suiteName: "test")!
#else
let defaults = UserDefaults.standard
#endif

// keep the existence and state of all tunnel(configuration)s
var tunnels = Tunnels()

Expand All @@ -30,6 +37,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, AppProtocol {
var privilegedHelper: HelperXPC?

func applicationDidFinishLaunching(_: Notification) {
// set default preferences
defaults.register(defaults: defaultSettings)

// set a default icon at startup
statusItem.image = NSImage(named: .appInit)!
statusItem.image!.isTemplate = true
Expand All @@ -40,7 +50,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, AppProtocol {
button.sendAction(on: [NSEvent.EventTypeMask.leftMouseDown, NSEvent.EventTypeMask.rightMouseDown])
}

// initialize helper,
// initialize helper XPC connection
privilegedHelper = HelperXPC(exportedObject: self)

// install the Helper or Update it if needed
Expand All @@ -64,9 +74,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, AppProtocol {
// build menu on the fly using tunnels state/configuration
@objc func statusBarButtonClicked(sender _: NSStatusBarButton) {
let event = NSApp.currentEvent!
let details = event.modifierFlags.contains(.option)
let optionClicked = event.modifierFlags.contains(.option)

let showAllTunnelDetails = defaults.bool(forKey: "showAllTunnelDetails")

let showDetails = optionClicked || showAllTunnelDetails
let showConnected = defaults.bool(forKey: "showConnectedTunnelDetails")

statusItem.popUpMenu(buildMenu(tunnels: tunnels, details: details,
statusItem.popUpMenu(buildMenu(tunnels: tunnels,
allTunnelDetails: showDetails,
connectedTunnelDetails: showConnected,
showInstallInstructions: !wireguardInstalled))
}

Expand Down Expand Up @@ -110,15 +127,23 @@ class AppDelegate: NSObject, NSApplicationDelegate, AppProtocol {
alert.runModal()
}

@objc func quit(_: NSMenuItem) {
NSApplication.shared.terminate(self)
}

@objc func about(_: NSMenuItem) {
NSApplication.shared.orderFrontStandardAboutPanel(self)
NSApplication.shared.activate(ignoringOtherApps: true)
}

var preferences: NSWindowController?
@objc func preferences(_: NSMenuItem) {
if preferences == nil {
preferences = Preferences()
}
preferences!.showWindow(nil)
}

@objc func quit(_: NSMenuItem) {
NSApplication.shared.terminate(self)
}

func applicationWillTerminate(_: Notification) {
// TODO: configurable option to disable tunnels on shutdown
}
Expand Down
2 changes: 1 addition & 1 deletion WireGuardStatusbar/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.13</string>
<string>1.14</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
Expand Down
15 changes: 10 additions & 5 deletions WireGuardStatusbar/Menu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import Cocoa

// contruct menu with all tunnels found in configuration
// TODO: find out if it is possible to have a dynamic bound IB menu with variable contents
func buildMenu(tunnels: Tunnels, details: Bool = false, showInstallInstructions: Bool = false) -> NSMenu {
func buildMenu(tunnels: Tunnels, allTunnelDetails: Bool = false, connectedTunnelDetails: Bool = true,
showInstallInstructions: Bool = false) -> NSMenu {
// TODO: currently just rebuilding the entire menu, maybe opt for replacing the tunnel entries instead?
let statusMenu = NSMenu()
statusMenu.minimumWidth = 200

statusMenu.addItem(NSMenuItem.separator())
statusMenu.addItem(NSMenuItem(title: "About", action: #selector(AppDelegate.about(_:)), keyEquivalent: ""))
statusMenu.addItem(NSMenuItem(title: "Quit", action: #selector(AppDelegate.quit(_:)), keyEquivalent: "q"))
statusMenu.addItem(NSMenuItem(title: "About", action: #selector(AppDelegate.about(_:)),
keyEquivalent: ""))
statusMenu.addItem(NSMenuItem(title: "Preferences...", action: #selector(AppDelegate.preferences(_:)),
keyEquivalent: ","))
statusMenu.addItem(NSMenuItem(title: "Quit", action: #selector(AppDelegate.quit(_:)),
keyEquivalent: "q"))

// WireGaurd missing is a big problem, user should fix this first. TODO, include WireGuard with the App
if showInstallInstructions {
Expand All @@ -33,7 +38,7 @@ func buildMenu(tunnels: Tunnels, details: Bool = false, showInstallInstructions:
if tunnel.connected {
item.state = NSControl.StateValue.on
}
if tunnel.connected || details {
if (tunnel.connected && connectedTunnelDetails) || allTunnelDetails {
if let config = tunnel.config {
for peer in config.peers {
statusMenu.insertItem(
Expand All @@ -51,7 +56,7 @@ func buildMenu(tunnels: Tunnels, details: Bool = false, showInstallInstructions:
}
}

if tunnel.connected, let interface = tunnel.interface {
if tunnel.connected && (connectedTunnelDetails || allTunnelDetails), let interface = tunnel.interface {
statusMenu.insertItem(NSMenuItem(title: " Interface: \(interface)",
action: nil, keyEquivalent: ""), at: 0)
}
Expand Down
28 changes: 28 additions & 0 deletions WireGuardStatusbar/PreferencesController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//

import Cocoa

class Preferences: NSWindowController {
override var windowNibName: String {
return "PreferencesController"
}

// make sure window is always brought to the front when it is opened
override func showWindow(_: Any?) {
window?.center()
window?.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
}

// close on ⌘-w (required because app has no menubar with close window action)
override func keyDown(with event: NSEvent) {
if event.modifierFlags.contains(.command) && event.characters == "w" {
window?.close()
}
}

// close on esc key
@objc func cancel(_: Any?) {
window?.close()
}
}
78 changes: 78 additions & 0 deletions WireGuardStatusbar/PreferencesController.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="PreferencesController" customModule="WireGuardStatusbar" customModuleProvider="target">
<connections>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="WireGuardStatusbar Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="464" height="99"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="464" height="99"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IDs-pg-KKz">
<rect key="frame" x="18" y="20" width="428" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Using ⌥ while clicking the icon will always show details for all tunnels." id="YUk-cT-Go7">
<font key="font" metaFont="system"/>
<color key="textColor" name="systemGrayColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tNl-7F-mIu">
<rect key="frame" x="18" y="63" width="183" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Show details on all tunnels" bezelStyle="regularSquare" imagePosition="left" inset="2" id="NM9-F3-wFq">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="6PC-Jo-aPx" name="value" keyPath="values.showAllTunnelDetails" id="W9W-qH-GrG"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HI0-mR-oFH">
<rect key="frame" x="18" y="43" width="234" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Show details on connected tunnels" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Yjb-1e-uAs">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="6PC-Jo-aPx" name="enabled" keyPath="values.showAllTunnelDetails" id="EOt-im-tYW">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
<binding destination="6PC-Jo-aPx" name="value" keyPath="values.showConnectedTunnelDetails" id="BAL-A3-vaz"/>
</connections>
</button>
</subviews>
</view>
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="8" y="2.5"/>
</window>
<userDefaultsController representsSharedInstance="YES" id="6PC-Jo-aPx"/>
<button verticalHuggingPriority="750" id="aHX-dO-il1">
<rect key="frame" x="0.0" y="0.0" width="61" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="radio" title="Radio" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="Vb7-ag-cJm">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</objects>
</document>
Loading

0 comments on commit 52ff4ef

Please sign in to comment.