Skip to content

Commit 1d619c0

Browse files
committed
[PM-32009] polish: add bank account icon and tighten foundation gating
Relies solely on the `newItemTypes` feature flag to gate bank account creation end-to-end. Adds the final PM-34128 bank account icon asset.
1 parent 75c5496 commit 1d619c0

26 files changed

Lines changed: 93 additions & 560 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "bank-account24.pdf",
5+
"idiom" : "universal"
6+
}
7+
],
8+
"info" : {
9+
"author" : "xcode",
10+
"version" : 1
11+
},
12+
"properties" : {
13+
"preserves-vector-representation" : true,
14+
"template-rendering-intent" : "template"
15+
}
16+
}
Binary file not shown.

BitwardenResources/Localizations/en.lproj/Localizable.strings

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,9 +1084,4 @@
10841084
"ToManageYourPremiumSubscriptionDescriptionLong" = "To manage your Premium subscription, please log in to your web vault on a computer.";
10851085
"CheckYourConnectionAndTryAgain" = "Check your connection and try again.";
10861086
"PricingUnavailable" = "Pricing unavailable";
1087-
1088-
/* PM-32009: New Item Types — Bank Account (Part 1/3 type-level keys)
1089-
Field labels, account-type display names, and processor alert strings are added
1090-
in PM-32809 Part 2/3 and Part 3/3 as the UI surfaces that consume them land. */
1091-
"TypeBankAccount" = "Bank account";
1092-
"ViewBankAccount" = "View bank account";
1087+
"BankAccount" = "Bank account";

BitwardenShared/Core/Vault/Extensions/BitwardenSdk+NewItemTypes.swift

Lines changed: 0 additions & 81 deletions
This file was deleted.

BitwardenShared/Core/Vault/Extensions/BitwardenSdk+Vault.swift

Lines changed: 7 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,10 @@ extension CipherCardModel {
6060
extension CipherDetailsResponseModel {
6161
init(cipher: BitwardenSdk.Cipher) throws {
6262
guard let id = cipher.id else { throw DataMappingError.invalidData }
63-
// TODO: PM-32009 Blocked on SDK — map cipher.bankAccount to CipherBankAccountModel once
64-
// BitwardenSdk.Cipher exposes a `bankAccount: BankAccount?` property.
65-
let bankAccount: CipherBankAccountModel? = nil
6663
self.init(
6764
archivedDate: cipher.archivedDate,
6865
attachments: cipher.attachments?.map(AttachmentResponseModel.init),
69-
bankAccount: bankAccount,
66+
bankAccount: nil,
7067
card: cipher.card.map(CipherCardModel.init),
7168
collectionIds: cipher.collectionIds,
7269
creationDate: cipher.creationDate,
@@ -89,10 +86,7 @@ extension CipherDetailsResponseModel {
8986
revisionDate: cipher.revisionDate,
9087
secureNote: cipher.secureNote.map(CipherSecureNoteModel.init),
9188
sshKey: cipher.sshKey.map(CipherSSHKeyModel.init),
92-
// Unknown SDK cipher types fall back to `.secureNote` on decode so
93-
// pre-PM-32813 users see an opaque item rather than a crash. The
94-
// backward-compat PR formalizes the "Unknown" display story.
95-
type: BitwardenShared.CipherType(type: cipher.type) ?? .secureNote,
89+
type: BitwardenShared.CipherType(type: cipher.type),
9690
viewPassword: cipher.viewPassword,
9791
)
9892
}
@@ -224,16 +218,7 @@ extension CipherSSHKeyModel {
224218
}
225219

226220
extension CipherType {
227-
/// Creates an app-layer `CipherType` from a `BitwardenSdk.CipherType`.
228-
///
229-
/// Fails (`nil`) when the SDK value is unknown to the app — either a future SDK case
230-
/// not yet mapped (e.g., `.bankAccount` while PM-32009 SDK work is pending) or a
231-
/// later SDK bump that adds unmapped cases. Callers must handle `nil` rather than
232-
/// assume an exhaustive mapping.
233-
///
234-
/// - Parameter type: The SDK cipher type to bridge into the app layer.
235-
///
236-
init?(type: BitwardenSdk.CipherType) {
221+
init(type: BitwardenSdk.CipherType) {
237222
switch type {
238223
case .card:
239224
self = .card
@@ -245,26 +230,10 @@ extension CipherType {
245230
self = .secureNote
246231
case .sshKey:
247232
self = .sshKey
248-
@unknown default:
249-
// Route through the centralized bridge so PM-32009 and future new-type
250-
// PRs flip a single switch (`NewItemTypesSdkBridge.isBankAccountAvailable`
251-
// et al.) rather than updating call sites.
252-
if let mapped = NewItemTypesSdkBridge.appCipherTypeForBankAccount(type) {
253-
self = mapped
254-
return
255-
}
256-
return nil
257233
}
258234
}
259235

260-
/// Creates an app-layer `CipherType` from a `BitwardenSdk.CipherListViewType`.
261-
///
262-
/// Fails (`nil`) when the SDK value is unknown — see `init?(type:)` above for
263-
/// rationale.
264-
///
265-
/// - Parameter type: The SDK list view type to bridge into the app layer.
266-
///
267-
init?(_ type: BitwardenSdk.CipherListViewType) {
236+
init(_ type: BitwardenSdk.CipherListViewType) {
268237
switch type {
269238
case .card:
270239
self = .card
@@ -276,12 +245,6 @@ extension CipherType {
276245
self = .secureNote
277246
case .sshKey:
278247
self = .sshKey
279-
@unknown default:
280-
if NewItemTypesSdkBridge.isBankAccountListViewType(type) {
281-
self = .bankAccount
282-
return
283-
}
284-
return nil
285248
}
286249
}
287250
}
@@ -374,12 +337,7 @@ extension BitwardenSdk.Cipher {
374337
key: model.key,
375338
name: model.name,
376339
notes: model.notes,
377-
// Fails closed when the app-layer `model.type` is not yet supported by
378-
// the SDK (e.g., `.bankAccount` before PM-32009 SDK readiness). The
379-
// `.secureNote` fallback is defensive only — the repository / save flow
380-
// must reject unsupported types upstream; an `assertionFailure` in
381-
// `BitwardenSdk.CipherType.init?(_:)` trips in Debug if reached.
382-
type: BitwardenSdk.CipherType(model.type) ?? .secureNote,
340+
type: BitwardenSdk.CipherType(model.type),
383341
login: model.login.map(Login.init),
384342
identity: model.identity.map(Identity.init),
385343
card: model.card.map(Card.init),
@@ -424,12 +382,7 @@ extension BitwardenSdk.Cipher {
424382
key: model.key,
425383
name: model.name,
426384
notes: model.notes,
427-
// Fails closed when the app-layer `model.type` is not yet supported by
428-
// the SDK (e.g., `.bankAccount` before PM-32009 SDK readiness). The
429-
// `.secureNote` fallback is defensive only — the repository / save flow
430-
// must reject unsupported types upstream; an `assertionFailure` in
431-
// `BitwardenSdk.CipherType.init?(_:)` trips in Debug if reached.
432-
type: BitwardenSdk.CipherType(model.type) ?? .secureNote,
385+
type: BitwardenSdk.CipherType(model.type),
433386
login: model.login.map(Login.init),
434387
identity: model.identity.map(Identity.init),
435388
card: model.card.map(Card.init),
@@ -543,19 +496,7 @@ extension BitwardenSdk.CipherView: @retroactive Identifiable, Fido2UserVerifiabl
543496
}
544497

545498
extension BitwardenSdk.CipherType {
546-
/// Creates a `BitwardenSdk.CipherType` from an app-layer `CipherType`.
547-
///
548-
/// Fails (`nil`) when the app-layer value cannot be represented in the SDK yet —
549-
/// currently `.bankAccount`, until PM-32009 SDK work lands. This initializer
550-
/// **never** silently coerces an unsupported app type to another SDK case; silent
551-
/// coercion would cause data loss on save.
552-
///
553-
/// Call sites must handle `nil` (fail the save, surface a clear error) rather than
554-
/// treat this as infallible.
555-
///
556-
/// - Parameter cipherType: The app-layer type to bridge.
557-
///
558-
init?(_ cipherType: CipherType) {
499+
init(_ cipherType: CipherType) {
559500
switch cipherType {
560501
case .login:
561502
self = .login
@@ -567,26 +508,6 @@ extension BitwardenSdk.CipherType {
567508
self = .identity
568509
case .sshKey:
569510
self = .sshKey
570-
case .bankAccount:
571-
// Route through the centralized bridge. When the SDK lands support,
572-
// `NewItemTypesSdkBridge.sdkCipherTypeForBankAccount()` returns the real
573-
// SDK case and this branch succeeds. Until then, it returns `nil` and we
574-
// fail closed — no silent coercion.
575-
guard let mapped = NewItemTypesSdkBridge.sdkCipherTypeForBankAccount() else {
576-
// Tripwire: in Debug builds, surface accidental enabling of the
577-
// feature flag before SDK readiness so the divergence is caught in
578-
// development rather than producing corrupted saves. Release builds
579-
// fail closed via `return nil` immediately below.
580-
assertionFailure(
581-
"BitwardenSdk.CipherType.init(_:) called with .bankAccount before the SDK " +
582-
"exposes BankAccount support. Did the newItemTypes feature flag get " +
583-
"enabled ahead of SDK readiness? Fix: keep the flag off until the SDK " +
584-
"dependency is bumped and NewItemTypesSdkBridge.isBankAccountAvailable " +
585-
"is set to true. See PM-32009.",
586-
)
587-
return nil
588-
}
589-
self = mapped
590511
}
591512
}
592513
}
Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,12 @@
11
/// API model for a bank account cipher.
22
///
3-
/// Every field defaults to `nil` so callers can use the synthesized memberwise init
4-
/// conveniently and so the JSON payload minimizes absent fields.
5-
///
6-
/// - Important: Instances of this model are **never** to be serialized directly to a
7-
/// request body reaching the server. All persisted bank account data must pass
8-
/// through the `BitwardenSdk` encryption path (`CipherView.bankAccount` /
9-
/// `Cipher.bankAccount` once the SDK exposes those types). This model is strictly an
10-
/// intermediate representation for JSON round-tripping when the SDK is not yet
11-
/// available (TODO: PM-32009 Blocked on SDK). See the serialization tripwire in
12-
/// `BankAccountItemState.apiModel`.
13-
///
143
struct CipherBankAccountModel: Codable, Equatable, Sendable {
154
// MARK: Properties
165

17-
/// The account number (sensitive; rendered as a hidden field in the UI).
6+
/// The account number.
187
let accountNumber: String?
198

20-
/// The type of the bank account (e.g., checking, savings).
9+
/// The type of the bank account.
2110
let accountType: BankAccountType?
2211

2312
/// The name of the bank.
@@ -35,53 +24,12 @@ struct CipherBankAccountModel: Codable, Equatable, Sendable {
3524
/// The name on the account.
3625
let nameOnAccount: String?
3726

38-
/// The personal identification number (sensitive; rendered as a hidden field in the UI).
27+
/// The personal identification number.
3928
let pin: String?
4029

4130
/// The routing number of the bank.
4231
let routingNumber: String?
4332

4433
/// The SWIFT / BIC code of the bank.
4534
let swiftCode: String?
46-
47-
// MARK: Initialization
48-
49-
/// Creates a new `CipherBankAccountModel`. All parameters default to `nil` so
50-
/// callers can build minimal payloads without listing every field.
51-
///
52-
/// - Parameters:
53-
/// - accountNumber: The account number (sensitive).
54-
/// - accountType: The bank account type.
55-
/// - bankName: The name of the bank.
56-
/// - bankPhone: The bank contact phone number.
57-
/// - branchNumber: The branch number of the bank.
58-
/// - iban: The IBAN.
59-
/// - nameOnAccount: The name on the account.
60-
/// - pin: The personal identification number (sensitive).
61-
/// - routingNumber: The routing number.
62-
/// - swiftCode: The SWIFT / BIC code.
63-
///
64-
init(
65-
accountNumber: String? = nil,
66-
accountType: BankAccountType? = nil,
67-
bankName: String? = nil,
68-
bankPhone: String? = nil,
69-
branchNumber: String? = nil,
70-
iban: String? = nil,
71-
nameOnAccount: String? = nil,
72-
pin: String? = nil,
73-
routingNumber: String? = nil,
74-
swiftCode: String? = nil,
75-
) {
76-
self.accountNumber = accountNumber
77-
self.accountType = accountType
78-
self.bankName = bankName
79-
self.bankPhone = bankPhone
80-
self.branchNumber = branchNumber
81-
self.iban = iban
82-
self.nameOnAccount = nameOnAccount
83-
self.pin = pin
84-
self.routingNumber = routingNumber
85-
self.swiftCode = swiftCode
86-
}
8735
}

0 commit comments

Comments
 (0)