Skip to content

Commit

Permalink
PasswordManager no longer optional
Browse files Browse the repository at this point in the history
Refactored PasswordManagerConfig -> OnePassword
Cleaned up PasswordManager usage
Additional tests
Reduced IconButton Size
  • Loading branch information
cocojoe committed Apr 20, 2017
1 parent 7599a11 commit 0753496
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 75 deletions.
4 changes: 1 addition & 3 deletions Lock/ClassicRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ struct ClassicRouter: Router {
guard self.lock.options.allow != [.ResetPassword] && self.lock.options.initialScreen != .resetPassword else { return forgotPassword }
let authentication = self.lock.authentication
let interactor = DatabaseInteractor(connection: database, authentication: authentication, user: self.user, options: self.lock.options, dispatcher: lock.observerStore)
self.lock.options.passwordManager.controller = self.controller
let presenter = DatabasePresenter(interactor: interactor, connection: database, navigator: self, options: self.lock.options)
if self.lock.options.passwordManager.enabled, OnePassword.isAvailable() {
presenter.passwordManager = OnePassword(withConfig: self.lock.options.passwordManager, controller: self.controller)
}
if !oauth2.isEmpty {
let interactor = Auth0OAuth2Interactor(authentication: self.lock.authentication, dispatcher: lock.observerStore, options: self.lock.options, nativeHandlers: self.lock.nativeHandlers)
presenter.authPresenter = AuthPresenter(connections: oauth2, interactor: interactor, customStyle: self.lock.style.oauth2)
Expand Down
16 changes: 8 additions & 8 deletions Lock/DatabaseOnlyView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class DatabaseOnlyView: UIView, DatabaseView {
private let separatorIndex = 2
private let socialIndex = 1

func showLogin(withIdentifierStyle style: DatabaseIdentifierStyle, identifier: String? = nil, authCollectionView: AuthCollectionView? = nil, passwordManager: PasswordManager?) {
func showLogin(withIdentifierStyle style: DatabaseIdentifierStyle, identifier: String? = nil, authCollectionView: AuthCollectionView? = nil, passwordManager: PasswordManager) {
let form = CredentialView()

let type: InputField.InputType
Expand All @@ -109,15 +109,15 @@ class DatabaseOnlyView: UIView, DatabaseView {
self.layoutSecondaryButton(self.allowedModes.contains(.ResetPassword))
self.form = form

if var passwordManager = passwordManager {
if passwordManager.enabled, passwordManager.isAvailable() {
self.passwordManagerButton = form.passwordField.addFieldButton(withIcon: "ic_onepassword", color: UIColor(red: 0.5725, green: 0.5804, blue: 0.5843, alpha: 1.0))
passwordManager.fields[AppExtensionUsernameKey] = form.identityField
passwordManager.fields[AppExtensionPasswordKey] = form.passwordField
passwordManager.setFields([AppExtensionUsernameKey: form.identityField,
AppExtensionPasswordKey: form.passwordField])
}

}

func showSignUp(withUsername showUsername: Bool, username: String?, email: String?, authCollectionView: AuthCollectionView? = nil, additionalFields: [CustomTextField], passwordPolicyValidator: PasswordPolicyValidator? = nil, passwordManager: PasswordManager?) {
func showSignUp(withUsername showUsername: Bool, username: String?, email: String?, authCollectionView: AuthCollectionView? = nil, additionalFields: [CustomTextField], passwordPolicyValidator: PasswordPolicyValidator? = nil, passwordManager: PasswordManager) {
let form = SignUpView(additionalFields: additionalFields)
form.showUsername = showUsername
form.emailField.text = email
Expand Down Expand Up @@ -154,10 +154,10 @@ class DatabaseOnlyView: UIView, DatabaseView {
}
}

if var passwordManager = passwordManager {
if passwordManager.enabled, passwordManager.isAvailable() {
self.passwordManagerButton = form.passwordField.addFieldButton(withIcon: "ic_onepassword", color: UIColor(red: 0.5725, green: 0.5804, blue: 0.5843, alpha: 1.0))
passwordManager.fields[AppExtensionUsernameKey] = showUsername ? form.usernameField : form.emailField
passwordManager.fields[AppExtensionPasswordKey] = form.passwordField
passwordManager.setFields([AppExtensionUsernameKey: showUsername ? form.usernameField : form.emailField,
AppExtensionPasswordKey: form.passwordField ])
}
}

Expand Down
11 changes: 6 additions & 5 deletions Lock/DatabasePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class DatabasePresenter: Presentable, Loggable {
}
}

var passwordManager: PasswordManager?
var passwordManager: PasswordManager

var authPresenter: AuthPresenter?
var enterpriseInteractor: EnterpriseDomainInteractor?
Expand All @@ -59,6 +59,7 @@ class DatabasePresenter: Presentable, Loggable {
self.database = connection
self.navigator = navigator
self.options = options
self.passwordManager = options.passwordManager
}

var view: View {
Expand Down Expand Up @@ -149,9 +150,9 @@ class DatabasePresenter: Presentable, Loggable {
self.navigator.navigate(.forgotPassword)
}

if let passwordManager = self.passwordManager, let passwordButton = view.passwordManagerButton {
if self.passwordManager.enabled, let passwordButton = view.passwordManagerButton {
passwordButton.onPress = { _ in
passwordManager.login { error, result in
self.passwordManager.login { error, result in
guard error == nil else {
return self.logger.error("There was a problem with the password manager: \(error)")
}
Expand Down Expand Up @@ -219,9 +220,9 @@ class DatabasePresenter: Presentable, Loggable {
self.navigator.present(alert)
}

if let passwordManager = self.passwordManager, let passwordButton = view.passwordManagerButton {
if self.passwordManager.enabled, let passwordButton = view.passwordManagerButton {
passwordButton.onPress = { _ in
passwordManager.store(withPolicy: passwordPolicyValidator?.policy.onePasswordRules()) { error, result in
self.passwordManager.store(withPolicy: passwordPolicyValidator?.policy.onePasswordRules()) { error, result in
guard error == nil else {
return self.logger.error("There was a problem with the password manager: \(error)")
}
Expand Down
4 changes: 2 additions & 2 deletions Lock/DatabaseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protocol DatabaseView: View, NSObjectProtocol {

var allowedModes: DatabaseMode { get }

func showLogin(withIdentifierStyle style: DatabaseIdentifierStyle, identifier: String?, authCollectionView: AuthCollectionView?, passwordManager: PasswordManager?)
func showLogin(withIdentifierStyle style: DatabaseIdentifierStyle, identifier: String?, authCollectionView: AuthCollectionView?, passwordManager: PasswordManager)
// swiftlint:disable:next function_parameter_count
func showSignUp(withUsername showUsername: Bool, username: String?, email: String?, authCollectionView: AuthCollectionView?, additionalFields: [CustomTextField], passwordPolicyValidator: PasswordPolicyValidator?, passwordManager: PasswordManager?)
func showSignUp(withUsername showUsername: Bool, username: String?, email: String?, authCollectionView: AuthCollectionView?, additionalFields: [CustomTextField], passwordPolicyValidator: PasswordPolicyValidator?, passwordManager: PasswordManager)
}
1 change: 1 addition & 0 deletions Lock/IconButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class IconButton: UIView {
button.translatesAutoresizingMaskIntoConstraints = false

button.addTarget(self, action: #selector(pressed), for: .touchUpInside)
button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
self.button = button
}

Expand Down
1 change: 0 additions & 1 deletion Lock/InputField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ class InputField: UIView, UITextFieldDelegate {
let button = IconButton()
button.icon = LazyImage(name: name, bundle: Lock.bundle).image(compatibleWithTraits: self.traitCollection)
button.color = color
button.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
container.addSubview(button)

self.textFieldRightPadding?.constant = -50
Expand Down
2 changes: 1 addition & 1 deletion Lock/LockOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ struct LockOptions: OptionBuildable {
var audience: String?

var passwordlessMethod: PasswordlessMethod = .code
var passwordManager: PasswordManagerConfig = PasswordManagerConfig()
var passwordManager: OnePassword = OnePassword()
}
53 changes: 25 additions & 28 deletions Lock/OnePassword.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,45 @@
import Foundation

protocol PasswordManager {
var fields: [String: InputField] { get set }

static func isAvailable() -> Bool
var enabled: Bool { get set }
func setFields(_ fields: [String: InputField?])

func isAvailable() -> Bool
func login(callback: @escaping (Error?, [String: InputField]?) -> Void)
func store(withPolicy policy: [String: Any]?, callback: @escaping (Error?, [String: InputField]?) -> Void)
}

class OnePassword: PasswordManager {
public class OnePassword: PasswordManager {

/// A Boolean value indicating whether the password manager is enabled.
public var enabled: Bool = true

/// The text identifier to use with the password manager to identify which credentials to use.
public var appIdentifier: String

/// The title to be displayed when creating a new password manager entry.
public var displayName: String

let config: PasswordManagerConfig
weak var controller: UIViewController?
var fields: [String: InputField] = [:]

required init(withConfig config: PasswordManagerConfig, controller: UIViewController?) {
self.config = config
self.controller = controller
public init() {
self.appIdentifier = Bundle.main.bundleIdentifier!
self.displayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String
}

static func isAvailable() -> Bool {
func isAvailable() -> Bool {
return OnePasswordExtension.shared().isAppExtensionAvailable()
}

func setFields(_ fields: [String: InputField?]) {
fields.forEach { self.fields[$0] = $1 }
}

func login(callback: @escaping (Error?, [String: InputField]?) -> Void) {
guard let controller = self.controller else { return }
OnePasswordExtension.shared().findLogin(forURLString: self.config.appIdentifier, for: controller, sender: nil) { (result, error) in
OnePasswordExtension.shared().findLogin(forURLString: self.appIdentifier, for: controller, sender: nil) { (result, error) in
guard error == nil else {
return callback(error, nil)
}
Expand All @@ -59,9 +73,9 @@ class OnePassword: PasswordManager {

func store(withPolicy policy: [String: Any]?, callback: @escaping (Error?, [String: InputField]?) -> Void) {
guard let controller = self.controller else { return }
var loginDetails: [String: String] = [ AppExtensionTitleKey: self.config.displayName ]
var loginDetails: [String: String] = [ AppExtensionTitleKey: self.displayName ]
self.fields.forEach { loginDetails[$0] = $1.text }
OnePasswordExtension.shared().storeLogin(forURLString: self.config.appIdentifier, loginDetails: loginDetails, passwordGenerationOptions: policy, for: controller, sender: nil) { (result, error) in
OnePasswordExtension.shared().storeLogin(forURLString: self.appIdentifier, loginDetails: loginDetails, passwordGenerationOptions: policy, for: controller, sender: nil) { (result, error) in
guard error == nil else {
return callback(error, nil)
}
Expand All @@ -71,20 +85,3 @@ class OnePassword: PasswordManager {
}
}
}

public struct PasswordManagerConfig {

/// A Boolean value indicating whether the password manager is enabled.
public var enabled: Bool = true

/// The text identifier to use with the password manager to identify which credentials to use.
public var appIdentifier: String

/// The title to be displayed when creating a new password manager entry.
public var displayName: String

public init() {
self.appIdentifier = Bundle.main.bundleIdentifier!
self.displayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String
}
}
4 changes: 2 additions & 2 deletions Lock/OptionBuildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ public protocol OptionBuildable: Options {
/// Specify the passwordless method, send a passcode or magic link. By default is .code
var passwordlessMethod: PasswordlessMethod { get set }

/// Specify the passwordManager configuration, specify the appIdentifier, displyName and enable/disable manager. By default manager is enabled and defaults to the app's bundle identifier and display name.
var passwordManager: PasswordManagerConfig { get set }
/// Specify the password manager configuration, specify the appIdentifier, displyName and enable/disable manager. By default manager is enabled and defaults to the app's bundle identifier and display name.
var passwordManager: OnePassword { get set }
}

extension OptionBuildable {
Expand Down
2 changes: 1 addition & 1 deletion Lock/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ public protocol Options {
var audience: String? { get }

var passwordlessMethod: PasswordlessMethod { get }
var passwordManager: PasswordManagerConfig { get }
var passwordManager: OnePassword { get }
}
42 changes: 22 additions & 20 deletions LockTests/OnePasswordSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,44 +31,46 @@ class OnePasswordSpec: QuickSpec {

var onePassword: OnePassword?
var viewController: MockViewController?
var passwordConfig: PasswordManagerConfig!

describe("availability") {
describe("init") {

it("should not be available without 1password installed") {
expect(OnePassword.isAvailable()) == false
beforeEach {
onePassword = nil
}

it("should init with defaults") {
onePassword = OnePassword()
expect(onePassword?.appIdentifier) == Bundle.main.bundleIdentifier!
expect(onePassword?.displayName) == Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String
expect(onePassword?.enabled) == true
}

it("should not be available without 1password installed") {
onePassword = OnePassword()
expect(onePassword?.isAvailable()) == false
}

}

describe("init") {
describe("data input") {

beforeEach {
onePassword = nil
viewController = MockViewController()
passwordConfig = PasswordManagerConfig()
onePassword = OnePassword()
}

it("should init with default config") {
onePassword = OnePassword(withConfig: passwordConfig, controller: nil)
expect(onePassword?.config.appIdentifier) == Bundle.main.bundleIdentifier!
expect(onePassword?.config.displayName) == Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String
expect(onePassword?.config.enabled) == true
it("should contain one inputfield") {
onePassword?.setFields(["field1": InputField()])
expect(onePassword?.fields.count) == 1
}

it("should init with identifier and controller") {
onePassword = OnePassword(withConfig: passwordConfig, controller: viewController)
expect(onePassword?.controller).to(equal(viewController))
}

}

describe("action") {

beforeEach {
viewController = MockViewController()
passwordConfig = PasswordManagerConfig()
onePassword = OnePassword(withConfig: passwordConfig, controller: viewController)
onePassword = OnePassword()
onePassword?.controller = viewController
}

it("should present extension prompt on login") {
Expand Down
22 changes: 22 additions & 0 deletions LockTests/Presenters/DatabasePresenterSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ class DatabasePresenterSpec: QuickSpec {
it("should show password manager button") {
expect(view.passwordManagerButton).toNot(beNil())
}

it("should not show password manager when disabled") {
presenter.passwordManager.enabled = false
view = presenter.view as! DatabaseOnlyView
expect(view.passwordManagerButton).to(beNil())
}
}

describe("user input") {
Expand Down Expand Up @@ -505,6 +511,22 @@ class DatabasePresenterSpec: QuickSpec {
it("should show password manager button") {
expect(view.passwordManagerButton).toNot(beNil())
}

context("disable password manager") {

beforeEach {
presenter.passwordManager = passwordManager
presenter.passwordManager.enabled = false
view = presenter.view as! DatabaseOnlyView
view.switcher?.selected = .signup
view.switcher?.onSelectionChange(view.switcher!)
}

it("should not show password manager when disabled") {
expect(view.passwordManagerButton).to(beNil())
}

}
}

}
Expand Down
12 changes: 9 additions & 3 deletions LockTests/Utils/Mocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -495,15 +495,21 @@ class MockPasswordlessInteractor: PasswordlessAuthenticatable {
}

class MockPasswordManager: PasswordManager {
static var available: Bool = true
var available: Bool = true

var enabled: Bool = true

var fields: [String: InputField] = [:]

func setFields(_ fields: [String: InputField?]) {
fields.forEach { self.fields[$0] = $1 }
}

var onLogin: ([String: InputField]) -> Void = {_ in }
var onStore: ([String: InputField]) -> Void = {_ in }

static func isAvailable() -> Bool {
return MockPasswordManager.available
func isAvailable() -> Bool {
return self.available
}

func login(callback: @escaping (Error?, [String: InputField]?) -> Void) {
Expand Down
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ coverage:
round: down
range: "70...100"
ignore:
- Lock/LockOnePasswordExtension.*
- Lock/OnePasswordExtension.*
- LockTests/*
- App/*
status:
Expand Down

0 comments on commit 0753496

Please sign in to comment.