Skip to content

Commit

Permalink
Logins+ authentication (#438)
Browse files Browse the repository at this point in the history
* Scroll to credentials found on a website.

* Select the first login if the match isn't found.

* Retain the filtering logic on 10.15.

* Remove the timer.

* Rename a view. Could still be clearer maybe?

* Drop the "www." prefix of domains when selecting.

* Work on login filtering.

* More sorting work. Inefficient at the moment though.

* Add new menu items. Need proper pixels.

* Update the images to be templates.

* Fix unit tests.

* Move sorting code out into a separate file.

* More sorting work.

* Monitor the scroll offset to fade in the divider.

* Use the custom NSPopUpButton in the PWM list view.

* Fix merge issues.

* Temporarily move back to VStack.

* Update the sorting icon.

* Update assets.

* Update filter UI styling.

* Rename some assets.

* Remove padding on the top section's title.

* Use category colors for the pop up button.

* Use the right appearance for allItems.

* Try adding an empty state.

* Silence a build warning.

* Add icons to the Add menu.

* Play with appearance changes.

* Add the rough PopUpButton implementation.

* Line up the category button frames.

* Change category picker colors.

* Improve the way empty states are displayed.

* Avoid uppercasing the month string.

* Sort out the image rendering issue once and for all.

* Update pixels.

* Work on self-review items.

* Fix unit test compilation.

* Add list section unit tests.

* Move strings into UserText.

* Add another section test.

* More UserText changes.

* Fix a compilation error when building for release.

* Remember the sort descriptor when opening Logins+.

* Fix the image issue… again!

* Partially fix the preferences divider rendering.

* Test out a way to detect the idle state of the system.

* Add the initial UI for Logins+ authentication.

* Store preferences in user defaults.

* Begin sketching out the authentication service flow.

* Avoid closing the popover when authenticating.

* Add logging.

* Implement more of the lock screen.

* Make sure that the timer runs all the time.

* Lock Logins+ while it’s visible.

* Use the correct LAContext policy.

* Add a new background color for the Auto-Lock screen.

* Rig up the user preferences link.

* Use the correct asset for the device state.

* Change the timer to 30 seconds.

* Make sure that the New Item buttons always work.

* Always authenticate credit card information.

* Set the dev timer to 15 seconds.

* Clean up some table view positioning.

* Prevent the GPC text from intercepting scrolling.

* More layout refinement.

* Tweak cell resizing.

* Clean up warnings.

* Intercept click events inside ColorView.

* Fix lock screen text colors.

* Re-enable a SwiftLint warning fix.

* Ensure that items within sections are sorted correctly.

* Use an empty to calculate the empty state.

* Update unit tests to reflect the sorting change.

* Add some unit tests for the new empty state logic.

* Fix self-review comments.

* Clean up some string value calculation.

* Clean up the new menu code.

* Swap to the correct category when selecting an item.

* Use the correct color for the unlock button.

* Dismiss the logins popover when clicking the Preferences button.

* Remove first responder when showing the lock screen.

* Clean up the NSImage tint function.

* Move the empty state code to its own section.

* Update the way selected items are managed.

* Disable category changes when editing.

* Don’t request permission every time settings change.

* Hide the password manager popover if clicking the button while it’s already visible.

* Avoid the default empty state appearing at unexpected times.

* Apply more dependency injection to the DeviceAuthenticator.

* Add unit tests.

* Disable the search field when editing.

* Point to the logins authentication BSK branch.

* Add pixels.

* Clean up some commented code.

* Fix a compilation error.

* Fix a couple last-minute issues.

* Display the correct unlock reason.

* Resolve self-review comments.

* Set the privacy dashboard back to the correct version.

* Remove a duplicate file.

* Remove the App Delegate timer call.

The app launches locked anyway.

* Fix unit tests.

* Resolve warnings now that Logins preferences aren’t a struct.

* Move remaining strings into UserText.

* update packages resolved

* Update the logins authentication BSK commit.

* Use an enum to return the authentication state.

* Update ContentOverlayViewController to implement SecureVaultManagerDelegate.

* Point to BSK 11.0.0.

Co-authored-by: Chris Brind <brindy@duckduckgo.com>
  • Loading branch information
samsymons and brindy authored Mar 1, 2022
1 parent f218745 commit 5b5986a
Show file tree
Hide file tree
Showing 48 changed files with 1,774 additions and 98 deletions.
62 changes: 61 additions & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/duckduckgo/BrowserServicesKit",
"state": {
"branch": null,
"revision": "b9c5cdb717c1d783e63e0fcfb16455f4db2a5d1a",
"version": "10.0.2"
"revision": "c4d86f4ac29d09dee34e144b4df9660cbf76df95",
"version": "11.0.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/AppDelegate/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
crashReporter.checkForNewReports()
#endif
urlEventHandler.applicationDidFinishLaunching()

UserDefaultsWrapper<Any>.clearRemovedKeys()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.100",
"blue" : "0.000",
"green" : "0.000",
"red" : "0.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.100",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.600",
"blue" : "0.000",
"green" : "0.000",
"red" : "0.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.600",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF0",
"green" : "0xEF",
"red" : "0xF1"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.200",
"green" : "0.200",
"red" : "0.200"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
12 changes: 12 additions & 0 deletions DuckDuckGo/Assets.xcassets/Images/Logins+.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Logins+.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "LoginsLockPassword.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"images" : [
{
"filename" : "LoginsLockTouchID.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "LoginsLockTouchID@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "LoginsLockTouchID@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions DuckDuckGo/Autofill/ContentOverlayViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public final class ContentOverlayViewController: NSViewController, EmailManagerR

lazy var vaultManager: SecureVaultManager = {
let manager = SecureVaultManager()
manager.delegate = self
return manager
}()

Expand Down Expand Up @@ -189,3 +190,25 @@ extension ContentOverlayViewController: OverlayAutofillUserScriptPresentationDel
self.requestResizeToSize(requestResizeToSize)
}
}

extension ContentOverlayViewController: SecureVaultManagerDelegate {

public func secureVaultManager(_: SecureVaultManager, promptUserToStoreCredentials credentials: SecureVaultModels.WebsiteCredentials) {
// No-op, the content overlay view controller should not be prompting the user to store credentials
}

public func secureVaultManager(_: SecureVaultManager, didAutofill type: AutofillType, withObjectId objectId: Int64) {
// No-op, Tab.swift handles this functionality
}

public func secureVaultManager(_: SecureVaultManager, didRequestAuthenticationWithCompletionHandler handler: @escaping (Bool) -> Void) {
DeviceAuthenticator.shared.authenticateUser(reason: .autofill) { authenticationResult in
handler(authenticationResult.authenticated)
}
}

public func secureVaultInitFailed(_ error: SecureVaultError) {
SecureVaultErrorReporter.shared.secureVaultInitFailed(error)
}

}
10 changes: 9 additions & 1 deletion DuckDuckGo/BrowserTab/Model/Tab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ final class Tab: NSObject {
return .homepage
} else if url == .welcome {
return .onboarding
} else if url == .preferences {
return .preferences
} else {
return .url(url ?? .blankPage)
}
Expand Down Expand Up @@ -699,7 +701,13 @@ extension Tab: SecureVaultManagerDelegate {

func secureVaultManager(_: SecureVaultManager, didAutofill type: AutofillType, withObjectId objectId: Int64) {
Pixel.fire(.formAutofilled(kind: type.formAutofillKind))
}
}

func secureVaultManager(_: SecureVaultManager, didRequestAuthenticationWithCompletionHandler handler: @escaping (Bool) -> Void) {
DeviceAuthenticator.shared.authenticateUser(reason: .autofill) { authenticationResult in
handler(authenticationResult.authenticated)
}
}

func secureVaultInitFailed(_ error: SecureVaultError) {
SecureVaultErrorReporter.shared.secureVaultInitFailed(error)
Expand Down
4 changes: 4 additions & 0 deletions DuckDuckGo/Common/Extensions/URLExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ extension URL {
static var welcome: URL {
return URL(string: "about:welcome")!
}

static var preferences: URL {
return URL(string: "about:preferences")!
}

// MARK: Pixel

Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ struct UserText {
static let downloads = NSLocalizedString("preferences.downloads", value: "Downloads", comment: "Show downloads browser preferences")
static let isDefaultBrowser = NSLocalizedString("preferences.default-browser.active", value: "DuckDuckGo is your default browser", comment: "Indicate that the browser is the default")
static let isNotDefaultBrowser = NSLocalizedString("preferences.default-browser.inactive", value: "DuckDuckGo is not your default browser.", comment: "Indicate that the browser is not the default")
static let loginsPlus = NSLocalizedString("preferences.logins-plus", value: "Logins+", comment: "Show Logins+ preferences")

static let feedbackBugDescription = NSLocalizedString("feedback.bug.description", value: "Please describe the problem in as much detail as possible:", comment: "Label in the feedback form")
static let feedbackFeatureRequestDescription = NSLocalizedString("feedback.feature.request.description", value: "What feature would you like to see?", comment: "Label in the feedback form")
Expand Down
7 changes: 7 additions & 0 deletions DuckDuckGo/Common/Utilities/Logging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ extension OSLog {
static var favicons: OSLog {
Logging.faviconLoggingEnabled ? Logging.faviconLog : .disabled
}

static var autoLock: OSLog {
Logging.autoLockLoggingEnabled ? Logging.autoLockLog : .disabled
}

}

Expand Down Expand Up @@ -83,6 +87,9 @@ struct Logging {

fileprivate static let faviconLoggingEnabled = false
fileprivate static let faviconLog: OSLog = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "DuckDuckGo", category: "Favicons")

fileprivate static let autoLockLoggingEnabled = true
fileprivate static let autoLockLog: OSLog = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "DuckDuckGo", category: "Auto-Lock")

fileprivate static let autoconsentLoggingEnabled = false
fileprivate static let autoconsentLog: OSLog = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "DuckDuckGo", category: "Autoconsent")
Expand Down
22 changes: 22 additions & 0 deletions DuckDuckGo/Common/View/AppKit/ColorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ final class ColorView: NSView {
layer?.borderWidth = borderWidth
}
}

@IBInspectable var interceptClickEvents: Bool = false

func setupView() {
self.wantsLayer = true
Expand All @@ -66,5 +68,25 @@ final class ColorView: NSView {
layer?.backgroundColor = backgroundColor?.cgColor
layer?.borderColor = borderColor?.cgColor
}

// MARK: - Click Event Interception

override func mouseDown(with event: NSEvent) {
if !interceptClickEvents {
super.mouseDown(with: event)
}
}

override func mouseUp(with event: NSEvent) {
if !interceptClickEvents {
super.mouseUp(with: event)
}
}

override func mouseDragged(with event: NSEvent) {
if !interceptClickEvents {
super.mouseDragged(with: event)
}
}

}
46 changes: 46 additions & 0 deletions DuckDuckGo/Common/View/AppKit/FlatButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// FlatButton.swift
//
// Copyright © 2022 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

@IBDesignable class FlatButton: NSButton {

@IBInspectable var cornerRadius: CGFloat = 5
@IBInspectable var horizontalPadding: CGFloat = 10
@IBInspectable var verticalPadding: CGFloat = 10
@IBInspectable var backgroundColor: NSColor = .blue

override func draw(_ dirtyRect: NSRect) {

self.wantsLayer = true
self.layer?.cornerRadius = cornerRadius

if isHighlighted {
layer?.backgroundColor = backgroundColor.blended(withFraction: 0.2, of: .black)?.cgColor
} else {
layer?.backgroundColor = backgroundColor.cgColor
}

let originalBounds = self.bounds
defer { self.bounds = originalBounds }

self.bounds = originalBounds.insetBy(dx: horizontalPadding, dy: verticalPadding)

super.draw(dirtyRect)
}
}
Loading

0 comments on commit 5b5986a

Please sign in to comment.