├── .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 [![License](https://img.shields.io/badge/license-Apache%202.0-lightgrey.svg)](https://raw.githubusercontent.com/leonbreedt/FavIcon/master/LICENSE) [![Build Status](https://travis-ci.org/leonbreedt/FavIcon.svg)](https://travis-ci.org/leonbreedt/FavIcon) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) ![Swift 4.0](https://img.shields.io/badge/Swift-4.0-orange.svg) ![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20macOS%20-lightgrey.svg) 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 | ![](quick.gif) 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 --------------------------------------------------------------------------------