This commit is contained in:
Michele Balistreri 2024-10-01 10:05:07 +02:00
parent 349b817fb9
commit b542c32e6d
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
4 changed files with 77 additions and 6 deletions

13
package-lock.json generated
View File

@ -8,6 +8,7 @@
"name": "KeycardExit",
"version": "0.0.1",
"dependencies": {
"@noble/hashes": "^1.5.0",
"@react-native-async-storage/async-storage": "^2.0.0",
"react": "18.3.1",
"react-native": "0.75.3",
@ -3111,6 +3112,18 @@
"eslint-scope": "5.1.1"
}
},
"node_modules/@noble/hashes": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz",
"integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==",
"license": "MIT",
"engines": {
"node": "^14.21.3 || >=16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",

View File

@ -11,6 +11,7 @@
"android-build-dev": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && cd android && gradlew assembleDebug"
},
"dependencies": {
"@noble/hashes": "^1.5.0",
"@react-native-async-storage/async-storage": "^2.0.0",
"react": "18.3.1",
"react-native": "0.75.3",

View File

@ -12,6 +12,8 @@ import NFCModal from './NFCModal';
//@ts-ignore
import Keycard from "react-native-status-keycard";
import Dialpad from './components/Dialpad';
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@noble/hashes/utils';
enum Step {
Discovery,
@ -25,6 +27,7 @@ enum Step {
const Main = () => {
const PIN_MAX_RETRY = 3;
const WALLET_DERIVATION_PATH = "m/84'/0'/0'/0/0";
const LOGIN_ENDPOINT = "https://exit.logos.co/keycard/auth";
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [step, setStep] = useState(Step.Discovery);
@ -36,8 +39,8 @@ const Main = () => {
const mnemonicRef = useRef("");
const isListeningCard = useRef(false);
const walletKey = useRef("");
const sessionId = useRef("")
const challenge = useRef("")
const sessionRef = useRef("")
const challengeRef = useRef("")
const getPairings = async () => {
const pairingJSON = await AsyncStorage.getItem("pairings");
@ -68,12 +71,29 @@ const Main = () => {
return null
}
const loginRequest = async () => {
var req = {'session-id': sessionRef.current};
const identChallenge = bytesToHex(sha256('Keycard auth' + challengeRef.current));
const data = await Keycard.verifyCard(identChallenge);
req['keycard-auth'] = data['tlv-data'];
const walletChallenge = bytesToHex(sha256('Wallet auth' + challengeRef.current));
req['wallet-auth'] = await Keycard.signWithPath(pinRef.current, WALLET_DERIVATION_PATH, walletChallenge);
challengeRef.current = "";
sessionRef.current = "";
return JSON.stringify(req);
}
const keycardConnectHandler = async () => {
if (!isListeningCard.current) {
return;
}
var newPinCounter = pinCounter;
var loginReq = "";
try {
const appInfo = await Keycard.getApplicationInfo();
@ -108,6 +128,9 @@ const Main = () => {
walletKey.current = await Keycard.exportKeyWithPath(pinRef.current, WALLET_DERIVATION_PATH);
setStep(Step.Home);
break;
case Step.Home:
loginReq = await loginRequest();
break;
case Step.FactoryReset:
await Keycard.factoryReset();
setStep(Step.Discovery);
@ -141,6 +164,27 @@ const Main = () => {
await Keycard.stopNFC("");
setIsModalVisible(false);
if (loginReq) {
console.log(loginReq);
try {
const resp = await fetch(LOGIN_ENDPOINT, {
method: 'POST',
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
body: loginReq,
});
const respJson = resp.json();
if (respJson['error']) {
//TODO: handle error
}
//TODO: handle success
} catch (e) {
//TODO: handle error
}
}
}
useEffect(() => {
@ -208,7 +252,9 @@ const Main = () => {
}
const login = (sessionId: string, challenge: string) => {
sessionRef.current = sessionId;
challengeRef.current = challenge;
return connectCard();
}
const cancel = () => {

View File

@ -23,9 +23,20 @@ const HomeScreen: FC<HomeScreenProps> = props => {
const codeScanner = useCodeScanner({
codeTypes: ['qr'],
onCodeScanned: (codes) => {
console.log(`Scanned ${codes.length} codes!`)
//TODO: implement
setStep(HomeSteps.Home);
if ((codes.length != 1) || !codes[0].value) {
return;
}
try {
const payload = JSON.parse(codes[0].value);
if (!payload["challenge"] || !payload["session-id"]) {
return;
}
setStep(HomeSteps.Home);
onPressFunc(payload["session-id"], payload["challenge"]);
} catch(e) {}
}
});