diff --git a/AppCheck.xcodeproj/project.pbxproj b/AppCheck.xcodeproj/project.pbxproj index 35a7ff2..1e00d91 100644 --- a/AppCheck.xcodeproj/project.pbxproj +++ b/AppCheck.xcodeproj/project.pbxproj @@ -71,6 +71,13 @@ 545DDDD424466D37003B6544 /* AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DDDD324466D37003B6544 /* AutoLayout.swift */; }; 546063E523FEFAFE008F505A /* DBCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B7562223D7B2DC008F0C41 /* DBCore.swift */; }; 54686A7624F8062C0084934D /* NotificationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54686A7524F8062C0084934D /* NotificationBanner.swift */; }; + 54686A8524FD0A3F0084934D /* tut-recording-howto.md in Resources */ = {isa = PBXBuildFile; fileRef = 54686A8424FD0A3F0084934D /* tut-recording-howto.md */; }; + 54686A8724FD27AA0084934D /* TinyMarkdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54686A8624FD26410084934D /* TinyMarkdown.swift */; }; + 54686A8D24FD428C0084934D /* tut-welcome-1.md in Resources */ = {isa = PBXBuildFile; fileRef = 54686A8824FD31580084934D /* tut-welcome-1.md */; }; + 54686A8E24FD42950084934D /* tut-welcome-2.md in Resources */ = {isa = PBXBuildFile; fileRef = 54686A8B24FD3F180084934D /* tut-welcome-2.md */; }; + 54686A8F24FD42950084934D /* tut-recording-1.md in Resources */ = {isa = PBXBuildFile; fileRef = 54686A8A24FD3F100084934D /* tut-recording-1.md */; }; + 54686A9024FD42950084934D /* tut-recording-2.md in Resources */ = {isa = PBXBuildFile; fileRef = 54686A8924FD31630084934D /* tut-recording-2.md */; }; + 54686A9124FD42950084934D /* tut-cooccurrence.md in Resources */ = {isa = PBXBuildFile; fileRef = 54686A8C24FD3F630084934D /* tut-cooccurrence.md */; }; 54751E512423955100168273 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54751E502423955000168273 /* URL.swift */; }; 54751E522423955100168273 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54751E502423955000168273 /* URL.swift */; }; 54953E3323DC752E0054345C /* DBCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B7562223D7B2DC008F0C41 /* DBCore.swift */; }; @@ -270,6 +277,13 @@ 545DDDD024436983003B6544 /* QuickUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickUI.swift; sourceTree = ""; }; 545DDDD324466D37003B6544 /* AutoLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoLayout.swift; sourceTree = ""; }; 54686A7524F8062C0084934D /* NotificationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationBanner.swift; sourceTree = ""; }; + 54686A8424FD0A3F0084934D /* tut-recording-howto.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = "tut-recording-howto.md"; sourceTree = ""; }; + 54686A8624FD26410084934D /* TinyMarkdown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinyMarkdown.swift; sourceTree = ""; }; + 54686A8824FD31580084934D /* tut-welcome-1.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "tut-welcome-1.md"; sourceTree = ""; }; + 54686A8924FD31630084934D /* tut-recording-2.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "tut-recording-2.md"; sourceTree = ""; }; + 54686A8A24FD3F100084934D /* tut-recording-1.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "tut-recording-1.md"; sourceTree = ""; }; + 54686A8B24FD3F180084934D /* tut-welcome-2.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "tut-welcome-2.md"; sourceTree = ""; }; + 54686A8C24FD3F630084934D /* tut-cooccurrence.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "tut-cooccurrence.md"; sourceTree = ""; }; 54751E502423955000168273 /* URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URL.swift; sourceTree = ""; }; 548B1F9423D338EC005B047C /* main.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = main.entitlements; sourceTree = ""; }; 54953E5E23DEBE840054345C /* TVCDomains.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVCDomains.swift; sourceTree = ""; }; @@ -515,6 +529,7 @@ 542E2A9B24051F79001462DC /* media */ = { isa = PBXGroup; children = ( + 54686A8324FD0A3F0084934D /* tutorials */, 5430789E24B5E10E00278F2D /* sounds */, 541A957523E602DF00C09C19 /* LaunchIcon.png */, 54B345AF242264F8004C53CC /* third-level.txt */, @@ -561,6 +576,7 @@ 54E67E4524A8B0FE0025D261 /* PrefsShared.swift */, 545DDDD024436983003B6544 /* QuickUI.swift */, 545DDDCE243E6267003B6544 /* TutorialSheet.swift */, + 54686A8624FD26410084934D /* TinyMarkdown.swift */, 54D8B979246C9F2000EB2414 /* FilterPipeline.swift */, 54448A3124899A4000771C96 /* SearchBarManager.swift */, 549ECD9C24A7AD550097571C /* CustomAlert.swift */, @@ -572,6 +588,19 @@ path = "Common Classes"; sourceTree = ""; }; + 54686A8324FD0A3F0084934D /* tutorials */ = { + isa = PBXGroup; + children = ( + 54686A8824FD31580084934D /* tut-welcome-1.md */, + 54686A8B24FD3F180084934D /* tut-welcome-2.md */, + 54686A8A24FD3F100084934D /* tut-recording-1.md */, + 54686A8924FD31630084934D /* tut-recording-2.md */, + 54686A8424FD0A3F0084934D /* tut-recording-howto.md */, + 54686A8C24FD3F630084934D /* tut-cooccurrence.md */, + ); + path = tutorials; + sourceTree = ""; + }; 54A0CC0D24E314B6009B5EC1 /* GUI */ = { isa = PBXGroup; children = ( @@ -956,16 +985,20 @@ files = ( 543078AC24B5E12500278F2D /* typewriter2.caf in Resources */, 54953E7123E473F10054345C /* Settings.bundle in Resources */, + 54686A9024FD42950084934D /* tut-recording-2.md in Resources */, 543078B024B5E12500278F2D /* plop2.caf in Resources */, 541AC5E22399498B00A769D7 /* LaunchScreen.storyboard in Resources */, 54A0CC0924E30C56009B5EC1 /* Recordings.storyboard in Resources */, + 54686A8D24FD428C0084934D /* tut-welcome-1.md in Resources */, 543078B824B5E12500278F2D /* wood2.caf in Resources */, 543078BE24B5E12500278F2D /* drum2.caf in Resources */, 543078B424B5E12500278F2D /* snap1.caf in Resources */, 541AC5DF2399498B00A769D7 /* Assets.xcassets in Resources */, 543078AE24B5E12500278F2D /* wood1.caf in Resources */, + 54686A8524FD0A3F0084934D /* tut-recording-howto.md in Resources */, 541AC5DD2399498A00A769D7 /* Main.storyboard in Resources */, 54B345B0242264F8004C53CC /* third-level.txt in Resources */, + 54686A8F24FD42950084934D /* tut-recording-1.md in Resources */, 543078BA24B5E12500278F2D /* typewriter1.caf in Resources */, 543078B224B5E12500278F2D /* plop1.caf in Resources */, 543078B624B5E12500278F2D /* drum1.caf in Resources */, @@ -973,6 +1006,8 @@ 543078C324B60F3B00278F2D /* Settings.storyboard in Resources */, 543078AA24B5E12500278F2D /* snap2.caf in Resources */, 54A0CC0C24E30D6F009B5EC1 /* Requests.storyboard in Resources */, + 54686A9124FD42950084934D /* tut-cooccurrence.md in Resources */, + 54686A8E24FD42950084934D /* tut-welcome-2.md in Resources */, 541A957623E602DF00C09C19 /* LaunchIcon.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1050,6 +1085,7 @@ 54448A3224899A4000771C96 /* SearchBarManager.swift in Sources */, 5458EBC0243A3F2200CFEB15 /* TVCRecordingDetails.swift in Sources */, 541FC9872497D81C00962623 /* TheGreatDestroyer.swift in Sources */, + 54686A8724FD27AA0084934D /* TinyMarkdown.swift in Sources */, 5412F8EE24571B8200A63D7A /* VCDateFilter.swift in Sources */, 5412FCC424C628FA000DE429 /* TVCConnectionAlerts.swift in Sources */, 543078C924B75CEA00278F2D /* PushNotificationAppOnly.swift in Sources */, diff --git a/main/Common Classes/TinyMarkdown.swift b/main/Common Classes/TinyMarkdown.swift new file mode 100644 index 0000000..a9d0da3 --- /dev/null +++ b/main/Common Classes/TinyMarkdown.swift @@ -0,0 +1,68 @@ +import UIKit + +struct TinyMarkdown { + /// Load markdown file and run through a (very) simple parser (see below). + /// - Parameters: + /// - filename: Will automatically append `.md` extension + /// - replacements: Replace a single occurrence of search string with an attributed replacement. + static func load(_ filename: String, replacements: [String : NSMutableAttributedString] = [:]) -> UITextView { + let url = Bundle.main.url(forResource: filename, withExtension: "md")! + let str = NSMutableAttributedString(withMarkdown: try! String(contentsOf: url)) + for (key, val) in replacements { + guard let r = str.string.range(of: key) else { + QLog.Debug("WARN: markdown key '\(key)' does not exist in \(filename)") + continue + } + str.replaceCharacters(in: NSRange(r, in: str.string), with: val) + } + return QuickUI.text(attributed: str) + } +} + +extension NSMutableAttributedString { + /// Supports only: `#h1`, `##h2`, `###h3`, `_italic_`, `__bold__`, `___boldItalic___` + convenience init(withMarkdown content: String) { + self.init() + let emph = try! NSRegularExpression(pattern: #"(?<=(^|\W))(_{1,3})(\S|\S.*?\S)\2"#, options: []) + beginEditing() + content.enumerateLines { (line, _) in + if line.starts(with: "#") { + var h = 0 + for char in line { + if char == "#" { h += 1 } + else { break } + } + var line = line + line.removeFirst(h) + line = line.trimmingCharacters(in: CharacterSet(charactersIn: " ")) + switch h { + case 1: self.h1(line + "\n") + case 2: self.h2(line + "\n") + default: self.h3(line + "\n") + } + } else { + let nsline = line as NSString + let range = NSRange(location: 0, length: nsline.length) + var i = 0 + for x in emph.matches(in: line, options: [], range: range) { + let r = x.range + self.normal(nsline.substring(from: i, to: r.location)) + i = r.upperBound + let before = nsline.substring(with: r) + let after = before.trimmingCharacters(in: CharacterSet(charactersIn: "_")) + switch (before.count - after.count) / 2 { + case 1: self.italic(after) + case 2: self.bold(after) + default: self.boldItalic(after) + } + } + if i < range.length { + self.normal(nsline.substring(from: i, to: range.length) + "\n") + } else { + self.normal("\n") + } + } + } + endEditing() + } +} diff --git a/main/Extensions/Font.swift b/main/Extensions/Font.swift index d824818..154cfb7 100644 --- a/main/Extensions/Font.swift +++ b/main/Extensions/Font.swift @@ -6,6 +6,7 @@ extension UIFont { } func bold() -> UIFont { withTraits(traits: .traitBold) } func italic() -> UIFont { withTraits(traits: .traitItalic) } + func boldItalic() -> UIFont { withTraits(traits: [.traitBold, .traitItalic]) } func monoSpace() -> UIFont { let traits = fontDescriptor.object(forKey: .traits) as? [UIFontDescriptor.TraitKey: Any] ?? [:] let weight = (traits[.weight] as? CGFloat) ?? UIFont.Weight.regular.rawValue @@ -13,24 +14,29 @@ extension UIFont { } } -extension NSAttributedString { - static func image(_ img: UIImage) -> Self { +extension NSMutableAttributedString { + convenience init(image: UIImage, centered: Bool = false) { + self.init() let att = NSTextAttachment() - att.image = img - return self.init(attachment: att) + att.image = image + append(.init(attachment: att)) + if centered { + let ps = NSMutableParagraphStyle() + ps.alignment = .center + addAttribute(.paragraphStyle, value: ps, range: .init(location: 0, length: length)) + } } } extension NSMutableAttributedString { - static private var def: UIFont = .preferredFont(forTextStyle: .body) + @discardableResult func normal(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: .preferredFont(forTextStyle: style)) } + @discardableResult func bold(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: UIFont.preferredFont(forTextStyle: style).bold()) } + @discardableResult func italic(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: UIFont.preferredFont(forTextStyle: style).italic()) } + @discardableResult func boldItalic(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: UIFont.preferredFont(forTextStyle: style).boldItalic()) } - func normal(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: .preferredFont(forTextStyle: style)) } - func bold(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: UIFont.preferredFont(forTextStyle: style).bold()) } - func italic(_ str: String, _ style: UIFont.TextStyle = .body) -> Self { append(str, withFont: UIFont.preferredFont(forTextStyle: style).italic()) } - - func h1(_ str: String) -> Self { normal(str, .title1) } - func h2(_ str: String) -> Self { normal(str, .title2) } - func h3(_ str: String) -> Self { normal(str, .title3) } + @discardableResult func h1(_ str: String) -> Self { normal(str, .title1) } + @discardableResult func h2(_ str: String) -> Self { normal(str, .title2) } + @discardableResult func h3(_ str: String) -> Self { normal(str, .title3) } private func append(_ str: String, withFont: UIFont) -> Self { append(NSAttributedString(string: str, attributes: [ @@ -39,13 +45,4 @@ extension NSMutableAttributedString { ])) return self } - - func centered(_ content: NSAttributedString) -> Self { - let before = length - append(content) - let ps = NSMutableParagraphStyle() - ps.alignment = .center - addAttribute(.paragraphStyle, value: ps, range: .init(location: before, length: content.length)) - return self - } } diff --git a/main/Extensions/String.swift b/main/Extensions/String.swift index d21775f..cb79ff6 100644 --- a/main/Extensions/String.swift +++ b/main/Extensions/String.swift @@ -47,3 +47,9 @@ private var listOfSLDs: [String : [String : Bool]] = { } return res }() + +extension NSString { + func substring(from: Int, to: Int) -> String { + substring(with: NSRange(location: from, length: to - from)) + } +} diff --git a/main/Recordings/VCRecordings.swift b/main/Recordings/VCRecordings.swift index 55ddbc7..1aac728 100644 --- a/main/Recordings/VCRecordings.swift +++ b/main/Recordings/VCRecordings.swift @@ -126,49 +126,15 @@ class VCRecordings: UIViewController, UINavigationControllerDelegate { @IBAction private func showInfo(_ sender: UIButton) { let x = TutorialSheet() - x.addSheet().addArrangedSubview(QuickUI.text(attributed: NSMutableAttributedString() - .h1("How to record?\n") - .normal("\nThere are two types: specific app recordings and general background activity. " + - "The former are usually 3 – 5 minutes long, the latter need to be at least an hour long.") - .h2("\n\nApp recording\n") - .normal("Before you begin make sure that you quit all running applications and wait a few seconds. " + - "Tap on the 'App' recording button and switch to the application you'd like to inspect. " + - "Use the App as you would normally. Try to get to all corners and functionality the App provides. " + - "When you feel that you have captured enough content, come back to ").italic("AppCheck").normal(" and stop the recording.") - .h2("\n\nBackground recording\n") - .normal("Will answer one simple question: What communications happen while you aren't using your device. " + - "You should solely start a background recording when you know you aren't going to use your device in the near future. " + - "For example, before you go to bed.\n" + - "As soon as you start using your device, you should stop the recording to avoid distorting the results.") - .h2("\n\nFinish\n") - .normal("Upon completion you will find your recording in the section below. " + - "You can review your results and remove any user specific information if necessary.\n") - )) + x.addSheet().addArrangedSubview(TinyMarkdown.load("tut-recording-howto")) x.buttonTitleDone = "Close" x.present() } @objc private func showTutorial() { let x = TutorialSheet() - x.addSheet().addArrangedSubview(QuickUI.text(attributed: NSMutableAttributedString() - .h1("What are Recordings?\n") - .normal("\nSimilar 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." + - "\n\n" + - "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.") - )) - x.addSheet().addArrangedSubview(QuickUI.text(attributed: NSMutableAttributedString() - .h1("Share results\n") - .normal("\nThis step is completely ").bold("optional").normal(". " + - "You can choose to share your results with us. " + - "We can compare similar applications and suggest privacy friendly alternatives. " + - "Together with other likeminded individuals we can increase the awareness for privacy friendly design." + - "\n\n" + - "Thank you very much.") - )) + x.addSheet().addArrangedSubview(TinyMarkdown.load("tut-recording-1")) + x.addSheet().addArrangedSubview(TinyMarkdown.load("tut-recording-2")) x.buttonTitleDone = "Got it" x.present { Prefs.DidShowTutorial.Recordings = true diff --git a/main/Requests/Analysis/VCCoOccurrence.swift b/main/Requests/Analysis/VCCoOccurrence.swift index 63408d4..3b99ee1 100644 --- a/main/Requests/Analysis/VCCoOccurrence.swift +++ b/main/Requests/Analysis/VCCoOccurrence.swift @@ -132,21 +132,9 @@ extension VCCoOccurrence { }() let x = TutorialSheet() - x.addSheet().addArrangedSubview(QuickUI.text(attributed: NSMutableAttributedString() - .h3("Co-Occurrence") - .normal(" allows you to find requests that happen often at the same time as the selected domain. " + - "Hence it will give you a hint what Apps might be involved in the activity." + - "\n\nHow do you interpret these results? Lets look at an example:\n\n") - .centered(.image(sampleCell)) - .normal("\n\nThe domain ").bold("example.org").normal(" had ").bold("14").normal(" requests with an ").italic("average time divergence").normal(" of ").bold("0.71 seconds").normal(". " + - "That is, these 14 domain calls happend, on average, less then a second before or after the original request of the selected domain." + - "\n\nClose temporal proximity and high occurrence counts are both indicators for domain correlation. " + - "Results are sorted by a ranking index (").bold("9.").normal(") which strikes a balance between the two. " + - "Preferring entries with higher counts as well as low time divergence.") - .italic("\n\nTip: ").normal("As a visual guide you can look for the colored bar beside each value. " + - "The larger the bar, the greater the correlation.") - )) - + x.addSheet().addArrangedSubview(TinyMarkdown.load("tut-cooccurrence", replacements: [ + "" : .init(image: sampleCell, centered: true) + ])) x.present(in: self) } } diff --git a/main/TBCMain.swift b/main/TBCMain.swift index a502b2d..2d3ebc8 100644 --- a/main/TBCMain.swift +++ b/main/TBCMain.swift @@ -34,27 +34,8 @@ class TBCMain: UITabBarController { @objc private func showWelcomeMessage() { let x = TutorialSheet() - x.addSheet().addArrangedSubview(QuickUI.text(attributed: NSMutableAttributedString() - .h1("Welcome\n") - .normal("\nAppCheck helps you identify which applications communicate with third parties. " + - "It does so by logging network requests. " + - "AppCheck learns only the destination addresses, not the actual data that is exchanged." + - "\n\n" + - "Your data belongs to you. " + - "Therefore, monitoring and analysis take place on your device only. " + - "The app does not share any data with us or any other third-party. " + - "Unless you choose to.") - )) - x.addSheet().addArrangedSubview(QuickUI.text(attributed: NSMutableAttributedString() - .h1("How it works\n") - .normal("\nAppCheck creates a local VPN tunnel to intercept all network connections. " + - "For each connection AppCheck looks into the DNS headers only, namely the domain names. " + - "\n" + - "These domain names are logged in the background while the VPN is active. " + - "That means, AppCheck does not have to be active in the foreground. " + - "You can close the app and come back later to see the results." - ) - )) + x.addSheet().addArrangedSubview(TinyMarkdown.load("tut-welcome-1")) + x.addSheet().addArrangedSubview(TinyMarkdown.load("tut-welcome-2")) x.present { Prefs.DidShowTutorial.Welcome = true } diff --git a/media/tutorials/tut-cooccurrence.md b/media/tutorials/tut-cooccurrence.md new file mode 100644 index 0000000..752bc35 --- /dev/null +++ b/media/tutorials/tut-cooccurrence.md @@ -0,0 +1,11 @@ +___Co-Occurrence___ allows you to find requests that happen often at the same time as the selected domain. Hence it will give you a hint what Apps might be involved in the activity. + +How do you interpret these results? Lets look at an example: + + + +The domain __example.org__ had __14__ requests with an _average time divergence_ of __0.71 seconds__. That is, these 14 domain calls happend, on average, less then a second before or after the original request of the selected domain. + +Close temporal proximity and high occurrence counts are both indicators for domain correlation. Results are sorted by a ranking index (__9.__) which strikes a balance between the two. Preferring entries with higher counts as well as low time divergence. + +_Tip:_ As a visual guide you can look for the colored bar beside each value. The larger the bar, the greater the correlation. diff --git a/media/tutorials/tut-recording-1.md b/media/tutorials/tut-recording-1.md new file mode 100644 index 0000000..4ed5b4c --- /dev/null +++ b/media/tutorials/tut-recording-1.md @@ -0,0 +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. + +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. diff --git a/media/tutorials/tut-recording-2.md b/media/tutorials/tut-recording-2.md new file mode 100644 index 0000000..30f0062 --- /dev/null +++ b/media/tutorials/tut-recording-2.md @@ -0,0 +1,5 @@ +# Share results + +This step is completely __optional__. You can choose to share your results with us. We can compare similar applications and suggest privacy friendly alternatives. Together with other likeminded individuals we can increase the awareness for privacy friendly design. + +Thank you very much. diff --git a/media/tutorials/tut-recording-howto.md b/media/tutorials/tut-recording-howto.md new file mode 100644 index 0000000..3399331 --- /dev/null +++ b/media/tutorials/tut-recording-howto.md @@ -0,0 +1,16 @@ +# How to record? + +There are two types: 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. + +## App recording + +Before you begin make sure that you quit all running applications and wait a few seconds. Tap on the 'App' recording button and switch to the application you'd like to inspect. Use the App as you would normally. Try to get to all corners and functionality the App provides. When you feel that you have captured enough content, come back to _AppCheck_ and stop the recording. + +## Background recording + +Will answer one simple question: What communications happen while you aren't using your device. You should solely start a background recording when you know you aren't going to use your device in the near future. For example, before you go to bed. +As soon as you start using your device, you should stop the recording to avoid distorting the results. + +## Afterwards + +Upon completion you will find your recording in the section below. You can review your results and remove any user specific information if necessary. diff --git a/media/tutorials/tut-welcome-1.md b/media/tutorials/tut-welcome-1.md new file mode 100644 index 0000000..3a958e3 --- /dev/null +++ b/media/tutorials/tut-welcome-1.md @@ -0,0 +1,5 @@ +# Welcome + +AppCheck helps you identify which applications communicate with third parties. It does so by logging network requests. AppCheck learns only the destination addresses, not the actual data that is exchanged. + +Your data belongs to you. Therefore, monitoring and analysis take place on your device only. The app does not share any data with us or any other third-party. Unless you choose to. diff --git a/media/tutorials/tut-welcome-2.md b/media/tutorials/tut-welcome-2.md new file mode 100644 index 0000000..8694c28 --- /dev/null +++ b/media/tutorials/tut-welcome-2.md @@ -0,0 +1,4 @@ +# How it works + +AppCheck creates a local VPN tunnel to intercept all network connections. For each connection AppCheck looks into the DNS headers only, namely the domain names. +These domain names are logged in the background while the VPN is active. That means, AppCheck does not have to be active in the foreground. You can close the app and come back later to see the results.