feat: add ability to view secret key

This commit is contained in:
Thomas Osmonson
2020-03-06 08:38:52 -06:00
committed by Hank Stoever
parent 9cc52c2bf9
commit 440c3e5420
17 changed files with 134 additions and 188 deletions

35
.github/workflows/bundle-sizes.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Compressed Size
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set Node Version
uses: actions/setup-node@v1
with:
node-version: 12.16.1
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Monorepo Dependencies
run: yarn
- name: Lerna Bootstrap
run: yarn lerna bootstrap
- uses: preactjs/compressed-size-action@v1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
build-script: "lerna run build --stream --scope @blockstack/connect"
pattern: '**/connect/dist/**/*.js'

View File

@@ -56,7 +56,7 @@ jobs:
- name: Lint
run: yarn lint
- name: Typecheck
run: yarn lerna run typecheck --parallel
run: yarn typecheck
publish:
needs: [test_keychain, codecheck]

View File

@@ -25,7 +25,7 @@
"typescript": "^3.8.2"
},
"scripts": {
"typecheck": "lerna run typecheck",
"typecheck": "lerna run typecheck --parallel",
"dev": "yarn lerna exec --parallel 'yarn dev' --scope test-app --scope @blockstack/app",
"bootstrap": "yarn lerna exec --parallel 'yarn'",
"build:libs": "yarn build:ui && yarn build:keychain && yarn build:connect",

View File

@@ -1,68 +0,0 @@
version: 2
jobs:
build:
working_directory: ~/blockstack-app
docker:
- image: circleci/node:10.16.3-browsers
steps:
- checkout
- restore_cache:
# https://circleci.com/docs/2.0/caching/
key: yarn-packages-{{ checksum "package.json" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile
- save_cache:
key: yarn-packages-{{ checksum "package.json" }}
paths:
- ./.cache/yarn
# TODO - get this cached so that you don't have to pull down the binaries each time
- run:
name: Update apt-get
working_directory: /
command: |
sudo apt-get update -y
- run:
name: Install Chrome headless dependencies
working_directory: /
command: |
sudo apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
- run:
name: Lint Prettier
command: yarn lint:prettier
- run:
name: Lint ESLint
command: yarn lint:eslint
- run:
name: typecheck
command: yarn typecheck
- run:
name: test server
command: yarn dev
background: true
- run:
name: Create .env file
working_directory: ./tests/test-app/
command: echo "SKIP_PREFLIGHT_CHECK=true" >> .env
- run:
name: Install test deps
working_directory: ./tests/test-app/
command: yarn
- run:
name: Run test app
working_directory: ./tests/test-app/
command: yarn start
background: true
- run:
name: test
command: yarn test
- run:
name: Build extension
command: yarn prod:ext && zip -r extension.zip dist
# https://circleci.com/docs/2.0/artifacts/
- store_artifacts:
path: extension.zip

View File

@@ -26,7 +26,7 @@
"@blockstack/connect": "^2.1.0",
"@blockstack/keychain": "^0.3.1",
"@blockstack/prettier-config": "^0.0.5",
"@blockstack/stats": "^0.5.4",
"@blockstack/stats": "^0.7.0",
"@blockstack/ui": "^1.0.1",
"@rehooks/document-title": "^1.0.1",
"@types/react-router-dom": "^5.1.3",

View File

@@ -7,14 +7,30 @@ import {
selectIsSignedIn,
} from '@store/wallet/selectors';
import { selectSecretKey } from '@store/onboarding/selectors';
import { decrypt } from '@blockstack/keychain';
import { DEFAULT_PASSWORD } from '@store/onboarding/types';
import { useState, useEffect } from 'react';
export const useWallet = () => {
const identities = useSelector(selectIdentities);
const firstIdentity = useSelector(selectFirstIdentity);
const wallet = useSelector(selectCurrentWallet);
const secretKey = useSelector(selectSecretKey);
const onboardingSecretKey = useSelector(selectSecretKey);
const isRestoringWallet = useSelector(selectIsRestoringWallet);
const isSignedIn = useSelector(selectIsSignedIn);
const [secretKey, setSecretKey] = useState(onboardingSecretKey);
const fetchSecretKey = async () => {
if (!secretKey && wallet) {
const decryptedKey = await decrypt(wallet?.encryptedBackupPhrase, DEFAULT_PASSWORD);
setSecretKey(decryptedKey);
}
};
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
fetchSecretKey();
}, [onboardingSecretKey]);
return { identities, firstIdentity, wallet, secretKey, isRestoringWallet, isSignedIn };
};

View File

@@ -33,6 +33,8 @@ export const pageTrackingNameMap = {
[ScreenPaths.RECOVERY_CODE]: 'Magic Recovery Code',
[ScreenPaths.ADD_ACCOUNT]: ' Select Username',
[ScreenPaths.REGISTRY_ERROR]: 'Username Registry Error',
[ScreenPaths.SETTINGS_KEY]: 'Settings: Secret Key',
[ScreenPaths.HOME]: 'App Home',
};
export const titleNameMap = {
@@ -45,28 +47,37 @@ export const titleNameMap = {
[ScreenPaths.RECOVERY_CODE]: 'Enter your password',
[ScreenPaths.ADD_ACCOUNT]: ' Select Username',
[ScreenPaths.REGISTRY_ERROR]: 'Failed to register username',
[ScreenPaths.SETTINGS_KEY]: 'View your Secret Key',
[ScreenPaths.HOME]: 'Secret Key',
};
export const doTrackScreenChange = (screen: ScreenPaths, decodedAuthRequest: DecodedAuthRequest | undefined) => {
document.title = titleNameMap[screen];
const appURL = decodedAuthRequest ? new URL(decodedAuthRequest?.redirect_uri) : null;
page({
name: pageTrackingNameMap[screen],
appName: decodedAuthRequest?.appDetails?.name,
appDomain: appURL?.host,
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
setTimeout(async () => {
await page({
name: pageTrackingNameMap[screen],
appName: decodedAuthRequest?.appDetails?.name,
appDomain: appURL?.host,
});
}, 1);
};
export const doTrack = (type: string, payload?: object) => {
console.log('Tracking:', { type, payload });
event({
name: type,
...payload,
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
setTimeout(async () => {
await event({
name: type,
...payload,
});
}, 1);
};
export const setStatsConfig = () => {
setConfig({
useHash: true,
host: STATS_URL,
providers: [
{

View File

@@ -17,7 +17,6 @@ import { authenticationInit } from '@common/utils';
import { useAnalytics } from '@common/hooks/use-analytics';
import { useWallet } from '@common/hooks/use-wallet';
import { useOnboardingState } from '@common/hooks/use-onboarding-state';
import { Routes as RoutesDom, Route, Navigate } from 'react-router-dom';
export const Routes: React.FC = () => {
@@ -102,8 +101,9 @@ export const Routes: React.FC = () => {
/>
}
/>
;{/*Error/Misc*/}
{/*Error/Misc*/}
<Route path="/username-error" element={<UsernameRegistryError />} />
<Route path="/settings/secret-key" element={<SecretKey next={() => doChangeScreen(ScreenPaths.HOME)} />} />
</RoutesDom>
);
};

View File

@@ -1,33 +1,43 @@
import React from 'react';
import { Screen, ScreenBody, Title, PoweredBy, ScreenFooter } from '@blockstack/connect';
import { Box } from '@blockstack/ui';
import { PoweredBy, Screen, ScreenBody, ScreenFooter, Title } from '@blockstack/connect';
import { Box, PseudoBox, Text } from '@blockstack/ui';
import { ScreenHeader } from '@components/connected-screen-header';
import { Accounts } from '@components/accounts';
import { AppIcon } from '@components/app-icon';
import { useSelector } from 'react-redux';
import { AppState } from '@store';
import { selectAppName } from '@store/onboarding/selectors';
import { AppState, store } from '@store';
import { selectAppName, selectDecodedAuthRequest } from '@store/onboarding/selectors';
import { Drawer } from '@components/drawer';
import { selectDecodedAuthRequest } from '@store/onboarding/selectors';
import { store } from '@store';
import { selectIdentities, selectCurrentWallet } from '@store/wallet/selectors';
import { selectCurrentWallet, selectIdentities } from '@store/wallet/selectors';
import { ConfigApp } from '@blockstack/keychain/wallet';
import { Wallet } from '@blockstack/keychain';
import { gaiaUrl } from '@common/constants';
import {
CHOOSE_ACCOUNT_CHOSEN,
CHOOSE_ACCOUNT_REUSE_WARNING,
CHOOSE_ACCOUNT_REUSE_WARNING_BACK,
CHOOSE_ACCOUNT_REUSE_WARNING_CONTINUE,
CHOOSE_ACCOUNT_REUSE_WARNING_DISABLED,
CHOOSE_ACCOUNT_REUSE_WARNING_BACK,
CHOOSE_ACCOUNT_CHOSEN,
} from '@common/track';
import { useAnalytics } from '@common/hooks/use-analytics';
import { ScreenPaths } from '@store/onboarding/types';
interface ChooseAccountProps {
next: (identityIndex: number) => void;
back?: () => void;
}
const SettingsButton = () => {
const { doChangeScreen } = useAnalytics();
return (
<PseudoBox _hover={{ cursor: 'pointer' }} onClick={() => doChangeScreen(ScreenPaths.HOME)}>
<Text color="blue" fontWeight={500} textStyle="body.small.medium" fontSize="12px">
Settings
</Text>
</PseudoBox>
);
};
export const ChooseAccount: React.FC<ChooseAccountProps> = ({ next }) => {
const { appName, identities, wallet } = useSelector((state: AppState) => ({
appName: selectAppName(state),
@@ -100,7 +110,7 @@ export const ChooseAccount: React.FC<ChooseAccountProps> = ({ next }) => {
}}
/>
<Screen textAlign="center">
<ScreenHeader hideIcon title="Continue with Secret Key" />
<ScreenHeader hideIcon title="Continue with Secret Key" rightContent={<SettingsButton />} />
<AppIcon mt={10} mb={4} size="72px" />
<ScreenBody
body={[

View File

@@ -1,9 +1,10 @@
import React from 'react';
import { Box, Flex, Text } from '@blockstack/ui';
import { Box, PseudoBox, Flex, Text } from '@blockstack/ui';
import { LogoWithName } from '@components/logo-with-name';
import { SignOut } from '@components/sign-out';
import { useAnalytics } from '@common/hooks/use-analytics';
import { useDispatch } from 'react-redux';
import { ScreenPaths } from '@store/onboarding/types';
import { useWallet } from '@common/hooks/use-wallet';
import { doSignOut } from '@store/wallet';
@@ -29,6 +30,17 @@ const SignedOut = () => (
</Flex>
);
const SecretKeyButton = () => {
const { doChangeScreen } = useAnalytics();
return (
<PseudoBox _hover={{ cursor: 'pointer' }} onClick={() => doChangeScreen(ScreenPaths.SETTINGS_KEY)}>
<Text color="blue" fontWeight={500} textStyle="body.small.medium" fontSize="12px">
View Secret Key
</Text>
</PseudoBox>
);
};
export const Home = () => {
const dispatch = useDispatch();
const { identities } = useWallet();
@@ -36,7 +48,10 @@ export const Home = () => {
return (
<Flex wrap="wrap" py={5} px={4} flexDirection="column" height="100vh">
<LogoWithName />
<Flex justifyContent="space-between" align="center">
<LogoWithName />
<SecretKeyButton />
</Flex>
<Flex flex={1} mt={10} justifyContent={[null, 'center']}>
{isSignedIn ? (
<SignOut

View File

@@ -23,6 +23,7 @@ export enum ScreenName {
export enum ScreenPaths {
GENERATION = '/sign-up',
SECRET_KEY = '/sign-up/secret-key',
SETTINGS_KEY = '/settings/secret-key',
SAVE_KEY = '/sign-up/save-secret-key',
USERNAME = '/sign-up/username',
SIGN_IN = '/sign-in',
@@ -30,6 +31,7 @@ export enum ScreenPaths {
ADD_ACCOUNT = '/sign-in/add-account',
CHOOSE_ACCOUNT = '/connect/choose-account',
REGISTRY_ERROR = '/username-error',
HOME = '/',
}
// TODO: clarify usage of password for local key encryption

View File

@@ -1,30 +0,0 @@
version: 2 # use CircleCI 2.0
jobs: # a collection of steps
build: # runs not using Workflows must have a `build` job as entry point
working_directory: ~/connect # directory where steps will run
docker: # run the steps with Docker
- image: circleci/node:10.16.3
steps: # a collection of executable commands
- checkout # special step to check out source code to working directory
- restore_cache: # special step to restore the dependency cache
# Read about caching dependencies: https://circleci.com/docs/2.0/caching/
key: yarn-packages-{{ checksum "package.json" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile
- save_cache: # special step to save the dependency cache
key: yarn-packages-{{ checksum "package.json" }}
paths:
- ./.cache/yarn
# - run: # run tests
# name: test
# command: yarn test
# - run: # run coverage report
# name: code-coverage
# command: './node_modules/.bin/nyc report --reporter=text-lcov'
- run: # run lint
name: lint
command: yarn lint
- run: # run lint
name: type check
command: yarn typecheck

View File

@@ -1,14 +0,0 @@
name: Compressed Size
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: preactjs/compressed-size-action@v1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -24,6 +24,7 @@ export interface ScreenHeaderProps {
icon: string;
};
title?: string | JSX.Element;
rightContent?: React.FC | JSX.Element;
close?: () => void;
hideIcon?: boolean;
hideLogo?: boolean;
@@ -34,6 +35,7 @@ export const ScreenHeader = ({
title = 'Secret Key',
hideIcon = false,
hideLogo = false,
rightContent,
...rest
}: ScreenHeaderProps) => {
const { name, icon } = useAppDetails();
@@ -59,14 +61,17 @@ export const ScreenHeader = ({
justify="space-between"
{...rest}
>
<Flex align="center">
{!hideIcon ? <AppIcon src={appIcon} alt={appName || 'loading'} /> : null}
{!hideIcon ? (
<Box mx="extra-tight" color="ink.300">
<ChevronIcon direction="right" />
</Box>
) : null}
<HeaderTitle hideLogo={hideLogo} title={title} />
<Flex width="100%" align="center" justifyContent="space-between">
<Flex align="center">
{!hideIcon ? <AppIcon src={appIcon} alt={appName || 'loading'} /> : null}
{!hideIcon ? (
<Box mx={1} color="ink.300">
<ChevronIcon direction="right" />
</Box>
) : null}
<HeaderTitle hideLogo={hideLogo} title={title} />
</Flex>
{rightContent ? rightContent : null}
</Flex>
</Flex>
);

View File

@@ -1,22 +0,0 @@
version: 2.1
jobs:
build:
docker:
- image: circleci/node:10.16.3
steps:
- checkout
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run:
name: Install Dependencies
command: yarn install --frozen-lockfile
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
- run:
name: Formatted with Prettier
command: yarn lint:formatting

View File

@@ -1,14 +0,0 @@
name: Compressed Size
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: preactjs/compressed-size-action@v1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -1230,10 +1230,10 @@
resolved "https://registry.yarnpkg.com/@blockstack/prettier-config/-/prettier-config-0.0.5.tgz#871bd2a38b5bc9aabb1cefeeba6199cc64098957"
integrity sha512-A+wfdVwD1Sxd/D3PPJI67Evo7q2fp15hCOFLB5jmzcS1MdN8BQdFm6j51Sti8xLN4qHmuYkicbFBUluGx2h63g==
"@blockstack/stats@^0.5.4":
version "0.5.4"
resolved "https://registry.yarnpkg.com/@blockstack/stats/-/stats-0.5.4.tgz#092ee64de324412688d227073f768907083cb6c4"
integrity sha512-tUHfEeXYF5QwVp3xZOPQzfH0Lr5GBc2tr/6M3/CH6GU/cHLRJ63cwiLpUj/3cnb+sYE+OYS00MtOfMsMUtVzug==
"@blockstack/stats@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@blockstack/stats/-/stats-0.7.0.tgz#be39d3e76c2a16c1cd1283aa702d1e20b5e04645"
integrity sha512-AS/UdJH/cJ7K8la3/TbQziEMlRrNI/4VEHSfYUsEzU7Nx892G6qE4uu/XvW9ycS0Jg2/TW2bjTnRijsyecaEJA==
"@cnakazawa/watch@^1.0.3":
version "1.0.4"