├── .gitignore
├── Podfile
├── Podfile.lock
├── Pods
├── FavIcon
│ ├── LICENSE
│ ├── README.md
│ └── Sources
│ │ ├── FavIcon
│ │ ├── ContentTypes.swift
│ │ ├── Detection.swift
│ │ ├── Download.swift
│ │ ├── FavIcon.swift
│ │ ├── HTML.swift
│ │ ├── Icon.swift
│ │ ├── IconType.swift
│ │ └── XML.swift
│ │ └── Modules
│ │ ├── libxml2-favicon.h
│ │ └── module.modulemap
├── Local Podspecs
│ └── SQLite.swift.podspec.json
├── Manifest.lock
├── Pods.xcodeproj
│ └── project.pbxproj
├── SQLCipher
│ ├── LICENSE
│ ├── README.md
│ ├── sqlite3.c
│ └── sqlite3.h
├── SQLite.swift
│ ├── LICENSE.txt
│ ├── README.md
│ └── Sources
│ │ ├── SQLite
│ │ ├── Core
│ │ │ ├── Blob.swift
│ │ │ ├── Connection.swift
│ │ │ ├── Errors.swift
│ │ │ ├── Statement.swift
│ │ │ └── Value.swift
│ │ ├── Extensions
│ │ │ ├── Cipher.swift
│ │ │ ├── FTS4.swift
│ │ │ ├── FTS5.swift
│ │ │ └── RTree.swift
│ │ ├── Foundation.swift
│ │ ├── Helpers.swift
│ │ ├── SQLite.h
│ │ └── Typed
│ │ │ ├── AggregateFunctions.swift
│ │ │ ├── Coding.swift
│ │ │ ├── Collation.swift
│ │ │ ├── CoreFunctions.swift
│ │ │ ├── CustomFunctions.swift
│ │ │ ├── DateAndTimeFunctions.swift
│ │ │ ├── Expression.swift
│ │ │ ├── Operators.swift
│ │ │ ├── Query.swift
│ │ │ ├── Schema.swift
│ │ │ └── Setter.swift
│ │ └── SQLiteObjc
│ │ ├── SQLite-Bridging.m
│ │ ├── fts3_tokenizer.h
│ │ └── include
│ │ └── SQLite-Bridging.h
└── Target Support Files
│ ├── FavIcon
│ ├── FavIcon-Info.plist
│ ├── FavIcon-dummy.m
│ ├── FavIcon-prefix.pch
│ ├── FavIcon-umbrella.h
│ ├── FavIcon.modulemap
│ └── FavIcon.xcconfig
│ ├── Pods-allyourpasswords
│ ├── Pods-allyourpasswords-Info.plist
│ ├── Pods-allyourpasswords-acknowledgements.markdown
│ ├── Pods-allyourpasswords-acknowledgements.plist
│ ├── Pods-allyourpasswords-dummy.m
│ ├── Pods-allyourpasswords-frameworks.sh
│ ├── Pods-allyourpasswords-umbrella.h
│ ├── Pods-allyourpasswords.debug.xcconfig
│ ├── Pods-allyourpasswords.modulemap
│ └── Pods-allyourpasswords.release.xcconfig
│ ├── SQLCipher
│ ├── SQLCipher-Info.plist
│ ├── SQLCipher-dummy.m
│ ├── SQLCipher-prefix.pch
│ ├── SQLCipher-umbrella.h
│ ├── SQLCipher.modulemap
│ └── SQLCipher.xcconfig
│ └── SQLite.swift
│ ├── SQLite.swift-Info.plist
│ ├── SQLite.swift-dummy.m
│ ├── SQLite.swift-prefix.pch
│ ├── SQLite.swift-umbrella.h
│ ├── SQLite.swift.modulemap
│ └── SQLite.swift.xcconfig
├── README.md
├── allyourpasswords.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcuserdata
│ └── swlkr.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── allyourpasswords.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── allyourpasswords
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-1025.png
│ │ ├── Icon-128.png
│ │ ├── Icon-128@2x.png
│ │ ├── Icon-16.png
│ │ ├── Icon-16@2x.png
│ │ ├── Icon-256.png
│ │ ├── Icon-256@2x.png
│ │ ├── Icon-32.png
│ │ ├── Icon-32@2x.png
│ │ └── Icon-512.png
│ └── Contents.json
├── Base.lproj
│ └── Main.storyboard
├── Components
│ ├── CursorChangingView.swift
│ ├── CustomTextFieldCell.swift
│ └── HyperlinkTextField.swift
├── Controllers
│ ├── MainViewController.swift
│ └── WindowController.swift
├── CoreData
│ └── Database.swift
├── Extensions
│ ├── NSImageExtensions.swift
│ └── NSTableViewExtension.swift
├── Info.plist
├── KeychainWrapper
│ ├── KeychainItemAccessibility.swift
│ └── KeychainWrapper.swift
├── Models
│ ├── Login.swift
│ └── Prop.swift
├── Views
│ ├── ContainerViewController.swift
│ ├── CustomTableViewCell.swift
│ ├── DetailViewController.swift
│ ├── EditViewController.swift
│ ├── EmptyViewController.swift
│ ├── ResetMasterPasswordViewController.swift
│ ├── SetMasterPasswordViewController.swift
│ ├── TableViewController.swift
│ ├── ToolbarCustomView.swift
│ └── UnlockViewController.swift
└── allyourpasswords.entitlements
└── quick.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 | #
51 | # Add this line if you want to avoid checking in source code from the Xcode workspace
52 | # *.xcworkspace
53 |
54 | # Carthage
55 | #
56 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
57 | # Carthage/Checkouts
58 |
59 | Carthage/Build
60 |
61 | # fastlane
62 | #
63 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
64 | # screenshots whenever they are needed.
65 | # For more information about the recommended setup visit:
66 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
67 |
68 | fastlane/report.xml
69 | fastlane/Preview.html
70 | fastlane/screenshots/**/*.png
71 | fastlane/test_output
72 |
73 | # Code Injection
74 | #
75 | # After new code Injection tools there's a generated folder /iOSInjectionProject
76 | # https://github.com/johnno1962/injectionforxcode
77 |
78 | iOSInjectionProject/
79 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :macos, '10.14'
2 | use_frameworks!
3 |
4 | target 'allyourpasswords' do
5 | pod 'SQLite.swift/SQLCipher', :git => 'https://github.com/stephencelis/SQLite.swift.git', :commit => '1a908a7da11852f252e7c6b6366a4d9f8a7d5272'
6 | pod 'FavIcon', '~> 3.0.0'
7 | end
8 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FavIcon (3.0.6)
3 | - SQLCipher (4.1.0):
4 | - SQLCipher/standard (= 4.1.0)
5 | - SQLCipher/common (4.1.0)
6 | - SQLCipher/standard (4.1.0):
7 | - SQLCipher/common
8 | - SQLite.swift/SQLCipher (0.11.6):
9 | - SQLCipher (>= 3.4.0)
10 |
11 | DEPENDENCIES:
12 | - FavIcon (~> 3.0.0)
13 | - SQLite.swift/SQLCipher (from `https://github.com/stephencelis/SQLite.swift.git`, commit `1a908a7da11852f252e7c6b6366a4d9f8a7d5272`)
14 |
15 | SPEC REPOS:
16 | https://github.com/cocoapods/specs.git:
17 | - FavIcon
18 | - SQLCipher
19 |
20 | EXTERNAL SOURCES:
21 | SQLite.swift:
22 | :commit: 1a908a7da11852f252e7c6b6366a4d9f8a7d5272
23 | :git: https://github.com/stephencelis/SQLite.swift.git
24 |
25 | CHECKOUT OPTIONS:
26 | SQLite.swift:
27 | :commit: 1a908a7da11852f252e7c6b6366a4d9f8a7d5272
28 | :git: https://github.com/stephencelis/SQLite.swift.git
29 |
30 | SPEC CHECKSUMS:
31 | FavIcon: e07ba9dd3cac1f76b81ccaa08fc2b41baa000b07
32 | SQLCipher: efbdb52cdbe340bcd892b1b14297df4e07241b7f
33 | SQLite.swift: 46d890be8601964454bd3392527f863d1b802d45
34 |
35 | PODFILE CHECKSUM: 68c1650a5fda33bfed5ea7f6384ac0c95d77e55c
36 |
37 | COCOAPODS: 1.6.1
38 |
--------------------------------------------------------------------------------
/Pods/FavIcon/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2018 Leon Breedt
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/Pods/FavIcon/README.md:
--------------------------------------------------------------------------------
1 | # FavIcon [](https://raw.githubusercontent.com/leonbreedt/FavIcon/master/LICENSE) [](https://travis-ci.org/leonbreedt/FavIcon) [](https://github.com/Carthage/Carthage)  
2 | FavIcon is a tiny Swift library for downloading the favicon representing a website.
3 |
4 | Wait, why is a library needed to do this? Surely it's just a simple HTTP GET of
5 | `/favicon.ico`, right? Right? Well. Go have a read of [this StackOverflow
6 | post](http://stackoverflow.com/questions/19029342/favicons-best-practices), and
7 | see how you feel afterwards.
8 |
9 | ## Quick Start
10 |
11 | ### CocoaPods
12 |
13 | *Note:* CocoaPods (1.4.0 or later) is required.
14 |
15 | Add it to your `Podfile`:
16 |
17 | ```ruby
18 | use_frameworks!
19 | pod 'FavIcon', '~> 3.0.0'
20 | ```
21 |
22 | ### Carthage
23 |
24 | Add it to your `Cartfile`:
25 |
26 | ```ogdl
27 | github "leonbreedt/FavIcon" ~> 3.0.0
28 | ```
29 |
30 | ## Features
31 | - Detection of `/favicon.ico` if it exists
32 | - Parsing of the HTML at a URL, and scanning for appropriate `` or
33 | `` tags that refer to icons using Apple, Google or Microsoft
34 | conventions.
35 | - Discovery of and parsing of Web Application manifest JSON files to obtain
36 | lists of icons.
37 | - Discovery of and parsing of Microsoft browser configuration XML files for
38 | obtaining lists of icons.
39 |
40 | Yup. These are all potential ways of indicating that your website has an icon
41 | that can be used in user interfaces. Good work, fellow programmers. 👍
42 |
43 | ## Usage Example
44 | Perhaps you have a location in your user interface where you want to put
45 | the icon of a website the user is currently visiting?
46 |
47 | ```swift
48 | try FavIcon.downloadPreferred("https://apple.com") { result in
49 | if case let .success(image) = result {
50 | // On iOS, this is a UIImage, do something with it here.
51 | // This closure will be executed on the main queue, so it's safe to touch
52 | // the UI here.
53 | }
54 | }
55 | ```
56 |
57 | This will detect all of the available icons at the URL, and if it is able to
58 | determine their sizes, it will try to find the icon closest in size to your
59 | desired size, otherwise, it will prefer the largest icon. If it has no idea of
60 | the size of any of the icons, it will prefer the first one it found.
61 |
62 | Of course, if this approach is too opaque for you, you can download them all
63 | using `downloadAll(url:completion:)`.
64 |
65 | Or perhaps you’d like to take a stab at downloading them yourself at a later
66 | time, choosing which icon you prefer based on your own criteria, in which case
67 | `scan(url:completion:)` will give you information about the detected icons, which
68 | you can feed to `download(url:completion:)` for downloading at your convenience.
69 |
70 |
71 | ## Example Project
72 |
73 | See the iOS project in `Example/` for a simple example of how to use the library.
74 |
75 | ## License
76 |
77 | Apache 2.0
78 |
79 |
--------------------------------------------------------------------------------
/Pods/FavIcon/Sources/FavIcon/ContentTypes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FavIcon
3 | // Copyright © 2018 Leon Breedt
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | //
17 |
18 | import Foundation
19 |
20 | func parseHTTPContentType(_ headerValue: String) -> (mimeType: String, encoding: String.Encoding) {
21 | let headerComponents = headerValue
22 | .components(separatedBy: ";")
23 | .map { $0.trimmingCharacters(in: .whitespaces) }
24 |
25 | if headerComponents.count > 1 {
26 | let parameterValues = headerComponents[1..(uniqueKeysWithValues: parameterValues)
32 |
33 | // Default according to RFC is ISO-8859-1, but probably nothing obeys that, so default
34 | // to UTF-8 instead.
35 | var encoding = String.Encoding.utf8
36 | if let charset = parameters["charset"], let parsedEncoding = parseStringEncoding(charset) {
37 | encoding = parsedEncoding
38 | }
39 |
40 | return (mimeType: headerComponents[0], encoding: encoding)
41 | } else {
42 | return (mimeType: headerComponents[0], encoding: .utf8)
43 | }
44 | }
45 |
46 | func parseStringEncoding(_ value: String) -> String.Encoding? {
47 | switch value.lowercased() {
48 | case "iso-8859-1", "latin1": return .isoLatin1
49 | case "iso-8859-2", "latin2": return .isoLatin2
50 | case "iso-2022-jp": return .iso2022JP
51 | case "shift_jis": return .shiftJIS
52 | case "us-ascii": return .ascii
53 | case "utf-8": return .utf8
54 | case "utf-16": return .utf16
55 | case "utf-32": return .utf32
56 | case "utf-32be": return .utf32BigEndian
57 | case "utf-32le": return .utf32LittleEndian
58 | case "windows-1250": return .windowsCP1250
59 | case "windows-1251": return .windowsCP1251
60 | case "windows-1252": return .windowsCP1252
61 | case "windows-1253": return .windowsCP1253
62 | case "windows-1254": return .windowsCP1254
63 | case "x-mac-roman": return .macOSRoman
64 | default:
65 | return nil
66 | }
67 | }
68 |
69 | extension HTTPURLResponse {
70 | func mimeTypeAndEncoding() -> (mimeType: String, encoding: String.Encoding) {
71 | if let contentType = allHeaderFields["Content-Type"] as? String {
72 | return parseHTTPContentType(contentType)
73 | }
74 | return (mimeType: "application/octet-stream", encoding: .utf8)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Pods/FavIcon/Sources/FavIcon/Detection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FavIcon
3 | // Copyright © 2018 Leon Breedt
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | //
17 |
18 | import Foundation
19 |
20 | private let iconSizeTypeHints: [IconSize: IconType] = [
21 | IconSize(width: 16, height: 16): .classic,
22 | IconSize(width: 32, height: 32): .appleOSXSafariTab,
23 | IconSize(width: 96, height: 96): .googleTV,
24 | IconSize(width: 192, height: 192): .googleAndroidChrome,
25 | IconSize(width: 196, height: 196): .googleAndroidChrome
26 | ]
27 |
28 | private let microsoftSizeHints: [String: IconSize] = [
29 | "msapplication-tileimage": IconSize(width: 144, height: 144),
30 | "msapplication-square70x70logo": IconSize(width: 70, height: 70),
31 | "msapplication-square150x150logo": IconSize(width: 150, height: 150),
32 | "msapplication-wide310x150logo": IconSize(width: 310, height: 150),
33 | "msapplication-square310x310logo": IconSize(width: 310, height: 310)
34 | ]
35 |
36 | func detectHTMLHeadIcons(_ document: HTMLDocument, baseURL: URL) -> [Icon] {
37 | var icons = [Icon]()
38 |
39 | for link in document.query(xpath: "/html/head/link") {
40 | guard let rel = link.attributes["rel"] else { continue }
41 | guard let href = link.attributes["href"] else { continue }
42 | guard let url = URL(string: href, relativeTo: baseURL)?.absoluteURL else { continue }
43 |
44 | switch rel.lowercased() {
45 | case "shortcut icon":
46 | icons.append(Icon(url: url.absoluteURL, type: .shortcut))
47 | case "icon":
48 | let sizes = parseHTMLIconSizes(link.attributes["sizes"])
49 | if sizes.count > 0 {
50 | for size in sizes {
51 | let type = iconSizeTypeHints[size] ?? .classic
52 | icons.append(Icon(url: url, type: type, width: size.width, height: size.height))
53 | }
54 | } else {
55 | icons.append(Icon(url: url.absoluteURL, type: .classic))
56 | }
57 | case "apple-touch-icon",
58 | "apple-touch-icon-precomposed":
59 | let sizes = parseHTMLIconSizes(link.attributes["sizes"])
60 | if sizes.count > 0 {
61 | for size in sizes {
62 | icons.append(Icon(url: url, type: .appleIOSWebClip, width: size.width, height: size.height))
63 | }
64 | } else {
65 | icons.append(Icon(url: url.absoluteURL, type: .appleIOSWebClip, width: 60, height: 60))
66 | }
67 | default:
68 | break
69 | }
70 | }
71 |
72 | for meta in document.query(xpath: "/html/head/meta") {
73 | if let name = meta.attributes["name"]?.lowercased() {
74 | guard let content = meta.attributes["content"] else { continue }
75 | guard let url = URL(string: content, relativeTo: baseURL) else { continue }
76 | guard let size = microsoftSizeHints[name] else { continue }
77 | icons.append(Icon(url: url, type: .microsoftPinnedSite, width: size.width, height: size.height))
78 | } else if let property = meta.attributes["property"]?.lowercased() {
79 | guard let content = meta.attributes["content"] else { continue }
80 | guard property == "og:image" else { continue }
81 | guard let imageURL = URL(string: content, relativeTo: baseURL) else { continue }
82 | icons.append(Icon(url: imageURL, type: .openGraphImage))
83 | }
84 | }
85 |
86 | return icons
87 | }
88 |
89 | func extractWebAppManifestURLs(_ document: HTMLDocument, baseURL: URL) -> [URL] {
90 | var urls: [URL] = []
91 | for link in document.query(xpath: "/html/head/link") {
92 | guard let rel = link.attributes["rel"]?.lowercased() else { continue }
93 | guard rel == "manifest" else { continue }
94 | guard let href = link.attributes["href"] else { continue }
95 | guard let manifestURL = URL(string: href, relativeTo: baseURL) else { continue }
96 |
97 | urls.append(manifestURL)
98 | }
99 | return urls
100 | }
101 |
102 | func detectWebAppManifestIcons(_ json: String, baseURL: URL) -> [Icon] {
103 | var icons: [Icon] = []
104 |
105 | guard let data = json.data(using: .utf8) else { return icons }
106 | guard let object = try? JSONSerialization.jsonObject(with: data, options: []) else {
107 | return icons
108 | }
109 | guard let manifest = object as? [String: Any] else { return icons }
110 | guard let manifestIcons = manifest["icons"] as? [[String: Any]] else { return icons }
111 |
112 | for icon in manifestIcons {
113 | guard let type = icon["type"] as? String else { continue }
114 | guard type.lowercased() == "image/png" else { continue }
115 | guard let src = icon["src"] as? String else { continue }
116 | guard let sizeValues = icon["sizes"] as? String else { continue }
117 | guard let url = URL(string: src, relativeTo: baseURL)?.absoluteURL else { continue }
118 |
119 | let sizes = parseHTMLIconSizes(sizeValues)
120 | if sizes.count > 0 {
121 | for size in sizes {
122 | icons.append(Icon(url: url, type: .webAppManifest, width: size.width, height: size.height))
123 | }
124 | } else {
125 | icons.append(Icon(url: url, type: .webAppManifest))
126 | }
127 | }
128 |
129 | return icons
130 | }
131 |
132 | func extractBrowserConfigURL(_ document: HTMLDocument, baseURL: URL) -> (url: URL?, disabled: Bool) {
133 | for meta in document.query(xpath: "/html/head/meta") {
134 | guard let name = meta.attributes["name"]?.lowercased() else { continue }
135 | guard name == "msapplication-config" else { continue }
136 | guard let content = meta.attributes["content"] else { continue }
137 | if content.lowercased() == "none" {
138 | // Explicitly asked us not to download the file.
139 | return (url: nil, disabled: true)
140 | } else {
141 | return (url: URL(string: content, relativeTo: baseURL)?.absoluteURL, disabled: false)
142 | }
143 | }
144 | return (url: nil, disabled: false)
145 | }
146 |
147 | func detectBrowserConfigXMLIcons(_ document: XMLDocument, baseURL: URL) -> [Icon] {
148 | var icons: [Icon] = []
149 |
150 | for tile in document.query(xpath: "/browserconfig/msapplication/tile/*") {
151 | guard let src = tile.attributes["src"] else { continue }
152 | guard let url = URL(string: src, relativeTo: baseURL)?.absoluteURL else { continue }
153 |
154 | switch tile.name.lowercased() {
155 | case "tileimage":
156 | icons.append(Icon(url: url, type: .microsoftPinnedSite, width: 144, height: 144))
157 | case "square70x70logo":
158 | icons.append(Icon(url: url, type: .microsoftPinnedSite, width: 70, height: 70))
159 | case "square150x150logo":
160 | icons.append(Icon(url: url, type: .microsoftPinnedSite, width: 150, height: 150))
161 | case "wide310x150logo":
162 | icons.append(Icon(url: url, type: .microsoftPinnedSite, width: 310, height: 150))
163 | case "square310x310logo":
164 | icons.append(Icon(url: url, type: .microsoftPinnedSite, width: 310, height: 310))
165 | default:
166 | break
167 | }
168 | }
169 |
170 | return icons
171 | }
172 |
173 | private func parseHTMLIconSizes(_ string: String?) -> [IconSize] {
174 | var sizes: [IconSize] = []
175 | if let string = string?.lowercased(), string != "any" {
176 | for size in string.components(separatedBy: .whitespaces) {
177 | let parts = size.components(separatedBy: "x")
178 | if parts.count != 2 { continue }
179 | if let width = Int(parts[0]), let height = Int(parts[1]) {
180 | sizes.append(IconSize(width: width, height: height))
181 | }
182 | }
183 | }
184 | return sizes
185 | }
186 |
187 | extension IconSize: Hashable {
188 | var hashValue: Int {
189 | return width.hashValue ^ height.hashValue
190 | }
191 | }
192 |
193 | private func == (lhs: IconSize, rhs: IconSize) -> Bool {
194 | return lhs.width == rhs.width && lhs.height == rhs.height
195 | }
196 |
197 | private struct IconSize {
198 | let width: Int
199 | let height: Int
200 | }
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/Pods/FavIcon/Sources/FavIcon/Download.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FavIcon
3 | // Copyright © 2018 Leon Breedt
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | //
17 |
18 | import Foundation
19 |
20 | enum DownloadResult {
21 | case text(value: String, mimeType: String, actualURL: URL)
22 | case binary(data: Data, mimeType: String, actualURL: URL)
23 | case exists
24 | case error(Error)
25 | }
26 |
27 | enum DownloadError: Error {
28 | case invalidResponse
29 | case emptyResponse
30 | case invalidTextResponse
31 | case notFound
32 | case serverError(code: Int)
33 | }
34 |
35 | private let downloadSession = URLSession(configuration: .ephemeral)
36 |
37 | func downloadURLs(_ urls: [URL], method: String = "GET", completion: @escaping ([DownloadResult]) -> Void) {
38 | let dispatchGroup = DispatchGroup()
39 |
40 | var results = [(index: Int, result: DownloadResult)]()
41 | let addResult: (Int, DownloadResult) -> Void = { (index: Int, result: DownloadResult) in
42 | DispatchQueue.main.async {
43 | results.append((index: index, result: result))
44 | }
45 | }
46 |
47 | for (index, url) in urls.enumerated() {
48 | dispatchGroup.enter()
49 |
50 | var request = URLRequest(url: url)
51 | request.httpMethod = method
52 | let task = downloadSession.dataTask(with: request) { data, response, error in
53 | defer {
54 | dispatchGroup.leave()
55 | }
56 |
57 | guard error == nil else {
58 | addResult(index, .error(error!))
59 | return
60 | }
61 |
62 | guard let response = response else {
63 | addResult(index, .error(DownloadError.invalidResponse))
64 | return
65 | }
66 |
67 | if let httpResponse = response as? HTTPURLResponse {
68 | if httpResponse.statusCode == 404 {
69 | addResult(index, .error(DownloadError.notFound))
70 | return
71 | }
72 |
73 | if httpResponse.statusCode < 200 || httpResponse.statusCode > 299 {
74 | addResult(index, .error(DownloadError.serverError(code: httpResponse.statusCode)))
75 | return
76 | }
77 |
78 | if method.lowercased() == "head" {
79 | addResult(index, .exists)
80 | return
81 | }
82 | }
83 |
84 | if let data = data {
85 | let mimeType = response.mimeType ?? "application/octet-stream"
86 | let encoding: String.Encoding = response.textEncodingName != nil
87 | ? parseStringEncoding(response.textEncodingName!) ?? .utf8
88 | : .utf8
89 | if mimeType.starts(with: "text/") || mimeType == "application/json" {
90 | guard let text = String(data: data, encoding: encoding) else {
91 | addResult(index, .error(DownloadError.invalidTextResponse))
92 | return
93 | }
94 | addResult(index, .text(value: text, mimeType: mimeType, actualURL: response.url!))
95 | return
96 | } else {
97 | addResult(index, .binary(data: data, mimeType: mimeType, actualURL: response.url!))
98 | return
99 | }
100 | } else {
101 | addResult(index, .error(DownloadError.emptyResponse))
102 | return
103 | }
104 | }
105 |
106 | task.resume()
107 | }
108 |
109 | dispatchGroup.notify(queue: .main) {
110 | let sortedResults =
111 | results
112 | .sorted(by: { $0.index < $1.index })
113 | .map { $0.result }
114 | completion(sortedResults)
115 | }
116 | }
117 |
118 | func downloadURL(_ url: URL, method: String = "GET", completion: @escaping (DownloadResult) -> Void) {
119 | downloadURLs([url], method: method) { results in
120 | completion(results.first!)
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Pods/FavIcon/Sources/FavIcon/HTML.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FavIcon
3 | // Copyright © 2018 Leon Breedt
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | //
17 |
18 | import Foundation
19 | import libxmlFavicon
20 |
21 | final class HTMLDocument {
22 | fileprivate var _document: htmlDocPtr!
23 | private var _children: [HTMLElement]?
24 |
25 | convenience init(string: String) {
26 | self.init(data: string.data(using: .utf8)!)
27 | }
28 |
29 | init(data: Data) {
30 | ensureLibXMLErrorHandlingSuppressed()
31 |
32 | guard data.count > 0 else { return }
33 |
34 | _document = data.withUnsafeBytes { (p: UnsafePointer) -> htmlDocPtr? in
35 | return htmlReadMemory(p, Int32(data.count), nil, nil, 0)
36 | }
37 | }
38 |
39 | var children: [HTMLElement] {
40 | guard let document = _document else {
41 | return []
42 | }
43 | if let children = _children {
44 | return children
45 | }
46 | var newChildren = [HTMLElement]()
47 |
48 | var currentChild = document.pointee.children
49 | while currentChild != nil {
50 | if currentChild?.pointee.type == XML_ELEMENT_NODE {
51 | newChildren.append(HTMLElement(document: self, node: currentChild!))
52 | }
53 | currentChild = currentChild?.pointee.next
54 | }
55 |
56 | _children = newChildren
57 | return newChildren
58 | }
59 |
60 | func query(xpath: String) -> [HTMLElement] {
61 | var results = [HTMLElement]()
62 |
63 | guard let document = _document else { return results }
64 | guard let context = xmlXPathNewContext(document) else {
65 | return results
66 | }
67 | defer { xmlXPathFreeContext(context) }
68 |
69 | var object: xmlXPathObjectPtr? = nil
70 | xpath.withCString { str in
71 | str.withMemoryRebound(to: UInt8.self, capacity: 1) { strp in
72 | object = xmlXPathEvalExpression(strp, context)
73 | }
74 | }
75 | guard object != nil else {
76 | return results
77 | }
78 | defer { xmlXPathFreeObject(object) }
79 |
80 | let nodeCount = object!.pointee.nodesetval.pointee.nodeNr
81 | for i in 0.. [HTMLElement] {
177 | var results = [HTMLElement]()
178 |
179 | guard let document = _document else { return results }
180 | guard let context = xmlXPathNewContext(document._document) else {
181 | return results
182 | }
183 | defer { xmlXPathFreeContext(context) }
184 |
185 | var object: xmlXPathObjectPtr? = nil
186 | xpath.withCString { str in
187 | str.withMemoryRebound(to: UInt8.self, capacity: 1) { strp in
188 | object = xmlXPathEvalExpression(strp, context)
189 | }
190 | }
191 | guard object != nil else {
192 | return results
193 | }
194 | defer { xmlXPathFreeObject(object) }
195 |
196 | let nodeCount = object!.pointee.nodesetval.pointee.nodeNr
197 | for i in 0.. 0 else { return }
35 |
36 | _document = data.withUnsafeBytes { (p: UnsafePointer) -> xmlDocPtr? in
37 | return xmlReadMemory(p, Int32(data.count), nil, nil, 0)
38 | }
39 | }
40 |
41 | var children: [XMLElement] {
42 | guard let document = _document else {
43 | return []
44 | }
45 | if let children = _children {
46 | return children
47 | }
48 | var newChildren = [XMLElement]()
49 |
50 | var currentChild = document.pointee.children
51 | while currentChild != nil {
52 | if currentChild?.pointee.type == XML_ELEMENT_NODE {
53 | newChildren.append(XMLElement(document: self, node: currentChild!))
54 | }
55 | currentChild = currentChild?.pointee.next
56 | }
57 |
58 | _children = newChildren
59 | return newChildren
60 | }
61 |
62 | func query(xpath: String) -> [XMLElement] {
63 | var results = [XMLElement]()
64 |
65 | guard let document = _document else { return results }
66 | guard let context = xmlXPathNewContext(document) else {
67 | return results
68 | }
69 | defer { xmlXPathFreeContext(context) }
70 |
71 | var object: xmlXPathObjectPtr? = nil
72 | xpath.withCString { str in
73 | str.withMemoryRebound(to: UInt8.self, capacity: 1) { strp in
74 | object = xmlXPathEvalExpression(strp, context)
75 | }
76 | }
77 | guard object != nil else {
78 | return results
79 | }
80 | defer { xmlXPathFreeObject(object) }
81 |
82 | let nodeCount = object!.pointee.nodesetval.pointee.nodeNr
83 | for i in 0.. [XMLElement] {
178 | var results = [XMLElement]()
179 |
180 | guard let document = _document else { return results }
181 | guard let context = xmlXPathNewContext(document._document) else {
182 | return results
183 | }
184 | defer { xmlXPathFreeContext(context) }
185 |
186 | var object: xmlXPathObjectPtr? = nil
187 | xpath.withCString { str in
188 | str.withMemoryRebound(to: UInt8.self, capacity: 1) { strp in
189 | object = xmlXPathEvalExpression(strp, context)
190 | }
191 | }
192 | guard object != nil else {
193 | return results
194 | }
195 | defer { xmlXPathFreeObject(object) }
196 |
197 | let nodeCount = object!.pointee.nodesetval.pointee.nodeNr
198 | for i in 0..
2 | #import
3 | #import
4 | #import
--------------------------------------------------------------------------------
/Pods/FavIcon/Sources/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | module libxmlFavicon [system] {
2 | link "xml2"
3 | umbrella header "libxml2-favicon.h"
4 | export *
5 | module * { export * }
6 | }
--------------------------------------------------------------------------------
/Pods/Local Podspecs/SQLite.swift.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SQLite.swift",
3 | "version": "0.11.6",
4 | "summary": "A type-safe, Swift-language layer over SQLite3 for iOS and OS X.",
5 | "description": "SQLite.swift provides compile-time confidence in SQL statement syntax and\nintent.",
6 | "homepage": "https://github.com/stephencelis/SQLite.swift",
7 | "license": "MIT",
8 | "authors": {
9 | "Stephen Celis": "stephen@stephencelis.com"
10 | },
11 | "source": {
12 | "git": "https://github.com/stephencelis/SQLite.swift.git",
13 | "tag": "0.11.6"
14 | },
15 | "social_media_url": "https://twitter.com/stephencelis",
16 | "module_name": "SQLite",
17 | "platforms": {
18 | "ios": "8.0",
19 | "tvos": "9.1",
20 | "osx": "10.10",
21 | "watchos": "2.2"
22 | },
23 | "default_subspecs": "standard",
24 | "pod_target_xcconfig": {
25 | "SWIFT_VERSION": "4.2"
26 | },
27 | "subspecs": [
28 | {
29 | "name": "standard",
30 | "source_files": "Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}",
31 | "exclude_files": "Sources/**/Cipher.swift",
32 | "private_header_files": "Sources/SQLiteObjc/*.h",
33 | "libraries": "sqlite3",
34 | "testspecs": [
35 | {
36 | "name": "tests",
37 | "test_type": "unit",
38 | "resources": "Tests/SQLiteTests/fixtures/*",
39 | "source_files": "Tests/SQLiteTests/*.swift"
40 | }
41 | ]
42 | },
43 | {
44 | "name": "standalone",
45 | "source_files": "Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}",
46 | "exclude_files": "Sources/**/Cipher.swift",
47 | "private_header_files": "Sources/SQLiteObjc/*.h",
48 | "xcconfig": {
49 | "OTHER_SWIFT_FLAGS": "$(inherited) -DSQLITE_SWIFT_STANDALONE"
50 | },
51 | "dependencies": {
52 | "sqlite3": [
53 |
54 | ]
55 | },
56 | "testspecs": [
57 | {
58 | "name": "tests",
59 | "test_type": "unit",
60 | "resources": "Tests/SQLiteTests/fixtures/*",
61 | "source_files": "Tests/SQLiteTests/*.swift"
62 | }
63 | ]
64 | },
65 | {
66 | "name": "SQLCipher",
67 | "source_files": "Sources/{SQLite,SQLiteObjc}/**/*.{c,h,m,swift}",
68 | "private_header_files": "Sources/SQLiteObjc/*.h",
69 | "xcconfig": {
70 | "OTHER_SWIFT_FLAGS": "$(inherited) -DSQLITE_SWIFT_SQLCIPHER",
71 | "GCC_PREPROCESSOR_DEFINITIONS": "$(inherited) SQLITE_HAS_CODEC=1"
72 | },
73 | "dependencies": {
74 | "SQLCipher": [
75 | ">= 3.4.0"
76 | ]
77 | },
78 | "testspecs": [
79 | {
80 | "name": "tests",
81 | "test_type": "unit",
82 | "resources": "Tests/SQLiteTests/fixtures/*",
83 | "source_files": "Tests/SQLiteTests/*.swift"
84 | }
85 | ]
86 | }
87 | ]
88 | }
89 |
--------------------------------------------------------------------------------
/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FavIcon (3.0.6)
3 | - SQLCipher (4.1.0):
4 | - SQLCipher/standard (= 4.1.0)
5 | - SQLCipher/common (4.1.0)
6 | - SQLCipher/standard (4.1.0):
7 | - SQLCipher/common
8 | - SQLite.swift/SQLCipher (0.11.6):
9 | - SQLCipher (>= 3.4.0)
10 |
11 | DEPENDENCIES:
12 | - FavIcon (~> 3.0.0)
13 | - SQLite.swift/SQLCipher (from `https://github.com/stephencelis/SQLite.swift.git`, commit `1a908a7da11852f252e7c6b6366a4d9f8a7d5272`)
14 |
15 | SPEC REPOS:
16 | https://github.com/cocoapods/specs.git:
17 | - FavIcon
18 | - SQLCipher
19 |
20 | EXTERNAL SOURCES:
21 | SQLite.swift:
22 | :commit: 1a908a7da11852f252e7c6b6366a4d9f8a7d5272
23 | :git: https://github.com/stephencelis/SQLite.swift.git
24 |
25 | CHECKOUT OPTIONS:
26 | SQLite.swift:
27 | :commit: 1a908a7da11852f252e7c6b6366a4d9f8a7d5272
28 | :git: https://github.com/stephencelis/SQLite.swift.git
29 |
30 | SPEC CHECKSUMS:
31 | FavIcon: e07ba9dd3cac1f76b81ccaa08fc2b41baa000b07
32 | SQLCipher: efbdb52cdbe340bcd892b1b14297df4e07241b7f
33 | SQLite.swift: 46d890be8601964454bd3392527f863d1b802d45
34 |
35 | PODFILE CHECKSUM: 68c1650a5fda33bfed5ea7f6384ac0c95d77e55c
36 |
37 | COCOAPODS: 1.6.1
38 |
--------------------------------------------------------------------------------
/Pods/SQLCipher/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008, ZETETIC LLC
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of the ZETETIC LLC nor the
12 | names of its contributors may be used to endorse or promote products
13 | derived from this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/LICENSE.txt:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Copyright (c) 2014-2015 Stephen Celis ()
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Core/Blob.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | public struct Blob {
26 |
27 | public let bytes: [UInt8]
28 |
29 | public init(bytes: [UInt8]) {
30 | self.bytes = bytes
31 | }
32 |
33 | public init(bytes: UnsafeRawPointer, length: Int) {
34 | let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length)
35 | self.init(bytes: [UInt8](i8bufptr))
36 | }
37 |
38 | public func toHex() -> String {
39 | return bytes.map {
40 | ($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false)
41 | }.joined(separator: "")
42 | }
43 |
44 | }
45 |
46 | extension Blob : CustomStringConvertible {
47 |
48 | public var description: String {
49 | return "x'\(toHex())'"
50 | }
51 |
52 | }
53 |
54 | extension Blob : Equatable {
55 |
56 | }
57 |
58 | public func ==(lhs: Blob, rhs: Blob) -> Bool {
59 | return lhs.bytes == rhs.bytes
60 | }
61 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Core/Errors.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum QueryError: Error, CustomStringConvertible {
4 | case noSuchTable(name: String)
5 | case noSuchColumn(name: String, columns: [String])
6 | case ambiguousColumn(name: String, similar: [String])
7 | case unexpectedNullValue(name: String)
8 |
9 | public var description: String {
10 | switch self {
11 | case .noSuchTable(let name):
12 | return "No such table: \(name)"
13 | case .noSuchColumn(let name, let columns):
14 | return "No such column `\(name)` in columns \(columns)"
15 | case .ambiguousColumn(let name, let similar):
16 | return "Ambiguous column `\(name)` (please disambiguate: \(similar))"
17 | case .unexpectedNullValue(let name):
18 | return "Unexpected null value for column `\(name)`"
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Core/Value.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// - Warning: `Binding` is a protocol that SQLite.swift uses internally to
26 | /// directly map SQLite types to Swift types.
27 | ///
28 | /// Do not conform custom types to the Binding protocol. See the `Value`
29 | /// protocol, instead.
30 | public protocol Binding {}
31 |
32 | public protocol Number : Binding {}
33 |
34 | public protocol Value : Expressible { // extensions cannot have inheritance clauses
35 |
36 | associatedtype ValueType = Self
37 |
38 | associatedtype Datatype : Binding
39 |
40 | static var declaredDatatype: String { get }
41 |
42 | static func fromDatatypeValue(_ datatypeValue: Datatype) -> ValueType
43 |
44 | var datatypeValue: Datatype { get }
45 |
46 | }
47 |
48 | extension Double : Number, Value {
49 |
50 | public static let declaredDatatype = "REAL"
51 |
52 | public static func fromDatatypeValue(_ datatypeValue: Double) -> Double {
53 | return datatypeValue
54 | }
55 |
56 | public var datatypeValue: Double {
57 | return self
58 | }
59 |
60 | }
61 |
62 | extension Int64 : Number, Value {
63 |
64 | public static let declaredDatatype = "INTEGER"
65 |
66 | public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int64 {
67 | return datatypeValue
68 | }
69 |
70 | public var datatypeValue: Int64 {
71 | return self
72 | }
73 |
74 | }
75 |
76 | extension String : Binding, Value {
77 |
78 | public static let declaredDatatype = "TEXT"
79 |
80 | public static func fromDatatypeValue(_ datatypeValue: String) -> String {
81 | return datatypeValue
82 | }
83 |
84 | public var datatypeValue: String {
85 | return self
86 | }
87 |
88 | }
89 |
90 | extension Blob : Binding, Value {
91 |
92 | public static let declaredDatatype = "BLOB"
93 |
94 | public static func fromDatatypeValue(_ datatypeValue: Blob) -> Blob {
95 | return datatypeValue
96 | }
97 |
98 | public var datatypeValue: Blob {
99 | return self
100 | }
101 |
102 | }
103 |
104 | // MARK: -
105 |
106 | extension Bool : Binding, Value {
107 |
108 | public static var declaredDatatype = Int64.declaredDatatype
109 |
110 | public static func fromDatatypeValue(_ datatypeValue: Int64) -> Bool {
111 | return datatypeValue != 0
112 | }
113 |
114 | public var datatypeValue: Int64 {
115 | return self ? 1 : 0
116 | }
117 |
118 | }
119 |
120 | extension Int : Number, Value {
121 |
122 | public static var declaredDatatype = Int64.declaredDatatype
123 |
124 | public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int {
125 | return Int(datatypeValue)
126 | }
127 |
128 | public var datatypeValue: Int64 {
129 | return Int64(self)
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Extensions/Cipher.swift:
--------------------------------------------------------------------------------
1 | #if SQLITE_SWIFT_SQLCIPHER
2 | import SQLCipher
3 |
4 |
5 | /// Extension methods for [SQLCipher](https://www.zetetic.net/sqlcipher/).
6 | /// @see [sqlcipher api](https://www.zetetic.net/sqlcipher/sqlcipher-api/)
7 | extension Connection {
8 |
9 | /// - Returns: the SQLCipher version
10 | public var cipherVersion: String? {
11 | return (try? scalar("PRAGMA cipher_version")) as? String
12 | }
13 |
14 | /// Specify the key for an encrypted database. This routine should be
15 | /// called right after sqlite3_open().
16 | ///
17 | /// @param key The key to use.The key itself can be a passphrase, which is converted to a key
18 | /// using [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) key derivation. The result
19 | /// is used as the encryption key for the database.
20 | ///
21 | /// Alternatively, it is possible to specify an exact byte sequence using a blob literal.
22 | /// With this method, it is the calling application's responsibility to ensure that the data
23 | /// provided is a 64 character hex string, which will be converted directly to 32 bytes (256 bits)
24 | /// of key data.
25 | /// e.g. x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'
26 | /// @param db name of the database, defaults to 'main'
27 | public func key(_ key: String, db: String = "main") throws {
28 | try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count)
29 | }
30 |
31 | public func key(_ key: Blob, db: String = "main") throws {
32 | try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
33 | }
34 |
35 |
36 | /// Change the key on an open database. If the current database is not encrypted, this routine
37 | /// will encrypt it.
38 | /// To change the key on an existing encrypted database, it must first be unlocked with the
39 | /// current encryption key. Once the database is readable and writeable, rekey can be used
40 | /// to re-encrypt every page in the database with a new key.
41 | public func rekey(_ key: String, db: String = "main") throws {
42 | try _rekey_v2(db: db, keyPointer: key, keySize: key.utf8.count)
43 | }
44 |
45 | public func rekey(_ key: Blob, db: String = "main") throws {
46 | try _rekey_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
47 | }
48 |
49 | // MARK: - private
50 | private func _key_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws {
51 | try check(sqlite3_key_v2(handle, db, keyPointer, Int32(keySize)))
52 | try cipher_key_check()
53 | }
54 |
55 | private func _rekey_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws {
56 | try check(sqlite3_rekey_v2(handle, db, keyPointer, Int32(keySize)))
57 | }
58 |
59 | // When opening an existing database, sqlite3_key_v2 will not immediately throw an error if
60 | // the key provided is incorrect. To test that the database can be successfully opened with the
61 | // provided key, it is necessary to perform some operation on the database (i.e. read from it).
62 | private func cipher_key_check() throws {
63 | try scalar("SELECT count(*) FROM sqlite_master;")
64 | }
65 | }
66 | #endif
67 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Extensions/FTS5.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | extension Module {
26 | public static func FTS5(_ config: FTS5Config) -> Module {
27 | return Module(name: "fts5", arguments: config.arguments())
28 | }
29 | }
30 |
31 | /// Configuration for the [FTS5](https://www.sqlite.org/fts5.html) extension.
32 | ///
33 | /// **Note:** this is currently only applicable when using SQLite.swift together with a FTS5-enabled version
34 | /// of SQLite.
35 | open class FTS5Config : FTSConfig {
36 | public enum Detail : CustomStringConvertible {
37 | /// store rowid, column number, term offset
38 | case full
39 | /// store rowid, column number
40 | case column
41 | /// store rowid
42 | case none
43 |
44 | public var description: String {
45 | switch self {
46 | case .full: return "full"
47 | case .column: return "column"
48 | case .none: return "none"
49 | }
50 | }
51 | }
52 |
53 | var detail: Detail?
54 | var contentRowId: Expressible?
55 | var columnSize: Int?
56 |
57 | override public init() {
58 | }
59 |
60 | /// [External Content Tables](https://www.sqlite.org/fts5.html#section_4_4_2)
61 | open func contentRowId(_ column: Expressible) -> Self {
62 | self.contentRowId = column
63 | return self
64 | }
65 |
66 | /// [The Columnsize Option](https://www.sqlite.org/fts5.html#section_4_5)
67 | open func columnSize(_ size: Int) -> Self {
68 | self.columnSize = size
69 | return self
70 | }
71 |
72 | /// [The Detail Option](https://www.sqlite.org/fts5.html#section_4_6)
73 | open func detail(_ detail: Detail) -> Self {
74 | self.detail = detail
75 | return self
76 | }
77 |
78 | override func options() -> Options {
79 | var options = super.options()
80 | options.append("content_rowid", value: contentRowId)
81 | if let columnSize = columnSize {
82 | options.append("columnsize", value: Expression(value: columnSize))
83 | }
84 | options.append("detail", value: detail)
85 | return options
86 | }
87 |
88 | override func formatColumnDefinitions() -> [Expressible] {
89 | return columnDefinitions.map { definition in
90 | if definition.options.contains(.unindexed) {
91 | return " ".join([definition.0, Expression(literal: "UNINDEXED")])
92 | } else {
93 | return definition.0
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Extensions/RTree.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | extension Module {
26 |
27 | public static func RTree(_ primaryKey: Expression, _ pairs: (Expression, Expression)...) -> Module where T.Datatype == Int64, U.Datatype == Double {
28 | var arguments: [Expressible] = [primaryKey]
29 |
30 | for pair in pairs {
31 | arguments.append(contentsOf: [pair.0, pair.1] as [Expressible])
32 | }
33 |
34 | return Module(name: "rtree", arguments: arguments)
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Foundation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension Data : Value {
28 |
29 | public static var declaredDatatype: String {
30 | return Blob.declaredDatatype
31 | }
32 |
33 | public static func fromDatatypeValue(_ dataValue: Blob) -> Data {
34 | return Data(dataValue.bytes)
35 | }
36 |
37 | public var datatypeValue: Blob {
38 | return withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Blob in
39 | return Blob(bytes: pointer.baseAddress!, length: count)
40 | }
41 | }
42 |
43 | }
44 |
45 | extension Date : Value {
46 |
47 | public static var declaredDatatype: String {
48 | return String.declaredDatatype
49 | }
50 |
51 | public static func fromDatatypeValue(_ stringValue: String) -> Date {
52 | return dateFormatter.date(from: stringValue)!
53 | }
54 |
55 | public var datatypeValue: String {
56 | return dateFormatter.string(from: self)
57 | }
58 |
59 | }
60 |
61 | /// A global date formatter used to serialize and deserialize `NSDate` objects.
62 | /// If multiple date formats are used in an application’s database(s), use a
63 | /// custom `Value` type per additional format.
64 | public var dateFormatter: DateFormatter = {
65 | let formatter = DateFormatter()
66 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
67 | formatter.locale = Locale(identifier: "en_US_POSIX")
68 | formatter.timeZone = TimeZone(secondsFromGMT: 0)
69 | return formatter
70 | }()
71 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Helpers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #if SQLITE_SWIFT_STANDALONE
26 | import sqlite3
27 | #elseif SQLITE_SWIFT_SQLCIPHER
28 | import SQLCipher
29 | #elseif os(Linux)
30 | import CSQLite
31 | #else
32 | import SQLite3
33 | #endif
34 |
35 | public typealias Star = (Expression?, Expression?) -> Expression
36 |
37 | public func *(_: Expression?, _: Expression?) -> Expression {
38 | return Expression(literal: "*")
39 | }
40 |
41 | public protocol _OptionalType {
42 |
43 | associatedtype WrappedType
44 |
45 | }
46 |
47 | extension Optional : _OptionalType {
48 |
49 | public typealias WrappedType = Wrapped
50 |
51 | }
52 |
53 | // let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self)
54 | let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
55 |
56 | extension String {
57 |
58 | func quote(_ mark: Character = "\"") -> String {
59 | let escaped = reduce("") { string, character in
60 | string + (character == mark ? "\(mark)\(mark)" : "\(character)")
61 | }
62 | return "\(mark)\(escaped)\(mark)"
63 | }
64 |
65 | func join(_ expressions: [Expressible]) -> Expressible {
66 | var (template, bindings) = ([String](), [Binding?]())
67 | for expressible in expressions {
68 | let expression = expressible.expression
69 | template.append(expression.template)
70 | bindings.append(contentsOf: expression.bindings)
71 | }
72 | return Expression(template.joined(separator: self), bindings)
73 | }
74 |
75 | func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression {
76 | let expression = Expression(" \(self) ".join([lhs, rhs]).expression)
77 | guard wrap else {
78 | return expression
79 | }
80 | return "".wrap(expression)
81 | }
82 |
83 | func prefix(_ expressions: Expressible) -> Expressible {
84 | return "\(self) ".wrap(expressions) as Expression
85 | }
86 |
87 | func prefix(_ expressions: [Expressible]) -> Expressible {
88 | return "\(self) ".wrap(expressions) as Expression
89 | }
90 |
91 | func wrap(_ expression: Expressible) -> Expression {
92 | return Expression("\(self)(\(expression.expression.template))", expression.expression.bindings)
93 | }
94 |
95 | func wrap(_ expressions: [Expressible]) -> Expression {
96 | return wrap(", ".join(expressions))
97 | }
98 |
99 | }
100 |
101 | func transcode(_ literal: Binding?) -> String {
102 | guard let literal = literal else { return "NULL" }
103 |
104 | switch literal {
105 | case let blob as Blob:
106 | return blob.description
107 | case let string as String:
108 | return string.quote("'")
109 | case let binding:
110 | return "\(binding)"
111 | }
112 | }
113 |
114 | func value(_ v: Binding) -> A {
115 | return A.fromDatatypeValue(v as! A.Datatype) as! A
116 | }
117 |
118 | func value(_ v: Binding?) -> A {
119 | return value(v!)
120 | }
121 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/SQLite.h:
--------------------------------------------------------------------------------
1 | @import Foundation;
2 |
3 | FOUNDATION_EXPORT double SQLiteVersionNumber;
4 | FOUNDATION_EXPORT const unsigned char SQLiteVersionString[];
5 |
6 | #import
7 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Typed/AggregateFunctions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | private enum Function: String {
26 | case count
27 | case max
28 | case min
29 | case avg
30 | case sum
31 | case total
32 |
33 | func wrap(_ expression: Expressible) -> Expression {
34 | return self.rawValue.wrap(expression)
35 | }
36 | }
37 |
38 | extension ExpressionType where UnderlyingType : Value {
39 |
40 | /// Builds a copy of the expression prefixed with the `DISTINCT` keyword.
41 | ///
42 | /// let name = Expression("name")
43 | /// name.distinct
44 | /// // DISTINCT "name"
45 | ///
46 | /// - Returns: A copy of the expression prefixed with the `DISTINCT`
47 | /// keyword.
48 | public var distinct: Expression {
49 | return Expression("DISTINCT \(template)", bindings)
50 | }
51 |
52 | /// Builds a copy of the expression wrapped with the `count` aggregate
53 | /// function.
54 | ///
55 | /// let name = Expression("name")
56 | /// name.count
57 | /// // count("name")
58 | /// name.distinct.count
59 | /// // count(DISTINCT "name")
60 | ///
61 | /// - Returns: A copy of the expression wrapped with the `count` aggregate
62 | /// function.
63 | public var count: Expression {
64 | return Function.count.wrap(self)
65 | }
66 |
67 | }
68 |
69 | extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value {
70 |
71 | /// Builds a copy of the expression prefixed with the `DISTINCT` keyword.
72 | ///
73 | /// let name = Expression("name")
74 | /// name.distinct
75 | /// // DISTINCT "name"
76 | ///
77 | /// - Returns: A copy of the expression prefixed with the `DISTINCT`
78 | /// keyword.
79 | public var distinct: Expression {
80 | return Expression("DISTINCT \(template)", bindings)
81 | }
82 |
83 | /// Builds a copy of the expression wrapped with the `count` aggregate
84 | /// function.
85 | ///
86 | /// let name = Expression("name")
87 | /// name.count
88 | /// // count("name")
89 | /// name.distinct.count
90 | /// // count(DISTINCT "name")
91 | ///
92 | /// - Returns: A copy of the expression wrapped with the `count` aggregate
93 | /// function.
94 | public var count: Expression {
95 | return Function.count.wrap(self)
96 | }
97 |
98 | }
99 |
100 | extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Comparable {
101 |
102 | /// Builds a copy of the expression wrapped with the `max` aggregate
103 | /// function.
104 | ///
105 | /// let age = Expression("age")
106 | /// age.max
107 | /// // max("age")
108 | ///
109 | /// - Returns: A copy of the expression wrapped with the `max` aggregate
110 | /// function.
111 | public var max: Expression {
112 | return Function.max.wrap(self)
113 | }
114 |
115 | /// Builds a copy of the expression wrapped with the `min` aggregate
116 | /// function.
117 | ///
118 | /// let age = Expression("age")
119 | /// age.min
120 | /// // min("age")
121 | ///
122 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
123 | /// function.
124 | public var min: Expression {
125 | return Function.min.wrap(self)
126 | }
127 |
128 | }
129 |
130 | extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Comparable {
131 |
132 | /// Builds a copy of the expression wrapped with the `max` aggregate
133 | /// function.
134 | ///
135 | /// let age = Expression("age")
136 | /// age.max
137 | /// // max("age")
138 | ///
139 | /// - Returns: A copy of the expression wrapped with the `max` aggregate
140 | /// function.
141 | public var max: Expression {
142 | return Function.max.wrap(self)
143 | }
144 |
145 | /// Builds a copy of the expression wrapped with the `min` aggregate
146 | /// function.
147 | ///
148 | /// let age = Expression("age")
149 | /// age.min
150 | /// // min("age")
151 | ///
152 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
153 | /// function.
154 | public var min: Expression {
155 | return Function.min.wrap(self)
156 | }
157 |
158 | }
159 |
160 | extension ExpressionType where UnderlyingType : Value, UnderlyingType.Datatype : Number {
161 |
162 | /// Builds a copy of the expression wrapped with the `avg` aggregate
163 | /// function.
164 | ///
165 | /// let salary = Expression("salary")
166 | /// salary.average
167 | /// // avg("salary")
168 | ///
169 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
170 | /// function.
171 | public var average: Expression {
172 | return Function.avg.wrap(self)
173 | }
174 |
175 | /// Builds a copy of the expression wrapped with the `sum` aggregate
176 | /// function.
177 | ///
178 | /// let salary = Expression("salary")
179 | /// salary.sum
180 | /// // sum("salary")
181 | ///
182 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
183 | /// function.
184 | public var sum: Expression {
185 | return Function.sum.wrap(self)
186 | }
187 |
188 | /// Builds a copy of the expression wrapped with the `total` aggregate
189 | /// function.
190 | ///
191 | /// let salary = Expression("salary")
192 | /// salary.total
193 | /// // total("salary")
194 | ///
195 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
196 | /// function.
197 | public var total: Expression {
198 | return Function.total.wrap(self)
199 | }
200 |
201 | }
202 |
203 | extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value, UnderlyingType.WrappedType.Datatype : Number {
204 |
205 | /// Builds a copy of the expression wrapped with the `avg` aggregate
206 | /// function.
207 | ///
208 | /// let salary = Expression("salary")
209 | /// salary.average
210 | /// // avg("salary")
211 | ///
212 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
213 | /// function.
214 | public var average: Expression {
215 | return Function.avg.wrap(self)
216 | }
217 |
218 | /// Builds a copy of the expression wrapped with the `sum` aggregate
219 | /// function.
220 | ///
221 | /// let salary = Expression("salary")
222 | /// salary.sum
223 | /// // sum("salary")
224 | ///
225 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
226 | /// function.
227 | public var sum: Expression {
228 | return Function.sum.wrap(self)
229 | }
230 |
231 | /// Builds a copy of the expression wrapped with the `total` aggregate
232 | /// function.
233 | ///
234 | /// let salary = Expression("salary")
235 | /// salary.total
236 | /// // total("salary")
237 | ///
238 | /// - Returns: A copy of the expression wrapped with the `min` aggregate
239 | /// function.
240 | public var total: Expression {
241 | return Function.total.wrap(self)
242 | }
243 |
244 | }
245 |
246 | extension ExpressionType where UnderlyingType == Int {
247 |
248 | static func count(_ star: Star) -> Expression {
249 | return Function.count.wrap(star(nil, nil))
250 | }
251 |
252 | }
253 |
254 | /// Builds an expression representing `count(*)` (when called with the `*`
255 | /// function literal).
256 | ///
257 | /// count(*)
258 | /// // count(*)
259 | ///
260 | /// - Returns: An expression returning `count(*)` (when called with the `*`
261 | /// function literal).
262 | public func count(_ star: Star) -> Expression {
263 | return Expression.count(star)
264 | }
265 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Typed/Collation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// A collating function used to compare to strings.
26 | ///
27 | /// - SeeAlso:
28 | public enum Collation {
29 |
30 | /// Compares string by raw data.
31 | case binary
32 |
33 | /// Like binary, but folds uppercase ASCII letters into their lowercase
34 | /// equivalents.
35 | case nocase
36 |
37 | /// Like binary, but strips trailing space.
38 | case rtrim
39 |
40 | /// A custom collating sequence identified by the given string, registered
41 | /// using `Database.create(collation:…)`
42 | case custom(String)
43 |
44 | }
45 |
46 | extension Collation : Expressible {
47 |
48 | public var expression: Expression {
49 | return Expression(literal: description)
50 | }
51 |
52 | }
53 |
54 | extension Collation : CustomStringConvertible {
55 |
56 | public var description : String {
57 | switch self {
58 | case .binary:
59 | return "BINARY"
60 | case .nocase:
61 | return "NOCASE"
62 | case .rtrim:
63 | return "RTRIM"
64 | case .custom(let collation):
65 | return collation.quote()
66 | }
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Typed/CustomFunctions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | public extension Connection {
26 |
27 | /// Creates or redefines a custom SQL function.
28 | ///
29 | /// - Parameters:
30 | ///
31 | /// - function: The name of the function to create or redefine.
32 | ///
33 | /// - deterministic: Whether or not the function is deterministic (_i.e._
34 | /// the function always returns the same result for a given input).
35 | ///
36 | /// Default: `false`
37 | ///
38 | /// - block: A block of code to run when the function is called.
39 | /// The assigned types must be explicit.
40 | ///
41 | /// - Returns: A closure returning an SQL expression to call the function.
42 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z) throws -> (() -> Expression) {
43 | let fn = try createFunction(function, 0, deterministic) { _ in block() }
44 | return { fn([]) }
45 | }
46 |
47 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping () -> Z?) throws -> (() -> Expression) {
48 | let fn = try createFunction(function, 0, deterministic) { _ in block() }
49 | return { fn([]) }
50 | }
51 |
52 | // MARK: -
53 |
54 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z) throws -> ((Expression) -> Expression) {
55 | let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) }
56 | return { arg in fn([arg]) }
57 | }
58 |
59 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z) throws -> ((Expression) -> Expression) {
60 | let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) }
61 | return { arg in fn([arg]) }
62 | }
63 |
64 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A) -> Z?) throws -> ((Expression) -> Expression) {
65 | let fn = try createFunction(function, 1, deterministic) { args in block(value(args[0])) }
66 | return { arg in fn([arg]) }
67 | }
68 |
69 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?) -> Z?) throws -> ((Expression) -> Expression) {
70 | let fn = try createFunction(function, 1, deterministic) { args in block(args[0].map(value)) }
71 | return { arg in fn([arg]) }
72 | }
73 |
74 | // MARK: -
75 |
76 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z) throws -> (Expression, Expression) -> Expression {
77 | let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), value(args[1])) }
78 | return { a, b in fn([a, b]) }
79 | }
80 |
81 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z) throws -> (Expression, Expression) -> Expression {
82 | let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), value(args[1])) }
83 | return { a, b in fn([a, b]) }
84 | }
85 |
86 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z) throws -> (Expression, Expression) -> Expression {
87 | let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), args[1].map(value)) }
88 | return { a, b in fn([a, b]) }
89 | }
90 |
91 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B) -> Z?) throws -> (Expression, Expression) -> Expression {
92 | let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), value(args[1])) }
93 | return { a, b in fn([a, b]) }
94 | }
95 |
96 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z) throws -> (Expression, Expression) -> Expression {
97 | let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), args[1].map(value)) }
98 | return { a, b in fn([a, b]) }
99 | }
100 |
101 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B) -> Z?) throws -> (Expression, Expression) -> Expression {
102 | let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), value(args[1])) }
103 | return { a, b in fn([a, b]) }
104 | }
105 |
106 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A, B?) -> Z?) throws -> (Expression, Expression) -> Expression {
107 | let fn = try createFunction(function, 2, deterministic) { args in block(value(args[0]), args[1].map(value)) }
108 | return { a, b in fn([a, b]) }
109 | }
110 |
111 | func createFunction(_ function: String, deterministic: Bool = false, _ block: @escaping (A?, B?) -> Z?) throws -> (Expression, Expression) -> Expression {
112 | let fn = try createFunction(function, 2, deterministic) { args in block(args[0].map(value), args[1].map(value)) }
113 | return { a, b in fn([a, b]) }
114 | }
115 |
116 | // MARK: -
117 |
118 | fileprivate func createFunction(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z) throws -> (([Expressible]) -> Expression) {
119 | createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in
120 | block(arguments).datatypeValue
121 | }
122 | return { arguments in
123 | function.quote().wrap(", ".join(arguments))
124 | }
125 | }
126 |
127 | fileprivate func createFunction(_ function: String, _ argumentCount: UInt, _ deterministic: Bool, _ block: @escaping ([Binding?]) -> Z?) throws -> (([Expressible]) -> Expression) {
128 | createFunction(function, argumentCount: argumentCount, deterministic: deterministic) { arguments in
129 | block(arguments)?.datatypeValue
130 | }
131 | return { arguments in
132 | function.quote().wrap(", ".join(arguments))
133 | }
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Typed/DateAndTimeFunctions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// All five date and time functions take a time string as an argument.
28 | /// The time string is followed by zero or more modifiers.
29 | /// The strftime() function also takes a format string as its first argument.
30 | ///
31 | /// https://www.sqlite.org/lang_datefunc.html
32 | public class DateFunctions {
33 | /// The date() function returns the date in this format: YYYY-MM-DD.
34 | public static func date(_ timestring: String, _ modifiers: String...) -> Expression {
35 | return timefunction("date", timestring: timestring, modifiers: modifiers)
36 | }
37 |
38 | /// The time() function returns the time as HH:MM:SS.
39 | public static func time(_ timestring: String, _ modifiers: String...) -> Expression {
40 | return timefunction("time", timestring: timestring, modifiers: modifiers)
41 | }
42 |
43 | /// The datetime() function returns "YYYY-MM-DD HH:MM:SS".
44 | public static func datetime(_ timestring: String, _ modifiers: String...) -> Expression {
45 | return timefunction("datetime", timestring: timestring, modifiers: modifiers)
46 | }
47 |
48 | /// The julianday() function returns the Julian day -
49 | /// the number of days since noon in Greenwich on November 24, 4714 B.C.
50 | public static func julianday(_ timestring: String, _ modifiers: String...) -> Expression {
51 | return timefunction("julianday", timestring: timestring, modifiers: modifiers)
52 | }
53 |
54 | /// The strftime() routine returns the date formatted according to the format string specified as the first argument.
55 | public static func strftime(_ format: String, _ timestring: String, _ modifiers: String...) -> Expression {
56 | if !modifiers.isEmpty {
57 | let templates = [String](repeating: "?", count: modifiers.count).joined(separator: ", ")
58 | return Expression("strftime(?, ?, \(templates))", [format, timestring] + modifiers)
59 | }
60 | return Expression("strftime(?, ?)", [format, timestring])
61 | }
62 |
63 | private static func timefunction(_ name: String, timestring: String, modifiers: [String]) -> Expression {
64 | if !modifiers.isEmpty {
65 | let templates = [String](repeating: "?", count: modifiers.count).joined(separator: ", ")
66 | return Expression("\(name)(?, \(templates))", [timestring] + modifiers)
67 | }
68 | return Expression("\(name)(?)", [timestring])
69 | }
70 | }
71 |
72 | extension Date {
73 | public var date: Expression {
74 | return DateFunctions.date(dateFormatter.string(from: self))
75 | }
76 |
77 | public var time: Expression {
78 | return DateFunctions.time(dateFormatter.string(from: self))
79 | }
80 |
81 | public var datetime: Expression {
82 | return DateFunctions.datetime(dateFormatter.string(from: self))
83 | }
84 |
85 | public var julianday: Expression {
86 | return DateFunctions.julianday(dateFormatter.string(from: self))
87 | }
88 | }
89 |
90 | extension Expression where UnderlyingType == Date {
91 | public var date: Expression {
92 | return Expression("date(\(template))", bindings)
93 | }
94 |
95 | public var time: Expression {
96 | return Expression("time(\(template))", bindings)
97 | }
98 |
99 | public var datetime: Expression {
100 | return Expression("datetime(\(template))", bindings)
101 | }
102 |
103 | public var julianday: Expression {
104 | return Expression("julianday(\(template))", bindings)
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLite/Typed/Expression.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | public protocol ExpressionType : Expressible { // extensions cannot have inheritance clauses
26 |
27 | associatedtype UnderlyingType = Void
28 |
29 | var template: String { get }
30 | var bindings: [Binding?] { get }
31 |
32 | init(_ template: String, _ bindings: [Binding?])
33 |
34 | }
35 |
36 | extension ExpressionType {
37 |
38 | public init(literal: String) {
39 | self.init(literal, [])
40 | }
41 |
42 | public init(_ identifier: String) {
43 | self.init(literal: identifier.quote())
44 | }
45 |
46 | public init(_ expression: U) {
47 | self.init(expression.template, expression.bindings)
48 | }
49 |
50 | }
51 |
52 | /// An `Expression` represents a raw SQL fragment and any associated bindings.
53 | public struct Expression : ExpressionType {
54 |
55 | public typealias UnderlyingType = Datatype
56 |
57 | public var template: String
58 | public var bindings: [Binding?]
59 |
60 | public init(_ template: String, _ bindings: [Binding?]) {
61 | self.template = template
62 | self.bindings = bindings
63 | }
64 |
65 | }
66 |
67 | public protocol Expressible {
68 |
69 | var expression: Expression { get }
70 |
71 | }
72 |
73 | extension Expressible {
74 |
75 | // naïve compiler for statements that can’t be bound, e.g., CREATE TABLE
76 | // FIXME: make internal (0.12.0)
77 | public func asSQL() -> String {
78 | let expressed = expression
79 | var idx = 0
80 | return expressed.template.reduce("") { template, character in
81 | let transcoded: String
82 |
83 | if character == "?" {
84 | transcoded = transcode(expressed.bindings[idx])
85 | idx += 1
86 | } else {
87 | transcoded = String(character)
88 | }
89 | return template + transcoded
90 | }
91 | }
92 |
93 | }
94 |
95 | extension ExpressionType {
96 |
97 | public var expression: Expression {
98 | return Expression(template, bindings)
99 | }
100 |
101 | public var asc: Expressible {
102 | return " ".join([self, Expression(literal: "ASC")])
103 | }
104 |
105 | public var desc: Expressible {
106 | return " ".join([self, Expression(literal: "DESC")])
107 | }
108 |
109 | }
110 |
111 | extension ExpressionType where UnderlyingType : Value {
112 |
113 | public init(value: UnderlyingType) {
114 | self.init("?", [value.datatypeValue])
115 | }
116 |
117 | }
118 |
119 | extension ExpressionType where UnderlyingType : _OptionalType, UnderlyingType.WrappedType : Value {
120 |
121 | public static var null: Self {
122 | return self.init(value: nil)
123 | }
124 |
125 | public init(value: UnderlyingType.WrappedType?) {
126 | self.init("?", [value?.datatypeValue])
127 | }
128 |
129 | }
130 |
131 | extension Value {
132 |
133 | public var expression: Expression {
134 | return Expression(value: self).expression
135 | }
136 |
137 | }
138 |
139 | public let rowid = Expression("ROWID")
140 |
141 | public func cast(_ expression: Expression) -> Expression {
142 | return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings)
143 | }
144 |
145 | public func cast(_ expression: Expression) -> Expression {
146 | return Expression("CAST (\(expression.template) AS \(U.declaredDatatype))", expression.bindings)
147 | }
148 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLiteObjc/SQLite-Bridging.m:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | #import "SQLite-Bridging.h"
26 | #import "fts3_tokenizer.h"
27 |
28 | #pragma mark - FTS
29 |
30 | typedef struct __SQLiteTokenizer {
31 | sqlite3_tokenizer base;
32 | __unsafe_unretained _SQLiteTokenizerNextCallback callback;
33 | } __SQLiteTokenizer;
34 |
35 | typedef struct __SQLiteTokenizerCursor {
36 | void * base;
37 | const char * input;
38 | int inputOffset;
39 | int inputLength;
40 | int idx;
41 | } __SQLiteTokenizerCursor;
42 |
43 | static NSMutableDictionary * __SQLiteTokenizerMap;
44 |
45 | static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) {
46 | __SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer));
47 | if (!tokenizer) {
48 | return SQLITE_NOMEM;
49 | }
50 | memset(tokenizer, 0, sizeof(* tokenizer));
51 |
52 | NSString * key = [NSString stringWithUTF8String:argv[0]];
53 | tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key];
54 | if (!tokenizer->callback) {
55 | return SQLITE_ERROR;
56 | }
57 |
58 | *ppTokenizer = &tokenizer->base;
59 | return SQLITE_OK;
60 | }
61 |
62 | static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) {
63 | sqlite3_free(pTokenizer);
64 | return SQLITE_OK;
65 | }
66 |
67 | static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) {
68 | __SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor));
69 | if (!cursor) {
70 | return SQLITE_NOMEM;
71 | }
72 |
73 | cursor->input = pInput;
74 | cursor->inputOffset = 0;
75 | cursor->inputLength = 0;
76 | cursor->idx = 0;
77 |
78 | *ppCursor = (sqlite3_tokenizer_cursor *)cursor;
79 | return SQLITE_OK;
80 | }
81 |
82 | static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) {
83 | sqlite3_free(pCursor);
84 | return SQLITE_OK;
85 | }
86 |
87 | static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) {
88 | __SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor;
89 | __SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base;
90 |
91 | cursor->inputOffset += cursor->inputLength;
92 | const char * input = cursor->input + cursor->inputOffset;
93 | const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding];
94 | if (!token) {
95 | return SQLITE_DONE;
96 | }
97 |
98 | *ppToken = token;
99 | *pnBytes = (int)strlen(token);
100 | *piStartOffset = cursor->inputOffset;
101 | *piEndOffset = cursor->inputOffset + cursor->inputLength;
102 | *piPosition = cursor->idx++;
103 | return SQLITE_OK;
104 | }
105 |
106 | static const sqlite3_tokenizer_module __SQLiteTokenizerModule = {
107 | 0,
108 | __SQLiteTokenizerCreate,
109 | __SQLiteTokenizerDestroy,
110 | __SQLiteTokenizerOpen,
111 | __SQLiteTokenizerClose,
112 | __SQLiteTokenizerNext
113 | };
114 |
115 | int _SQLiteRegisterTokenizer(sqlite3 *db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) {
116 | static dispatch_once_t onceToken;
117 | dispatch_once(&onceToken, ^{
118 | __SQLiteTokenizerMap = [NSMutableDictionary new];
119 | });
120 |
121 | sqlite3_stmt * stmt;
122 | int status = sqlite3_prepare_v2(db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0);
123 | if (status != SQLITE_OK ){
124 | return status;
125 | }
126 | const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule;
127 | sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC);
128 | sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC);
129 | sqlite3_step(stmt);
130 | status = sqlite3_finalize(stmt);
131 | if (status != SQLITE_OK ){
132 | return status;
133 | }
134 |
135 | [__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]];
136 |
137 | return SQLITE_OK;
138 | }
139 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLiteObjc/fts3_tokenizer.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** 2006 July 10
3 | **
4 | ** The author disclaims copyright to this source code.
5 | **
6 | *************************************************************************
7 | ** Defines the interface to tokenizers used by fulltext-search. There
8 | ** are three basic components:
9 | **
10 | ** sqlite3_tokenizer_module is a singleton defining the tokenizer
11 | ** interface functions. This is essentially the class structure for
12 | ** tokenizers.
13 | **
14 | ** sqlite3_tokenizer is used to define a particular tokenizer, perhaps
15 | ** including customization information defined at creation time.
16 | **
17 | ** sqlite3_tokenizer_cursor is generated by a tokenizer to generate
18 | ** tokens from a particular input.
19 | */
20 | #ifndef _FTS3_TOKENIZER_H_
21 | #define _FTS3_TOKENIZER_H_
22 |
23 | /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
24 | ** If tokenizers are to be allowed to call sqlite3_*() functions, then
25 | ** we will need a way to register the API consistently.
26 | */
27 | #import "sqlite3.h"
28 |
29 | /*
30 | ** Structures used by the tokenizer interface. When a new tokenizer
31 | ** implementation is registered, the caller provides a pointer to
32 | ** an sqlite3_tokenizer_module containing pointers to the callback
33 | ** functions that make up an implementation.
34 | **
35 | ** When an fts3 table is created, it passes any arguments passed to
36 | ** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
37 | ** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
38 | ** implementation. The xCreate() function in turn returns an
39 | ** sqlite3_tokenizer structure representing the specific tokenizer to
40 | ** be used for the fts3 table (customized by the tokenizer clause arguments).
41 | **
42 | ** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen()
43 | ** method is called. It returns an sqlite3_tokenizer_cursor object
44 | ** that may be used to tokenize a specific input buffer based on
45 | ** the tokenization rules supplied by a specific sqlite3_tokenizer
46 | ** object.
47 | */
48 | typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
49 | typedef struct sqlite3_tokenizer sqlite3_tokenizer;
50 | typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;
51 |
52 | struct sqlite3_tokenizer_module {
53 |
54 | /*
55 | ** Structure version. Should always be set to 0 or 1.
56 | */
57 | int iVersion;
58 |
59 | /*
60 | ** Create a new tokenizer. The values in the argv[] array are the
61 | ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL
62 | ** TABLE statement that created the fts3 table. For example, if
63 | ** the following SQL is executed:
64 | **
65 | ** CREATE .. USING fts3( ... , tokenizer arg1 arg2)
66 | **
67 | ** then argc is set to 2, and the argv[] array contains pointers
68 | ** to the strings "arg1" and "arg2".
69 | **
70 | ** This method should return either SQLITE_OK (0), or an SQLite error
71 | ** code. If SQLITE_OK is returned, then *ppTokenizer should be set
72 | ** to point at the newly created tokenizer structure. The generic
73 | ** sqlite3_tokenizer.pModule variable should not be initialized by
74 | ** this callback. The caller will do so.
75 | */
76 | int (*xCreate)(
77 | int argc, /* Size of argv array */
78 | const char *const*argv, /* Tokenizer argument strings */
79 | sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */
80 | );
81 |
82 | /*
83 | ** Destroy an existing tokenizer. The fts3 module calls this method
84 | ** exactly once for each successful call to xCreate().
85 | */
86 | int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
87 |
88 | /*
89 | ** Create a tokenizer cursor to tokenize an input buffer. The caller
90 | ** is responsible for ensuring that the input buffer remains valid
91 | ** until the cursor is closed (using the xClose() method).
92 | */
93 | int (*xOpen)(
94 | sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
95 | const char *pInput, int nBytes, /* Input buffer */
96 | sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
97 | );
98 |
99 | /*
100 | ** Destroy an existing tokenizer cursor. The fts3 module calls this
101 | ** method exactly once for each successful call to xOpen().
102 | */
103 | int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
104 |
105 | /*
106 | ** Retrieve the next token from the tokenizer cursor pCursor. This
107 | ** method should either return SQLITE_OK and set the values of the
108 | ** "OUT" variables identified below, or SQLITE_DONE to indicate that
109 | ** the end of the buffer has been reached, or an SQLite error code.
110 | **
111 | ** *ppToken should be set to point at a buffer containing the
112 | ** normalized version of the token (i.e. after any case-folding and/or
113 | ** stemming has been performed). *pnBytes should be set to the length
114 | ** of this buffer in bytes. The input text that generated the token is
115 | ** identified by the byte offsets returned in *piStartOffset and
116 | ** *piEndOffset. *piStartOffset should be set to the index of the first
117 | ** byte of the token in the input buffer. *piEndOffset should be set
118 | ** to the index of the first byte just past the end of the token in
119 | ** the input buffer.
120 | **
121 | ** The buffer *ppToken is set to point at is managed by the tokenizer
122 | ** implementation. It is only required to be valid until the next call
123 | ** to xNext() or xClose().
124 | */
125 | /* TODO(shess) current implementation requires pInput to be
126 | ** nul-terminated. This should either be fixed, or pInput/nBytes
127 | ** should be converted to zInput.
128 | */
129 | int (*xNext)(
130 | sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */
131 | const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
132 | int *piStartOffset, /* OUT: Byte offset of token in input buffer */
133 | int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
134 | int *piPosition /* OUT: Number of tokens returned before this one */
135 | );
136 |
137 | /***********************************************************************
138 | ** Methods below this point are only available if iVersion>=1.
139 | */
140 |
141 | /*
142 | ** Configure the language id of a tokenizer cursor.
143 | */
144 | int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
145 | };
146 |
147 | struct sqlite3_tokenizer {
148 | const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */
149 | /* Tokenizer implementations will typically add additional fields */
150 | };
151 |
152 | struct sqlite3_tokenizer_cursor {
153 | sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */
154 | /* Tokenizer implementations will typically add additional fields */
155 | };
156 |
157 | int fts3_global_term_cnt(int iTerm, int iCol);
158 | int fts3_term_cnt(int iTerm, int iCol);
159 |
160 |
161 | #endif /* _FTS3_TOKENIZER_H_ */
162 |
--------------------------------------------------------------------------------
/Pods/SQLite.swift/Sources/SQLiteObjc/include/SQLite-Bridging.h:
--------------------------------------------------------------------------------
1 | //
2 | // SQLite.swift
3 | // https://github.com/stephencelis/SQLite.swift
4 | // Copyright © 2014-2015 Stephen Celis.
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | @import Foundation;
26 | @import SQLite3;
27 |
28 | NS_ASSUME_NONNULL_BEGIN
29 | typedef NSString * _Nullable (^_SQLiteTokenizerNextCallback)(const char *input, int *inputOffset, int *inputLength);
30 | int _SQLiteRegisterTokenizer(sqlite3 *db, const char *module, const char *tokenizer, _Nullable _SQLiteTokenizerNextCallback callback);
31 | NS_ASSUME_NONNULL_END
32 |
33 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FavIcon/FavIcon-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 3.0.6
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FavIcon/FavIcon-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_FavIcon : NSObject
3 | @end
4 | @implementation PodsDummy_FavIcon
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FavIcon/FavIcon-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FavIcon/FavIcon-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double FavIconVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char FavIconVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FavIcon/FavIcon.modulemap:
--------------------------------------------------------------------------------
1 | framework module FavIcon {
2 | umbrella header "FavIcon-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/FavIcon/FavIcon.xcconfig:
--------------------------------------------------------------------------------
1 | CODE_SIGN_IDENTITY =
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FavIcon
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = /usr/include/libxml2
5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FavIcon
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | SWIFT_INCLUDE_PATHS = $(PODS_TARGET_SRCROOT)/Sources/Modules
13 | SWIFT_VERSION = 4.0
14 | SWIFT_WHOLE_MODULE_OPTIMIZATION = YES
15 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## FavIcon
5 |
6 | Copyright (C) 2018 Leon Breedt
7 |
8 | Licensed under the Apache License, Version 2.0 (the "License");
9 | you may not use this file except in compliance with the License.
10 | You may obtain a copy of the License at
11 |
12 | http://www.apache.org/licenses/LICENSE-2.0
13 |
14 | Unless required by applicable law or agreed to in writing, software
15 | distributed under the License is distributed on an "AS IS" BASIS,
16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | See the License for the specific language governing permissions and
18 | limitations under the License.
19 |
20 |
21 | ## SQLCipher
22 |
23 | Copyright (c) 2008, ZETETIC LLC
24 | All rights reserved.
25 |
26 | Redistribution and use in source and binary forms, with or without
27 | modification, are permitted provided that the following conditions are met:
28 | * Redistributions of source code must retain the above copyright
29 | notice, this list of conditions and the following disclaimer.
30 | * Redistributions in binary form must reproduce the above copyright
31 | notice, this list of conditions and the following disclaimer in the
32 | documentation and/or other materials provided with the distribution.
33 | * Neither the name of the ZETETIC LLC nor the
34 | names of its contributors may be used to endorse or promote products
35 | derived from this software without specific prior written permission.
36 |
37 | THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
38 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 | DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
41 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 |
48 |
49 | ## SQLite.swift
50 |
51 | (The MIT License)
52 |
53 | Copyright (c) 2014-2015 Stephen Celis ()
54 |
55 | Permission is hereby granted, free of charge, to any person obtaining a copy
56 | of this software and associated documentation files (the "Software"), to deal
57 | in the Software without restriction, including without limitation the rights
58 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
59 | copies of the Software, and to permit persons to whom the Software is
60 | furnished to do so, subject to the following conditions:
61 |
62 | The above copyright notice and this permission notice shall be included in all
63 | copies or substantial portions of the Software.
64 |
65 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
67 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
71 | SOFTWARE.
72 |
73 | Generated by CocoaPods - https://cocoapods.org
74 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (C) 2018 Leon Breedt
18 |
19 | Licensed under the Apache License, Version 2.0 (the "License");
20 | you may not use this file except in compliance with the License.
21 | You may obtain a copy of the License at
22 |
23 | http://www.apache.org/licenses/LICENSE-2.0
24 |
25 | Unless required by applicable law or agreed to in writing, software
26 | distributed under the License is distributed on an "AS IS" BASIS,
27 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | See the License for the specific language governing permissions and
29 | limitations under the License.
30 |
31 | License
32 | Apache
33 | Title
34 | FavIcon
35 | Type
36 | PSGroupSpecifier
37 |
38 |
39 | FooterText
40 | Copyright (c) 2008, ZETETIC LLC
41 | All rights reserved.
42 |
43 | Redistribution and use in source and binary forms, with or without
44 | modification, are permitted provided that the following conditions are met:
45 | * Redistributions of source code must retain the above copyright
46 | notice, this list of conditions and the following disclaimer.
47 | * Redistributions in binary form must reproduce the above copyright
48 | notice, this list of conditions and the following disclaimer in the
49 | documentation and/or other materials provided with the distribution.
50 | * Neither the name of the ZETETIC LLC nor the
51 | names of its contributors may be used to endorse or promote products
52 | derived from this software without specific prior written permission.
53 |
54 | THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
55 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
56 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
57 | DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
58 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 |
65 | License
66 | BSD
67 | Title
68 | SQLCipher
69 | Type
70 | PSGroupSpecifier
71 |
72 |
73 | FooterText
74 | (The MIT License)
75 |
76 | Copyright (c) 2014-2015 Stephen Celis (<stephen@stephencelis.com>)
77 |
78 | Permission is hereby granted, free of charge, to any person obtaining a copy
79 | of this software and associated documentation files (the "Software"), to deal
80 | in the Software without restriction, including without limitation the rights
81 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
82 | copies of the Software, and to permit persons to whom the Software is
83 | furnished to do so, subject to the following conditions:
84 |
85 | The above copyright notice and this permission notice shall be included in all
86 | copies or substantial portions of the Software.
87 |
88 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
89 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
91 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
92 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
93 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
94 | SOFTWARE.
95 |
96 | License
97 | MIT
98 | Title
99 | SQLite.swift
100 | Type
101 | PSGroupSpecifier
102 |
103 |
104 | FooterText
105 | Generated by CocoaPods - https://cocoapods.org
106 | Title
107 |
108 | Type
109 | PSGroupSpecifier
110 |
111 |
112 | StringsTable
113 | Acknowledgements
114 | Title
115 | Acknowledgements
116 |
117 |
118 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_allyourpasswords : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_allyourpasswords
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 |
23 | # Used as a return value for each invocation of `strip_invalid_archs` function.
24 | STRIP_BINARY_RETVAL=0
25 |
26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
29 |
30 | # Copies and strips a vendored framework
31 | install_framework()
32 | {
33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
34 | local source="${BUILT_PRODUCTS_DIR}/$1"
35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
37 | elif [ -r "$1" ]; then
38 | local source="$1"
39 | fi
40 |
41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
42 |
43 | if [ -L "${source}" ]; then
44 | echo "Symlinked..."
45 | source="$(readlink "${source}")"
46 | fi
47 |
48 | # Use filter instead of exclude so missing patterns don't throw errors.
49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
51 |
52 | local basename
53 | basename="$(basename -s .framework "$1")"
54 | binary="${destination}/${basename}.framework/${basename}"
55 |
56 | if ! [ -r "$binary" ]; then
57 | binary="${destination}/${basename}"
58 | elif [ -L "${binary}" ]; then
59 | echo "Destination binary is symlinked..."
60 | dirname="$(dirname "${binary}")"
61 | binary="${dirname}/$(readlink "${binary}")"
62 | fi
63 |
64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
66 | strip_invalid_archs "$binary"
67 | fi
68 |
69 | # Resign the code if required by the build settings to avoid unstable apps
70 | code_sign_if_enabled "${destination}/$(basename "$1")"
71 |
72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
74 | local swift_runtime_libs
75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
76 | for lib in $swift_runtime_libs; do
77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
79 | code_sign_if_enabled "${destination}/${lib}"
80 | done
81 | fi
82 | }
83 |
84 | # Copies and strips a vendored dSYM
85 | install_dsym() {
86 | local source="$1"
87 | if [ -r "$source" ]; then
88 | # Copy the dSYM into a the targets temp dir.
89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
91 |
92 | local basename
93 | basename="$(basename -s .framework.dSYM "$source")"
94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
95 |
96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
97 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
98 | strip_invalid_archs "$binary"
99 | fi
100 |
101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
102 | # Move the stripped file into its final destination.
103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
105 | else
106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
108 | fi
109 | fi
110 | }
111 |
112 | # Signs a framework with the provided identity
113 | code_sign_if_enabled() {
114 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
115 | # Use the current code_sign_identity
116 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
117 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
118 |
119 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
120 | code_sign_cmd="$code_sign_cmd &"
121 | fi
122 | echo "$code_sign_cmd"
123 | eval "$code_sign_cmd"
124 | fi
125 | }
126 |
127 | # Strip invalid architectures
128 | strip_invalid_archs() {
129 | binary="$1"
130 | # Get architectures for current target binary
131 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
132 | # Intersect them with the architectures we are building for
133 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
134 | # If there are no archs supported by this binary then warn the user
135 | if [[ -z "$intersected_archs" ]]; then
136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 | STRIP_BINARY_RETVAL=0
138 | return
139 | fi
140 | stripped=""
141 | for arch in $binary_archs; do
142 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
143 | # Strip non-valid architectures in-place
144 | lipo -remove "$arch" -output "$binary" "$binary"
145 | stripped="$stripped $arch"
146 | fi
147 | done
148 | if [[ "$stripped" ]]; then
149 | echo "Stripped $binary of architectures:$stripped"
150 | fi
151 | STRIP_BINARY_RETVAL=1
152 | }
153 |
154 |
155 | if [[ "$CONFIGURATION" == "Debug" ]]; then
156 | install_framework "${BUILT_PRODUCTS_DIR}/FavIcon/FavIcon.framework"
157 | install_framework "${BUILT_PRODUCTS_DIR}/SQLCipher/SQLCipher.framework"
158 | install_framework "${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework"
159 | fi
160 | if [[ "$CONFIGURATION" == "Release" ]]; then
161 | install_framework "${BUILT_PRODUCTS_DIR}/FavIcon/FavIcon.framework"
162 | install_framework "${BUILT_PRODUCTS_DIR}/SQLCipher/SQLCipher.framework"
163 | install_framework "${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework"
164 | fi
165 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
166 | wait
167 | fi
168 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_allyourpasswordsVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_allyourpasswordsVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CODE_SIGN_IDENTITY =
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FavIcon" "${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) SQLITE_HAS_CODEC=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FavIcon/FavIcon.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher/SQLCipher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.framework/Headers" /usr/include/libxml2 $(PODS_ROOT)/SQLCipher
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks'
7 | OTHER_CFLAGS = $(inherited) -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_SOUNDEX -DSQLITE_THREADSAFE -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT3 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLCIPHER_CRYPTO_CC -DHAVE_USLEEP=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999
8 | OTHER_LDFLAGS = $(inherited) -framework "FavIcon" -framework "Foundation" -framework "SQLCipher" -framework "SQLite" -framework "Security"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS $(inherited) -DSQLITE_SWIFT_SQLCIPHER
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | SWIFT_INCLUDE_PATHS = $(PODS_TARGET_SRCROOT)/Sources/Modules
15 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_allyourpasswords {
2 | umbrella header "Pods-allyourpasswords-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-allyourpasswords/Pods-allyourpasswords.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CODE_SIGN_IDENTITY =
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FavIcon" "${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) SQLITE_HAS_CODEC=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FavIcon/FavIcon.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher/SQLCipher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.framework/Headers" /usr/include/libxml2 $(PODS_ROOT)/SQLCipher
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks'
7 | OTHER_CFLAGS = $(inherited) -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_SOUNDEX -DSQLITE_THREADSAFE -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT3 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLCIPHER_CRYPTO_CC -DHAVE_USLEEP=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999
8 | OTHER_LDFLAGS = $(inherited) -framework "FavIcon" -framework "Foundation" -framework "SQLCipher" -framework "SQLite" -framework "Security"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS $(inherited) -DSQLITE_SWIFT_SQLCIPHER
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | SWIFT_INCLUDE_PATHS = $(PODS_TARGET_SRCROOT)/Sources/Modules
15 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLCipher/SQLCipher-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 4.1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLCipher/SQLCipher-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_SQLCipher : NSObject
3 | @end
4 | @implementation PodsDummy_SQLCipher
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLCipher/SQLCipher-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLCipher/SQLCipher-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "sqlite3.h"
14 |
15 | FOUNDATION_EXPORT double SQLCipherVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char SQLCipherVersionString[];
17 |
18 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLCipher/SQLCipher.modulemap:
--------------------------------------------------------------------------------
1 | framework module SQLCipher {
2 | umbrella header "SQLCipher-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLCipher/SQLCipher.xcconfig:
--------------------------------------------------------------------------------
1 | CODE_SIGN_IDENTITY =
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) SQLITE_HAS_CODEC=1
4 | HEADER_SEARCH_PATHS = $(PODS_ROOT)/SQLCipher
5 | OTHER_CFLAGS = $(inherited) -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_SOUNDEX -DSQLITE_THREADSAFE -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT3 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLCIPHER_CRYPTO_CC -DHAVE_USLEEP=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999
6 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "Security"
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SQLCipher
11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
12 | SKIP_INSTALL = YES
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLite.swift/SQLite.swift-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.11.6
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLite.swift/SQLite.swift-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_SQLite_swift : NSObject
3 | @end
4 | @implementation PodsDummy_SQLite_swift
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLite.swift/SQLite.swift-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLite.swift/SQLite.swift-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "SQLite.h"
14 | #import "SQLite-Bridging.h"
15 |
16 | FOUNDATION_EXPORT double SQLiteVersionNumber;
17 | FOUNDATION_EXPORT const unsigned char SQLiteVersionString[];
18 |
19 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLite.swift/SQLite.swift.modulemap:
--------------------------------------------------------------------------------
1 | framework module SQLite {
2 | umbrella header "SQLite.swift-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/SQLite.swift/SQLite.swift.xcconfig:
--------------------------------------------------------------------------------
1 | CODE_SIGN_IDENTITY =
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) SQLITE_HAS_CODEC=1
5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS $(inherited) -DSQLITE_SWIFT_SQLCIPHER
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SQLite.swift
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | SWIFT_VERSION = 4.2
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # allyourpasswords
2 | The offline password manager. Requires macOS 10.14 or later
3 |
4 | ### In Action
5 |
6 | 
7 |
8 | ### No electron
9 |
10 | Although I am more proficient at making websites, I don't like electron "apps" taking away all of my battery and spinning up my CPU to 100% randomly, so swift it is.
11 |
12 | ### The process
13 |
14 | I logged every day of the 30 day process it took me to make this thing [here on a dev focused blogging platform](https://dev.to/swlkr/day-1-making-a-native-macos-password-manager-for-people-who-hate-the-cloud-3j68)
15 |
16 | ### The stack
17 | This is essentially a swift wrapper around SQLite that uses three open source libraries, which is why I was able to get it done in a month as a side project around my full time job.
18 |
19 | 1. [SQLite.swift](https://github.com/stephencelis/SQLite.swift)
20 | 2. [FavIcon](https://github.com/leonbreedt/FavIcon)
21 | 3. [SQLCipher](https://github.com/sqlcipher/sqlcipher)
22 |
23 | The roles of sqlite.swift and sqlcipher are to read/write to an encrypted sqlite db that gets encrypted with the master password that you set when the app opens up. There are few columns in one table "logins" and that's pretty much it for now. Future versions will be more sophisticated, but for now it does what it says and says what it does. Wait...
24 |
25 | ### Building
26 |
27 | Have a mac running macOS mojave 10.14, open up xcode, hit the play button.
28 |
29 | ### Support
30 |
31 | If you want to support future dev efforts with cold hard cash, you can buy it either from my (very basic) lander here: [allyourpasswords.com](https://allyourpasswords.com) or from the [mac app store here](https://itunes.apple.com/us/app/all-your-passwords/id1450537302?mt=12)
32 |
33 | If you don't want to pay the full price of the app in the mac app store, you can use the code ph-50 after you click the buy button on the lander, it uses paddle and devmate, so it requires an email to send the .app file to, just trying to be as upfront as possible here.
34 |
35 | The mas branch stands for "mac app store" and the master branch is the binary distributed through the landing page (allyourpasswords.com)
36 |
--------------------------------------------------------------------------------
/allyourpasswords.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/allyourpasswords.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/allyourpasswords.xcodeproj/xcuserdata/swlkr.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | allyourpasswords.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 4
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/allyourpasswords.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/allyourpasswords.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/allyourpasswords/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | var window : WindowController?
15 | var storyboard : NSStoryboard?
16 | @IBOutlet weak var changeMasterPasswordMenuItem: NSMenuItem!
17 |
18 | func applicationWillFinishLaunching(_ notification: Notification) {
19 | NotificationCenter.default.addObserver(self, selector: #selector(enableChangeMasterPasswordMenuItem), name: NSNotification.Name(rawValue: "enableChangeMasterPasswordMenuItem"), object: nil)
20 | }
21 |
22 | func applicationDidFinishLaunching(_ aNotification: Notification) {
23 | changeMasterPasswordMenuItem.isEnabled = false
24 |
25 | storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
26 | window = storyboard?.instantiateController(withIdentifier: "WindowController") as? WindowController
27 | let masterPassword: String? = KeychainWrapper.standard.string(forKey: "MasterPassword")
28 | if masterPassword == nil {
29 | let viewController = storyboard?.instantiateController(withIdentifier: "SetMasterPasswordViewController") as! SetMasterPasswordViewController
30 | window?.contentViewController = viewController
31 | } else {
32 | let viewController = storyboard?.instantiateController(withIdentifier: "UnlockViewController") as! UnlockViewController
33 | window?.contentViewController = viewController
34 |
35 | DispatchQueue.global(qos: .background).async {
36 | let db = Database.open()
37 | let prop = Prop()
38 |
39 | try! db.run(prop.table.create(ifNotExists: true) { t in
40 | t.column(prop.id, primaryKey: true)
41 | t.column(prop.login)
42 | t.column(prop.name)
43 | t.column(prop.value)
44 | })
45 | }
46 |
47 | }
48 |
49 | window?.showWindow(self)
50 | }
51 |
52 | func applicationWillTerminate(_ aNotification: Notification) {
53 | // Insert code here to tear down your application
54 | }
55 |
56 | @IBAction func addNewLogin(_ sender: NSMenuItem) {
57 | }
58 |
59 | @IBAction func deleteLogin(_ sender: NSMenuItem) {
60 | }
61 |
62 | @IBAction func copy(_ sender: NSMenuItem) {
63 | }
64 |
65 | @IBAction func copyEmailOrUsername(_ sender: NSMenuItem) {
66 | }
67 |
68 | @IBAction func copyPassword(_ sender: NSMenuItem) {
69 | }
70 |
71 | @IBAction func saveLogin(_ sender: NSMenuItem) {
72 | }
73 |
74 | @IBAction func changeMasterPassword(_ sender: NSMenuItem) {
75 | if window?.contentViewController is UnlockViewController ||
76 | window?.contentViewController is SetMasterPasswordViewController {
77 | return
78 | }
79 |
80 | let viewController = storyboard?.instantiateController(withIdentifier: "ResetMasterPasswordViewController") as! ResetMasterPasswordViewController
81 | window?.contentViewController = viewController
82 | }
83 |
84 | @objc func enableChangeMasterPasswordMenuItem() {
85 | changeMasterPasswordMenuItem.isEnabled = true
86 | }
87 |
88 | @IBAction func reopenWindow(_ sender: NSMenuItem) {
89 | window?.window?.makeKeyAndOrderFront(self)
90 | }
91 |
92 | func escape(_ str: String) -> String {
93 | if(str.contains(",")) {
94 | return "\"\(str)\""
95 | } else {
96 | return str
97 | }
98 | }
99 |
100 | @IBAction func exportAsCSV(_ sender: NSMenuItem) {
101 | var csvText = "id,name,url,username,email,password\n"
102 |
103 | let db = Database.open()
104 | let login = Login()
105 |
106 | let query = login.table.order(login.name, login.url)
107 | let rows = Array(try! db.prepare(query))
108 |
109 | for row in rows {
110 | let newLine = "\(row[login.id]),\(escape(row[login.name]!)),\(escape(row[login.url]!)),\(escape(row[login.username]!)),\(escape(row[login.email]!)),\(escape(row[login.password]!))\n"
111 | csvText = csvText + newLine
112 | }
113 |
114 | let savePanel = NSSavePanel()
115 | savePanel.canCreateDirectories = true
116 | savePanel.showsTagField = false
117 | savePanel.nameFieldStringValue = "allyourpasswords.csv"
118 | savePanel.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.modalPanelWindow)))
119 | savePanel.begin { (result) in
120 | if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
121 |
122 | do {
123 | try csvText.write(to: savePanel.url!, atomically: true, encoding: String.Encoding.utf8)
124 | } catch {
125 | print("Failed to create file")
126 | print("\(error)")
127 | }
128 | }
129 | }
130 | }
131 |
132 | func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
133 | if flag {
134 | window?.window?.orderFront(self)
135 | } else {
136 | window?.window?.makeKeyAndOrderFront(self)
137 | }
138 | return true
139 | }
140 | }
141 |
142 |
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "Icon-16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "Icon-16@2x.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "Icon-32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "Icon-32@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "Icon-128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "Icon-128@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "Icon-256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "Icon-256@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "Icon-512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "Icon-1025.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-1025.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-1025.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-128.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-128@2x.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-16.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-16@2x.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-256.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-256@2x.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-32.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/allyourpasswords/Assets.xcassets/AppIcon.appiconset/Icon-512.png
--------------------------------------------------------------------------------
/allyourpasswords/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/allyourpasswords/Components/CursorChangingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MouseTrackingTextView.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 2/2/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class CursorChangingView: NSView {
12 |
13 | // MARK: - Lifecycle
14 |
15 | override func awakeFromNib() {
16 | setupTrackingArea()
17 | }
18 |
19 | // MARK: - Resizing
20 |
21 | // Call this in your controller's `viewDidLayout`
22 | // so it only gets called when the view resizes
23 | func superviewResized() {
24 | resetTrackingArea()
25 | }
26 |
27 | // MARK: - Mouse Events
28 |
29 | override func resetCursorRects() {
30 | addCursorRect(bounds, cursor: cursorType)
31 | }
32 |
33 | override func mouseMoved(with event: NSEvent) {
34 | cursorType.set()
35 | }
36 |
37 | // MARK: - Private Properties
38 |
39 | private var currentTrackingArea: NSTrackingArea?
40 |
41 | private var cursorType: NSCursor {
42 | return .pointingHand
43 | }
44 |
45 | // MARK: - Private API
46 |
47 | private func setupTrackingArea() {
48 | let trackingArea = NSTrackingArea(rect: bounds,
49 | options: [.activeAlways, .mouseMoved],
50 | owner: self, userInfo: nil)
51 | currentTrackingArea = trackingArea
52 | addTrackingArea(trackingArea)
53 | }
54 |
55 | private func resetTrackingArea() {
56 | if let trackingArea = currentTrackingArea {
57 | removeTrackingArea(trackingArea)
58 | }
59 | setupTrackingArea()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/allyourpasswords/Components/CustomTextFieldCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomTextFieldCell.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class CustomTextFieldCell: NSTextFieldCell {
12 |
13 | private static let padding = CGSize(width: 4.0, height: 4.0)
14 |
15 | override func cellSize(forBounds rect: NSRect) -> NSSize {
16 | var size = super.cellSize(forBounds: rect)
17 | size.height += (CustomTextFieldCell.padding.height * 2)
18 | return size
19 | }
20 |
21 | override func titleRect(forBounds rect: NSRect) -> NSRect {
22 | return rect.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
23 | }
24 |
25 | override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
26 | let insetRect = rect.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
27 | super.edit(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, event: event)
28 | }
29 |
30 | override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
31 | let insetRect = rect.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
32 | super.select(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
33 | }
34 |
35 | override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
36 | let insetRect = cellFrame.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
37 | super.drawInterior(withFrame: insetRect, in: controlView)
38 | }
39 |
40 | }
41 |
42 | class CustomSecureTextFieldCell: NSSecureTextFieldCell {
43 |
44 | private static let padding = CGSize(width: 4.0, height: 8.0)
45 |
46 | override func cellSize(forBounds rect: NSRect) -> NSSize {
47 | var size = super.cellSize(forBounds: rect)
48 | size.height += (CustomSecureTextFieldCell.padding.height * 2)
49 | return size
50 | }
51 |
52 | override func titleRect(forBounds rect: NSRect) -> NSRect {
53 | return rect.insetBy(dx: CustomSecureTextFieldCell.padding.width, dy: CustomSecureTextFieldCell.padding.height)
54 | }
55 |
56 | override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
57 | let insetRect = rect.insetBy(dx: CustomSecureTextFieldCell.padding.width, dy: CustomSecureTextFieldCell.padding.height)
58 | super.edit(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, event: event)
59 | }
60 |
61 | override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
62 | let insetRect = rect.insetBy(dx: CustomSecureTextFieldCell.padding.width, dy: CustomSecureTextFieldCell.padding.height)
63 | super.select(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
64 | }
65 |
66 | override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
67 | let insetRect = cellFrame.insetBy(dx: CustomSecureTextFieldCell.padding.width, dy: CustomSecureTextFieldCell.padding.height)
68 | super.drawInterior(withFrame: insetRect, in: controlView)
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/allyourpasswords/Components/HyperlinkTextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HyperlinkTextField.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 2/2/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @IBDesignable
12 | class HyperlinkTextField: NSTextField {
13 | @IBInspectable var href: String?
14 |
15 | override func awakeFromNib() {
16 | super.awakeFromNib()
17 |
18 | let attributes: [NSAttributedString.Key: Any] = [
19 | NSAttributedString.Key.foregroundColor: NSColor.blue,
20 | NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single
21 | ]
22 | self.attributedStringValue = NSAttributedString(string: self.stringValue, attributes: attributes)
23 | }
24 |
25 | override func mouseDown(with theEvent: NSEvent) {
26 | if !(self.href ?? "").isEmpty {
27 | NSWorkspace.shared.open(URL(string: self.href ?? "")!)
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/allyourpasswords/Controllers/MainViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class MainViewController : NSSplitViewController {
12 | @IBOutlet weak var leftSplit: NSSplitViewItem!
13 | @IBOutlet weak var rightSplit: NSSplitViewItem!
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 |
18 | let containerViewController = rightSplit.viewController as? ContainerViewController
19 | let tableViewController = leftSplit.viewController as? TableViewController
20 | tableViewController?.containerViewController = containerViewController
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/allyourpasswords/Controllers/WindowController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 2/23/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class WindowController : NSWindowController {
12 | override func windowDidLoad() {
13 | shouldCascadeWindows = false
14 | window?.setFrameAutosaveName("MainWindow")
15 |
16 | super.windowDidLoad()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/allyourpasswords/CoreData/Database.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Database.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import SQLite
10 |
11 | public struct Database {
12 | static func open() -> Connection {
13 | let path = NSSearchPathForDirectoriesInDomains(
14 | .applicationSupportDirectory, .userDomainMask, true
15 | ).first! + "/" + Bundle.main.bundleIdentifier!
16 |
17 | try! FileManager.default.createDirectory(
18 | atPath: path, withIntermediateDirectories: true, attributes: nil
19 | )
20 |
21 | let masterPassword = KeychainWrapper.standard.string(forKey: "MasterPassword")
22 |
23 | let conn = try! Connection("\(path)/encrypted.sqlite3")
24 | try! conn.key(masterPassword!)
25 |
26 | #if DEBUG
27 | conn.trace { print($0) }
28 | #endif
29 |
30 | return conn
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/allyourpasswords/Extensions/NSImageExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSImageExtensions.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/20/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension NSImage {
12 | func write(to url: URL, fileType: NSBitmapImageRep.FileType, options: Data.WritingOptions = .atomic) -> Bool {
13 | do {
14 | if let bits = representations.first as? NSBitmapImageRep {
15 | let data = bits.representation(using: fileType, properties: [:])
16 | try data?.write(to: url, options: options)
17 | }
18 | return true
19 | } catch {
20 | print(error)
21 | return false
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/allyourpasswords/Extensions/NSTableViewExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSTableViewExtension.swift
3 | // allyourpasswords
4 | //
5 | // File created by cognophile on 15/04/2019.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension NSTableView {
12 | open override func mouseDown(with event: NSEvent) {
13 | super.mouseDown(with: event)
14 |
15 | let globalLocation = event.locationInWindow
16 | let localLocation = self.convert(globalLocation, to: nil)
17 | let selectedRow = self.row(at: localLocation)
18 |
19 | if (selectedRow != -1) {
20 | (self.delegate as? NSTableViewClickableDelegate)?.tableView(self, didClickRow: selectedRow)
21 | }
22 | }
23 | }
24 |
25 | protocol NSTableViewClickableDelegate: NSTableViewDelegate {
26 | func tableView(_ tableView: NSTableView, didClickRow selectedRow: Int)
27 | }
28 |
--------------------------------------------------------------------------------
/allyourpasswords/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 | APPL
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | 10
23 | LSApplicationCategoryType
24 | public.app-category.utilities
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Copyright © 2019 Sean Walker. All rights reserved.
29 | NSMainStoryboardFile
30 | Main
31 | NSPrincipalClass
32 | NSApplication
33 | SUFeedURL
34 | https://allyourpasswords.com/appcast.xml
35 | SUPublicEDKey
36 | Y6Qy/oZULI6rGWvsxvplO9Oo+N9C6aDKDprFoZS45Jc=
37 |
38 |
39 |
--------------------------------------------------------------------------------
/allyourpasswords/KeychainWrapper/KeychainItemAccessibility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeychainOptions.swift
3 | // SwiftKeychainWrapper
4 | //
5 | // Created by James Blair on 4/24/16.
6 | // Copyright © 2016 Jason Rendel. All rights reserved.
7 | //
8 | // The MIT License (MIT)
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in all
18 | // copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | // SOFTWARE.
27 |
28 | import Foundation
29 |
30 | protocol KeychainAttrRepresentable {
31 | var keychainAttrValue: CFString { get }
32 | }
33 |
34 | // MARK: - KeychainItemAccessibility
35 | public enum KeychainItemAccessibility {
36 | /**
37 | The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user.
38 |
39 | After the first unlock, the data remains accessible until the next restart. This is recommended for items that need to be accessed by background applications. Items with this attribute migrate to a new device when using encrypted backups.
40 | */
41 | @available(iOS 4, *)
42 | case afterFirstUnlock
43 |
44 | /**
45 | The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user.
46 |
47 | After the first unlock, the data remains accessible until the next restart. This is recommended for items that need to be accessed by background applications. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present.
48 | */
49 | @available(iOS 4, *)
50 | case afterFirstUnlockThisDeviceOnly
51 |
52 | /**
53 | The data in the keychain item can always be accessed regardless of whether the device is locked.
54 |
55 | This is not recommended for application use. Items with this attribute migrate to a new device when using encrypted backups.
56 | */
57 | @available(iOS 4, *)
58 | case always
59 |
60 | /**
61 | The data in the keychain can only be accessed when the device is unlocked. Only available if a passcode is set on the device.
62 |
63 | This is recommended for items that only need to be accessible while the application is in the foreground. Items with this attribute never migrate to a new device. After a backup is restored to a new device, these items are missing. No items can be stored in this class on devices without a passcode. Disabling the device passcode causes all items in this class to be deleted.
64 | */
65 | @available(iOS 8, *)
66 | case whenPasscodeSetThisDeviceOnly
67 |
68 | /**
69 | The data in the keychain item can always be accessed regardless of whether the device is locked.
70 |
71 | This is not recommended for application use. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present.
72 | */
73 | @available(iOS 4, *)
74 | case alwaysThisDeviceOnly
75 |
76 | /**
77 | The data in the keychain item can be accessed only while the device is unlocked by the user.
78 |
79 | This is recommended for items that need to be accessible only while the application is in the foreground. Items with this attribute migrate to a new device when using encrypted backups.
80 |
81 | This is the default value for keychain items added without explicitly setting an accessibility constant.
82 | */
83 | @available(iOS 4, *)
84 | case whenUnlocked
85 |
86 | /**
87 | The data in the keychain item can be accessed only while the device is unlocked by the user.
88 |
89 | This is recommended for items that need to be accessible only while the application is in the foreground. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present.
90 | */
91 | @available(iOS 4, *)
92 | case whenUnlockedThisDeviceOnly
93 |
94 | static func accessibilityForAttributeValue(_ keychainAttrValue: CFString) -> KeychainItemAccessibility? {
95 | for (key, value) in keychainItemAccessibilityLookup {
96 | if value == keychainAttrValue {
97 | return key
98 | }
99 | }
100 |
101 | return nil
102 | }
103 | }
104 |
105 | private let keychainItemAccessibilityLookup: [KeychainItemAccessibility:CFString] = {
106 | var lookup: [KeychainItemAccessibility:CFString] = [
107 | .afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock,
108 | .afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
109 | .always: kSecAttrAccessibleAlways,
110 | .whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
111 | .alwaysThisDeviceOnly : kSecAttrAccessibleAlwaysThisDeviceOnly,
112 | .whenUnlocked: kSecAttrAccessibleWhenUnlocked,
113 | .whenUnlockedThisDeviceOnly: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
114 | ]
115 |
116 | return lookup
117 | }()
118 |
119 | extension KeychainItemAccessibility : KeychainAttrRepresentable {
120 | internal var keychainAttrValue: CFString {
121 | return keychainItemAccessibilityLookup[self]!
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/allyourpasswords/Models/Login.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Login.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/18/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import SQLite
10 |
11 | public struct Login {
12 | let table = Table("login")
13 | let id = Expression("id")
14 | let name = Expression("name")
15 | let url = Expression("url")
16 | let username = Expression("username")
17 | let email = Expression("email")
18 | let password = Expression("password")
19 |
20 | init() {}
21 | }
22 |
--------------------------------------------------------------------------------
/allyourpasswords/Models/Prop.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Prop.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 2/7/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import SQLite
10 |
11 | public struct Prop {
12 | let table = Table("prop")
13 | let id = Expression("id")
14 | let login = Expression("login")
15 | let name = Expression("name")
16 | let value = Expression("value")
17 |
18 | init() {}
19 | }
20 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/ContainerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContainerViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/18/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SQLite
11 |
12 | class ContainerViewController : NSViewController {
13 |
14 | var db : Connection?
15 | var row : Row?
16 | var firstRow : Row?
17 | var isNew : Bool?
18 | var detailViewController: DetailViewController?
19 | var emptyViewController: EmptyViewController?
20 | var editViewController: EditViewController?
21 |
22 | @IBOutlet weak var containerView: NSView!
23 |
24 | override func viewWillAppear() {
25 | super.viewWillAppear()
26 |
27 | db = Database.open()
28 | let login = Login()
29 | let rowCount = try! db?.scalar(login.table.count)
30 |
31 | firstRow = try! db?.pluck(login.table.limit(0).order(login.name, login.url))
32 |
33 | if (rowCount ?? 0 > 0) {
34 | row = firstRow
35 | showDetailViewController()
36 | } else {
37 | showEmptyViewController()
38 | }
39 | }
40 |
41 | override func viewDidLoad() {
42 | super.viewDidLoad()
43 | }
44 |
45 | func showDetailViewController() {
46 | if let oldViewController = detailViewController {
47 | oldViewController.view.removeFromSuperview()
48 | oldViewController.removeFromParent()
49 | detailViewController = nil
50 | }
51 |
52 | if let oldViewController = editViewController {
53 | oldViewController.view.removeFromSuperview()
54 | oldViewController.removeFromParent()
55 | editViewController = nil
56 | }
57 |
58 | if let oldViewController = emptyViewController {
59 | oldViewController.view.removeFromSuperview()
60 | oldViewController.removeFromParent()
61 | emptyViewController = nil
62 | }
63 |
64 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
65 | detailViewController = storyboard.instantiateController(withIdentifier: "DetailViewController") as? DetailViewController
66 | detailViewController!.row = row ?? firstRow
67 |
68 | addChild(detailViewController!)
69 | detailViewController!.view.frame = containerView.bounds
70 | containerView.addSubview(detailViewController!.view)
71 | }
72 |
73 | func showEmptyViewController() {
74 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
75 |
76 | if let oldViewController = emptyViewController {
77 | oldViewController.view.removeFromSuperview()
78 | oldViewController.removeFromParent()
79 | emptyViewController = nil
80 | }
81 |
82 | if let oldViewController = detailViewController {
83 | oldViewController.view.removeFromSuperview()
84 | oldViewController.removeFromParent()
85 | detailViewController = nil
86 | }
87 |
88 | if let oldViewController = editViewController {
89 | oldViewController.view.removeFromSuperview()
90 | oldViewController.removeFromParent()
91 | editViewController = nil
92 | }
93 |
94 | emptyViewController = storyboard.instantiateController(withIdentifier: "EmptyViewController") as? EmptyViewController
95 |
96 | addChild(emptyViewController!)
97 | emptyViewController!.view.frame = containerView.bounds
98 | containerView.addSubview(emptyViewController!.view)
99 | }
100 |
101 | func showEditViewController() {
102 | if let oldViewController = editViewController {
103 | oldViewController.view.removeFromSuperview()
104 | oldViewController.removeFromParent()
105 | editViewController = nil
106 | }
107 |
108 | if let oldViewController = detailViewController {
109 | oldViewController.view.removeFromSuperview()
110 | oldViewController.removeFromParent()
111 | detailViewController = nil
112 | }
113 |
114 | if let oldViewController = emptyViewController {
115 | oldViewController.view.removeFromSuperview()
116 | oldViewController.removeFromParent()
117 | emptyViewController = nil
118 | }
119 |
120 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
121 | editViewController = storyboard.instantiateController(withIdentifier: "EditViewController") as? EditViewController
122 | editViewController!.row = row
123 | editViewController!.db = db
124 | editViewController!.isNew = isNew
125 |
126 | addChild(editViewController!)
127 | editViewController!.view.frame = containerView.bounds
128 | containerView.addSubview(editViewController!.view)
129 | }
130 |
131 | @IBAction func addNewLogin(_ sender: NSMenuItem) {
132 | showEditViewController()
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/CustomTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomTableViewCell.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class CustomTableCellView : NSTableCellView {
12 | @IBOutlet weak var nameOrUrl: NSTextField!
13 | @IBOutlet weak var emailOrUsername: NSTextField!
14 | @IBOutlet weak var favicon: NSImageView!
15 | }
16 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/DetailViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DetailViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/18/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SQLite
11 |
12 | class DetailViewController : NSViewController {
13 |
14 | var row : Row?
15 | let login = Login()
16 | @IBOutlet weak var nameOrUrl: HyperlinkTextField!
17 | @IBOutlet weak var favicon: NSImageView!
18 | @IBOutlet weak var email: NSTextField!
19 | @IBOutlet weak var username: NSTextField!
20 | @IBOutlet weak var password: NSSecureTextField!
21 | @IBOutlet weak var toolbarView: NSView!
22 | @IBOutlet weak var plaintText: NSTextField!
23 | @IBOutlet weak var showButton: NSButton!
24 |
25 | override func viewDidLoad() {
26 | super.viewDidLoad()
27 |
28 | let emailValue = row?[login.email]
29 | if (emailValue ?? "").isEmpty {
30 | email.stringValue = "---"
31 | } else {
32 | email.stringValue = emailValue!
33 | }
34 |
35 | let usernameValue = row?[login.username]
36 | if (usernameValue ?? "").isEmpty {
37 | username.stringValue = "---"
38 | } else {
39 | username.stringValue = usernameValue!
40 | }
41 |
42 | let nameValue = row?[login.name]
43 | if (nameValue ?? "").isEmpty {
44 | nameOrUrl.stringValue = row?[login.url] ?? ""
45 | nameOrUrl.href = row?[login.url] ?? ""
46 | } else {
47 | nameOrUrl.stringValue = nameValue ?? ""
48 | nameOrUrl.href = row?[login.url] ?? ""
49 | }
50 |
51 | let passwordValue = row?[login.password]
52 | if (passwordValue ?? "").isEmpty {
53 | password.stringValue = "---"
54 | } else {
55 | password.stringValue = row?[login.password] ?? ""
56 | }
57 |
58 | let path = NSSearchPathForDirectoriesInDomains(
59 | .applicationSupportDirectory, .userDomainMask, true
60 | ).first! + "/" + Bundle.main.bundleIdentifier!
61 | let url = URL(string: row?[login.url] ?? "")
62 | let domain = url?.host
63 | let str = "\(path)/\(domain ?? "").png"
64 | let image = NSImage(contentsOfFile: str)
65 | favicon.image = image
66 | }
67 |
68 | @IBAction func editButtonClicked(_ sender: NSButton) {
69 | let container = self.parent as! ContainerViewController
70 | container.row = row
71 | container.isNew = false
72 | container.showEditViewController()
73 | }
74 |
75 | func copyToPasteBoard(_ string: String) {
76 | let pasteBoard = NSPasteboard.general
77 | pasteBoard.clearContents()
78 | pasteBoard.setString(string, forType: .string)
79 | }
80 |
81 | @IBAction func copyEmailClicked(_ sender: NSButton) {
82 | copyToPasteBoard(email.stringValue)
83 | }
84 |
85 | @IBAction func copyPasswordClicked(_ sender: NSButton) {
86 | copyToPasteBoard(password.stringValue)
87 | }
88 |
89 | @IBAction func copyUsernameClicked(_ sender: NSButton) {
90 | copyToPasteBoard(username.stringValue)
91 | }
92 |
93 | @IBAction func showButtonClicked(_ sender: NSButton) {
94 | plaintText.stringValue = password.stringValue
95 | plaintText.isHidden = !plaintText.isHidden
96 | password.isHidden = !password.isHidden
97 | if plaintText.isHidden {
98 | showButton.title = "Show"
99 | } else {
100 | showButton.title = "Hide"
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/EditViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EditViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/18/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SQLite
11 | import FavIcon
12 |
13 | class EditViewController : NSViewController {
14 |
15 | var row : Row?
16 | var isNew : Bool?
17 | let login = Login()
18 | var db : Connection?
19 |
20 | @IBOutlet weak var emailTextField: NSTextField!
21 | @IBOutlet weak var usernameTextField: NSTextField!
22 | @IBOutlet weak var passwordTextField: NSTextField!
23 | @IBOutlet weak var websiteTextField: NSTextField!
24 | @IBOutlet weak var nameTextField: NSTextField!
25 | @IBOutlet weak var passwordLengthLabel: NSTextField!
26 | @IBOutlet weak var numberButton: NSButton!
27 | @IBOutlet weak var symbolButton: NSButton!
28 | @IBOutlet weak var passwordLengthSlider: NSSlider!
29 | @IBOutlet weak var saveButton: NSButton!
30 | @IBOutlet weak var faviconImageView: NSImageView!
31 |
32 | override func viewDidLoad() {
33 | super.viewDidLoad()
34 |
35 | self.view.window?.defaultButtonCell = saveButton.cell as? NSButtonCell
36 |
37 | websiteTextField.becomeFirstResponder()
38 |
39 | if isNew == true {
40 | passwordTextField.stringValue = randomString(passwordLengthSlider.integerValue)
41 | passwordLengthLabel.stringValue = "\(passwordTextField.stringValue.count)"
42 | } else {
43 | emailTextField.stringValue = row?[login.email] ?? ""
44 | usernameTextField.stringValue = row?[login.username] ?? ""
45 | passwordTextField.stringValue = row?[login.password] ?? ""
46 | websiteTextField.stringValue = row?[login.url] ?? ""
47 | nameTextField.stringValue = row?[login.name] ?? ""
48 | passwordLengthLabel.stringValue = "\(passwordTextField.stringValue.count)"
49 | let path = NSSearchPathForDirectoriesInDomains(
50 | .applicationSupportDirectory, .userDomainMask, true
51 | ).first! + "/" + Bundle.main.bundleIdentifier!
52 | let url = URL(string: row?[login.url] ?? "")
53 | let domain = url?.host
54 | let str = "\(path)/\(domain ?? "").png"
55 | let image = NSImage(contentsOfFile: str)
56 | faviconImageView.image = image
57 | }
58 | }
59 | @IBAction func websiteDidEndEditing(_ sender: NSTextField) {
60 | let urlString = sender.stringValue
61 | let url = URL(string: urlString)
62 | let domain = url?.host
63 | if nameTextField.stringValue.isEmpty {
64 | nameTextField.stringValue = domain ?? ""
65 | }
66 |
67 | do {
68 | if url != nil {
69 | try FavIcon.downloadPreferred(url!, width: 152, height: 152) { result in
70 | if case let .success(image) = result {
71 | let path = NSSearchPathForDirectoriesInDomains(
72 | .applicationSupportDirectory, .userDomainMask, true
73 | ).first! + "/" + Bundle.main.bundleIdentifier!
74 | let url = NSURL(fileURLWithPath: "\(path)/\(domain!).png").filePathURL!
75 | image.write(to: url, fileType: .png)
76 | }
77 | }
78 | }
79 | } catch {
80 | print("Error: \(error)")
81 |
82 | }
83 | }
84 |
85 | func saveLogin() {
86 | if emailTextField.stringValue.isEmpty &&
87 | usernameTextField.stringValue.isEmpty &&
88 | nameTextField.stringValue.isEmpty &&
89 | websiteTextField.stringValue.isEmpty {
90 | return
91 | }
92 |
93 | if isNew == true {
94 | let insert = login.table.insert(
95 | login.email <- emailTextField.stringValue,
96 | login.username <- usernameTextField.stringValue,
97 | login.password <- passwordTextField.stringValue,
98 | login.name <- nameTextField.stringValue,
99 | login.url <- websiteTextField.stringValue)
100 |
101 | try! db?.run(insert)
102 |
103 | let query = login.table.order(login.id.desc).limit(1)
104 |
105 | row = try! db?.pluck(query)
106 | } else {
107 | let editRow = login.table.filter(login.id == row?[login.id] ?? -1)
108 |
109 | let update = editRow.update(
110 | login.email <- emailTextField.stringValue,
111 | login.username <- usernameTextField.stringValue,
112 | login.password <- passwordTextField.stringValue,
113 | login.name <- nameTextField.stringValue,
114 | login.url <- websiteTextField.stringValue)
115 |
116 | try! db?.run(update)
117 |
118 | row = try! db?.pluck(login.table.filter(login.id == row?[login.id] ?? -1))
119 | }
120 |
121 | let container = self.parent as! ContainerViewController
122 | container.row = row
123 | container.showDetailViewController()
124 |
125 | let userInfo = ["id": row?[login.id]]
126 |
127 | NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTableView"), object: nil, userInfo: userInfo as [AnyHashable : Any])
128 | }
129 |
130 | @IBAction func saveLogin(_ sender: NSMenuItem) {
131 | saveLogin()
132 | }
133 |
134 | @IBAction func saveButtonClicked(_ sender: NSButton) {
135 | saveLogin()
136 | }
137 |
138 | @IBAction func cancelButtonClicked(_ sender: NSButton) {
139 | let container = self.parent as! ContainerViewController
140 | let rowCount = try! db?.scalar(login.table.count)
141 |
142 | if rowCount ?? 0 > 0 {
143 | container.row = self.row
144 | container.showDetailViewController()
145 | } else {
146 | container.showEmptyViewController()
147 | }
148 | }
149 |
150 | func randomString(_ length: Int) -> String {
151 | var numberValues = ""
152 | if numberButton.state == .on {
153 | numberValues = "123456790"
154 | }
155 |
156 | var symbolValues = ""
157 | if symbolButton.state == .on {
158 | symbolValues = "!@#$%^&*()-_"
159 | }
160 |
161 | let values = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\(numberValues)\(symbolValues)"
162 | return String((0...length-1).map{ _ in values.randomElement()! })
163 | }
164 |
165 | @IBAction func sliderChanged(_ sender: NSSlider) {
166 | let passwordLength = sender.integerValue
167 | let password = randomString(passwordLength)
168 | passwordLengthLabel.stringValue = "\(passwordLength)"
169 | passwordTextField.stringValue = password
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/EmptyViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmptyViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/19/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class EmptyViewController : NSViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | }
16 |
17 | @IBAction func addPasswordClicked(_ sender: NSButton) {
18 | let container = self.parent as! ContainerViewController
19 | container.row = nil
20 | container.isNew = true
21 | container.showEditViewController()
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/ResetMasterPasswordViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResetMasterPasswordViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/29/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SQLite
11 |
12 | class ResetMasterPasswordViewController : NSViewController {
13 | @IBOutlet weak var currentPasswordTextField: NSTextField!
14 | @IBOutlet weak var newPasswordTextField: NSTextField!
15 | @IBOutlet weak var confirmPasswordTextField: NSTextField!
16 | var db : Connection?
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | db = Database.open()
22 | }
23 |
24 | @IBAction func cancelButtonClicked(_ sender: NSButton) {
25 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
26 | let viewController = storyboard.instantiateController(withIdentifier: "MainViewController") as! MainViewController
27 | self.view.window?.contentViewController = viewController
28 | }
29 |
30 | @IBAction func okButtonClicked(_ sender: NSButton) {
31 | let masterPassword = KeychainWrapper.standard.string(forKey: "MasterPassword")
32 |
33 | if !newPasswordTextField.stringValue.isEmpty &&
34 | newPasswordTextField.stringValue == confirmPasswordTextField.stringValue &&
35 | currentPasswordTextField.stringValue == masterPassword ?? "" &&
36 | !(masterPassword ?? "").isEmpty &&
37 | KeychainWrapper.standard.set(newPasswordTextField.stringValue, forKey: "MasterPassword") {
38 | try! db?.rekey(newPasswordTextField.stringValue)
39 |
40 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
41 | let viewController = storyboard.instantiateController(withIdentifier: "MainViewController") as! MainViewController
42 | self.view.window?.contentViewController = viewController
43 | } else {
44 | self.view.window?.shakeWindow()
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/SetMasterPasswordViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SetMasterPasswordViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class SetMasterPasswordViewController: NSViewController {
12 | @IBOutlet weak var masterPasswordTextField: NSTextField!
13 |
14 | @IBAction func setPasswordClicked(_ sender: NSButton) {
15 | if masterPasswordTextField.stringValue.count > 0 {
16 | setMasterPassword(masterPasswordTextField.stringValue)
17 | }
18 | }
19 |
20 | @IBAction func masterPasswordTextFieldEnterPressed(_ sender: NSTextField) {
21 | if masterPasswordTextField.stringValue.count > 0 {
22 | setMasterPassword(masterPasswordTextField.stringValue)
23 | }
24 | }
25 |
26 | override func viewDidLoad() {
27 | super.viewDidLoad()
28 | }
29 |
30 | func setMasterPassword(_ masterPassword: String) {
31 | if KeychainWrapper.standard.set(masterPassword, forKey: "MasterPassword") {
32 | let db = Database.open()
33 | let login = Login()
34 |
35 | try! db.run(login.table.create(ifNotExists: true) { t in
36 | t.column(login.id, primaryKey: true)
37 | t.column(login.name)
38 | t.column(login.username)
39 | t.column(login.email)
40 | t.column(login.url)
41 | t.column(login.password)
42 | })
43 |
44 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
45 | let viewController = storyboard.instantiateController(withIdentifier: "MainViewController") as! MainViewController
46 | self.view.window?.contentViewController = viewController
47 | }
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/TableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/18/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SQLite
11 |
12 | class TableViewController : NSViewController, NSTableViewDelegate, NSTableViewDataSource, NSSearchFieldDelegate, NSTableViewClickableDelegate {
13 | @IBOutlet weak var tableView: NSTableView!
14 | @IBOutlet weak var searchField: NSSearchField!
15 | @IBOutlet weak var addButton: NSButton!
16 |
17 | var rows : [Row]?
18 | var filteredRows : [Row]?
19 | var row : Row?
20 | var db : Connection?
21 | let login = Login()
22 | var containerViewController : ContainerViewController?
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 |
27 | NotificationCenter.default.addObserver(self, selector: #selector(reloadTableView), name: NSNotification.Name(rawValue: "reloadTableView"), object: nil)
28 |
29 | tableView.delegate = self
30 | tableView.dataSource = self
31 | searchField.delegate = self
32 |
33 | db = Database.open()
34 |
35 | reloadTableView()
36 | }
37 |
38 | @objc func reloadTableView(_ notification: NSNotification? = nil) {
39 | let query = login.table.order(login.name, login.url)
40 | rows = Array((try! db?.prepare(query))!)
41 | filteredRows = rows
42 | tableView.reloadData()
43 | var index : Int = 0
44 |
45 | if let userInfo = notification?.userInfo {
46 | let id = userInfo["id"] as? Int64
47 | index = filteredRows?.firstIndex(where: { $0[login.id] == id }) ?? 0
48 | }
49 |
50 | if (filteredRows?.count)! > 0 {
51 | tableView.selectRowIndexes(NSIndexSet(index: index) as IndexSet, byExtendingSelection: false)
52 | tableView.scrollRowToVisible(index)
53 | containerViewController?.row = rows?[index]
54 | containerViewController?.showDetailViewController()
55 | } else {
56 | containerViewController?.showEmptyViewController()
57 | }
58 | }
59 |
60 | func controlTextDidChange(_ obj: Notification) {
61 | if obj.object as? NSSearchField == searchField {
62 | filterWithString(searchField.stringValue)
63 | }
64 | }
65 |
66 | func filterWithString(_ searchFieldValue: String) {
67 | if searchFieldValue.count > 0 {
68 | filteredRows = rows?.filter { r in
69 | return (r[login.name]?.lowercased().contains(searchFieldValue.lowercased()))! ||
70 | (r[login.username]?.lowercased().contains(searchFieldValue.lowercased()))! ||
71 | (r[login.email]?.lowercased().contains(searchFieldValue.lowercased()))!
72 | }
73 | } else {
74 | filteredRows = rows
75 | }
76 |
77 | tableView.reloadData()
78 |
79 | if(filteredRows?.count == 1) {
80 | tableView.selectRowIndexes(NSIndexSet(index: 0) as IndexSet, byExtendingSelection: false)
81 | }
82 | }
83 |
84 | func numberOfRows(in tableView: NSTableView) -> Int {
85 | return filteredRows?.count ?? 0
86 | }
87 |
88 | func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
89 | return 64
90 | }
91 |
92 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
93 | let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CustomTableCellView"), owner: self) as? CustomTableCellView
94 |
95 | guard let item = filteredRows?[row] else {
96 | return nil
97 | }
98 |
99 | if item[login.name]?.count ?? 0 > 0 {
100 | cell?.nameOrUrl.stringValue = item[login.name] ?? ""
101 | } else {
102 | cell?.nameOrUrl.stringValue = item[login.url] ?? ""
103 | }
104 |
105 | if item[login.email]?.count ?? 0 > 0 {
106 | cell?.emailOrUsername.stringValue = item[login.email] ?? ""
107 | } else {
108 | cell?.emailOrUsername.stringValue = item[login.username] ?? ""
109 | }
110 |
111 | let path = NSSearchPathForDirectoriesInDomains(
112 | .applicationSupportDirectory, .userDomainMask, true
113 | ).first! + "/" + Bundle.main.bundleIdentifier!
114 | let url = URL(string: item[login.url]!)
115 | let domain = url?.host
116 | let str = "\(path)/\(domain ?? "").png"
117 | let image = NSImage(contentsOfFile: str)
118 | cell?.favicon.image = image
119 |
120 | return cell
121 | }
122 |
123 | @nonobjc func tableView(_ tableView: NSTableView, didClickRow selectedRow: Int) {
124 | tableView.selectRowIndexes(NSIndexSet(index: selectedRow) as IndexSet, byExtendingSelection: false)
125 | tableView.scrollRowToVisible(selectedRow)
126 |
127 | if selectedRow > -1, selectedRow < filteredRows?.count ?? 0 {
128 | self.row = filteredRows?[selectedRow]
129 | containerViewController?.row = self.row
130 | containerViewController?.showDetailViewController()
131 | }
132 | }
133 |
134 | @IBAction func addButtonClicked(_ sender: NSButton) {
135 | searchField.resignFirstResponder()
136 | containerViewController?.row = row
137 | containerViewController?.isNew = true
138 | containerViewController?.showEditViewController()
139 | }
140 |
141 | func dialogOKCancel(question: String, text: String) -> Bool {
142 | let alert = NSAlert()
143 | alert.messageText = question
144 | alert.informativeText = text
145 | alert.alertStyle = .warning
146 | alert.addButton(withTitle: "OK")
147 | alert.addButton(withTitle: "Cancel")
148 | return alert.runModal() == .alertFirstButtonReturn
149 | }
150 |
151 | @IBAction func deleteLogin(_ sender: NSMenuItem) {
152 | let indices = tableView.selectedRowIndexes
153 | let ids = indices.compactMap { (filteredRows?.count ?? -1 > $0) ? filteredRows?[$0][login.id] : nil}
154 | let answer = dialogOKCancel(question: "Are you sure you want to delete \(ids.count) login(s)?", text: "")
155 |
156 | if answer == true {
157 | do {
158 | let lg = login.table.filter(ids.contains(login.id))
159 | if try db?.run(lg.delete()) ?? 0 > 0 {
160 | reloadTableView()
161 | } else {
162 | print("login not found")
163 | }
164 | } catch {
165 | print("delete failed: \(error)")
166 | }
167 | }
168 | }
169 |
170 | func copyToPasteBoard(_ string: String) {
171 | let pasteBoard = NSPasteboard.general
172 | pasteBoard.clearContents()
173 | pasteBoard.setString(string, forType: .string)
174 | }
175 |
176 | @IBAction func copy(_ sender: NSMenuItem) {
177 | copyToPasteBoard(row?[login.password] ?? "")
178 | }
179 |
180 | @IBAction func copyEmailOrUsername(_ sender: NSMenuItem) {
181 | if row?[login.email] != nil && row?[login.email] != "" {
182 | copyToPasteBoard(row?[login.email] ?? "")
183 | } else {
184 | copyToPasteBoard(row?[login.username] ?? "")
185 | }
186 | }
187 |
188 | @IBAction func copyPassword(_ sender: NSMenuItem) {
189 | copyToPasteBoard(row?[login.password] ?? "")
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/ToolbarCustomView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ToolbarCustomView.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/19/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ToolbarCustomView: NSView {
12 |
13 | var gradient:NSGradient! = nil
14 |
15 | override func draw(_ dirtyRect: NSRect) {
16 | super.draw(dirtyRect)
17 |
18 | self.wantsLayer = true
19 | self.needsDisplay = true;
20 | self.layer?.masksToBounds = true
21 |
22 | let startingColor:NSColor = NSColor(red: 244/256, green: 244/256, blue: 244/256, alpha: 1.0)
23 | let endingColor:NSColor = NSColor(red: 203/256, green: 203/256, blue: 203/256, alpha: 1.0)
24 |
25 | gradient = NSGradient(starting: startingColor, ending: endingColor)!;
26 |
27 | if self.window?.isKeyWindow == true {
28 | gradient.draw(in: self.bounds, angle: 270 )
29 | }else{
30 | self.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
31 | }
32 |
33 | //The bottom border
34 | self.layer?.borderColor = NSColor(red: 160/256, green: 160/256, blue: 160/256, alpha: 1).cgColor;
35 |
36 |
37 | //Recieve window key status notification and force redraw of the custom toolbar to update the background
38 | // NotificationCenter.default.setObserver(self, selector: #selector(ToolbarCustomView.handleParentWindowStateChange(_:)) , name: NSNotification.Name.NSWindowDidBecomeKey.rawValue, object: self.window)
39 | // NotificationCenter.default.setObserver(self, selector: #selector(ToolbarCustomView.handleParentWindowStateChange(_:)) , name: NSNotification.Name.NSWindowDidResignKey.rawValue, object: self.window)
40 |
41 | }
42 |
43 |
44 |
45 | func handleParentWindowStateChange(_ notification:Notification) {
46 |
47 | //The background
48 | //self.needsDisplay = true;
49 | //self.needsLayout = true
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/allyourpasswords/Views/UnlockViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UnlockViewController.swift
3 | // allyourpasswords
4 | //
5 | // Created by Sean Walker on 1/17/19.
6 | // Copyright © 2019 Sean Walker. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import SQLite
11 | import LocalAuthentication
12 |
13 | extension NSWindow {
14 | func shakeWindow(){
15 | let numberOfShakes = 3
16 | let durationOfShake = 0.7
17 | let vigourOfShake : CGFloat = 0.01
18 | let frame : CGRect = self.frame
19 | let shakeAnimation :CAKeyframeAnimation = CAKeyframeAnimation()
20 |
21 | let shakePath = CGMutablePath()
22 | shakePath.move( to: CGPoint(x:NSMinX(frame), y:NSMinY(frame)))
23 |
24 | for _ in 0...numberOfShakes-1 {
25 | shakePath.addLine(to: CGPoint(x:NSMinX(frame) - frame.size.width * vigourOfShake, y:NSMinY(frame)))
26 | shakePath.addLine(to: CGPoint(x:NSMinX(frame) + frame.size.width * vigourOfShake, y:NSMinY(frame)))
27 | }
28 |
29 | shakePath.closeSubpath()
30 | shakeAnimation.path = shakePath
31 | shakeAnimation.duration = durationOfShake
32 |
33 | self.animations = ["frameOrigin":shakeAnimation]
34 | self.animator().setFrameOrigin(self.frame.origin)
35 | }
36 | }
37 |
38 | class UnlockViewController: NSViewController {
39 | @IBOutlet weak var masterPasswordTextField: NSTextField!
40 |
41 | override func viewDidLoad() {
42 | super.viewDidLoad()
43 |
44 | showTouchID()
45 | }
46 | @IBAction func unlockWithTouchID(_ sender: NSButton) {
47 | showTouchID()
48 | }
49 |
50 | func showTouchID() {
51 | let context = LAContext()
52 | context.localizedCancelTitle = "Cancel"
53 | context.localizedFallbackTitle = "Unlock with password"
54 |
55 | var error: NSError?
56 | if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
57 | let reason = "unlock AllYourPasswords"
58 |
59 | context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason ) { success, error in
60 |
61 | if success {
62 | // Move to the main thread because a state update triggers UI changes.
63 | DispatchQueue.main.async { [unowned self] in
64 | self.showPasswords()
65 | }
66 |
67 | } else {
68 | print(error?.localizedDescription ?? "Failed to authenticate")
69 | }
70 | }
71 | }
72 | }
73 |
74 | func showPasswords() {
75 | let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
76 | let viewController = storyboard.instantiateController(withIdentifier: "MainViewController") as! NSSplitViewController
77 | self.view.window?.contentViewController = viewController
78 |
79 | NotificationCenter.default.post(name: NSNotification.Name(rawValue: "enableChangeMasterPasswordMenuItem"), object: nil)
80 | }
81 |
82 | func unlockApp() {
83 | if let masterPassword = KeychainWrapper.standard.string(forKey: "MasterPassword") {
84 | if masterPassword == masterPasswordTextField.stringValue {
85 | showPasswords()
86 | } else {
87 | self.view.window?.shakeWindow()
88 | }
89 | }
90 | }
91 |
92 | @IBAction func unlockPressed(_ sender: NSButton) {
93 | unlockApp()
94 | }
95 |
96 | @IBAction func enterPressed(_ sender: NSTextField) {
97 | unlockApp()
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/allyourpasswords/allyourpasswords.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 | com.apple.security.network.client
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/quick.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/swlkr/allyourpasswords/fc109eb2b33e987f8c18dd5d8f7014f4139e5b35/quick.gif
--------------------------------------------------------------------------------