mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
SEL-269: Update ESLint rules & lock prettier config (#781)
* Update ESLint config and lock prettier config * Refine ESLint config and fix lint issues * Apply eslint fixes * Use socketIo alias (#782) * move gesture handler * save wip updates * fix svg imports * update tsconfig * eslint updates * eslint fixes * improve ignore folders * coderabbit feedback * Fix style prop shorthands (#787) * Expand view style props * Expand remaining style props * update types * fix pipeline * fix test env check * nicer casting * fix booleans * update deeplink url handling and make it more robust * add socket error handler
This commit is contained in:
@@ -8,10 +8,20 @@ import {
|
||||
AuthorizeResult,
|
||||
} from 'react-native-app-auth';
|
||||
|
||||
// Ensure the client ID is available at runtime (skip in test environment)
|
||||
const isTestEnvironment =
|
||||
process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID;
|
||||
|
||||
if (!isTestEnvironment && !GOOGLE_SIGNIN_ANDROID_CLIENT_ID) {
|
||||
throw new Error(
|
||||
'GOOGLE_SIGNIN_ANDROID_CLIENT_ID environment variable is not set',
|
||||
);
|
||||
}
|
||||
|
||||
const config: AuthConfiguration = {
|
||||
// DEBUG: log config for Auth
|
||||
// ensure this prints the correct values before calling authorize
|
||||
clientId: GOOGLE_SIGNIN_ANDROID_CLIENT_ID,
|
||||
clientId: GOOGLE_SIGNIN_ANDROID_CLIENT_ID || 'mock-client-id',
|
||||
redirectUrl: 'com.proofofpassportapp:/oauth2redirect',
|
||||
scopes: ['https://www.googleapis.com/auth/drive.appdata'],
|
||||
serviceConfiguration: {
|
||||
|
||||
@@ -1,34 +1,94 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11
|
||||
|
||||
import queryString from 'query-string';
|
||||
import { parseUrl } from 'query-string';
|
||||
import { Linking, Platform } from 'react-native';
|
||||
|
||||
import { navigationRef } from '../navigation';
|
||||
import { useSelfAppStore } from '../stores/selfAppStore';
|
||||
import useUserStore from '../stores/userStore';
|
||||
|
||||
// Validation patterns for each expected parameter
|
||||
const VALIDATION_PATTERNS = {
|
||||
sessionId: /^[a-zA-Z0-9_-]+$/,
|
||||
selfApp: /^[\s\S]*$/, // JSON strings can contain any characters, we'll validate JSON parsing separately
|
||||
mock_passport: /^[\s\S]*$/, // JSON strings can contain any characters, we'll validate JSON parsing separately
|
||||
} as const;
|
||||
|
||||
type ValidatedParams = {
|
||||
sessionId?: string;
|
||||
selfApp?: string;
|
||||
mock_passport?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a URL-encoded string.
|
||||
* @param {string} encodedUrl
|
||||
* @returns {string}
|
||||
* Validates and sanitizes a query parameter value
|
||||
* @param key - The parameter key
|
||||
* @param value - The parameter value to validate
|
||||
* @returns The sanitized value or undefined if invalid
|
||||
*/
|
||||
const decodeUrl = (encodedUrl: string): string => {
|
||||
const validateAndSanitizeParam = (
|
||||
key: string,
|
||||
value: string,
|
||||
): string | undefined => {
|
||||
if (!value) return undefined;
|
||||
|
||||
// Decode the value first
|
||||
let decodedValue: string;
|
||||
try {
|
||||
return decodeURIComponent(encodedUrl);
|
||||
decodedValue = decodeURIComponent(value);
|
||||
} catch (error) {
|
||||
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
||||
console.error('Error decoding URL:', error);
|
||||
console.error(`Error decoding parameter ${key}:`, error);
|
||||
}
|
||||
return encodedUrl;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Validate against pattern if we have one for this key
|
||||
if (key in VALIDATION_PATTERNS) {
|
||||
const pattern =
|
||||
VALIDATION_PATTERNS[key as keyof typeof VALIDATION_PATTERNS];
|
||||
if (!pattern.test(decodedValue)) {
|
||||
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
||||
console.error(`Parameter ${key} failed validation:`, decodedValue);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return decodedValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses and validates query parameters from a URL
|
||||
* @param uri - The URL to parse
|
||||
* @returns Validated and sanitized parameters
|
||||
*/
|
||||
export const parseAndValidateUrlParams = (uri: string): ValidatedParams => {
|
||||
// Parse the URL directly without pre-decoding to avoid issues with fragment separators
|
||||
const parsed = parseUrl(uri);
|
||||
const query = parsed.query || {};
|
||||
|
||||
const validatedParams: ValidatedParams = {};
|
||||
|
||||
// Only process expected parameters and validate them
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (key in VALIDATION_PATTERNS && typeof value === 'string') {
|
||||
const sanitizedValue = validateAndSanitizeParam(key, value);
|
||||
if (sanitizedValue !== undefined) {
|
||||
validatedParams[key as keyof ValidatedParams] = sanitizedValue;
|
||||
}
|
||||
} else if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
||||
// Log unexpected parameters in development
|
||||
console.warn(`Unexpected or invalid parameter ignored: ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
return validatedParams;
|
||||
};
|
||||
|
||||
export const handleUrl = (uri: string) => {
|
||||
const decodedUri = decodeUrl(uri);
|
||||
const encodedData = queryString.parseUrl(decodedUri).query;
|
||||
const sessionId = encodedData.sessionId;
|
||||
const selfAppStr = encodedData.selfApp as string | undefined;
|
||||
const mock_passport = encodedData.mock_passport as string | undefined;
|
||||
const validatedParams = parseAndValidateUrlParams(uri);
|
||||
const { sessionId, selfApp: selfAppStr, mock_passport } = validatedParams;
|
||||
|
||||
if (selfAppStr) {
|
||||
try {
|
||||
|
||||
@@ -22,7 +22,7 @@ interface Inputs {
|
||||
export const scan = async (inputs: Inputs) => {
|
||||
if (MIXPANEL_NFC_PROJECT_TOKEN) {
|
||||
if (Platform.OS === 'ios') {
|
||||
const enableDebugLogs = ENABLE_DEBUG_LOGS === 'true';
|
||||
const enableDebugLogs = JSON.parse(String(ENABLE_DEBUG_LOGS));
|
||||
NativeModules.PassportReader.configure(
|
||||
MIXPANEL_NFC_PROJECT_TOKEN,
|
||||
enableDebugLogs,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PCR0_MANAGER_ADDRESS, RPC_URL } from '@selfxyz/common';
|
||||
import { decode } from '@stablelib/cbor';
|
||||
import { fromBER } from 'asn1js';
|
||||
import { Buffer } from 'buffer';
|
||||
import elliptic from 'elliptic';
|
||||
import { ec as ellipticEc } from 'elliptic';
|
||||
import { ethers } from 'ethers';
|
||||
import { sha384 } from 'js-sha512';
|
||||
import { Certificate } from 'pkijs';
|
||||
@@ -289,7 +289,7 @@ function getPublicKeyFromPem(pem: string) {
|
||||
const curve = 'p384';
|
||||
const publicKeyBuffer =
|
||||
cert.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
|
||||
const ec = new elliptic.ec(curve);
|
||||
const ec = new ellipticEc(curve);
|
||||
const key = ec.keyFromPublic(publicKeyBuffer);
|
||||
const x_point = key.getPublic().getX().toString('hex');
|
||||
const y_point = key.getPublic().getY().toString('hex');
|
||||
@@ -337,7 +337,7 @@ function verifyCertificateSignature(child: string, parent: string): boolean {
|
||||
const publicKeyBuffer_csca =
|
||||
publicKeyInfo_csca.subjectPublicKey.valueBlock.valueHexView;
|
||||
const curve = 'p384';
|
||||
const ec_csca = new elliptic.ec(curve);
|
||||
const ec_csca = new ellipticEc(curve);
|
||||
const key_csca = ec_csca.keyFromPublic(publicKeyBuffer_csca);
|
||||
|
||||
const tbsHash = getTBSHash(child);
|
||||
|
||||
@@ -19,7 +19,7 @@ import { sha384 } from 'js-sha512';
|
||||
* to ensure that the TEE's COSE_Sign1 attestation document has not been tampered with.
|
||||
* @see https://docs.aws.amazon.com/enclaves/latest/user/set-up-attestation.html for p384 sha384 usage
|
||||
*/
|
||||
export const cose = {
|
||||
const cose = {
|
||||
sign: {
|
||||
verify: async (
|
||||
data: Buffer,
|
||||
|
||||
@@ -5,22 +5,20 @@ import { SMT } from '@openpassport/zk-kit-smt';
|
||||
import {
|
||||
attributeToPosition,
|
||||
attributeToPosition_ID,
|
||||
calculateUserIdentifierHash,
|
||||
DEFAULT_MAJORITY,
|
||||
DocumentCategory,
|
||||
ID_CARD_ATTESTATION_ID,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
SelfAppDisclosureConfig,
|
||||
} from '@selfxyz/common';
|
||||
import { SelfApp } from '@selfxyz/common';
|
||||
import { getCircuitNameFromPassportData } from '@selfxyz/common';
|
||||
import {
|
||||
generateCircuitInputsDSC,
|
||||
generateCircuitInputsRegister,
|
||||
generateCircuitInputsVCandDisclose,
|
||||
getCircuitNameFromPassportData,
|
||||
hashEndpointWithScope,
|
||||
ID_CARD_ATTESTATION_ID,
|
||||
PASSPORT_ATTESTATION_ID,
|
||||
PassportData,
|
||||
SelfApp,
|
||||
SelfAppDisclosureConfig,
|
||||
} from '@selfxyz/common';
|
||||
import { hashEndpointWithScope } from '@selfxyz/common';
|
||||
import { calculateUserIdentifierHash } from '@selfxyz/common';
|
||||
import { PassportData } from '@selfxyz/common';
|
||||
import { poseidon2 } from 'poseidon-lite';
|
||||
|
||||
import { useProtocolStore } from '../../stores/protocolStore';
|
||||
@@ -79,14 +77,13 @@ export function generateTEEInputsDisclose(
|
||||
throw new Error('OFAC trees not loaded');
|
||||
}
|
||||
let passportNoAndNationalitySMT: SMT | null = null;
|
||||
let nameAndDobSMT, nameAndYobSMT;
|
||||
const nameAndDobSMT = new SMT(poseidon2, true);
|
||||
const nameAndYobSMT = new SMT(poseidon2, true);
|
||||
if (document === 'passport') {
|
||||
passportNoAndNationalitySMT = new SMT(poseidon2, true);
|
||||
passportNoAndNationalitySMT.import(ofac_trees.passportNoAndNationality);
|
||||
}
|
||||
nameAndDobSMT = new SMT(poseidon2, true);
|
||||
nameAndDobSMT.import(ofac_trees.nameAndDob);
|
||||
nameAndYobSMT = new SMT(poseidon2, true);
|
||||
nameAndYobSMT.import(ofac_trees.nameAndYob);
|
||||
|
||||
const serialized_tree = useProtocolStore.getState()[document].commitment_tree;
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
SelfApp,
|
||||
} from '@selfxyz/common';
|
||||
import forge from 'node-forge';
|
||||
import io, { Socket } from 'socket.io-client';
|
||||
import socketIo, { Socket } from 'socket.io-client';
|
||||
import { v4 } from 'uuid';
|
||||
import { AnyActorRef, createActor, createMachine } from 'xstate';
|
||||
import { create } from 'zustand';
|
||||
@@ -405,7 +405,7 @@ export const useProvingStore = create<ProvingState>((set, get) => {
|
||||
}
|
||||
|
||||
const url = getWSDbRelayerUrl(endpointType);
|
||||
let socket: Socket | null = io(url, {
|
||||
const socket: Socket = socketIo(url, {
|
||||
path: '/',
|
||||
transports: ['websocket'],
|
||||
});
|
||||
@@ -417,6 +417,37 @@ export const useProvingStore = create<ProvingState>((set, get) => {
|
||||
trackEvent(ProofEvents.SOCKETIO_SUBSCRIBED);
|
||||
});
|
||||
|
||||
socket.on('connect_error', error => {
|
||||
console.error('SocketIO connection error:', error);
|
||||
trackEvent(ProofEvents.SOCKETIO_CONNECT_ERROR, {
|
||||
message: (error as any).message,
|
||||
});
|
||||
trackEvent(ProofEvents.PROOF_FAILED, {
|
||||
circuitType: get().circuitType,
|
||||
error: get().error_code ?? 'unknown',
|
||||
});
|
||||
actor!.send({ type: 'PROVE_ERROR' });
|
||||
set({ socketConnection: null });
|
||||
});
|
||||
|
||||
socket.on('disconnect', (reason: string) => {
|
||||
console.log(`SocketIO disconnected. Reason: ${reason}`);
|
||||
const currentActor = actor;
|
||||
|
||||
if (get().currentState === 'ready_to_prove' && currentActor) {
|
||||
console.error(
|
||||
'SocketIO disconnected unexpectedly during proof listening.',
|
||||
);
|
||||
trackEvent(ProofEvents.SOCKETIO_DISCONNECT_UNEXPECTED);
|
||||
trackEvent(ProofEvents.PROOF_FAILED, {
|
||||
circuitType: get().circuitType,
|
||||
error: get().error_code ?? 'unknown',
|
||||
});
|
||||
currentActor.send({ type: 'PROVE_ERROR' });
|
||||
}
|
||||
set({ socketConnection: null });
|
||||
});
|
||||
|
||||
socket.on('status', (message: any) => {
|
||||
const data =
|
||||
typeof message === 'string' ? JSON.parse(message) : message;
|
||||
@@ -451,37 +482,6 @@ export const useProvingStore = create<ProvingState>((set, get) => {
|
||||
actor!.send({ type: 'PROVE_SUCCESS' });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('disconnect', (reason: string) => {
|
||||
console.log(`SocketIO disconnected. Reason: ${reason}`);
|
||||
const currentActor = actor;
|
||||
|
||||
if (get().currentState === 'ready_to_prove' && currentActor) {
|
||||
console.error(
|
||||
'SocketIO disconnected unexpectedly during proof listening.',
|
||||
);
|
||||
trackEvent(ProofEvents.SOCKETIO_DISCONNECT_UNEXPECTED);
|
||||
trackEvent(ProofEvents.PROOF_FAILED, {
|
||||
circuitType: get().circuitType,
|
||||
error: get().error_code ?? 'unknown',
|
||||
});
|
||||
currentActor.send({ type: 'PROVE_ERROR' });
|
||||
}
|
||||
set({ socketConnection: null });
|
||||
});
|
||||
|
||||
socket.on('connect_error', error => {
|
||||
console.error('SocketIO connection error:', error);
|
||||
trackEvent(ProofEvents.SOCKETIO_CONNECT_ERROR, {
|
||||
message: (error as any).message,
|
||||
});
|
||||
trackEvent(ProofEvents.PROOF_FAILED, {
|
||||
circuitType: get().circuitType,
|
||||
error: get().error_code ?? 'unknown',
|
||||
});
|
||||
actor!.send({ type: 'PROVE_ERROR' });
|
||||
set({ socketConnection: null });
|
||||
});
|
||||
},
|
||||
|
||||
_handleWsOpen: () => {
|
||||
|
||||
Reference in New Issue
Block a user