Merge branch 'main' of https://github.com/status-im/keycard-exit
This commit is contained in:
commit
b5d00c8d69
|
@ -8,6 +8,7 @@
|
|||
"name": "KeycardExit",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "^2.0.0",
|
||||
"react": "18.3.1",
|
||||
"react-native": "0.75.2",
|
||||
"react-native-modal": "^13.0.1",
|
||||
|
@ -2935,6 +2936,17 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-async-storage/async-storage": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.0.0.tgz",
|
||||
"integrity": "sha512-af6H9JjfL6G/PktBfUivvexoiFKQTJGQCtSWxMdivLzNIY94mu9DdiY0JqCSg/LyPCLGKhHPUlRQhNvpu3/KVA==",
|
||||
"dependencies": {
|
||||
"merge-options": "^3.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native": "^0.0.0-0 || >=0.65 <1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/cli": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-14.0.0.tgz",
|
||||
|
@ -8298,6 +8310,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-obj": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
|
@ -10688,6 +10708,17 @@
|
|||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
|
||||
},
|
||||
"node_modules/merge-options": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
|
||||
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
|
||||
"dependencies": {
|
||||
"is-plain-obj": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "^2.0.0",
|
||||
"react": "18.3.1",
|
||||
"react-native": "0.75.2",
|
||||
"react-native-modal": "^13.0.1",
|
||||
|
|
78
src/Main.tsx
78
src/Main.tsx
|
@ -1,14 +1,16 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Platform, SafeAreaView, StyleSheet, useColorScheme, DeviceEventEmitter } from 'react-native';
|
||||
import { SafeAreaView, StyleSheet, useColorScheme, DeviceEventEmitter } from 'react-native';
|
||||
import { Colors } from 'react-native/Libraries/NewAppScreen';
|
||||
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 NFCModal from './NFCModal';
|
||||
|
||||
//@ts-ignore
|
||||
import Keycard from "react-native-status-keycard";
|
||||
import InitializationScreen from './components/steps/InitializationScreen';
|
||||
import NFCModal from './NFCModal';
|
||||
import MnemonicScreen from './components/steps/MnemonicScreen';
|
||||
import AuthenticationScreen from './components/steps/AuthenticationScreen';
|
||||
|
||||
enum Step {
|
||||
Discovery,
|
||||
|
@ -26,11 +28,45 @@ const Main = () => {
|
|||
const stepRef = useRef(step);
|
||||
const pinRef = useRef("");
|
||||
const mnemonicRef = useRef("");
|
||||
const isListeningCard = useRef(false);
|
||||
|
||||
const getPairings = async () => {
|
||||
const pairingJSON = await AsyncStorage.getItem("pairings");
|
||||
return pairingJSON ? JSON.parse(pairingJSON) : {};
|
||||
}
|
||||
|
||||
const addPairing = async (instanceUID, pairing) => {
|
||||
const pairings = await getPairings();
|
||||
pairings[instanceUID] = {pairing: pairing};
|
||||
return AsyncStorage.setItem("pairings", JSON.stringify(pairings));
|
||||
}
|
||||
|
||||
const isCardLost = (err) => {
|
||||
return (err == "Tag was lost.") || err.includes("NFCError:100");
|
||||
}
|
||||
|
||||
const wrongPINCounter = (err) => {
|
||||
const matches = /Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)/.exec(err)
|
||||
|
||||
if (matches && matches.length == 2) {
|
||||
return parseInt(matches[1])
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const keycardConnectHandler = async () => {
|
||||
if (!isListeningCard.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const appInfo = await Keycard.getApplicationInfo();
|
||||
|
||||
if (appInfo["new-pairing"]) {
|
||||
await addPairing(appInfo["instance-uid"], appInfo["new-pairing"]);
|
||||
}
|
||||
|
||||
switch (stepRef.current) {
|
||||
case Step.Discovery:
|
||||
if (appInfo["initialized?"]) {
|
||||
|
@ -58,22 +94,39 @@ const Main = () => {
|
|||
setStep(Step.Discovery);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pinRef.current) {
|
||||
await Keycard.unpair(pinRef.current);
|
||||
} catch (err: any) {
|
||||
if (isCardLost(err.message)) {
|
||||
console.log("connection to card lost");
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
const pinRetryCounter = wrongPINCounter(err.message);
|
||||
|
||||
if (pinRetryCounter !== null) {
|
||||
//TODO: better handling
|
||||
console.log("wrong PIN. Retry counter: " + pinRetryCounter);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
await Keycard.stopNFC("");
|
||||
setIsModalVisible(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
stepRef.current = step;
|
||||
isListeningCard.current = isModalVisible;
|
||||
|
||||
if (!didMount.current) {
|
||||
didMount.current = true;
|
||||
|
||||
const loadPairing = async () => {
|
||||
await Keycard.setPairings(await getPairings());
|
||||
};
|
||||
|
||||
loadPairing().catch(console.log);
|
||||
DeviceEventEmitter.addListener("keyCardOnConnected", keycardConnectHandler);
|
||||
DeviceEventEmitter.addListener("keyCardOnDisconnected", () => console.log("keycard disconnected"));
|
||||
DeviceEventEmitter.addListener("keyCardOnNFCEnabled", () => console.log("nfc enabled"));
|
||||
|
@ -92,9 +145,7 @@ const Main = () => {
|
|||
|
||||
await Keycard.startNFC("Tap your Keycard");
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
setIsModalVisible(true);
|
||||
}
|
||||
setIsModalVisible(true);
|
||||
}
|
||||
|
||||
const initPin = async (p: string) => {
|
||||
|
@ -103,9 +154,10 @@ const Main = () => {
|
|||
}
|
||||
|
||||
const loadMnemonic = (mnemonic: string, p?: string) => {
|
||||
if(p) {
|
||||
if (p) {
|
||||
pinRef.current = p;
|
||||
}
|
||||
|
||||
mnemonicRef.current = mnemonic;
|
||||
|
||||
return connectCard();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, {FC, useEffect, useState } from "react";
|
||||
import {StyleSheet, Text, View } from "react-native";
|
||||
import {Platform, StyleSheet, Text, View } from "react-native";
|
||||
import Modal from "react-native-modal/dist/modal";
|
||||
|
||||
type NFCModalProps = {
|
||||
|
@ -11,7 +11,7 @@ const NFCModal: FC<NFCModalProps> = props => {
|
|||
const {isVisible, onChangeFunc} = props;
|
||||
|
||||
return (
|
||||
<Modal isVisible={isVisible} onSwipeComplete={() => onChangeFunc(!isVisible)} swipeDirection={['up', 'left', 'right', 'down']} style={modalStyle.modalContainer}>
|
||||
<Modal isVisible={(Platform.OS === 'android') && isVisible} onSwipeComplete={() => onChangeFunc(!isVisible)} swipeDirection={['up', 'left', 'right', 'down']} style={modalStyle.modalContainer}>
|
||||
<View style={modalStyle.container}>
|
||||
<Text style={modalStyle.header}>Ready to Scan</Text>
|
||||
<Text style={modalStyle.prompt}>Tap your Keycard</Text>
|
||||
|
|
Loading…
Reference in New Issue