Skip to content

Commit

Permalink
Load validation from CDN.
Browse files Browse the repository at this point in the history
Fix issue where DB connections where not properly filtered
  • Loading branch information
hzalaz committed Sep 20, 2016
1 parent 728e262 commit ee9b64e
Show file tree
Hide file tree
Showing 13 changed files with 51 additions and 53 deletions.
10 changes: 6 additions & 4 deletions Lock/CDNLoaderInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ struct CDNLoaderInteractor: RemoteConnectionLoader, Loggable {
let json = try NSJSONSerialization.JSONObjectWithData(jsonp.dataUsingEncoding(NSUTF8StringEncoding)!, options: []) as? JSONObject
self.logger.debug("Client configuration is \(json)")
let info = ClientInfo(json: json)
if let auth0 = info.auth0, let connection = auth0.connections.first {
let requiresUsername = connection.booleanValue(forKey: "requires_username")
connections.database(name: connection.name, requiresUsername: requiresUsername, usernameValidator: connection.usernameValidation)
if let auth0 = info.auth0 {
auth0.connections.forEach { connection in
let requiresUsername = connection.booleanValue(forKey: "requires_username")
connections.database(name: connection.name, requiresUsername: requiresUsername, usernameValidator: connection.usernameValidation)
}
}
info.oauth2.forEach { strategy in
strategy.connections.forEach { connections.social(name: $0.name, style: AuthStyle.style(forStrategy: strategy.name, connectionName: $0.name)) }
Expand Down Expand Up @@ -150,7 +152,7 @@ private struct ConnectionInfo {

func booleanValue(forKey key: String, defaultValue: Bool = false) -> Bool { return json[key] as? Bool ?? defaultValue }

var usernameValidation: InputValidator {
var usernameValidation: UsernameValidator {
let validation = json["validation"] as? JSONObject
let username = validation?["username"] as? JSONObject
switch (username?["min"], username?["max"]) {
Expand Down
4 changes: 2 additions & 2 deletions Lock/ConnectionBuildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public protocol ConnectionBuildable: Connections {
- parameter usernameValidator: custom validator for username. Connection must allow username
- important: Only **ONE** database connection can be used so subsequent calls will override the previous value
*/
mutating func database(name name: String, requiresUsername: Bool, usernameValidator: InputValidator)
mutating func database(name name: String, requiresUsername: Bool, usernameValidator: UsernameValidator)

/**
Adds a new social connection
Expand Down Expand Up @@ -66,7 +66,7 @@ public extension ConnectionBuildable {
- parameter usernameValidator: custom validator for username. Connection must allow username and defaults to 1..15 characters
- important: Only **ONE** database connection can be used so subsequent calls will override the previous value
*/
public mutating func database(name name: String, requiresUsername: Bool, usernameValidator: InputValidator = UsernameValidator()) {
public mutating func database(name name: String, requiresUsername: Bool, usernameValidator: UsernameValidator = UsernameValidator()) {
self.database(name: name, requiresUsername: requiresUsername, usernameValidator: usernameValidator)
}

Expand Down
4 changes: 2 additions & 2 deletions Lock/Connections.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public protocol Connections {
public struct DatabaseConnection {
public let name: String
public let requiresUsername: Bool
public let usernameValidator: InputValidator
public let usernameValidator: UsernameValidator

public init(name: String, requiresUsername: Bool, usernameValidator: InputValidator = UsernameValidator()) {
public init(name: String, requiresUsername: Bool, usernameValidator: UsernameValidator = UsernameValidator()) {
self.name = name
self.requiresUsername = requiresUsername
self.usernameValidator = usernameValidator
Expand Down
4 changes: 2 additions & 2 deletions Lock/DatabaseForgotPasswordPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class DatabaseForgotPasswordPresenter: Presentable, Loggable {
try self.interactor.updateEmail(input.text)
input.showValid()
} catch let error as InputValidationError {
input.showError(error.localizedMessage)
input.showError(error.localizedMessage(withConnection: self.database))
} catch {
input.showError()
}
Expand Down Expand Up @@ -80,4 +80,4 @@ class DatabaseForgotPasswordPresenter: Presentable, Loggable {
}
return view
}
}
}
4 changes: 2 additions & 2 deletions Lock/DatabasePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class DatabasePresenter: Presentable, Loggable {
try self.authenticator.update(attr, value: input.text)
input.showValid()
} catch let error as InputValidationError {
input.showError(error.localizedMessage)
input.showError(error.localizedMessage(withConnection: self.database))
} catch {
input.showError()
}
Expand All @@ -205,4 +205,4 @@ private func safariBuilder(forURL url: NSURL, navigator: Navigable) -> (UIAlertA
let safari = SFSafariViewController(URL: url)
navigator.present(safari)
}
}
}
7 changes: 4 additions & 3 deletions Lock/InputValidationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ enum InputValidationError: ErrorType {
case NotAUsername
case NotAOneTimePassword

var localizedMessage: String {
func localizedMessage(withConnection connection: DatabaseConnection) -> String {
switch self {
case .NotAUsername:
return "Can only contain between 1 to 15 alphanumeric characters and \'_\'.".i18n(key: "com.auth0.lock.input.username.error", comment: "invalid username")
let format = "Can only contain between %d to %d alphanumeric characters and \'_\'.".i18n(key: "com.auth0.lock.input.username.error", comment: "invalid username")
return String(format: format, connection.usernameValidator.min, connection.usernameValidator.max)
case .NotAnEmailAddress:
return "Must be a valid email address".i18n(key: "com.auth0.lock.input.email.error", comment: "invalid email")
case .MustNotBeEmpty:
Expand All @@ -40,4 +41,4 @@ enum InputValidationError: ErrorType {
return "Must be a valid numeric code".i18n(key: "com.auth0.lock.input.otp.error", comment: "invalid otp")
}
}
}
}
4 changes: 2 additions & 2 deletions Lock/MultifactorPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class MultifactorPresenter: Presentable, Loggable {
try self.interactor.setMultifactorCode(input.text)
input.showValid()
} catch let error as InputValidationError {
input.showError(error.localizedMessage)
input.showError(error.localizedMessage(withConnection: self.database))
} catch {
input.showError()
}
Expand Down Expand Up @@ -75,4 +75,4 @@ class MultifactorPresenter: Presentable, Loggable {
view.primaryButton?.onPress = action
return view
}
}
}
11 changes: 5 additions & 6 deletions Lock/OfflineConnections.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ import Foundation

struct OfflineConnections: ConnectionBuildable {

private (set) var database: DatabaseConnection? = nil
private (set) var databases: [DatabaseConnection] = []
var database: DatabaseConnection? { return self.databases.first }
private (set) var oauth2: [OAuth2Connection] = []

mutating func database(name name: String, requiresUsername: Bool, usernameValidator: InputValidator = UsernameValidator()) {
self.database = DatabaseConnection(name: name, requiresUsername: requiresUsername, usernameValidator: usernameValidator)
mutating func database(name name: String, requiresUsername: Bool, usernameValidator: UsernameValidator = UsernameValidator()) {
self.databases.append(DatabaseConnection(name: name, requiresUsername: requiresUsername, usernameValidator: usernameValidator))
}

mutating func social(name name: String, style: AuthStyle) {
Expand All @@ -46,9 +47,7 @@ struct OfflineConnections: ConnectionBuildable {

func select(byNames names: [String]) -> OfflineConnections {
var connections = OfflineConnections()
if let database = self.database where isWhitelisted(connectionName: database.name, inList: names) {
connections.database = database
}
connections.databases = self.databases.filter { isWhitelisted(connectionName: $0.name, inList: names) }
connections.oauth2 = self.oauth2.filter { isWhitelisted(connectionName: $0.name, inList: names) }
return connections
}
Expand Down
18 changes: 8 additions & 10 deletions Lock/Validators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,33 @@

import Foundation

public protocol InputValidator {
protocol InputValidator {
func validate(value: String?) -> ErrorType?
}

public func usernameLength(atLeast min: Int, upTo max: Int) -> InputValidator {
guard min < max else { return UsernameValidator() }
return UsernameValidator(range: min...max)
}

struct OneTimePasswordValidator: InputValidator {
public class OneTimePasswordValidator: InputValidator {
func validate(value: String?) -> ErrorType? {
guard let value = value?.trimmed where !value.isEmpty else { return InputValidationError.MustNotBeEmpty }
guard value.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet()) != nil else { return InputValidationError.NotAOneTimePassword }
return nil
}
}

struct NonEmptyValidator: InputValidator {
public class NonEmptyValidator: InputValidator {
func validate(value: String?) -> ErrorType? {
guard let value = value?.trimmed where !value.isEmpty else { return InputValidationError.MustNotBeEmpty }
return nil
}
}

struct UsernameValidator: InputValidator {
public class UsernameValidator: InputValidator {

let invalidSet: NSCharacterSet
let range: Range<Int>

var min: Int { return self.range.startIndex }
var max: Int { return self.range.endIndex - 1 }

init(range: Range<Int> = 1...15) {
let set = NSMutableCharacterSet()
set.formUnionWithCharacterSet(NSCharacterSet.alphanumericCharacterSet())
Expand All @@ -67,7 +65,7 @@ struct UsernameValidator: InputValidator {
}
}

struct EmailValidator: InputValidator {
public class EmailValidator: InputValidator {
let predicate: NSPredicate

init() {
Expand Down
4 changes: 2 additions & 2 deletions LockTests/Interactors/CDNLoaderInteractorSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class CDNLoaderInteractorSpec: QuickSpec {
expect(connections?.database).toEventuallyNot(beNil())
expect(connections?.database?.name).toEventually(equal(databaseConnection))
expect(connections?.database?.requiresUsername).toEventually(beFalsy())
let validator = connections?.database?.usernameValidator as? UsernameValidator
let validator = connections?.database?.usernameValidator
expect(validator?.range.startIndex) == 10
expect(validator?.range.endIndex) == 201
}
Expand All @@ -152,7 +152,7 @@ class CDNLoaderInteractorSpec: QuickSpec {
expect(connections?.database).toEventuallyNot(beNil())
expect(connections?.database?.name).toEventually(equal(databaseConnection))
expect(connections?.database?.requiresUsername).toEventually(beFalsy())
let validator = connections?.database?.usernameValidator as? UsernameValidator
let validator = connections?.database?.usernameValidator
expect(validator?.range.startIndex) == 9
expect(validator?.range.endIndex) == 101
}
Expand Down
12 changes: 11 additions & 1 deletion LockTests/Models/OfflineConnectionsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,18 @@ class OfflineConnectionsSpec: QuickSpec {
expect(filtered.oauth2).to(beEmpty())
}

it("should select by name database connection") {
var connections = OfflineConnections()
connections.database(name: connection, requiresUsername: false)
connections.database(name: "another-connection", requiresUsername: false)
connections.social(name: "facebook", style: .Facebook)
let filtered = connections.select(byNames: [connection])
expect(filtered.database?.name) == connection
expect(filtered.oauth2).to(beEmpty())
}

}

}

}
}
10 changes: 5 additions & 5 deletions LockTests/Presenters/AuthPresenterSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,25 @@ class AuthPresenterSpec: QuickSpec {
}

it("should return view with expanded mode for single connection") {
let connections = OfflineConnections(database: nil, oauth2: mockConnections(count: 1))
let connections = OfflineConnections(databases: [], oauth2: mockConnections(count: 1))
presenter = AuthPresenter(connections: connections, interactor: interactor, customStyle: [:])
expect(presenter.newViewToEmbed(withInsets: UIEdgeInsetsZero).mode).to(beExpandedMode())
}

it("should return view with expanded mode and signup flag") {
let connections = OfflineConnections(database: nil, oauth2: mockConnections(count: 1))
let connections = OfflineConnections(databases: [], oauth2: mockConnections(count: 1))
presenter = AuthPresenter(connections: connections, interactor: interactor, customStyle: [:])
expect(presenter.newViewToEmbed(withInsets: UIEdgeInsetsZero, isLogin: false).mode).to(beExpandedMode(isLogin: false))
}

it("should return view with expanded mode for two connections") {
let connections = OfflineConnections(database: nil, oauth2: mockConnections(count: 2))
let connections = OfflineConnections(databases: [], oauth2: mockConnections(count: 2))
presenter = AuthPresenter(connections: connections, interactor: interactor, customStyle: [:])
expect(presenter.newViewToEmbed(withInsets: UIEdgeInsetsZero).mode).to(beExpandedMode())
}

it("should return view with compact mode for more than three connecitons") {
let connections = OfflineConnections(database: nil, oauth2: mockConnections(count: Int(arc4random_uniform(10)) + 3))
let connections = OfflineConnections(databases: [], oauth2: mockConnections(count: Int(arc4random_uniform(10)) + 3))
presenter = AuthPresenter(connections: connections, interactor: interactor, customStyle: [:])
expect(presenter.newViewToEmbed(withInsets: UIEdgeInsetsZero).mode).to(beCompactMode())
}
Expand Down Expand Up @@ -114,4 +114,4 @@ class AuthPresenterSpec: QuickSpec {
}
}

}
}
12 changes: 0 additions & 12 deletions LockTests/UsernameValidatorSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,6 @@ class UsernameValidatorSpec: QuickSpec {

override func spec() {

it("should return validator using builder") {
let validator = usernameLength(atLeast: 1, upTo: 20) as? UsernameValidator
expect(validator?.range.startIndex) == 1
expect(validator?.range.endIndex) == 21
}

it("should return validator using builder with default values when invalid") {
let validator = usernameLength(atLeast: 100, upTo: 20) as? UsernameValidator
expect(validator?.range.startIndex) == 1
expect(validator?.range.endIndex) == 16
}

context("default") {
var validator: UsernameValidator { return UsernameValidator() }

Expand Down

0 comments on commit ee9b64e

Please sign in to comment.