diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 16ffca3..3e30e82 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
+
NFCReaderUsageDescription
Enable Keycard
+ NSCameraUsageDescription
+ $(PRODUCT_NAME) needs access to your Camera.
CFBundleDevelopmentRegion
en
CFBundleDisplayName
diff --git a/package-lock.json b/package-lock.json
index 2a28876..54420c4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,8 @@
"react-native": "0.75.3",
"react-native-modal": "^13.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.0",
- "react-native-vector-icons": "^10.1.0"
+ "react-native-vector-icons": "^10.1.0",
+ "react-native-vision-camera": "^4.5.3"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@@ -4775,9 +4776,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.5.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
- "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
+ "version": "22.7.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
+ "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
@@ -4800,9 +4801,9 @@
"license": "MIT"
},
"node_modules/@types/react": {
- "version": "18.3.8",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz",
- "integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==",
+ "version": "18.3.10",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz",
+ "integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -5729,9 +5730,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
- "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
+ "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==",
"funding": [
{
"type": "opencollective",
@@ -5748,8 +5749,8 @@
],
"license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001646",
- "electron-to-chromium": "^1.5.4",
+ "caniuse-lite": "^1.0.30001663",
+ "electron-to-chromium": "^1.5.28",
"node-releases": "^2.0.18",
"update-browserslist-db": "^1.1.0"
},
@@ -5880,9 +5881,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001663",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz",
- "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==",
+ "version": "1.0.30001664",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz",
+ "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==",
"funding": [
{
"type": "opencollective",
@@ -6652,9 +6653,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.27",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz",
- "integrity": "sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==",
+ "version": "1.5.29",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz",
+ "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==",
"license": "ISC"
},
"node_modules/emittery": {
@@ -7192,9 +7193,9 @@
}
},
"node_modules/eslint-plugin-react": {
- "version": "7.36.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz",
- "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==",
+ "version": "7.37.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz",
+ "integrity": "sha512-IHBePmfWH5lKhJnJ7WB1V+v/GolbB0rjS8XYVCSQCZKaQCAUhMoVoOEn1Ef8Z8Wf0a7l8KTJvuZg5/e4qrZ6nA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8047,9 +8048,9 @@
"license": "MIT"
},
"node_modules/flow-parser": {
- "version": "0.246.0",
- "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.246.0.tgz",
- "integrity": "sha512-WHRizzSrWFTcKo7cVcbP3wzZVhzsoYxoWqbnH4z+JXGqrjVmnsld6kBZWVlB200PwD5ur8r+HV3KUDxv3cHhOQ==",
+ "version": "0.247.1",
+ "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.247.1.tgz",
+ "integrity": "sha512-DHwcm06fWbn2Z6uFD3NaBZ5lMOoABIQ4asrVA80IWvYjjT5WdbghkUOL1wIcbLcagnFTdCZYOlSNnKNp/xnRZQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@@ -13056,6 +13057,30 @@
"node": ">=10"
}
},
+ "node_modules/react-native-vision-camera": {
+ "version": "4.5.3",
+ "resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.5.3.tgz",
+ "integrity": "sha512-wulpS6ZY6SwuYMDD8csIFMFJ6lXeQq4bJvaAhwEnr0R9cZ53jDUs0/SFZva6UFEPIw64h0IdrrzuVTEufhDSgQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@shopify/react-native-skia": "*",
+ "react": "*",
+ "react-native": "*",
+ "react-native-reanimated": "*",
+ "react-native-worklets-core": "*"
+ },
+ "peerDependenciesMeta": {
+ "@shopify/react-native-skia": {
+ "optional": true
+ },
+ "react-native-reanimated": {
+ "optional": true
+ },
+ "react-native-worklets-core": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-native/node_modules/@jest/types": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",
@@ -14224,9 +14249,9 @@
}
},
"node_modules/terser": {
- "version": "5.33.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.33.0.tgz",
- "integrity": "sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==",
+ "version": "5.34.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz",
+ "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==",
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
@@ -14640,9 +14665,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
- "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
+ "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
"funding": [
{
"type": "opencollective",
@@ -14659,8 +14684,8 @@
],
"license": "MIT",
"dependencies": {
- "escalade": "^3.1.2",
- "picocolors": "^1.0.1"
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.0"
},
"bin": {
"update-browserslist-db": "cli.js"
diff --git a/package.json b/package.json
index 977587c..3e8c860 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,8 @@
"react-native": "0.75.3",
"react-native-modal": "^13.0.1",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.6.0",
- "react-native-vector-icons": "^10.1.0"
+ "react-native-vector-icons": "^10.1.0",
+ "react-native-vision-camera": "^4.5.3"
},
"devDependencies": {
"@babel/core": "^7.20.0",
diff --git a/src/Main.tsx b/src/Main.tsx
index 724bc0d..77ba145 100644
--- a/src/Main.tsx
+++ b/src/Main.tsx
@@ -5,23 +5,26 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import DiscoveryScreen from './components/steps/DiscoveryScreen';
import InitializationScreen from './components/steps/InitializationScreen';
import MnemonicScreen from './components/steps/MnemonicScreen';
-import AuthenticationScreen from './components/steps/AuthenticationScreen';
+import HomeScreen from './components/steps/HomeScreen';
import FactoryResetScreen from './components/steps/FactoryResetScreen';
import NFCModal from './NFCModal';
//@ts-ignore
import Keycard from "react-native-status-keycard";
+import Dialpad from './components/Dialpad';
enum Step {
Discovery,
Initialization,
Loading,
Authentication,
+ Home,
FactoryReset,
}
const Main = () => {
const PIN_MAX_RETRY = 3;
+ const WALLET_DERIVATION_PATH = "m/84'/0'/0'/0/0";
const [isModalVisible, setIsModalVisible] = useState(false);
const [step, setStep] = useState(Step.Discovery);
@@ -32,6 +35,9 @@ const Main = () => {
const pinRef = useRef("");
const mnemonicRef = useRef("");
const isListeningCard = useRef(false);
+ const walletKey = useRef("");
+ const sessionId = useRef("")
+ const challenge = useRef("")
const getPairings = async () => {
const pairingJSON = await AsyncStorage.getItem("pairings");
@@ -97,10 +103,10 @@ const Main = () => {
break;
case Step.Loading:
await Keycard.saveMnemonic(mnemonicRef.current, pinRef.current);
- setStep(Step.Authentication);
- break;
+ //fallthrough
case Step.Authentication:
- setStep(Step.Discovery);
+ walletKey.current = await Keycard.exportKeyWithPath(pinRef.current, WALLET_DERIVATION_PATH);
+ setStep(Step.Home);
break;
case Step.FactoryReset:
await Keycard.factoryReset();
@@ -195,6 +201,16 @@ const Main = () => {
return connectCard();
}
+ const authenticate = (pin: string) => {
+ pinRef.current = pin
+ connectCard();
+ return true;
+ }
+
+ const login = (sessionId: string, challenge: string) => {
+
+ }
+
const cancel = () => {
setStep(Step.Discovery);
}
@@ -208,8 +224,9 @@ const Main = () => {
{step == Step.Discovery && }
{step == Step.Initialization && }
{step == Step.Loading && }
- {step == Step.Authentication && {} } onCancelFunc={cancel}>}
- {step == Step.FactoryReset && }
+ {step == Step.Authentication && }
+ {step == Step.Home && }
+ {step == Step.FactoryReset && }
);
diff --git a/src/components/steps/AuthenticationScreen.tsx b/src/components/steps/AuthenticationScreen.tsx
deleted file mode 100644
index f08759f..0000000
--- a/src/components/steps/AuthenticationScreen.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import {FC } from "react";
-import { StyleSheet, Text, View } from "react-native";
-import Button from "../Button";
-
-type AuthenticationScreenProps = {
- pinRetryCounter: number;
- onPressFunc: () => void;
- onCancelFunc: () => void;
-};
-
-const AuthenticationScreen: FC = props => {
- const {pinRetryCounter, onPressFunc, onCancelFunc} = props;
-
- return (
-
-
- Success
- Work in progress...
-
-
-
- )};
-
-const styles = StyleSheet.create({
- heading: {
- textAlign: 'center',
- fontSize: 30,
- fontFamily: 'Inconsolata Medium',
- color: '#199515',
- marginTop: '50%'
- },
- prompt: {
- textAlign: 'center',
- fontSize: 18,
- fontFamily: 'Inconsolata Regular',
- color: 'white',
- marginTop: '5%'
- }
-});
-
-export default AuthenticationScreen;
\ No newline at end of file
diff --git a/src/components/steps/HomeScreen.tsx b/src/components/steps/HomeScreen.tsx
new file mode 100644
index 0000000..1aa1606
--- /dev/null
+++ b/src/components/steps/HomeScreen.tsx
@@ -0,0 +1,62 @@
+import {FC, useEffect } from "react";
+import { StyleSheet, Text, View } from "react-native";
+import Button from "../Button";
+import { useCameraDevice, useCameraPermission, useCodeScanner } from "react-native-vision-camera";
+
+type HomeScreenProps = {
+ walletKey: string;
+ onPressFunc: (sessionId: string, challenge: string) => void;
+ onCancelFunc: () => void;
+};
+
+const HomeScreen: FC = props => {
+ const {walletKey, onPressFunc, onCancelFunc} = props;
+ const cameraDevice = useCameraDevice('back')
+ const { hasPermission, requestPermission } = useCameraPermission();
+ const codeScanner = useCodeScanner({
+ codeTypes: ['qr'],
+ onCodeScanned: (codes) => {
+ console.log(`Scanned ${codes.length} codes!`)
+ }
+ });
+
+ const walletAddress = () => {
+ return walletKey;
+ }
+
+ useEffect(() => {
+ if (!hasPermission) {
+ if (!requestPermission()) {
+ onCancelFunc();
+ };
+ }
+ });
+
+ return (
+
+
+ Success
+ {walletAddress()}
+
+
+
+ )};
+
+const styles = StyleSheet.create({
+ heading: {
+ textAlign: 'center',
+ fontSize: 30,
+ fontFamily: 'Inconsolata Medium',
+ color: '#199515',
+ marginTop: '50%'
+ },
+ prompt: {
+ textAlign: 'center',
+ fontSize: 18,
+ fontFamily: 'Inconsolata Regular',
+ color: 'white',
+ marginTop: '5%'
+ }
+});
+
+export default HomeScreen;
\ No newline at end of file