Skip to content

2FA: Standalone 2FA Form#394

Merged
giorgikh93 merged 6 commits intotetherto:mainfrom
giorgikh93:create-otp
May 7, 2026
Merged

2FA: Standalone 2FA Form#394
giorgikh93 merged 6 commits intotetherto:mainfrom
giorgikh93:create-otp

Conversation

@giorgikh93
Copy link
Copy Markdown
Contributor

@giorgikh93 giorgikh93 commented May 7, 2026

Requirements

2FA: otp create record

Changes

  • add new screen for otp creation

Testing Notes

  • Tested on android emulator
  • Tested on real physical ios device

Things reviewers should pay attention to

Screenshots/Recordings

Screen.Recording.2026-05-07.at.11.22.08.mov

dependencies


@giorgikh93
Copy link
Copy Markdown
Contributor Author

@nickgr2 please review

Copy link
Copy Markdown

@nickgr2 nickgr2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues to address, plus a few minor cleanups.

note is required where peer screens make it optional

src/screens/CreateRecord/v2/CreateOrEditAuthenticatorContent.tsx:95

note: Validator.string().required(t`Comment is required`)

The empty-state branch (line 285) renders a single InputField whose onChangeText is handleFirstCustomFieldChange. The first keystroke pushes [{ type: 'note', note: 'x' }], which switches the render to the mapped branch. The trash button only renders for customFieldsList.length > 1, so the user cannot remove that single entry — only clear it. Once cleared, validation fails on submit and the user has no escape other than retyping something.

Peer screens use note: Validator.string() (not required) — see CreateOrEditCustomContent.tsx:103 and CreateOrEditLoginContent.tsx:144. Match that pattern.

HeaderV2.tsx branch checks the prop, not the parameter

src/containers/Header/HeaderV2.tsx:42

const handleCreateRecord = (type: string) => {
  if (type === 'password') { ... }
  if (recordType === RECORD_TYPES.OTP) {
    navigation.navigate('CreateRecord', { recordType: RECORD_TYPES.OTP })
    return
  }
  navigation.navigate('CreateRecord', { recordType: type })
}

The original branch checked the type parameter (type === 'authenticator'); the new branch checks the screen-level recordType prop. With the current call sites (addItemButton passes recordType; the context menu passes the user's selection, now RECORD_TYPES.OTP), the fallthrough at line 47 produces the same navigation, so the branch is dead. Either remove it, or change to type === RECORD_TYPES.OTP to mirror the previous line and keep the file consistent.

Minor

  • minor: src/screens/Authenticator/index.jsx:10-16 — two consecutive import statements from @tetherto/pearpass-lib-vault. Merge into one.
  • minor: src/screens/CreateRecord/v2/CreateOrEditAuthenticatorContent.tsx:276aria-label="Delete note" is the only user-facing string in the file not localized. Use aria-label={t\Delete note`}`.
  • minor: src/types/pearpass-lib-vault.d.ts:6OTP: "otp", uses double quotes and a trailing comma; every other entry uses single quotes and no trailing comma. Match the surrounding style.
  • minor: src/screens/CreateRecord/v2/CreateOrEditAuthenticatorContent.tsx:125initialRecord: initialRecord as object cast isn't needed. useGetMultipleFiles is JS with JSDoc Object; peer screens pass initialRecord directly.
  • src/screens/CreateRecord/v2/CreateOrEditAuthenticatorContent.tsx:92otpSecret: Validator.string() allows saving a "Standalone 2FA" record with no secret. Such a record won't appear in the Authenticator listing (r.otpPublic is null on submit). Is this intentional (user pre-creates the entry and pastes later), or should the secret be required?

@giorgikh93
Copy link
Copy Markdown
Contributor Author

@nickgr2 I've addressed your points, please review

Copy link
Copy Markdown

@nickgr2 nickgr2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two main issues from the last round are addressed (note field made optional, dead HeaderV2 branch removed). The two import/style nits are also addressed.

Withdrawing the aria-label nit — CreateOrEditCustomContent.tsx:305 uses the same unlocalized pattern, so this PR is consistent with the rest of the codebase.

Two open items, neither blocking:

  • src/screens/CreateRecord/v2/CreateOrEditAuthenticatorContent.tsx:125initialRecord as object cast still present; peer screens (e.g. CreateOrEditCustomContent.tsx:133) pass initialRecord to useGetMultipleFiles directly. The AuthenticatorRecord type already satisfies object, so the cast is redundant.
  • The empty-otpSecret question from the prior round wasn't answered — saving submits as RECORD_TYPES.LOGIN with otpInput undefined, which means a "Standalone 2FA" entry can be created without a secret and won't appear in the Authenticator listing. If that's the intended UX (entry now, paste secret later), no change needed; flagging in case it isn't.

Approving — these can land separately.

boris91
boris91 previously approved these changes May 7, 2026
@giorgikh93 giorgikh93 merged commit 0191b33 into tetherto:main May 7, 2026
0 of 2 checks passed
@giorgikh93 giorgikh93 deleted the create-otp branch May 7, 2026 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants