Skip to content

Commit

Permalink
UI work for mnemonic phrase screen, url whitelisting improvements (#8)
Browse files Browse the repository at this point in the history
* content script update

* whitelist PR preview env

* adding UI work for mnemonic phrase screen plus some url whitelisting improvemnents

* rm debugger
  • Loading branch information
piyalbasu authored May 26, 2020
1 parent 753bc18 commit 3b8f47f
Show file tree
Hide file tree
Showing 20 changed files with 225 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import StellarSdk from "stellar-sdk";

import { ExternalRequest as Request } from "api/types";
import { EXTERNAL_SERVICE_TYPES } from "statics";
import { removeQueryParam } from "helpers";
import { Sender, SendResponseInterface } from "../types";
import { responseQueue, uiData, transactionQueue } from "../messageListener";

Expand All @@ -21,7 +22,7 @@ export const externalMessageListener = (
const { tab } = sender;
const tabUrl = tab?.url ? tab.url : "";

if (whitelist.includes(tabUrl)) {
if (whitelist.includes(removeQueryParam(tabUrl))) {
if (uiData.publicKey) {
// okay, the requester checks out and we have public key, send it
sendResponse({ publicKey: uiData.publicKey });
Expand All @@ -31,7 +32,6 @@ export const externalMessageListener = (

// otherwise, we need to confirm either url or password. Maybe both
const encodeOrigin = btoa(JSON.stringify(tab));

window.open(
chrome.runtime.getURL(`/index.html#/grant-access?${encodeOrigin}`),
"Lyra: Connect",
Expand Down
6 changes: 5 additions & 1 deletion background/backgroundComponents/messageListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import StellarSdk from "stellar-sdk";
import { fromMnemonic, generateMnemonic } from "stellar-hd-wallet";
import { SERVICE_TYPES, APPLICATION_STATE, SERVER_URL } from "statics";
import { Response as Request } from "api/types";
import { removeQueryParam } from "helpers";
import { externalMessageListener } from "./externalMessageListener";
import { Sender, SendResponseInterface } from "./types";

Expand Down Expand Up @@ -183,18 +184,20 @@ const initMessageListener = () => {

const grantAccess = () => {
const { url = "" } = request;
const sanitizedUrl = removeQueryParam(url);

// TODO: right now we're just grabbing the last thing in the queue, but this should be smarter.
// Maybe we need to search through responses to find a matching reponse :thinking_face
const response = responseQueue.pop();
const whitelistStr = localStorage.getItem(WHITELIST_ID) || "";
const whitelist = whitelistStr.split(",");
whitelist.push(url);
whitelist.push(sanitizedUrl);

localStorage.setItem(WHITELIST_ID, whitelist.join());

if (typeof response === "function") {
response(url);
sendResponse({});
} else {
sendResponse({ error: "Access was denied" });
}
Expand Down Expand Up @@ -240,6 +243,7 @@ const initMessageListener = () => {
const transactionResponse = responseQueue.pop();
if (typeof transactionResponse === "function") {
transactionResponse(response);
sendResponse({});
}
}
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"buffer": "^5.6.0",
"eslint-loader": "^4.0.2",
"fetch": "^1.1.0",
"file-loader": "^6.0.0",
"lodash": "^4.17.15",
"react": "^16.12.0",
"react-copy-to-clipboard": "^5.0.2",
Expand Down
3 changes: 3 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
name="description"
content="Web site created using create-react-app"
/>
<style>
@import url("https://fonts.googleapis.com/css2?family=Muli:ital,wght@0,200;0,400;0,700;1,200;1,400;1,700&display=swap");
</style>
<title>React App</title>
</head>
<body>
Expand Down
16 changes: 10 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@ import { combineReducers } from "redux";
import { Provider } from "react-redux";
import styled, { createGlobalStyle } from "styled-components";

import { COLOR_PALETTE } from "styles";
import { reducer as auth } from "ducks/authServices";
import Menu from "components/Menu";
import Router from "./Router";

const GlobalStyle = createGlobalStyle`
html, body, #root {
height: 100%;
}
body {
background: ${COLOR_PALETTE.background};
overscroll-behavior: none;
font-family: sans-serif;
width: 357px;
height: 600px;
font-family: 'Muli', sans-serif;
margin: 0;
}
`;

const Wrapper = styled.div`
text-align: center;
display: flex;
flex-flow: column;
height: 100%;
text-align: left;
`;

const store = configureStore({
Expand All @@ -36,7 +41,6 @@ export function App() {
<Provider store={store}>
<Wrapper>
<GlobalStyle />
<Menu />
<Router />
</Wrapper>
</Provider>
Expand Down
Binary file added src/assets/copy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/download.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/spy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions src/components/Layout/Fullscreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from "react";
import styled from "styled-components";
import Header from "./Header";

const H1 = styled.h1`
font-weight: 200;
font-size: 2.5rem;
line-height: 3.4rem;
margin: 1rem 0;
`;

const Screen = styled.div`
align-content: center;
align-items: center;
display: flex;
justify-content: center;
padding: 100px 170px;
`;

const HalfScreen = styled.div`
padding: 0 30px;
width: 355px;
:nth-child(1) {
margin-top: -20px;
}
`;

const Fullscreen = ({
header,
icon: [src, alt],
children,
}: {
header: string;
icon: [string, string];
children: JSX.Element;
}) => {
return (
<>
<Header />
<Screen>
<HalfScreen>
<img src={src} alt={alt} />
<H1>{header}</H1>
</HalfScreen>
<HalfScreen>{children}</HalfScreen>
</Screen>
</>
);
};

export default Fullscreen;
39 changes: 39 additions & 0 deletions src/components/Layout/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import styled from "styled-components";
import { COLOR_PALETTE } from "styles";

const HeaderEl = styled.header`
background: ${COLOR_PALETTE.primaryGradient};
box-sizing: border-box;
font-family: "Muli";
display: flex;
height: 6.2rem;
justify-content: space-between;
padding: 26px 54px;
text-align: left;
`;

const HeaderH1 = styled.h1`
color: #fff;
font-size: 2rem;
font-weight: 200;
line-height: 41px;
margin: 0;
`;

const NetworkEl = styled.h3`
opacity: 0.5;
color: #fff;
font-size: 1rem;
font-weight: 800;
line-height: 21px;
`;

const Header = () => (
<HeaderEl>
<HeaderH1>Lyra</HeaderH1>
<NetworkEl>Test net</NetworkEl>
</HeaderEl>
);

export default Header;
14 changes: 14 additions & 0 deletions src/components/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from "react";
import styled from "styled-components";
import { COLOR_PALETTE } from "styles";
import { Button } from "styles/Basics";

const ErrorEl = styled.p`
color: red;
Expand All @@ -13,3 +15,15 @@ interface ErrorMessageProps {
export const ErrorMessage = ({ authError }: ErrorMessageProps) => (
<>{authError ? <ErrorEl>{authError}</ErrorEl> : null}</>
);

export const FormButton = styled(Button)`
background: ${COLOR_PALETTE.primaryGradient};
border-radius: 1.5rem;
color: #fff;
display: block;
font-size: 1.1rem;
font-weight: 600;
line-height: 1.3rem;
margin: 2rem auto;
padding: 1.6rem 6rem;
`;
62 changes: 53 additions & 9 deletions src/components/mnemonicPhrase/DisplayMnemonicPhrase.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
import React, { useState, useEffect } from "react";
import CopyToClipboard from "react-copy-to-clipboard";
import styled from "styled-components";
import { COLOR_PALETTE } from "styles";
import Download from "assets/download.png";
import Copy from "assets/copy.png";
import { FormButton } from "components/form";
import ActionButton from "./basics/ActionButton";

const Warning = styled.strong`
color: ${COLOR_PALETTE.primary};
`;

const MnemonicDisplay = styled.div`
background: ${COLOR_PALETTE.primaryGradient};
border-radius: 30px;
color: #fff;
font-size: 1.125 rem;
line-height: 1.8rem;
margin: 3.5rem 0 1rem;
padding: 27px 37px;
text-align: center;
`;

const DisplayButtons = styled.div`
margin-right: 1rem;
text-align: right;
img {
margin-left: 0.5rem;
}
`;

const DisplayMnemonicPhrase = ({
mnemonicPhrase,
Expand Down Expand Up @@ -29,20 +59,34 @@ const DisplayMnemonicPhrase = ({

return (
<>
<h1>Secret backup Phrase</h1>
<p>{mnemonicPhrase}</p>
<CopyToClipboard text={mnemonicPhrase} onCopy={() => setCopied(true)}>
<button>Copy to clopboard with button</button>
</CopyToClipboard>
<button onClick={downloadPhrase}>Download phrase</button>
{copied ? <span>Copied!</span> : null}
<button
<p>
Your secret backup phrase makes it easy to back up and restore your
account.
</p>
<p>
<Warning>WARNING:</Warning> Never disclose your backup phase.
</p>
<MnemonicDisplay>{mnemonicPhrase}</MnemonicDisplay>
<DisplayButtons>
<ActionButton onClick={downloadPhrase}>
Download
<img src={Download} alt="Download button" />
</ActionButton>
<CopyToClipboard text={mnemonicPhrase} onCopy={() => setCopied(true)}>
<ActionButton>
Copy
<img src={Copy} alt="copy button" />
</ActionButton>
</CopyToClipboard>
{copied ? <span>Copied!</span> : null}
</DisplayButtons>
<FormButton
onClick={() => {
setReadyToConfirm(true);
}}
>
Next
</button>
</FormButton>
</>
);
};
Expand Down
12 changes: 12 additions & 0 deletions src/components/mnemonicPhrase/basics/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styled from "styled-components";
import { Button } from "styles/Basics";

const ActionButton = styled(Button)`
color: #748098;
font-size: 0.875rem;
font-weight: 500;
line-height: 1.7rem;
opacity: 0.6;
`;

export default ActionButton;
1 change: 1 addition & 0 deletions src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const newTabHref = (path = "") => `index.html#${path}`;
export const removeQueryParam = (url = "") => url.replace(/\?(.*)/, "");
12 changes: 12 additions & 0 deletions src/styles/Basics/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styled from "styled-components";

export const Button = styled.button`
background: none;
border: none;
cursor: pointer;
-webkit-appearance: none;
:focus {
outline: none;
}
`;
6 changes: 6 additions & 0 deletions src/styles/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const COLOR_PALETTE = {
background: "#F0F2F6",
text: "#060E1A",
primary: "#391EDA",
primaryGradient: "linear-gradient(90deg, #391EDA 100%, #5339ED 0%)",
};
7 changes: 5 additions & 2 deletions src/views/MnemonicPhrase/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import React, { useState } from "react";
import ConfirmMnemonicPhrase from "components/mnemonicPhrase/ConfirmMnemonicPhrase";
import useMnemonicPhrase from "hooks/useMnemonicPhrase";
import DisplayMnemonicPhrase from "components/mnemonicPhrase/DisplayMnemonicPhrase";
import Fullscreen from "components/Layout/Fullscreen";

import spy from "assets/spy.png";

const MnemonicPhrase = () => {
const [readyToConfirm, setReadyToConfirm] = useState(false);

const mnemonicPhrase = useMnemonicPhrase();

return (
<>
<Fullscreen header="Secret backup phrase" icon={[spy, "Spy"]}>
{readyToConfirm ? (
<ConfirmMnemonicPhrase
mnemonicPhrase={mnemonicPhrase}
Expand All @@ -21,7 +24,7 @@ const MnemonicPhrase = () => {
setReadyToConfirm={setReadyToConfirm}
/>
)}
</>
</Fullscreen>
);
};

Expand Down
3 changes: 1 addition & 2 deletions src/views/RecoverAccount/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useEffect, useRef, useState, useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
import { history } from "App";
import {
authErrorSelector,
publicKeySelector,
Expand Down Expand Up @@ -44,7 +43,7 @@ const RecoverAccount = () => {

useEffect(() => {
if (publicKey) {
history.push("/account");
window.close();
}
}, [publicKey]);

Expand Down
Loading

0 comments on commit 3b8f47f

Please sign in to comment.