Skip to content

Commit

Permalink
Address autofill security concerns with copy changes (#3211)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1199230911884351/1207411921782782/f

**Description**:
[✓ Implement Survey for Password Manager
Users](https://app.asana.com/0/72649045549333/1206568003117818) showed
that a proportion of users are hesitant to use our Password Manager
because they don't know how secure it is. Easing these concerns should
increase the adoption of DuckDuckGo's Password Manager.
These changes update and add copy to more clearly explain the security
safe-guards of using the Password Manager.

**Steps to test this PR**:
- Go to the screens from the designs in
[Figma](https://www.figma.com/design/wAWx1a0mAooj6sDCmoTFbS/Password-Manager-security?node-id=192-10952&node-type=FRAME&t=0sLE1hdNaQCkC7A8-0)
and check they match. Double check Ship Review for any copy divergences.

**Definition of Done**:

* [ ] Does this PR satisfy our [Definition of
Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)?

---
###### Internal references:
[Pull Request Review
Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f)
[Software Engineering
Expectations](https://app.asana.com/0/59792373528535/199064865822552)
[Technical Design
Template](https://app.asana.com/0/59792373528535/184709971311943)
[Pull Request
Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f)
  • Loading branch information
graeme committed Sep 19, 2024
1 parent 85175a9 commit 8c31e5d
Show file tree
Hide file tree
Showing 20 changed files with 620 additions and 37 deletions.
14 changes: 14 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2882,6 +2882,8 @@
EEC8EB402982CD550065AA39 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; };
EECE10E529DD77E60044D027 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECE10E429DD77E60044D027 /* FeatureFlag.swift */; };
EECE10E629DD77E60044D027 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECE10E429DD77E60044D027 /* FeatureFlag.swift */; };
EED4D3D82C874AE200C79EEA /* PopoverInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED4D3D72C874AE200C79EEA /* PopoverInfoViewController.swift */; };
EED4D3D92C874AE200C79EEA /* PopoverInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED4D3D72C874AE200C79EEA /* PopoverInfoViewController.swift */; };
EED4D3DF2C8A298D00C79EEA /* AutofillPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED4D3DE2C8A298D00C79EEA /* AutofillPixelEvent.swift */; };
EED4D3E02C8A298D00C79EEA /* AutofillPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED4D3DE2C8A298D00C79EEA /* AutofillPixelEvent.swift */; };
EED735362BB46B6000F173D6 /* AutocompleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EED735352BB46B6000F173D6 /* AutocompleteTests.swift */; };
Expand Down Expand Up @@ -4616,6 +4618,7 @@
EEC4A6702B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationPreferenceItem.swift; sourceTree = "<group>"; };
EEC7BE2D2BC6C09400F86835 /* AddressBarKeyboardShortcutsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressBarKeyboardShortcutsTests.swift; sourceTree = "<group>"; };
EECE10E429DD77E60044D027 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = "<group>"; };
EED4D3D72C874AE200C79EEA /* PopoverInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopoverInfoViewController.swift; sourceTree = "<group>"; };
EED4D3DE2C8A298D00C79EEA /* AutofillPixelEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillPixelEvent.swift; sourceTree = "<group>"; };
EED735352BB46B6000F173D6 /* AutocompleteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutocompleteTests.swift; sourceTree = "<group>"; };
EED9A6732C37FE6800E0FAB9 /* login_deduplication_test_data.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = login_deduplication_test_data.csv; sourceTree = "<group>"; };
Expand Down Expand Up @@ -7415,6 +7418,7 @@
B65536902684409300085A79 /* Geolocation */,
AAE75275263B036300B973F8 /* History */,
AAE71DB225F66A0900D74437 /* HomePage */,
EED4D3D62C87480B00C79EEA /* InfoViews */,
56CEE9092B7A66C500CF10AA /* Info.plist */,
56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */,
EEAEA3F4294D05CF00D04DF3 /* JSAlert */,
Expand Down Expand Up @@ -9168,6 +9172,14 @@
path = AppAndExtensionAndAgentTargets;
sourceTree = "<group>";
};
EED4D3D62C87480B00C79EEA /* InfoViews */ = {
isa = PBXGroup;
children = (
EED4D3D72C874AE200C79EEA /* PopoverInfoViewController.swift */,
);
path = InfoViews;
sourceTree = "<group>";
};
EEE0E1CB2C32F53C0058E148 /* DataImport */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -10656,6 +10668,7 @@
FD22255E2C64B68500199373 /* AutoconsentExperiment.swift in Sources */,
3706FAD7293F65D500E42796 /* Feedback.swift in Sources */,
1D0DE9422C3BB9CC0037ABC2 /* ReleaseNotesParser.swift in Sources */,
EED4D3D92C874AE200C79EEA /* PopoverInfoViewController.swift in Sources */,
3707C722294B5D2900682A9F /* WKWebViewExtension.swift in Sources */,
3706FAD9293F65D500E42796 /* FirefoxFaviconsReader.swift in Sources */,
3706FADB293F65D500E42796 /* ContentBlockingRulesUpdateObserver.swift in Sources */,
Expand Down Expand Up @@ -12564,6 +12577,7 @@
856CADF0271710F400E79BB0 /* HoverUserScript.swift in Sources */,
B6DE57F62B05EA9000CD54B9 /* SheetHostingWindow.swift in Sources */,
AA6EF9B525081B4C004754E6 /* MainMenuActions.swift in Sources */,
EED4D3D82C874AE200C79EEA /* PopoverInfoViewController.swift in Sources */,
56A0541F2C1CA1F5007D8FAB /* OnboardingTabExtension.swift in Sources */,
B63D466925BEB6C200874977 /* WKWebView+SessionState.swift in Sources */,
B6F1B0222BCE5658005E863C /* BrokenSiteInfoTabExtension.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.090",
"blue" : "0x00",
"green" : "0x00",
"red" : "0x00"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.090",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"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.180",
"blue" : "0x00",
"green" : "0x00",
"red" : "0x00"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.180",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Lock-Color-16.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,15 @@
{
"images" : [
{
"filename" : "Lock-Solid-16.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Binary file not shown.
4 changes: 4 additions & 0 deletions DuckDuckGo/Common/Extensions/URLExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,10 @@ extension URL {
return URL(string: "https://duckduckgo.com/duckduckgo-help-pages/search-privacy/")!
}

static var passwordManagerLearnMore: URL {
return URL(string: "https://duckduckgo.com/duckduckgo-help-pages/sync-and-backup/password-manager-security/")!
}

static var searchSettings: URL {
return URL(string: "https://duckduckgo.com/settings/")!
}
Expand Down
2 changes: 2 additions & 0 deletions DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@ struct UserText {
}

static let importLoginsPasswords = NSLocalizedString("import.logins.passwords", value: "Passwords", comment: "Title text for the Passwords import option")
static let importLoginsPasswordsExplainer = NSLocalizedString("import.logins.passwords.explainer", value: "Passwords are encrypted. Viewing them or filling out forms requires Touch ID or a password. Nobody but you can see your passwords, not even us. Find Passwords in DuckDuckGo Settings > Passwords & Autofill.", comment: "Explanatory text for the Passwords import option to alleviate security concerns and explain usage.")
static let importLoginsPasswordsExplainerAutolockOff = NSLocalizedString("import.logins.passwords.explainer.autolock.off", value: "Passwords are encrypted. We recommend setting up Auto-lock to keep your passwords even more secure. Set it up in DuckDuckGo Settings > Passwords & Autofill.", comment: "Explanatory text for the Passwords import option to alleviate security concerns and explain usage when autolock is disabled")

static let importBookmarksButtonTitle = NSLocalizedString("bookmarks.import.button.title", value: "Import", comment: "Button text to open bookmark import dialog")
static let initiateImport = NSLocalizedString("import.data.initiate", value: "Import", comment: "Button text for importing data")
Expand Down
6 changes: 5 additions & 1 deletion DuckDuckGo/DataImport/Model/DataImportViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,14 @@ struct DataImportViewModel {

#endif

let isPasswordManagerAutolockEnabled: Bool

init(importSource: Source? = nil,
screen: Screen? = nil,
availableImportSources: [DataImport.Source] = Source.allCases.filter { $0.canImportData },
preferredImportSources: [Source] = [.chrome, .firefox, .safari],
summary: [DataTypeImportResult] = [],
isPasswordManagerAutolockEnabled: Bool = AutofillPreferences().isAutoLockEnabled,
loadProfiles: @escaping (ThirdPartyBrowser) -> BrowserProfileList = { $0.browserProfiles() },
dataImporterFactory: @escaping DataImporterFactory = dataImporter,
requestPrimaryPasswordCallback: @escaping @MainActor (Source) -> String? = Self.requestPrimaryPasswordCallback,
Expand All @@ -161,6 +164,7 @@ struct DataImportViewModel {
self.selectedDataTypes = importSource.supportedDataTypes

self.summary = summary
self.isPasswordManagerAutolockEnabled = isPasswordManagerAutolockEnabled

self.requestPrimaryPasswordCallback = requestPrimaryPasswordCallback
self.openPanelCallback = openPanelCallback
Expand Down Expand Up @@ -683,7 +687,7 @@ extension DataImportViewModel {
}

mutating func update(with importSource: Source) {
self = .init(importSource: importSource, loadProfiles: loadProfiles, dataImporterFactory: dataImporterFactory, requestPrimaryPasswordCallback: requestPrimaryPasswordCallback, reportSenderFactory: reportSenderFactory, onFinished: onFinished, onCancelled: onCancelled)
self = .init(importSource: importSource, isPasswordManagerAutolockEnabled: isPasswordManagerAutolockEnabled, loadProfiles: loadProfiles, dataImporterFactory: dataImporterFactory, requestPrimaryPasswordCallback: requestPrimaryPasswordCallback, reportSenderFactory: reportSenderFactory, onFinished: onFinished, onCancelled: onCancelled)
}

@MainActor
Expand Down
21 changes: 14 additions & 7 deletions DuckDuckGo/DataImport/View/DataImportView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ struct DataImportView: ModalView {
DataImportTypePicker(viewModel: $model)
.disabled(model.isImportSourcePickerDisabled)

importPasswordSubtitle()
passwordsExplainerView().padding(.top, 20)

case .moreInfo:
// you will be asked for your keychain password blah blah...
Expand Down Expand Up @@ -159,7 +159,7 @@ struct DataImportView: ModalView {
}

if dataType == .passwords {
importPasswordSubtitle()
passwordsExplainerView().padding(.top, 20)
}

case .summary(let dataTypes, let isFileImport):
Expand Down Expand Up @@ -208,11 +208,18 @@ struct DataImportView: ModalView {
}
}

private func importPasswordSubtitle() -> some View {
Text(UserText.importDataSubtitle)
.font(.subheadline)
.foregroundColor(Color(.greyText))
.padding(.top, 16)
private func passwordsExplainerView() -> some View {
HStack(alignment: .top, spacing: 8) {
Image(.lockColor16)
Text(model.isPasswordManagerAutolockEnabled ? UserText.importLoginsPasswordsExplainer : UserText.importLoginsPasswordsExplainerAutolockOff)
.font(.system(size: 12))
.foregroundColor(.secondary)
.frame(maxWidth: .infinity, alignment: .topLeading)
}
.frame(idealWidth: .infinity, maxWidth: .infinity, alignment: .topLeading)
.padding(14)
.background(Color.blackWhite1)
.roundedBorder()
}

private func handleImportProgress(_ progress: TaskProgress<DataImportViewModel, Never, DataImportProgressEvent>) async {
Expand Down
Loading

0 comments on commit 8c31e5d

Please sign in to comment.