Skip to content

Commit

Permalink
Fix of the Bitwarden issue (#2646)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1177771139624306/1207063591659803/f

**Description**:
Fix of the detection that DuckDuckGo integration is enabled in Bitwarden
app.
  • Loading branch information
tomasstrba authored Apr 19, 2024
1 parent 481f195 commit ea1dbb9
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 37 deletions.
3 changes: 3 additions & 0 deletions DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,9 @@ struct UserText {
static let bitwardenError = NSLocalizedString("bitwarden.error", value: "Unable to find or connect to Bitwarden", comment: "This message appears when the application is unable to find or connect to Bitwarden, indicating a connection issue.")
static let bitwardenNotInstalled = NSLocalizedString("bitwarden.not.installed", value: "Bitwarden app is not installed", comment: "")
static let bitwardenOldVersion = NSLocalizedString("bitwarden.old.version", value: "Please update Bitwarden to the latest version", comment: "Message that warns user they need to update their password manager Bitwarden app vesion")
static let bitwardenIncompatible = NSLocalizedString("bitwarden.incompatible", value: "The following Bitwarden versions are incompatible with DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Please revert to an older version by following these steps:", comment: "Message that warns user that specific Bitwarden app vesions are not compatible with this app")
static let bitwardenIncompatibleStep1 = NSLocalizedString("bitwarden.incompatible.step.1", value: "Download v2014.2.1", comment: "First step to downgrade Bitwarden")
static let bitwardenIncompatibleStep2 = NSLocalizedString("bitwarden.incompatible.step.2", value: "2. Open the downloaded DMG file and drag the Bitwarden application to\nthe /Applications folder.", comment: "Second step to downgrade Bitwarden")
static let bitwardenIntegrationNotApproved = NSLocalizedString("bitwarden.integration.not.approved", value: "Integration with DuckDuckGo is not approved in Bitwarden app", comment: "While the user tries to connect the DuckDuckGo Browser to password manager Bitwarden This message indicates that the integration with DuckDuckGo has not been approved in the Bitwarden app.")
static let bitwardenMissingHandshake = NSLocalizedString("bitwarden.missing.handshake", value: "Missing handshake", comment: "While the user tries to connect the DuckDuckGo Browser to password manager Bitwarden This message indicates a missing handshake (a way for two devices or systems to say hello to each other and agree to communicate or exchange information).")
static let bitwardenWaitingForHandshake = NSLocalizedString("bitwarden.waiting.for.handshake", value: "Waiting for the handshake approval in Bitwarden app", comment: "While the user tries to connect the DuckDuckGo Browser to password manager Bitwarden This message indicates the system is waiting for the handshake (a way for two devices or systems to say hello to each other and agree to communicate or exchange information).")
Expand Down
45 changes: 45 additions & 0 deletions DuckDuckGo/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,12 @@
}
}
}
},
"1." : {

},
"2. Open the downloaded DMG file and drag the Bitwarden application to\nthe /Applications folder." : {

},
"about.app_name" : {
"comment" : "Application name to be displayed in the About dialog",
Expand Down Expand Up @@ -6253,6 +6259,42 @@
}
}
},
"bitwarden.incompatible" : {
"comment" : "Message that warns user that specific Bitwarden app vesions are not compatible with this app",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "The following Bitwarden versions are incompatible with DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Please revert to an older version by following these steps:"
}
}
}
},
"bitwarden.incompatible.step.1" : {
"comment" : "First step to downgrade Bitwarden",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Download v2014.2.1"
}
}
}
},
"bitwarden.incompatible.step.2" : {
"comment" : "Second step to downgrade Bitwarden",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "2. Open the downloaded DMG file and drag the Bitwarden application to\nthe /Applications folder."
}
}
}
},
"bitwarden.install" : {
"comment" : "Button to install Bitwarden app",
"extractionState" : "extracted_with_value",
Expand Down Expand Up @@ -13288,6 +13330,9 @@
}
}
}
},
"Download v2014.2.1" : {

},
"download.finishing" : {
"comment" : "Download being finished information text",
Expand Down
4 changes: 4 additions & 0 deletions DuckDuckGo/PasswordManager/Bitwarden/Model/BWManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ final class BWManager: BWManagement, ObservableObject {
status = .oldVersion
scheduleConnectionAttempt()
return
case .incompatible:
status = .incompatible
scheduleConnectionAttempt()
return
case .installed:
break
}
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/PasswordManager/Bitwarden/Model/BWStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum BWStatus: Equatable {

// Installed Bitwarden doesn't support the integration
case oldVersion
case incompatible

// Bitwarden application isn't running
case notRunning
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum BWInstallationState {

case notInstalled
case oldVersion
case incompatible
case installed

}
Expand All @@ -41,6 +42,7 @@ final class LocalBitwardenInstallationService: BWInstallationService {
static var bundlePath = "/Applications/Bitwarden.app"
private lazy var bundleUrl = URL(fileURLWithPath: Self.bundlePath)
static var minimumVersion = "2022.10.1"
static var incompatibleVersions = ["2024.3.0", "2024.3.2", "2024.4.0", "2024.4.1"]

private lazy var manifestPath: String = {
#if DEBUG
Expand Down Expand Up @@ -75,6 +77,10 @@ final class LocalBitwardenInstallationService: BWInstallationService {
return .oldVersion
}

guard !Self.incompatibleVersions.contains(version) else {
return .incompatible
}

return .installed
}

Expand Down Expand Up @@ -124,7 +130,7 @@ final class LocalBitwardenInstallationService: BWInstallationService {
private func isIntegrationEnabled(in dataFileURL: URL) -> Bool {
do {
let dataFile = try String(contentsOf: dataFileURL)
return dataFile.range(of: "\"enableDuckDuckGoBrowserIntegration\": true") != nil
return dataFile.range(of: "enableDuckDuckGoBrowserIntegration\": true") != nil
} catch {
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ struct ConnectBitwardenView: View {
@ViewBuilder private func bodyView(for state: ConnectBitwardenViewModel.ViewState) -> some View {
switch viewModel.viewState {
case .disclaimer: ConnectToBitwardenDisclaimerView()
case .lookingForBitwarden: BitwardenInstallationDetectionView(bitwardenDetected: false, bitwardenNeedsUpdate: false)
case .oldVersion: BitwardenInstallationDetectionView(bitwardenDetected: true, bitwardenNeedsUpdate: true)
case .bitwardenFound: BitwardenInstallationDetectionView(bitwardenDetected: true, bitwardenNeedsUpdate: false)
case .lookingForBitwarden: BitwardenInstallationDetectionView(bitwardenDetected: false, bitwardenNeedsUpdate: false, bitwardenIsIncompatible: false)
case .incompatible: BitwardenInstallationDetectionView(bitwardenDetected: true, bitwardenNeedsUpdate: false, bitwardenIsIncompatible: true)
case .oldVersion: BitwardenInstallationDetectionView(bitwardenDetected: true, bitwardenNeedsUpdate: true, bitwardenIsIncompatible: false)
case .bitwardenFound: BitwardenInstallationDetectionView(bitwardenDetected: true, bitwardenNeedsUpdate: false, bitwardenIsIncompatible: false)
case .accessToContainersNotApproved: ConnectToBitwardenView(canConnect: false, canNotAccessSandboxContainers: true)
case .waitingForConnectionPermission: ConnectToBitwardenView(canConnect: false, canNotAccessSandboxContainers: false)
case .connectToBitwarden: ConnectToBitwardenView(canConnect: true, canNotAccessSandboxContainers: false)
Expand Down Expand Up @@ -155,44 +156,55 @@ private struct BitwardenInstallationDetectionView: View {

let bitwardenDetected: Bool
let bitwardenNeedsUpdate: Bool
let bitwardenIsIncompatible: Bool

var body: some View {

VStack(alignment: .leading, spacing: 10) {
Text(UserText.installBitwarden)
.font(.system(size: 13, weight: .bold))

HStack {
NumberedBadge(value: 1)

Text(UserText.installBitwardenInfo)
if !bitwardenIsIncompatible {
Text(UserText.installBitwarden)
.font(.system(size: 13, weight: .bold))

Spacer()
}

HStack {
NumberedBadge(value: 2)
HStack {
NumberedBadge(value: 1)
Text(UserText.installBitwardenInfo)
Spacer()
}

Text(UserText.afterBitwardenInstallationInfo)
HStack {
NumberedBadge(value: 2)
Text(UserText.afterBitwardenInstallationInfo)
Spacer()
}

Spacer()
Button(action: {
viewModel.process(action: .openBitwardenProductPage)
}, label: {
Image(.macAppStoreButton)
})
.buttonStyle(PlainButtonStyle())
.frame(width: 156, height: 40)
}

Button(action: {
viewModel.process(action: .openBitwardenProductPage)
}, label: {
Image(.macAppStoreButton)
})
.buttonStyle(PlainButtonStyle())
.frame(width: 156, height: 40)

if bitwardenDetected {
if bitwardenNeedsUpdate {
HStack {
ActivityIndicator(isAnimating: .constant(true), style: .spinning)

Text(UserText.bitwardenOldVersion)
}
} else if bitwardenIsIncompatible {
HStack {
ActivityIndicator(isAnimating: .constant(true), style: .spinning)

VStack(alignment: .leading) {
Text(UserText.bitwardenIncompatible)
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
BitwardenDowngradeInfoView()
}
}
} else {
HStack {
Image(.successCheckmark)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ final class ConnectBitwardenViewModel: ObservableObject {
// Bitwarden installation:
case lookingForBitwarden
case oldVersion
case incompatible
case bitwardenFound

// Bitwarden connection:
Expand All @@ -48,14 +49,14 @@ final class ConnectBitwardenViewModel: ObservableObject {

var canContinue: Bool {
switch self {
case .lookingForBitwarden, .oldVersion, .waitingForConnectionPermission: return false
case .lookingForBitwarden, .oldVersion, .incompatible, .waitingForConnectionPermission: return false
default: return true
}
}

var confirmButtonTitle: String {
switch self {
case .disclaimer, .lookingForBitwarden, .oldVersion, .bitwardenFound: return "Next"
case .disclaimer, .lookingForBitwarden, .oldVersion, .incompatible, .bitwardenFound: return "Next"
case .waitingForConnectionPermission, .connectToBitwarden: return "Connect"
case .accessToContainersNotApproved: return "Open System Settings"
case .connectedToBitwarden: return "OK"
Expand Down Expand Up @@ -106,6 +107,8 @@ final class ConnectBitwardenViewModel: ObservableObject {
}
case .oldVersion:
self.viewState = .oldVersion
case .incompatible:
self.viewState = .incompatible
case .notRunning:
self.viewState = .waitingForConnectionPermission
case .integrationNotApproved:
Expand All @@ -126,7 +129,6 @@ final class ConnectBitwardenViewModel: ObservableObject {
self.viewState = .connectedToBitwarden
case .error(error: let error):
self.error = error

}
}
// swiftlint:enable cyclomatic_complexity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ final class PasswordManagerCoordinator: PasswordManagerCoordinating {

func askToUnlock(completionHandler: @escaping () -> Void) {
switch bitwardenManagement.status {
case .disabled, .notInstalled, .oldVersion, .missingHandshake, .handshakeNotApproved, .error, .accessToContainersNotApproved:
case .disabled, .notInstalled, .oldVersion, .incompatible, .missingHandshake, .handshakeNotApproved, .error, .accessToContainersNotApproved:
Task {
await WindowControllersManager.shared.showPreferencesTab(withSelectedPane: .autofill)
}
Expand Down
52 changes: 44 additions & 8 deletions DuckDuckGo/Preferences/View/PreferencesAutofillView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,18 @@ extension Preferences {
.offset(x: Preferences.Const.autoLockWarningOffset)
case .notInstalled:
BitwardenStatusView(iconType: .warning,
title: UserText.bitwardenNotInstalled,
buttonValue: nil)
title: UserText.bitwardenNotInstalled)
.offset(x: Preferences.Const.autoLockWarningOffset)
case .oldVersion:
BitwardenStatusView(iconType: .warning,
title: UserText.bitwardenOldVersion,
buttonValue: nil)
title: UserText.bitwardenOldVersion)
.offset(x: Preferences.Const.autoLockWarningOffset)
case .incompatible:
BitwardenStatusView(iconType: .warning,
title: UserText.bitwardenIncompatible,
content: AnyView(BitwardenDowngradeInfoView()))
.offset(x: Preferences.Const.autoLockWarningOffset)
.offset(x: Preferences.Const.autoLockWarningOffset)
case .notRunning:
BitwardenStatusView(iconType: .warning,
title: UserText.bitwardenPreferencesRun,
Expand Down Expand Up @@ -273,6 +277,13 @@ extension Preferences {

private struct BitwardenStatusView: View {

internal init(iconType: BitwardenStatusView.IconType, title: String, buttonValue: BitwardenStatusView.ButtonValue? = nil, content: AnyView? = nil) {
self.iconType = iconType
self.title = title
self.buttonValue = buttonValue
self.content = content
}

struct ButtonValue {
let title: String
let action: () -> Void
Expand All @@ -295,17 +306,23 @@ private struct BitwardenStatusView: View {
let iconType: IconType
let title: String
let buttonValue: ButtonValue?
let content: AnyView?

var body: some View {

VStack(alignment: .leading) {
HStack(alignment: .top) {
Image(iconType.imageName)
.padding(.top, 2)
Text(title)
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
.padding([.top, .bottom], 2)
VStack(alignment: .leading) {
Text(title)
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
.padding([.top, .bottom], 2)
if let content {
content.padding([.top, .bottom], 2)
}
}
}
.padding([.leading, .trailing], 6)
.padding([.top, .bottom], 2)
Expand All @@ -325,6 +342,25 @@ private struct BitwardenStatusView: View {

}

struct BitwardenDowngradeInfoView: View, PreferencesTabOpening {

var body: some View {
VStack(alignment: .leading) {
VStack(alignment: .leading) {
HStack {
Text("1.")
Button(UserText.bitwardenIncompatibleStep1, action: {
openNewTab(with: URL(string: "https://github.com/bitwarden/clients/releases/download/desktop-v2024.2.1/Bitwarden-2024.2.1-universal.dmg")!)
}).foregroundColor(.accentColor)
}
Text(UserText.bitwardenIncompatibleStep2)
.lineLimit(nil)
.fixedSize(horizontal: false, vertical: true)
}
}
}
}

struct ResetNeverPromptSitesSheet: View {

@ObservedObject var autofillPreferencesModel: AutofillPreferencesModel
Expand Down

0 comments on commit ea1dbb9

Please sign in to comment.