Skip to content

Commit

Permalink
Merge branch 'release/0.2.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
mssun committed Mar 24, 2017
2 parents 852a0b8 + 449294e commit 02fe05c
Show file tree
Hide file tree
Showing 32 changed files with 655 additions and 391 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,24 @@ testing. Thank you.

## Features

- Try to be compatible with Password Store command line tool
- Try to be compatible with the Password Store command line tool
- Support to view, copy, add, edit password entries
- Encrypt and decrypt password entries by PGP keys
- Synchronize with you password Git repository
- Synchronize with your password Git repository
- User-friendly interface: search, long press to copy, copy and open link, etc.
- Support one-time password (OTP) tokens
- Written in Swift
- No need to jailbreak your devices
- Get from App Store (stay tuned, under review)
- Get from App Store (stay tuned)

## Screenshots

<p>
<img src="screenshot/preview.gif" width="200"/>
<img src="screenshot/screenshot1.png" width="200"/>
<img src="screenshot/screenshot2.png" width="200"/>
<img src="screenshot/screenshot3.png" width="200"/>
</p>

## Build

Expand Down
77 changes: 51 additions & 26 deletions pass/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

47 changes: 13 additions & 34 deletions pass/Controllers/AboutRepositoryTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,19 @@ import UIKit

class AboutRepositoryTableViewController: BasicStaticTableViewController {

var needRefresh = false
var indicatorLabel: UILabel!
var indicator: UIActivityIndicatorView!
let passwordStore = PasswordStore.shared
private var needRefresh = false
private var indicator: UIActivityIndicatorView = {
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
return indicator
}()
private let passwordStore = PasswordStore.shared

override func viewDidLoad() {
navigationItemTitle = "About Repository"
super.viewDidLoad()

indicatorLabel = UILabel(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 21))
indicatorLabel.center = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height * 0.382 + 22)
indicatorLabel.backgroundColor = UIColor.clear
indicatorLabel.textColor = UIColor.gray
indicatorLabel.text = "calculating"
indicatorLabel.textAlignment = .center
indicatorLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
indicator.center = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height * 0.382)

indicator.center = CGPoint(x: view.bounds.midX, y: view.bounds.height * 0.382)
tableView.addSubview(indicator)
tableView.addSubview(indicatorLabel)

setTableData()

Expand All @@ -40,7 +33,6 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if needRefresh {
indicatorLabel.text = "reloading"
setTableData()
needRefresh = false
}
Expand All @@ -51,45 +43,32 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
// clear current contents (if any)
self.tableData.removeAll(keepingCapacity: true)
self.tableView.reloadData()
indicatorLabel.isHidden = false
indicator.startAnimating()

// reload the table
DispatchQueue.global(qos: .userInitiated).async {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = NumberFormatter.Style.decimal
let fm = FileManager.default

let passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
let numberOfPasswords = numberFormatter.string(from: NSNumber(value: passwordEntities.count))!

var size = UInt64(0)
do {
if fm.fileExists(atPath: self.passwordStore.storeURL.path) {
size = try fm.allocatedSizeOfDirectoryAtURL(directoryURL: self.passwordStore.storeURL)
}
} catch {
print(error)
}
let sizeOfRepository = ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: ByteCountFormatter.CountStyle.file)
let numberOfPasswordsString = numberFormatter.string(from: NSNumber(value: self.passwordStore.numberOfPasswords))!
let sizeOfRepositoryString = ByteCountFormatter.string(fromByteCount: Int64(self.passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)

let numberOfCommits = self.passwordStore.storeRepository?.numberOfCommits(inCurrentBranch: NSErrorPointer(nilLiteral: ())) ?? 0
let numberOfCommitsString = numberFormatter.string(from: NSNumber(value: numberOfCommits))!


DispatchQueue.main.async { [weak self] in
let type = UITableViewCellAccessoryType.none
self?.tableData = [
// section 0
[[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: numberOfPasswords],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: sizeOfRepository], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Unsynced", .detailText: String(self?.passwordStore.getNumberOfUnsyncedPasswords() ?? 0)],
[[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: numberOfPasswordsString],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: sizeOfRepositoryString],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Local Commits", .detailText: String(self?.passwordStore.numberOfLocalCommits() ?? 0)],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: Utils.getLastUpdatedTimeString()],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: numberOfCommitsString],
[.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"],
],
]
self?.indicator.stopAnimating()
self?.indicatorLabel.isHidden = true
self?.tableView.reloadData()
}
}
Expand Down
1 change: 1 addition & 0 deletions pass/Controllers/AboutTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class AboutTableViewController: BasicStaticTableViewController {
tableData = [
// section 0
[[.title: "Website", .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
[.title: "Help", .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
[.title: "Contact Developer", .action: "link", .link: "mailto:bob@mssun.me?subject=passforiOS"],],

// section 1,
Expand Down
15 changes: 11 additions & 4 deletions pass/Controllers/AddPasswordTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import UIKit
import SwiftyUserDefaults

class AddPasswordTableViewController: PasswordEditorTableViewController {

var password: Password?
var tempContent: String = ""
let passwordStore = PasswordStore.shared

Expand All @@ -28,20 +26,29 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "saveAddPasswordSegue" {
// check PGP key
if passwordStore.privateKey == nil {
guard passwordStore.privateKey != nil else {
let alertTitle = "Cannot Add Password"
let alertMessage = "PGP Key is not set. Please set your PGP Key first."
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
return false
}

// check name
let nameCell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as! TextFieldTableViewCell
if nameCell.getContent()!.isEmpty {
guard nameCell.getContent()!.isEmpty == false else {
let alertTitle = "Cannot Add Password"
let alertMessage = "Please fill in the name."
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
return false
}

// check "/"
guard nameCell.getContent()!.contains("/") == false else {
let alertTitle = "Cannot Add Password"
let alertMessage = "Illegal character."
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
return false
}
}
return true
}
Expand Down
26 changes: 20 additions & 6 deletions pass/Controllers/AdvancedSettingsTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,34 @@

import UIKit
import SVProgressHUD
import SwiftyUserDefaults

class AdvancedSettingsTableViewController: UITableViewController {

@IBOutlet weak var encryptInASCIIArmoredTableViewCell: UITableViewCell!
@IBOutlet weak var eraseDataTableViewCell: UITableViewCell!
@IBOutlet weak var discardChangesTableViewCell: UITableViewCell!
let passwordStore = PasswordStore.shared

let encryptInASCIIArmoredSwitch: UISwitch = {
let uiSwitch = UISwitch()
uiSwitch.onTintColor = Globals.blue
uiSwitch.sizeToFit()
uiSwitch.addTarget(self, action: #selector(encryptInASCIIArmoredAction(_:)), for: UIControlEvents.valueChanged)
return uiSwitch
}()

override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Advanced"
encryptInASCIIArmoredSwitch.isOn = Defaults[.encryptInArmored]
encryptInASCIIArmoredTableViewCell.accessoryView = encryptInASCIIArmoredSwitch
encryptInASCIIArmoredTableViewCell.selectionStyle = .none
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if tableView.cellForRow(at: indexPath) == eraseDataTableViewCell {
print("erase data")
let alert = UIAlertController(title: "Erase Password Store Data?", message: "This will delete all local data and settings. Password store data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Erase Password Data", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
SVProgressHUD.show(withStatus: "Erasing ...")
Expand All @@ -32,7 +46,6 @@ class AdvancedSettingsTableViewController: UITableViewController {
}))
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil))
self.present(alert, animated: true, completion: nil)
tableView.deselectRow(at: indexPath, animated: true)
} else if tableView.cellForRow(at: indexPath) == discardChangesTableViewCell {
let alert = UIAlertController(title: "Discard All Changes?", message: "Do you want to permanently discard all changes to the local copy of your password data? You cannot undo this action.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Discard All Changes", style: UIAlertActionStyle.destructive, handler: {[unowned self] (action) -> Void in
Expand All @@ -52,18 +65,19 @@ class AdvancedSettingsTableViewController: UITableViewController {
}
SVProgressHUD.dismiss(withDelay: 1)
} catch {
DispatchQueue.main.async {
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
}
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
}
}
}

}))
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.cancel, handler:nil))
self.present(alert, animated: true, completion: nil)
tableView.deselectRow(at: indexPath, animated: true)
}
}

func encryptInASCIIArmoredAction(_ sender: Any?) {
Defaults[.encryptInArmored] = encryptInASCIIArmoredSwitch.isOn
}

}
13 changes: 6 additions & 7 deletions pass/Controllers/EditPasswordTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
import UIKit

class EditPasswordTableViewController: PasswordEditorTableViewController {

var password: Password?

override func viewDidLoad() {
tableData = [
[[.type: PasswordEditorCellType.textFieldCell, .title: "name", .content: password!.name]],
[[.type: PasswordEditorCellType.fillPasswordCell, .title: "password", .content: password!.password],
[.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"]],
[[.type: PasswordEditorCellType.textViewCell, .title: "additions", .content: password!.getAdditionsPlainText()]],
[[.type: PasswordEditorCellType.deletePasswordCell]],
]
super.viewDidLoad()
}
Expand All @@ -43,10 +41,11 @@ class EditPasswordTableViewController: PasswordEditorTableViewController {
var cellContents = [String: String]()
for cell in cells {
let indexPath = tableView.indexPath(for: cell)!
let contentCell = cell as! ContentTableViewCell
let cellTitle = tableData[indexPath.section][indexPath.row][.title] as! String
if let cellContent = contentCell.getContent() {
cellContents[cellTitle] = cellContent
if let contentCell = cell as? ContentTableViewCell {
let cellTitle = tableData[indexPath.section][indexPath.row][.title] as! String
if let cellContent = contentCell.getContent() {
cellContents[cellTitle] = cellContent
}
}
}
var plainText = ""
Expand Down
4 changes: 3 additions & 1 deletion pass/Controllers/GeneralSettingsTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,12 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {

func hideUnknownSwitchAction(_ sender: Any?) {
Defaults[.isHideUnknownOn] = hideUnknownSwitch.isOn
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
}

func hideOTPSwitchAction(_ sender: Any?) {
Defaults[.isHideOTPOn] = hideOTPSwitch.isOn
NotificationCenter.default.post(name: .passwordDetailDisplaySettingChanged, object: nil)
}

func rememberPassphraseSwitchAction(_ sender: Any?) {
Expand All @@ -184,7 +186,7 @@ class GeneralSettingsTableViewController: BasicStaticTableViewController {

func showFolderSwitchAction(_ sender: Any?) {
Defaults[.isShowFolderOn] = showFolderSwitch.isOn
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.post(name: .passwordDisplaySettingChanged, object: nil)
}

}
15 changes: 6 additions & 9 deletions pass/Controllers/GitServerSettingTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,12 @@ class GitServerSettingTableViewController: UITableViewController {

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "saveGitServerSettingSegue" {
if gitRepositoryURLTextField.text == "" || authenticationMethod == nil {
var alertMessage = ""
if gitRepositoryURLTextField.text == "" {
alertMessage = "Git Server is not set. Please set the Git server first."
}
if authenticationMethod == nil {
alertMessage = "Authentication method is not set. Please set your authentication method first."
}
Utils.alert(title: "Cannot Save Settings", message: alertMessage, controller: self, completion: nil)
guard let _ = URL(string: gitRepositoryURLTextField.text!) else {
Utils.alert(title: "Cannot Save", message: "Git Server is not set.", controller: self, completion: nil)
return false
}
guard authenticationMethod != nil else {
Utils.alert(title: "Cannot Save", message: "Authentication method is not set.", controller: self, completion: nil)
return false
}
}
Expand Down
19 changes: 6 additions & 13 deletions pass/Controllers/PGPKeySettingTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,15 @@ class PGPKeySettingTableViewController: UITableViewController {

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "savePGPKeySegue" {
guard pgpPublicKeyURLTextField.text != nil else {
return false
}
guard pgpPrivateKeyURLTextField.text != nil else {
return false
}

guard URL(string: pgpPublicKeyURLTextField.text!) != nil else {
guard let pgpPublicKeyURL = URL(string: pgpPublicKeyURLTextField.text!) else {
Utils.alert(title: "Cannot Save", message: "Please set Public Key URL first.", controller: self, completion: nil)
return false
}
guard URL(string: pgpPrivateKeyURLTextField.text!) != nil else {
guard let pgpPrivateKeyURL = URL(string: pgpPrivateKeyURLTextField.text!) else {
Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil)
return false
}

if URL(string: pgpPublicKeyURLTextField.text!)!.scheme! == "http" &&
URL(string: pgpPrivateKeyURLTextField.text!)!.scheme! == "http" {
guard pgpPublicKeyURL.scheme! == "https", pgpPrivateKeyURL.scheme! == "https" else {
Utils.alert(title: "Cannot Save Settings", message: "HTTP connection is not supported.", controller: self, completion: nil)
return false
}
Expand All @@ -55,7 +46,9 @@ class PGPKeySettingTableViewController: UITableViewController {
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
self.pgpPassphrase = alert.textFields?.first?.text
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
if self.shouldPerformSegue(withIdentifier: "savePGPKeySegue", sender: self) {
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
}
}))
alert.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = self.pgpPassphrase
Expand Down
Loading

0 comments on commit 02fe05c

Please sign in to comment.