fix(app): add masking of phones to settings
This commit is contained in:
parent
a129b162b7
commit
2db53689a1
@ -37,6 +37,7 @@ const AccountSecurityTab: React.FC = observer(() => {
|
|||||||
const {t} = useLingui();
|
const {t} = useLingui();
|
||||||
const user = UserStore.currentUser;
|
const user = UserStore.currentUser;
|
||||||
const [showMaskedEmail, setShowMaskedEmail] = useState(false);
|
const [showMaskedEmail, setShowMaskedEmail] = useState(false);
|
||||||
|
const [showMaskedPhone, setShowMaskedPhone] = useState(false);
|
||||||
const [passkeys, setPasskeys] = useState<Array<UserActionCreators.WebAuthnCredential>>([]);
|
const [passkeys, setPasskeys] = useState<Array<UserActionCreators.WebAuthnCredential>>([]);
|
||||||
const [loadingPasskeys, setLoadingPasskeys] = useState(false);
|
const [loadingPasskeys, setLoadingPasskeys] = useState(false);
|
||||||
const [enablingSmsMfa, setEnablingSmsMfa] = useState(false);
|
const [enablingSmsMfa, setEnablingSmsMfa] = useState(false);
|
||||||
@ -100,9 +101,11 @@ const AccountSecurityTab: React.FC = observer(() => {
|
|||||||
loadingPasskeys={loadingPasskeys}
|
loadingPasskeys={loadingPasskeys}
|
||||||
enablingSmsMfa={enablingSmsMfa}
|
enablingSmsMfa={enablingSmsMfa}
|
||||||
disablingSmsMfa={disablingSmsMfa}
|
disablingSmsMfa={disablingSmsMfa}
|
||||||
|
showMaskedPhone={showMaskedPhone}
|
||||||
loadPasskeys={loadPasskeys}
|
loadPasskeys={loadPasskeys}
|
||||||
setEnablingSmsMfa={setEnablingSmsMfa}
|
setEnablingSmsMfa={setEnablingSmsMfa}
|
||||||
setDisablingSmsMfa={setDisablingSmsMfa}
|
setDisablingSmsMfa={setDisablingSmsMfa}
|
||||||
|
setShowMaskedPhone={setShowMaskedPhone}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export const AccountSecurityInlineTab = observer(() => {
|
|||||||
const {t} = useLingui();
|
const {t} = useLingui();
|
||||||
const user = UserStore.currentUser;
|
const user = UserStore.currentUser;
|
||||||
const [showMaskedEmail, setShowMaskedEmail] = useState(false);
|
const [showMaskedEmail, setShowMaskedEmail] = useState(false);
|
||||||
|
const [showMaskedPhone, setShowMaskedPhone] = useState(false);
|
||||||
const [passkeys, setPasskeys] = useState<Array<UserActionCreators.WebAuthnCredential>>([]);
|
const [passkeys, setPasskeys] = useState<Array<UserActionCreators.WebAuthnCredential>>([]);
|
||||||
const [loadingPasskeys, setLoadingPasskeys] = useState(false);
|
const [loadingPasskeys, setLoadingPasskeys] = useState(false);
|
||||||
const [enablingSmsMfa, setEnablingSmsMfa] = useState(false);
|
const [enablingSmsMfa, setEnablingSmsMfa] = useState(false);
|
||||||
@ -89,9 +90,11 @@ export const AccountSecurityInlineTab = observer(() => {
|
|||||||
loadingPasskeys={loadingPasskeys}
|
loadingPasskeys={loadingPasskeys}
|
||||||
enablingSmsMfa={enablingSmsMfa}
|
enablingSmsMfa={enablingSmsMfa}
|
||||||
disablingSmsMfa={disablingSmsMfa}
|
disablingSmsMfa={disablingSmsMfa}
|
||||||
|
showMaskedPhone={showMaskedPhone}
|
||||||
loadPasskeys={loadPasskeys}
|
loadPasskeys={loadPasskeys}
|
||||||
setEnablingSmsMfa={setEnablingSmsMfa}
|
setEnablingSmsMfa={setEnablingSmsMfa}
|
||||||
setDisablingSmsMfa={setDisablingSmsMfa}
|
setDisablingSmsMfa={setDisablingSmsMfa}
|
||||||
|
setShowMaskedPhone={setShowMaskedPhone}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
<SettingsSection id="danger_zone" title={t`Danger Zone`}>
|
<SettingsSection id="danger_zone" title={t`Danger Zone`}>
|
||||||
|
|||||||
@ -97,6 +97,48 @@
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phoneRow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.phoneRow {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneText {
|
||||||
|
color: var(--text-primary-muted);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneTextSelectable {
|
||||||
|
user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleButton {
|
||||||
|
margin-top: 0.1em;
|
||||||
|
text-align: left;
|
||||||
|
color: var(--text-link);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleButton:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.toggleButton {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.claimButton {
|
.claimButton {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,15 @@ import type React from 'react';
|
|||||||
|
|
||||||
const logger = new Logger('SecurityTab');
|
const logger = new Logger('SecurityTab');
|
||||||
|
|
||||||
|
const maskPhone = (phone: string): string => {
|
||||||
|
if (phone.length <= 4) {
|
||||||
|
return phone.replace(/./g, '*');
|
||||||
|
}
|
||||||
|
const lastTwo = phone.slice(-2);
|
||||||
|
const masked = phone.slice(0, -2).replace(/\d/g, '*');
|
||||||
|
return `${masked}${lastTwo}`;
|
||||||
|
};
|
||||||
|
|
||||||
interface SecurityTabProps {
|
interface SecurityTabProps {
|
||||||
user: UserRecord;
|
user: UserRecord;
|
||||||
isClaimed: boolean;
|
isClaimed: boolean;
|
||||||
@ -51,9 +60,11 @@ interface SecurityTabProps {
|
|||||||
loadingPasskeys: boolean;
|
loadingPasskeys: boolean;
|
||||||
enablingSmsMfa: boolean;
|
enablingSmsMfa: boolean;
|
||||||
disablingSmsMfa: boolean;
|
disablingSmsMfa: boolean;
|
||||||
|
showMaskedPhone: boolean;
|
||||||
loadPasskeys: () => Promise<void>;
|
loadPasskeys: () => Promise<void>;
|
||||||
setEnablingSmsMfa: React.Dispatch<React.SetStateAction<boolean>>;
|
setEnablingSmsMfa: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
setDisablingSmsMfa: React.Dispatch<React.SetStateAction<boolean>>;
|
setDisablingSmsMfa: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
setShowMaskedPhone: (show: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SecurityTabContent: React.FC<SecurityTabProps> = observer(
|
export const SecurityTabContent: React.FC<SecurityTabProps> = observer(
|
||||||
@ -67,9 +78,11 @@ export const SecurityTabContent: React.FC<SecurityTabProps> = observer(
|
|||||||
loadingPasskeys,
|
loadingPasskeys,
|
||||||
enablingSmsMfa,
|
enablingSmsMfa,
|
||||||
disablingSmsMfa,
|
disablingSmsMfa,
|
||||||
|
showMaskedPhone,
|
||||||
loadPasskeys,
|
loadPasskeys,
|
||||||
setEnablingSmsMfa,
|
setEnablingSmsMfa,
|
||||||
setDisablingSmsMfa,
|
setDisablingSmsMfa,
|
||||||
|
setShowMaskedPhone,
|
||||||
}) => {
|
}) => {
|
||||||
const {t, i18n} = useLingui();
|
const {t, i18n} = useLingui();
|
||||||
|
|
||||||
@ -344,13 +357,24 @@ export const SecurityTabContent: React.FC<SecurityTabProps> = observer(
|
|||||||
<div className={styles.label}>
|
<div className={styles.label}>
|
||||||
<Trans>Phone Number</Trans>
|
<Trans>Phone Number</Trans>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.description}>
|
{user.phone ? (
|
||||||
{user.phone ? (
|
<div className={styles.phoneRow}>
|
||||||
<Trans>Phone number added: {user.phone}</Trans>
|
<span className={`${styles.phoneText} ${showMaskedPhone ? styles.phoneTextSelectable : ''}`}>
|
||||||
) : (
|
{showMaskedPhone ? user.phone : maskPhone(user.phone)}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.toggleButton}
|
||||||
|
onClick={() => setShowMaskedPhone(!showMaskedPhone)}
|
||||||
|
>
|
||||||
|
{showMaskedPhone ? t`Hide` : t`Reveal`}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={styles.description}>
|
||||||
<Trans>Add a phone number to enable SMS two-factor authentication</Trans>
|
<Trans>Add a phone number to enable SMS two-factor authentication</Trans>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
{user.phone ? (
|
{user.phone ? (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user