Move codes to an embed framework
- Move bundle/group identifiers to passKit/Global - Fix Core Data - Change Defaults to SharedDefaults
This commit is contained in:
parent
850dc75820
commit
d2ba620ae4
45 changed files with 1062 additions and 523 deletions
22
PassKitTests/Info.plist
Normal file
22
PassKitTests/Info.plist
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>BNDL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
36
PassKitTests/passKitTests.swift
Normal file
36
PassKitTests/passKitTests.swift
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// passKitTests.swift
|
||||||
|
// passKitTests
|
||||||
|
//
|
||||||
|
// Created by Yishi Lin on 11/6/17.
|
||||||
|
// Copyright © 2017年 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import passKit
|
||||||
|
|
||||||
|
class passKitTests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testExample() {
|
||||||
|
// This is an example of a functional test case.
|
||||||
|
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPerformanceExample() {
|
||||||
|
// This is an example of a performance test case.
|
||||||
|
self.measure {
|
||||||
|
// Put the code you want to measure the time of here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
44
Podfile
44
Podfile
|
|
@ -1,3 +1,47 @@
|
||||||
|
def generate_modulemap(name, path)
|
||||||
|
f = File.new(File.join("#{path}/module.modulemap"), "w+")
|
||||||
|
module_name = "#{name}"
|
||||||
|
while(module_name["+"])
|
||||||
|
module_name["+"] = "_"
|
||||||
|
end
|
||||||
|
f.puts("module #{module_name} {")
|
||||||
|
f.puts(" umbrella header \"#{name}_umbrella.h\"")
|
||||||
|
f.puts(" export *")
|
||||||
|
f.puts("}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_umbrella(name, path)
|
||||||
|
f = File.new(File.join("#{path}/#{name}_umbrella.h"), "w+")
|
||||||
|
f.puts("#import <Foundation/Foundation.h>")
|
||||||
|
Dir.chdir(path) {
|
||||||
|
Dir.glob("**/*.h").map {
|
||||||
|
|filename| f.puts("#import \"#{filename}\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
require "fileutils"
|
||||||
|
headers_path = "#{Dir::pwd}/Pods/Headers/Public/"
|
||||||
|
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
target_header_path = "#{headers_path}#{target.product_name}"
|
||||||
|
if File.exist?(target_header_path)
|
||||||
|
filename = target.product_name
|
||||||
|
if filename != "." and filename != ".."
|
||||||
|
generate_umbrella(filename, target_header_path)
|
||||||
|
generate_modulemap(filename, target_header_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
target 'pass' do
|
target 'pass' do
|
||||||
pod 'ObjectivePGP', :git => 'https://github.com/mssun/ObjectivePGP.git'
|
pod 'ObjectivePGP', :git => 'https://github.com/mssun/ObjectivePGP.git'
|
||||||
|
target 'passKit' do
|
||||||
|
inherit! :search_paths
|
||||||
|
end
|
||||||
|
target 'passextension' do
|
||||||
|
inherit! :search_paths
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,108 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "0820"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
|
||||||
BuildableName = "pass.app"
|
|
||||||
BlueprintName = "pass"
|
|
||||||
ReferencedContainer = "container:pass.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<Testables>
|
|
||||||
<TestableReference
|
|
||||||
skipped = "NO">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "DC13B14D1E8640810097803F"
|
|
||||||
BuildableName = "passTests.xctest"
|
|
||||||
BlueprintName = "passTests"
|
|
||||||
ReferencedContainer = "container:pass.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</TestableReference>
|
|
||||||
</Testables>
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
|
||||||
BuildableName = "pass.app"
|
|
||||||
BlueprintName = "pass"
|
|
||||||
ReferencedContainer = "container:pass.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
|
||||||
BuildableName = "pass.app"
|
|
||||||
BlueprintName = "pass"
|
|
||||||
ReferencedContainer = "container:pass.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
<EnvironmentVariables>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "OS_ACTIVITY_MODE"
|
|
||||||
value = "disable"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
</EnvironmentVariables>
|
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<BuildableProductRunnable
|
|
||||||
runnableDebuggingMode = "0">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
|
|
||||||
BuildableName = "pass.app"
|
|
||||||
BlueprintName = "pass"
|
|
||||||
ReferencedContainer = "container:pass.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildableProductRunnable>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
||||||
|
|
@ -10,6 +10,7 @@ import UIKit
|
||||||
import CoreData
|
import CoreData
|
||||||
import PasscodeLock
|
import PasscodeLock
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
import passKit
|
||||||
|
|
||||||
@UIApplicationMain
|
@UIApplicationMain
|
||||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
@ -20,7 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var passcodeLockPresenter: PasscodeLockPresenter = {
|
lazy var passcodeLockPresenter: PasscodeLockPresenter = {
|
||||||
let presenter = PasscodeLockPresenter(mainWindow: self.window, configuration: Globals.passcodeConfiguration)
|
let presenter = PasscodeLockPresenter(mainWindow: self.window, configuration: PasscodeLockConfiguration.shared)
|
||||||
return presenter
|
return presenter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -29,9 +30,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100))
|
SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100))
|
||||||
passcodeLockPresenter.present()
|
passcodeLockPresenter.present()
|
||||||
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
|
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
|
||||||
var searchType = Bundle.main.bundleIdentifier!
|
if shortcutItem.type == Globals.bundleIdentifier + ".search" {
|
||||||
searchType.append(".search")
|
|
||||||
if shortcutItem.type == searchType {
|
|
||||||
self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,9 +43,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||||
var searchType = Bundle.main.bundleIdentifier!
|
if shortcutItem.type == Globals.bundleIdentifier + ".search" {
|
||||||
searchType.append(".search")
|
|
||||||
if shortcutItem.type == searchType {
|
|
||||||
let tabBarController = self.window!.rootViewController as! UITabBarController
|
let tabBarController = self.window!.rootViewController as! UITabBarController
|
||||||
tabBarController.selectedIndex = 0
|
tabBarController.selectedIndex = 0
|
||||||
let navigationController = tabBarController.selectedViewController as! UINavigationController
|
let navigationController = tabBarController.selectedViewController as! UINavigationController
|
||||||
|
|
@ -112,9 +109,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
application to it. This property is optional since there are legitimate
|
application to it. This property is optional since there are legitimate
|
||||||
error conditions that could cause the creation of the store to fail.
|
error conditions that could cause the creation of the store to fail.
|
||||||
*/
|
*/
|
||||||
let container = NSPersistentContainer(name: "pass")
|
let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")!
|
||||||
let description = NSPersistentStoreDescription(url: Globals.sharedContainerURL)
|
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
||||||
container.loadPersistentStores(completionHandler: { (description, error) in
|
let container = NSPersistentContainer(name: "pass", managedObjectModel: managedObjectModel!)
|
||||||
|
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: Globals.sharedContainerURL.appendingPathComponent("Documents/pass.sqlite"))]
|
||||||
|
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||||
if let error = error as NSError? {
|
if let error = error as NSError? {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
// Replace this implementation with code to handle the error appropriately.
|
||||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import passKit
|
||||||
|
|
||||||
class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class AddPasswordTableViewController: PasswordEditorTableViewController {
|
class AddPasswordTableViewController: PasswordEditorTableViewController {
|
||||||
var tempContent: String = ""
|
var tempContent: String = ""
|
||||||
|
|
@ -20,7 +20,7 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
||||||
[[.type: PasswordEditorCellType.additionsCell, .title: "additions"]],
|
[[.type: PasswordEditorCellType.additionsCell, .title: "additions"]],
|
||||||
[[.type: PasswordEditorCellType.scanQRCodeCell]]
|
[[.type: PasswordEditorCellType.scanQRCodeCell]]
|
||||||
]
|
]
|
||||||
if let lengthSetting = Globals.passwordDefaultLength[Defaults[.passwordGeneratorFlavor]],
|
if let lengthSetting = Globals.passwordDefaultLength[SharedDefaults[.passwordGeneratorFlavor]],
|
||||||
lengthSetting.max > lengthSetting.min {
|
lengthSetting.max > lengthSetting.min {
|
||||||
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
|
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class AdvancedSettingsTableViewController: UITableViewController {
|
class AdvancedSettingsTableViewController: UITableViewController {
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
encryptInASCIIArmoredSwitch.isOn = Defaults[.encryptInArmored]
|
encryptInASCIIArmoredSwitch.isOn = SharedDefaults[.encryptInArmored]
|
||||||
encryptInASCIIArmoredTableViewCell.accessoryView = encryptInASCIIArmoredSwitch
|
encryptInASCIIArmoredTableViewCell.accessoryView = encryptInASCIIArmoredSwitch
|
||||||
encryptInASCIIArmoredTableViewCell.selectionStyle = .none
|
encryptInASCIIArmoredTableViewCell.selectionStyle = .none
|
||||||
setGitSignatureText()
|
setGitSignatureText()
|
||||||
|
|
@ -39,7 +39,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
||||||
let gitSignatureEmail = passwordStore.gitSignatureForNow.email!
|
let gitSignatureEmail = passwordStore.gitSignatureForNow.email!
|
||||||
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 14)
|
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 14)
|
||||||
self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
|
self.gitSignatureTableViewCell.detailTextLabel?.text = "\(gitSignatureName) <\(gitSignatureEmail)>"
|
||||||
if Defaults[.gitSignatureName] == nil && Defaults[.gitSignatureEmail] == nil {
|
if SharedDefaults[.gitSignatureName] == nil && SharedDefaults[.gitSignatureEmail] == nil {
|
||||||
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 17)
|
self.gitSignatureTableViewCell.detailTextLabel?.font = UIFont.systemFont(ofSize: 17)
|
||||||
gitSignatureTableViewCell.detailTextLabel?.text = "Not Set"
|
gitSignatureTableViewCell.detailTextLabel?.text = "Not Set"
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptInASCIIArmoredAction(_ sender: Any?) {
|
func encryptInASCIIArmoredAction(_ sender: Any?) {
|
||||||
Defaults[.encryptInArmored] = encryptInASCIIArmoredSwitch.isOn
|
SharedDefaults[.encryptInArmored] = encryptInASCIIArmoredSwitch.isOn
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func cancelGitConfigSetting(segue: UIStoryboardSegue) {
|
@IBAction func cancelGitConfigSetting(segue: UIStoryboardSegue) {
|
||||||
|
|
@ -95,8 +95,8 @@ class AdvancedSettingsTableViewController: UITableViewController {
|
||||||
if let controller = segue.source as? GitConfigSettingTableViewController {
|
if let controller = segue.source as? GitConfigSettingTableViewController {
|
||||||
if let gitSignatureName = controller.nameTextField.text,
|
if let gitSignatureName = controller.nameTextField.text,
|
||||||
let gitSignatureEmail = controller.emailTextField.text {
|
let gitSignatureEmail = controller.emailTextField.text {
|
||||||
Defaults[.gitSignatureName] = gitSignatureName.isEmpty ? nil : gitSignatureName
|
SharedDefaults[.gitSignatureName] = gitSignatureName.isEmpty ? nil : gitSignatureName
|
||||||
Defaults[.gitSignatureEmail] = gitSignatureEmail.isEmpty ? nil : gitSignatureEmail
|
SharedDefaults[.gitSignatureEmail] = gitSignatureEmail.isEmpty ? nil : gitSignatureEmail
|
||||||
}
|
}
|
||||||
setGitSignatureText()
|
setGitSignatureText()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import SafariServices
|
import SafariServices
|
||||||
import MessageUI
|
import MessageUI
|
||||||
|
import passKit
|
||||||
|
|
||||||
|
|
||||||
enum CellDataType {
|
enum CellDataType {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import ObjectiveGit
|
import ObjectiveGit
|
||||||
|
import passKit
|
||||||
|
|
||||||
class CommitLogsTableViewController: UITableViewController {
|
class CommitLogsTableViewController: UITableViewController {
|
||||||
var commits: [GTCommit] = []
|
var commits: [GTCommit] = []
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class EditPasswordTableViewController: PasswordEditorTableViewController {
|
class EditPasswordTableViewController: PasswordEditorTableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
|
|
@ -18,7 +18,7 @@ class EditPasswordTableViewController: PasswordEditorTableViewController {
|
||||||
[[.type: PasswordEditorCellType.scanQRCodeCell],
|
[[.type: PasswordEditorCellType.scanQRCodeCell],
|
||||||
[.type: PasswordEditorCellType.deletePasswordCell]]
|
[.type: PasswordEditorCellType.deletePasswordCell]]
|
||||||
]
|
]
|
||||||
if let lengthSetting = Globals.passwordDefaultLength[Defaults[.passwordGeneratorFlavor]],
|
if let lengthSetting = Globals.passwordDefaultLength[SharedDefaults[.passwordGeneratorFlavor]],
|
||||||
lengthSetting.max > lengthSetting.min {
|
lengthSetting.max > lengthSetting.min {
|
||||||
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
|
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
let passwordStore = PasswordStore.shared
|
let passwordStore = PasswordStore.shared
|
||||||
|
|
@ -33,7 +33,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
uiSwitch.onTintColor = Globals.blue
|
uiSwitch.onTintColor = Globals.blue
|
||||||
uiSwitch.sizeToFit()
|
uiSwitch.sizeToFit()
|
||||||
uiSwitch.addTarget(self, action: #selector(rememberPassphraseSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
uiSwitch.addTarget(self, action: #selector(rememberPassphraseSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||||
uiSwitch.isOn = Defaults[.isRememberPassphraseOn]
|
uiSwitch.isOn = SharedDefaults[.isRememberPassphraseOn]
|
||||||
return uiSwitch
|
return uiSwitch
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
uiSwitch.onTintColor = Globals.blue
|
uiSwitch.onTintColor = Globals.blue
|
||||||
uiSwitch.sizeToFit()
|
uiSwitch.sizeToFit()
|
||||||
uiSwitch.addTarget(self, action: #selector(showFolderSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
uiSwitch.addTarget(self, action: #selector(showFolderSwitchAction(_:)), for: UIControlEvents.valueChanged)
|
||||||
uiSwitch.isOn = Defaults[.isShowFolderOn]
|
uiSwitch.isOn = SharedDefaults[.isShowFolderOn]
|
||||||
return uiSwitch
|
return uiSwitch
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
accessoryView.addSubview(hideUnknownSwitch)
|
accessoryView.addSubview(hideUnknownSwitch)
|
||||||
cell.accessoryView = accessoryView
|
cell.accessoryView = accessoryView
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
hideUnknownSwitch.isOn = Defaults[.isHideUnknownOn]
|
hideUnknownSwitch.isOn = SharedDefaults[.isHideUnknownOn]
|
||||||
case "Hide OTP Fields":
|
case "Hide OTP Fields":
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
let detailButton = UIButton(type: .detailDisclosure)
|
let detailButton = UIButton(type: .detailDisclosure)
|
||||||
|
|
@ -97,7 +97,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
accessoryView.addSubview(hideOTPSwitch)
|
accessoryView.addSubview(hideOTPSwitch)
|
||||||
cell.accessoryView = accessoryView
|
cell.accessoryView = accessoryView
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
hideOTPSwitch.isOn = Defaults[.isHideOTPOn]
|
hideOTPSwitch.isOn = SharedDefaults[.isHideOTPOn]
|
||||||
case "Remember Passphrase":
|
case "Remember Passphrase":
|
||||||
cell.accessoryType = .none
|
cell.accessoryType = .none
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
|
|
@ -108,7 +108,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
cell.accessoryView = showFolderSwitch
|
cell.accessoryView = showFolderSwitch
|
||||||
case "Password Generator Flavor":
|
case "Password Generator Flavor":
|
||||||
cell.accessoryType = .disclosureIndicator
|
cell.accessoryType = .disclosureIndicator
|
||||||
cell.detailTextLabel?.text = Defaults[.passwordGeneratorFlavor]
|
cell.detailTextLabel?.text = SharedDefaults[.passwordGeneratorFlavor]
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
return cell
|
return cell
|
||||||
|
|
@ -127,7 +127,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
var randomFlavorActionTitle = ""
|
var randomFlavorActionTitle = ""
|
||||||
var appleFlavorActionTitle = ""
|
var appleFlavorActionTitle = ""
|
||||||
if Defaults[.passwordGeneratorFlavor] == "Random" {
|
if SharedDefaults[.passwordGeneratorFlavor] == "Random" {
|
||||||
randomFlavorActionTitle = "✓ Random String"
|
randomFlavorActionTitle = "✓ Random String"
|
||||||
appleFlavorActionTitle = "Apple's Keychain Style"
|
appleFlavorActionTitle = "Apple's Keychain Style"
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -135,12 +135,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
appleFlavorActionTitle = "✓ Apple's Keychain Style"
|
appleFlavorActionTitle = "✓ Apple's Keychain Style"
|
||||||
}
|
}
|
||||||
let randomFlavorAction = UIAlertAction(title: randomFlavorActionTitle, style: .default) { _ in
|
let randomFlavorAction = UIAlertAction(title: randomFlavorActionTitle, style: .default) { _ in
|
||||||
Defaults[.passwordGeneratorFlavor] = "Random"
|
SharedDefaults[.passwordGeneratorFlavor] = "Random"
|
||||||
sourceCell.detailTextLabel?.text = "Random"
|
sourceCell.detailTextLabel?.text = "Random"
|
||||||
}
|
}
|
||||||
|
|
||||||
let appleFlavorAction = UIAlertAction(title: appleFlavorActionTitle, style: .default) { _ in
|
let appleFlavorAction = UIAlertAction(title: appleFlavorActionTitle, style: .default) { _ in
|
||||||
Defaults[.passwordGeneratorFlavor] = "Apple"
|
SharedDefaults[.passwordGeneratorFlavor] = "Apple"
|
||||||
sourceCell.detailTextLabel?.text = "Apple"
|
sourceCell.detailTextLabel?.text = "Apple"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,24 +167,24 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func hideUnknownSwitchAction(_ sender: Any?) {
|
func hideUnknownSwitchAction(_ sender: Any?) {
|
||||||
Defaults[.isHideUnknownOn] = hideUnknownSwitch.isOn
|
SharedDefaults[.isHideUnknownOn] = hideUnknownSwitch.isOn
|
||||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hideOTPSwitchAction(_ sender: Any?) {
|
func hideOTPSwitchAction(_ sender: Any?) {
|
||||||
Defaults[.isHideOTPOn] = hideOTPSwitch.isOn
|
SharedDefaults[.isHideOTPOn] = hideOTPSwitch.isOn
|
||||||
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rememberPassphraseSwitchAction(_ sender: Any?) {
|
func rememberPassphraseSwitchAction(_ sender: Any?) {
|
||||||
Defaults[.isRememberPassphraseOn] = rememberPassphraseSwitch.isOn
|
SharedDefaults[.isRememberPassphraseOn] = rememberPassphraseSwitch.isOn
|
||||||
if rememberPassphraseSwitch.isOn == false {
|
if rememberPassphraseSwitch.isOn == false {
|
||||||
passwordStore.pgpKeyPassphrase = nil
|
passwordStore.pgpKeyPassphrase = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showFolderSwitchAction(_ sender: Any?) {
|
func showFolderSwitchAction(_ sender: Any?) {
|
||||||
Defaults[.isShowFolderOn] = showFolderSwitch.isOn
|
SharedDefaults[.isShowFolderOn] = showFolderSwitch.isOn
|
||||||
NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil)
|
NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import SwiftyUserDefaults
|
||||||
|
import passKit
|
||||||
|
|
||||||
class GitConfigSettingTableViewController: UITableViewController {
|
class GitConfigSettingTableViewController: UITableViewController {
|
||||||
let passwordStore = PasswordStore.shared
|
let passwordStore = PasswordStore.shared
|
||||||
|
|
@ -22,8 +23,8 @@ class GitConfigSettingTableViewController: UITableViewController {
|
||||||
let signature = passwordStore.gitSignatureForNow
|
let signature = passwordStore.gitSignatureForNow
|
||||||
nameTextField.placeholder = signature.name
|
nameTextField.placeholder = signature.name
|
||||||
emailTextField.placeholder = signature.email
|
emailTextField.placeholder = signature.email
|
||||||
nameTextField.text = Defaults[.gitSignatureName]
|
nameTextField.text = SharedDefaults[.gitSignatureName]
|
||||||
emailTextField.text = Defaults[.gitSignatureEmail]
|
emailTextField.text = SharedDefaults[.gitSignatureEmail]
|
||||||
}
|
}
|
||||||
|
|
||||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
||||||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||||
|
|
@ -73,7 +73,7 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
armorPrivateKeyTextView.text = Defaults[.gitSSHPrivateKeyArmor]
|
armorPrivateKeyTextView.text = SharedDefaults[.gitSSHPrivateKeyArmor]
|
||||||
armorPrivateKeyTextView.delegate = self
|
armorPrivateKeyTextView.delegate = self
|
||||||
|
|
||||||
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
|
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
|
||||||
|
|
@ -83,13 +83,13 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func doneButtonTapped(_ sender: Any) {
|
@IBAction func doneButtonTapped(_ sender: Any) {
|
||||||
Defaults[.gitSSHPrivateKeyArmor] = armorPrivateKeyTextView.text
|
SharedDefaults[.gitSSHPrivateKeyArmor] = armorPrivateKeyTextView.text
|
||||||
do {
|
do {
|
||||||
try passwordStore.initGitSSHKey(with: armorPrivateKeyTextView.text, .secret)
|
try passwordStore.initGitSSHKey(with: armorPrivateKeyTextView.text)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Cannot Save", message: "Cannot Save SSH Key", controller: self, completion: nil)
|
Utils.alert(title: "Cannot Save", message: "Cannot Save SSH Key", controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
Defaults[.gitSSHKeySource] = "armor"
|
SharedDefaults[.gitSSHKeySource] = "armor"
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
import passKit
|
||||||
|
|
||||||
class GitServerSettingTableViewController: UITableViewController {
|
class GitServerSettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
let passwordStore = PasswordStore.shared
|
let passwordStore = PasswordStore.shared
|
||||||
var sshLabel: UILabel? = nil
|
var sshLabel: UILabel? = nil
|
||||||
|
|
||||||
var authenticationMethod = Defaults[.gitAuthenticationMethod] ?? "Password"
|
var authenticationMethod = SharedDefaults[.gitAuthenticationMethod] ?? "Password"
|
||||||
|
|
||||||
private func checkAuthenticationMethod(method: String) {
|
private func checkAuthenticationMethod(method: String) {
|
||||||
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
|
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
|
||||||
|
|
@ -47,10 +47,10 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
if let url = Defaults[.gitURL] {
|
if let url = SharedDefaults[.gitURL] {
|
||||||
gitURLTextField.text = url.absoluteString
|
gitURLTextField.text = url.absoluteString
|
||||||
}
|
}
|
||||||
usernameTextField.text = Defaults[.gitUsername]
|
usernameTextField.text = SharedDefaults[.gitUsername]
|
||||||
sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel
|
sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel
|
||||||
checkAuthenticationMethod(method: authenticationMethod)
|
checkAuthenticationMethod(method: authenticationMethod)
|
||||||
authSSHKeyCell.accessoryType = .detailButton
|
authSSHKeyCell.accessoryType = .detailButton
|
||||||
|
|
@ -110,9 +110,9 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
Defaults[.gitURL] = URL(string: gitRepostiroyURL)
|
SharedDefaults[.gitURL] = URL(string: gitRepostiroyURL)
|
||||||
Defaults[.gitUsername] = username
|
SharedDefaults[.gitUsername] = username
|
||||||
Defaults[.gitAuthenticationMethod] = auth
|
SharedDefaults[.gitAuthenticationMethod] = auth
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||||
|
|
@ -167,11 +167,11 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
||||||
var fileActionTitle = "Use Imported Keys"
|
var fileActionTitle = "Use Imported Keys"
|
||||||
|
|
||||||
if Defaults[.gitSSHKeySource] == "url" {
|
if SharedDefaults[.gitSSHKeySource] == "url" {
|
||||||
urlActionTitle = "✓ \(urlActionTitle)"
|
urlActionTitle = "✓ \(urlActionTitle)"
|
||||||
} else if Defaults[.gitSSHKeySource] == "armor" {
|
} else if SharedDefaults[.gitSSHKeySource] == "armor" {
|
||||||
armorActionTitle = "✓ \(armorActionTitle)"
|
armorActionTitle = "✓ \(armorActionTitle)"
|
||||||
} else if Defaults[.gitSSHKeySource] == "file" {
|
} else if SharedDefaults[.gitSSHKeySource] == "file" {
|
||||||
fileActionTitle = "✓ \(fileActionTitle)"
|
fileActionTitle = "✓ \(fileActionTitle)"
|
||||||
}
|
}
|
||||||
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
|
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
|
||||||
|
|
@ -187,7 +187,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
if passwordStore.gitSSHKeyExists() {
|
if passwordStore.gitSSHKeyExists() {
|
||||||
// might keys updated via iTunes, or downloaded/pasted inside the app
|
// might keys updated via iTunes, or downloaded/pasted inside the app
|
||||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||||
Defaults[.gitSSHKeySource] = "file"
|
SharedDefaults[.gitSSHKeySource] = "file"
|
||||||
}
|
}
|
||||||
optionMenu.addAction(fileAction)
|
optionMenu.addAction(fileAction)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -199,10 +199,10 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
optionMenu.addAction(fileAction)
|
optionMenu.addAction(fileAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Defaults[.gitSSHKeySource] != nil {
|
if SharedDefaults[.gitSSHKeySource] != nil {
|
||||||
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
|
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
|
||||||
self.passwordStore.removeGitSSHKeys()
|
self.passwordStore.removeGitSSHKeys()
|
||||||
Defaults[.gitSSHKeySource] = nil
|
SharedDefaults[.gitSSHKeySource] = nil
|
||||||
if let sshLabel = self.sshLabel {
|
if let sshLabel = self.sshLabel {
|
||||||
sshLabel.isEnabled = false
|
sshLabel.isEnabled = false
|
||||||
self.checkAuthenticationMethod(method: "Password")
|
self.checkAuthenticationMethod(method: "Password")
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import passKit
|
||||||
|
|
||||||
class OTPScannerController: QRScannerController {
|
class OTPScannerController: QRScannerController {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
||||||
@IBOutlet weak var armorPublicKeyTextView: UITextView!
|
@IBOutlet weak var armorPublicKeyTextView: UITextView!
|
||||||
|
|
@ -92,8 +92,8 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
armorPublicKeyTextView.text = Defaults[.pgpPublicKeyArmor]
|
armorPublicKeyTextView.text = SharedDefaults[.pgpPublicKeyArmor]
|
||||||
armorPrivateKeyTextView.text = Defaults[.pgpPrivateKeyArmor]
|
armorPrivateKeyTextView.text = SharedDefaults[.pgpPrivateKeyArmor]
|
||||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||||
|
|
||||||
scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes"
|
scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes"
|
||||||
|
|
@ -126,7 +126,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||||
self.pgpPassphrase = nil
|
self.pgpPassphrase = nil
|
||||||
Defaults[.isRememberPassphraseOn] = false
|
SharedDefaults[.isRememberPassphraseOn] = false
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
|
|
@ -135,7 +135,7 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||||
self.pgpPassphrase = alert.textFields?.first?.text
|
self.pgpPassphrase = alert.textFields?.first?.text
|
||||||
Defaults[.isRememberPassphraseOn] = true
|
SharedDefaults[.isRememberPassphraseOn] = true
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
}))
|
}))
|
||||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
class PGPKeySettingTableViewController: UITableViewController {
|
class PGPKeySettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
|
|
@ -19,8 +19,8 @@ class PGPKeySettingTableViewController: UITableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
tableView.rowHeight = UITableViewAutomaticDimension
|
tableView.rowHeight = UITableViewAutomaticDimension
|
||||||
pgpPublicKeyURLTextField.text = Defaults[.pgpPublicKeyURL]?.absoluteString
|
pgpPublicKeyURLTextField.text = SharedDefaults[.pgpPublicKeyURL]?.absoluteString
|
||||||
pgpPrivateKeyURLTextField.text = Defaults[.pgpPrivateKeyURL]?.absoluteString
|
pgpPrivateKeyURLTextField.text = SharedDefaults[.pgpPrivateKeyURL]?.absoluteString
|
||||||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ class PGPKeySettingTableViewController: UITableViewController {
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||||
self.pgpPassphrase = nil
|
self.pgpPassphrase = nil
|
||||||
Defaults[.isRememberPassphraseOn] = false
|
SharedDefaults[.isRememberPassphraseOn] = false
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
|
|
@ -60,7 +60,7 @@ class PGPKeySettingTableViewController: UITableViewController {
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||||
self.pgpPassphrase = alert.textFields?.first?.text
|
self.pgpPassphrase = alert.textFields?.first?.text
|
||||||
Defaults[.isRememberPassphraseOn] = true
|
SharedDefaults[.isRememberPassphraseOn] = true
|
||||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||||
}))
|
}))
|
||||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import FavIcon
|
import FavIcon
|
||||||
import SwiftyUserDefaults
|
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
import passKit
|
||||||
|
|
||||||
class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate {
|
class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate {
|
||||||
var passwordEntity: PasswordEntity?
|
var passwordEntity: PasswordEntity?
|
||||||
|
|
@ -134,7 +134,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
self.present(alert, animated: true, completion: nil)
|
self.present(alert, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||||
if Defaults[.isRememberPassphraseOn] {
|
if SharedDefaults[.isRememberPassphraseOn] {
|
||||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||||
}
|
}
|
||||||
return passphrase
|
return passphrase
|
||||||
|
|
@ -281,8 +281,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
||||||
let filteredAdditionKeys = password.additionKeys.filter {
|
let filteredAdditionKeys = password.additionKeys.filter {
|
||||||
$0.lowercased() != "username" &&
|
$0.lowercased() != "username" &&
|
||||||
$0.lowercased() != "password" &&
|
$0.lowercased() != "password" &&
|
||||||
(!$0.hasPrefix("unknown") || !Defaults[.isHideUnknownOn]) &&
|
(!$0.hasPrefix("unknown") || !SharedDefaults[.isHideUnknownOn]) &&
|
||||||
(!Password.otpKeywords.contains($0) || !Defaults[.isHideOTPOn]) }
|
(!Password.otpKeywords.contains($0) || !SharedDefaults[.isHideOTPOn]) }
|
||||||
|
|
||||||
if filteredAdditionKeys.count > 0 {
|
if filteredAdditionKeys.count > 0 {
|
||||||
section = TableSection(type: .addition, header: "additions")
|
section = TableSection(type: .addition, header: "additions")
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
|
||||||
import OneTimePassword
|
import OneTimePassword
|
||||||
|
import passKit
|
||||||
|
|
||||||
enum PasswordEditorCellType {
|
enum PasswordEditorCellType {
|
||||||
case nameCell, fillPasswordCell, passwordLengthCell, additionsCell, deletePasswordCell, scanQRCodeCell
|
case nameCell, fillPasswordCell, passwordLengthCell, additionsCell, deletePasswordCell, scanQRCodeCell
|
||||||
|
|
@ -95,7 +95,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
||||||
return fillPasswordCell!
|
return fillPasswordCell!
|
||||||
case .passwordLengthCell:
|
case .passwordLengthCell:
|
||||||
passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell
|
passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell
|
||||||
let lengthSetting = Globals.passwordDefaultLength[Defaults[.passwordGeneratorFlavor]] ??
|
let lengthSetting = Globals.passwordDefaultLength[SharedDefaults[.passwordGeneratorFlavor]] ??
|
||||||
Globals.passwordDefaultLength["Random"]
|
Globals.passwordDefaultLength["Random"]
|
||||||
passwordLengthCell?.reset(title: "Length",
|
passwordLengthCell?.reset(title: "Length",
|
||||||
minimumValue: lengthSetting?.min ?? 0,
|
minimumValue: lengthSetting?.min ?? 0,
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
import PasscodeLock
|
|
||||||
|
|
||||||
fileprivate class PasswordsTableEntry : NSObject {
|
fileprivate class PasswordsTableEntry : NSObject {
|
||||||
var title: String
|
var title: String
|
||||||
|
|
@ -87,7 +86,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
filteredPasswordsTableEntries.removeAll()
|
filteredPasswordsTableEntries.removeAll()
|
||||||
var passwordEntities = [PasswordEntity]()
|
var passwordEntities = [PasswordEntity]()
|
||||||
var passwordAllEntities = [PasswordEntity]()
|
var passwordAllEntities = [PasswordEntity]()
|
||||||
if Defaults[.isShowFolderOn] {
|
if SharedDefaults[.isShowFolderOn] {
|
||||||
passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(parent: parent)
|
passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(parent: parent)
|
||||||
} else {
|
} else {
|
||||||
passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
|
passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
|
||||||
|
|
@ -139,12 +138,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
SVProgressHUD.show(withStatus: "Sync Password Store")
|
SVProgressHUD.show(withStatus: "Sync Password Store")
|
||||||
let numberOfLocalCommits = self.passwordStore.numberOfLocalCommits()
|
let numberOfLocalCommits = self.passwordStore.numberOfLocalCommits()
|
||||||
var gitCredential: GitCredential
|
var gitCredential: GitCredential
|
||||||
if Defaults[.gitAuthenticationMethod] == "Password" {
|
if SharedDefaults[.gitAuthenticationMethod] == "Password" {
|
||||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitUsername]!, controller: self))
|
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: SharedDefaults[.gitUsername]!, controller: self))
|
||||||
} else {
|
} else {
|
||||||
gitCredential = GitCredential(
|
gitCredential = GitCredential(
|
||||||
credential: GitCredential.Credential.ssh(
|
credential: GitCredential.Credential.ssh(
|
||||||
userName: Defaults[.gitUsername]!,
|
userName: SharedDefaults[.gitUsername]!,
|
||||||
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||||
controller: self
|
controller: self
|
||||||
)
|
)
|
||||||
|
|
@ -184,7 +183,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
if Defaults[.isShowFolderOn] {
|
if SharedDefaults[.isShowFolderOn] {
|
||||||
searchController.searchBar.scopeButtonTitles = ["Current", "All"]
|
searchController.searchBar.scopeButtonTitles = ["Current", "All"]
|
||||||
} else {
|
} else {
|
||||||
searchController.searchBar.scopeButtonTitles = nil
|
searchController.searchBar.scopeButtonTitles = nil
|
||||||
|
|
@ -238,7 +237,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(_:)))
|
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(_:)))
|
||||||
longPressGestureRecognizer.minimumPressDuration = 0.6
|
longPressGestureRecognizer.minimumPressDuration = 0.6
|
||||||
if Defaults[.isShowFolderOn] && searchController.searchBar.selectedScopeButtonIndex == 0{
|
if SharedDefaults[.isShowFolderOn] && searchController.searchBar.selectedScopeButtonIndex == 0{
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath)
|
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath)
|
||||||
|
|
||||||
let entry = getPasswordEntry(by: indexPath)
|
let entry = getPasswordEntry(by: indexPath)
|
||||||
|
|
@ -296,7 +295,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
}
|
}
|
||||||
|
|
||||||
func backAction(_ sender: Any?) {
|
func backAction(_ sender: Any?) {
|
||||||
guard Defaults[.isShowFolderOn] else { return }
|
guard SharedDefaults[.isShowFolderOn] else { return }
|
||||||
var anim: CATransition? = transitionFromLeft
|
var anim: CATransition? = transitionFromLeft
|
||||||
if parentPasswordEntity == nil {
|
if parentPasswordEntity == nil {
|
||||||
anim = nil
|
anim = nil
|
||||||
|
|
@ -363,7 +362,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
||||||
// bring back
|
// bring back
|
||||||
SVProgressHUD.show(withStatus: "Decrypting")
|
SVProgressHUD.show(withStatus: "Decrypting")
|
||||||
}
|
}
|
||||||
if Defaults[.isRememberPassphraseOn] {
|
if SharedDefaults[.isRememberPassphraseOn] {
|
||||||
self.passwordStore.pgpKeyPassphrase = passphrase
|
self.passwordStore.pgpKeyPassphrase = passphrase
|
||||||
}
|
}
|
||||||
return passphrase
|
return passphrase
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import passKit
|
||||||
|
|
||||||
class RawPasswordViewController: UIViewController {
|
class RawPasswordViewController: UIViewController {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SwiftyUserDefaults
|
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
import passKit
|
||||||
|
|
||||||
class SSHKeySettingTableViewController: UITableViewController {
|
class SSHKeySettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ class SSHKeySettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
privateKeyURLTextField.text = Defaults[.gitSSHPrivateKeyURL]?.absoluteString
|
privateKeyURLTextField.text = SharedDefaults[.gitSSHPrivateKeyURL]?.absoluteString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,14 +27,14 @@ class SSHKeySettingTableViewController: UITableViewController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Defaults[.gitSSHPrivateKeyURL] = privateKeyURL
|
SharedDefaults[.gitSSHPrivateKeyURL] = privateKeyURL
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
Defaults[.gitSSHKeySource] = "url"
|
SharedDefaults[.gitSSHKeySource] = "url"
|
||||||
self.navigationController!.popViewController(animated: true)
|
self.navigationController!.popViewController(animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
import CoreData
|
import CoreData
|
||||||
import SwiftyUserDefaults
|
|
||||||
import PasscodeLock
|
import PasscodeLock
|
||||||
import LocalAuthentication
|
import LocalAuthentication
|
||||||
|
import passKit
|
||||||
|
|
||||||
class SettingsTableViewController: UITableViewController {
|
class SettingsTableViewController: UITableViewController {
|
||||||
|
|
||||||
|
|
@ -27,26 +27,27 @@ class SettingsTableViewController: UITableViewController {
|
||||||
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
|
@IBOutlet weak var passcodeTableViewCell: UITableViewCell!
|
||||||
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
|
@IBOutlet weak var passwordRepositoryTableViewCell: UITableViewCell!
|
||||||
let passwordStore = PasswordStore.shared
|
let passwordStore = PasswordStore.shared
|
||||||
|
var passcodeLockConfig = PasscodeLockConfiguration.shared
|
||||||
|
|
||||||
@IBAction func cancelPGPKey(segue: UIStoryboardSegue) {
|
@IBAction func cancelPGPKey(segue: UIStoryboardSegue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func savePGPKey(segue: UIStoryboardSegue) {
|
@IBAction func savePGPKey(segue: UIStoryboardSegue) {
|
||||||
if let controller = segue.source as? PGPKeySettingTableViewController {
|
if let controller = segue.source as? PGPKeySettingTableViewController {
|
||||||
Defaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!)
|
SharedDefaults[.pgpPrivateKeyURL] = URL(string: controller.pgpPrivateKeyURLTextField.text!)
|
||||||
Defaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!)
|
SharedDefaults[.pgpPublicKeyURL] = URL(string: controller.pgpPublicKeyURLTextField.text!)
|
||||||
if Defaults[.isRememberPassphraseOn] {
|
if SharedDefaults[.isRememberPassphraseOn] {
|
||||||
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
||||||
}
|
}
|
||||||
Defaults[.pgpKeySource] = "url"
|
SharedDefaults[.pgpKeySource] = "url"
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||||
do {
|
do {
|
||||||
try self.passwordStore.initPGPKey(from: Defaults[.pgpPublicKeyURL]!, keyType: .public)
|
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPublicKeyURL]!, keyType: .public)
|
||||||
try self.passwordStore.initPGPKey(from: Defaults[.pgpPrivateKeyURL]!, keyType: .secret)
|
try self.passwordStore.initPGPKey(from: SharedDefaults[.pgpPrivateKeyURL]!, keyType: .secret)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||||
SVProgressHUD.showSuccess(withStatus: "Success")
|
SVProgressHUD.showSuccess(withStatus: "Success")
|
||||||
|
|
@ -62,13 +63,13 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
|
} else if let controller = segue.source as? PGPKeyArmorSettingTableViewController {
|
||||||
Defaults[.pgpKeySource] = "armor"
|
SharedDefaults[.pgpKeySource] = "armor"
|
||||||
if Defaults[.isRememberPassphraseOn] {
|
if SharedDefaults[.isRememberPassphraseOn] {
|
||||||
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
self.passwordStore.pgpKeyPassphrase = controller.pgpPassphrase
|
||||||
}
|
}
|
||||||
|
|
||||||
Defaults[.pgpPublicKeyArmor] = controller.armorPublicKeyTextView.text!
|
SharedDefaults[.pgpPublicKeyArmor] = controller.armorPublicKeyTextView.text!
|
||||||
Defaults[.pgpPrivateKeyArmor] = controller.armorPrivateKeyTextView.text!
|
SharedDefaults[.pgpPrivateKeyArmor] = controller.armorPrivateKeyTextView.text!
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
|
|
@ -94,7 +95,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
|
|
||||||
private func saveImportedPGPKey() {
|
private func saveImportedPGPKey() {
|
||||||
// load keys
|
// load keys
|
||||||
Defaults[.pgpKeySource] = "file"
|
SharedDefaults[.pgpKeySource] = "file"
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
SVProgressHUD.setDefaultStyle(.light)
|
SVProgressHUD.setDefaultStyle(.light)
|
||||||
|
|
@ -120,7 +121,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
|
@ -138,7 +139,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
||||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
self.passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]?.host
|
||||||
touchIDTableViewCell.accessoryView = touchIDSwitch
|
touchIDTableViewCell.accessoryView = touchIDSwitch
|
||||||
setPGPKeyTableViewCellDetailText()
|
setPGPKeyTableViewCellDetailText()
|
||||||
setPasswordRepositoryTableViewCellDetailText()
|
setPasswordRepositoryTableViewCellDetailText()
|
||||||
|
|
@ -170,13 +171,13 @@ class SettingsTableViewController: UITableViewController {
|
||||||
private func setPasscodeLockTouchIDCells() {
|
private func setPasscodeLockTouchIDCells() {
|
||||||
if PasscodeLockRepository().hasPasscode {
|
if PasscodeLockRepository().hasPasscode {
|
||||||
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
||||||
Globals.passcodeConfiguration.isTouchIDAllowed = true
|
passcodeLockConfig.isTouchIDAllowed = true
|
||||||
touchIDSwitch.isOn = Defaults[.isTouchIDOn]
|
touchIDSwitch.isOn = SharedDefaults[.isTouchIDOn]
|
||||||
} else {
|
} else {
|
||||||
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
|
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
|
||||||
Globals.passcodeConfiguration.isTouchIDAllowed = false
|
passcodeLockConfig.isTouchIDAllowed = false
|
||||||
Defaults[.isTouchIDOn] = false
|
SharedDefaults[.isTouchIDOn] = false
|
||||||
touchIDSwitch.isOn = Defaults[.isTouchIDOn]
|
touchIDSwitch.isOn = SharedDefaults[.isTouchIDOn]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,10 +190,10 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setPasswordRepositoryTableViewCellDetailText() {
|
private func setPasswordRepositoryTableViewCellDetailText() {
|
||||||
if Defaults[.gitURL] == nil {
|
if SharedDefaults[.gitURL] == nil {
|
||||||
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
||||||
} else {
|
} else {
|
||||||
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]!.host
|
passwordRepositoryTableViewCell.detailTextLabel?.text = SharedDefaults[.gitURL]!.host
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,12 +203,12 @@ class SettingsTableViewController: UITableViewController {
|
||||||
setPasscodeLockTouchIDCells()
|
setPasscodeLockTouchIDCells()
|
||||||
|
|
||||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||||
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
|
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: passcodeLockConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
if tableView.cellForRow(at: indexPath) == passcodeTableViewCell {
|
if tableView.cellForRow(at: indexPath) == passcodeTableViewCell {
|
||||||
if Defaults[.passcodeKey] != nil{
|
if SharedDefaults[.passcodeKey] != nil{
|
||||||
showPasscodeActionSheet()
|
showPasscodeActionSheet()
|
||||||
} else {
|
} else {
|
||||||
setPasscodeLock()
|
setPasscodeLock()
|
||||||
|
|
@ -219,17 +220,17 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func touchIDSwitchAction(uiSwitch: UISwitch) {
|
func touchIDSwitchAction(uiSwitch: UISwitch) {
|
||||||
if !Globals.passcodeConfiguration.isTouchIDAllowed || !isTouchIDEnabled() {
|
if !passcodeLockConfig.isTouchIDAllowed || !isTouchIDEnabled() {
|
||||||
// switch off
|
// switch off
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
|
||||||
uiSwitch.isOn = Defaults[.isTouchIDOn] // false
|
uiSwitch.isOn = SharedDefaults[.isTouchIDOn] // false
|
||||||
Utils.alert(title: "Notice", message: "Please enable Touch ID and set the passcode lock first.", controller: self, completion: nil)
|
Utils.alert(title: "Notice", message: "Please enable Touch ID and set the passcode lock first.", controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Defaults[.isTouchIDOn] = uiSwitch.isOn
|
SharedDefaults[.isTouchIDOn] = uiSwitch.isOn
|
||||||
}
|
}
|
||||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||||
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
|
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: passcodeLockConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showPGPKeyActionSheet() {
|
func showPGPKeyActionSheet() {
|
||||||
|
|
@ -238,11 +239,11 @@ class SettingsTableViewController: UITableViewController {
|
||||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
||||||
var fileActionTitle = "Use Imported Keys"
|
var fileActionTitle = "Use Imported Keys"
|
||||||
|
|
||||||
if Defaults[.pgpKeySource] == "url" {
|
if SharedDefaults[.pgpKeySource] == "url" {
|
||||||
urlActionTitle = "✓ \(urlActionTitle)"
|
urlActionTitle = "✓ \(urlActionTitle)"
|
||||||
} else if Defaults[.pgpKeySource] == "armor" {
|
} else if SharedDefaults[.pgpKeySource] == "armor" {
|
||||||
armorActionTitle = "✓ \(armorActionTitle)"
|
armorActionTitle = "✓ \(armorActionTitle)"
|
||||||
} else if Defaults[.pgpKeySource] == "file" {
|
} else if SharedDefaults[.pgpKeySource] == "file" {
|
||||||
fileActionTitle = "✓ \(fileActionTitle)"
|
fileActionTitle = "✓ \(fileActionTitle)"
|
||||||
}
|
}
|
||||||
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
|
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
|
||||||
|
|
@ -262,7 +263,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
// no
|
// no
|
||||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||||
self.passwordStore.pgpKeyPassphrase = nil
|
self.passwordStore.pgpKeyPassphrase = nil
|
||||||
Defaults[.isRememberPassphraseOn] = false
|
SharedDefaults[.isRememberPassphraseOn] = false
|
||||||
self.saveImportedPGPKey()
|
self.saveImportedPGPKey()
|
||||||
})
|
})
|
||||||
// yes
|
// yes
|
||||||
|
|
@ -271,7 +272,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||||
self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text
|
self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text
|
||||||
Defaults[.isRememberPassphraseOn] = true
|
SharedDefaults[.isRememberPassphraseOn] = true
|
||||||
self.saveImportedPGPKey()
|
self.saveImportedPGPKey()
|
||||||
}))
|
}))
|
||||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
|
|
@ -293,7 +294,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if Defaults[.pgpKeySource] != nil {
|
if SharedDefaults[.pgpKeySource] != nil {
|
||||||
let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in
|
let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in
|
||||||
self.passwordStore.removePGPKeys()
|
self.passwordStore.removePGPKeys()
|
||||||
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
||||||
|
|
@ -307,15 +308,15 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func showPasscodeActionSheet() {
|
func showPasscodeActionSheet() {
|
||||||
let passcodeChangeViewController = PasscodeLockViewController(state: .change, configuration: Globals.passcodeConfiguration)
|
let passcodeChangeViewController = PasscodeLockViewController(state: .change, configuration: passcodeLockConfig)
|
||||||
let passcodeRemoveViewController = PasscodeLockViewController(state: .remove, configuration: Globals.passcodeConfiguration)
|
let passcodeRemoveViewController = PasscodeLockViewController(state: .remove, configuration: passcodeLockConfig)
|
||||||
|
|
||||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
|
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
|
||||||
passcodeRemoveViewController.successCallback = { _ in
|
passcodeRemoveViewController.successCallback = { _ in
|
||||||
self?.setPasscodeLockTouchIDCells()
|
self?.setPasscodeLockTouchIDCells()
|
||||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||||
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
|
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: (self?.passcodeLockConfig)!)
|
||||||
}
|
}
|
||||||
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
self?.present(passcodeRemoveViewController, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +335,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPasscodeLock() {
|
func setPasscodeLock() {
|
||||||
let passcodeSetViewController = PasscodeLockViewController(state: .set, configuration: Globals.passcodeConfiguration)
|
let passcodeSetViewController = PasscodeLockViewController(state: .set, configuration: passcodeLockConfig)
|
||||||
passcodeSetViewController.successCallback = { _ in
|
passcodeSetViewController.successCallback = { _ in
|
||||||
self.setPasscodeLockTouchIDCells()
|
self.setPasscodeLockTouchIDCells()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
//
|
|
||||||
// Globals.swift
|
|
||||||
// pass
|
|
||||||
//
|
|
||||||
// Created by Mingshen Sun on 21/1/2017.
|
|
||||||
// Copyright © 2017 Bob Sun. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
class Globals {
|
|
||||||
|
|
||||||
// Legacy paths (not shared)
|
|
||||||
static let documentPathLegacy = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
|
|
||||||
static let libraryPathLegacy = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0];
|
|
||||||
static let pgpPublicKeyPathLegacy = "\(documentPathLegacy)/gpg_key.pub"
|
|
||||||
static let pgpPrivateKeyPathLegacy = "\(documentPathLegacy)/gpg_key"
|
|
||||||
static let gitSSHPrivateKeyPathLegacy = "\(documentPathLegacy)/ssh_key"
|
|
||||||
static let gitSSHPrivateKeyURLLegacy = URL(fileURLWithPath: gitSSHPrivateKeyPathLegacy)
|
|
||||||
static let repositoryPathLegacy = "\(libraryPathLegacy)/password-store"
|
|
||||||
|
|
||||||
static let groupIdentifier = "group." + Bundle.main.bundleIdentifier!
|
|
||||||
static let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier)!
|
|
||||||
static let documentPath = sharedContainerURL.appendingPathComponent("Keys").path
|
|
||||||
static let libraryPath = sharedContainerURL.appendingPathComponent("Repository").path
|
|
||||||
static let pgpPublicKeyPath = documentPath + "/gpg_key.pub"
|
|
||||||
static let pgpPrivateKeyPath = documentPath + "/gpg_key"
|
|
||||||
static let gitSSHPrivateKeyPath = documentPath + "/ssh_key"
|
|
||||||
static let gitSSHPrivateKeyURL = URL(fileURLWithPath: gitSSHPrivateKeyPath)
|
|
||||||
static let repositoryPath = libraryPath + "/password-store"
|
|
||||||
|
|
||||||
static var passcodeConfiguration = PasscodeLockConfiguration()
|
|
||||||
|
|
||||||
static let passwordDefaultLength = ["Random": (min: 4, max: 64, def: 16),
|
|
||||||
"Apple": (min: 15, max: 15, def: 15)]
|
|
||||||
|
|
||||||
static let gitSignatureDefaultName = "Pass for iOS"
|
|
||||||
static let gitSignatureDefaultEmail = "user@passforios"
|
|
||||||
|
|
||||||
static let passwordDots = "••••••••••••"
|
|
||||||
static let oneTimePasswordDots = "••••••"
|
|
||||||
static let passwordFonts = "Menlo"
|
|
||||||
|
|
||||||
// UI related
|
|
||||||
static let red = UIColor(red:1.00, green:0.23, blue:0.19, alpha:1.0)
|
|
||||||
static let blue = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0)
|
|
||||||
static let tableCellButtonSize = CGFloat(20.0)
|
|
||||||
|
|
||||||
private init() { }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Bundle {
|
|
||||||
var releaseVersionNumber: String? {
|
|
||||||
return infoDictionary?["CFBundleShortVersionString"] as? String
|
|
||||||
}
|
|
||||||
var buildVersionNumber: String? {
|
|
||||||
return infoDictionary?["CFBundleVersion"] as? String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#ifndef Objective_CBridgingHeader_h
|
#ifndef Objective_CBridgingHeader_h
|
||||||
#define Objective_CBridgingHeader_h
|
#define Objective_CBridgingHeader_h
|
||||||
|
|
||||||
#import <ObjectivePGP/ObjectivePGP.h>
|
// #import <ObjectivePGP/ObjectivePGP.h>
|
||||||
#import <ObjectiveGit/ObjectiveGit.h>
|
#import <ObjectiveGit/ObjectiveGit.h>
|
||||||
|
|
||||||
#endif /* Objective_CBridgingHeader_h */
|
#endif /* Objective_CBridgingHeader_h */
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,15 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import PasscodeLock
|
import PasscodeLock
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
struct PasscodeLockConfiguration: PasscodeLockConfigurationType {
|
struct PasscodeLockConfiguration: PasscodeLockConfigurationType {
|
||||||
|
|
||||||
|
static let shared = PasscodeLockConfiguration()
|
||||||
|
|
||||||
let repository: PasscodeRepositoryType
|
let repository: PasscodeRepositoryType
|
||||||
let passcodeLength = 4
|
let passcodeLength = 4
|
||||||
var isTouchIDAllowed = Defaults[.isTouchIDOn]
|
var isTouchIDAllowed = SharedDefaults[.isTouchIDOn]
|
||||||
let shouldRequestTouchIDImmediately = true
|
let shouldRequestTouchIDImmediately = true
|
||||||
let maximumInccorectPasscodeAttempts = 3
|
let maximumInccorectPasscodeAttempts = 3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import PasscodeLock
|
import PasscodeLock
|
||||||
import SwiftyUserDefaults
|
import passKit
|
||||||
|
|
||||||
public class PasscodeLockRepository: PasscodeRepositoryType {
|
public class PasscodeLockRepository: PasscodeRepositoryType {
|
||||||
private let passcodeKey = "passcode.lock.passcode"
|
private let passcodeKey = "passcode.lock.passcode"
|
||||||
|
|
@ -23,11 +23,11 @@ public class PasscodeLockRepository: PasscodeRepositoryType {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var passcode: String? {
|
private var passcode: String? {
|
||||||
return Defaults[.passcodeKey]
|
return SharedDefaults[.passcodeKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func save(passcode: String) {
|
public func save(passcode: String) {
|
||||||
Defaults[.passcodeKey] = passcode
|
SharedDefaults[.passcodeKey] = passcode
|
||||||
}
|
}
|
||||||
|
|
||||||
public func check(passcode: String) -> Bool {
|
public func check(passcode: String) -> Bool {
|
||||||
|
|
@ -35,6 +35,6 @@ public class PasscodeLockRepository: PasscodeRepositoryType {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func delete() {
|
public func delete() {
|
||||||
Defaults[.passcodeKey] = nil
|
SharedDefaults[.passcodeKey] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import passKit
|
||||||
|
|
||||||
protocol FillPasswordTableViewCellDelegate {
|
protocol FillPasswordTableViewCellDelegate {
|
||||||
func generateAndCopyPassword()
|
func generateAndCopyPassword()
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
import passKit
|
||||||
|
|
||||||
struct LabelTableViewCellData {
|
struct LabelTableViewCellData {
|
||||||
var title: String
|
var title: String
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftyUserDefaults
|
import SwiftyUserDefaults
|
||||||
|
|
||||||
var Defaults = UserDefaults(suiteName: Globals.groupIdentifier)!
|
public var SharedDefaults = UserDefaults(suiteName: Globals.groupIdentifier)!
|
||||||
|
|
||||||
extension DefaultsKeys {
|
public extension DefaultsKeys {
|
||||||
static let pgpKeySource = DefaultsKey<String?>("pgpKeySource")
|
static let pgpKeySource = DefaultsKey<String?>("pgpKeySource")
|
||||||
static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL")
|
static let pgpPublicKeyURL = DefaultsKey<URL?>("pgpPublicKeyURL")
|
||||||
static let pgpPrivateKeyURL = DefaultsKey<URL?>("pgpPrivateKeyURL")
|
static let pgpPrivateKeyURL = DefaultsKey<URL?>("pgpPrivateKeyURL")
|
||||||
61
passKit/Helpers/Globals.swift
Normal file
61
passKit/Helpers/Globals.swift
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
//
|
||||||
|
// Globals.swift
|
||||||
|
// pass
|
||||||
|
//
|
||||||
|
// Created by Mingshen Sun on 21/1/2017.
|
||||||
|
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public class Globals {
|
||||||
|
|
||||||
|
// Legacy paths (not shared)
|
||||||
|
public static let documentPathLegacy = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
|
||||||
|
public static let libraryPathLegacy = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0];
|
||||||
|
public static let pgpPublicKeyPathLegacy = "\(documentPathLegacy)/gpg_key.pub"
|
||||||
|
public static let pgpPrivateKeyPathLegacy = "\(documentPathLegacy)/gpg_key"
|
||||||
|
public static let gitSSHPrivateKeyPathLegacy = "\(documentPathLegacy)/ssh_key"
|
||||||
|
public static let gitSSHPrivateKeyURLLegacy = URL(fileURLWithPath: gitSSHPrivateKeyPathLegacy)
|
||||||
|
public static let repositoryPathLegacy = "\(libraryPathLegacy)/password-store"
|
||||||
|
|
||||||
|
public static let bundleIdentifier = "me.mssun.passforios"
|
||||||
|
public static let groupIdentifier = "group." + bundleIdentifier
|
||||||
|
public static let passKitBundleIdentifier = bundleIdentifier + ".passKit"
|
||||||
|
|
||||||
|
public static let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier)!
|
||||||
|
public static let documentPath = sharedContainerURL.appendingPathComponent("Documents").path
|
||||||
|
public static let libraryPath = sharedContainerURL.appendingPathComponent("Library").path
|
||||||
|
public static let pgpPublicKeyPath = documentPath + "/gpg_key.pub"
|
||||||
|
public static let pgpPrivateKeyPath = documentPath + "/gpg_key"
|
||||||
|
public static let gitSSHPrivateKeyPath = documentPath + "/ssh_key"
|
||||||
|
public static let gitSSHPrivateKeyURL = URL(fileURLWithPath: gitSSHPrivateKeyPath)
|
||||||
|
public static let repositoryPath = libraryPath + "/password-store"
|
||||||
|
|
||||||
|
public static let passwordDefaultLength = ["Random": (min: 4, max: 64, def: 16),
|
||||||
|
"Apple": (min: 15, max: 15, def: 15)]
|
||||||
|
|
||||||
|
public static let gitSignatureDefaultName = "Pass for iOS"
|
||||||
|
public static let gitSignatureDefaultEmail = "user@passforios"
|
||||||
|
|
||||||
|
public static let passwordDots = "••••••••••••"
|
||||||
|
public static let oneTimePasswordDots = "••••••"
|
||||||
|
public static let passwordFonts = "Menlo"
|
||||||
|
|
||||||
|
// UI related
|
||||||
|
public static let red = UIColor(red:1.00, green:0.23, blue:0.19, alpha:1.0)
|
||||||
|
public static let blue = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0)
|
||||||
|
public static let tableCellButtonSize = CGFloat(20.0)
|
||||||
|
|
||||||
|
private init() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Bundle {
|
||||||
|
var releaseVersionNumber: String? {
|
||||||
|
return infoDictionary?["CFBundleShortVersionString"] as? String
|
||||||
|
}
|
||||||
|
var buildVersionNumber: String? {
|
||||||
|
return infoDictionary?["CFBundleVersion"] as? String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension Notification.Name {
|
public extension Notification.Name {
|
||||||
static let passwordStoreUpdated = Notification.Name("passwordStoreUpdated")
|
static let passwordStoreUpdated = Notification.Name("passwordStoreUpdated")
|
||||||
static let passwordStoreErased = Notification.Name("passwordStoreErased")
|
static let passwordStoreErased = Notification.Name("passwordStoreErased")
|
||||||
static let passwordStoreChangeDiscarded = Notification.Name("passwordStoreChangeDiscarded")
|
static let passwordStoreChangeDiscarded = Notification.Name("passwordStoreChangeDiscarded")
|
||||||
|
|
@ -12,8 +12,8 @@ import KeychainAccess
|
||||||
import UIKit
|
import UIKit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
|
||||||
class Utils {
|
public class Utils {
|
||||||
static func removeFileIfExists(atPath path: String) {
|
public static func removeFileIfExists(atPath path: String) {
|
||||||
let fm = FileManager.default
|
let fm = FileManager.default
|
||||||
do {
|
do {
|
||||||
if fm.fileExists(atPath: path) {
|
if fm.fileExists(atPath: path) {
|
||||||
|
|
@ -23,12 +23,12 @@ class Utils {
|
||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static func removeFileIfExists(at url: URL) {
|
public static func removeFileIfExists(at url: URL) {
|
||||||
removeFileIfExists(atPath: url.path)
|
removeFileIfExists(atPath: url.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getLastSyncedTimeString() -> String {
|
public static func getLastSyncedTimeString() -> String {
|
||||||
guard let lastSyncedTime = Defaults[.lastSyncedTime] else {
|
guard let lastSyncedTime = SharedDefaults[.lastSyncedTime] else {
|
||||||
return "Oops! Sync again?"
|
return "Oops! Sync again?"
|
||||||
}
|
}
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
|
|
@ -37,8 +37,8 @@ class Utils {
|
||||||
return formatter.string(from: lastSyncedTime)
|
return formatter.string(from: lastSyncedTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func generatePassword(length: Int) -> String{
|
public static func generatePassword(length: Int) -> String{
|
||||||
switch Defaults[.passwordGeneratorFlavor] {
|
switch SharedDefaults[.passwordGeneratorFlavor] {
|
||||||
case "Random":
|
case "Random":
|
||||||
return randomString(length: length)
|
return randomString(length: length)
|
||||||
case "Apple":
|
case "Apple":
|
||||||
|
|
@ -48,7 +48,7 @@ class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func randomString(length: Int) -> String {
|
public static func randomString(length: Int) -> String {
|
||||||
|
|
||||||
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*_+-="
|
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*_+-="
|
||||||
let len = UInt32(letters.length)
|
let len = UInt32(letters.length)
|
||||||
|
|
@ -64,15 +64,15 @@ class Utils {
|
||||||
return randomString
|
return randomString
|
||||||
}
|
}
|
||||||
|
|
||||||
static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
public static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
||||||
SVProgressHUD.dismiss()
|
SVProgressHUD.dismiss()
|
||||||
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
|
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
|
||||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: handler))
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: handler))
|
||||||
controller.present(alert, animated: true, completion: completion)
|
controller.present(alert, animated: true, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getPasswordFromKeychain(name: String) -> String? {
|
public static func getPasswordFromKeychain(name: String) -> String? {
|
||||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
let keychain = Keychain(service: Globals.bundleIdentifier)
|
||||||
do {
|
do {
|
||||||
return try keychain.getString(name)
|
return try keychain.getString(name)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -81,27 +81,27 @@ class Utils {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
static func addPasswordToKeychain(name: String, password: String?) {
|
public static func addPasswordToKeychain(name: String, password: String?) {
|
||||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
let keychain = Keychain(service: Globals.bundleIdentifier)
|
||||||
keychain[name] = password
|
keychain[name] = password
|
||||||
}
|
}
|
||||||
static func removeKeychain(name: String) {
|
public static func removeKeychain(name: String) {
|
||||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
let keychain = Keychain(service: Globals.bundleIdentifier)
|
||||||
do {
|
do {
|
||||||
try keychain.remove(name)
|
try keychain.remove(name)
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static func removeAllKeychain() {
|
public static func removeAllKeychain() {
|
||||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
let keychain = Keychain(service: Globals.bundleIdentifier)
|
||||||
do {
|
do {
|
||||||
try keychain.removeAll()
|
try keychain.removeAll()
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static func copyToPasteboard(textToCopy: String?, expirationTime: Double = 45) {
|
public static func copyToPasteboard(textToCopy: String?, expirationTime: Double = 45) {
|
||||||
guard textToCopy != nil else {
|
guard textToCopy != nil else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +113,7 @@ class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static func attributedPassword(plainPassword: String) -> NSAttributedString{
|
public static func attributedPassword(plainPassword: String) -> NSAttributedString{
|
||||||
let attributedPassword = NSMutableAttributedString.init(string: plainPassword)
|
let attributedPassword = NSMutableAttributedString.init(string: plainPassword)
|
||||||
// draw all digits in the password into red
|
// draw all digits in the password into red
|
||||||
// draw all punctuation characters in the password into blue
|
// draw all punctuation characters in the password into blue
|
||||||
|
|
@ -126,15 +126,15 @@ class Utils {
|
||||||
}
|
}
|
||||||
return attributedPassword
|
return attributedPassword
|
||||||
}
|
}
|
||||||
static func initDefaultKeys() {
|
public static func initDefaultKeys() {
|
||||||
if Defaults[.passwordGeneratorFlavor] == "" {
|
if SharedDefaults[.passwordGeneratorFlavor] == "" {
|
||||||
Defaults[.passwordGeneratorFlavor] = "Random"
|
SharedDefaults[.passwordGeneratorFlavor] = "Random"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://gist.github.com/NikolaiRuhe/eeb135d20c84a7097516
|
// https://gist.github.com/NikolaiRuhe/eeb135d20c84a7097516
|
||||||
extension FileManager {
|
public extension FileManager {
|
||||||
|
|
||||||
/// This method calculates the accumulated size of a directory on the volume in bytes.
|
/// This method calculates the accumulated size of a directory on the volume in bytes.
|
||||||
///
|
///
|
||||||
|
|
@ -217,7 +217,7 @@ extension FileManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension String {
|
public extension String {
|
||||||
func stringByAddingPercentEncodingForRFC3986() -> String? {
|
func stringByAddingPercentEncodingForRFC3986() -> String? {
|
||||||
let unreserved = "-._~/?"
|
let unreserved = "-._~/?"
|
||||||
var allowed = CharacterSet.alphanumerics
|
var allowed = CharacterSet.alphanumerics
|
||||||
26
passKit/Info.plist
Normal file
26
passKit/Info.plist
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>PassKit</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -12,19 +12,19 @@ import SwiftyUserDefaults
|
||||||
import ObjectiveGit
|
import ObjectiveGit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
|
||||||
struct GitCredential {
|
public struct GitCredential {
|
||||||
var credential: Credential
|
public var credential: Credential
|
||||||
|
|
||||||
enum Credential {
|
public enum Credential {
|
||||||
case http(userName: String, controller: UIViewController)
|
case http(userName: String, controller: UIViewController)
|
||||||
case ssh(userName: String, privateKeyFile: URL, controller: UIViewController)
|
case ssh(userName: String, privateKeyFile: URL, controller: UIViewController)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(credential: Credential) {
|
public init(credential: Credential) {
|
||||||
self.credential = credential
|
self.credential = credential
|
||||||
}
|
}
|
||||||
|
|
||||||
func credentialProvider() throws -> GTCredentialProvider {
|
public func credentialProvider() throws -> GTCredentialProvider {
|
||||||
var attempts = 0
|
var attempts = 0
|
||||||
var lastPassword: String? = nil
|
var lastPassword: String? = nil
|
||||||
return GTCredentialProvider { (_, _, _) -> (GTCredential?) in
|
return GTCredentialProvider { (_, _, _) -> (GTCredential?) in
|
||||||
|
|
@ -63,7 +63,7 @@ struct GitCredential {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func delete() {
|
public func delete() {
|
||||||
switch credential {
|
switch credential {
|
||||||
case .http:
|
case .http:
|
||||||
Utils.removeKeychain(name: "gitPassword")
|
Utils.removeKeychain(name: "gitPassword")
|
||||||
|
|
@ -22,12 +22,12 @@ enum PasswordChange: Int {
|
||||||
case none = 0x00
|
case none = 0x00
|
||||||
}
|
}
|
||||||
|
|
||||||
class Password {
|
public class Password {
|
||||||
static let otpKeywords = ["otp_secret", "otp_type", "otp_algorithm", "otp_period", "otp_digits", "otp_counter", "otpauth"]
|
public static let otpKeywords = ["otp_secret", "otp_type", "otp_algorithm", "otp_period", "otp_digits", "otp_counter", "otpauth"]
|
||||||
|
|
||||||
var name = ""
|
public var name = ""
|
||||||
var url: URL?
|
public var url: URL?
|
||||||
var namePath: String {
|
public var namePath: String {
|
||||||
get {
|
get {
|
||||||
if url == nil {
|
if url == nil {
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -35,20 +35,20 @@ class Password {
|
||||||
return url!.deletingPathExtension().path
|
return url!.deletingPathExtension().path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var password = ""
|
public var password = ""
|
||||||
var additions = [String: String]()
|
public var additions = [String: String]()
|
||||||
var additionKeys = [String]()
|
public var additionKeys = [String]()
|
||||||
var changed: Int = 0
|
public var changed: Int = 0
|
||||||
var plainText = ""
|
public var plainText = ""
|
||||||
|
|
||||||
private var firstLineIsOTPField = false
|
private var firstLineIsOTPField = false
|
||||||
private var otpToken: Token?
|
private var otpToken: Token?
|
||||||
|
|
||||||
enum OtpType {
|
public enum OtpType {
|
||||||
case totp, hotp, none
|
case totp, hotp, none
|
||||||
}
|
}
|
||||||
|
|
||||||
var otpType: OtpType {
|
public var otpType: OtpType {
|
||||||
get {
|
get {
|
||||||
guard let token = self.otpToken else {
|
guard let token = self.otpToken else {
|
||||||
return OtpType.none
|
return OtpType.none
|
||||||
|
|
@ -62,11 +62,11 @@ class Password {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(name: String, url: URL?, plainText: String) {
|
public init(name: String, url: URL?, plainText: String) {
|
||||||
self.initEverything(name: name, url: url, plainText: plainText)
|
self.initEverything(name: name, url: url, plainText: plainText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePassword(name: String, url: URL?, plainText: String) {
|
public func updatePassword(name: String, url: URL?, plainText: String) {
|
||||||
if self.plainText != plainText || self.url != url {
|
if self.plainText != plainText || self.url != url {
|
||||||
if self.plainText != plainText {
|
if self.plainText != plainText {
|
||||||
changed = changed|PasswordChange.content.rawValue
|
changed = changed|PasswordChange.content.rawValue
|
||||||
|
|
@ -108,17 +108,17 @@ class Password {
|
||||||
self.updateOtpToken()
|
self.updateOtpToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUsername() -> String? {
|
public func getUsername() -> String? {
|
||||||
return getAdditionValue(withKey: "Username") ?? getAdditionValue(withKey: "username")
|
return getAdditionValue(withKey: "Username") ?? getAdditionValue(withKey: "username")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getURLString() -> String? {
|
public func getURLString() -> String? {
|
||||||
return getAdditionValue(withKey: "URL") ?? getAdditionValue(withKey: "url") ?? getAdditionValue(withKey: "Url")
|
return getAdditionValue(withKey: "URL") ?? getAdditionValue(withKey: "url") ?? getAdditionValue(withKey: "Url")
|
||||||
}
|
}
|
||||||
|
|
||||||
// return a key-value pair from the line
|
// return a key-value pair from the line
|
||||||
// key might be nil, if there is no ":" in the line
|
// key might be nil, if there is no ":" in the line
|
||||||
static private func getKeyValuePair(from line: String) -> (key: String?, value: String) {
|
private static func getKeyValuePair(from line: String) -> (key: String?, value: String) {
|
||||||
let items = line.components(separatedBy: ": ").map{String($0).trimmingCharacters(in: .whitespaces)}
|
let items = line.components(separatedBy: ": ").map{String($0).trimmingCharacters(in: .whitespaces)}
|
||||||
var key : String? = nil
|
var key : String? = nil
|
||||||
var value = ""
|
var value = ""
|
||||||
|
|
@ -138,7 +138,7 @@ class Password {
|
||||||
return (key, value)
|
return (key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
static private func getAdditionFields(from additionFieldsPlainText: String) -> ([String: String], [String]){
|
private static func getAdditionFields(from additionFieldsPlainText: String) -> ([String: String], [String]){
|
||||||
var additions = [String: String]()
|
var additions = [String: String]()
|
||||||
var additionKeys = [String]()
|
var additionKeys = [String]()
|
||||||
var unknownIndex = 0
|
var unknownIndex = 0
|
||||||
|
|
@ -159,7 +159,7 @@ class Password {
|
||||||
return (additions, additionKeys)
|
return (additions, additionKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAdditionsPlainText() -> String {
|
public func getAdditionsPlainText() -> String {
|
||||||
// lines starting from the second
|
// lines starting from the second
|
||||||
let plainTextSplit = plainText.characters.split(maxSplits: 1, omittingEmptySubsequences: false) {
|
let plainTextSplit = plainText.characters.split(maxSplits: 1, omittingEmptySubsequences: false) {
|
||||||
$0 == "\n" || $0 == "\r\n"
|
$0 == "\n" || $0 == "\r\n"
|
||||||
|
|
@ -175,7 +175,7 @@ class Password {
|
||||||
return self.plainText
|
return self.plainText
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPlainData() -> Data {
|
public func getPlainData() -> Data {
|
||||||
return getPlainText().data(using: .utf8)!
|
return getPlainText().data(using: .utf8)!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,7 +290,7 @@ class Password {
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the description and the password strings
|
// return the description and the password strings
|
||||||
func getOtpStrings() -> (description: String, otp: String)? {
|
public func getOtpStrings() -> (description: String, otp: String)? {
|
||||||
guard let token = self.otpToken else {
|
guard let token = self.otpToken else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -310,7 +310,7 @@ class Password {
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the password strings
|
// return the password strings
|
||||||
func getOtp() -> String? {
|
public func getOtp() -> String? {
|
||||||
if let otp = self.otpToken?.currentPassword {
|
if let otp = self.otpToken?.currentPassword {
|
||||||
return otp
|
return otp
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -320,7 +320,7 @@ class Password {
|
||||||
|
|
||||||
// return the password strings
|
// return the password strings
|
||||||
// it is guaranteed that it is a HOTP password when we call this
|
// it is guaranteed that it is a HOTP password when we call this
|
||||||
func getNextHotp() -> String? {
|
public func getNextHotp() -> String? {
|
||||||
// increase the counter
|
// increase the counter
|
||||||
otpToken = otpToken?.updatedToken()
|
otpToken = otpToken?.updatedToken()
|
||||||
|
|
||||||
|
|
@ -349,7 +349,7 @@ class Password {
|
||||||
return self.otpToken?.currentPassword
|
return self.otpToken?.currentPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
static func LooksLikeOTP(line: String) -> Bool {
|
public static func LooksLikeOTP(line: String) -> Bool {
|
||||||
let (key, _) = getKeyValuePair(from: line)
|
let (key, _) = getKeyValuePair(from: line)
|
||||||
return Password.otpKeywords.contains(key ?? "")
|
return Password.otpKeywords.contains(key ?? "")
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import SwiftyUserDefaults
|
||||||
|
|
||||||
extension PasswordEntity {
|
extension PasswordEntity {
|
||||||
|
|
||||||
var nameWithCategory: String {
|
public var nameWithCategory: String {
|
||||||
get {
|
get {
|
||||||
if let p = path, p.hasSuffix(".gpg") {
|
if let p = path, p.hasSuffix(".gpg") {
|
||||||
return p.substring(to: p.index(p.endIndex, offsetBy: -4))
|
return p.substring(to: p.index(p.endIndex, offsetBy: -4))
|
||||||
|
|
@ -21,7 +21,7 @@ extension PasswordEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCategoryText() -> String {
|
public func getCategoryText() -> String {
|
||||||
var parentEntity = parent
|
var parentEntity = parent
|
||||||
var passwordCategoryArray: [String] = []
|
var passwordCategoryArray: [String] = []
|
||||||
while parentEntity != nil {
|
while parentEntity != nil {
|
||||||
|
|
@ -32,7 +32,7 @@ extension PasswordEntity {
|
||||||
return passwordCategoryArray.joined(separator: " > ")
|
return passwordCategoryArray.joined(separator: " > ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getURL() -> URL? {
|
public func getURL() -> URL? {
|
||||||
if let p = path {
|
if let p = path {
|
||||||
return URL(string: p.stringByAddingPercentEncodingForRFC3986()!)
|
return URL(string: p.stringByAddingPercentEncodingForRFC3986()!)
|
||||||
}
|
}
|
||||||
|
|
@ -12,15 +12,16 @@ import UIKit
|
||||||
import SwiftyUserDefaults
|
import SwiftyUserDefaults
|
||||||
import ObjectiveGit
|
import ObjectiveGit
|
||||||
import SVProgressHUD
|
import SVProgressHUD
|
||||||
|
import ObjectivePGP
|
||||||
|
|
||||||
class PasswordStore {
|
public class PasswordStore {
|
||||||
static let shared = PasswordStore()
|
public static let shared = PasswordStore()
|
||||||
let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)")
|
public let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)")
|
||||||
let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp")
|
public let tempStoreURL = URL(fileURLWithPath: "\(Globals.repositoryPath)-temp")
|
||||||
|
|
||||||
var storeRepository: GTRepository?
|
public var storeRepository: GTRepository?
|
||||||
var pgpKeyID: String?
|
public var pgpKeyID: String?
|
||||||
var publicKey: PGPKey? {
|
public var publicKey: PGPKey? {
|
||||||
didSet {
|
didSet {
|
||||||
if publicKey != nil {
|
if publicKey != nil {
|
||||||
pgpKeyID = publicKey!.keyID!.shortKeyString
|
pgpKeyID = publicKey!.keyID!.shortKeyString
|
||||||
|
|
@ -29,19 +30,19 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var privateKey: PGPKey?
|
public var privateKey: PGPKey?
|
||||||
|
|
||||||
var gitSignatureForNow: GTSignature {
|
public var gitSignatureForNow: GTSignature {
|
||||||
get {
|
get {
|
||||||
let gitSignatureName = Defaults[.gitSignatureName] ?? Globals.gitSignatureDefaultName
|
let gitSignatureName = SharedDefaults[.gitSignatureName] ?? Globals.gitSignatureDefaultName
|
||||||
let gitSignatureEmail = Defaults[.gitSignatureEmail] ?? Globals.gitSignatureDefaultEmail
|
let gitSignatureEmail = SharedDefaults[.gitSignatureEmail] ?? Globals.gitSignatureDefaultEmail
|
||||||
return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())!
|
return GTSignature(name: gitSignatureName, email: gitSignatureEmail, time: Date())!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pgp: ObjectivePGP = ObjectivePGP()
|
public var pgp: ObjectivePGP = ObjectivePGP()
|
||||||
|
|
||||||
var pgpKeyPassphrase: String? {
|
public var pgpKeyPassphrase: String? {
|
||||||
set {
|
set {
|
||||||
Utils.addPasswordToKeychain(name: "pgpKeyPassphrase", password: newValue)
|
Utils.addPasswordToKeychain(name: "pgpKeyPassphrase", password: newValue)
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +51,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitPassword: String? {
|
public var gitPassword: String? {
|
||||||
set {
|
set {
|
||||||
Utils.addPasswordToKeychain(name: "gitPassword", password: newValue)
|
Utils.addPasswordToKeychain(name: "gitPassword", password: newValue)
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +60,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitSSHPrivateKeyPassphrase: String? {
|
public var gitSSHPrivateKeyPassphrase: String? {
|
||||||
set {
|
set {
|
||||||
Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", password: newValue)
|
Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", password: newValue)
|
||||||
}
|
}
|
||||||
|
|
@ -68,17 +69,13 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fm = FileManager.default
|
private let fm = FileManager.default
|
||||||
lazy var context: NSManagedObjectContext = {
|
lazy private var context: NSManagedObjectContext = {
|
||||||
/*
|
let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")!
|
||||||
The persistent container for the application. This implementation
|
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
||||||
creates and returns a container, having loaded the store for the
|
let container = NSPersistentContainer(name: "pass", managedObjectModel: managedObjectModel!)
|
||||||
application to it. This property is optional since there are legitimate
|
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: Globals.sharedContainerURL.appendingPathComponent("Documents/pass.sqlite"))]
|
||||||
error conditions that could cause the creation of the store to fail.
|
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||||
*/
|
|
||||||
let container = NSPersistentContainer(name: "pass")
|
|
||||||
let description = NSPersistentStoreDescription(url: Globals.sharedContainerURL)
|
|
||||||
container.loadPersistentStores(completionHandler: { (description, error) in
|
|
||||||
if let error = error as NSError? {
|
if let error = error as NSError? {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
// Replace this implementation with code to handle the error appropriately.
|
||||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||||
|
|
@ -97,11 +94,11 @@ class PasswordStore {
|
||||||
return container.viewContext
|
return container.viewContext
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var numberOfPasswords : Int {
|
public var numberOfPasswords : Int {
|
||||||
return self.fetchPasswordEntityCoreData(withDir: false).count
|
return self.fetchPasswordEntityCoreData(withDir: false).count
|
||||||
}
|
}
|
||||||
|
|
||||||
var sizeOfRepositoryByteCount : UInt64 {
|
public var sizeOfRepositoryByteCount : UInt64 {
|
||||||
var size = UInt64(0)
|
var size = UInt64(0)
|
||||||
do {
|
do {
|
||||||
if fm.fileExists(atPath: self.storeURL.path) {
|
if fm.fileExists(atPath: self.storeURL.path) {
|
||||||
|
|
@ -116,8 +113,11 @@ class PasswordStore {
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
// File migration to group
|
// File migration to group
|
||||||
|
print(Globals.documentPath)
|
||||||
|
print(Globals.libraryPath)
|
||||||
|
print(Globals.documentPathLegacy)
|
||||||
|
print(Globals.libraryPathLegacy)
|
||||||
migration()
|
migration()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if fm.fileExists(atPath: storeURL.path) {
|
if fm.fileExists(atPath: storeURL.path) {
|
||||||
try storeRepository = GTRepository.init(url: storeURL)
|
try storeRepository = GTRepository.init(url: storeURL)
|
||||||
|
|
@ -134,8 +134,9 @@ class PasswordStore {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
try fm.copyItem(atPath: Globals.documentPathLegacy, toPath: Globals.documentPath)
|
try fm.moveItem(atPath: Globals.documentPathLegacy, toPath: Globals.documentPath)
|
||||||
try fm.copyItem(atPath: Globals.libraryPathLegacy, toPath: Globals.libraryPath)
|
try fm.moveItem(atPath: Globals.libraryPathLegacy, toPath: Globals.libraryPath)
|
||||||
|
SharedDefaults = Defaults
|
||||||
} catch {
|
} catch {
|
||||||
print("Cannot migrate: \(error)")
|
print("Cannot migrate: \(error)")
|
||||||
}
|
}
|
||||||
|
|
@ -146,10 +147,7 @@ class PasswordStore {
|
||||||
case `public`, secret
|
case `public`, secret
|
||||||
}
|
}
|
||||||
|
|
||||||
public func initGitSSHKey(with armorKey: String, _ keyType: SSHKeyType) throws {
|
public func initGitSSHKey(with armorKey: String) throws {
|
||||||
guard keyType == .secret else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let keyPath = Globals.gitSSHPrivateKeyPath
|
let keyPath = Globals.gitSSHPrivateKeyPath
|
||||||
try armorKey.write(toFile: keyPath, atomically: true, encoding: .ascii)
|
try armorKey.write(toFile: keyPath, atomically: true, encoding: .ascii)
|
||||||
}
|
}
|
||||||
|
|
@ -211,16 +209,16 @@ class PasswordStore {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPgpPrivateKey() -> PGPKey {
|
public func getPgpPrivateKey() -> PGPKey {
|
||||||
return pgp.getKeysOf(.secret)[0]
|
return pgp.getKeysOf(.secret)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func repositoryExisted() -> Bool {
|
public func repositoryExisted() -> Bool {
|
||||||
let fm = FileManager()
|
let fm = FileManager()
|
||||||
return fm.fileExists(atPath: Globals.repositoryPath)
|
return fm.fileExists(atPath: Globals.repositoryPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func passwordExisted(password: Password) -> Bool {
|
public func passwordExisted(password: Password) -> Bool {
|
||||||
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
passwordEntityFetchRequest.predicate = NSPredicate(format: "name = %@ and path = %@", password.name, password.url!.path)
|
passwordEntityFetchRequest.predicate = NSPredicate(format: "name = %@ and path = %@", password.name, password.url!.path)
|
||||||
|
|
@ -236,7 +234,7 @@ class PasswordStore {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func passwordEntityExisted(path: String) -> Bool {
|
public func passwordEntityExisted(path: String) -> Bool {
|
||||||
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@", path)
|
passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@", path)
|
||||||
|
|
@ -252,7 +250,7 @@ class PasswordStore {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPasswordEntity(by path: String, isDir: Bool) -> PasswordEntity? {
|
public func getPasswordEntity(by path: String, isDir: Bool) -> PasswordEntity? {
|
||||||
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@ and isDir = %@", path, isDir.description)
|
passwordEntityFetchRequest.predicate = NSPredicate(format: "path = %@ and isDir = %@", path, isDir.description)
|
||||||
|
|
@ -262,7 +260,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cloneRepository(remoteRepoURL: URL,
|
public func cloneRepository(remoteRepoURL: URL,
|
||||||
credential: GitCredential,
|
credential: GitCredential,
|
||||||
transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void,
|
transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void,
|
||||||
checkoutProgressBlock: @escaping (String?, UInt, UInt) -> Void) throws {
|
checkoutProgressBlock: @escaping (String?, UInt, UInt) -> Void) throws {
|
||||||
|
|
@ -283,13 +281,13 @@ class PasswordStore {
|
||||||
throw(error)
|
throw(error)
|
||||||
}
|
}
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
Defaults[.lastSyncedTime] = Date()
|
SharedDefaults[.lastSyncedTime] = Date()
|
||||||
self.updatePasswordEntityCoreData()
|
self.updatePasswordEntityCoreData()
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pullRepository(credential: GitCredential, transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
public func pullRepository(credential: GitCredential, transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSetError
|
throw AppError.RepositoryNotSetError
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +301,7 @@ class PasswordStore {
|
||||||
throw(error)
|
throw(error)
|
||||||
}
|
}
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
Defaults[.lastSyncedTime] = Date()
|
SharedDefaults[.lastSyncedTime] = Date()
|
||||||
self.setAllSynced()
|
self.setAllSynced()
|
||||||
self.updatePasswordEntityCoreData()
|
self.updatePasswordEntityCoreData()
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
|
|
@ -364,7 +362,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRecentCommits(count: Int) throws -> [GTCommit] {
|
public func getRecentCommits(count: Int) throws -> [GTCommit] {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
@ -380,7 +378,7 @@ class PasswordStore {
|
||||||
return commits
|
return commits
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPasswordEntityCoreData(parent: PasswordEntity?) -> [PasswordEntity] {
|
public func fetchPasswordEntityCoreData(parent: PasswordEntity?) -> [PasswordEntity] {
|
||||||
let passwordEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
passwordEntityFetch.predicate = NSPredicate(format: "parent = %@", parent ?? 0)
|
passwordEntityFetch.predicate = NSPredicate(format: "parent = %@", parent ?? 0)
|
||||||
|
|
@ -391,7 +389,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchPasswordEntityCoreData(withDir: Bool) -> [PasswordEntity] {
|
public func fetchPasswordEntityCoreData(withDir: Bool) -> [PasswordEntity] {
|
||||||
let passwordEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
if !withDir {
|
if !withDir {
|
||||||
|
|
@ -405,7 +403,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func fetchUnsyncedPasswords() -> [PasswordEntity] {
|
public func fetchUnsyncedPasswords() -> [PasswordEntity] {
|
||||||
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0)
|
passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0)
|
||||||
do {
|
do {
|
||||||
|
|
@ -416,7 +414,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setAllSynced() {
|
public func setAllSynced() {
|
||||||
let passwordEntities = fetchUnsyncedPasswords()
|
let passwordEntities = fetchUnsyncedPasswords()
|
||||||
for passwordEntity in passwordEntities {
|
for passwordEntity in passwordEntities {
|
||||||
passwordEntity.synced = true
|
passwordEntity.synced = true
|
||||||
|
|
@ -430,7 +428,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNumberOfUnsyncedPasswords() -> Int {
|
public func getNumberOfUnsyncedPasswords() -> Int {
|
||||||
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
let passwordEntityFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PasswordEntity")
|
||||||
do {
|
do {
|
||||||
passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0)
|
passwordEntityFetchRequest.predicate = NSPredicate(format: "synced = %i", 0)
|
||||||
|
|
@ -441,7 +439,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func getLatestUpdateInfo(filename: String) -> String {
|
public func getLatestUpdateInfo(filename: String) -> String {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
@ -467,7 +465,7 @@ class PasswordStore {
|
||||||
return autoFormattedDifference
|
return autoFormattedDifference
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRemoteRepo() {
|
public func updateRemoteRepo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func gitAdd(path: String) throws {
|
private func gitAdd(path: String) throws {
|
||||||
|
|
@ -540,7 +538,7 @@ class PasswordStore {
|
||||||
return branches.first
|
return branches.first
|
||||||
}
|
}
|
||||||
|
|
||||||
func pushRepository(credential: GitCredential, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
public func pushRepository(credential: GitCredential, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSetError
|
throw AppError.RepositoryNotSetError
|
||||||
}
|
}
|
||||||
|
|
@ -604,7 +602,7 @@ class PasswordStore {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(password: Password) throws -> PasswordEntity? {
|
public func add(password: Password) throws -> PasswordEntity? {
|
||||||
try createDirectoryTree(at: password.url!)
|
try createDirectoryTree(at: password.url!)
|
||||||
let newPasswordEntity = try addPasswordEntities(password: password)
|
let newPasswordEntity = try addPasswordEntities(password: password)
|
||||||
let saveURL = storeURL.appendingPathComponent(password.url!.path)
|
let saveURL = storeURL.appendingPathComponent(password.url!.path)
|
||||||
|
|
@ -624,7 +622,7 @@ class PasswordStore {
|
||||||
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func edit(passwordEntity: PasswordEntity, password: Password) throws -> PasswordEntity? {
|
public func edit(passwordEntity: PasswordEntity, password: Password) throws -> PasswordEntity? {
|
||||||
var newPasswordEntity: PasswordEntity? = passwordEntity
|
var newPasswordEntity: PasswordEntity? = passwordEntity
|
||||||
|
|
||||||
if password.changed&PasswordChange.content.rawValue != 0 {
|
if password.changed&PasswordChange.content.rawValue != 0 {
|
||||||
|
|
@ -670,7 +668,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveUpdated(passwordEntity: PasswordEntity) {
|
public func saveUpdated(passwordEntity: PasswordEntity) {
|
||||||
do {
|
do {
|
||||||
try context.save()
|
try context.save()
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -678,7 +676,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteCoreData(entityName: String) {
|
public func deleteCoreData(entityName: String) {
|
||||||
let deleteFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
|
let deleteFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
|
||||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest)
|
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetchRequest)
|
||||||
|
|
||||||
|
|
@ -691,7 +689,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateImage(passwordEntity: PasswordEntity, image: Data?) {
|
public func updateImage(passwordEntity: PasswordEntity, image: Data?) {
|
||||||
guard let image = image else {
|
guard let image = image else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -714,7 +712,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func erase() {
|
public func erase() {
|
||||||
publicKey = nil
|
publicKey = nil
|
||||||
privateKey = nil
|
privateKey = nil
|
||||||
Utils.removeFileIfExists(at: storeURL)
|
Utils.removeFileIfExists(at: storeURL)
|
||||||
|
|
@ -736,7 +734,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the number of discarded commits
|
// return the number of discarded commits
|
||||||
func reset() throws -> Int {
|
public func reset() throws -> Int {
|
||||||
guard let storeRepository = storeRepository else {
|
guard let storeRepository = storeRepository else {
|
||||||
throw AppError.RepositoryNotSetError
|
throw AppError.RepositoryNotSetError
|
||||||
}
|
}
|
||||||
|
|
@ -761,7 +759,7 @@ class PasswordStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func numberOfLocalCommits() -> Int {
|
public func numberOfLocalCommits() -> Int {
|
||||||
do {
|
do {
|
||||||
if let localCommits = try getLocalCommits() {
|
if let localCommits = try getLocalCommits() {
|
||||||
return localCommits.count
|
return localCommits.count
|
||||||
|
|
@ -795,7 +793,7 @@ class PasswordStore {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? {
|
public func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? {
|
||||||
let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.path!)
|
let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.path!)
|
||||||
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
let encryptedData = try Data(contentsOf: encryptedDataPath)
|
||||||
var passphrase = self.pgpKeyPassphrase
|
var passphrase = self.pgpKeyPassphrase
|
||||||
|
|
@ -808,16 +806,16 @@ class PasswordStore {
|
||||||
return Password(name: passwordEntity.name!, url: URL(string: escapedPath), plainText: plainText)
|
return Password(name: passwordEntity.name!, url: URL(string: escapedPath), plainText: plainText)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encrypt(password: Password) throws -> Data {
|
public func encrypt(password: Password) throws -> Data {
|
||||||
guard let publicKey = pgp.getKeysOf(.public).first else {
|
guard let publicKey = pgp.getKeysOf(.public).first else {
|
||||||
throw AppError.PGPPublicKeyNotExistError
|
throw AppError.PGPPublicKeyNotExistError
|
||||||
}
|
}
|
||||||
let plainData = password.getPlainData()
|
let plainData = password.getPlainData()
|
||||||
let encryptedData = try pgp.encryptData(plainData, usingPublicKey: publicKey, armored: Defaults[.encryptInArmored])
|
let encryptedData = try pgp.encryptData(plainData, usingPublicKey: publicKey, armored: SharedDefaults[.encryptInArmored])
|
||||||
return encryptedData
|
return encryptedData
|
||||||
}
|
}
|
||||||
|
|
||||||
func removePGPKeys() {
|
public func removePGPKeys() {
|
||||||
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||||
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||||
Defaults.remove(.pgpKeySource)
|
Defaults.remove(.pgpKeySource)
|
||||||
|
|
@ -831,18 +829,18 @@ class PasswordStore {
|
||||||
privateKey = nil
|
privateKey = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeGitSSHKeys() {
|
public func removeGitSSHKeys() {
|
||||||
Utils.removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||||
Defaults.remove(.gitSSHPrivateKeyArmor)
|
Defaults.remove(.gitSSHPrivateKeyArmor)
|
||||||
Defaults.remove(.gitSSHPrivateKeyURL)
|
Defaults.remove(.gitSSHPrivateKeyURL)
|
||||||
Utils.removeKeychain(name: ".gitSSHPrivateKeyPassphrase")
|
Utils.removeKeychain(name: ".gitSSHPrivateKeyPassphrase")
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitSSHKeyExists() -> Bool {
|
public func gitSSHKeyExists() -> Bool {
|
||||||
return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
|
return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pgpKeyExists() -> Bool {
|
public func pgpKeyExists() -> Bool {
|
||||||
return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath)
|
return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12124.1" systemVersion="16E175b" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16F73" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="PasswordEntity" representedClassName="PasswordEntity" syncable="YES" codeGenerationType="class">
|
<entity name="PasswordEntity" representedClassName="PasswordEntity" syncable="YES" codeGenerationType="class">
|
||||||
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
|
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
|
||||||
<attribute name="isDir" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
<attribute name="isDir" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||||
15
passKit/passKit.h
Normal file
15
passKit/passKit.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// passKit.h
|
||||||
|
// passKit
|
||||||
|
//
|
||||||
|
// Created by Yishi Lin on 11/6/17.
|
||||||
|
// Copyright © 2017年 Bob Sun. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
//! Project version number for passKit.
|
||||||
|
FOUNDATION_EXPORT double passKitVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for passKit.
|
||||||
|
FOUNDATION_EXPORT const unsigned char passKitVersionString[];
|
||||||
|
|
@ -8,10 +8,12 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
|
import passKit
|
||||||
|
|
||||||
class ActionViewController: UIViewController {
|
class ActionViewController: UIViewController {
|
||||||
|
|
||||||
@IBOutlet weak var textView: UITextView!
|
@IBOutlet weak var textView: UITextView!
|
||||||
|
let passwordStore = PasswordStore.shared
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
@ -23,9 +25,32 @@ class ActionViewController: UIViewController {
|
||||||
provider.loadItem(forTypeIdentifier: propertyList, options: nil, completionHandler: { (item, error) -> Void in
|
provider.loadItem(forTypeIdentifier: propertyList, options: nil, completionHandler: { (item, error) -> Void in
|
||||||
let dictionary = item as! NSDictionary
|
let dictionary = item as! NSDictionary
|
||||||
let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as! NSDictionary
|
let results = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as! NSDictionary
|
||||||
let url = results["url"] as? String
|
let url = URL(string: (results["url"] as? String)!)?.host
|
||||||
|
|
||||||
|
let numberFormatter = NumberFormatter()
|
||||||
|
numberFormatter.numberStyle = NumberFormatter.Style.decimal
|
||||||
|
|
||||||
|
let numberOfPasswordsString = "Number of password:" + numberFormatter.string(from: NSNumber(value: self.passwordStore.numberOfPasswords))!
|
||||||
|
let sizeOfRepositoryString = "Size of repo:" + ByteCountFormatter.string(fromByteCount: Int64(self.passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)
|
||||||
|
var numberOfCommits: UInt = 0
|
||||||
|
|
||||||
|
do {
|
||||||
|
if let _ = try self.passwordStore.storeRepository?.currentBranch().oid {
|
||||||
|
numberOfCommits = self.passwordStore.storeRepository?.numberOfCommits(inCurrentBranch: NSErrorPointer(nilLiteral: ())) ?? 0
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
let numberOfCommitsString = "Number of commits:" + numberFormatter.string(from: NSNumber(value: numberOfCommits))!
|
||||||
|
|
||||||
|
let gitURL = SharedDefaults[.gitURL]!
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.textView.text = url
|
self?.textView.text = url!
|
||||||
|
print(numberOfPasswordsString)
|
||||||
|
print(numberOfCommitsString)
|
||||||
|
print(sizeOfRepositoryString)
|
||||||
|
print(gitURL)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue