Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d68e4ec869 | ||
|
|
762263bfbd | ||
|
|
b1cddc796e | ||
|
|
77e20f31f5 | ||
|
|
0175f5390e | ||
|
|
effc305b86 | ||
|
|
c1fe258b0d | ||
|
|
36a8f0b97b | ||
|
|
33b9cab8a8 | ||
|
|
b88874b38b | ||
|
|
f55f3ea32d | ||
|
|
c843bd76a2 | ||
|
|
4dd2339ed8 | ||
|
|
280526bef4 | ||
|
|
34caffd4a7 | ||
|
|
9e19b457e2 | ||
|
|
e6846953b7 | ||
|
|
6d78aeac7b |
@@ -1397,7 +1397,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = main/main.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 28;
|
||||
CURRENT_PROJECT_VERSION = 33;
|
||||
INFOPLIST_FILE = main/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -1416,7 +1416,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = main/main.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 28;
|
||||
CURRENT_PROJECT_VERSION = 33;
|
||||
INFOPLIST_FILE = main/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -1435,7 +1435,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = GlassVPN/GlassVPN.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 28;
|
||||
CURRENT_PROJECT_VERSION = 33;
|
||||
INFOPLIST_FILE = GlassVPN/Info.plist;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.uni-bamberg.psi.AppCheck.VPN";
|
||||
@@ -1453,7 +1453,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = GlassVPN/GlassVPN.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 28;
|
||||
CURRENT_PROJECT_VERSION = 33;
|
||||
INFOPLIST_FILE = GlassVPN/Info.plist;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "de.uni-bamberg.psi.AppCheck.VPN";
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import NetworkExtension
|
||||
|
||||
let connectMessage: Data = "CONNECT".data(using: .ascii)!
|
||||
let swcdUserAgent: Data = "User-Agent: swcd".data(using: .ascii)!
|
||||
fileprivate var hook : GlassVPNHook!
|
||||
|
||||
// MARK: ObserverFactory
|
||||
@@ -15,8 +17,20 @@ class LDObserverFactory: ObserverFactory {
|
||||
override func signal(_ event: ProxySocketEvent) {
|
||||
switch event {
|
||||
case .receivedRequest(let session, let socket):
|
||||
if socket.isCancelled ||
|
||||
(hook.forceDisconnectUnresolvable && session.ipAddress.isEmpty) {
|
||||
hook.silentlyPrevented(session.host)
|
||||
socket.forceDisconnect()
|
||||
return
|
||||
}
|
||||
let kill = hook.processDNSRequest(session.host)
|
||||
if kill { socket.forceDisconnect() }
|
||||
case .readData(let data, on: let socket):
|
||||
if hook.forceDisconnectSWCD,
|
||||
data.starts(with: connectMessage),
|
||||
data.range(of: swcdUserAgent) != nil {
|
||||
socket.disconnect()
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -53,3 +53,5 @@ That means, AppCheck does not have to be active in the foreground all the time.
|
||||
|
||||
*information will be added soon™*
|
||||
|
||||
For now, go to the results page at [https://appchk.de/](https://appchk.de/).
|
||||
Btw. we are searching for [help](https://appchk.de/help/) on our ongoing research project.
|
||||
|
||||
@@ -30,14 +30,16 @@ struct NotificationBanner {
|
||||
img.tintColor = fg
|
||||
view.addSubview(lbl)
|
||||
view.addSubview(img)
|
||||
img.anchor([.centerY], to: view.layoutMarginsGuide)
|
||||
lbl.anchor([.top, .bottom, .trailing], to: view.layoutMarginsGuide)
|
||||
img.anchor([.centerY], to: lbl)
|
||||
lbl.anchor([.bottom, .trailing], to: view.layoutMarginsGuide)
|
||||
img.widthAnchor =&= 25
|
||||
img.heightAnchor =&= 25
|
||||
if #available(iOS 11, *) {
|
||||
img.leadingAnchor =&= view.layoutMarginsGuide.leadingAnchor
|
||||
lbl.topAnchor =&= view.layoutMarginsGuide.topAnchor
|
||||
} else {
|
||||
img.leadingAnchor =&= view.leadingAnchor + 8
|
||||
lbl.topAnchor =&= view.topAnchor + 8
|
||||
}
|
||||
lbl.leadingAnchor =&= img.trailingAnchor + 8
|
||||
img.bottomAnchor =<= view.bottomAnchor - 8 | .init(rawValue: 999)
|
||||
|
||||
@@ -12,6 +12,7 @@ enum PrefsShared {
|
||||
|
||||
static func registerDefaults() {
|
||||
suite.register(defaults: [
|
||||
"ForceDisconnectSWCD" : true,
|
||||
"RestartReminderEnabled" : true,
|
||||
"RestartReminderWithText" : true,
|
||||
"RestartReminderWithBadge" : true,
|
||||
@@ -37,6 +38,14 @@ extension PrefsShared {
|
||||
get { CurrentRecordingState(rawValue: Int("CurrentlyRecording")) ?? .Off }
|
||||
set { Int("CurrentlyRecording", newValue.rawValue) }
|
||||
}
|
||||
static var ForceDisconnectUnresolvableDNS: Bool {
|
||||
get { PrefsShared.Bool("ForceDisconnectUnresolvableDNS") }
|
||||
set { PrefsShared.Bool("ForceDisconnectUnresolvableDNS", newValue) }
|
||||
}
|
||||
static var ForceDisconnectSWCD: Bool {
|
||||
get { PrefsShared.Bool("ForceDisconnectSWCD") }
|
||||
set { PrefsShared.Bool("ForceDisconnectSWCD", newValue) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -405,7 +405,7 @@ extension SQLiteDatabase {
|
||||
}
|
||||
|
||||
func appBundleList() -> [AppBundleInfo]? {
|
||||
try? run(sql: "SELECT appid, title, subtitle FROM rec WHERE appid IS NOT NULL GROUP BY appid ORDER BY title ASC;") {
|
||||
try? run(sql: "SELECT appid, title, subtitle FROM rec WHERE appid IS NOT NULL GROUP BY appid ORDER BY lower(title) ASC;") {
|
||||
allRows($0) {
|
||||
AppBundleInfo(col_text($0, 0)!, col_text($0, 1), col_text($0, 2))
|
||||
}
|
||||
|
||||
@@ -33,11 +33,13 @@ extension FilterOptions {
|
||||
}
|
||||
|
||||
extension Recording {
|
||||
static let minTimeLongTerm: Timestamp = .hours(1)
|
||||
|
||||
var fallbackTitle: String { get {
|
||||
isLongTerm ? "Background Recording" : "Unnamed Recording #\(id)"
|
||||
} }
|
||||
var duration: Timestamp { get { (stop ?? .now()) - start } }
|
||||
var isLongTerm: Bool { duration > Timestamp.hours(1) }
|
||||
var isLongTerm: Bool { duration > Recording.minTimeLongTerm }
|
||||
var isShared: Bool { uploadkey?.count ?? 0 > 0}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,14 +87,21 @@ struct TimeFormat {
|
||||
|
||||
/// Duration string with format `mm:ss` or `mm:ss.SSS`
|
||||
static func from(_ duration: TimeInterval, millis: Bool = false, hours: Bool = false) -> String {
|
||||
let t = Int(duration)
|
||||
let min = t / 60
|
||||
let sec = t % 60
|
||||
var t = Int(duration)
|
||||
var min = t / 60
|
||||
var sec = t % 60
|
||||
if millis {
|
||||
let mil = Int(duration * 1000) % 1000
|
||||
return String(format: "%02d:%02d.%03d", min, sec, mil)
|
||||
} else if hours {
|
||||
return String(format: "%02d:%02d:%02d", min / 60, min % 60, sec)
|
||||
if t < Recording.minTimeLongTerm {
|
||||
t = Int(Recording.minTimeLongTerm) - t
|
||||
min = t / 60
|
||||
sec = t % 60
|
||||
return String(format: "-%02d:%02d:%02d", min / 60, min % 60, sec)
|
||||
} else {
|
||||
return String(format: "%02d:%02d:%02d", min / 60, min % 60, sec)
|
||||
}
|
||||
}
|
||||
return String(format: "%02d:%02d", min, sec)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="hm5-7q-Zfi">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="hm5-7q-Zfi">
|
||||
<device id="retina4_0" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
@@ -128,6 +128,7 @@
|
||||
<outlet property="buttonView" destination="La3-9e-6TK" id="UMg-xx-6OV"/>
|
||||
<outlet property="headerView" destination="ppJ-js-Wwz" id="68u-8M-R2Q"/>
|
||||
<outlet property="runningView" destination="9Yj-FX-eFd" id="L2C-YR-2HN"/>
|
||||
<outlet property="startSegment" destination="2MI-6l-YQt" id="Jun-ct-Xag"/>
|
||||
<outlet property="stopButton" destination="vAq-EZ-Gmx" id="XiW-1H-I9y"/>
|
||||
<outlet property="timeLabel" destination="rbR-np-cXD" id="EEe-8F-HT6"/>
|
||||
</connections>
|
||||
@@ -413,15 +414,15 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="c0B-OV-ujb">
|
||||
<rect key="frame" x="16" y="8" width="33.5" height="20.5"/>
|
||||
<rect key="frame" x="16" y="9" width="33.5" height="20.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="4" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" id="sAD-Ns-DV6">
|
||||
<rect key="frame" x="16" y="31.5" width="35" height="16"/>
|
||||
<rect key="frame" x="16" y="32.5" width="33" height="14.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
@@ -656,6 +657,7 @@ Duration: 60:00</string>
|
||||
<outlet property="appIcon" destination="rbW-pK-Kct" id="VlO-fG-y1a"/>
|
||||
<outlet property="appTitle" destination="Et0-8d-CId" id="HgD-oI-0J8"/>
|
||||
<outlet property="buttonCancel" destination="TGg-60-wZW" id="5Ej-7t-jaD"/>
|
||||
<outlet property="buttonFilter" destination="LOr-e7-foG" id="qUx-1k-xJK"/>
|
||||
<outlet property="buttonSave" destination="rWg-hE-Ydl" id="zfM-kx-erX"/>
|
||||
<outlet property="chooseAppTap" destination="Jab-q2-U9X" id="Tzv-lm-sUm"/>
|
||||
<outlet property="inputDetails" destination="pql-H5-k6U" id="NXm-8f-5E6"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="qdB-ZO-LHY">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.3" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="qdB-ZO-LHY">
|
||||
<device id="retina4_0" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
@@ -243,25 +243,93 @@
|
||||
</tableViewSection>
|
||||
<tableViewSection headerTitle="Advanced Settings" id="Vlg-nm-VB3">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="VnR-9B-1zl">
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" textLabel="rio-m6-pXN" detailTextLabel="rr4-sR-VxD" style="IBUITableViewCellStyleSubtitle" id="pQ5-lm-Rco">
|
||||
<rect key="frame" x="0.0" y="687.5" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VnR-9B-1zl" id="ZTz-vZ-l5p">
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pQ5-lm-Rco" id="52Y-H3-jvJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="twS-Ne-dU0">
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Force disconnect unresolvable" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="rio-m6-pXN">
|
||||
<rect key="frame" x="16" y="5" width="234" height="20.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="in case DNS returns empty IP" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="rr4-sR-VxD">
|
||||
<rect key="frame" x="16" y="25.5" width="166" height="14.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TSu-IP-KFG">
|
||||
<rect key="frame" x="257" y="6" width="49" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="togglePreventUnresolvable:" destination="qdB-ZO-LHY" eventType="valueChanged" id="xKv-Hp-Nyq"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="accessoryView" destination="TSu-IP-KFG" id="VGm-hN-DLK"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" textLabel="x5u-5T-XTO" detailTextLabel="n7p-Ab-69G" style="IBUITableViewCellStyleSubtitle" id="lxs-NQ-Q7V">
|
||||
<rect key="frame" x="0.0" y="731.5" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="lxs-NQ-Q7V" id="B1l-cb-yQg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Force disconnect swcd" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="x5u-5T-XTO">
|
||||
<rect key="frame" x="16" y="5" width="177" height="20.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="background deamon User-Agent: swcd" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="n7p-Ab-69G">
|
||||
<rect key="frame" x="16" y="25.5" width="220.5" height="14.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c5N-PN-qWU">
|
||||
<rect key="frame" x="257" y="6" width="49" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="togglePreventSWCD:" destination="qdB-ZO-LHY" eventType="valueChanged" id="MAa-5v-djq"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="accessoryView" destination="c5N-PN-qWU" id="SAN-Q9-VOn"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="Tgc-re-gI7">
|
||||
<rect key="frame" x="0.0" y="775.5" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Tgc-re-gI7" id="haV-RB-dEa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vZa-EO-FAZ">
|
||||
<rect key="frame" x="125" y="7" width="70" height="30"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
||||
<state key="normal" title="Export DB"/>
|
||||
<connections>
|
||||
<action selector="exportDB" destination="qdB-ZO-LHY" eventType="touchUpInside" id="FYN-Zz-UK4"/>
|
||||
<action selector="exportDB" destination="qdB-ZO-LHY" eventType="touchUpInside" id="NPx-9w-ua0"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="twS-Ne-dU0" firstAttribute="centerY" secondItem="ZTz-vZ-l5p" secondAttribute="centerY" id="LgK-8q-r6K"/>
|
||||
<constraint firstItem="twS-Ne-dU0" firstAttribute="centerX" secondItem="ZTz-vZ-l5p" secondAttribute="centerX" id="ltC-Ba-Bxr"/>
|
||||
<constraint firstItem="vZa-EO-FAZ" firstAttribute="centerX" secondItem="haV-RB-dEa" secondAttribute="centerX" id="h0M-qz-pHV"/>
|
||||
<constraint firstItem="vZa-EO-FAZ" firstAttribute="centerY" secondItem="haV-RB-dEa" secondAttribute="centerY" id="xBJ-94-nJh"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
@@ -282,6 +350,8 @@
|
||||
<outlet property="cellNotificationConnectionAlert" destination="OTC-Kt-LFT" id="XiG-CC-4lC"/>
|
||||
<outlet property="cellNotificationReminder" destination="jZA-aP-aHG" id="sjo-2s-rqW"/>
|
||||
<outlet property="cellPrivacyAutoDelete" destination="Qyy-0U-yhd" id="PzN-iv-kFl"/>
|
||||
<outlet property="swcdToggle" destination="c5N-PN-qWU" id="qDy-BX-O85"/>
|
||||
<outlet property="unresolvableToggle" destination="TSu-IP-KFG" id="Vdb-cm-Uy2"/>
|
||||
<outlet property="vpnToggle" destination="ZAz-WT-FDb" id="lGX-J8-WrU"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
@@ -364,7 +434,7 @@ If App Badge is enabled, display the letter "1" on the homescreen app icon, as l
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" id="zaV-mh-eqb">
|
||||
<rect key="frame" x="252" y="6" width="54" height="31"/>
|
||||
<rect key="frame" x="250" y="6" width="54" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleAllowRestartReminder:" destination="JYM-cs-i4H" eventType="valueChanged" id="F4e-k2-bni"/>
|
||||
@@ -391,7 +461,7 @@ If App Badge is enabled, display the letter "1" on the homescreen app icon, as l
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" id="HaE-En-NH3">
|
||||
<rect key="frame" x="252" y="6" width="54" height="31"/>
|
||||
<rect key="frame" x="250" y="6" width="54" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleAllowRestartNotify:" destination="JYM-cs-i4H" eventType="valueChanged" id="12C-h5-mrR"/>
|
||||
@@ -418,7 +488,7 @@ If App Badge is enabled, display the letter "1" on the homescreen app icon, as l
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" id="N2Q-cU-pkd">
|
||||
<rect key="frame" x="252" y="6" width="54" height="31"/>
|
||||
<rect key="frame" x="250" y="6" width="54" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleAllowRestartBadge:" destination="JYM-cs-i4H" eventType="valueChanged" id="76l-6y-fOu"/>
|
||||
@@ -476,7 +546,7 @@ If App Badge is enabled, display the letter "1" on the homescreen app icon, as l
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mTm-Rm-1RQ">
|
||||
<rect key="frame" x="255" y="6" width="49" height="31"/>
|
||||
<rect key="frame" x="255" y="6" width="48" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleAllowRecordingReminder:" destination="JYM-cs-i4H" eventType="valueChanged" id="unC-Ur-jPM"/>
|
||||
@@ -602,7 +672,7 @@ If App Badge is enabled, display the letter "1" on the homescreen app icon, as l
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="who-8G-voz">
|
||||
<rect key="frame" x="256" y="6" width="48" height="31"/>
|
||||
<rect key="frame" x="256" y="6" width="47" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<connections>
|
||||
<action selector="toggleShowNotifications:" destination="D2a-Po-vDU" eventType="valueChanged" id="Thg-6R-7wM"/>
|
||||
@@ -832,6 +902,6 @@ If App Badge is enabled, display the letter "1" on the homescreen app icon, as l
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="tUF-Kv-koO"/>
|
||||
<segue reference="6wc-d1-VYY"/>
|
||||
<segue reference="EzT-Xq-wka"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
||||
@@ -161,4 +161,12 @@ struct VPNAppMessage {
|
||||
static func isRecording(_ state: CurrentRecordingState) -> Self {
|
||||
.init("recording-now:\(state.rawValue)")
|
||||
}
|
||||
/// Triggered whenever user taps on the switch in settings
|
||||
static func disconnectUnresolvable(_ state: Bool) -> Self {
|
||||
.init("disconnect-unresolvable:\(state ? 1 : 0)")
|
||||
}
|
||||
/// Triggered whenever user taps on the switch in settings
|
||||
static func disconnectSWCD(_ state: Bool) -> Self {
|
||||
.init("disconnect-swcd:\(state ? 1 : 0)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ class GlassVPNHook {
|
||||
private var cachedNotify: CachedConnectionAlert!
|
||||
private var currentlyRecording: Bool = false
|
||||
|
||||
public var forceDisconnectUnresolvable: Bool = false
|
||||
public var forceDisconnectSWCD: Bool = false
|
||||
|
||||
|
||||
init() { reset() }
|
||||
|
||||
/// Reload from stored settings and rebuilt binary search tree
|
||||
@@ -18,6 +22,8 @@ class GlassVPNHook {
|
||||
setAutoDelete(PrefsShared.AutoDeleteLogsDays)
|
||||
cachedNotify = CachedConnectionAlert()
|
||||
currentlyRecording = PrefsShared.CurrentlyRecording != .Off
|
||||
forceDisconnectUnresolvable = PrefsShared.ForceDisconnectUnresolvableDNS
|
||||
forceDisconnectSWCD = PrefsShared.ForceDisconnectSWCD
|
||||
}
|
||||
|
||||
/// Invalidate auto-delete timer and release stored properties. You should nullify this instance afterwards.
|
||||
@@ -28,6 +34,8 @@ class GlassVPNHook {
|
||||
autoDeleteTimer?.invalidate()
|
||||
cachedNotify = nil
|
||||
currentlyRecording = false
|
||||
forceDisconnectUnresolvable = false
|
||||
forceDisconnectSWCD = false
|
||||
}
|
||||
|
||||
/// Call this method from `PacketTunnelProvider.handleAppMessage(_:completionHandler:)`
|
||||
@@ -50,6 +58,12 @@ class GlassVPNHook {
|
||||
let newState = CurrentRecordingState(rawValue: Int(value) ?? 0)
|
||||
currentlyRecording = newState != .Off
|
||||
return
|
||||
case "disconnect-unresolvable":
|
||||
forceDisconnectUnresolvable = value == "1"
|
||||
return
|
||||
case "disconnect-swcd":
|
||||
forceDisconnectSWCD = value == "1"
|
||||
return
|
||||
default: break
|
||||
}
|
||||
}
|
||||
@@ -79,6 +93,11 @@ class GlassVPNHook {
|
||||
return blockActive
|
||||
}
|
||||
|
||||
func silentlyPrevented(_ domain: String) {
|
||||
// TODO: persist in a separate db/table?
|
||||
NSLog("[VPN.INFO] preventing connection to \(domain)")
|
||||
}
|
||||
|
||||
/// Build binary tree for reverse DNS lookup
|
||||
private func reloadDomainFilter() {
|
||||
let tmp = AppDB?.loadFilters()?.map({
|
||||
@@ -133,13 +152,12 @@ class GlassVPNHook {
|
||||
@objc private func autoDeleteNow(_ sender: Timer) {
|
||||
NSLog("[VPN.INFO] Auto-delete old logs")
|
||||
queue.async {
|
||||
guard sender.isValid else { return }
|
||||
do {
|
||||
try AppDB?.dnsLogsDeleteOlderThan(days: sender.userInfo as! Int)
|
||||
} catch {
|
||||
NSLog("[VPN.WARN] Couldn't delete logs, will retry in 5 minutes. \(error)")
|
||||
if sender.isValid {
|
||||
sender.fireDate = Date().addingTimeInterval(300) // retry in 5 min
|
||||
}
|
||||
sender.fireDate = Date().addingTimeInterval(300) // retry in 5 min
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ class TVCShareRecording : UITableViewController, UITextViewDelegate, VCEditTextD
|
||||
|
||||
// vars
|
||||
var record: Recording!
|
||||
private var shareNotes: Bool = false // opt-in
|
||||
private var shareNotes: Bool = true // green switch is more present
|
||||
private lazy var hasNotes: Bool = (self.record.notes != nil)
|
||||
private lazy var editedNotes: String = self.record.notes ?? ""
|
||||
private lazy var weekInYear: String = {
|
||||
@@ -86,6 +86,13 @@ class TVCShareRecording : UITableViewController, UITextViewDelegate, VCEditTextD
|
||||
}
|
||||
}
|
||||
|
||||
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
|
||||
if motion == .motionShake, let key = record.uploadkey {
|
||||
UIPasteboard.general.string = key
|
||||
banner(.ok, "Copied to clipboard", timeout: 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Table Data Source
|
||||
|
||||
@@ -145,7 +152,7 @@ class TVCShareRecording : UITableViewController, UITextViewDelegate, VCEditTextD
|
||||
cell = tableView.dequeueReusableCell(withIdentifier: "shareKeyValueCell")!
|
||||
let src = dataSourceKeyValue[indexPath.row]
|
||||
cell.textLabel?.text = src.key
|
||||
let flag = shareNotes && indexPath.row == 4
|
||||
let flag = indexPath.row == 4 && shareNotes && hasNotes
|
||||
cell.detailTextLabel?.text = flag ? editedNotes : src.value
|
||||
case 3:
|
||||
cell = tableView.dequeueReusableCell(withIdentifier: "shareLogCell")!
|
||||
@@ -234,8 +241,8 @@ class TVCShareRecording : UITableViewController, UITextViewDelegate, VCEditTextD
|
||||
|
||||
// MARK: - Alerts & Banner
|
||||
|
||||
private func banner(_ style: NotificationBanner.Style, _ msg: String) {
|
||||
NotificationBanner(msg, style: style).present(in: self)
|
||||
private func banner(_ style: NotificationBanner.Style, _ msg: String, timeout: TimeInterval = 3) {
|
||||
NotificationBanner(msg, style: style).present(in: navigationController!, hideAfter: timeout)
|
||||
}
|
||||
|
||||
private func showAlertAvailableSoon(_ urlStr: String, when: Int?) {
|
||||
|
||||
@@ -16,13 +16,18 @@ class VCEditRecording: UIViewController, UITextFieldDelegate, UITextViewDelegate
|
||||
@IBOutlet private var noteBottom: NSLayoutConstraint!
|
||||
|
||||
@IBOutlet private var chooseAppTap: UITapGestureRecognizer!
|
||||
@IBOutlet private var buttonFilter: UIButton!
|
||||
|
||||
override func viewDidLoad() {
|
||||
if deleteOnCancel { // aka newly created
|
||||
RecordingsDB.persist(record)
|
||||
if Prefs.RecordingReminder.Enabled {
|
||||
PushNotification.scheduleRecordingReminder(force: true)
|
||||
let r = record!
|
||||
DispatchQueue.global().async {
|
||||
RecordingsDB.persist(r)
|
||||
if Prefs.RecordingReminder.Enabled {
|
||||
PushNotification.scheduleRecordingReminder(force: true)
|
||||
}
|
||||
}
|
||||
buttonFilter.isHidden = true
|
||||
// mark as destructive
|
||||
buttonCancel.tintColor = .systemRed
|
||||
if #available(iOS 13.0, *) {
|
||||
|
||||
@@ -10,8 +10,10 @@ class VCRecordings: UIViewController, UINavigationControllerDelegate {
|
||||
@IBOutlet private var runningView: UIView!
|
||||
@IBOutlet private var timeLabel: UILabel!
|
||||
@IBOutlet private var stopButton: UIButton!
|
||||
@IBOutlet private var startSegment: UISegmentedControl!
|
||||
|
||||
override func viewDidLoad() {
|
||||
startSegment.setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.sysLink], for: .normal)
|
||||
timeLabel.font = timeLabel.font.monoSpace()
|
||||
if let ongoing = RecordingsDB.getCurrent() {
|
||||
currentRecording = ongoing
|
||||
|
||||
@@ -70,7 +70,7 @@ class TVCOccurrenceContext: UITableViewController {
|
||||
private var copyDomain: String? = nil
|
||||
|
||||
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
if cellMenu.start(tableView, indexPath) {
|
||||
if !firstOrLast(indexPath.row), cellMenu.start(tableView, indexPath) {
|
||||
copyDomain = cellMenu.getSelected(dataSource)?.domain
|
||||
self.becomeFirstResponder()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import UIKit
|
||||
class TVCSettings: UITableViewController {
|
||||
|
||||
@IBOutlet var vpnToggle: UISwitch!
|
||||
@IBOutlet var unresolvableToggle: UISwitch!
|
||||
@IBOutlet var swcdToggle: UISwitch!
|
||||
@IBOutlet var cellDomainsIgnored: UITableViewCell!
|
||||
@IBOutlet var cellDomainsBlocked: UITableViewCell!
|
||||
@IBOutlet var cellPrivacyAutoDelete: UITableViewCell!
|
||||
@@ -14,6 +16,7 @@ class TVCSettings: UITableViewController {
|
||||
reloadVPNState()
|
||||
reloadLoggingFilterUI()
|
||||
reloadPrivacyUI()
|
||||
reloadAdvancedUI()
|
||||
NotifyVPNStateChanged.observe(call: #selector(reloadVPNState), on: self)
|
||||
NotifyDNSFilterChanged.observe(call: #selector(reloadLoggingFilterUI), on: self)
|
||||
}
|
||||
@@ -191,6 +194,21 @@ extension TVCSettings {
|
||||
// MARK: - Advanced
|
||||
|
||||
extension TVCSettings {
|
||||
private func reloadAdvancedUI() {
|
||||
unresolvableToggle.isOn = PrefsShared.ForceDisconnectUnresolvableDNS
|
||||
swcdToggle.isOn = PrefsShared.ForceDisconnectSWCD
|
||||
}
|
||||
|
||||
@IBAction private func togglePreventUnresolvable(_ sender: UISwitch) {
|
||||
PrefsShared.ForceDisconnectUnresolvableDNS = sender.isOn
|
||||
GlassVPN.send(.disconnectUnresolvable(sender.isOn))
|
||||
}
|
||||
|
||||
@IBAction private func togglePreventSWCD(_ sender: UISwitch) {
|
||||
PrefsShared.ForceDisconnectSWCD = sender.isOn
|
||||
GlassVPN.send(.disconnectSWCD(sender.isOn))
|
||||
}
|
||||
|
||||
@IBAction private func exportDB() {
|
||||
AppDB?.vacuum()
|
||||
let sheet = UIActivityViewController(activityItems: [URL.internalDB()], applicationActivities: nil)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# What are Recordings?
|
||||
|
||||
Similar to the default logging, recordings will intercept every request and log it for later review. App recordings are usually 3 – 5 minutes long and cover a single application. You can utilize recordings for App analysis or to get a ground truth on background traffic.
|
||||
Similar to the default logging, recordings will intercept every request and log it for later review. App recordings are usually 1 – 4 minutes long and cover a single application. You can utilize recordings for App analysis or to get a ground truth on background traffic.
|
||||
|
||||
Optionally, you can help us by providing your app specific recordings. Together with your findings we can create a community driven privacy monitor. The research results will help you and others avoid Apps that unnecessarily share data with third-party providers.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# How to record?
|
||||
|
||||
Before you begin, there are two types of recordings: app specific recordings and general background activity. The former are usually 3 – 5 minutes long, the latter need to be at least an hour long.
|
||||
Before you begin, there are two types of recordings: app specific recordings and general background activity. The former are usually less than 5 minutes long, the latter must be at least an hour long.
|
||||
|
||||
### Important notice
|
||||
|
||||
|
||||
Reference in New Issue
Block a user