Files

4.4 KiB

OTP Screen

Displays the current TOTP (Time-based One-Time Password) code for each enrolled bank authenticator. Used when confirming transfers, QR payments, or other 2FA-protected operations.


Fragment — OtpFragment

Hosts one card per enrolled bank authenticator. Banks with no stored TOTP seed are not shown.


TOTP Display

Each card shows:

  • Bank logo, bank name and account holder name
  • A circular countdown ring with the seconds left in the current 30-second window; the ring and code turn red in the last 5 seconds
  • The current 6-digit TOTP code (large text) with a copy button
  • The next window's code (smaller, below a divider) with its own copy button — handy when the current code is about to expire
  • The codes refresh automatically when the window expires — no user interaction needed

Tapping anywhere on the card also copies the current code. If no logins have a seed, an empty-state message is shown instead.


Seed Actions

Long-pressing a card opens a menu with:

Export seed

A dialog titled {bank} · {name} showing:

  • A QR code of a minimal otpauth://totp/{BANK}?secret=… link (e.g. otpauth://totp/BML?secret=…), always drawn black-on-white so it scans in dark mode. No username or issuer is included, and algorithm, digits and period are left out because SHA1, 6 and 30s are the spec defaults. Export is single-account only; otpauth-migration:// is supported for import but never produced.
  • The Base32 seed in groups of 4 (selectable text)
  • A Copy seed button. The copy is flagged EXTRA_IS_SENSITIVE, so Android 13+ hides the value in the clipboard preview.

Update seed

Replaces the stored seed for that login, e.g. after re-enrolling the authenticator with the bank.

  • A red warning banner explains that the old seed is deleted permanently.
  • The new seed can be typed or pasted (raw Base32 or an otpauth:// link) or scanned with the QR button. Scans that contain several accounts (otpauth-migration://) ask which one to use.
  • Once the input is a valid seed, a live preview shows its current and next code with a countdown so the user can check it against the bank before saving. The preview is the same card as the sign-in screen (view_otp_preview.xml, shared by both), and tapping it copies the code. Input that isn't valid Base32, is shorter than 8 characters (such as a pasted 6-digit code), or matches the current seed disables Replace.
  • Replace asks for confirmation ("Delete old seed?"). Confirming calls CredentialStore.updateMibOtpSeed() / updateBmlOtpSeed(), which overwrite only the encrypted seed. For MIB it also calls MibLoginFlow.updateOtpSeed() so silent re-login uses the new seed.

The username, password and sessions are not touched. Other places that need an OTP (transfers, QR pay, pay with card) read the seed from CredentialStore each time, so they pick up the new seed immediately.

Algorithm

Standard RFC 6238 TOTP:

  • Hash: SHA-1
  • Window: 30 seconds
  • Digits: 6
  • Seed: stored per-bank in CredentialStore (encrypted)

Supported Banks

One card is rendered for every MIB and every BML login that has a stored OTP seed (OtpFragment.kt), sorted by the user's login order. Seeds are per-loginId in CredentialStore.

Bank Seed source Card title / subtitle
MIB loadMibCredentials(loginId).otpSeed (entered at login) MIB / {fullName}
BML loadBmlCredentials(loginId).otpSeed (entered at login) BML / {fullName}

If no full name has been cached the subtitle falls back to "Authenticator" and a background MibProfileClient.fetchPersonalProfile() / BmlAccountClient.fetchUserInfo() call refreshes it.


Background Name Refresh

When the screen opens, the fragment may fire a background API call to refresh the account holder name associated with each seed. This is a best-effort call — failure does not affect OTP display.


Usage

The OTP screen is informational — the user copies the displayed code manually and enters it wherever required (e.g., in TransferFragment's OTP dialog, or in an external portal). The code is never submitted automatically from this screen.


Security

The TOTP seeds are stored encrypted in CredentialStore. They are never logged or included in error reports. They leave the app only when the user chooses Export seed.


 


← Activities     Next → PayMV QR Screen