diff --git a/AutofillCredentialProvider/AutofillCredentialProvider.entitlements b/AutofillCredentialProvider/AutofillCredentialProvider.entitlements
index b50ab55a01..f7959669d1 100644
--- a/AutofillCredentialProvider/AutofillCredentialProvider.entitlements
+++ b/AutofillCredentialProvider/AutofillCredentialProvider.entitlements
@@ -3,6 +3,16 @@
com.apple.developer.authentication-services.autofill-credential-provider
-
+
+ com.apple.security.application-groups
+
+ $(GROUP_ID_PREFIX).vault
+ $(GROUP_ID_PREFIX).bookmarks
+
+ keychain-access-groups
+
+ $(AppIdentifierPrefix)$(APP_ID)
+ $(AppIdentifierPrefix)$(VAULT_APP_GROUP)
+
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedView.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedView.swift
index 1f6a32564b..fe36f9e3b2 100644
--- a/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedView.swift
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedView.swift
@@ -49,12 +49,6 @@ struct CredentialProviderActivatedView: View {
.padding(.top, 16)
.multilineTextAlignment(.center)
- Text(UserText.credentialProviderActivatedSubtitle)
- .daxBodyRegular()
- .foregroundColor(Color(designSystemColor: .textSecondary))
- .padding(.top, 8)
- .multilineTextAlignment(.center)
-
Spacer()
Button {
@@ -67,7 +61,7 @@ struct CredentialProviderActivatedView: View {
}
.padding(.horizontal, 24)
- .navigationBarItems(trailing: Button(UserText.actionCancel) {
+ .navigationBarItems(trailing: Button(UserText.actionDone) {
viewModel.dismiss()
})
}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedViewModel.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedViewModel.swift
index 759683d555..bdf4eba455 100644
--- a/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedViewModel.swift
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderActivation/CredentialProviderActivatedViewModel.swift
@@ -18,6 +18,7 @@
//
import Foundation
+import Core
struct CredentialProviderActivatedViewModel {
@@ -30,10 +31,12 @@ struct CredentialProviderActivatedViewModel {
}
func dismiss() {
+ Pixel.fire(pixel: .autofillExtensionWelcomeDismiss)
completion?(false)
}
func launchDDGApp() {
+ Pixel.fire(pixel: .autofillExtensionWelcomeLaunchApp)
completion?(true)
}
}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListItemTableViewCell.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListItemTableViewCell.swift
index 2e659cc21e..a0701ec178 100644
--- a/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListItemTableViewCell.swift
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListItemTableViewCell.swift
@@ -24,7 +24,9 @@ import DesignResourcesKit
class CredentialProviderListItemTableViewCell: UITableViewCell {
static var reuseIdentifier = "CredentialProviderListItemTableViewCell"
-
+
+ var disclosureButtonTapped: (() -> Void)?
+
private lazy var titleLabel: UILabel = {
let label = UILabel(frame: CGRect.zero)
label.font = .preferredFont(forTextStyle: .callout)
@@ -64,7 +66,23 @@ class CredentialProviderListItemTableViewCell: UITableViewCell {
stackView.alignment = .center
return stackView
}()
-
+
+ private lazy var disclosureButton: UIButton = {
+ let button = UIButton(type: .system)
+ let image = UIImage(systemName: "chevron.forward")
+ let boldImage = image?.withConfiguration(UIImage.SymbolConfiguration(pointSize: 11, weight: .bold))
+ button.setImage(boldImage, for: .normal)
+ button.tintColor = UIColor.tertiaryLabel
+ button.addTarget(self, action: #selector(handleDisclosureButtonTap), for: .touchUpInside)
+
+ let buttonSize: CGFloat = 44
+ button.frame = CGRect(x: 0, y: 0, width: buttonSize, height: buttonSize)
+ button.contentHorizontalAlignment = .center
+ button.contentVerticalAlignment = .center
+
+ return button
+ }()
+
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
installSubviews()
@@ -85,22 +103,29 @@ class CredentialProviderListItemTableViewCell: UITableViewCell {
private func installSubviews() {
contentView.addSubview(contentStackView)
+ contentView.addSubview(disclosureButton)
installConstraints()
}
private func installConstraints() {
contentStackView.translatesAutoresizingMaskIntoConstraints = false
iconImageView.translatesAutoresizingMaskIntoConstraints = false
-
+ disclosureButton.translatesAutoresizingMaskIntoConstraints = false
+
let imageSize: CGFloat = 32
let margins = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
iconImageView.widthAnchor.constraint(equalToConstant: imageSize),
iconImageView.heightAnchor.constraint(equalToConstant: imageSize),
-
+
+ disclosureButton.widthAnchor.constraint(equalToConstant: 44),
+ disclosureButton.heightAnchor.constraint(equalToConstant: 44),
+ disclosureButton.centerYAnchor.constraint(equalTo: margins.centerYAnchor),
+ disclosureButton.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 16),
+
contentStackView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
- contentStackView.trailingAnchor.constraint(equalTo: margins.trailingAnchor),
+ contentStackView.trailingAnchor.constraint(equalTo: disclosureButton.leadingAnchor, constant: -12),
contentStackView.topAnchor.constraint(equalTo: margins.topAnchor),
contentStackView.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
])
@@ -109,7 +134,7 @@ class CredentialProviderListItemTableViewCell: UITableViewCell {
private func setupContentView(with item: AutofillLoginItem) {
titleLabel.text = item.title
subtitleLabel.text = item.subtitle
- iconImageView.image = loadImageFromCache(forDomain: item.account.domain)
+ iconImageView.image = FaviconHelper.loadImageFromCache(forDomain: item.account.domain, preferredFakeFaviconLetters: item.preferredFaviconLetters)
}
override func layoutSubviews() {
@@ -118,67 +143,9 @@ class CredentialProviderListItemTableViewCell: UITableViewCell {
separatorInset = UIEdgeInsets(top: 0, left: contentView.layoutMargins.left + textStackView.frame.origin.x, bottom: 0, right: 0)
}
-
-
- private func loadImageFromCache(forDomain domain: String?) -> UIImage? {
- guard let domain = domain,
- let cacheUrl = FaviconsCacheType.fireproof.cacheLocation() else { return nil }
-
- let key = FaviconHasher.createHash(ofDomain: domain)
- // Slight leap here to avoid loading Kingisher as a library for the widgets.
- // Once dependency management is fixed, link it and use Favicons directly.
- let imageUrl = cacheUrl.appendingPathComponent("com.onevcat.Kingfisher.ImageCache.fireproof").appendingPathComponent(key)
-
- guard let data = (try? Data(contentsOf: imageUrl)) else {
- let image = createFakeFavicon(forDomain: domain, size: 32, backgroundColor: UIColor.forDomain(domain), preferredFakeFaviconLetters: item?.preferredFaviconLetters)
- return image
- }
-
- return UIImage(data: data)?.toSRGB()
- }
-
- private func createFakeFavicon(forDomain domain: String,
- size: CGFloat = 192,
- backgroundColor: UIColor = UIColor.red,
- bold: Bool = true,
- preferredFakeFaviconLetters: String? = nil,
- letterCount: Int = 2) -> UIImage? {
-
- let cornerRadius = size * 0.125
- let imageRect = CGRect(x: 0, y: 0, width: size, height: size)
- let padding = size * 0.16
- let labelFrame = CGRect(x: padding, y: padding, width: imageRect.width - (2 * padding), height: imageRect.height - (2 * padding))
-
- let renderer = UIGraphicsImageRenderer(size: imageRect.size)
- let icon = renderer.image { imageContext in
- let context = imageContext.cgContext
-
- context.setFillColor(backgroundColor.cgColor)
- context.addPath(CGPath(roundedRect: imageRect, cornerWidth: cornerRadius, cornerHeight: cornerRadius, transform: nil))
- context.fillPath()
-
- let label = UILabel(frame: labelFrame)
- label.numberOfLines = 1
- label.adjustsFontSizeToFitWidth = true
- label.minimumScaleFactor = 0.1
- label.baselineAdjustment = .alignCenters
- label.font = bold ? UIFont.boldSystemFont(ofSize: size) : UIFont.systemFont(ofSize: size)
- label.textColor = .white
- label.textAlignment = .center
-
- if let prefferedPrefix = preferredFakeFaviconLetters?.droppingWwwPrefix().prefix(letterCount).capitalized {
- label.text = prefferedPrefix
- } else {
- label.text = item?.preferredFaviconLetters.capitalized ?? "#"
- }
-
- context.translateBy(x: padding, y: padding)
-
- label.layer.draw(in: context)
- }
-
- return icon.withRenderingMode(.alwaysOriginal)
+ @objc private func handleDisclosureButtonTap() {
+ disclosureButtonTapped?()
}
-
+
}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewController.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewController.swift
index e0d0e8eaff..6094773e0c 100644
--- a/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewController.swift
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewController.swift
@@ -21,13 +21,17 @@ import UIKit
import AuthenticationServices
import BrowserServicesKit
import Combine
+import Common
import Core
import SwiftUI
final class CredentialProviderListViewController: UIViewController {
private let viewModel: CredentialProviderListViewModel
+ private let shouldProvideTextToInsert: Bool
+ private let tld: TLD
private let onRowSelected: (AutofillLoginItem) -> Void
+ private let onTextProvided: (String) -> Void
private let onDismiss: () -> Void
private var cancellables: Set = []
@@ -80,21 +84,35 @@ final class CredentialProviderListViewController: UIViewController {
constant: (tableView.frame.height / 2))
}()
-
init(serviceIdentifiers: [ASCredentialServiceIdentifier],
secureVault: (any AutofillSecureVault)?,
credentialIdentityStoreManager: AutofillCredentialIdentityStoreManaging,
+ shouldProvideTextToInsert: Bool,
+ tld: TLD,
onRowSelected: @escaping (AutofillLoginItem) -> Void,
+ onTextProvided: @escaping (String) -> Void,
onDismiss: @escaping () -> Void) {
self.viewModel = CredentialProviderListViewModel(serviceIdentifiers: serviceIdentifiers,
secureVault: secureVault,
- credentialIdentityStoreManager: credentialIdentityStoreManager)
+ credentialIdentityStoreManager: credentialIdentityStoreManager,
+ tld: tld)
+ self.shouldProvideTextToInsert = shouldProvideTextToInsert
+ self.tld = tld
self.onRowSelected = onRowSelected
+ self.onTextProvided = onTextProvided
self.onDismiss = onDismiss
super.init(nibName: nil, bundle: nil)
- authenticate()
+ if #available(iOS 18.0, *) {
+ authenticate()
+ } else {
+ // pre-iOS 18.0 authentication can fail silently if extension is loaded twice in quick succession
+ // if authenticate is called without a slight delay
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
+ self?.authenticate()
+ }
+ }
}
required init?(coder: NSCoder) {
@@ -106,6 +124,10 @@ final class CredentialProviderListViewController: UIViewController {
title = UserText.credentialProviderListTitle
+ if let itemPrompt = viewModel.serviceIdentifierPromptLabel {
+ navigationItem.prompt = itemPrompt
+ }
+
let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
navigationItem.rightBarButtonItem = doneItem
@@ -117,6 +139,8 @@ final class CredentialProviderListViewController: UIViewController {
registerForKeyboardNotifications()
navigationItem.searchController = searchController
+
+ Pixel.fire(pixel: .autofillExtensionPasswordsOpened)
}
override func viewWillDisappear(_ animated: Bool) {
@@ -156,19 +180,17 @@ final class CredentialProviderListViewController: UIViewController {
}
private func authenticate() {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
- self?.viewModel.authenticate {[weak self] error in
- guard let self = self else { return }
-
- if error != nil {
- if error != .noAuthAvailable {
- self.onDismiss()
- } else {
- let alert = UIAlertController.makeDeviceAuthenticationAlert { [weak self] in
- self?.onDismiss()
- }
- present(alert, animated: true)
+ viewModel.authenticate {[weak self] error in
+ guard let self = self else { return }
+
+ if error != nil {
+ if error != .noAuthAvailable {
+ self.onDismiss()
+ } else {
+ let alert = UIAlertController.makeDeviceAuthenticationAlert { [weak self] in
+ self?.onDismiss()
}
+ present(alert, animated: true)
}
}
}
@@ -270,6 +292,7 @@ final class CredentialProviderListViewController: UIViewController {
@objc private func doneTapped() {
onDismiss()
+ Pixel.fire(pixel: .autofillExtensionPasswordsDismissed)
}
}
@@ -293,6 +316,11 @@ extension CredentialProviderListViewController: UITableViewDataSource {
}
cell.item = items[indexPath.row]
cell.backgroundColor = UIColor(designSystemColor: .surface)
+
+ cell.disclosureButtonTapped = { [weak self] in
+ let item = items[indexPath.row]
+ self?.presentDetailsForCredentials(item: item)
+ }
return cell
default:
return UITableViewCell()
@@ -312,6 +340,14 @@ extension CredentialProviderListViewController: UITableViewDataSource {
viewModel.viewState == .showItems ? UILocalizedIndexedCollation.current().sectionIndexTitles : []
}
+ private func presentDetailsForCredentials(item: AutofillLoginItem) {
+ let detailViewController = CredentialProviderListDetailsViewController(account: item.account,
+ tld: tld,
+ shouldProvideTextToInsert: self.shouldProvideTextToInsert)
+ detailViewController.delegate = self
+
+ self.navigationController?.pushViewController(detailViewController, animated: true)
+ }
}
extension CredentialProviderListViewController: UITableViewDelegate {
@@ -321,9 +357,14 @@ extension CredentialProviderListViewController: UITableViewDelegate {
switch viewModel.sections[indexPath.section] {
case .suggestions(_, items: let items), .credentials(_, let items):
let item = items[indexPath.row]
- onRowSelected(item)
+ if shouldProvideTextToInsert {
+ presentDetailsForCredentials(item: item)
+ } else {
+ onRowSelected(item)
+ Pixel.fire(pixel: .autofillExtensionPasswordSelected)
+ }
default:
- break
+ return
}
}
@@ -378,5 +419,12 @@ extension CredentialProviderListViewController {
(tableView.frame.height / 2) - searchController.searchBar.frame.height
)
}
+}
+
+extension CredentialProviderListViewController: CredentialProviderListDetailsViewControllerDelegate {
+
+ func credentialProviderListDetailsViewControllerDidProvideText(_ controller: CredentialProviderListDetailsViewController, text: String) {
+ onTextProvided(text)
+ }
}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewModel.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewModel.swift
index 40664022a6..1b0ab0c601 100644
--- a/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewModel.swift
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderList/CredentialProviderListViewModel.swift
@@ -36,7 +36,13 @@ final class CredentialProviderListViewModel: ObservableObject {
case searchingNoResults
}
- var isSearching: Bool = false
+ var isSearching: Bool = false {
+ didSet {
+ if oldValue != isSearching, isSearching {
+ Pixel.fire(pixel: .autofillExtensionPasswordsSearch)
+ }
+ }
+ }
var authenticationNotRequired = false
private let serviceIdentifiers: [ASCredentialServiceIdentifier]
@@ -45,7 +51,7 @@ final class CredentialProviderListViewModel: ObservableObject {
private var accounts = [SecureVaultModels.WebsiteAccount]()
private var accountsToSuggest = [SecureVaultModels.WebsiteAccount]()
private var cancellables: Set = []
- private let tld: TLD = TLD()
+ private let tld: TLD
private let autofillDomainNameUrlMatcher = AutofillDomainNameUrlMatcher()
private let autofillDomainNameUrlSort = AutofillDomainNameUrlSort()
@@ -55,6 +61,13 @@ final class CredentialProviderListViewModel: ObservableObject {
return !accounts.isEmpty
}
+ var serviceIdentifierPromptLabel: String? {
+ guard let identifier = serviceIdentifiers.first?.identifier else {
+ return nil
+ }
+ return String(format: UserText.credentialProviderListPrompt, autofillDomainNameUrlMatcher.normalizeUrlForWeb(identifier))
+ }
+
@Published private(set) var viewState: CredentialProviderListViewModel.ViewState = .authLocked
@Published private(set) var sections = [AutofillLoginListSectionType]() {
didSet {
@@ -64,10 +77,12 @@ final class CredentialProviderListViewModel: ObservableObject {
init(serviceIdentifiers: [ASCredentialServiceIdentifier],
secureVault: (any AutofillSecureVault)?,
- credentialIdentityStoreManager: AutofillCredentialIdentityStoreManaging) {
+ credentialIdentityStoreManager: AutofillCredentialIdentityStoreManaging,
+ tld: TLD) {
self.serviceIdentifiers = serviceIdentifiers
self.secureVault = secureVault
self.credentialIdentityStoreManager = credentialIdentityStoreManager
+ self.tld = tld
if let count = getAccountsCount() {
authenticationNotRequired = count == 0
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsView.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsView.swift
new file mode 100644
index 0000000000..ae2a9113ce
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsView.swift
@@ -0,0 +1,359 @@
+//
+// CredentialProviderListDetailsView.swift
+// DuckDuckGo
+//
+// Copyright © 2024 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 SwiftUI
+import DuckUI
+import DesignResourcesKit
+
+struct CredentialProviderListDetailsView: View {
+
+ @ObservedObject var viewModel: CredentialProviderListDetailsViewModel
+
+ var body: some View {
+ listWithBackground
+ }
+
+ @ViewBuilder
+ private var listWithBackground: some View {
+ if #available(iOS 16.0, *) {
+ list
+ .scrollContentBackground(.hidden)
+ .background(Color(designSystemColor: .background))
+ } else {
+ list
+ .background(Color(designSystemColor: .background))
+ }
+ }
+
+ private var list: some View {
+ List {
+ viewingContentView
+ }
+ .simultaneousGesture(
+ DragGesture().onChanged({_ in
+ viewModel.selectedCell = nil
+ }))
+ .listStyle(.insetGrouped)
+ }
+
+ private var viewingContentView: some View {
+ Group {
+ Section {
+ Header(viewModel: viewModel.headerViewModel)
+ }
+
+ Section {
+ usernameCell()
+ .onTapGesture {
+ if viewModel.shouldProvideTextToInsert {
+ viewModel.textToReturn(.username)
+ }
+ }
+
+ passwordCell()
+ .onTapGesture {
+ if viewModel.shouldProvideTextToInsert {
+ viewModel.textToReturn(.password)
+ }
+ }
+ }
+
+ Section {
+ addressCell()
+ }
+
+ Section {
+ notesCell()
+ }
+ }
+ }
+
+ private func usernameCell() -> some View {
+ CopyableCell(title: UserText.credentialProviderDetailsUsername,
+ subtitle: viewModel.usernameDisplayString,
+ selectedCell: $viewModel.selectedCell,
+ buttonImageName: "Copy-24",
+ buttonAccessibilityLabel: UserText.credentialProviderDetailsCopyPrompt(for: UserText.credentialProviderDetailsUsername),
+ buttonAction: { viewModel.copyToPasteboard(.username) })
+ }
+
+ private func passwordCell() -> some View {
+ CopyableCell(title: UserText.credentialProviderDetailsPassword,
+ subtitle: viewModel.userVisiblePassword,
+ selectedCell: $viewModel.selectedCell,
+ isMonospaced: true,
+ buttonImageName: viewModel.isPasswordHidden ? "Eye-24" : "Eye-Closed-24",
+ buttonAccessibilityLabel: viewModel.isPasswordHidden ? UserText.credentialProviderDetailsShowPassword : UserText.credentialProviderDetailsHidePassword,
+ buttonAction: { viewModel.isPasswordHidden.toggle() },
+ secondaryButtonImageName: "Copy-24",
+ secondaryButtonAccessibilityLabel: UserText.credentialProviderDetailsCopyPrompt(for: UserText.credentialProviderDetailsPassword),
+ secondaryButtonAction: { viewModel.copyToPasteboard(.password) })
+ }
+
+ private func addressCell() -> some View {
+ CopyableCell(title: UserText.credentialProviderDetailsAddress,
+ subtitle: viewModel.address,
+ selectedCell: $viewModel.selectedCell,
+ truncationMode: .middle,
+ buttonImageName: "Copy-24",
+ buttonAccessibilityLabel: UserText.credentialProviderDetailsCopyPrompt(for: UserText.credentialProviderDetailsAddress),
+ buttonAction: { viewModel.copyToPasteboard(.address) })
+ }
+
+ private func notesCell() -> some View {
+ CopyableCell(title: UserText.credentialProviderDetailsNotes,
+ subtitle: viewModel.notes,
+ selectedCell: $viewModel.selectedCell,
+ truncationMode: .middle,
+ multiLine: true)
+ }
+
+}
+
+private struct Header: View {
+
+ @Environment(\.colorScheme) private var colorScheme
+
+ private struct Constants {
+ static let imageSize: CGFloat = 32
+ static let horizontalStackSpacing: CGFloat = 12
+ static let verticalStackSpacing: CGFloat = 1
+ static let viewHeight: CGFloat = 60
+ static let insets = EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)
+ }
+
+ var viewModel: CredentialProviderListDetailsHeaderViewModel
+
+ var body: some View {
+ HStack(spacing: Constants.horizontalStackSpacing) {
+ Image(uiImage: viewModel.favicon)
+ .resizable()
+ .cornerRadius(4)
+ .scaledToFit()
+ .frame(width: Constants.imageSize, height: Constants.imageSize)
+ .accessibilityHidden(true)
+
+ VStack(alignment: .leading, spacing: Constants.verticalStackSpacing) {
+ Text(viewModel.title)
+ .font(.callout)
+ .foregroundColor(colorScheme == .light ? .gray90 : .white)
+ .truncationMode(.middle)
+ .lineLimit(1)
+
+ Text(viewModel.subtitle)
+ .font(.footnote)
+ .foregroundColor(colorScheme == .light ? .gray50 : .gray20)
+ }
+
+ Spacer()
+ }
+ .frame(minHeight: Constants.viewHeight)
+ .frame(maxWidth: .infinity)
+ .contentShape(Rectangle())
+ .listRowBackground(Color(designSystemColor: .surface))
+ .listRowInsets(Constants.insets)
+ }
+}
+
+private struct CopyableCell: View {
+ @State private var id = UUID()
+ let title: String
+ let subtitle: String
+ @Binding var selectedCell: UUID?
+ var truncationMode: Text.TruncationMode = .tail
+ var multiLine: Bool = false
+ var isMonospaced: Bool = false
+
+ var buttonImageName: String?
+ var buttonAccessibilityLabel: String?
+ var buttonAction: (() -> Void)?
+
+ var secondaryButtonImageName: String?
+ var secondaryButtonAccessibilityLabel: String?
+ var secondaryButtonAction: (() -> Void)?
+
+ var shouldProvideTextToInsertAction: (() -> Void)?
+
+ var body: some View {
+ ZStack {
+ HStack {
+ VStack(alignment: .leading, spacing: Constants.verticalPadding) {
+ Text(title)
+ .label4Style()
+ HStack {
+ if multiLine {
+ Text(subtitle)
+ .label4Style(design: isMonospaced ? .monospaced : .default,
+ foregroundColorLight: ForegroundColor(isSelected: selectedCell == id).color,
+ foregroundColorDark: .gray30)
+ .truncationMode(truncationMode)
+ .frame(maxHeight: .greatestFiniteMagnitude)
+ .textSelection(.enabled)
+ } else {
+ Text(subtitle)
+ .label4Style(design: isMonospaced ? .monospaced : .default,
+ foregroundColorLight: ForegroundColor(isSelected: selectedCell == id).color,
+ foregroundColorDark: .gray30)
+ .truncationMode(truncationMode)
+ }
+ }
+ }
+ .padding(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 8))
+
+ if secondaryButtonImageName != nil {
+ Spacer(minLength: Constants.textFieldImageSize * 2 + 8)
+ } else {
+ Spacer(minLength: buttonImageName != nil ? Constants.textFieldImageSize : 8)
+ }
+ }
+
+ if let buttonImageName = buttonImageName, let buttonAccessibilityLabel = buttonAccessibilityLabel {
+ let differenceBetweenImageSizeAndTapAreaPerEdge = (Constants.textFieldTapSize - Constants.textFieldImageSize) / 2.0
+ HStack(alignment: .center, spacing: 0) {
+ Spacer()
+
+ Button {
+ buttonAction?()
+ self.selectedCell = nil
+ } label: {
+ VStack(alignment: .trailing) {
+ Spacer()
+ HStack {
+ Spacer()
+ Image(buttonImageName)
+ .resizable()
+ .frame(width: Constants.textFieldImageSize, height: Constants.textFieldImageSize)
+ .foregroundColor(Color(UIColor.label).opacity(Constants.textFieldImageOpacity))
+ .opacity(subtitle.isEmpty ? 0 : 1)
+ Spacer()
+ }
+ Spacer()
+ }
+ }
+ .buttonStyle(.plain) // Prevent taps from being forwarded to the container view
+ // can't use .clear here or else both button padded area and container both respond to tap events
+ .background(BackgroundColor(isSelected: selectedCell == id).color.opacity(0))
+ .accessibilityLabel(buttonAccessibilityLabel)
+ .contentShape(Rectangle())
+ .frame(width: Constants.textFieldTapSize, height: Constants.textFieldTapSize)
+
+ if let secondaryButtonImageName = secondaryButtonImageName,
+ let secondaryButtonAccessibilityLabel = secondaryButtonAccessibilityLabel {
+ Button {
+ secondaryButtonAction?()
+ self.selectedCell = nil
+ } label: {
+ VStack(alignment: .trailing) {
+ Spacer()
+ HStack {
+ Spacer()
+ Image(secondaryButtonImageName)
+ .resizable()
+ .frame(width: Constants.textFieldImageSize, height: Constants.textFieldImageSize)
+ .foregroundColor(Color(UIColor.label).opacity(Constants.textFieldImageOpacity))
+ .opacity(subtitle.isEmpty ? 0 : 1)
+ Spacer()
+ }
+ Spacer()
+ }
+ }
+ .buttonStyle(.plain) // Prevent taps from being forwarded to the container view
+ .background(BackgroundColor(isSelected: selectedCell == id).color.opacity(0))
+ .accessibilityLabel(secondaryButtonAccessibilityLabel)
+ .contentShape(Rectangle())
+ .frame(width: Constants.textFieldTapSize, height: Constants.textFieldTapSize)
+ }
+
+ }
+ .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: -differenceBetweenImageSizeAndTapAreaPerEdge))
+ }
+ }
+ .selectableBackground(isSelected: selectedCell == id)
+ }
+}
+
+private extension View {
+ func copyable(isSelected: Bool) -> some View {
+ modifier(Copyable(isSelected: isSelected))
+ }
+
+ func selectableBackground(isSelected: Bool) -> some View {
+ modifier(SelectableBackground(isSelected: isSelected))
+ }
+}
+
+private struct Copyable: ViewModifier {
+ var isSelected: Bool
+
+ public func body(content: Content) -> some View {
+ ZStack {
+ Rectangle()
+ .foregroundColor(.clear)
+
+ content
+ .allowsHitTesting(false)
+ .contentShape(Rectangle())
+ .frame(maxWidth: .infinity)
+ .frame(minHeight: Constants.minRowHeight)
+ }
+ }
+}
+
+private struct SelectableBackground: ViewModifier {
+ var isSelected: Bool
+
+ public func body(content: Content) -> some View {
+ content
+ .listRowBackground(BackgroundColor(isSelected: isSelected).color)
+ .listRowInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16))
+ }
+}
+
+private struct ForegroundColor {
+ let isSelected: Bool
+
+ var color: Color {
+ if isSelected {
+ return .gray90
+ } else {
+ return .gray50
+ }
+ }
+}
+
+private struct BackgroundColor {
+ let isSelected: Bool
+
+ var color: Color {
+ if isSelected {
+ return Color("AutofillCellSelectedBackground")
+ } else {
+ return Color(designSystemColor: .surface)
+ }
+ }
+}
+
+private struct Constants {
+ static let verticalPadding: CGFloat = 4
+ static let minRowHeight: CGFloat = 60
+ static let textFieldImageOpacity: CGFloat = 0.84
+ static let textFieldImageSize: CGFloat = 24
+ static let textFieldTapSize: CGFloat = 36
+ static let insets = EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsViewController.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsViewController.swift
new file mode 100644
index 0000000000..cb4a37c95c
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsViewController.swift
@@ -0,0 +1,125 @@
+//
+// CredentialProviderListDetailsViewController.swift
+// DuckDuckGo
+//
+// Copyright © 2024 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 UIKit
+import SwiftUI
+import BrowserServicesKit
+import Common
+import Combine
+import Core
+
+protocol CredentialProviderListDetailsViewControllerDelegate: AnyObject {
+ func credentialProviderListDetailsViewControllerDidProvideText(_ controller: CredentialProviderListDetailsViewController, text: String)
+}
+
+class CredentialProviderListDetailsViewController: UIViewController {
+
+ private enum Constants {
+ static let padding: CGFloat = 16
+ }
+
+ weak var delegate: CredentialProviderListDetailsViewControllerDelegate?
+ private let viewModel: CredentialProviderListDetailsViewModel
+ private var cancellables: Set = []
+ private var contentView: UIView?
+
+ init(account: SecureVaultModels.WebsiteAccount? = nil, tld: TLD, shouldProvideTextToInsert: Bool = false) {
+ self.viewModel = CredentialProviderListDetailsViewModel(account: account,
+ tld: tld,
+ shouldProvideTextToInsert: shouldProvideTextToInsert)
+ super.init(nibName: nil, bundle: nil)
+ self.viewModel.delegate = self
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ var account: SecureVaultModels.WebsiteAccount? {
+ get {
+ viewModel.account
+ }
+ set {
+ if let newValue {
+ viewModel.updateData(with: newValue)
+ }
+ }
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ installSubviews()
+ setupCancellables()
+ setupNavigationBar()
+ }
+
+ private func installSubviews() {
+ installContentView()
+ }
+
+ private func setupCancellables() {
+ Publishers.MergeMany(
+ viewModel.$title,
+ viewModel.$username,
+ viewModel.$password,
+ viewModel.$address,
+ viewModel.$notes)
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] _ in
+ self?.setupNavigationBar()
+ }
+ .store(in: &cancellables)
+
+ }
+
+ private func installContentView() {
+ let contentView = CredentialProviderListDetailsView(viewModel: viewModel)
+ let hostingController = UIHostingController(rootView: contentView)
+ addChild(hostingController)
+ hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ hostingController.view.frame = view.bounds
+ view.addSubview(hostingController.view)
+ hostingController.didMove(toParent: self)
+ self.contentView = hostingController.view
+ }
+
+ private func setupNavigationBar() {
+ title = viewModel.navigationTitle
+ }
+
+ func showActionMessage(_ message: String) {
+ ActionMessageView.present(
+ message: message,
+ actionTitle: "",
+ onAction: {},
+ inView: self.view
+ )
+ }
+}
+
+extension CredentialProviderListDetailsViewController: CredentialProviderListDetailsViewModelDelegate {
+ func credentialProviderListDetailsViewModelDidProvideText(text: String) {
+ delegate?.credentialProviderListDetailsViewControllerDidProvideText(self, text: text)
+ }
+
+ func credentialProviderListDetailsViewModelShowActionMessage(message: String) {
+ showActionMessage(message)
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsViewModel.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsViewModel.swift
new file mode 100644
index 0000000000..33fac86061
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderListDetails/CredentialProviderListDetailsViewModel.swift
@@ -0,0 +1,192 @@
+//
+// CredentialProviderListDetailsViewModel.swift
+// DuckDuckGo
+//
+// Copyright © 2024 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 UIKit
+import SwiftUI
+import BrowserServicesKit
+import Common
+import Combine
+import Core
+
+protocol CredentialProviderListDetailsViewModelDelegate: AnyObject {
+ func credentialProviderListDetailsViewModelShowActionMessage(message: String)
+ func credentialProviderListDetailsViewModelDidProvideText(text: String)
+}
+
+final class CredentialProviderListDetailsViewModel: ObservableObject {
+ enum ViewMode {
+ case view
+ }
+
+ enum PasteboardCopyAction {
+ case username
+ case password
+ case address
+ case notes
+ }
+
+ weak var delegate: CredentialProviderListDetailsViewModelDelegate?
+ var account: SecureVaultModels.WebsiteAccount?
+
+ private let tld: TLD
+ private let autofillDomainNameUrlMatcher = AutofillDomainNameUrlMatcher()
+ private let autofillDomainNameUrlSort = AutofillDomainNameUrlSort()
+
+ @ObservedObject var headerViewModel: CredentialProviderListDetailsHeaderViewModel
+ @Published var isPasswordHidden = true
+ @Published var username = ""
+ @Published var password = ""
+ @Published var address = ""
+ @Published var notes = ""
+ @Published var title = ""
+ @Published var selectedCell: UUID?
+
+ private var passwordData: Data {
+ password.data(using: .utf8)!
+ }
+
+ var navigationTitle: String {
+ return title.isEmpty ? address : title
+ }
+
+ var websiteIsValidUrl: Bool {
+ account?.domain?.toTrimmedURL != nil
+ }
+
+ var userVisiblePassword: String {
+ let passwordHider = PasswordHider(password: password)
+ return isPasswordHidden ? passwordHider.hiddenPassword : passwordHider.password
+ }
+
+ var usernameDisplayString: String {
+ AutofillInterfaceEmailTruncator.truncateEmail(username, maxLength: 36)
+ }
+
+ let shouldProvideTextToInsert: Bool
+
+ internal init(account: SecureVaultModels.WebsiteAccount? = nil,
+ tld: TLD,
+ emailManager: EmailManager = EmailManager(),
+ shouldProvideTextToInsert: Bool) {
+ self.account = account
+ self.tld = tld
+ self.headerViewModel = CredentialProviderListDetailsHeaderViewModel()
+ self.shouldProvideTextToInsert = shouldProvideTextToInsert
+ if let account = account {
+ self.updateData(with: account)
+ }
+ }
+
+ func updateData(with account: SecureVaultModels.WebsiteAccount) {
+ self.account = account
+ username = account.username ?? ""
+ address = account.domain ?? ""
+ title = account.title ?? ""
+ notes = account.notes ?? ""
+ headerViewModel.updateData(with: account,
+ tld: tld,
+ autofillDomainNameUrlMatcher: autofillDomainNameUrlMatcher,
+ autofillDomainNameUrlSort: autofillDomainNameUrlSort)
+ setupPassword(with: account)
+ }
+
+ func copyToPasteboard(_ action: PasteboardCopyAction) {
+ var message = ""
+ switch action {
+ case .username:
+ message = UserText.credentialProviderDetailsCopyToastUsernameCopied
+ UIPasteboard.general.string = username
+ Pixel.fire(pixel: .autofillManagementCopyUsername)
+ case .password:
+ message = UserText.credentialProviderDetailsCopyToastPasswordCopied
+ UIPasteboard.general.string = password
+ Pixel.fire(pixel: .autofillManagementCopyPassword)
+ case .address:
+ message = UserText.credentialProviderDetailsCopyToastAddressCopied
+ UIPasteboard.general.string = address
+ case .notes:
+ message = UserText.credentialProviderDetailsCopyToastNotesCopied
+ UIPasteboard.general.string = notes
+ }
+
+ delegate?.credentialProviderListDetailsViewModelShowActionMessage(message: message)
+ }
+
+ func textToReturn(_ action: PasteboardCopyAction) {
+ var text = ""
+ switch action {
+ case .username:
+ text = username
+ case .password:
+ text = password
+ default:
+ return
+ }
+
+ delegate?.credentialProviderListDetailsViewModelDidProvideText(text: text)
+ }
+
+ private func setupPassword(with account: SecureVaultModels.WebsiteAccount) {
+ do {
+ if let accountID = account.id, let accountIdInt = Int64(accountID) {
+ let vault = try AutofillSecureVaultFactory.makeVault(reporter: nil)
+
+ if let credential = try
+ vault.websiteCredentialsFor(accountId: accountIdInt) {
+ self.password = credential.password.flatMap { String(data: $0, encoding: .utf8) } ?? ""
+ }
+ }
+ } catch {
+ Pixel.fire(pixel: .secureVaultError, error: error)
+ }
+ }
+
+ private func handleSecureVaultError(_ error: Error) {
+ Pixel.fire(pixel: .secureVaultError, error: error)
+ }
+}
+
+final class CredentialProviderListDetailsHeaderViewModel: ObservableObject {
+ private var dateFormatter: DateFormatter = {
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateStyle = .medium
+ dateFormatter.timeStyle = .short
+ return dateFormatter
+ }()
+
+ @Published var title: String = ""
+ @Published var subtitle: String = ""
+ @Published var domain: String = ""
+ @Published var favicon: UIImage = UIImage(named: "Logo")!
+
+ func updateData(with account: SecureVaultModels.WebsiteAccount, tld: TLD, autofillDomainNameUrlMatcher: AutofillDomainNameUrlMatcher, autofillDomainNameUrlSort: AutofillDomainNameUrlSort) {
+ self.title = account.name(tld: tld, autofillDomainNameUrlMatcher: autofillDomainNameUrlMatcher)
+ self.subtitle = UserText.credentialProviderDetailsLastUpdated(for: (dateFormatter.string(from: account.lastUpdated)))
+ self.domain = account.domain ?? ""
+
+ // Update favicon
+ let accountName = account.name(tld: tld, autofillDomainNameUrlMatcher: autofillDomainNameUrlMatcher)
+ let accountTitle = (account.title?.isEmpty == false) ? account.title! : "#"
+ let preferredFakeFaviconLetters = tld.eTLDplus1(accountName) ?? accountTitle
+ if let image = FaviconHelper.loadImageFromCache(forDomain: domain, preferredFakeFaviconLetters: preferredFakeFaviconLetters) {
+ self.favicon = image
+ }
+ }
+
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/CredentialProviderViewController.swift b/AutofillCredentialProvider/CredentialProvider/CredentialProviderViewController.swift
index 397b1a5781..35f730611e 100644
--- a/AutofillCredentialProvider/CredentialProvider/CredentialProviderViewController.swift
+++ b/AutofillCredentialProvider/CredentialProvider/CredentialProviderViewController.swift
@@ -112,26 +112,39 @@ class CredentialProviderViewController: ASCredentialProviderViewController {
Task {
await credentialIdentityStoreManager.populateCredentialStore()
}
+
+ Pixel.fire(pixel: .autofillExtensionEnabled)
+ }
+
+ @available(iOSApplicationExtension 18.0, *)
+ override func prepareInterfaceForUserChoosingTextToInsert() {
+ loadCredentialsList(for: [], shouldProvideTextToInsert: true)
}
// MARK: - Private
- private func loadCredentialsList(for serviceIdentifiers: [ASCredentialServiceIdentifier], returnString: Bool = false) {
+ private func loadCredentialsList(for serviceIdentifiers: [ASCredentialServiceIdentifier], shouldProvideTextToInsert: Bool = false) {
let credentialProviderListViewController = CredentialProviderListViewController(serviceIdentifiers: serviceIdentifiers,
secureVault: secureVault,
credentialIdentityStoreManager: credentialIdentityStoreManager,
+ shouldProvideTextToInsert: shouldProvideTextToInsert,
+ tld: tld,
onRowSelected: { [weak self] item in
- guard let self = self else {
- self?.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain,
- code: ASExtensionError.failed.rawValue))
- return
- }
+ guard let self = self else {
+ self?.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain,
+ code: ASExtensionError.failed.rawValue))
+ return
+ }
- let credential = self.vaultCredentialManager.fetchCredential(for: item.account)
+ let credential = self.vaultCredentialManager.fetchCredential(for: item.account)
- self.extensionContext.completeRequest(withSelectedCredential: credential, completionHandler: nil)
+ self.extensionContext.completeRequest(withSelectedCredential: credential, completionHandler: nil)
- }, onDismiss: {
+ }, onTextProvided: { [weak self] text in
+ if #available(iOSApplicationExtension 18.0, *) {
+ self?.extensionContext.completeRequest(withTextToInsert: text)
+ }
+ }, onDismiss: {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain,
code: ASExtensionError.userCanceled.rawValue))
})
@@ -150,20 +163,24 @@ class CredentialProviderViewController: ASCredentialProviderViewController {
guard let passwordCredential = vaultCredentialManager.fetchCredential(for: credentialIdentity) else {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain,
code: ASExtensionError.credentialIdentityNotFound.rawValue))
+ Pixel.fire(pixel: .autofillExtensionQuickTypeCancelled)
return
}
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
+ Pixel.fire(pixel: .autofillExtensionQuickTypeConfirmed)
}
private func provideCredential(for credentialIdentity: ASPasswordCredentialIdentity) {
guard let passwordCredential = vaultCredentialManager.fetchCredential(for: credentialIdentity) else {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain,
code: ASExtensionError.credentialIdentityNotFound.rawValue))
+ Pixel.fire(pixel: .autofillExtensionQuickTypeCancelled)
return
}
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential)
+ Pixel.fire(pixel: .autofillExtensionQuickTypeConfirmed)
}
private func authenticateAndHandleCredential(provideCredential: @escaping () -> Void) {
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/AutofillCellSelectedBackground.colorset/Contents.json b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/AutofillCellSelectedBackground.colorset/Contents.json
new file mode 100644
index 0000000000..cc91bfda6f
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/AutofillCellSelectedBackground.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "display-p3",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0.800",
+ "green" : "0.800",
+ "red" : "0.800"
+ }
+ },
+ "idiom" : "universal"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "color" : {
+ "color-space" : "display-p3",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0.267",
+ "green" : "0.267",
+ "red" : "0.267"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Copy-24.imageset/Contents.json b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Copy-24.imageset/Contents.json
new file mode 100644
index 0000000000..1a533a908e
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Copy-24.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "filename" : "Copy-24.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true,
+ "template-rendering-intent" : "template"
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Copy-24.imageset/Copy-24.pdf b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Copy-24.imageset/Copy-24.pdf
new file mode 100644
index 0000000000..56407ef84b
Binary files /dev/null and b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Copy-24.imageset/Copy-24.pdf differ
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-24.imageset/Contents.json b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-24.imageset/Contents.json
new file mode 100644
index 0000000000..d46a04ef5b
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-24.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "filename" : "Eye-24.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true,
+ "template-rendering-intent" : "template"
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-24.imageset/Eye-24.pdf b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-24.imageset/Eye-24.pdf
new file mode 100644
index 0000000000..ac69e29aa6
Binary files /dev/null and b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-24.imageset/Eye-24.pdf differ
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-Closed-24.imageset/Contents.json b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-Closed-24.imageset/Contents.json
new file mode 100644
index 0000000000..ac2612ee62
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-Closed-24.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "filename" : "Eye-Closed-24.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true,
+ "template-rendering-intent" : "template"
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-Closed-24.imageset/Eye-Closed-24.pdf b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-Closed-24.imageset/Eye-Closed-24.pdf
new file mode 100644
index 0000000000..78b200d65b
Binary files /dev/null and b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Eye-Closed-24.imageset/Eye-Closed-24.pdf differ
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Logo.imageset/Contents.json b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Logo.imageset/Contents.json
new file mode 100644
index 0000000000..5cf237b7f3
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Logo.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "Dax_default.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Logo.imageset/Dax_default.pdf b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Logo.imageset/Dax_default.pdf
new file mode 100644
index 0000000000..46ebb1057c
Binary files /dev/null and b/AutofillCredentialProvider/CredentialProvider/Resources/Assets.xcassets/Logo.imageset/Dax_default.pdf differ
diff --git a/AutofillCredentialProvider/CredentialProvider/Resources/UserText.swift b/AutofillCredentialProvider/CredentialProvider/Resources/UserText.swift
index 74922adc7a..9068764c55 100644
--- a/AutofillCredentialProvider/CredentialProvider/Resources/UserText.swift
+++ b/AutofillCredentialProvider/CredentialProvider/Resources/UserText.swift
@@ -21,18 +21,18 @@ import Foundation
final class UserText {
- static let credentialProviderActivatedTitle = NSLocalizedString("credential.provider.activated.title", value: "Autofill activated!", comment: "The title of the screen confirming DuckDuckGo can now be used for autofilling passwords")
-
- static let credentialProviderActivatedSubtitle = NSLocalizedString("credential.provider.activated.subtitle", value: "You can now autofill your DuckDuckGo passwords from anywhere.", comment: "The subtitle of the screen confirming DuckDuckGo can now be used for autofilling passwords")
+ static let credentialProviderActivatedTitle = NSLocalizedString("credential.provider.activated.title", value: "Autofill Passwords activated!", comment: "The title of the screen confirming DuckDuckGo can now be used for autofilling passwords")
static let credentialProviderActivatedButton = NSLocalizedString("credential.provider.activated.button", value: "Open DuckDuckGo", comment: "Title of button to launch the DuckDuckGo app")
- static let actionCancel = NSLocalizedString("action.button.cancel", value: "Cancel", comment: "Cancel button title")
+ static let actionClose = NSLocalizedString("action.button.close", value: "Close", comment: "Close button title")
- static let actionClose = NSLocalizedString("action.button.cancel", value: "Close", comment: "Close button title")
+ static let actionDone = NSLocalizedString("action.button.done", value: "Done", comment: "Done button title")
static let credentialProviderListTitle = NSLocalizedString("credential.provider.list.title", value: "Passwords", comment: "Title for screen listing autofill logins")
+ static let credentialProviderListPrompt = NSLocalizedString("credential.provider.list.prompt", value: "Choose a password to use for \"%@\"", comment: "Prompt above the title for screen listing autofill logins, example: Choose a password to use for \"website.com\"")
+
static let credentialProviderListSearchPlaceholder = NSLocalizedString("credential.provider.list.search-placeholder", value: "Search passwords", comment: "Placeholder for search field on autofill login listing")
static let credentialProviderListEmptyViewTitle = NSLocalizedString("credential.provider.list.empty-view.title", value: "No passwords saved yet", comment: "Title for view displayed when autofill has no items")
@@ -58,6 +58,29 @@ final class UserText {
static let deviceTypeiPhone = NSLocalizedString("credential.provider.device.type.iphone", value: "iPhone", comment: "Device type is iPhone")
static let deviceTypeiPad = NSLocalizedString("credential.provider.device.type.pad", value: "iPad", comment: "Device type is iPad")
- static let deviceTypeDefault = NSLocalizedString("credential.providerdevice.type.default", value: "device", comment: "Default string used if users device is not iPhone or iPad")
+ static let deviceTypeDefault = NSLocalizedString("credential.provider.device.type.default", value: "device", comment: "Default string used if users device is not iPhone or iPad")
+
+ public static let credentialProviderDetailsCopyToastUsernameCopied = NSLocalizedString("credential.provider.list.details.copy-toast.username-copied", value: "Username copied", comment: "Title for toast when copying username")
+ public static let credentialProviderDetailsCopyToastPasswordCopied = NSLocalizedString("credential.provider.list.details.copy-toast.password-copied", value: "Password copied", comment: "Title for toast when copying password")
+ public static let credentialProviderDetailsCopyToastAddressCopied = NSLocalizedString("credential.provider.list.details.copy-toast.address-copied", value: "Address copied", comment: "Title for toast when copying address")
+ public static let credentialProviderDetailsCopyToastNotesCopied = NSLocalizedString("credential.provider.list.details.copy-toast.notes-copied", value: "Notes copied", comment: "Title for toast when copying notes")
+
+ public static func credentialProviderDetailsLastUpdated(for date: String) -> String {
+ let message = NSLocalizedString("credential.provider.list.details.last-updated", value: "Last updated %@", comment: "Message displaying when the login was last updated")
+ return message.format(arguments: date)
+ }
+
+ public static let credentialProviderDetailsLoginName = NSLocalizedString("credential.provider.list.details.login-name", value: "Title", comment: "Login name label for login details on autofill")
+ public static let credentialProviderDetailsUsername = NSLocalizedString("credential.provider.list.details.username", value: "Username", comment: "Username label for login details on autofill")
+ public static let credentialProviderDetailsPassword = NSLocalizedString("credential.provider.list.details.password", value: "Password", comment: "Password label for login details on autofill")
+ public static let credentialProviderDetailsAddress = NSLocalizedString("credential.provider.list.details.address", value: "Website URL", comment: "Address label for login details on autofill")
+ public static let credentialProviderDetailsNotes = NSLocalizedString("credential.provider.list.details.notes", value: "Notes", comment: "Notes label for login details on autofill")
+
+ public static func credentialProviderDetailsCopyPrompt(for type: String) -> String {
+ let message = NSLocalizedString("credential.provider.list.details.copy-prompt", value: "Copy %@", comment: "Menu item text for copying autofill login details")
+ return message.format(arguments: type)
+ }
+ public static let credentialProviderDetailsShowPassword = NSLocalizedString("credential.provider.list.details.show-password", value: "Show Password", comment: "Accessibility title for a Show Password button displaying actial password instead of *****")
+ public static let credentialProviderDetailsHidePassword = NSLocalizedString("credential.provider.list.details.hide-password", value: "Hide Password", comment: "Accessibility title for a Hide Password button replacing displayed password with *****")
}
diff --git a/AutofillCredentialProvider/CredentialProvider/Shared/ActionMessageView.swift b/AutofillCredentialProvider/CredentialProvider/Shared/ActionMessageView.swift
new file mode 100644
index 0000000000..50a1b38a4e
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Shared/ActionMessageView.swift
@@ -0,0 +1,197 @@
+//
+// ActionMessageView.swift
+// DuckDuckGo
+//
+// Copyright © 2021 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 UIKit
+
+extension ActionMessageView: NibLoading {}
+
+class ActionMessageView: UIView {
+
+ enum PresentationLocation {
+ case withBottomBar(andAddressBarBottom: Bool)
+ case withoutBottomBar
+ }
+
+ private static var presentedMessages = [ActionMessageView]()
+
+ private enum Constants {
+ static var maxWidth: CGFloat = 346
+ static var minimumHorizontalPadding: CGFloat = 20
+ static var cornerRadius: CGFloat = 10
+
+ static var animationDuration: TimeInterval = 0.2
+ static var duration: TimeInterval = 3.0
+
+ static var windowBottomPaddingWithBottomBar: CGFloat {
+ if UIDevice.current.userInterfaceIdiom == .phone && !UIDevice.current.orientation.isPortrait {
+ return 40
+ }
+
+ return 70
+ }
+
+ static var windowBottomPaddingWithAddressBar: CGFloat {
+ return windowBottomPaddingWithBottomBar + 52
+ }
+
+ static var windowBottomPaddingWithoutBottomBar: CGFloat {
+ return 0
+ }
+
+ }
+
+ private static func bottomPadding(for location: PresentationLocation) -> CGFloat {
+ switch location {
+ case .withBottomBar(let isAddressBarBottom):
+ return isAddressBarBottom ? Constants.windowBottomPaddingWithAddressBar : Constants.windowBottomPaddingWithBottomBar
+ case .withoutBottomBar:
+ return Constants.windowBottomPaddingWithoutBottomBar
+ }
+ }
+
+ @IBOutlet weak var message: UILabel!
+ @IBOutlet weak var actionButton: UIButton!
+
+ @IBOutlet var labelToButton: NSLayoutConstraint!
+ @IBOutlet var labelToTrailing: NSLayoutConstraint!
+
+ private var action: () -> Void = {}
+ private var onDidDismiss: () -> Void = {}
+
+ private var dismissWorkItem: DispatchWorkItem?
+
+ static func loadFromXib() -> ActionMessageView {
+ return ActionMessageView.load(nibName: "ActionMessageView")
+ }
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+
+ layer.cornerRadius = Constants.cornerRadius
+ }
+
+ static func present(message: NSAttributedString,
+ numberOfLines: Int = 0,
+ actionTitle: String? = nil,
+ presentationLocation: PresentationLocation = .withBottomBar(andAddressBarBottom: false),
+ duration: TimeInterval = Constants.duration,
+ onAction: @escaping () -> Void = {},
+ onDidDismiss: @escaping () -> Void = {},
+ inView: UIView) {
+ let messageView = loadFromXib()
+ messageView.message.attributedText = message
+ messageView.message.numberOfLines = numberOfLines
+ ActionMessageView.present(messageView: messageView,
+ message: message.string,
+ actionTitle: actionTitle,
+ presentationLocation: presentationLocation,
+ duration: duration,
+ onAction: onAction,
+ onDidDismiss: onDidDismiss,
+ inView: inView)
+ }
+
+ static func present(message: String,
+ actionTitle: String? = nil,
+ presentationLocation: PresentationLocation = .withBottomBar(andAddressBarBottom: false),
+ duration: TimeInterval = Constants.duration,
+ onAction: @escaping () -> Void = {},
+ onDidDismiss: @escaping () -> Void = {},
+ inView: UIView) {
+ let messageView = loadFromXib()
+ messageView.message.text = message
+ ActionMessageView.present(messageView: messageView,
+ message: message,
+ actionTitle: actionTitle,
+ presentationLocation: presentationLocation,
+ duration: duration,
+ onAction: onAction,
+ onDidDismiss: onDidDismiss,
+ inView: inView)
+ }
+
+ private static func present(messageView: ActionMessageView,
+ message: String,
+ actionTitle: String? = nil,
+ presentationLocation: PresentationLocation = .withBottomBar(andAddressBarBottom: false),
+ duration: TimeInterval = Constants.duration,
+ onAction: @escaping () -> Void = {},
+ onDidDismiss: @escaping () -> Void = {},
+ inView: UIView) {
+ dismissAllMessages()
+
+ if let actionTitle = actionTitle, let title = messageView.actionButton.attributedTitle(for: .normal) {
+ messageView.actionButton.setAttributedTitle(title.withText(actionTitle), for: .normal)
+ messageView.action = onAction
+ } else {
+ messageView.labelToButton.isActive = false
+ messageView.labelToTrailing.isActive = true
+ messageView.actionButton.isHidden = true
+ }
+ messageView.onDidDismiss = onDidDismiss
+
+ inView.addSubview(messageView)
+ inView.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: messageView.bottomAnchor,
+ constant: bottomPadding(for: presentationLocation)).isActive = true
+
+ let messageViewWidth = inView.frame.width <= Constants.maxWidth ? inView.frame.width - Constants.minimumHorizontalPadding : Constants.maxWidth
+ messageView.widthAnchor.constraint(equalToConstant: messageViewWidth).isActive = true
+ messageView.centerXAnchor.constraint(equalTo: inView.centerXAnchor).isActive = true
+
+ inView.layoutIfNeeded()
+
+ messageView.alpha = 0
+ UIView.animate(withDuration: Constants.animationDuration) {
+ messageView.alpha = 1
+ } completion: { _ in
+ UIAccessibility.post(notification: .announcement, argument: message)
+ }
+
+ let workItem = DispatchWorkItem { [weak messageView] in
+ messageView?.dismissAndFadeOut()
+ }
+ messageView.dismissWorkItem = workItem
+ DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: workItem)
+ presentedMessages.append(messageView)
+ }
+
+ static func dismissAllMessages() {
+ presentedMessages.forEach { $0.dismissAndFadeOut() }
+ }
+
+ func dismissAndFadeOut() {
+ dismissWorkItem?.cancel()
+ dismissWorkItem = nil
+
+ UIView.animate(withDuration: Constants.animationDuration, animations: {
+ self.alpha = 0
+ }, completion: { _ in
+ self.removeFromSuperview()
+ if let position = Self.presentedMessages.firstIndex(of: self) {
+ Self.presentedMessages.remove(at: position)
+ }
+ self.onDidDismiss()
+ })
+ }
+
+ @IBAction func onButtonTap() {
+ action()
+ dismissAndFadeOut()
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Shared/ActionMessageView.xib b/AutofillCredentialProvider/CredentialProvider/Shared/ActionMessageView.xib
new file mode 100644
index 0000000000..2c532dc85f
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Shared/ActionMessageView.xib
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AutofillCredentialProvider/CredentialProvider/Shared/FaviconHelper.swift b/AutofillCredentialProvider/CredentialProvider/Shared/FaviconHelper.swift
new file mode 100644
index 0000000000..b1d95ef7a8
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Shared/FaviconHelper.swift
@@ -0,0 +1,87 @@
+//
+// FaviconHelper.swift
+// DuckDuckGo
+//
+// Copyright © 2024 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
+import Common
+import Core
+import UIKit
+
+struct FaviconHelper {
+
+ static func loadImageFromCache(forDomain domain: String?, preferredFakeFaviconLetters: String) -> UIImage? {
+ guard let domain = domain,
+ let cacheUrl = FaviconsCacheType.fireproof.cacheLocation() else { return nil }
+
+ let key = FaviconHasher.createHash(ofDomain: domain)
+
+ // Slight leap here to avoid loading Kingfisher as a library for the widgets.
+ // Once dependency management is fixed, link it and use Favicons directly.
+ let imageUrl = cacheUrl.appendingPathComponent("com.onevcat.Kingfisher.ImageCache.fireproof").appendingPathComponent(key)
+
+ guard let data = (try? Data(contentsOf: imageUrl)) else {
+ let image = Self.createFakeFavicon(forDomain: domain, size: 32, backgroundColor: UIColor.forDomain(domain), preferredFakeFaviconLetters: preferredFakeFaviconLetters)
+ return image
+ }
+
+ return UIImage(data: data)?.toSRGB()
+ }
+
+ private static func createFakeFavicon(forDomain domain: String,
+ size: CGFloat = 192,
+ backgroundColor: UIColor = UIColor.red,
+ bold: Bool = true,
+ preferredFakeFaviconLetters: String? = nil,
+ letterCount: Int = 2) -> UIImage? {
+
+ let cornerRadius = size * 0.125
+ let imageRect = CGRect(x: 0, y: 0, width: size, height: size)
+ let padding = size * 0.16
+ let labelFrame = CGRect(x: padding, y: padding, width: imageRect.width - (2 * padding), height: imageRect.height - (2 * padding))
+
+ let renderer = UIGraphicsImageRenderer(size: imageRect.size)
+ let icon = renderer.image { imageContext in
+ let context = imageContext.cgContext
+
+ context.setFillColor(backgroundColor.cgColor)
+ context.addPath(CGPath(roundedRect: imageRect, cornerWidth: cornerRadius, cornerHeight: cornerRadius, transform: nil))
+ context.fillPath()
+
+ let label = UILabel(frame: labelFrame)
+ label.numberOfLines = 1
+ label.adjustsFontSizeToFitWidth = true
+ label.minimumScaleFactor = 0.1
+ label.baselineAdjustment = .alignCenters
+ label.font = bold ? UIFont.boldSystemFont(ofSize: size) : UIFont.systemFont(ofSize: size)
+ label.textColor = .white
+ label.textAlignment = .center
+
+ if let preferedPrefix = preferredFakeFaviconLetters?.droppingWwwPrefix().prefix(letterCount).capitalized {
+ label.text = preferedPrefix
+ } else {
+ label.text = preferredFakeFaviconLetters?.capitalized ?? "#"
+ }
+
+ context.translateBy(x: padding, y: padding)
+
+ label.layer.draw(in: context)
+ }
+
+ return icon.withRenderingMode(.alwaysOriginal)
+ }
+}
diff --git a/AutofillCredentialProvider/CredentialProvider/Shared/NibLoading.swift b/AutofillCredentialProvider/CredentialProvider/Shared/NibLoading.swift
new file mode 100644
index 0000000000..af24b38f7c
--- /dev/null
+++ b/AutofillCredentialProvider/CredentialProvider/Shared/NibLoading.swift
@@ -0,0 +1,34 @@
+//
+// NibLoading.swift
+// DuckDuckGo
+//
+// Copyright © 2017 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 UIKit
+
+protocol NibLoading {
+}
+
+extension NibLoading where Self: UIView {
+ static func load(nibName: String) -> Self {
+ let nib = UINib(nibName: nibName, bundle: nil)
+ guard let view = nib.instantiate(withOwner: self, options: nil).first as? Self else {
+ fatalError("Error instantiating view")
+ }
+ view.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
+ return view
+ }
+}
diff --git a/AutofillCredentialProvider/Info.plist b/AutofillCredentialProvider/Info.plist
index cb9ba8ea30..c00abcf6dc 100644
--- a/AutofillCredentialProvider/Info.plist
+++ b/AutofillCredentialProvider/Info.plist
@@ -12,6 +12,13 @@
$(PRODUCT_MODULE_NAME).CredentialProviderViewController
ASCredentialProviderExtensionShowsConfigurationUI
+ ASCredentialProviderExtensionCapabilities
+
+ ProvidesPasswords
+
+ ProvidesTextToInsert
+
+
NSExtensionPointIdentifier
com.apple.authentication-services-credential-provider-ui
diff --git a/AutofillCredentialProvider/bg.lproj/InfoPlist.strings b/AutofillCredentialProvider/bg.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/bg.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/bg.lproj/Localizable.strings b/AutofillCredentialProvider/bg.lproj/Localizable.strings
new file mode 100644
index 0000000000..82a8dc2b8c
--- /dev/null
+++ b/AutofillCredentialProvider/bg.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Затваряне";
+
+/* Done button title */
+"action.button.done" = "Готово";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Отваряне на DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Автоматичното попълване на пароли е активирано!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "устройство";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Отмени";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Отключете устройството, за да получите достъп до паролите";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Адрес на уебсайта";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Копиране на %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Адресът е копиран";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Бележките са копирани";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Паролата е копирана";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Потребителското име е копирано";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Скриване на паролата";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Последна актуализация %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Заглавие";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Бележки";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Парола";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Показване на паролата";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Потребителско име";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Паролите се съхраняват сигурно на Вашето устройство.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Все още няма запазени пароли";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Избиране на парола, която да бъде използвана за „%@“";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Търсене на пароли";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "за '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Няма резултати";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Предложения";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Пароли";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Задаване на парола на %@ за автоматично попълване на паролите за DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Изисква се парола на устройството";
+
diff --git a/AutofillCredentialProvider/cs.lproj/InfoPlist.strings b/AutofillCredentialProvider/cs.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/cs.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/cs.lproj/Localizable.strings b/AutofillCredentialProvider/cs.lproj/Localizable.strings
new file mode 100644
index 0000000000..230c19ae1c
--- /dev/null
+++ b/AutofillCredentialProvider/cs.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Zavřít";
+
+/* Done button title */
+"action.button.done" = "Hotovo";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Otevřít DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatické vyplňování hesel je zapnuté.";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "zařízení";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhonu";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPadu";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Zrušit";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Pro přístup k heslům zařízení odemkni";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL webové stránky";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopírovat %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresa zkopírovaná";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Poznámky zkopírované";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Heslo zkopírované";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Uživatelské jméno zkopírované";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Skrýt heslo";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Poslední aktualizace %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Název";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Poznámky";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Heslo";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Zobrazit heslo";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Uživatelské jméno";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Hesla se bezpečně ukládají do tvého zařízení.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Zatím nemáš uložená žádná hesla";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Vyber si, které heslo použiješ pro účet %@";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Prohledat hesla";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "pro „%@“";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Žádné výsledky";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Navrhované";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Hesla";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Nastav si přístupový kód pro zařízení %@ a DuckDuckGo bude automaticky vyplňovat hesla.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Přístupový kód pro zařízení je povinný";
+
diff --git a/AutofillCredentialProvider/da.lproj/InfoPlist.strings b/AutofillCredentialProvider/da.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/da.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/da.lproj/Localizable.strings b/AutofillCredentialProvider/da.lproj/Localizable.strings
new file mode 100644
index 0000000000..49ea766df6
--- /dev/null
+++ b/AutofillCredentialProvider/da.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Luk";
+
+/* Done button title */
+"action.button.done" = "Færdig";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Åbn DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatisk udfyldning af adgangskoder er aktiveret!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "enhed";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Annullér";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Lås enheden op for at få adgang til adgangskoder";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL til webstedet";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopiér %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresse kopieret";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Noter kopieret";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Adgangskode kopieret";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Brugernavn kopieret";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Skjul adgangskode";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Sidst opdateret %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Titel";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Noter";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Adgangskode";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Vis adgangskode";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Brugernavn";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Adgangskoder gemmes sikkert på din enhed.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Ingen adgangskoder gemt endnu";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Vælg en adgangskode til \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Søg adgangskoder";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "for '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Ingen resultater";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Foreslået";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Adgangskoder";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Opret en adgangskode på %@ for automatisk at udfylde dine DuckDuckGo-adgangskoder.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Adgangskode til enheden påkrævet";
+
diff --git a/AutofillCredentialProvider/de.lproj/InfoPlist.strings b/AutofillCredentialProvider/de.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/de.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/de.lproj/Localizable.strings b/AutofillCredentialProvider/de.lproj/Localizable.strings
new file mode 100644
index 0000000000..e36875c16b
--- /dev/null
+++ b/AutofillCredentialProvider/de.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Schließen";
+
+/* Done button title */
+"action.button.done" = "Fertig";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "DuckDuckGo öffnen";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatisches Ausfüllen von Passwörtern aktiviert!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "Gerät";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Abbrechen";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Gerät entsperren, um auf Passwörter zuzugreifen";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL der Website";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "%@ kopieren";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresse kopiert";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Notizen kopiert";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Passwort kopiert";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Benutzername kopiert";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Passwort ausblenden";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Zuletzt aktualisiert %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Titel";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Notizen";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Passwort";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Passwort anzeigen";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Benutzername";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Passwörter werden sicher auf deinem Gerät gespeichert.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Noch keine Passwörter gespeichert";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Wähle ein Passwort, das du für „%@“ verwendest";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Passwörter suchen";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "für „%@“";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Keine Ergebnisse";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Vorgeschlagen";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Passwörter";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Lege einen Passcode für dein %@ fest, um deine DuckDuckGo-Passwörter automatisch auszufüllen.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Geräte-Passcode erforderlich";
+
diff --git a/AutofillCredentialProvider/el.lproj/InfoPlist.strings b/AutofillCredentialProvider/el.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/el.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/el.lproj/Localizable.strings b/AutofillCredentialProvider/el.lproj/Localizable.strings
new file mode 100644
index 0000000000..cc073f02b6
--- /dev/null
+++ b/AutofillCredentialProvider/el.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Κλείσιμο";
+
+/* Done button title */
+"action.button.done" = "Ολοκληρώθηκε";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Άνοιγμα του DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Η Αυτόματη συμπλήρωση κωδικών πρόσβασης ενεργοποιήθηκε!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "συσκευή";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Ακύρωση";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Ξεκλειδώστε τη συσκευή για πρόσβαση σε κωδικούς πρόσβασης";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Διεύθυνση URL ιστότοπου";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Αντιγραφή %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Η διεύθυνση αντιγράφηκε";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Οι σημειώσεις αντιγράφηκαν";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Ο κωδικός πρόσβασης αντιγράφηκε";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Το όνομα χρήστη αντιγράφηκε";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Απόκρυψη κωδικού πρόσβασης";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Τελευταία ενημέρωση %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Τίτλος";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Σημειώσεις";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Κωδικός πρόσβασης";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Εμφάνιση κωδικού πρόσβασης";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Όνομα χρήστη";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Οι κωδικοί πρόσβασης αποθηκεύονται με ασφάλεια στη συσκευή σας.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Δεν έχουν αποθηκευτεί ακόμα κωδικοί πρόσβασης";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Επιλέξτε έναν κωδικό πρόσβασης για χρήση στο «%@»";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Αναζήτηση κωδικών πρόσβασης";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "για '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Κανένα αποτέλεσμα";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Προτεινόμενο";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Κωδικός πρόσβασης";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Ορίστε έναν κωδικό πρόσβασης στο %@ για αυτόματη συμπλήρωση των κωδικών πρόσβασης DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Απαιτείται κωδικός πρόσβασης συσκευής";
+
diff --git a/AutofillCredentialProvider/es.lproj/InfoPlist.strings b/AutofillCredentialProvider/es.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/es.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/es.lproj/Localizable.strings b/AutofillCredentialProvider/es.lproj/Localizable.strings
new file mode 100644
index 0000000000..572db888b4
--- /dev/null
+++ b/AutofillCredentialProvider/es.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Cerrar";
+
+/* Done button title */
+"action.button.done" = "Hecho";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Abrir DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "¡La función de autocompletar contraseñas está activada!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "dispositivo";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Cancelar";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Desbloquear dispositivo para acceder a contraseñas";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL del sitio web";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Copiar %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Dirección copiada";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Notas copiadas";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Contraseña copiada";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Nombre de usuario copiado";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Ocultar contraseña";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Última actualización % @";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Título";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Notas";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Contraseña";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Mostrar contraseña";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Nombre de usuario";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Las contraseñas se almacenan de forma segura en tu dispositivo.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Aún no hay contraseñas guardadas";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Elige una contraseña para \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Buscar contraseñas";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "para '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Sin resultados";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Sugerencias";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Contraseñas";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Configura un código de acceso en %@ para autocompletar tus contraseñas de DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Se requiere código de acceso del dispositivo";
+
diff --git a/AutofillCredentialProvider/et.lproj/InfoPlist.strings b/AutofillCredentialProvider/et.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/et.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/et.lproj/Localizable.strings b/AutofillCredentialProvider/et.lproj/Localizable.strings
new file mode 100644
index 0000000000..0e60b0e2e6
--- /dev/null
+++ b/AutofillCredentialProvider/et.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Sulge";
+
+/* Done button title */
+"action.button.done" = "Valmis";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Ava DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Paroolide automaatne täitmine on aktiveeritud!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "seade";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Tühista";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Paroolidele juurdepääsuks ava seade";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Veebisaidi URL";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopeeri %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Aadress on kopeeritud";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Märkmed on kopeeritud";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Parool on kopeeritud";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Kasutajanimi on kopeeritud";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Peida parool";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Viimati uuendatud %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Pealkiri";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Märkused";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Parool";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Kuva parool";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Kasutajanimi";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Paroolid salvestatakse turvaliselt sinu seadmesse.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Paroole ei ole veel salvestatud";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Valige salasõna, mida kasutada \"%@\" jaoks";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Otsi paroole";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "otsinguga '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Tulemusi pole";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Soovitatud";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Paroolid";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "DuckDuckGo paroolide automaatseks täitmiseks määrake saidile %@ pääsukood.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Nõutav seadme pääsukood";
+
diff --git a/AutofillCredentialProvider/fi.lproj/InfoPlist.strings b/AutofillCredentialProvider/fi.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/fi.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/fi.lproj/Localizable.strings b/AutofillCredentialProvider/fi.lproj/Localizable.strings
new file mode 100644
index 0000000000..6bbcdd63c0
--- /dev/null
+++ b/AutofillCredentialProvider/fi.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Sulje";
+
+/* Done button title */
+"action.button.done" = "Valmis";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Avaa DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Salasanojen automaattinen täyttö on nyt käytössä!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "laitteelle";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhonelle";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPadille";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Peruuta";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Avaa laitteen lukitus päästäksesi salasanoihin";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Sivuston URL-osoite";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopioi %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Osoite kopioitu";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Muistiinpanot kopioitu";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Salasana kopioitu";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Käyttäjätunnus kopioitu";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Piilota salasana";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Viimeksi päivitetty %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Otsikko";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Huomautukset";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Salasana";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Näytä salasana";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Käyttäjätunnus";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Salasanat tallennetaan laitteellesi turvallisesti.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Salasanoja ei ole vielä tallennettu";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Valitse sivuston salasana: %@";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Etsi salasanoja";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "kohteelle '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Ei tuloksia";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Ehdotettu";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Salasanat";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Jos haluat, että DuckDuckGo täyttää salasanasi automaattisesti, määritä pääsykoodi laitteessa %@.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Edellyttää laitteen pääsykoodia";
+
diff --git a/AutofillCredentialProvider/fr.lproj/InfoPlist.strings b/AutofillCredentialProvider/fr.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/fr.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/fr.lproj/Localizable.strings b/AutofillCredentialProvider/fr.lproj/Localizable.strings
new file mode 100644
index 0000000000..8f01a4e036
--- /dev/null
+++ b/AutofillCredentialProvider/fr.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Fermer";
+
+/* Done button title */
+"action.button.done" = "Terminé";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Ouvrir DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Saisie automatique des mots de passe activée !";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "appareil";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Annuler";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Déverrouiller l'appareil pour accéder aux mots de passe";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL du site Web";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Copier %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresse copiée";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Notes copiées";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Mot de passe copié";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Nom d'utilisateur copié";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Masquer le mot de passe";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Dernière modification : %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Titre";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Notes";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Mot de passe";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Afficher le mot de passe";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Nom d'utilisateur";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Les mots de passe sont stockés en toute sécurité sur votre appareil.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Aucun mot de passe n'a été enregistré";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Choisissez un mot de passe à utiliser pour « %@ »";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Rechercher un mot de passe";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "pour '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Aucun résultat";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Suggéré";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Mots de passe";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Définissez un code d'accès sur %@ pour saisir automatiquement vos mots de passe DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Code d'accès de l'appareil requis";
+
diff --git a/AutofillCredentialProvider/hr.lproj/InfoPlist.strings b/AutofillCredentialProvider/hr.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/hr.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/hr.lproj/Localizable.strings b/AutofillCredentialProvider/hr.lproj/Localizable.strings
new file mode 100644
index 0000000000..38cc9387d7
--- /dev/null
+++ b/AutofillCredentialProvider/hr.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Zatvori";
+
+/* Done button title */
+"action.button.done" = "Gotovo";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Otvori DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatsko popunjavanje lozinki je aktivirano!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "uređaj";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Otkaži";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Otključaj uređaj za pristup lozinkama";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL web lokacije";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopiraj %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresa je kopirana";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Bilješke su kopirane";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Lozinka je kopirana";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Korisničko ime je kopirano";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Sakrij lozinku";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Posljednje ažuriranje: %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Naslov";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Bilješke";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Lozinka";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Pokaži lozinku";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Korisničko ime";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Lozinke su sigurno pohranjene na tvom uređaju.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Još nema spremljenih lozinki";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Odaberi lozinku koju ćeš koristiti za \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Pretraživanje lozinki";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "za '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Nema rezultata";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Predloženo";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Lozinke";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Postavi šifru na uređaju %@ kako bi se tvoje DuckDuckGo lozinke popunjavale automatski.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Potrebna je šifra uređaja.";
+
diff --git a/AutofillCredentialProvider/hu.lproj/InfoPlist.strings b/AutofillCredentialProvider/hu.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/hu.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/hu.lproj/Localizable.strings b/AutofillCredentialProvider/hu.lproj/Localizable.strings
new file mode 100644
index 0000000000..c21a3bb9fb
--- /dev/null
+++ b/AutofillCredentialProvider/hu.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Bezárás";
+
+/* Done button title */
+"action.button.done" = "Kész";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Nyisd meg a DuckDuckGo-alkalmazást";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Jelszavak automatikus kitöltése aktiválva!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "eszközön";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone készüléken";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad készüléken";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Mégsem";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Oldd fel az eszközt a jelszavakhoz való hozzáféréshez";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Webhely URL-címe";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "%@ másolása";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Cím másolva";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Megjegyzések másolva";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Jelszó másolva";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Felhasználónév másolva";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Jelszó elrejtése";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Utolsó frissítés: %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Cím";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Megjegyzések";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Jelszó";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Jelszó megjelenítése";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Felhasználónév";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "A jelszavakat az eszközöd biztonságosan tárolja.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Még nincsenek mentett jelszavak";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Válassz egy jelszót ehhez: \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Jelszavak keresése";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "erre: „%@“";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Nincs találat";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Javasolt";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Jelszavak";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "A DuckDuckGo-jelszavak automatikus kitöltéséhez állíts be egy jelkódot itt: %@.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Meg kell adni az eszköz jelkódját";
+
diff --git a/AutofillCredentialProvider/it.lproj/InfoPlist.strings b/AutofillCredentialProvider/it.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/it.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/it.lproj/Localizable.strings b/AutofillCredentialProvider/it.lproj/Localizable.strings
new file mode 100644
index 0000000000..5b97f6c41c
--- /dev/null
+++ b/AutofillCredentialProvider/it.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Chiudi";
+
+/* Done button title */
+"action.button.done" = "Fatto";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Apri DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Compilazione automatica delle password attivata!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "dispositivo";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Annulla";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Sblocca il dispositivo per accedere alle password";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL del sito Web";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Copia %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Indirizzo copiato";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Appunti copiati";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Password copiata";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Nome utente copiato";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Nascondi password";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Ultimo aggiornamento %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Titolo";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Note";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Password";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Mostra password";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Nome utente";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Le password sono archiviate in modo sicuro sul tuo dispositivo.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Nessuna password ancora salvata";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Scegli una password da usare per \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Cerca password";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "per \"%@\"";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Nessun risultato";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Suggerimenti";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Password";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Imposta un codice di accesso su %@ per inserire automaticamente le tue password DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "È necessario il codice di accesso del dispositivo";
+
diff --git a/AutofillCredentialProvider/lt.lproj/InfoPlist.strings b/AutofillCredentialProvider/lt.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/lt.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/lt.lproj/Localizable.strings b/AutofillCredentialProvider/lt.lproj/Localizable.strings
new file mode 100644
index 0000000000..9867833bfd
--- /dev/null
+++ b/AutofillCredentialProvider/lt.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Uždaryti";
+
+/* Done button title */
+"action.button.done" = "Atlikta";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Atidaryti „DuckDuckGo“";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatinis slaptažodžių pildymas įjungtas!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "įrenginys";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Atšaukti";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Atrakinkite įrenginį, kad galėtumėte pasiekti slaptažodžius";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Svetainės URL";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopijuoti %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresas nukopijuotas";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Pastabos nukopijuotos";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Slaptažodis nukopijuotas";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Naudotojo vardas nukopijuotas";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Paslėpti slaptažodį";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Paskutinį kartą atnaujinta %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Pavadinimas";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Pastabos";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Slaptažodis";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Rodyti slaptažodį";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Naudotojo vardas";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Slaptažodžiai saugiai saugomi jūsų įrenginyje.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Dar nėra išsaugotų slaptažodžių";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Pasirinkite slaptažodį, kurį naudosite „%@“";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Ieškoti slaptažodžių";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "„%@“";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Rezultatų nerasta";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Siūloma";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Slaptažodžiai";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Nustatykite %@ prieigos kodą, kad automatiškai užpildytumėte „DuckDuckGo“ slaptažodžius.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Reikalingas įrenginio kodas";
+
diff --git a/AutofillCredentialProvider/lv.lproj/InfoPlist.strings b/AutofillCredentialProvider/lv.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/lv.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/lv.lproj/Localizable.strings b/AutofillCredentialProvider/lv.lproj/Localizable.strings
new file mode 100644
index 0000000000..5c9150e72f
--- /dev/null
+++ b/AutofillCredentialProvider/lv.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Aizvērt";
+
+/* Done button title */
+"action.button.done" = "Gatavs";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Atvērt DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Paroļu automātiskā aizpildīšana ir aktivizēta!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "ierīcē";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Atcelt";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Atbloķē ierīci, lai piekļūtu parolēm";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Tīmekļa vietnes URL";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopēt %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adrese nokopēta";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Piezīmes nokopētas";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Parole nokopēta";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Lietotājvārds nokopēts";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Paslēpt paroli";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Pēdējoreiz atjaunināts %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Nosaukums";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Piezīmes";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Parole";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Rādīt paroli";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Lietotājvārds";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Paroles tiek droši glabātas tavā ierīcē.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Vēl nav saglabāta neviena parole";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Izvēlies paroli, ko izmantot \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Meklēt paroles";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "meklējumam \"%@\"";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Nav rezultātu";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Ieteikts";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Paroles";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Iestati piekļuves kodu %@, lai automātiski aizpildītu savas DuckDuckGo paroles.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Nepieciešams ierīces piekļuves kods";
+
diff --git a/AutofillCredentialProvider/nb.lproj/InfoPlist.strings b/AutofillCredentialProvider/nb.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/nb.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/nb.lproj/Localizable.strings b/AutofillCredentialProvider/nb.lproj/Localizable.strings
new file mode 100644
index 0000000000..858f84a0d9
--- /dev/null
+++ b/AutofillCredentialProvider/nb.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Lukk";
+
+/* Done button title */
+"action.button.done" = "Ferdig";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Åpne DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatisk fylling av passord er aktivert!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "enhet";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Avbryt";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Lås opp enheten for å få tilgang til passord";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL-adresse til nettsted";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopier %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adressen er kopiert";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Notatene er kopiert";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Passordet er kopiert";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Brukernavnet er kopiert";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Skjul passord";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Sist oppdatert %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Tittel";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Notater";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Passord";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Vis passord";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Brukernavn";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Passord lagres på enheten din på en sikker måte.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Ingen passord er lagret ennå";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Velg et passord du vil bruke til «%@»";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Søk i passord";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "for «%@»";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Ingen resultater";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Forslag";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Passord";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Angi en kode på %@ for å fylle inn DuckDuckGo-passordene dine automatisk.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Enhetens kode kreves";
+
diff --git a/AutofillCredentialProvider/nl.lproj/InfoPlist.strings b/AutofillCredentialProvider/nl.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/nl.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/nl.lproj/Localizable.strings b/AutofillCredentialProvider/nl.lproj/Localizable.strings
new file mode 100644
index 0000000000..5737a0c75a
--- /dev/null
+++ b/AutofillCredentialProvider/nl.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Sluiten";
+
+/* Done button title */
+"action.button.done" = "Klaar";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "DuckDuckGo openen";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatisch invullen van wachtwoorden geactiveerd!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "apparaat";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Annuleren";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Ontgrendel het apparaat om toegang te krijgen tot wachtwoorden";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL van de website";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "%@ kopiëren";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adres gekopieerd";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Opmerkingen gekopieerd";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Wachtwoord gekopieerd";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Gebruikersnaam gekopieerd";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Wachtwoord verbergen";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Laatst bijgewerkt op %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Titel";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Opmerkingen";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Wachtwoord";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Wachtwoord weergeven";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Gebruikersnaam";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Wachtwoorden worden veilig opgeslagen op je apparaat.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Nog geen wachtwoorden opgeslagen";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Kies een wachtwoord voor '%@'";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Wachtwoorden zoeken";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "voor '%@'";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Geen resultaten";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Aanbevolen";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Wachtwoorden";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Stel een toegangscode in op %@ om je DuckDuckGo-wachtwoorden automatisch in te vullen.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Toegangscode voor apparaat vereist";
+
diff --git a/AutofillCredentialProvider/pl.lproj/InfoPlist.strings b/AutofillCredentialProvider/pl.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/pl.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/pl.lproj/Localizable.strings b/AutofillCredentialProvider/pl.lproj/Localizable.strings
new file mode 100644
index 0000000000..b2198855c4
--- /dev/null
+++ b/AutofillCredentialProvider/pl.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Zamknij";
+
+/* Done button title */
+"action.button.done" = "Gotowe";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Otwórz DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatyczne uzupełnianie haseł zostało aktywowane!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "tym urządzeniu";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "tym telefonie iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "tym iPadzie";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Anuluj";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Odblokuj urządzenie, aby uzyskać dostęp do haseł";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Adres URL witryny";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopiuj %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Skopiowano adres";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Skopiowano notatki";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Skopiowano hasło";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Skopiowano nazwę użytkownika";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Ukryj hasło";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Ostatnia aktualizacja %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Tytuł";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Uwagi";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Hasło";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Pokaż hasło";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Nazwa użytkownika";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Hasła są bezpiecznie przechowywane na Twoim urządzeniu.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Nie zapisano jeszcze żadnych haseł";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Wybierz hasło do wykorzystania z „%@”";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Wyszukaj hasła";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "dla frazy: %@";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Brak wyników";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Sugerowane";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Hasła";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Ustaw kod dostępu na urządzeniu %@, aby automatycznie uzupełniać hasła DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Wymagany kod dostępu urządzenia";
+
diff --git a/AutofillCredentialProvider/pt.lproj/InfoPlist.strings b/AutofillCredentialProvider/pt.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/pt.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/pt.lproj/Localizable.strings b/AutofillCredentialProvider/pt.lproj/Localizable.strings
new file mode 100644
index 0000000000..6d2929f0ee
--- /dev/null
+++ b/AutofillCredentialProvider/pt.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Fechar";
+
+/* Done button title */
+"action.button.done" = "Feito";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Abrir DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Preenchimento automático de palavras-passe ativado!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "dispositivo";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Cancelar";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Desbloquear dispositivo para aceder às palavras-passe";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL do site";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Copiar %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Endereço copiado";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Notas copiadas";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Palavra-passe copiada";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Nome de utilizador copiado";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Ocultar palavra-passe";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Última atualização em %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Título";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Notas";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Palavra-passe";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Mostrar palavra-passe";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Nome de utilizador";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "As palavras-passe são armazenadas com segurança no teu dispositivo.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Ainda não há palavras-passe guardadas";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Escolhe uma palavra-passe para usar em \"%@\"";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Pesquisar palavras-passe";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "para \"%@\"";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Sem resultados";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Sugerido";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Palavras-passe";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Define um código de acesso em %@ para preencher automaticamente as tuas palavras-passe DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Código de acesso do dispositivo necessário";
+
diff --git a/AutofillCredentialProvider/ro.lproj/InfoPlist.strings b/AutofillCredentialProvider/ro.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/ro.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/ro.lproj/Localizable.strings b/AutofillCredentialProvider/ro.lproj/Localizable.strings
new file mode 100644
index 0000000000..e90eb1030d
--- /dev/null
+++ b/AutofillCredentialProvider/ro.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Închidere";
+
+/* Done button title */
+"action.button.done" = "Terminat";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Deschide DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Completarea automată a parolelor a fost activată!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "dispozitiv";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Renunță";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Deblochează dispozitivul pentru a accesa parolele";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL-ul site-ului";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Copiază %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresă copiată";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Note copiate";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Parolă copiată";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Numele de utilizator a fost copiat";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Ascunde parola";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Ultima actualizare la %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Titlu";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Note";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Parolă";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Arată parola";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Nume utilizator";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Parolele sunt stocate în siguranță pe dispozitivul tău.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Nici o parolă nu a fost salvată încă";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Alege o parolă pe care să o utilizezi pentru „%@”";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Caută parole";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "pentru „%@”";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Niciun rezultat";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Sugerat";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Parole";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Setează o parolă pe %@ pentru a-ți completa automat parolele DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Codul de acces al dispozitivului este necesar";
+
diff --git a/AutofillCredentialProvider/ru.lproj/InfoPlist.strings b/AutofillCredentialProvider/ru.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/ru.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/ru.lproj/Localizable.strings b/AutofillCredentialProvider/ru.lproj/Localizable.strings
new file mode 100644
index 0000000000..823459918c
--- /dev/null
+++ b/AutofillCredentialProvider/ru.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Закрыть";
+
+/* Done button title */
+"action.button.done" = "Готово";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Открыть DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Автозаполнение паролей включено!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "устройстве";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Отменить";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Разблокируйте устройство, чтобы получить доступ к паролям";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Адрес сайта";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Копировать %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Адрес скопирован";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Примечания скопированы";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Пароль скопирован";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Имя пользователя скопировано!";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Скрыть пароль";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Последнее обновление: %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Название";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Примечания";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Пароль";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Показать пароль";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Имя пользователя";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Пароли надежно защищены и хранятся на вашем устройстве.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Сохраненных паролей пока нет";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Выберите пароль для сайта %@";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Найти пароль";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "по запросу «%@»";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Нет результатов";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Рекомендации";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Пароли";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Задайте код доступа, и %@ будет заполнять пароли из DuckDuckGo автоматически.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Требуется код доступа к устройству";
+
diff --git a/AutofillCredentialProvider/sk.lproj/InfoPlist.strings b/AutofillCredentialProvider/sk.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/sk.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/sk.lproj/Localizable.strings b/AutofillCredentialProvider/sk.lproj/Localizable.strings
new file mode 100644
index 0000000000..c704caedba
--- /dev/null
+++ b/AutofillCredentialProvider/sk.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Zatvoriť";
+
+/* Done button title */
+"action.button.done" = "Hotovo";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Otvoriť DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatické dopĺňanie hesiel je aktivované!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "zariadenie";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Zrušiť";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Ak chcete získať prístup k heslám, odomknite zariadenie";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Adresa URL webových stránok";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopírovať %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adresa bola skopírovaná";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Poznámky boli skopírované";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Heslo bolo skopírované";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Meno používateľa bolo skopírované";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Skryť heslo";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Naposledy aktualizované %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Názov";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Poznámky";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Heslo";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Zobraziť heslo";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Používateľské meno";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Heslá sú bezpečne uložené vo vašom zariadení.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Zatiaľ nie sú uložené žiadne heslá";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Vyber si heslo, ktoré chceš použiť pre „%@“";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Vyhľadávanie hesiel";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "pre „%@”";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Žiadne výsledky";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Navrhované";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Heslo";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Nastav prístupový kód na %@ na automatické vypĺňanie tvojich hesiel DuckDuckGo.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Vyžaduje sa prístupový kód zariadenia.";
+
diff --git a/AutofillCredentialProvider/sl.lproj/InfoPlist.strings b/AutofillCredentialProvider/sl.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/sl.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/sl.lproj/Localizable.strings b/AutofillCredentialProvider/sl.lproj/Localizable.strings
new file mode 100644
index 0000000000..2ccec47f15
--- /dev/null
+++ b/AutofillCredentialProvider/sl.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Zapri";
+
+/* Done button title */
+"action.button.done" = "Končano";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Odpri DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Samodejno izpolnjevanje gesel je aktivirano.";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "naprava";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Prekliči";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Če želite dostopati do gesel, odklenite napravo";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "URL spletnega mesta";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopiraj %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Naslov je bil kopiran";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Opombe so kopirane";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Geslo je bilo kopirano";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Uporabniško ime je bilo kopirano";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Skrij geslo";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Zadnja posodobitev %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Naslov";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Opombe";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Geslo";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Prikaži geslo";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Uporabniško ime";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Gesla so varno shranjena v vaši napravi.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Nobeno geslo še ni shranjeno";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Izberite geslo za »%@«";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Iskanje gesel";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "za »%@«";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Ni rezultatov";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Predlagano";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Gesla";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Za samodejno izpolnjevanje gesel DuckDuckGo nastavite kodo za dostop v svoji napravi (%@).";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Zahtevana je koda za dostop do naprave";
+
diff --git a/AutofillCredentialProvider/sv.lproj/InfoPlist.strings b/AutofillCredentialProvider/sv.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/sv.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/sv.lproj/Localizable.strings b/AutofillCredentialProvider/sv.lproj/Localizable.strings
new file mode 100644
index 0000000000..04f1b6425c
--- /dev/null
+++ b/AutofillCredentialProvider/sv.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Stäng";
+
+/* Done button title */
+"action.button.done" = "Klart";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "Öppna DuckDuckGo";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Automatisk ifyllning av lösenord har aktiverats!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "enhet";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "Avbryt";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Lås upp enheten för att komma åt lösenord";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Webbplats-URL";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "Kopiera %@";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adress kopierad";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Anteckningar kopierade";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Lösenord kopierat";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Användarnamn kopierat";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Dölj lösenord";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Uppdaterades senast %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Rubrik";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Anteckningar";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Lösenord";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Visa lösenord";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Användarnamn";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Lösenord lagras säkert på din enhet.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Inga lösenord sparade ännu";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "Välj ett lösenord att använda för %@";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Sök lösenord";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "för ”%@”";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Inga resultat";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Förslag";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Lösenord";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "Ställ in en lösenkod på %@ för att automatiskt fylla i dina DuckDuckGo-lösenord.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Enhetens lösenkod krävs";
+
diff --git a/AutofillCredentialProvider/tr.lproj/InfoPlist.strings b/AutofillCredentialProvider/tr.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..9809aa19f5
--- /dev/null
+++ b/AutofillCredentialProvider/tr.lproj/InfoPlist.strings
@@ -0,0 +1,9 @@
+/* Bundle display name */
+"CFBundleDisplayName" = "AutofillCredentialProvider";
+
+/* Bundle name */
+"CFBundleName" = "AutofillCredentialProvider";
+
+/* Copyright (human-readable) */
+"NSHumanReadableCopyright" = "Copyright © 2024 DuckDuckGo. All rights reserved.";
+
diff --git a/AutofillCredentialProvider/tr.lproj/Localizable.strings b/AutofillCredentialProvider/tr.lproj/Localizable.strings
new file mode 100644
index 0000000000..1bf39ce8dc
--- /dev/null
+++ b/AutofillCredentialProvider/tr.lproj/Localizable.strings
@@ -0,0 +1,96 @@
+/* Close button title */
+"action.button.close" = "Kapat";
+
+/* Done button title */
+"action.button.done" = "Bitti";
+
+/* Title of button to launch the DuckDuckGo app */
+"credential.provider.activated.button" = "DuckDuckGo'yu aç";
+
+/* The title of the screen confirming DuckDuckGo can now be used for autofilling passwords */
+"credential.provider.activated.title" = "Şifreleri otomatik doldurma etkinleştirildi!";
+
+/* Default string used if users device is not iPhone or iPad */
+"credential.provider.device.type.default" = "cihaz";
+
+/* Device type is iPhone */
+"credential.provider.device.type.iphone" = "iPhone";
+
+/* Device type is iPad */
+"credential.provider.device.type.pad" = "iPad";
+
+/* Cancel button for auth when opening login list */
+"credential.provider.list.auth.cancel" = "İptal";
+
+/* Reason for auth when opening screen with list of saved passwords */
+"credential.provider.list.auth.reason" = "Şifrelere erişmek için cihazın kilidini açın";
+
+/* Address label for login details on autofill */
+"credential.provider.list.details.address" = "Web sitesi URL'si";
+
+/* Menu item text for copying autofill login details */
+"credential.provider.list.details.copy-prompt" = "%@ Ögesini Kopyala";
+
+/* Title for toast when copying address */
+"credential.provider.list.details.copy-toast.address-copied" = "Adres kopyalandı";
+
+/* Title for toast when copying notes */
+"credential.provider.list.details.copy-toast.notes-copied" = "Notlar kopyalandı";
+
+/* Title for toast when copying password */
+"credential.provider.list.details.copy-toast.password-copied" = "Şifre kopyalandı";
+
+/* Title for toast when copying username */
+"credential.provider.list.details.copy-toast.username-copied" = "Kullanıcı adı kopyalandı";
+
+/* Accessibility title for a Hide Password button replacing displayed password with ***** */
+"credential.provider.list.details.hide-password" = "Parolayı gizle";
+
+/* Message displaying when the login was last updated */
+"credential.provider.list.details.last-updated" = "Son güncelleme %@";
+
+/* Login name label for login details on autofill */
+"credential.provider.list.details.login-name" = "Title";
+
+/* Notes label for login details on autofill */
+"credential.provider.list.details.notes" = "Notlar";
+
+/* Password label for login details on autofill */
+"credential.provider.list.details.password" = "Parola";
+
+/* Accessibility title for a Show Password button displaying actial password instead of ***** */
+"credential.provider.list.details.show-password" = "Parolayı göster";
+
+/* Username label for login details on autofill */
+"credential.provider.list.details.username" = "Kullanıcı adı";
+
+/* Footer label displayed below table section with option to enable autofill */
+"credential.provider.list.empty-view.footer" = "Şifreler cihazınızda güvenli bir şekilde saklanır.";
+
+/* Title for view displayed when autofill has no items */
+"credential.provider.list.empty-view.title" = "Henüz şifre kaydedilmedi";
+
+/* Prompt above the title for screen listing autofill logins, example: Choose a password to use for "website.com" */
+"credential.provider.list.prompt" = "\"%@\" için kullanılacak bir şifre seçin";
+
+/* Placeholder for search field on autofill login listing */
+"credential.provider.list.search-placeholder" = "Şifreleri ara";
+
+/* Subtitle displayed when there are no results on Autofill search, example : No Result (Title) for Duck (Subtitle) */
+"credential.provider.list.search.no-results.subtitle" = "\"%@\" için";
+
+/* Title displayed when there are no results on Autofill search */
+"credential.provider.list.search.no-results.title" = "Sonuç yok";
+
+/* Section title for group of suggested saved logins */
+"credential.provider.list.suggested" = "Önerilen";
+
+/* Title for screen listing autofill logins */
+"credential.provider.list.title" = "Şifreler";
+
+/* Message for alert when device authentication is not set, where %@ is iPhone|iPad|device */
+"credential.provider.no-device-auth-set.message" = "DuckDuckGo şifrelerinizi otomatik olarak doldurmak için %@ üzerinde bir parola belirleyin.";
+
+/* Title for alert when device authentication is not set */
+"credential.provider.no-device-auth-set.title" = "Cihaz Parolası Gerekli";
+
diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig
index 2f435d72f7..9ef4c72f39 100644
--- a/Configuration/Version.xcconfig
+++ b/Configuration/Version.xcconfig
@@ -1 +1 @@
-MARKETING_VERSION = 7.148.0
+MARKETING_VERSION = 7.149.0
diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift
index 3d1a36860f..538a5c786b 100644
--- a/Core/AppPrivacyConfigurationDataProvider.swift
+++ b/Core/AppPrivacyConfigurationDataProvider.swift
@@ -23,8 +23,8 @@ import BrowserServicesKit
final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider {
public struct Constants {
- public static let embeddedDataETag = "\"a913df909743eadb5bd381c7fddf4902\""
- public static let embeddedDataSHA = "d1fb789ab4def06b6cf359d5e9971c840668ab5307f5690bc1483bb2266a2558"
+ public static let embeddedDataETag = "\"5e5dc1c97834210a4803eb2683f21f95\""
+ public static let embeddedDataSHA = "758a4d35540518b71b74ef7769a1652d124b75c12dd244fe7612b829c824d510"
}
public var embeddedDataEtag: String {
diff --git a/Core/AppTrackerDataSetProvider.swift b/Core/AppTrackerDataSetProvider.swift
index 1ad2d9fb89..4e73164f0a 100644
--- a/Core/AppTrackerDataSetProvider.swift
+++ b/Core/AppTrackerDataSetProvider.swift
@@ -23,8 +23,8 @@ import BrowserServicesKit
final public class AppTrackerDataSetProvider: EmbeddedDataProvider {
public struct Constants {
- public static let embeddedDataETag = "\"7af63a1c5812c9200d3120f5dd598993\""
- public static let embeddedDataSHA = "ef3eb8b998faa201192a190cff3fe0fc228cf2212be44271036dbd63ade5ddcf"
+ public static let embeddedDataETag = "\"382541021cbc55b218714db779561a51\""
+ public static let embeddedDataSHA = "5e8293a4c3e3ea5217e8e39db0c8525de4647ec78b102cff292ab5fa213578aa"
}
public var embeddedDataEtag: String {
diff --git a/DuckDuckGo/AutofillInterfaceEmailTruncator.swift b/Core/AutofillInterfaceEmailTruncator.swift
similarity index 91%
rename from DuckDuckGo/AutofillInterfaceEmailTruncator.swift
rename to Core/AutofillInterfaceEmailTruncator.swift
index 2eb28faa1b..41fb28342c 100644
--- a/DuckDuckGo/AutofillInterfaceEmailTruncator.swift
+++ b/Core/AutofillInterfaceEmailTruncator.swift
@@ -19,8 +19,8 @@
import Foundation
-struct AutofillInterfaceEmailTruncator {
- static func truncateEmail(_ email: String, maxLength: Int) -> String {
+public struct AutofillInterfaceEmailTruncator {
+ public static func truncateEmail(_ email: String, maxLength: Int) -> String {
let emailComponents = email.components(separatedBy: "@")
if emailComponents.count > 1 && email.count > maxLength {
let ellipsis = "..."
diff --git a/DuckDuckGo/PasswordHider.swift b/Core/PasswordHider.swift
similarity index 83%
rename from DuckDuckGo/PasswordHider.swift
rename to Core/PasswordHider.swift
index 1849248f24..ffe3a70929 100644
--- a/DuckDuckGo/PasswordHider.swift
+++ b/Core/PasswordHider.swift
@@ -19,11 +19,15 @@
import Foundation
-struct PasswordHider {
- let password: String
- var hiddenPassword: String {
+public struct PasswordHider {
+ public let password: String
+ public var hiddenPassword: String {
let maximumPasswordDisplayCount = 22
let passwordCount = password.count > maximumPasswordDisplayCount ? maximumPasswordDisplayCount : password.count
return String(repeating: "•", count: passwordCount)
}
+
+ public init(password: String) {
+ self.password = password
+ }
}
diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift
index 4c9d909115..29eadee0f7 100644
--- a/Core/PixelEvent.swift
+++ b/Core/PixelEvent.swift
@@ -312,6 +312,8 @@ extension Pixel {
case autofillOnboardedUser
case autofillToggledOn
case autofillToggledOff
+ case autofillExtensionToggledOn
+ case autofillExtensionToggledOff
case autofillLoginsStacked
case autofillManagementOpened
@@ -332,7 +334,18 @@ extension Pixel {
case getDesktopCopy
case getDesktopShare
-
+
+ case autofillExtensionEnabled
+ case autofillExtensionDisabled
+ case autofillExtensionWelcomeDismiss
+ case autofillExtensionWelcomeLaunchApp
+ case autofillExtensionQuickTypeConfirmed
+ case autofillExtensionQuickTypeCancelled
+ case autofillExtensionPasswordsOpened
+ case autofillExtensionPasswordsDismissed
+ case autofillExtensionPasswordSelected
+ case autofillExtensionPasswordsSearch
+
case autofillJSPixelFired(_ pixel: AutofillUserScript.JSPixel)
case secureVaultError
@@ -1203,6 +1216,8 @@ extension Pixel.Event {
case .autofillOnboardedUser: return "m_autofill_onboardeduser"
case .autofillToggledOn: return "m_autofill_toggled_on"
case .autofillToggledOff: return "m_autofill_toggled_off"
+ case .autofillExtensionToggledOn: return "m_autofill_extension_toggled_on"
+ case .autofillExtensionToggledOff: return "m_autofill_extension_toggled_off"
case .autofillLoginsStacked: return "m_autofill_logins_stacked"
@@ -1232,6 +1247,18 @@ extension Pixel.Event {
case .getDesktopCopy: return "m_get_desktop_copy"
case .getDesktopShare: return "m_get_desktop_share"
+ // Autofill Credential Provider Extension
+ case .autofillExtensionEnabled: return "autofill_extension_enabled"
+ case .autofillExtensionDisabled: return "autofill_extension_disabled"
+ case .autofillExtensionWelcomeDismiss: return "autofill_extension_welcome_dismiss"
+ case .autofillExtensionWelcomeLaunchApp: return "autofill_extension_welcome_launch_app"
+ case .autofillExtensionQuickTypeConfirmed: return "autofill_extension_quicktype_confirmed"
+ case .autofillExtensionQuickTypeCancelled: return "autofill_extension_quicktype_cancelled"
+ case .autofillExtensionPasswordsOpened: return "autofill_extension_passwords_opened"
+ case .autofillExtensionPasswordsDismissed: return "autofill_extension_passwords_dismissed"
+ case .autofillExtensionPasswordSelected: return "autofill_extension_password_selected"
+ case .autofillExtensionPasswordsSearch: return "autofill_extension_passwords_search"
+
case .autofillJSPixelFired(let pixel):
return "m_ios_\(pixel.pixelName)"
diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift
index 4858ad964d..4b0b9682ab 100644
--- a/Core/UserDefaultsPropertyWrapper.swift
+++ b/Core/UserDefaultsPropertyWrapper.swift
@@ -95,6 +95,7 @@ public struct UserDefaultsWrapper {
case autofillFillDate = "com.duckduckgo.app.autofill.FillDate"
case autofillOnboardedUser = "com.duckduckgo.app.autofill.OnboardedUser"
case autofillSurveysCompleted = "com.duckduckgo.app.autofill.SurveysCompleted"
+ case autofillExtensionEnabled = "com.duckduckgo.app.autofill.ExtensionEnabled"
case syncPromoBookmarksDismissed = "com.duckduckgo.app.sync.PromoBookmarksDismissed"
case syncPromoPasswordsDismissed = "com.duckduckgo.app.sync.PromoPasswordsDismissed"
diff --git a/Core/ios-config.json b/Core/ios-config.json
index 188f9299e7..2263fb2097 100644
--- a/Core/ios-config.json
+++ b/Core/ios-config.json
@@ -1,6 +1,6 @@
{
"readme": "https://github.com/duckduckgo/privacy-configuration",
- "version": 1733157661102,
+ "version": 1733826965137,
"features": {
"adAttributionReporting": {
"state": "disabled",
@@ -75,20 +75,20 @@
"hash": "c292bb627849854515cebbded288ef5a"
},
"aiChat": {
- "state": "enabled",
+ "state": "disabled",
"exceptions": [],
"features": {
"browsingToolbarShortcut": {
- "state": "enabled"
+ "state": "disabled"
},
"addressBarShortcut": {
- "state": "enabled"
+ "state": "disabled"
}
},
"settings": {
"aiChatURL": "https://duckduckgo.com/?q=DuckDuckGo+AI+Chat&ia=chat&duckai=4"
},
- "hash": "14908e76cd3a8b4919e03003fd201300"
+ "hash": "4b5209f8cbe489299641ea30ed9a2542"
},
"ampLinks": {
"exceptions": [
@@ -116,6 +116,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -144,7 +147,7 @@
]
},
"state": "enabled",
- "hash": "fa5f86bac5946c528cd6bc7449a2718a"
+ "hash": "2e91c1024751b208d974721cd5c4a020"
},
"androidBrowserConfig": {
"exceptions": [],
@@ -156,6 +159,14 @@
"state": "disabled",
"hash": "728493ef7a1488e4781656d3f9db84aa"
},
+ "auraExperiment": {
+ "exceptions": [],
+ "settings": {
+ "packages": []
+ },
+ "state": "disabled",
+ "hash": "527fd2e156c7669f001516ee2d3d7c0e"
+ },
"autocompleteTabs": {
"state": "enabled",
"exceptions": [],
@@ -601,6 +612,201 @@
{
"domain": "outlet46.de"
},
+ {
+ "domain": "mytolino.de"
+ },
+ {
+ "domain": "google.ae"
+ },
+ {
+ "domain": "google.at"
+ },
+ {
+ "domain": "google.be"
+ },
+ {
+ "domain": "google.bg"
+ },
+ {
+ "domain": "google.by"
+ },
+ {
+ "domain": "google.ca"
+ },
+ {
+ "domain": "google.ch"
+ },
+ {
+ "domain": "google.cl"
+ },
+ {
+ "domain": "google.co.id"
+ },
+ {
+ "domain": "google.co.il"
+ },
+ {
+ "domain": "google.co.in"
+ },
+ {
+ "domain": "google.co.jp"
+ },
+ {
+ "domain": "google.co.ke"
+ },
+ {
+ "domain": "google.co.kr"
+ },
+ {
+ "domain": "google.co.nz"
+ },
+ {
+ "domain": "google.co.th"
+ },
+ {
+ "domain": "google.co.uk"
+ },
+ {
+ "domain": "google.co.ve"
+ },
+ {
+ "domain": "google.co.za"
+ },
+ {
+ "domain": "google.com"
+ },
+ {
+ "domain": "google.com.ar"
+ },
+ {
+ "domain": "google.com.au"
+ },
+ {
+ "domain": "google.com.br"
+ },
+ {
+ "domain": "google.com.co"
+ },
+ {
+ "domain": "google.com.ec"
+ },
+ {
+ "domain": "google.com.eg"
+ },
+ {
+ "domain": "google.com.hk"
+ },
+ {
+ "domain": "google.com.mx"
+ },
+ {
+ "domain": "google.com.my"
+ },
+ {
+ "domain": "google.com.pe"
+ },
+ {
+ "domain": "google.com.ph"
+ },
+ {
+ "domain": "google.com.pk"
+ },
+ {
+ "domain": "google.com.py"
+ },
+ {
+ "domain": "google.com.sa"
+ },
+ {
+ "domain": "google.com.sg"
+ },
+ {
+ "domain": "google.com.tr"
+ },
+ {
+ "domain": "google.com.tw"
+ },
+ {
+ "domain": "google.com.ua"
+ },
+ {
+ "domain": "google.com.uy"
+ },
+ {
+ "domain": "google.com.vn"
+ },
+ {
+ "domain": "google.cz"
+ },
+ {
+ "domain": "google.de"
+ },
+ {
+ "domain": "google.dk"
+ },
+ {
+ "domain": "google.dz"
+ },
+ {
+ "domain": "google.ee"
+ },
+ {
+ "domain": "google.es"
+ },
+ {
+ "domain": "google.fi"
+ },
+ {
+ "domain": "google.fr"
+ },
+ {
+ "domain": "google.gr"
+ },
+ {
+ "domain": "google.hr"
+ },
+ {
+ "domain": "google.hu"
+ },
+ {
+ "domain": "google.ie"
+ },
+ {
+ "domain": "google.it"
+ },
+ {
+ "domain": "google.lt"
+ },
+ {
+ "domain": "google.lv"
+ },
+ {
+ "domain": "google.nl"
+ },
+ {
+ "domain": "google.no"
+ },
+ {
+ "domain": "google.pl"
+ },
+ {
+ "domain": "google.pt"
+ },
+ {
+ "domain": "google.ro"
+ },
+ {
+ "domain": "google.rs"
+ },
+ {
+ "domain": "google.ru"
+ },
+ {
+ "domain": "google.se"
+ },
+ {
+ "domain": "google.sk"
+ },
{
"domain": "marvel.com"
},
@@ -613,6 +819,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -643,7 +852,7 @@
}
}
},
- "hash": "2c73b04e22812bf92bc2a859e7540c3a"
+ "hash": "32cbf1af6d2dd1ef9c61bb3cc34852dd"
},
"autofillBreakageReporter": {
"state": "enabled",
@@ -656,10 +865,15 @@
"autofillSurveys": {
"state": "enabled",
"settings": {
- "surveys": []
+ "surveys": [
+ {
+ "id": "2024-12-04",
+ "url": "https://selfserve.decipherinc.com/survey/selfserve/32ab/241201"
+ }
+ ]
},
"exceptions": [],
- "hash": "1d554e00b6a8adc2a7514accf9a92fdb"
+ "hash": "2f7e9f55c5dbcb35ee01be966b079512"
},
"autofill": {
"exceptions": [
@@ -724,9 +938,12 @@
}
]
}
+ },
+ "partialFormSaves": {
+ "state": "enabled"
}
},
- "hash": "28d4af98382248e184c4315bd49f4222"
+ "hash": "07b6b3bb0e6ddc4bf3dadbbbd0419478"
},
"backgroundAgentPixelTest": {
"state": "enabled",
@@ -776,11 +993,14 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
- "hash": "37e0cf88badfc8b01b6394f0884502f6"
+ "hash": "2b0962b6ea0b84b7450358766ccf667d"
},
"brokenSitePrompt": {
"state": "enabled",
@@ -1482,6 +1702,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -1501,7 +1724,7 @@
}
},
"state": "disabled",
- "hash": "cb1f114a9e0314393b2a0f789cba163f"
+ "hash": "9b33d212830c6b5b67317c0621b15006"
},
"clickToPlay": {
"exceptions": [
@@ -1517,6 +1740,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -1531,7 +1757,7 @@
}
},
"state": "disabled",
- "hash": "894fb86c1f058aee9db47cfcdf3637de"
+ "hash": "1533ba1f2ef66001f0e4d6faf0d48be7"
},
"clientBrandHint": {
"exceptions": [],
@@ -1574,11 +1800,14 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
- "hash": "96b2f778bab196aa424e9c859ddea778"
+ "hash": "ee5eabf360024d267d4668e73c053a48"
},
"contextualOnboarding": {
"exceptions": [],
@@ -1650,12 +1879,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "fce0a9ccd7ae060d25e7debe4d8905fb"
+ "hash": "91ceb18e840b0b322c2fd818e6b5453a"
},
"customUserAgent": {
"settings": {
@@ -1846,6 +2078,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -2791,7 +3026,7 @@
},
{
"selector": "[data-identity='billboard-ad']",
- "type": "hide-empty"
+ "type": "hide"
},
{
"selector": "[data-identity='leaderboard-ad']",
@@ -2994,6 +3229,23 @@
}
]
},
+ {
+ "domain": "e-chords.com",
+ "rules": [
+ {
+ "selector": ".adscifra",
+ "type": "hide"
+ },
+ {
+ "selector": ".banner",
+ "type": "hide-empty"
+ },
+ {
+ "selector": "#banner",
+ "type": "hide-empty"
+ }
+ ]
+ },
{
"domain": "ebay.com",
"rules": [
@@ -5210,7 +5462,7 @@
]
},
"state": "enabled",
- "hash": "16e64ea4c926bdf7c865a8b7cbde1b2b"
+ "hash": "a3957788141533420149b5c96c8de136"
},
"exceptionHandler": {
"exceptions": [
@@ -5226,12 +5478,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf"
+ "hash": "01c90bccc9b20770953ff3f786fa4dac"
},
"extendedOnboarding": {
"exceptions": [],
@@ -5256,11 +5511,14 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
- "hash": "7f042650922da2636492e77ed1101bce"
+ "hash": "0cc652d37e184686c92eb64e6ab9d3fa"
},
"fingerprintingBattery": {
"exceptions": [
@@ -5279,12 +5537,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "enabled",
- "hash": "fcc2138fa97c35ded544b39708fda919"
+ "hash": "3821c0fed8912dd05b1618e3a0594fcf"
},
"fingerprintingCanvas": {
"settings": {
@@ -5387,12 +5648,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "49a3d497835bf5715aaaa73f87dd974f"
+ "hash": "1165c91b6e289988a60b72a97d3a5a3b"
},
"fingerprintingHardware": {
"settings": {
@@ -5462,6 +5726,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "target.com"
},
@@ -5470,7 +5737,7 @@
}
],
"state": "enabled",
- "hash": "b1f406c6ff87e27244d26289c0e383f9"
+ "hash": "b1de304ce2c53c1fc1ef395c98296f8f"
},
"fingerprintingScreenSize": {
"settings": {
@@ -5522,12 +5789,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "enabled",
- "hash": "046340bb9287a20efed6189525ec5fed"
+ "hash": "7e7b65104a08a935f2263eb34b84d3cb"
},
"fingerprintingTemporaryStorage": {
"exceptions": [
@@ -5552,12 +5822,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "enabled",
- "hash": "14b7fe3d276b52109c59f0c71aee4f71"
+ "hash": "934f0960313eb7801841ee99cd3dc802"
},
"googleRejected": {
"exceptions": [
@@ -5573,12 +5846,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf"
+ "hash": "01c90bccc9b20770953ff3f786fa4dac"
},
"gpc": {
"state": "enabled",
@@ -5625,6 +5901,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -5638,7 +5917,7 @@
"privacy-test-pages.site"
]
},
- "hash": "501bbc6471eb079cb27fa8a2a47467a5"
+ "hash": "92dbff4d73bdec464f5767165933b0bf"
},
"harmfulApis": {
"settings": {
@@ -5752,12 +6031,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "fb598c4167ff166d85dd49c701cc5579"
+ "hash": "603b489064ac5a2379d18a946644e499"
},
"history": {
"state": "enabled",
@@ -5806,11 +6088,14 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
- "hash": "b47d255c6f836ecb7ae0b3e61cc2c025"
+ "hash": "a0a328c1f5189fabc27bd1659146c3a2"
},
"incontextSignup": {
"exceptions": [],
@@ -5838,11 +6123,6 @@
"exceptions": [],
"hash": "429cea8d27316dc62af04159ec7c42b5"
},
- "loadingBarExp": {
- "exceptions": [],
- "state": "disabled",
- "hash": "728493ef7a1488e4781656d3f9db84aa"
- },
"maliciousSiteProtection": {
"state": "internal",
"exceptions": [],
@@ -5885,6 +6165,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -5897,7 +6180,7 @@
]
},
"state": "enabled",
- "hash": "d14f6e3a9aa4139ee1d517016b59691e"
+ "hash": "ac148f97532e086f27bedc5b7f6fc4a2"
},
"networkProtection": {
"state": "enabled",
@@ -5945,12 +6228,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "82088db85ca7f64418fbfd57db25ade1"
+ "hash": "e3342b0dc61ba52c56a90f553b7bfc43"
},
"performanceMetrics": {
"state": "enabled",
@@ -5967,11 +6253,14 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
- "hash": "6792064606a5a72c5cd44addb4d40bda"
+ "hash": "04fb7d6e0337563a26060b1a32d2332e"
},
"phishingDetection": {
"state": "disabled",
@@ -6110,12 +6399,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "138c3b2409f6b3bf967b804ab9bf2ce2"
+ "hash": "359af23cc499c17b84ef08a118fedc4a"
},
"remoteMessaging": {
"state": "enabled",
@@ -6137,6 +6429,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
@@ -6144,7 +6439,7 @@
"settings": {
"windowInMs": 0
},
- "hash": "baf19d9e0f506ed09f46c95b1849adee"
+ "hash": "54b249ffdfd7710373849720c7bf1ed8"
},
"runtimeChecks": {
"state": "disabled",
@@ -6161,12 +6456,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"settings": {},
- "hash": "dfede9f06b9e322e198736703d013d15"
+ "hash": "c2c2d48b0fc1b03db53065ca5da92675"
},
"sendFullPackageInstallSource": {
"state": "enabled",
@@ -6188,12 +6486,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf"
+ "hash": "01c90bccc9b20770953ff3f786fa4dac"
},
"showOnAppLaunch": {
"exceptions": [
@@ -6209,12 +6510,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf"
+ "hash": "01c90bccc9b20770953ff3f786fa4dac"
},
"sslCertificates": {
"state": "enabled",
@@ -6240,12 +6544,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf"
+ "hash": "01c90bccc9b20770953ff3f786fa4dac"
},
"syncPromotion": {
"state": "enabled",
@@ -7154,6 +7461,7 @@
"itsthevibe.com",
"nytimes.com",
"realmadrid.com",
+ "repretel.com",
"rocketnews24.com",
"solitaired.com",
"stuff.co.nz",
@@ -7171,6 +7479,7 @@
{
"rule": "securepubads.g.doubleclick.net/pagead/ppub_config",
"domains": [
+ "repretel.com",
"rocketnews24.com",
"weather.com",
"wunderground.com"
@@ -9715,11 +10024,14 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
- "hash": "f5b235ed3c5c9afdd44edfa3464235cf"
+ "hash": "cc188a741d0bbe34cd7de16f70a69df7"
},
"trackingCookies1p": {
"settings": {
@@ -9741,12 +10053,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "763f56424b0827b5731927a043219912"
+ "hash": "2426b21363085484652b231ca66897a5"
},
"trackingCookies3p": {
"settings": {
@@ -9765,12 +10080,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "82088db85ca7f64418fbfd57db25ade1"
+ "hash": "e3342b0dc61ba52c56a90f553b7bfc43"
},
"trackingParameters": {
"exceptions": [
@@ -9801,6 +10119,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "theverge.com"
},
@@ -9838,7 +10159,7 @@
]
},
"state": "enabled",
- "hash": "3792a4970c07fe00da08f77e7dcf01ed"
+ "hash": "51753ddb14b1c7a22eb20f74f46c092d"
},
"userAgentRotation": {
"settings": {
@@ -9857,12 +10178,15 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "instructure.com"
}
],
"state": "disabled",
- "hash": "9225b8785d6973db37abde99d81d219c"
+ "hash": "fbc6687658b62b108ed7769a660dd8e0"
},
"voiceSearch": {
"exceptions": [],
@@ -9888,6 +10212,9 @@
{
"domain": "flexmls.com"
},
+ {
+ "domain": "asuracomic.net"
+ },
{
"domain": "wsj.com"
},
@@ -9965,7 +10292,7 @@
}
]
},
- "hash": "2853748f3ebb813d59f4db4a7bb13c83"
+ "hash": "39bd8f30c68f608ae78ffde4e13bef93"
},
"webViewBlobDownload": {
"exceptions": [],
@@ -10021,6 +10348,26 @@
"exceptions": [],
"state": "disabled",
"hash": "728493ef7a1488e4781656d3f9db84aa"
+ },
+ "experimentTest": {
+ "state": "enabled",
+ "exceptions": [],
+ "features": {
+ "experimentTestAA": {
+ "state": "enabled",
+ "cohorts": [
+ {
+ "name": "control",
+ "weight": 1
+ },
+ {
+ "name": "treatment",
+ "weight": 1
+ }
+ ]
+ }
+ },
+ "hash": "0fe5af5a94e036bf5d78076df6dd771b"
}
},
"unprotectedTemporary": []
diff --git a/Core/trackerData.json b/Core/trackerData.json
index b2123dd778..f09798f0e6 100644
--- a/Core/trackerData.json
+++ b/Core/trackerData.json
@@ -1,6 +1,6 @@
{
"_builtWith": {
- "tracker-radar": "e270978af9ffd0c909a62969df5f894128d41682920fb7a4c913e25e9ab1ecef-4013b4e91930c643394cb31c6c745356f133b04f",
+ "tracker-radar": "1108f03ca047465b2b8d8ab3385ba2cd4f21e1d0111571f8342b3eb0735b1c4a-4013b4e91930c643394cb31c6c745356f133b04f",
"tracker-surrogates": "fe15c53e755af1257774459ecf066f673f485cb0"
},
"readme": "https://github.com/duckduckgo/tracker-blocklists",
@@ -6604,44 +6604,7 @@
"fingerprinting": 2,
"cookies": 0.00112,
"categories": [],
- "default": "ignore",
- "rules": [
- {
- "rule": "coveo\\.com\\/coveo\\.analytics\\.js\\/2\\/coveoua\\.js",
- "fingerprinting": 2,
- "cookies": 0.000163
- },
- {
- "rule": "coveo\\.com\\/coveo\\.analytics\\.js\\/1\\.0\\/coveoua\\.js",
- "fingerprinting": 2,
- "cookies": 0.0000613
- },
- {
- "rule": "coveo\\.com\\/coveo\\.analytics\\.js\\/coveoua\\.js",
- "fingerprinting": 1,
- "cookies": 0.0000681
- },
- {
- "rule": "coveo\\.com\\/coveo\\.analytics\\.js\\/latest\\/coveoua\\.js",
- "fingerprinting": 1,
- "cookies": 0.0000204
- },
- {
- "rule": "coveo\\.com\\/atomic\\/v1\\.110\\/p-f4cb35d7\\.js",
- "fingerprinting": 2,
- "cookies": 0.0000136
- },
- {
- "rule": "coveo\\.com\\/atomic\\/v1\\/p-217d4a01\\.js",
- "fingerprinting": 2,
- "cookies": 0
- },
- {
- "rule": "coveo\\.com\\/coveo\\.analytics\\.js\\/2\\/coveoua\\.browser\\.js",
- "fingerprinting": 2,
- "cookies": 0.0000136
- }
- ]
+ "default": "ignore"
},
"cpmstar.com": {
"domain": "cpmstar.com",
@@ -8652,14 +8615,7 @@
"fingerprinting": 2,
"cookies": 0.00114,
"categories": [],
- "default": "ignore",
- "rules": [
- {
- "rule": "elfsight\\.com\\/apps\\/social-share-buttons\\/release\\/bcbd1ca01fc572c7bc650c98dbe032152aa706f5\\/app\\/socialShareButtons\\.js",
- "fingerprinting": 3,
- "cookies": 0
- }
- ]
+ "default": "ignore"
},
"elitrack.com": {
"domain": "elitrack.com",
@@ -13283,7 +13239,27 @@
"default": "ignore",
"rules": [
{
- "rule": "impervadns\\.net//SP2013v1/Enterprise/JS/",
+ "rule": "impervadns\\.net\\/\\/SP2013v1\\/Enterprise\\/JS\\/foundation\\.min\\.js",
+ "fingerprinting": 1,
+ "cookies": 0.000136
+ },
+ {
+ "rule": "impervadns\\.net\\/\\/SP2013v1\\/Enterprise\\/JS\\/enterprise\\.min\\.js",
+ "fingerprinting": 1,
+ "cookies": 0.000136
+ },
+ {
+ "rule": "impervadns\\.net\\/\\/SP2013v1\\/Enterprise\\/JS\\/jquery\\.cookie\\.js",
+ "fingerprinting": 1,
+ "cookies": 0.000136
+ },
+ {
+ "rule": "impervadns\\.net\\/\\/SP2013v1\\/Enterprise\\/JS\\/knockout\\.min\\.js",
+ "fingerprinting": 1,
+ "cookies": 0.000136
+ },
+ {
+ "rule": "impervadns\\.net\\/\\/SP2013v1\\/Enterprise\\/JS\\/jquery-ui\\.js",
"fingerprinting": 1,
"cookies": 0.000136
},
@@ -15753,30 +15729,9 @@
{
"rule": "listrakbi\\.com/v1/Product"
},
- {
- "rule": "listrakbi\\.com/json/07c34100-1080-4c55-9097-05c7f4a2b19b"
- },
- {
- "rule": "listrakbi\\.com/json/f5f04466-f923-491d-9354-679d54e32def"
- },
- {
- "rule": "listrakbi\\.com/json/eb9d26f3-d7e9-4df8-9800-a79cfaf345be"
- },
{
"rule": "listrakbi\\.com/SadvKLqKgI5T/cart/update"
},
- {
- "rule": "listrakbi\\.com/json/a6c8a6f0-379f-4e0e-8f1a-db4e3efa6123"
- },
- {
- "rule": "listrakbi\\.com/json/86d9476c-c670-4b5d-a33c-bca65c91576f"
- },
- {
- "rule": "listrakbi\\.com/json/043b15b6-cb62-4e61-9d8a-89856bdbf496"
- },
- {
- "rule": "listrakbi\\.com/json/9902c090-0d30-4673-b94b-3851cb8d6035"
- },
{
"rule": "listrakbi\\.com/RmR1Kqh2AYPr/cart/update"
},
@@ -15797,6 +15752,9 @@
},
{
"rule": "listrakbi\\.com/[a-zA-Z0-9]+\\.js"
+ },
+ {
+ "rule": "listrakbi\\.com/json/.*"
}
]
},
@@ -21827,18 +21785,6 @@
{
"rule": "qualtrics\\.com/WRSiteInterceptEngine/"
},
- {
- "rule": "qualtrics\\.com/WRQualtricsShared/Graphics/siteintercept/wr-dialog-close-btn-black\\.png"
- },
- {
- "rule": "qualtrics\\.com/WRQualtricsShared/Graphics/siteintercept/wr-dialog-close-btn-white\\.png"
- },
- {
- "rule": "qualtrics\\.com/WRQualtricsShared/Graphics/siteintercept/building_preview\\.gif"
- },
- {
- "rule": "qualtrics\\.com/WRQualtricsShared/Graphics/siteintercept/remove_screen_capture\\.png"
- },
{
"rule": "qualtrics\\.com/static/prototype-ui-modules/SharedGraphics/siteintercept/svg-close-btn-black-7\\.svg"
},
@@ -21854,12 +21800,6 @@
{
"rule": "qualtrics\\.com/static/prototype-ui-modules/SharedGraphics/siteintercept/svg-close-btn-black-4\\.svg"
},
- {
- "rule": "qualtrics\\.com/WRQualtricsShared/Graphics/siteintercept/popup_shadow_transparent\\.png"
- },
- {
- "rule": "qualtrics\\.com/WRQualtricsShared/Graphics/siteintercept/feedback-blue-right\\.png"
- },
{
"rule": "qualtrics\\.com/ControlPanel/Graphic\\.php"
},
@@ -21874,6 +21814,9 @@
},
{
"rule": "qualtrics\\.com/static/q-siteintercept/"
+ },
+ {
+ "rule": "qualtrics\\.com/WRQualtricsShared/"
}
]
},
@@ -22243,6 +22186,18 @@
"cookies": 0.01,
"default": "block"
},
+ "rebuyengine.com": {
+ "domain": "rebuyengine.com",
+ "owner": {
+ "name": "rebuyengine.com",
+ "displayName": "rebuyengine.com"
+ },
+ "prevalence": 0.00142,
+ "fingerprinting": 2,
+ "cookies": 0.00125,
+ "categories": [],
+ "default": "ignore"
+ },
"reconditerake.com": {
"domain": "reconditerake.com",
"owner": {
@@ -26891,30 +26846,12 @@
"categories": [],
"default": "ignore",
"rules": [
- {
- "rule": "tiktok\\.com/i18n/pixel/events\\.js"
- },
- {
- "rule": "tiktok\\.com/i18n/pixel/static/identify_d1af3\\.js"
- },
{
"rule": "tiktok\\.com/api/v2/pixel"
},
- {
- "rule": "tiktok\\.com/i18n/pixel/sdk\\.js"
- },
{
"rule": "tiktok\\.com/api/v2/performance_interaction"
},
- {
- "rule": "tiktok\\.com/i18n/pixel/config\\.js"
- },
- {
- "rule": "tiktok\\.com/i18n/pixel/disable_cookie"
- },
- {
- "rule": "tiktok\\.com/i18n/pixel/static/identify_821f6\\.js"
- },
{
"rule": "tiktok\\.com/v1/user/webid"
},
@@ -26934,13 +26871,7 @@
"rule": "tiktok\\.com/oembed"
},
{
- "rule": "tiktok\\.com/i18n/pixel/enable_cookie"
- },
- {
- "rule": "tiktok\\.com/i18n/pixel/static/identify_a7248\\.js"
- },
- {
- "rule": "tiktok\\.com/i18n/pixel/static/main\\..*\\.js"
+ "rule": "tiktok\\.com/i18n/pixel/"
}
]
},
@@ -32665,17 +32596,6 @@
"cookies": 0.01,
"default": "block"
},
- "acceptableauthority.com": {
- "domain": "acceptableauthority.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (acceptableauthority.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"accountsdoor.com": {
"domain": "accountsdoor.com",
"owner": {
@@ -32951,17 +32871,6 @@
"cookies": 0.01,
"default": "block"
},
- "alertarithmetic.com": {
- "domain": "alertarithmetic.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (alertarithmetic.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"aliasanvil.com": {
"domain": "aliasanvil.com",
"owner": {
@@ -35107,17 +35016,6 @@
"cookies": 0.01,
"default": "block"
},
- "concernedchange.com": {
- "domain": "concernedchange.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (concernedchange.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"concernedchickens.com": {
"domain": "concernedchickens.com",
"owner": {
@@ -37516,17 +37414,6 @@
"cookies": 0.01,
"default": "block"
},
- "fertilefeeling.com": {
- "domain": "fertilefeeling.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (fertilefeeling.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"fewjuice.com": {
"domain": "fewjuice.com",
"owner": {
@@ -38913,17 +38800,6 @@
"cookies": 0.01,
"default": "block"
},
- "hatefulrequest.com": {
- "domain": "hatefulrequest.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (hatefulrequest.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"headydegree.com": {
"domain": "headydegree.com",
"owner": {
@@ -41454,17 +41330,6 @@
"cookies": 0.01,
"default": "block"
},
- "numberlessring.com": {
- "domain": "numberlessring.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (numberlessring.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"numerousnest.com": {
"domain": "numerousnest.com",
"owner": {
@@ -42928,6 +42793,17 @@
"cookies": 0.01,
"default": "block"
},
+ "razzweb.com": {
+ "domain": "razzweb.com",
+ "owner": {
+ "name": "Leven Labs, Inc. DBA Admiral (razzweb.com)",
+ "displayName": "Admiral"
+ },
+ "prevalence": 0.0107,
+ "fingerprinting": 1,
+ "cookies": 0.01,
+ "default": "block"
+ },
"reactjspdf.com": {
"domain": "reactjspdf.com",
"owner": {
@@ -43082,17 +42958,6 @@
"cookies": 0.01,
"default": "block"
},
- "reflectivestatement.com": {
- "domain": "reflectivestatement.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (reflectivestatement.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"refundradar.com": {
"domain": "refundradar.com",
"owner": {
@@ -43500,6 +43365,17 @@
"cookies": 0.01,
"default": "block"
},
+ "sableshelf.com": {
+ "domain": "sableshelf.com",
+ "owner": {
+ "name": "Leven Labs, Inc. DBA Admiral (sableshelf.com)",
+ "displayName": "Admiral"
+ },
+ "prevalence": 0.0107,
+ "fingerprinting": 1,
+ "cookies": 0.01,
+ "default": "block"
+ },
"sablesmile.com": {
"domain": "sablesmile.com",
"owner": {
@@ -43588,6 +43464,17 @@
"cookies": 0.01,
"default": "block"
},
+ "samuraibots.com": {
+ "domain": "samuraibots.com",
+ "owner": {
+ "name": "Leven Labs, Inc. DBA Admiral (samuraibots.com)",
+ "displayName": "Admiral"
+ },
+ "prevalence": 0.0107,
+ "fingerprinting": 1,
+ "cookies": 0.01,
+ "default": "block"
+ },
"sandstrophies.com": {
"domain": "sandstrophies.com",
"owner": {
@@ -43841,17 +43728,6 @@
"cookies": 0.01,
"default": "block"
},
- "scribbleson.com": {
- "domain": "scribbleson.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (scribbleson.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"scrollservice.com": {
"domain": "scrollservice.com",
"owner": {
@@ -43940,17 +43816,6 @@
"cookies": 0.01,
"default": "block"
},
- "seemlysuggestion.com": {
- "domain": "seemlysuggestion.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (seemlysuggestion.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"selfishsea.com": {
"domain": "selfishsea.com",
"owner": {
@@ -44171,6 +44036,17 @@
"cookies": 0.01,
"default": "block"
},
+ "shallowart.com": {
+ "domain": "shallowart.com",
+ "owner": {
+ "name": "Leven Labs, Inc. DBA Admiral (shallowart.com)",
+ "displayName": "Admiral"
+ },
+ "prevalence": 0.0107,
+ "fingerprinting": 1,
+ "cookies": 0.01,
+ "default": "block"
+ },
"shallowblade.com": {
"domain": "shallowblade.com",
"owner": {
@@ -44402,17 +44278,6 @@
"cookies": 0.01,
"default": "block"
},
- "sinkbooks.com": {
- "domain": "sinkbooks.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (sinkbooks.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"sixscissors.com": {
"domain": "sixscissors.com",
"owner": {
@@ -45293,17 +45158,6 @@
"cookies": 0.01,
"default": "block"
},
- "steepscale.com": {
- "domain": "steepscale.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (steepscale.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"steepsister.com": {
"domain": "steepsister.com",
"owner": {
@@ -45491,17 +45345,6 @@
"cookies": 0.01,
"default": "block"
},
- "strangersponge.com": {
- "domain": "strangersponge.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (strangersponge.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"strangesink.com": {
"domain": "strangesink.com",
"owner": {
@@ -45678,17 +45521,6 @@
"cookies": 0.01,
"default": "block"
},
- "sugarfriction.com": {
- "domain": "sugarfriction.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (sugarfriction.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"suggestionbridge.com": {
"domain": "suggestionbridge.com",
"owner": {
@@ -45777,17 +45609,6 @@
"cookies": 0.01,
"default": "block"
},
- "swelteringsleep.com": {
- "domain": "swelteringsleep.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (swelteringsleep.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"swimfreely.com": {
"domain": "swimfreely.com",
"owner": {
@@ -45942,17 +45763,6 @@
"cookies": 0.01,
"default": "block"
},
- "tastelesstrucks.com": {
- "domain": "tastelesstrucks.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (tastelesstrucks.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"tastesnake.com": {
"domain": "tastesnake.com",
"owner": {
@@ -47251,17 +47061,6 @@
"cookies": 0.01,
"default": "block"
},
- "voicelessvein.com": {
- "domain": "voicelessvein.com",
- "owner": {
- "name": "Leven Labs, Inc. DBA Admiral (voicelessvein.com)",
- "displayName": "Admiral"
- },
- "prevalence": 0.0107,
- "fingerprinting": 1,
- "cookies": 0.01,
- "default": "block"
- },
"voidgoo.com": {
"domain": "voidgoo.com",
"owner": {
@@ -47548,6 +47347,17 @@
"cookies": 0.01,
"default": "block"
},
+ "wildwoodavenue.com": {
+ "domain": "wildwoodavenue.com",
+ "owner": {
+ "name": "Leven Labs, Inc. DBA Admiral (wildwoodavenue.com)",
+ "displayName": "Admiral"
+ },
+ "prevalence": 0.0107,
+ "fingerprinting": 1,
+ "cookies": 0.01,
+ "default": "block"
+ },
"wirecomic.com": {
"domain": "wirecomic.com",
"owner": {
@@ -55488,6 +55298,13 @@
"prevalence": 0.0136,
"displayName": "Rating-Widget"
},
+ "rebuyengine.com": {
+ "domains": [
+ "rebuyengine.com"
+ ],
+ "prevalence": 0,
+ "displayName": "rebuyengine.com"
+ },
"Recruitics LLC": {
"domains": [
"recruitics.com"
@@ -57949,13 +57766,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (acceptableauthority.com)": {
- "domains": [
- "acceptableauthority.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (accountsdoor.com)": {
"domains": [
"accountsdoor.com"
@@ -58138,13 +57948,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (alertarithmetic.com)": {
- "domains": [
- "alertarithmetic.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (aliasanvil.com)": {
"domains": [
"aliasanvil.com"
@@ -59755,13 +59558,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (concernedchange.com)": {
- "domains": [
- "concernedchange.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (concernedchickens.com)": {
"domains": [
"concernedchickens.com"
@@ -61477,13 +61273,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (fertilefeeling.com)": {
- "domains": [
- "fertilefeeling.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (fewjuice.com)": {
"domains": [
"fewjuice.com"
@@ -62520,13 +62309,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (hatefulrequest.com)": {
- "domains": [
- "hatefulrequest.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (headydegree.com)": {
"domains": [
"headydegree.com"
@@ -64284,13 +64066,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (numberlessring.com)": {
- "domains": [
- "numberlessring.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (numerousnest.com)": {
"domains": [
"numerousnest.com"
@@ -65418,6 +65193,13 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
+ "Leven Labs, Inc. DBA Admiral (razzweb.com)": {
+ "domains": [
+ "razzweb.com"
+ ],
+ "prevalence": 0.0107,
+ "displayName": "Admiral"
+ },
"Leven Labs, Inc. DBA Admiral (reactjspdf.com)": {
"domains": [
"reactjspdf.com"
@@ -65537,13 +65319,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (reflectivestatement.com)": {
- "domains": [
- "reflectivestatement.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (refundradar.com)": {
"domains": [
"refundradar.com"
@@ -65866,6 +65641,13 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
+ "Leven Labs, Inc. DBA Admiral (sableshelf.com)": {
+ "domains": [
+ "sableshelf.com"
+ ],
+ "prevalence": 0.0107,
+ "displayName": "Admiral"
+ },
"Leven Labs, Inc. DBA Admiral (sablesmile.com)": {
"domains": [
"sablesmile.com"
@@ -65936,6 +65718,13 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
+ "Leven Labs, Inc. DBA Admiral (samuraibots.com)": {
+ "domains": [
+ "samuraibots.com"
+ ],
+ "prevalence": 0.0107,
+ "displayName": "Admiral"
+ },
"Leven Labs, Inc. DBA Admiral (sandstrophies.com)": {
"domains": [
"sandstrophies.com"
@@ -66153,13 +65942,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (scribbleson.com)": {
- "domains": [
- "scribbleson.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (scribblestring.com)": {
"domains": [
"scribblestring.com"
@@ -66230,13 +66012,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (seemlysuggestion.com)": {
- "domains": [
- "seemlysuggestion.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (selectivesummer.com)": {
"domains": [
"selectivesummer.com"
@@ -66398,6 +66173,13 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
+ "Leven Labs, Inc. DBA Admiral (shallowart.com)": {
+ "domains": [
+ "shallowart.com"
+ ],
+ "prevalence": 0.0107,
+ "displayName": "Admiral"
+ },
"Leven Labs, Inc. DBA Admiral (shallowblade.com)": {
"domains": [
"shallowblade.com"
@@ -66580,13 +66362,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (sinkbooks.com)": {
- "domains": [
- "sinkbooks.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (sixauthority.com)": {
"domains": [
"sixauthority.com"
@@ -67266,13 +67041,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (steepscale.com)": {
- "domains": [
- "steepscale.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (steepsister.com)": {
"domains": [
"steepsister.com"
@@ -67427,13 +67195,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (strangersponge.com)": {
- "domains": [
- "strangersponge.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (strangesink.com)": {
"domains": [
"strangesink.com"
@@ -67581,13 +67342,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (sugarfriction.com)": {
- "domains": [
- "sugarfriction.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (suggestionbridge.com)": {
"domains": [
"suggestionbridge.com"
@@ -67672,13 +67426,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (swelteringsleep.com)": {
- "domains": [
- "swelteringsleep.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (swimfreely.com)": {
"domains": [
"swimfreely.com"
@@ -67784,13 +67531,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (tastelesstrucks.com)": {
- "domains": [
- "tastelesstrucks.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (tastesnake.com)": {
"domains": [
"tastesnake.com"
@@ -68708,13 +68448,6 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
- "Leven Labs, Inc. DBA Admiral (voicelessvein.com)": {
- "domains": [
- "voicelessvein.com"
- ],
- "prevalence": 0.0107,
- "displayName": "Admiral"
- },
"Leven Labs, Inc. DBA Admiral (voidgoo.com)": {
"domains": [
"voidgoo.com"
@@ -68925,6 +68658,13 @@
"prevalence": 0.0107,
"displayName": "Admiral"
},
+ "Leven Labs, Inc. DBA Admiral (wildwoodavenue.com)": {
+ "domains": [
+ "wildwoodavenue.com"
+ ],
+ "prevalence": 0.0107,
+ "displayName": "Admiral"
+ },
"Leven Labs, Inc. DBA Admiral (wirecomic.com)": {
"domains": [
"wirecomic.com"
@@ -69842,7 +69582,6 @@
"abstractedauthority.com": "Leven Labs, Inc. DBA Admiral (abstractedauthority.com)",
"absurdapple.com": "Leven Labs, Inc. DBA Admiral (absurdapple.com)",
"abundantcoin.com": "Leven Labs, Inc. DBA Admiral (abundantcoin.com)",
- "acceptableauthority.com": "Leven Labs, Inc. DBA Admiral (acceptableauthority.com)",
"accountsdoor.com": "Leven Labs, Inc. DBA Admiral (accountsdoor.com)",
"accurateanimal.com": "Leven Labs, Inc. DBA Admiral (accurateanimal.com)",
"accuratecoal.com": "Leven Labs, Inc. DBA Admiral (accuratecoal.com)",
@@ -69869,7 +69608,6 @@
"aheadgrow.com": "Leven Labs, Inc. DBA Admiral (aheadgrow.com)",
"aheadmachine.com": "Leven Labs, Inc. DBA Admiral (aheadmachine.com)",
"ak0gsh40.com": "Leven Labs, Inc. DBA Admiral (ak0gsh40.com)",
- "alertarithmetic.com": "Leven Labs, Inc. DBA Admiral (alertarithmetic.com)",
"aliasanvil.com": "Leven Labs, Inc. DBA Admiral (aliasanvil.com)",
"alikeaddition.com": "Leven Labs, Inc. DBA Admiral (alikeaddition.com)",
"aliveachiever.com": "Leven Labs, Inc. DBA Admiral (aliveachiever.com)",
@@ -70100,7 +69838,6 @@
"comfygoodness.com": "Leven Labs, Inc. DBA Admiral (comfygoodness.com)",
"comparereaction.com": "Leven Labs, Inc. DBA Admiral (comparereaction.com)",
"compiledoctor.com": "Leven Labs, Inc. DBA Admiral (compiledoctor.com)",
- "concernedchange.com": "Leven Labs, Inc. DBA Admiral (concernedchange.com)",
"concernedchickens.com": "Leven Labs, Inc. DBA Admiral (concernedchickens.com)",
"condemnedcomb.com": "Leven Labs, Inc. DBA Admiral (condemnedcomb.com)",
"conditionchange.com": "Leven Labs, Inc. DBA Admiral (conditionchange.com)",
@@ -70346,7 +70083,6 @@
"feeblestamp.com": "Leven Labs, Inc. DBA Admiral (feeblestamp.com)",
"feignedfaucet.com": "Leven Labs, Inc. DBA Admiral (feignedfaucet.com)",
"fernwaycloud.com": "Leven Labs, Inc. DBA Admiral (fernwaycloud.com)",
- "fertilefeeling.com": "Leven Labs, Inc. DBA Admiral (fertilefeeling.com)",
"fewjuice.com": "Leven Labs, Inc. DBA Admiral (fewjuice.com)",
"fewkittens.com": "Leven Labs, Inc. DBA Admiral (fewkittens.com)",
"finalizeforce.com": "Leven Labs, Inc. DBA Admiral (finalizeforce.com)",
@@ -70495,7 +70231,6 @@
"harborcub.com": "Leven Labs, Inc. DBA Admiral (harborcub.com)",
"harmonicbamboo.com": "Leven Labs, Inc. DBA Admiral (harmonicbamboo.com)",
"harmonywing.com": "Leven Labs, Inc. DBA Admiral (harmonywing.com)",
- "hatefulrequest.com": "Leven Labs, Inc. DBA Admiral (hatefulrequest.com)",
"headydegree.com": "Leven Labs, Inc. DBA Admiral (headydegree.com)",
"headyhook.com": "Leven Labs, Inc. DBA Admiral (headyhook.com)",
"healflowers.com": "Leven Labs, Inc. DBA Admiral (healflowers.com)",
@@ -70747,7 +70482,6 @@
"notifyglass.com": "Leven Labs, Inc. DBA Admiral (notifyglass.com)",
"nudgeduck.com": "Leven Labs, Inc. DBA Admiral (nudgeduck.com)",
"nullnorth.com": "Leven Labs, Inc. DBA Admiral (nullnorth.com)",
- "numberlessring.com": "Leven Labs, Inc. DBA Admiral (numberlessring.com)",
"numerousnest.com": "Leven Labs, Inc. DBA Admiral (numerousnest.com)",
"nutritiousbean.com": "Leven Labs, Inc. DBA Admiral (nutritiousbean.com)",
"nuttyorganization.com": "Leven Labs, Inc. DBA Admiral (nuttyorganization.com)",
@@ -70909,6 +70643,7 @@
"rangergustav.com": "Leven Labs, Inc. DBA Admiral (rangergustav.com)",
"rarestcandy.com": "Leven Labs, Inc. DBA Admiral (rarestcandy.com)",
"raresummer.com": "Leven Labs, Inc. DBA Admiral (raresummer.com)",
+ "razzweb.com": "Leven Labs, Inc. DBA Admiral (razzweb.com)",
"reactjspdf.com": "Leven Labs, Inc. DBA Admiral (reactjspdf.com)",
"readingguilt.com": "Leven Labs, Inc. DBA Admiral (readingguilt.com)",
"readymoon.com": "Leven Labs, Inc. DBA Admiral (readymoon.com)",
@@ -70926,7 +70661,6 @@
"reconditeprison.com": "Leven Labs, Inc. DBA Admiral (reconditeprison.com)",
"reconditerake.com": "Leven Labs, Inc. DBA Admiral (reconditerake.com)",
"reconditerespect.com": "Leven Labs, Inc. DBA Admiral (reconditerespect.com)",
- "reflectivestatement.com": "Leven Labs, Inc. DBA Admiral (reflectivestatement.com)",
"refundradar.com": "Leven Labs, Inc. DBA Admiral (refundradar.com)",
"regexmail.com": "Leven Labs, Inc. DBA Admiral (regexmail.com)",
"regularplants.com": "Leven Labs, Inc. DBA Admiral (regularplants.com)",
@@ -70973,6 +70707,7 @@
"ruthlessdegree.com": "Leven Labs, Inc. DBA Admiral (ruthlessdegree.com)",
"ruthlessmilk.com": "Leven Labs, Inc. DBA Admiral (ruthlessmilk.com)",
"sableloss.com": "Leven Labs, Inc. DBA Admiral (sableloss.com)",
+ "sableshelf.com": "Leven Labs, Inc. DBA Admiral (sableshelf.com)",
"sablesmile.com": "Leven Labs, Inc. DBA Admiral (sablesmile.com)",
"sablesong.com": "Leven Labs, Inc. DBA Admiral (sablesong.com)",
"sadloaf.com": "Leven Labs, Inc. DBA Admiral (sadloaf.com)",
@@ -70983,6 +70718,7 @@
"samesticks.com": "Leven Labs, Inc. DBA Admiral (samesticks.com)",
"samestretch.com": "Leven Labs, Inc. DBA Admiral (samestretch.com)",
"samplesamba.com": "Leven Labs, Inc. DBA Admiral (samplesamba.com)",
+ "samuraibots.com": "Leven Labs, Inc. DBA Admiral (samuraibots.com)",
"sandstrophies.com": "Leven Labs, Inc. DBA Admiral (sandstrophies.com)",
"satisfycork.com": "Leven Labs, Inc. DBA Admiral (satisfycork.com)",
"savoryorange.com": "Leven Labs, Inc. DBA Admiral (savoryorange.com)",
@@ -71014,7 +70750,6 @@
"screechingfurniture.com": "Leven Labs, Inc. DBA Admiral (screechingfurniture.com)",
"screechingstocking.com": "Leven Labs, Inc. DBA Admiral (screechingstocking.com)",
"screechingstove.com": "Leven Labs, Inc. DBA Admiral (screechingstove.com)",
- "scribbleson.com": "Leven Labs, Inc. DBA Admiral (scribbleson.com)",
"scribblestring.com": "Leven Labs, Inc. DBA Admiral (scribblestring.com)",
"scrollservice.com": "Leven Labs, Inc. DBA Admiral (scrollservice.com)",
"scrubswim.com": "Leven Labs, Inc. DBA Admiral (scrubswim.com)",
@@ -71025,7 +70760,6 @@
"secretspiders.com": "Leven Labs, Inc. DBA Admiral (secretspiders.com)",
"secretturtle.com": "Leven Labs, Inc. DBA Admiral (secretturtle.com)",
"seedscissors.com": "Leven Labs, Inc. DBA Admiral (seedscissors.com)",
- "seemlysuggestion.com": "Leven Labs, Inc. DBA Admiral (seemlysuggestion.com)",
"selectivesummer.com": "Leven Labs, Inc. DBA Admiral (selectivesummer.com)",
"selfishsea.com": "Leven Labs, Inc. DBA Admiral (selfishsea.com)",
"selfishsnake.com": "Leven Labs, Inc. DBA Admiral (selfishsnake.com)",
@@ -71049,6 +70783,7 @@
"shakyseat.com": "Leven Labs, Inc. DBA Admiral (shakyseat.com)",
"shakysurprise.com": "Leven Labs, Inc. DBA Admiral (shakysurprise.com)",
"shakytaste.com": "Leven Labs, Inc. DBA Admiral (shakytaste.com)",
+ "shallowart.com": "Leven Labs, Inc. DBA Admiral (shallowart.com)",
"shallowblade.com": "Leven Labs, Inc. DBA Admiral (shallowblade.com)",
"shamerain.com": "Leven Labs, Inc. DBA Admiral (shamerain.com)",
"shapecomb.com": "Leven Labs, Inc. DBA Admiral (shapecomb.com)",
@@ -71075,7 +70810,6 @@
"sincerepelican.com": "Leven Labs, Inc. DBA Admiral (sincerepelican.com)",
"sinceresubstance.com": "Leven Labs, Inc. DBA Admiral (sinceresubstance.com)",
"singroot.com": "Leven Labs, Inc. DBA Admiral (singroot.com)",
- "sinkbooks.com": "Leven Labs, Inc. DBA Admiral (sinkbooks.com)",
"sixauthority.com": "Leven Labs, Inc. DBA Admiral (sixauthority.com)",
"sixscissors.com": "Leven Labs, Inc. DBA Admiral (sixscissors.com)",
"sizzlingsmoke.com": "Leven Labs, Inc. DBA Admiral (sizzlingsmoke.com)",
@@ -71173,7 +70907,6 @@
"steadfastsystem.com": "Leven Labs, Inc. DBA Admiral (steadfastsystem.com)",
"steadycopper.com": "Leven Labs, Inc. DBA Admiral (steadycopper.com)",
"stealsteel.com": "Leven Labs, Inc. DBA Admiral (stealsteel.com)",
- "steepscale.com": "Leven Labs, Inc. DBA Admiral (steepscale.com)",
"steepsister.com": "Leven Labs, Inc. DBA Admiral (steepsister.com)",
"steepsquirrel.com": "Leven Labs, Inc. DBA Admiral (steepsquirrel.com)",
"stepcattle.com": "Leven Labs, Inc. DBA Admiral (stepcattle.com)",
@@ -71196,7 +70929,6 @@
"stormyachiever.com": "Leven Labs, Inc. DBA Admiral (stormyachiever.com)",
"straightnest.com": "Leven Labs, Inc. DBA Admiral (straightnest.com)",
"strangeclocks.com": "Leven Labs, Inc. DBA Admiral (strangeclocks.com)",
- "strangersponge.com": "Leven Labs, Inc. DBA Admiral (strangersponge.com)",
"strangesink.com": "Leven Labs, Inc. DBA Admiral (strangesink.com)",
"streetsort.com": "Leven Labs, Inc. DBA Admiral (streetsort.com)",
"stretchsister.com": "Leven Labs, Inc. DBA Admiral (stretchsister.com)",
@@ -71218,7 +70950,6 @@
"succeedscene.com": "Leven Labs, Inc. DBA Admiral (succeedscene.com)",
"successfulscent.com": "Leven Labs, Inc. DBA Admiral (successfulscent.com)",
"suddensoda.com": "Leven Labs, Inc. DBA Admiral (suddensoda.com)",
- "sugarfriction.com": "Leven Labs, Inc. DBA Admiral (sugarfriction.com)",
"suggestionbridge.com": "Leven Labs, Inc. DBA Admiral (suggestionbridge.com)",
"sulkycook.com": "Leven Labs, Inc. DBA Admiral (sulkycook.com)",
"summerobject.com": "Leven Labs, Inc. DBA Admiral (summerobject.com)",
@@ -71231,7 +70962,6 @@
"suspectmark.com": "Leven Labs, Inc. DBA Admiral (suspectmark.com)",
"swankysquare.com": "Leven Labs, Inc. DBA Admiral (swankysquare.com)",
"swellstocking.com": "Leven Labs, Inc. DBA Admiral (swellstocking.com)",
- "swelteringsleep.com": "Leven Labs, Inc. DBA Admiral (swelteringsleep.com)",
"swimfreely.com": "Leven Labs, Inc. DBA Admiral (swimfreely.com)",
"swingslip.com": "Leven Labs, Inc. DBA Admiral (swingslip.com)",
"swordgoose.com": "Leven Labs, Inc. DBA Admiral (swordgoose.com)",
@@ -71247,7 +70977,6 @@
"tangyamount.com": "Leven Labs, Inc. DBA Admiral (tangyamount.com)",
"tangycover.com": "Leven Labs, Inc. DBA Admiral (tangycover.com)",
"tastelesstrees.com": "Leven Labs, Inc. DBA Admiral (tastelesstrees.com)",
- "tastelesstrucks.com": "Leven Labs, Inc. DBA Admiral (tastelesstrucks.com)",
"tastesnake.com": "Leven Labs, Inc. DBA Admiral (tastesnake.com)",
"tawdryson.com": "Leven Labs, Inc. DBA Admiral (tawdryson.com)",
"tdzvm.pw": "Leven Labs, Inc. DBA Admiral (tdzvm.pw)",
@@ -71379,7 +71108,6 @@
"vividfrost.com": "Leven Labs, Inc. DBA Admiral (vividfrost.com)",
"vividmeadow.com": "Leven Labs, Inc. DBA Admiral (vividmeadow.com)",
"vividplume.com": "Leven Labs, Inc. DBA Admiral (vividplume.com)",
- "voicelessvein.com": "Leven Labs, Inc. DBA Admiral (voicelessvein.com)",
"voidgoo.com": "Leven Labs, Inc. DBA Admiral (voidgoo.com)",
"volatileprofit.com": "Leven Labs, Inc. DBA Admiral (volatileprofit.com)",
"volatilevessel.com": "Leven Labs, Inc. DBA Admiral (volatilevessel.com)",
@@ -71410,6 +71138,7 @@
"whisperingsummit.com": "Leven Labs, Inc. DBA Admiral (whisperingsummit.com)",
"whispermeeting.com": "Leven Labs, Inc. DBA Admiral (whispermeeting.com)",
"wildcommittee.com": "Leven Labs, Inc. DBA Admiral (wildcommittee.com)",
+ "wildwoodavenue.com": "Leven Labs, Inc. DBA Admiral (wildwoodavenue.com)",
"wirecomic.com": "Leven Labs, Inc. DBA Admiral (wirecomic.com)",
"wiredforcoffee.com": "Leven Labs, Inc. DBA Admiral (wiredforcoffee.com)",
"wirypaste.com": "Leven Labs, Inc. DBA Admiral (wirypaste.com)",
@@ -74914,6 +74643,7 @@
"secretmag.ru": "Rambler Internet Holding, LLC",
"top100.ru": "Rambler Internet Holding, LLC",
"rating-widget.com": "Rating-Widget, Inc.",
+ "rebuyengine.com": "rebuyengine.com",
"recruitics.com": "Recruitics LLC",
"dubsmash.com": "Reddit Inc.",
"redd.it": "Reddit Inc.",
diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj
index 86e91dc461..fce5b52b68 100644
--- a/DuckDuckGo.xcodeproj/project.pbxproj
+++ b/DuckDuckGo.xcodeproj/project.pbxproj
@@ -175,7 +175,6 @@
317F5F982C94A9EB0081666F /* MarketplaceAdPostbackStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317F5F972C94A9EB0081666F /* MarketplaceAdPostbackStorage.swift */; };
31860A5B2C57ED2D005561F5 /* DuckPlayerStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31860A5A2C57ED2D005561F5 /* DuckPlayerStorage.swift */; };
31951E8E2823003200CAF535 /* AutofillLoginDetailsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31951E8D2823003200CAF535 /* AutofillLoginDetailsHeaderView.swift */; };
- 319A371028299A850079FBCE /* PasswordHider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319A370F28299A850079FBCE /* PasswordHider.swift */; };
319A37152829A55F0079FBCE /* AutofillListItemTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319A37142829A55F0079FBCE /* AutofillListItemTableViewCell.swift */; };
319A37172829C8AD0079FBCE /* UITableViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 319A37162829C8AD0079FBCE /* UITableViewExtension.swift */; };
31A42564285A09E800049386 /* FaviconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A42563285A09E800049386 /* FaviconView.swift */; };
@@ -919,6 +918,15 @@
C1BF0BA529B63D7200482B73 /* AutofillLoginPromptHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */; };
C1BF0BA929B63E2200482B73 /* AutofillLoginPromptViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */; };
C1BF26152C74D10F00F6405E /* SyncPromoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF26142C74D10F00F6405E /* SyncPromoManager.swift */; };
+ C1C1FF452D085A280017ACCE /* CredentialProviderListDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF412D085A280017ACCE /* CredentialProviderListDetailsView.swift */; };
+ C1C1FF462D085A280017ACCE /* CredentialProviderListDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF422D085A280017ACCE /* CredentialProviderListDetailsViewController.swift */; };
+ C1C1FF472D085A280017ACCE /* CredentialProviderListDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF432D085A280017ACCE /* CredentialProviderListDetailsViewModel.swift */; };
+ C1C1FF4A2D085A4C0017ACCE /* AutofillInterfaceEmailTruncator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF482D085A4C0017ACCE /* AutofillInterfaceEmailTruncator.swift */; };
+ C1C1FF4B2D085A4C0017ACCE /* PasswordHider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF492D085A4C0017ACCE /* PasswordHider.swift */; };
+ C1C1FF502D085AD70017ACCE /* ActionMessageView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C1C1FF4D2D085AD70017ACCE /* ActionMessageView.xib */; };
+ C1C1FF512D085AD70017ACCE /* FaviconHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF4E2D085AD70017ACCE /* FaviconHelper.swift */; };
+ C1C1FF522D085AD70017ACCE /* ActionMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF4C2D085AD70017ACCE /* ActionMessageView.swift */; };
+ C1C1FF532D085AD70017ACCE /* NibLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C1FF4F2D085AD70017ACCE /* NibLoading.swift */; };
C1CAAA6A2CF8BABF00C37EE6 /* CredentialProviderActivatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CAAA692CF8BABF00C37EE6 /* CredentialProviderActivatedView.swift */; };
C1CAAA712CF8BC0B00C37EE6 /* UIViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CAAA702CF8BC0B00C37EE6 /* UIViewControllerExtension.swift */; };
C1CAAA732CF8BD1C00C37EE6 /* CredentialProviderActivatedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CAAA722CF8BD1C00C37EE6 /* CredentialProviderActivatedViewModel.swift */; };
@@ -945,6 +953,8 @@
C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */; };
C1D21E2F293A599C006E5A05 /* AutofillLoginSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */; };
C1E42C7B2C5CD8AE00509204 /* AutofillCredentialsDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E42C7A2C5CD8AD00509204 /* AutofillCredentialsDebugViewController.swift */; };
+ C1E4E9A62D0861AD00AA39AF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1E4E9A42D0861AD00AA39AF /* InfoPlist.strings */; };
+ C1E4E9A92D0861AD00AA39AF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C1E4E9A72D0861AD00AA39AF /* Localizable.strings */; };
C1EA86602C74CB6C00E8604D /* SyncPromoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EA865F2C74CB6C00E8604D /* SyncPromoView.swift */; };
C1EA86622C74CB8B00E8604D /* SyncPromoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EA86612C74CB8B00E8604D /* SyncPromoViewModel.swift */; };
C1EF5B232CC0457B002980E6 /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1EF5B222CC0457B002980E6 /* AuthenticationServices.framework */; };
@@ -1205,7 +1215,6 @@
F486D3382506A225002D07D7 /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F486D3372506A225002D07D7 /* OHHTTPStubsSwift */; };
F4B0B78C252CAFF700830156 /* OnboardingWidgetsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4B0B78B252CAFF700830156 /* OnboardingWidgetsViewController.swift */; };
F4B0B796252CB35700830156 /* OnboardingWidgetsDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4B0B795252CB35700830156 /* OnboardingWidgetsDetailsViewController.swift */; };
- F4C9FBF528340DDA002281CC /* AutofillInterfaceEmailTruncator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4C9FBF428340DDA002281CC /* AutofillInterfaceEmailTruncator.swift */; };
F4CE6D1B257EA33C00D0A6AA /* FireButtonAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4CE6D1A257EA33C00D0A6AA /* FireButtonAnimator.swift */; };
F4D7221026F29A70007D6193 /* BookmarkDetailsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4D7220F26F29A70007D6193 /* BookmarkDetailsCell.swift */; };
F4D7F634298C00C3006C3AE9 /* FindInPageIOSJSSupport in Frameworks */ = {isa = PBXBuildFile; productRef = F4D7F633298C00C3006C3AE9 /* FindInPageIOSJSSupport */; };
@@ -1542,7 +1551,6 @@
317F5F972C94A9EB0081666F /* MarketplaceAdPostbackStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketplaceAdPostbackStorage.swift; sourceTree = ""; };
31860A5A2C57ED2D005561F5 /* DuckPlayerStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DuckPlayerStorage.swift; sourceTree = ""; };
31951E8D2823003200CAF535 /* AutofillLoginDetailsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginDetailsHeaderView.swift; sourceTree = ""; };
- 319A370F28299A850079FBCE /* PasswordHider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordHider.swift; sourceTree = ""; };
319A37142829A55F0079FBCE /* AutofillListItemTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillListItemTableViewCell.swift; sourceTree = ""; };
319A37162829C8AD0079FBCE /* UITableViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewExtension.swift; sourceTree = ""; };
31A42563285A09E800049386 /* FaviconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconView.swift; sourceTree = ""; };
@@ -2707,14 +2715,28 @@
BDFF03242BA3D92E00F324C9 /* NetworkProtectionFeatureVisibilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionFeatureVisibilityTests.swift; sourceTree = ""; };
C10CB5F22A1A5BDF0048E503 /* AutofillViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillViews.swift; sourceTree = ""; };
C111B26827F579EF006558B1 /* BookmarkOrFolderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkOrFolderTests.swift; sourceTree = ""; };
+ C1193F602D08642900CB3239 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1193F612D08642900CB3239 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; };
+ C11C4D302D08648100288E85 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; };
+ C11C4D312D08648100288E85 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; };
C12726ED2A5FF88C00215B02 /* EmailSignupPromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignupPromptView.swift; sourceTree = ""; };
C12726EF2A5FF89900215B02 /* EmailSignupPromptViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignupPromptViewModel.swift; sourceTree = ""; };
C12726F12A5FF8CB00215B02 /* EmailSignupPromptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignupPromptViewController.swift; sourceTree = ""; };
+ C12854D82D08636E00C8353F /* lv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lv; path = lv.lproj/InfoPlist.strings; sourceTree = ""; };
+ C12854D92D08636E00C8353F /* lv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lv; path = lv.lproj/Localizable.strings; sourceTree = ""; };
+ C129DF092D0862D7007AB046 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; };
+ C129DF0A2D0862D7007AB046 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; };
+ C132F5A32D0862B8000C81D0 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = ""; };
+ C132F5A42D0862B8000C81D0 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; };
C13B32D12A0E750700A59236 /* AutofillSettingStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillSettingStatus.swift; sourceTree = ""; };
C13C076B2D00A6B7006386CF /* VaultCredentialManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultCredentialManager.swift; sourceTree = ""; };
C13F3F672B7F88100083BE40 /* AuthConfirmationPromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthConfirmationPromptView.swift; sourceTree = ""; };
C13F3F692B7F883A0083BE40 /* AuthConfirmationPromptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthConfirmationPromptViewController.swift; sourceTree = ""; };
C13F3F6B2B7F88470083BE40 /* AuthConfirmationPromptViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthConfirmationPromptViewModel.swift; sourceTree = ""; };
+ C1406D862D0862F30082CB50 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1406D872D0862F30082CB50 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/Localizable.strings; sourceTree = ""; };
+ C1453E322D0863C80024449B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1453E332D0863C80024449B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; };
C14882D727F2011C00D59F0C /* BookmarksExporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksExporter.swift; sourceTree = ""; };
C14882D927F2011C00D59F0C /* BookmarksImporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksImporter.swift; sourceTree = ""; };
C14882E127F20D9A00D59F0C /* BookmarksExporterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksExporterTests.swift; sourceTree = ""; };
@@ -2722,23 +2744,37 @@
C14882E527F20DAA00D59F0C /* HtmlTestDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HtmlTestDataLoader.swift; sourceTree = ""; };
C14882E627F20DAB00D59F0C /* TestDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestDataLoader.swift; sourceTree = ""; };
C14882E927F20DD000D59F0C /* MockBookmarksCoreDataStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockBookmarksCoreDataStorage.swift; sourceTree = ""; };
+ C14D37D62D08649E00FCFC59 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; };
+ C14D37D72D08649E00FCFC59 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; };
C14D43002B45D6CD00ACA4DC /* AutofillDebugViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillDebugViewController.swift; sourceTree = ""; };
C14E2F7629DE14EA002AC515 /* AutofillInterfaceUsernameTruncatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillInterfaceUsernameTruncatorTests.swift; sourceTree = ""; };
+ C1588FC42D08644800C9BE70 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1588FC52D08644800C9BE70 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; };
C158AC7A297AB5DC0008723A /* MockSecureVault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSecureVault.swift; sourceTree = ""; };
C159DF062A430B60007834BB /* EmailSignupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignupViewController.swift; sourceTree = ""; };
C160544029D6044D00B715A1 /* AutofillInterfaceUsernameTruncator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillInterfaceUsernameTruncator.swift; sourceTree = ""; };
+ C163677A2D08638C001D1094 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = ""; };
+ C163677B2D08638C001D1094 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; };
C1641EAE2BC2F5140012607A /* ImportPasswordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsViewController.swift; sourceTree = ""; };
C1641EB02BC2F52B0012607A /* ImportPasswordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsView.swift; sourceTree = ""; };
C1641EB22BC2F53C0012607A /* ImportPasswordsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsViewModel.swift; sourceTree = ""; };
+ C164F9472D0861D600BAE88E /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/InfoPlist.strings; sourceTree = ""; };
+ C164F9482D0861D600BAE88E /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; };
+ C174E08E2D08625300ACE1AF /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/InfoPlist.strings; sourceTree = ""; };
+ C174E08F2D08625300ACE1AF /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = ""; };
C177D9F52CFDDFEB0039CBF7 /* UIAlertControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertControllerExtension.swift; sourceTree = ""; };
C17B59562A03AAD30055F2D1 /* PasswordGenerationPromptViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerationPromptViewModel.swift; sourceTree = ""; };
C17B59572A03AAD30055F2D1 /* PasswordGenerationPromptViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerationPromptViewController.swift; sourceTree = ""; };
C17B59582A03AAD30055F2D1 /* PasswordGenerationPromptView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerationPromptView.swift; sourceTree = ""; };
+ C180CAFA2D0863E500ADB0FE /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/InfoPlist.strings; sourceTree = ""; };
+ C180CAFB2D0863E500ADB0FE /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Localizable.strings; sourceTree = ""; };
C1836CE02C359EC90016D057 /* AutofillBreakageReportCellContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillBreakageReportCellContentView.swift; sourceTree = ""; };
C1836CE42C35A0EA0016D057 /* AutofillBreakageReportTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillBreakageReportTableViewCell.swift; sourceTree = ""; };
C185ED602BD4329700BAE9DC /* ImportPasswordsStatusHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsStatusHandler.swift; sourceTree = ""; };
C185ED632BD438AF00BAE9DC /* ImportPasswordsStatusHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsStatusHandlerTests.swift; sourceTree = ""; };
C185ED652BD43A5500BAE9DC /* MockDDGSyncing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDDGSyncing.swift; sourceTree = ""; };
+ C18D7C412D08620D00FB3F87 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/InfoPlist.strings; sourceTree = ""; };
+ C18D7C422D08620D00FB3F87 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; };
C18ED4392AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillSettingsEnableFooterView.swift; sourceTree = ""; };
C18ED43B2AB8364400BF3805 /* FileTextPreviewDebugViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileTextPreviewDebugViewController.swift; sourceTree = ""; };
C1935A0D2C88D11D001AD72D /* AutofillSurveyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillSurveyView.swift; sourceTree = ""; };
@@ -2748,15 +2784,30 @@
C1935A232C89CC6D001AD72D /* AutofillHeaderViewFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillHeaderViewFactoryTests.swift; sourceTree = ""; };
C1963862283794A000298D4D /* BookmarksCachingSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksCachingSearch.swift; sourceTree = ""; };
C19D90D02CFE3A7F00D17DF3 /* AutofillLoginListSectionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginListSectionType.swift; sourceTree = ""; };
+ C1A001092D08635100372C87 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1A0010A2D08635100372C87 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = ""; };
C1B0F6412AB08BE9001EAF05 /* MockPrivacyConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrivacyConfiguration.swift; sourceTree = ""; };
+ C1B783DB2D0863110071C53B /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1B783DC2D0863110071C53B /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; };
C1B7B51B28941E980098FD6A /* HomeMessageViewModelBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeMessageViewModelBuilder.swift; sourceTree = ""; };
C1B7B52128941F2A0098FD6A /* RemoteMessagingClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMessagingClient.swift; sourceTree = ""; };
C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVariantManager.swift; sourceTree = ""; };
C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataTestUtilities.swift; sourceTree = ""; };
+ C1B7BF522D08640B0024FF56 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1B7BF532D08640B0024FF56 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = ""; };
C1B924B62ACD6E6800EE7B06 /* AutofillNeverSavedTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverSavedTableViewCell.swift; sourceTree = ""; };
C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptHelper.swift; sourceTree = ""; };
C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptViewModelTests.swift; sourceTree = ""; };
C1BF26142C74D10F00F6405E /* SyncPromoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPromoManager.swift; sourceTree = ""; };
+ C1C1FF412D085A280017ACCE /* CredentialProviderListDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialProviderListDetailsView.swift; sourceTree = ""; };
+ C1C1FF422D085A280017ACCE /* CredentialProviderListDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialProviderListDetailsViewController.swift; sourceTree = ""; };
+ C1C1FF432D085A280017ACCE /* CredentialProviderListDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialProviderListDetailsViewModel.swift; sourceTree = ""; };
+ C1C1FF482D085A4C0017ACCE /* AutofillInterfaceEmailTruncator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillInterfaceEmailTruncator.swift; sourceTree = ""; };
+ C1C1FF492D085A4C0017ACCE /* PasswordHider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordHider.swift; sourceTree = ""; };
+ C1C1FF4C2D085AD70017ACCE /* ActionMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionMessageView.swift; sourceTree = ""; };
+ C1C1FF4D2D085AD70017ACCE /* ActionMessageView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ActionMessageView.xib; sourceTree = ""; };
+ C1C1FF4E2D085AD70017ACCE /* FaviconHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconHelper.swift; sourceTree = ""; };
+ C1C1FF4F2D085AD70017ACCE /* NibLoading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NibLoading.swift; sourceTree = ""; };
C1CAAA672CF8B74200C37EE6 /* AutofillCredentialProviderAlpha.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AutofillCredentialProviderAlpha.entitlements; sourceTree = ""; };
C1CAAA692CF8BABF00C37EE6 /* CredentialProviderActivatedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialProviderActivatedView.swift; sourceTree = ""; };
C1CAAA702CF8BC0B00C37EE6 /* UIViewControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExtension.swift; sourceTree = ""; };
@@ -2776,11 +2827,19 @@
C1CAAAA72CFCBE4800C37EE6 /* EmptySearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptySearchView.swift; sourceTree = ""; };
C1CAAAA92CFCC13E00C37EE6 /* SecureVaultReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureVaultReporter.swift; sourceTree = ""; };
C1CAAAAB2CFCC91D00C37EE6 /* EmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyView.swift; sourceTree = ""; };
+ C1CB0AA52D08629800335287 /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1CB0AA62D08629800335287 /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = ""; };
C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManager.swift; sourceTree = ""; };
C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManagerTests.swift; sourceTree = ""; };
C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSession.swift; sourceTree = ""; };
C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSessionTests.swift; sourceTree = ""; };
+ C1DCF3502D0862330055F8B0 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1DCF3512D0862330055F8B0 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; };
C1E42C7A2C5CD8AD00509204 /* AutofillCredentialsDebugViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillCredentialsDebugViewController.swift; sourceTree = ""; };
+ C1E490582D08646400F86C5A /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1E490592D08646400F86C5A /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Localizable.strings; sourceTree = ""; };
+ C1E4E9A52D0861AD00AA39AF /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1E4E9A82D0861AD00AA39AF /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; };
C1EA865F2C74CB6C00E8604D /* SyncPromoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPromoView.swift; sourceTree = ""; };
C1EA86612C74CB8B00E8604D /* SyncPromoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPromoViewModel.swift; sourceTree = ""; };
C1EF5B212CC0457B002980E6 /* AutofillCredentialProvider.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AutofillCredentialProvider.appex; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -2791,6 +2850,12 @@
C1F341C42A6924000032057B /* EmailAddressPromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailAddressPromptView.swift; sourceTree = ""; };
C1F341C62A6924100032057B /* EmailAddressPromptViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailAddressPromptViewModel.swift; sourceTree = ""; };
C1F341C82A6926920032057B /* EmailAddressPromptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailAddressPromptViewController.swift; sourceTree = ""; };
+ C1F883372D08627900DFF79A /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1F883382D08627900DFF79A /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; };
+ C1FE93E52D0863AA009F8F5E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1FE93E62D0863AA009F8F5E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; };
+ C1FEDCEA2D08633100BFBF3F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; };
+ C1FEDCEB2D08633100BFBF3F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; };
C1FFBD452C761BE20073622B /* SyncPromoManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPromoManagerTests.swift; sourceTree = ""; };
C1FFBD472C7749A90073622B /* SyncSettingsViewController+PlatformLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SyncSettingsViewController+PlatformLinks.swift"; sourceTree = ""; };
CB1143DD2AF6D4B600C1CCD3 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/InfoPlist.strings; sourceTree = ""; };
@@ -3076,7 +3141,6 @@
F47E53DA250A9A1C0037C686 /* Onboarding.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Onboarding.xcassets; sourceTree = ""; };
F4B0B78B252CAFF700830156 /* OnboardingWidgetsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingWidgetsViewController.swift; sourceTree = ""; };
F4B0B795252CB35700830156 /* OnboardingWidgetsDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingWidgetsDetailsViewController.swift; sourceTree = ""; };
- F4C9FBF428340DDA002281CC /* AutofillInterfaceEmailTruncator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillInterfaceEmailTruncator.swift; sourceTree = ""; };
F4CE6D1A257EA33C00D0A6AA /* FireButtonAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FireButtonAnimator.swift; sourceTree = ""; };
F4D7220F26F29A70007D6193 /* BookmarkDetailsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkDetailsCell.swift; sourceTree = ""; };
F4D9C4F925117A0F00814B71 /* HomeMessageStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeMessageStorage.swift; sourceTree = ""; };
@@ -3721,7 +3785,6 @@
31951E9328230D8900CAF535 /* Shared */ = {
isa = PBXGroup;
children = (
- F4C9FBF428340DDA002281CC /* AutofillInterfaceEmailTruncator.swift */,
31A42563285A09E800049386 /* FaviconView.swift */,
31A42565285A0A6300049386 /* FaviconViewModel.swift */,
C160544029D6044D00B715A1 /* AutofillInterfaceUsernameTruncator.swift */,
@@ -5329,6 +5392,16 @@
name = AutofillLoginUI;
sourceTree = "";
};
+ C1C1FF442D085A280017ACCE /* CredentialProviderListDetails */ = {
+ isa = PBXGroup;
+ children = (
+ C1C1FF412D085A280017ACCE /* CredentialProviderListDetailsView.swift */,
+ C1C1FF422D085A280017ACCE /* CredentialProviderListDetailsViewController.swift */,
+ C1C1FF432D085A280017ACCE /* CredentialProviderListDetailsViewModel.swift */,
+ );
+ path = CredentialProviderListDetails;
+ sourceTree = "";
+ };
C1CAA3D52A630ECB00807703 /* EmailSignup */ = {
isa = PBXGroup;
children = (
@@ -5355,6 +5428,7 @@
C1EF5B252CC0457B002980E6 /* CredentialProviderViewController.swift */,
C1CAAA682CF8B8C400C37EE6 /* CredentialProviderActivation */,
C1CAAA862CF9FFBE00C37EE6 /* CredentialProviderList */,
+ C1C1FF442D085A280017ACCE /* CredentialProviderListDetails */,
C1CAAA6E2CF8BBC900C37EE6 /* Extensions */,
C1CAAA742CF8BDC400C37EE6 /* Resources */,
C1CAAAA42CFCBD6B00C37EE6 /* Shared */,
@@ -5398,6 +5472,8 @@
C1CAAA962CFCAB8000C37EE6 /* Autofill */ = {
isa = PBXGroup;
children = (
+ C1C1FF482D085A4C0017ACCE /* AutofillInterfaceEmailTruncator.swift */,
+ C1C1FF492D085A4C0017ACCE /* PasswordHider.swift */,
C19D90D02CFE3A7F00D17DF3 /* AutofillLoginListSectionType.swift */,
C1CAAA992CFCAD3E00C37EE6 /* AutofillLoginItem.swift */,
C1CAAA9B2CFCB39800C37EE6 /* AutofillLoginListSorting.swift */,
@@ -5416,7 +5492,11 @@
C1CAAAA42CFCBD6B00C37EE6 /* Shared */ = {
isa = PBXGroup;
children = (
+ C1C1FF4C2D085AD70017ACCE /* ActionMessageView.swift */,
+ C1C1FF4D2D085AD70017ACCE /* ActionMessageView.xib */,
+ C1C1FF4E2D085AD70017ACCE /* FaviconHelper.swift */,
C1CAAAA52CFCBD7900C37EE6 /* LockScreenView.swift */,
+ C1C1FF4F2D085AD70017ACCE /* NibLoading.swift */,
C1CAAAA92CFCC13E00C37EE6 /* SecureVaultReporter.swift */,
C13C076B2D00A6B7006386CF /* VaultCredentialManager.swift */,
);
@@ -5439,6 +5519,8 @@
C1CAAA6D2CF8BBBC00C37EE6 /* CredentialProvider */,
C1CAAA672CF8B74200C37EE6 /* AutofillCredentialProviderAlpha.entitlements */,
C1EF5B2A2CC0457B002980E6 /* Info.plist */,
+ C1E4E9A72D0861AD00AA39AF /* Localizable.strings */,
+ C1E4E9A42D0861AD00AA39AF /* InfoPlist.strings */,
C1EF5B2B2CC0457B002980E6 /* AutofillCredentialProvider.entitlements */,
);
path = AutofillCredentialProvider;
@@ -6633,7 +6715,6 @@
C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */,
C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */,
C13B32D12A0E750700A59236 /* AutofillSettingStatus.swift */,
- 319A370F28299A850079FBCE /* PasswordHider.swift */,
31C70B5428045E3500FB6AD1 /* SecureVaultReporter.swift */,
C1AFFC4B2B8773060060448E /* AuthConfirmation */,
F407605328131910006B1E0B /* AutofillLoginUI */,
@@ -7396,6 +7477,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ C1C1FF502D085AD70017ACCE /* ActionMessageView.xib in Resources */,
+ C1E4E9A92D0861AD00AA39AF /* Localizable.strings in Resources */,
+ C1E4E9A62D0861AD00AA39AF /* InfoPlist.strings in Resources */,
C1CAAA7A2CF8BE0200C37EE6 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -7616,7 +7700,6 @@
6F03CAFE2C32DD08004179A8 /* HomePageMessagesConfiguration.swift in Sources */,
851952682CE2522700578553 /* AutocompleteSuggestionsDataSource.swift in Sources */,
EE9D68D12AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift in Sources */,
- 319A371028299A850079FBCE /* PasswordHider.swift in Sources */,
982C87C42255559A00919035 /* UITableViewCellExtension.swift in Sources */,
B623C1C42862CD670043013E /* WKDownloadSession.swift in Sources */,
6FD1BAE42B87A107000C475C /* AdAttributionPixelReporter.swift in Sources */,
@@ -7865,7 +7948,6 @@
6F5CC0812C2AFFE400AFC840 /* ToggleExpandButtonStyle.swift in Sources */,
D68A21462B7EC16200BB372E /* SubscriptionExternalLinkViewModel.swift in Sources */,
31DE43C22C2C480D00F8C51F /* DuckPlayerFeaturePresentationView.swift in Sources */,
- F4C9FBF528340DDA002281CC /* AutofillInterfaceEmailTruncator.swift in Sources */,
1E016AB42949FEB500F21625 /* OmniBarNotificationViewModel.swift in Sources */,
6AC6DAB328804F97002723C0 /* BarsAnimator.swift in Sources */,
CB4FA44E2C78AACE00A16F5A /* SpecialErrorPageUserScript.swift in Sources */,
@@ -8536,8 +8618,14 @@
C1CAAA9E2CFCB78700C37EE6 /* UIColorExtension.swift in Sources */,
C1CAAA8A2CF9FFF300C37EE6 /* CredentialProviderListViewModel.swift in Sources */,
C1CAAAA02CFCB7C200C37EE6 /* UImageExtension.swift in Sources */,
+ C1C1FF512D085AD70017ACCE /* FaviconHelper.swift in Sources */,
+ C1C1FF522D085AD70017ACCE /* ActionMessageView.swift in Sources */,
+ C1C1FF532D085AD70017ACCE /* NibLoading.swift in Sources */,
C177D9F62CFDDFEB0039CBF7 /* UIAlertControllerExtension.swift in Sources */,
C1CAAA882CF9FFE100C37EE6 /* CredentialProviderListViewController.swift in Sources */,
+ C1C1FF452D085A280017ACCE /* CredentialProviderListDetailsView.swift in Sources */,
+ C1C1FF462D085A280017ACCE /* CredentialProviderListDetailsViewController.swift in Sources */,
+ C1C1FF472D085A280017ACCE /* CredentialProviderListDetailsViewModel.swift in Sources */,
C1CAAAAA2CFCC13E00C37EE6 /* SecureVaultReporter.swift in Sources */,
C1CAAAA82CFCBE4800C37EE6 /* EmptySearchView.swift in Sources */,
);
@@ -8577,6 +8665,8 @@
85BDC3192436161C0053DB07 /* LoginFormDetectionUserScript.swift in Sources */,
37DF000A29F9C416002B7D3E /* SyncMetadataDatabase.swift in Sources */,
F143C3291E4A9A0E00CFDE3A /* URLExtension.swift in Sources */,
+ C1C1FF4A2D085A4C0017ACCE /* AutofillInterfaceEmailTruncator.swift in Sources */,
+ C1C1FF4B2D085A4C0017ACCE /* PasswordHider.swift in Sources */,
85E065BC2C73A54700D73E2A /* UsageSegmentationStorage.swift in Sources */,
F143C3271E4A9A0E00CFDE3A /* Logger+Multiple.swift in Sources */,
85372447220DD103009D09CD /* UIKeyCommandExtension.swift in Sources */,
@@ -9314,6 +9404,68 @@
name = OmniBar.xib;
sourceTree = "";
};
+ C1E4E9A42D0861AD00AA39AF /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ C1E4E9A52D0861AD00AA39AF /* bg */,
+ C164F9472D0861D600BAE88E /* cs */,
+ C18D7C412D08620D00FB3F87 /* da */,
+ C1DCF3502D0862330055F8B0 /* de */,
+ C174E08E2D08625300ACE1AF /* el */,
+ C1F883372D08627900DFF79A /* es */,
+ C1CB0AA52D08629800335287 /* et */,
+ C132F5A32D0862B8000C81D0 /* fi */,
+ C129DF092D0862D7007AB046 /* fr */,
+ C1406D862D0862F30082CB50 /* hr */,
+ C1B783DB2D0863110071C53B /* hu */,
+ C1FEDCEA2D08633100BFBF3F /* it */,
+ C1A001092D08635100372C87 /* lt */,
+ C12854D82D08636E00C8353F /* lv */,
+ C163677A2D08638C001D1094 /* nb */,
+ C1FE93E52D0863AA009F8F5E /* nl */,
+ C1453E322D0863C80024449B /* pl */,
+ C180CAFA2D0863E500ADB0FE /* pt */,
+ C1B7BF522D08640B0024FF56 /* ro */,
+ C1193F602D08642900CB3239 /* ru */,
+ C1588FC42D08644800C9BE70 /* sk */,
+ C1E490582D08646400F86C5A /* sl */,
+ C11C4D302D08648100288E85 /* sv */,
+ C14D37D62D08649E00FCFC59 /* tr */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
+ C1E4E9A72D0861AD00AA39AF /* Localizable.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ C1E4E9A82D0861AD00AA39AF /* bg */,
+ C164F9482D0861D600BAE88E /* cs */,
+ C18D7C422D08620D00FB3F87 /* da */,
+ C1DCF3512D0862330055F8B0 /* de */,
+ C174E08F2D08625300ACE1AF /* el */,
+ C1F883382D08627900DFF79A /* es */,
+ C1CB0AA62D08629800335287 /* et */,
+ C132F5A42D0862B8000C81D0 /* fi */,
+ C129DF0A2D0862D7007AB046 /* fr */,
+ C1406D872D0862F30082CB50 /* hr */,
+ C1B783DC2D0863110071C53B /* hu */,
+ C1FEDCEB2D08633100BFBF3F /* it */,
+ C1A0010A2D08635100372C87 /* lt */,
+ C12854D92D08636E00C8353F /* lv */,
+ C163677B2D08638C001D1094 /* nb */,
+ C1FE93E62D0863AA009F8F5E /* nl */,
+ C1453E332D0863C80024449B /* pl */,
+ C180CAFB2D0863E500ADB0FE /* pt */,
+ C1B7BF532D08640B0024FF56 /* ro */,
+ C1193F612D08642900CB3239 /* ru */,
+ C1588FC52D08644800C9BE70 /* sk */,
+ C1E490592D08646400F86C5A /* sl */,
+ C11C4D312D08648100288E85 /* sv */,
+ C14D37D72D08649E00FCFC59 /* tr */,
+ );
+ name = Localizable.strings;
+ sourceTree = "";
+ };
CB1143DC2AF6D4B600C1CCD3 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
@@ -9518,7 +9670,7 @@
CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
@@ -9555,7 +9707,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -9645,7 +9797,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ShareExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -9672,7 +9824,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -9820,7 +9972,7 @@
CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
@@ -9846,7 +9998,7 @@
CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
INFOPLIST_FILE = DuckDuckGo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -9913,7 +10065,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = Widgets/Info.plist;
@@ -9947,7 +10099,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
@@ -9980,7 +10132,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = OpenAction/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -10010,7 +10162,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -10341,7 +10493,7 @@
CODE_SIGN_ENTITLEMENTS = AutofillCredentialProvider/AutofillCredentialProvider.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = HKE973VLUW;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -10357,7 +10509,7 @@
);
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.AutofillCredentialProvider;
+ PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.CredentialExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
@@ -10379,7 +10531,7 @@
CODE_SIGN_ENTITLEMENTS = AutofillCredentialProvider/AutofillCredentialProviderAlpha.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = HKE973VLUW;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -10416,7 +10568,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -10435,7 +10587,7 @@
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.alpha.CredentialExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
- "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.duckduckgo.mobile.ios.alpha.CredentialExtension";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.duckduckgo.mobile.ios.alpha.CredentialExtension";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -10455,7 +10607,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -10472,8 +10624,9 @@
);
LOCALIZATION_PREFERS_STRING_CATALOGS = NO;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.AutofillCredentialProvider;
+ PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.CredentialExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.duckduckgo.mobile.ios.CredentialExtension";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -10552,7 +10705,7 @@
CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
@@ -10583,7 +10736,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ShareExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -10611,7 +10764,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = OpenAction/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -10644,7 +10797,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = Widgets/Info.plist;
@@ -10674,7 +10827,7 @@
CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
@@ -10707,11 +10860,11 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 3;
+ DYLIB_CURRENT_VERSION = 0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Core/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -10943,7 +11096,7 @@
CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
@@ -10971,7 +11124,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -11003,7 +11156,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -11040,7 +11193,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
@@ -11075,7 +11228,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -11110,11 +11263,11 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 3;
+ DYLIB_CURRENT_VERSION = 0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Core/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -11286,11 +11439,11 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 3;
+ DYLIB_CURRENT_VERSION = 0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Core/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -11319,10 +11472,10 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 3;
+ CURRENT_PROJECT_VERSION = 0;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 3;
+ DYLIB_CURRENT_VERSION = 0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Core/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift
index 75296ae8ea..38ff685038 100644
--- a/DuckDuckGo/AppDelegate.swift
+++ b/DuckDuckGo/AppDelegate.swift
@@ -1108,7 +1108,7 @@ import os.log
autofillPixelReporter = AutofillPixelReporter(
userDefaults: .standard,
autofillEnabled: AppDependencyProvider.shared.appSettings.autofillCredentialsEnabled,
- eventMapping: EventMapping {event, _, params, _ in
+ eventMapping: EventMapping {[weak self] event, _, params, _ in
switch event {
case .autofillActiveUser:
Pixel.fire(pixel: .autofillActiveUser)
@@ -1118,8 +1118,16 @@ import os.log
Pixel.fire(pixel: .autofillOnboardedUser)
case .autofillToggledOn:
Pixel.fire(pixel: .autofillToggledOn, withAdditionalParameters: params ?? [:])
+ if let autofillExtensionToggled = self?.autofillUsageMonitor.autofillExtensionEnabled {
+ Pixel.fire(pixel: autofillExtensionToggled ? .autofillExtensionToggledOn : .autofillExtensionToggledOff,
+ withAdditionalParameters: params ?? [:])
+ }
case .autofillToggledOff:
Pixel.fire(pixel: .autofillToggledOff, withAdditionalParameters: params ?? [:])
+ if let autofillExtensionToggled = self?.autofillUsageMonitor.autofillExtensionEnabled {
+ Pixel.fire(pixel: autofillExtensionToggled ? .autofillExtensionToggledOn : .autofillExtensionToggledOff,
+ withAdditionalParameters: params ?? [:])
+ }
case .autofillLoginsStacked:
Pixel.fire(pixel: .autofillLoginsStacked, withAdditionalParameters: params ?? [:])
default:
diff --git a/DuckDuckGo/AutofillLoginPromptViewModel.swift b/DuckDuckGo/AutofillLoginPromptViewModel.swift
index da3a3e551a..4193ba26af 100644
--- a/DuckDuckGo/AutofillLoginPromptViewModel.swift
+++ b/DuckDuckGo/AutofillLoginPromptViewModel.swift
@@ -20,6 +20,7 @@
import Foundation
import UIKit
import BrowserServicesKit
+import Core
protocol AutofillLoginPromptViewModelDelegate: AnyObject {
func autofillLoginPromptViewModel(_ viewModel: AutofillLoginPromptViewModel, didSelectAccount account: SecureVaultModels.WebsiteAccount)
diff --git a/DuckDuckGo/AutofillUsageMonitor.swift b/DuckDuckGo/AutofillUsageMonitor.swift
index 4302aec266..5c9f9bf87f 100644
--- a/DuckDuckGo/AutofillUsageMonitor.swift
+++ b/DuckDuckGo/AutofillUsageMonitor.swift
@@ -18,13 +18,28 @@
//
import Core
+import AuthenticationServices
final class AutofillUsageMonitor {
init() {
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveSaveEvent), name: .autofillSaveEvent, object: nil)
+
+ ASCredentialIdentityStore.shared.getState({ state in
+ if state.isEnabled {
+ self.autofillExtensionEnabled = true
+ } else {
+ if self.autofillExtensionEnabled != nil {
+ Pixel.fire(pixel: .autofillExtensionDisabled)
+ self.autofillExtensionEnabled = false
+ }
+ }
+ })
}
-
+
+ @UserDefaultsWrapper(key: .autofillExtensionEnabled, defaultValue: nil)
+ var autofillExtensionEnabled: Bool?
+
@UserDefaultsWrapper(key: .autofillFirstTimeUser, defaultValue: true)
private var autofillFirstTimeUser: Bool
diff --git a/DuckDuckGo/DuckDuckGo.entitlements b/DuckDuckGo/DuckDuckGo.entitlements
index b798cc1099..ee77dff2bf 100644
--- a/DuckDuckGo/DuckDuckGo.entitlements
+++ b/DuckDuckGo/DuckDuckGo.entitlements
@@ -2,6 +2,8 @@
+ com.apple.developer.authentication-services.autofill-credential-provider
+
com.apple.developer.browser.app-installation
com.apple.developer.networking.networkextension
diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist
index c23b94b9bc..740cfbe9a5 100644
--- a/DuckDuckGo/Settings.bundle/Root.plist
+++ b/DuckDuckGo/Settings.bundle/Root.plist
@@ -6,7 +6,7 @@
DefaultValue
- 7.148.0
+ 7.149.0
Key
version
Title
diff --git a/DuckDuckGoTests/AutofillInterfaceEmailTruncatorTests.swift b/DuckDuckGoTests/AutofillInterfaceEmailTruncatorTests.swift
index c247ea0d97..a3d9340697 100644
--- a/DuckDuckGoTests/AutofillInterfaceEmailTruncatorTests.swift
+++ b/DuckDuckGoTests/AutofillInterfaceEmailTruncatorTests.swift
@@ -18,6 +18,7 @@
//
import XCTest
+import Core
@testable import DuckDuckGo
class AutofillInterfaceEmailTruncatorTests: XCTestCase {
diff --git a/adhocExportOptions.plist b/adhocExportOptions.plist
index 8af7edc154..de2b86d155 100644
--- a/adhocExportOptions.plist
+++ b/adhocExportOptions.plist
@@ -25,6 +25,9 @@
com.duckduckgo.mobile.ios.NetworkExtension
match AdHoc com.duckduckgo.mobile.ios.NetworkExtension
+
+ com.duckduckgo.mobile.ios.CredentialExtension
+ match AdHoc com.duckduckgo.mobile.ios.CredentialExtension
diff --git a/appStoreExportOptions.plist b/appStoreExportOptions.plist
index ff60631b5c..ed346823e8 100644
--- a/appStoreExportOptions.plist
+++ b/appStoreExportOptions.plist
@@ -18,6 +18,8 @@
match AppStore com.duckduckgo.mobile.ios.Widgets
com.duckduckgo.mobile.ios.NetworkExtension
match AppStore com.duckduckgo.mobile.ios.NetworkExtension
+ com.duckduckgo.mobile.ios.CredentialExtension
+ match AppStore com.duckduckgo.mobile.ios.CredentialExtension
diff --git a/fastlane/Matchfile b/fastlane/Matchfile
index 4212b95ef5..f577d97171 100644
--- a/fastlane/Matchfile
+++ b/fastlane/Matchfile
@@ -4,7 +4,7 @@ git_branch "ios"
platform "ios"
type "appstore"
-app_identifier ["com.duckduckgo.mobile.ios", "com.duckduckgo.mobile.ios.ShareExtension", "com.duckduckgo.mobile.ios.OpenAction2", "com.duckduckgo.mobile.ios.Widgets", "com.duckduckgo.mobile.ios.NetworkExtension"]
+app_identifier ["com.duckduckgo.mobile.ios", "com.duckduckgo.mobile.ios.ShareExtension", "com.duckduckgo.mobile.ios.OpenAction2", "com.duckduckgo.mobile.ios.Widgets", "com.duckduckgo.mobile.ios.NetworkExtension", "com.duckduckgo.mobile.ios.CredentialExtension"]
generate_apple_certs false
for_lane :sync_signing_adhoc do
@@ -21,7 +21,7 @@ end
for_lane :adhoc do
type "adhoc"
- app_identifier ["com.duckduckgo.mobile.ios.alpha", "com.duckduckgo.mobile.ios.alpha.ShareExtension", "com.duckduckgo.mobile.ios.alpha.OpenAction2", "com.duckduckgo.mobile.ios.alpha.Widgets", "com.duckduckgo.mobile.ios.alpha.NetworkExtension"]
+ app_identifier ["com.duckduckgo.mobile.ios.alpha", "com.duckduckgo.mobile.ios.alpha.ShareExtension", "com.duckduckgo.mobile.ios.alpha.OpenAction2", "com.duckduckgo.mobile.ios.alpha.Widgets", "com.duckduckgo.mobile.ios.alpha.NetworkExtension", "com.duckduckgo.mobile.ios.alpha.CredentialExtension"]
force_for_new_devices true
template_name "Default Web Browser iOS (Dist)"
end
@@ -40,11 +40,11 @@ for_lane :alpha_adhoc do
end
for_lane :sync_signing_alpha do
- app_identifier ["com.duckduckgo.mobile.ios.alpha", "com.duckduckgo.mobile.ios.alpha.ShareExtension", "com.duckduckgo.mobile.ios.alpha.OpenAction2", "com.duckduckgo.mobile.ios.alpha.Widgets", "com.duckduckgo.mobile.ios.alpha.NetworkExtension"]
+ app_identifier ["com.duckduckgo.mobile.ios.alpha", "com.duckduckgo.mobile.ios.alpha.ShareExtension", "com.duckduckgo.mobile.ios.alpha.OpenAction2", "com.duckduckgo.mobile.ios.alpha.Widgets", "com.duckduckgo.mobile.ios.alpha.NetworkExtension", "com.duckduckgo.mobile.ios.alpha.CredentialExtension"]
template_name "Default Web Browser iOS (Dist)"
end
for_lane :release_alpha do
- app_identifier ["com.duckduckgo.mobile.ios.alpha", "com.duckduckgo.mobile.ios.alpha.ShareExtension", "com.duckduckgo.mobile.ios.alpha.OpenAction2", "com.duckduckgo.mobile.ios.alpha.Widgets", "com.duckduckgo.mobile.ios.alpha.NetworkExtension"]
+ app_identifier ["com.duckduckgo.mobile.ios.alpha", "com.duckduckgo.mobile.ios.alpha.ShareExtension", "com.duckduckgo.mobile.ios.alpha.OpenAction2", "com.duckduckgo.mobile.ios.alpha.Widgets", "com.duckduckgo.mobile.ios.alpha.NetworkExtension", "com.duckduckgo.mobile.ios.alpha.CredentialExtension"]
template_name "Default Web Browser iOS (Dist)"
end
diff --git a/fastlane/metadata/default/release_notes.txt b/fastlane/metadata/default/release_notes.txt
index 098fd1666f..66b16c0810 100644
--- a/fastlane/metadata/default/release_notes.txt
+++ b/fastlane/metadata/default/release_notes.txt
@@ -1 +1 @@
-- Bug fixes and other improvements.
\ No newline at end of file
+- Bug fixes and other improvements
\ No newline at end of file