Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ public protocol ApplicationPasswordUseCase {
func deletePassword() async throws
}

/// A wrapper for the `UIDevice` `model` and `identifierForVendor` properties.
///
/// This is necessary because `UIDevice` is part of UIKit which we cannot use when targeting watchOS.
/// So, to keep this package compatible with watchOS, we need to abstract UIKit away and delegate it to the consumers to provide us
/// with the device information.
///
/// This approach is feasible because only the `applicationPasswordName` method in
/// `DefaultApplicationPasswordUseCase` needs access to the information and watchOS does not need to create application
/// passwords. We can therefore pass a `nil` value to it to satisfy the compilation without issues for the user experience.
public struct DeviceModelIdentifierInfo {
let model: String
let identifierForVendor: String

public init(model: String, identifierForVendor: String) {
self.model = model
self.identifierForVendor = identifierForVendor
}
}

final public class DefaultApplicationPasswordUseCase: ApplicationPasswordUseCase {
/// Site Address
///
Expand All @@ -46,30 +65,31 @@ final public class DefaultApplicationPasswordUseCase: ApplicationPasswordUseCase
///
private let storage: ApplicationPasswordStorage

private let deviceModelIdentifierInfo: DeviceModelIdentifierInfo?

/// Used to name the password in wpadmin.
///
private var applicationPasswordName: String {
get async {
#if !os(watchOS)
get {
guard let deviceModelIdentifierInfo else {
return "" // This is not needed on watchOS as the watch does not create application passwords.
}

let bundleIdentifier = Bundle.main.bundleIdentifier ?? "Unknown"
let model = await UIDevice.current.model
let identifierForVendor = await UIDevice.current.identifierForVendor?.uuidString ?? ""
return "\(bundleIdentifier).ios-app-client.\(model).\(identifierForVendor)"
#endif
#if os(watchOS)
return "" // This is not needed on watchOS as the watch does not create application passwords.
#endif
return "\(bundleIdentifier).ios-app-client.\(deviceModelIdentifierInfo.model).\(deviceModelIdentifierInfo.identifierForVendor)"
}
}

public init(username: String,
password: String,
siteAddress: String,
deviceModelIdentifierInfo: DeviceModelIdentifierInfo? = nil,
network: Network? = nil,
keychain: Keychain = Keychain(service: WooConstants.keychainServiceName)) throws {
self.siteAddress = siteAddress
self.username = username
self.storage = ApplicationPasswordStorage(keychain: keychain)
self.deviceModelIdentifierInfo = deviceModelIdentifierInfo

if let network {
self.network = network
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import KeychainAccess
import WordPressAuthenticator
import WordPressUI
import Yosemite
import UIKit
import class Networking.UserAgent
import enum Experiments.ABTest
import struct Networking.Settings
Expand Down Expand Up @@ -751,7 +752,8 @@ private extension AuthenticationManager {
guard let useCase = try? DefaultApplicationPasswordUseCase(
username: siteCredentials.username,
password: siteCredentials.password,
siteAddress: siteCredentials.siteURL
siteAddress: siteCredentials.siteURL,
deviceModelIdentifierInfo: UIDevice.current.deviceModelIdentifierInfo
) else {
return assertionFailure("⛔️ Error creating application password use case")
}
Expand Down
2 changes: 2 additions & 0 deletions WooCommerce/Classes/System/SessionManager.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Combine
import Foundation
import Yosemite
import UIKit
import KeychainAccess
import protocol Networking.ApplicationPasswordUseCase
import class Networking.OneTimeApplicationPasswordUseCase
Expand Down Expand Up @@ -233,6 +234,7 @@ final class SessionManager: SessionManagerProtocol {
return try? DefaultApplicationPasswordUseCase(username: username,
password: password,
siteAddress: siteAddress,
deviceModelIdentifierInfo: UIDevice.current.deviceModelIdentifierInfo,
keychain: keychain)
case let .applicationPassword(_, _, siteAddress):
return OneTimeApplicationPasswordUseCase(siteAddress: siteAddress, keychain: keychain)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Networking
import UIKit

extension UIDevice {

var deviceModelIdentifierInfo: DeviceModelIdentifierInfo {
DeviceModelIdentifierInfo(
model: model,
identifierForVendor: identifierForVendor?.uuidString ?? ""
)
}
}
4 changes: 4 additions & 0 deletions WooCommerce/WooCommerce.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,7 @@
3F58701F281B947E004F7556 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3F58701E281B947E004F7556 /* Main.storyboard */; };
3F587021281B9494004F7556 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3F587020281B9494004F7556 /* LaunchScreen.storyboard */; };
3F587026281B9C19004F7556 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3F587028281B9C19004F7556 /* InfoPlist.strings */; };
3F88EC3F2DF8D4BC0023A6F4 /* UIDevice+DeviceModelIdentifierInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F88EC3E2DF8D4BC0023A6F4 /* UIDevice+DeviceModelIdentifierInfo.swift */; };
3FA96DF42C94043200CDA78F /* Yosemite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FA96DF32C94043200CDA78F /* Yosemite.framework */; };
3FF314E126FC74450012E68E /* UITestsFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF314E026FC74450012E68E /* UITestsFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
3FF314EA26FC751B0012E68E /* XCTest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F997173223DBCF2800592D8E /* XCTest+Extensions.swift */; };
Expand Down Expand Up @@ -4509,6 +4510,7 @@
3F587037281B9C50004F7556 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3F587038281B9C52004F7556 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3F64F76C2C06A3A50085DEEF /* WooCommerce.release-alpha.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "WooCommerce.release-alpha.xcconfig"; sourceTree = "<group>"; };
3F88EC3E2DF8D4BC0023A6F4 /* UIDevice+DeviceModelIdentifierInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+DeviceModelIdentifierInfo.swift"; sourceTree = "<group>"; };
3FA96DF32C94043200CDA78F /* Yosemite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Yosemite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3FF314D626FC55DE0012E68E /* ScreenObject+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScreenObject+Extension.swift"; sourceTree = "<group>"; };
3FF314DE26FC74450012E68E /* UITestsFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UITestsFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -11131,6 +11133,7 @@
DE6906E627D74A1900735E3B /* WooSplitViewController.swift */,
26A7C8782BE91F3D00382627 /* WatchDependenciesSynchronizer.swift */,
26B249702BEC801400730730 /* WatchDependencies.swift */,
3F88EC3E2DF8D4BC0023A6F4 /* UIDevice+DeviceModelIdentifierInfo.swift */,
);
path = System;
sourceTree = "<group>";
Expand Down Expand Up @@ -16512,6 +16515,7 @@
02CE4304276993DA0006EAEF /* CaptureDevicePermissionChecker.swift in Sources */,
205B7ECD2C19FD2F00D14A36 /* PointOfSaleCardPresentPaymentDisplayReaderMessageMessageViewModel.swift in Sources */,
DEF8CF1F29AC870A00800A60 /* WPComEmailLoginViewModel.swift in Sources */,
3F88EC3F2DF8D4BC0023A6F4 /* UIDevice+DeviceModelIdentifierInfo.swift in Sources */,
74A33D8021C3F234009E25DE /* LicensesViewController.swift in Sources */,
454453CA27566CDE00464AC5 /* HubMenuViewModel.swift in Sources */,
934CB123224EAB150005CCB9 /* main.swift in Sources */,
Expand Down