Add magic code verification for card provisioning default contact method change#90004
Add magic code verification for card provisioning default contact method change#90004MelvinBot wants to merge 2 commits into
Conversation
… card provisioning Both the company card and Expensify card provisioning flows previously called setContactMethodAsDefault() directly when a validated email was submitted, allowing a default contact method change without any verification. This adds a magic code challenge step (sent to the current primary login) before allowing the change, closing the account takeover vector described in the linked issue. For the unvalidated email branch, the existing verify-work-email pages now navigate to the new confirmation page after the email is validated, instead of directly linking the card feed. When the submitted email already matches the current primary contact method, the magic code step is skipped since no default-login change is needed. Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
🦜 Polyglot Parrot! 🦜Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues: View the translation diffdiff --git a/src/languages/de.ts b/src/languages/de.ts
index c73eab89..e55f49aa 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -5198,8 +5198,9 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU
fromOtherWorkspaces: 'Aus anderen Workspaces',
addWorkEmail: 'Fügen Sie Ihre Arbeits-E-Mail hinzu',
addWorkEmailDescription: 'Bitte fügen Sie Ihre Arbeits-E-Mail hinzu, um vorhandene Feeds aus anderen Workspaces zu nutzen.',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'Lass uns überprüfen, ob du es bist',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) =>
+ `Bitte gib den magischen Code ein, der an ${primaryLogin} gesendet wurde, um die Änderung deiner Standard-Kontaktmethode zu bestätigen.`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'Kartendaten konnten nicht geladen werden',
workspaceFeedsCouldNotBeLoadedMessage:
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index d1f33469..10f896da 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -5208,8 +5208,9 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
fromOtherWorkspaces: "D'autres espaces de travail",
addWorkEmail: 'Ajoutez votre adresse e-mail professionnelle',
addWorkEmailDescription: "Veuillez ajouter votre e-mail professionnel pour utiliser les flux existants d'autres espaces de travail.",
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'Vérifions que c’est bien vous',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) =>
+ `Veuillez saisir le code magique envoyé à ${primaryLogin} pour confirmer la modification de votre méthode de contact par défaut.`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'Impossible de charger les flux de cartes',
workspaceFeedsCouldNotBeLoadedMessage:
diff --git a/src/languages/it.ts b/src/languages/it.ts
index e56dbe1b..65ad2d05 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -5183,8 +5183,9 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST.
fromOtherWorkspaces: 'Da altri spazi di lavoro',
addWorkEmail: 'Aggiungi la tua email di lavoro',
addWorkEmailDescription: 'Aggiungi la tua email di lavoro per utilizzare i feed esistenti di altri spazi di lavoro.',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'Verifichiamo che tu sia tu',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) =>
+ `Inserisci il codice magico inviato a ${primaryLogin} per confermare la modifica del tuo metodo di contatto predefinito.`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'Impossibile caricare i feed della carta',
workspaceFeedsCouldNotBeLoadedMessage:
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index bade5697..f0a02aa2 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -5137,8 +5137,8 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO
fromOtherWorkspaces: '他のワークスペースから',
addWorkEmail: 'あなたの勤務用メールアドレスを追加',
addWorkEmailDescription: '他のワークスペースの既存フィードを使用するには、勤務用メールアドレスを追加してください。',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'ご本人確認を行います',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `デフォルトの連絡方法を変更するために、${primaryLogin} に送信されたマジックコードを入力してください。`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'カードフィードを読み込めませんでした',
workspaceFeedsCouldNotBeLoadedMessage: 'ワークスペースカードフィードの読み込み中にエラーが発生しました。もう一度お試しいただくか、管理者にお問い合わせください。',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 7439c9e7..6bb5b774 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -5175,8 +5175,9 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_
fromOtherWorkspaces: 'Uit andere workspaces',
addWorkEmail: 'Voeg je werkmail toe',
addWorkEmailDescription: 'Voeg je werkmail toe om bestaande feeds van andere workspaces te gebruiken.',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'Laten we verifiëren dat jij het bent',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) =>
+ `Voer de magische code in die naar ${primaryLogin} is gestuurd om het wijzigen van je standaardcontactmethode te bevestigen.`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'Kaartfeeds konden niet worden geladen',
workspaceFeedsCouldNotBeLoadedMessage: 'Er is een fout opgetreden bij het laden van workspacekaartfeeds. Probeer het opnieuw of neem contact op met je beheerder.',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 1c3cff84..b87e5f3a 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -5167,8 +5167,8 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy
fromOtherWorkspaces: 'Z innych przestrzeni roboczych',
addWorkEmail: 'Dodaj swój służbowy e-mail',
addWorkEmailDescription: 'Dodaj swój służbowy e-mail, aby korzystać z istniejących kanałów z innych przestrzeni roboczych.',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'Zweryfikujmy, czy to na pewno Ty',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Wpisz magiczny kod wysłany na ${primaryLogin}, aby potwierdzić zmianę domyślnej metody kontaktu.`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'Nie można wczytać kanałów kart',
workspaceFeedsCouldNotBeLoadedMessage: 'Wystąpił błąd podczas ładowania kanałów kart w przestrzeni roboczej. Spróbuj ponownie lub skontaktuj się ze swoim administratorem.',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index a0d35b8e..0c9acf13 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -5169,8 +5169,8 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS
fromOtherWorkspaces: 'De outros workspaces',
addWorkEmail: 'Adicione seu e-mail de trabalho',
addWorkEmailDescription: 'Adicione seu e-mail de trabalho para usar os feeds existentes de outros workspaces.',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: 'Vamos verificar se é você',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Insira o código mágico enviado para ${primaryLogin} para confirmar a alteração do seu método de contato padrão.`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: 'Não foi possível carregar os feeds do cartão',
workspaceFeedsCouldNotBeLoadedMessage: 'Ocorreu um erro ao carregar os feeds de cartões do workspace. Tente novamente ou contate o seu administrador.',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 014a7d56..81d2d25a 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -5053,8 +5053,8 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
fromOtherWorkspaces: '来自其他工作区',
addWorkEmail: '添加您的工作邮箱',
addWorkEmailDescription: '请添加您的工作邮箱以使用其他工作区的现有流水。',
- confirmDefaultContactMethod: "Let's verify it's you",
- enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `Please enter the magic code sent to ${primaryLogin} to confirm changing your default contact method.`,
+ confirmDefaultContactMethod: '让我们验证一下你的身份',
+ enterMagicCodeDefaultContactMethod: (primaryLogin: string) => `请输入发送到 ${primaryLogin} 的魔法验证码,以确认更改您的默认联系方式。`,
error: {
workspaceFeedsCouldNotBeLoadedTitle: '无法加载卡片流水',
workspaceFeedsCouldNotBeLoadedMessage: '加载工作区卡片动态时发生错误。请重试或联系管理员。',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
|
@shubham1206agra are you helping MelvinBot take this one across the finish line? |
|
@MelvinBot I think you forgot to implement #89121 (comment) |
|
Hi
Could you clarify what you think is missing? Happy to make any adjustments needed. |
|
@MelvinBot If the isWorkEmailValidated is false, what will happen? Will I see the validation flow once or twice? |
|
Twice. When
This is intentional per the proposal — the first code proves you own the new email, the second code proves you own the current primary (preventing a bad actor from silently promoting a planted email). |
|
@MelvinBot Merge main please |
…deForCardProvisioning Co-authored-by: Shubham Agrawal <shubham1206agra@users.noreply.github.com>
|
✅ Merged main into this branch successfully. |
|
@MelvinBot Why am I seeing the code to the same email when I try to enter unverified work email? |
|
The The confirmation page also displays the updated The fix: The confirmation page needs to send the magic code to the original primary login (before
The same issue applies to both the company card and Expensify card confirmation pages. |
I think this should be fixed on the frontend. Rather then sending I wouldn't advise changing the backend for this because it is used for many different flows. |
Explanation of Change
Both the company card and Expensify card provisioning flows previously called
setContactMethodAsDefault()directly when a user submitted a validated secondary email — no magic code verification was required. A bad actor who planted their email as a validated secondary contact method could exploit this to silently promote it to primary, intercepting all future magic codes.This PR adds a magic code verification step (sent to the current primary login via
requestValidateCodeAction()) before allowing the default contact method change. Two new RHP pages are introduced — one for company cards and one for Expensify cards — that renderValidateCodeActionContentand only callsetContactMethodAsDefault(email, validateCode)after the user enters the code.Both the "already validated email" branch (from the add-work-email pages) and the "newly validated email" branch (from the verify-work-account pages) now converge on the new confirmation page before the default contact method is changed. When the submitted email already matches the current primary, the magic code step is skipped since no default-login change is needed.
Fixed Issues
$ #89121
PROPOSAL: #89121 (comment)
Tests
// TODO: The human co-author must fill out the tests you ran before marking this PR as "ready for review"
// Please describe what tests you performed that validates your changed worked.
Offline tests
// TODO: The human co-author must fill out the offline tests before marking this PR as "ready for review"
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Screenshots/Videosundefined