added qr code render

This commit is contained in:
Abhinav-grd 2021-06-17 16:15:52 +05:30
parent f7a8bc0660
commit f5b3ded190
5 changed files with 156 additions and 33 deletions

View file

@ -28,6 +28,7 @@ import { LogoImage } from 'pages/_app';
import { SetDialogMessage } from './MessageDialog';
import EnteSpinner from './EnteSpinner';
import RecoveryKeyModal from './RecoveryKeyModal';
import TwoFactorModal from './TwoFactorModal';
interface Props {
files: File[];
@ -45,6 +46,7 @@ export default function Sidebar(props: Props) {
}, []);
const [isOpen, setIsOpen] = useState(false);
const [recoverModalView, setRecoveryModalView] = useState(false);
const [twoFactorModal, setTwoFactorModal] = useState(true);
useEffect(() => {
const main = async () => {
if (!isOpen) {
@ -214,6 +216,22 @@ export default function Sidebar(props: Props) {
{constants.DOWNLOAD_RECOVERY_KEY}
</LinkButton>
</>
<>
<TwoFactorModal
show={twoFactorModal}
onHide={() => setTwoFactorModal(false)}
somethingWentWrong={() => props.setDialogMessage({
title: constants.TWO_FACTOR_SECRET_FETCHING_FAILED,
close: { variant: 'danger' },
})}
/>
<LinkButton
style={{ marginTop: '30px' }}
onClick={() => setTwoFactorModal(true)}
>
{constants.TWO_FACTOR_AUTHENTICATION}
</LinkButton>
</>
<LinkButton
style={{ marginTop: '30px' }}
onClick={() => {

View file

@ -0,0 +1,85 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect, useState } from 'react';
import constants from 'utils/strings/constants';
import MessageDialog from './MessageDialog';
import { DeadCenter } from 'pages/gallery';
import { Button } from 'react-bootstrap';
import { setupTwoFactor, TwoFactorSector } from 'services/userService';
import styled from 'styled-components';
import EnteSpinner from './EnteSpinner';
const QRCode = styled.img`
height:200px;
width:200px;
`;
interface Props {
show: boolean;
onHide: () => void;
somethingWentWrong: any;
}
enum SetupMode {
QR_CODE,
MANUAL_CODE,
}
function TwoFactorModal({ somethingWentWrong, ...props }: Props) {
const [setupMode, setSetupMode] = useState<SetupMode>(SetupMode.QR_CODE);
const [twoFactorSecret, setTwoFactorSecret] = useState<TwoFactorSector>(null);
useEffect(() => {
if (!props.show) {
return;
}
const main = async () => {
const twoFactorSecret = await setupTwoFactor();
setTwoFactorSecret(twoFactorSecret);
};
main();
}, [props.show]);
return (
<MessageDialog
{...props}
attributes={{
title: constants.DOWNLOAD_RECOVERY_KEY,
close: {
text: constants.SAVE_LATER,
variant: 'danger',
},
staticBackdrop: true,
proceed: {
text: constants.SAVE,
action: () => null,
disabled: false,
variant: 'success',
},
}}
>
{setupMode === SetupMode.QR_CODE ? (
<>
<p>{constants.TWO_FACTOR_AUTHENTICATION_QR_INSTRUCTION}</p>
<DeadCenter>
{!twoFactorSecret ? <EnteSpinner /> :
<QRCode src={`data:image/png;base64,${twoFactorSecret.qrCode}`} />
}
<Button block variant="link" onClick={() => setSetupMode(SetupMode.MANUAL_CODE)}>
{constants.ENTER_CODE_MANUALLY}
</Button>
</DeadCenter>
</>
) : (<>
<p>{constants.TWO_FACTOR_AUTHENTICATION_MANUAL_CODE_INSTRUCTION}</p>
<DeadCenter>
<div style={{ width: '300px', height: '30px', backgroundColor: 'red', marginBottom: '10px' }}>
</div>
<Button block variant="link" onClick={() => setSetupMode(SetupMode.QR_CODE)}>
{constants.ENTER_CODE_MANUALLY}
</Button>
</DeadCenter>
</>
)
}
</MessageDialog>
);
}
export default TwoFactorModal;

View file

@ -161,6 +161,9 @@ const GlobalStyles = createGlobalStyle`
background-size: 20px 20px;
background-position: center;
}
.btn.focus , .btn:focus{
box-shadow: none;
}
.btn-success {
background: #2dc262;
border-color: #29a354;

View file

@ -34,6 +34,10 @@ export interface VerificationResponse {
encryptedToken?: string;
token?: string;
}
export interface TwoFactorSector {
secretKey: string
qrCode: string
}
export const getOtt = (email: string) => HTTPService.get(`${ENDPOINT}/users/ott`, {
email,
@ -98,3 +102,10 @@ export const isTokenValid = async () => {
return false;
}
};
export const setupTwoFactor = async () => {
const resp = await HTTPService.get(`${ENDPOINT}/users/two-factor/setup`, null, {
'X-Auth-Token': getToken(),
});
return resp.data as TwoFactorSector;
};

View file

@ -5,7 +5,7 @@ import styled from 'styled-components';
* Global English constants.
*/
const dateString = function(date) {
const dateString = function (date) {
return new Date(date / 1000).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
@ -24,7 +24,7 @@ const Logo = styled.img`
`;
const englishConstants = {
HERO_HEADER: () => <div>with <Logo src='/icon.svg' /><br/>your <Strong>memories</Strong> are</div>,
HERO_HEADER: () => <div>with <Logo src='/icon.svg' /><br />your <Strong>memories</Strong> are</div>,
HERO_SLIDE_1_TITLE: 'protected',
HERO_SLIDE_1: 'end-to-end encrypted with your password, visible only to you',
HERO_SLIDE_2_TITLE: 'synced',
@ -46,7 +46,7 @@ const englishConstants = {
VERIFY_EMAIL: 'verify email',
EMAIL_SENT: ({ email }) => (
<p>
we have sent a mail to <b>{email}</b>
we have sent a mail to <b>{email}</b>
</p>
),
CHECK_INBOX: 'please check your inbox (and spam) to complete verification',
@ -67,10 +67,10 @@ const englishConstants = {
'please enter a password that we can use to encrypt your data',
PASSPHRASE_DISCLAIMER: () => (
<p>
we don't store your password, so if you forget,
we don't store your password, so if you forget,
<strong> we will not be able to help you</strong>
{' '}
recover your data.
recover your data.
</p>
),
PASSPHRASE_HINT: 'password',
@ -182,26 +182,26 @@ const englishConstants = {
MESSAGE: 'message',
INSTALL_MOBILE_APP: () => (
<>
install our{' '}
install our{' '}
<a
href="https://play.google.com/store/apps/details?id=io.ente.photos"
target="_blank"
style={{ color: '#2dc262' }} rel="noreferrer"
>
android
android
</a>
{' '}
or
or
{' '}
<a
href="https://apps.apple.com/in/app/ente-photos/id1542026904"
style={{ color: '#2dc262' }}
target="_blank" rel="noreferrer"
>
ios app
ios app
{' '}
</a>
to automatically backup all your photos
to automatically backup all your photos
</>
),
DOWNLOAD_APP_MESSAGE: () => (
@ -230,41 +230,41 @@ const englishConstants = {
FREE_SUBSCRIPTION_INFO: (expiryTime) => (
<>
<p>
you are on the <strong>free</strong>
you are on the <strong>free</strong>
{' '}
plan that expires on{' '}
plan that expires on{' '}
{dateString(expiryTime)}
</p>
</>
),
RENEWAL_ACTIVE_SUBSCRIPTION_INFO: (expiryTime) => (
<p>
your subscription will renew on {dateString(expiryTime)}
your subscription will renew on {dateString(expiryTime)}
</p>
),
RENEWAL_CANCELLED_SUBSCRIPTION_INFO: (expiryTime) => (
<>
<p>
your subscription will be cancelled on {dateString(expiryTime)}
your subscription will be cancelled on {dateString(expiryTime)}
</p>
</>
),
USAGE_INFO: (usage, quota) => (
<p>
you have used {usage}
you have used {usage}
{' '}
GB out of your {quota}
GB out of your {quota}
{' '}
GB quota
GB quota
</p>
),
SUBSCRIPTION_PURCHASE_SUCCESS: (expiryTime) => (
<>
<p>we've received your payment</p>
your subscription is valid till{' '}
your subscription is valid till{' '}
<strong>{dateString(expiryTime)}</strong>
</>
),
@ -287,8 +287,8 @@ const englishConstants = {
CANCEL_SUBSCRIPTION_MESSAGE: () => (
<>
<p>
all of your data will be deleted from our servers at the end of
this billing period.
all of your data will be deleted from our servers at the end of
this billing period.
</p>
<p>are you sure that you want to unsubscribe?</p>
</>
@ -313,8 +313,8 @@ const englishConstants = {
<>
<p>are you sure you want to delete this album?</p>
<p>
all files that are present only in this album will be
permanently deleted
all files that are present only in this album will be
permanently deleted
</p>
</>
),
@ -336,42 +336,42 @@ const englishConstants = {
SEARCH_HINT: () => <span>try searching for New York, April 14, Christmas...</span>,
TERMS_AND_CONDITIONS: () => (
<p>
I agree to the{' '}
I agree to the{' '}
<a href="https://ente.io/terms" target="_blank" rel="noreferrer">
terms
terms
</a>
{' '}
and
and
{' '}
<a href="https://ente.io/privacy" target="_blank" rel="noreferrer">
privacy policy
privacy policy
</a>
{' '}
</p>
),
CONFIRM_PASSWORD_NOT_SAVED: () => (
<p>
i understand that if i lose my password , i may lose my data since
my data is{' '}
i understand that if i lose my password , i may lose my data since
my data is{' '}
<a href="https://ente.io/encryption" target="_blank" rel="noreferrer">
end-to-end encrypted
end-to-end encrypted
</a>
{' '}
with ente
with ente
</p>
),
SEARCH_STATS: ({ resultCount, timeTaken }) => (
<span>
found <span style={{ color: '#2dc262' }}>{resultCount}</span>
found <span style={{ color: '#2dc262' }}>{resultCount}</span>
{' '}
memories (
memories (
{' '}
<span style={{ color: '#2dc262' }}>
{' '}
{timeTaken}
</span>
{' '}
seconds )
seconds )
</span>
),
NOT_FILE_OWNER: 'deleting shared collection files is not allowed',
@ -397,6 +397,12 @@ const englishConstants = {
SHOW_ALL: 'show all',
LOGIN_TO_UPLOAD_FILES: (count: number) => count === 1 ? `1 file received. login to upload` : `${count} files received. login to upload`,
FILES_TO_BE_UPLOADED: (count: number) => count === 1 ? `1 file received. uploading in a jiffy` : `${count} files received. Uploading in a jiffy`,
TWO_FACTOR_AUTHENTICATION: 'two-factor authentication',
TWO_FACTOR_SECRET_FETCHING_FAILED: 'unable to get two factor authentication data, please try again ',
TWO_FACTOR_AUTHENTICATION_QR_INSTRUCTION: 'please scan QR code below with your favorite authenticator app',
ENTER_CODE_MANUALLY: 'enter the code manually',
TWO_FACTOR_AUTHENTICATION_MANUAL_CODE_INSTRUCTION: 'please enter this code in your favorite authenticator app',
};
export default englishConstants;