feat: allow VC sharing between Android and iOS

This commit is contained in:
Paolo Miguel de Leon
2022-08-05 16:20:41 +08:00
parent 5b5449020d
commit 61f895b6b6
15 changed files with 654 additions and 832 deletions

View File

@@ -2,7 +2,7 @@ import React from 'react';
import {
FlexStyle,
StyleProp,
SafeAreaView,
View,
ViewStyle,
StyleSheet,
ScrollView,
@@ -50,7 +50,7 @@ function createLayout(
{props.children}
</ScrollView>
) : (
<SafeAreaView style={styles}>{props.children}</SafeAreaView>
<View style={styles}>{props.children}</View>
);
};

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { StyleProp, TextStyle, StyleSheet, Text as RNText } from 'react-native';
import { Colors, spacing } from './styleUtils';
import { Colors, Spacing, spacing } from './styleUtils';
const styles = StyleSheet.create({
base: {
@@ -52,7 +52,7 @@ interface TextProps {
color?: string;
weight?: 'regular' | 'semibold' | 'bold';
align?: TextStyle['textAlign'];
margin?: string;
margin?: Spacing;
size?: 'small' | 'smaller' | 'regular';
lineHeight?: number;
numLines?: number;

View File

@@ -1,5 +1,7 @@
// import SmartShare from '@idpass/smartshare-react-native';
const SmartShare = {};
import SmartshareReactNative from '@idpass/smartshare-react-native';
const { IdpassSmartshare, GoogleNearbyMessages } = SmartshareReactNative;
import uuid from 'react-native-uuid';
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
import { EmitterSubscription, Platform } from 'react-native';
import { assign, EventFrom, send, sendParent, StateFrom } from 'xstate';
@@ -17,11 +19,10 @@ import {
} from '../shared/constants';
import { ActivityLogEvents } from './activityLog';
import { VcEvents } from './vc';
import {
addOnErrorListener,
connect,
publish,
} from 'react-native-google-nearby-messages';
import { ConnectionParams } from '@idpass/smartshare-react-native/lib/typescript/IdpassSmartshare';
import { gnmSubscribe } from '../shared/smartshare';
type SharingProtocol = 'OFFLINE' | 'ONLINE';
const model = createModel(
{
@@ -31,6 +32,9 @@ const model = createModel(
incomingVc: {} as VC,
connectionParams: '',
loggers: [] as EmitterSubscription[],
sharingProtocol: (Platform.OS === 'ios'
? 'ONLINE'
: 'OFFLINE') as SharingProtocol,
},
{
events: {
@@ -39,7 +43,6 @@ const model = createModel(
CANCEL: () => ({}),
DISMISS: () => ({}),
VC_RECEIVED: (vc: VC) => ({ vc }),
RESPONSE_SENT: () => ({}),
CONNECTED: () => ({}),
DISCONNECT: () => ({}),
EXCHANGE_DONE: (senderInfo: DeviceInfo) => ({ senderInfo }),
@@ -52,6 +55,7 @@ const model = createModel(
RECEIVE_DEVICE_INFO: (info: DeviceInfo) => ({ info }),
RECEIVED_VCS_UPDATED: () => ({}),
VC_RESPONSE: (response: unknown) => ({ response }),
SWITCH_PROTOCOL: (value: boolean) => ({ value }),
},
}
);
@@ -73,6 +77,10 @@ export const requestMachine = model.createMachine(
on: {
SCREEN_BLUR: 'inactive',
SCREEN_FOCUS: 'checkingBluetoothService',
SWITCH_PROTOCOL: {
target: 'checkingBluetoothService',
actions: 'switchProtocol',
},
},
states: {
inactive: {
@@ -247,6 +255,11 @@ export const requestMachine = model.createMachine(
},
{
actions: {
switchProtocol: assign({
sharingProtocol: (_context, event) =>
event.value ? 'ONLINE' : 'OFFLINE',
}),
requestReceivedVcs: send(VcEvents.GET_RECEIVED_VCS(), {
to: (context) => context.serviceRefs.vc,
}),
@@ -257,20 +270,29 @@ export const requestMachine = model.createMachine(
receiverInfo: (_context, event) => event.info,
}),
disconnect: () => {
disconnect: (context) => {
try {
Platform.OS === 'android' && SmartShare.destroyConnection();
if (context.sharingProtocol === 'OFFLINE') {
IdpassSmartshare.destroyConnection();
} else {
GoogleNearbyMessages.disconnect();
}
} catch (e) {
// pass
}
},
generateConnectionParams: assign({
connectionParams: () => {
if (Platform.OS === 'android') {
return SmartShare.getConnectionParameters();
connectionParams: (context) => {
if (context.sharingProtocol === 'OFFLINE') {
return IdpassSmartshare.getConnectionParameters();
} else {
return 'TEST';
const cid = uuid.v4();
console.log('ONLINE', cid);
return JSON.stringify({
pk: '',
cid,
});
}
},
}),
@@ -285,26 +307,26 @@ export const requestMachine = model.createMachine(
registerLoggers: assign({
loggers: () => {
// if (__DEV__) {
// return [
// SmartShare.handleNearbyEvents((event) => {
// console.log(
// getDeviceNameSync(),
// '<Receiver.Event>',
// JSON.stringify(event)
// );
// }),
// SmartShare.handleLogEvents((event) => {
// console.log(
// getDeviceNameSync(),
// '<Receiver.Log>',
// JSON.stringify(event)
// );
// }),
// ];
// } else {
return [];
// }
if (__DEV__) {
return [
IdpassSmartshare.handleNearbyEvents((event) => {
console.log(
getDeviceNameSync(),
'<Receiver.Event>',
JSON.stringify(event)
);
}),
IdpassSmartshare.handleLogEvents((event) => {
console.log(
getDeviceNameSync(),
'<Receiver.Log>',
JSON.stringify(event)
);
}),
];
} else {
return [];
}
},
}),
@@ -373,14 +395,14 @@ export const requestMachine = model.createMachine(
services: {
checkBluetoothService: () => (callback) => {
// const subscription = BluetoothStateManager.onStateChange((state) => {
// if (state === 'PoweredOn') {
// callback(model.events.BLUETOOTH_ENABLED());
// } else {
// callback(model.events.BLUETOOTH_DISABLED());
// }
// }, true);
// return () => subscription.remove();
const subscription = BluetoothStateManager.onStateChange((state) => {
if (state === 'PoweredOn') {
callback(model.events.BLUETOOTH_ENABLED());
} else {
callback(model.events.BLUETOOTH_DISABLED());
}
}, true);
return () => subscription.remove();
},
requestBluetooth: () => (callback) => {
@@ -389,8 +411,46 @@ export const requestMachine = model.createMachine(
.catch(() => callback(model.events.BLUETOOTH_DISABLED()));
},
advertiseDevice: (context) => (callback) => {
if (context.sharingProtocol === 'OFFLINE') {
IdpassSmartshare.createConnection('advertiser', () => {
callback({ type: 'CONNECTED' });
});
} else {
GoogleNearbyMessages.addOnErrorListener((kind, message) =>
console.log('\n\n[request] GNM Error', kind, message)
);
GoogleNearbyMessages.connect({
apiKey: GNM_API_KEY,
discoveryMediums: ['ble'],
discoveryModes: ['broadcast'],
}).then(() => {
console.log('[request] GNM connected!');
gnmSubscribe<ConnectionParams>(
'pairing',
async (scannedQrParams) => {
try {
const generatedParams = JSON.parse(
context.connectionParams
) as ConnectionParams;
if (scannedQrParams.cid === generatedParams.cid) {
const message = new Message('pairing', 'cid:matches');
await GoogleNearbyMessages.publish(message.toString());
callback({ type: 'CONNECTED' });
}
} catch (e) {
console.error('Could not parse message.', e);
}
}
);
});
}
},
checkConnection: () => (callback) => {
const subscription = SmartShare.handleNearbyEvents((event) => {
const subscription = IdpassSmartshare.handleNearbyEvents((event) => {
if (event.type === 'onDisconnected') {
callback({ type: 'DISCONNECT' });
}
@@ -399,53 +459,73 @@ export const requestMachine = model.createMachine(
return () => subscription.remove();
},
advertiseDevice: () => (callback) => {
SmartShare.createConnection('advertiser', () => {
callback({ type: 'CONNECTED' });
});
},
exchangeDeviceInfo: (context) => (callback) => {
const subscription = SmartShare.handleNearbyEvents((event) => {
if (event.type !== 'msg') return;
const response = new Message(
'exchange:receiver-info',
context.receiverInfo
);
const message = Message.fromString<DeviceInfo>(event.data);
if (message.type === 'exchange:sender-info') {
const response = new Message(
'exchange:receiver-info',
context.receiverInfo
);
SmartShare.send(response.toString(), () => {
callback({ type: 'EXCHANGE_DONE', senderInfo: message.data });
});
}
});
if (context.sharingProtocol === 'OFFLINE') {
const subscription = IdpassSmartshare.handleNearbyEvents((event) => {
if (event.type !== 'msg') return;
return () => subscription.remove();
const message = Message.fromString<DeviceInfo>(event.data);
if (message.type === 'exchange:sender-info') {
IdpassSmartshare.send(response.toString(), () => {
callback({ type: 'EXCHANGE_DONE', senderInfo: message.data });
});
}
});
return () => subscription.remove();
} else {
gnmSubscribe<DeviceInfo>(
'exchange:sender-info',
async (senderInfo) => {
await GoogleNearbyMessages.unpublish();
await GoogleNearbyMessages.publish(response.toString());
callback({ type: 'EXCHANGE_DONE', senderInfo });
}
);
}
},
receiveVc: () => (callback) => {
// const subscription = SmartShare.handleNearbyEvents((event) => {
// if (event.type === 'onDisconnected') {
// callback({ type: 'DISCONNECT' });
// }
// if (event.type !== 'msg') return;
// const message = Message.fromString<VC>(event.data);
// if (message.type === 'send:vc') {
// callback({ type: 'VC_RECEIVED', vc: message.data });
// }
// });
// return () => subscription.remove();
receiveVc: (context) => (callback) => {
if (context.sharingProtocol === 'OFFLINE') {
const subscription = IdpassSmartshare.handleNearbyEvents((event) => {
if (event.type === 'onDisconnected') {
callback({ type: 'DISCONNECT' });
}
if (event.type !== 'msg') return;
const message = Message.fromString<VC>(event.data);
if (message.type === 'send:vc') {
callback({ type: 'VC_RECEIVED', vc: message.data });
}
});
return () => subscription.remove();
} else {
gnmSubscribe<VC>('send:vc', async (vc) => {
await GoogleNearbyMessages.unpublish();
callback({ type: 'VC_RECEIVED', vc });
});
}
},
sendVcResponse: (_context, _event, meta) => (callback) => {
const response = new Message('send:vc:response', {
sendVcResponse: (context, _event, meta) => () => {
const message = new Message('send:vc:response', {
status: meta.data.status,
});
SmartShare.send(response.toString(), () => {
callback({ type: 'RESPONSE_SENT' });
});
if (context.sharingProtocol === 'OFFLINE') {
IdpassSmartshare.send(message.toString(), () => {
/*pass*/
});
} else {
GoogleNearbyMessages.publish(message.toString());
}
},
},
@@ -484,6 +564,10 @@ export function selectIncomingVc(state: State) {
return state.context.incomingVc;
}
export function selectSharingProtocol(state: State) {
return state.context.sharingProtocol;
}
export function selectIsReviewing(state: State) {
return state.matches('reviewing');
}

View File

@@ -3,20 +3,20 @@
export interface Typegen0 {
'@@xstate/typegen': true;
'internalEvents': {
'xstate.stop': { type: 'xstate.stop' };
'': { type: '' };
'xstate.after(CLEAR_DELAY)#clearingConnection': {
type: 'xstate.after(CLEAR_DELAY)#clearingConnection';
};
'xstate.init': { type: 'xstate.init' };
'xstate.stop': { type: 'xstate.stop' };
};
'invokeSrcNameMap': {
checkConnection: 'done.invoke.request:invocation[0]';
checkBluetoothService: 'done.invoke.request.checkingBluetoothService.checking:invocation[0]';
requestBluetooth: 'done.invoke.request.checkingBluetoothService.requesting:invocation[0]';
advertiseDevice: 'done.invoke.waitingForConnection:invocation[0]';
checkBluetoothService: 'done.invoke.request.checkingBluetoothService.checking:invocation[0]';
checkConnection: 'done.invoke.request:invocation[0]';
exchangeDeviceInfo: 'done.invoke.request.exchangingDeviceInfo:invocation[0]';
receiveVc: 'done.invoke.request.waitingForVc:invocation[0]';
requestBluetooth: 'done.invoke.request.checkingBluetoothService.requesting:invocation[0]';
sendVcResponse:
| 'done.invoke.accepted:invocation[0]'
| 'done.invoke.request.reviewing.rejected:invocation[0]';
@@ -29,42 +29,49 @@ export interface Typegen0 {
};
'eventsCausingActions': {
disconnect:
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop'
| 'DISMISS'
| ''
| 'DISCONNECT';
setReceiverInfo: 'RECEIVE_DEVICE_INFO';
setSenderInfo: 'EXCHANGE_DONE';
setIncomingVc: 'VC_RECEIVED';
removeLoggers:
| 'DISCONNECT'
| 'DISMISS'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.init'
| 'xstate.after(CLEAR_DELAY)#clearingConnection'
| 'DISMISS';
registerLoggers: 'xstate.after(CLEAR_DELAY)#clearingConnection' | 'DISMISS';
| 'SWITCH_PROTOCOL'
| 'xstate.stop';
generateConnectionParams:
| 'xstate.after(CLEAR_DELAY)#clearingConnection'
| 'DISMISS';
requestReceiverInfo: 'CONNECTED';
requestReceivedVcs: 'ACCEPT';
requestExistingVc: 'VC_RESPONSE';
| 'DISMISS'
| 'xstate.after(CLEAR_DELAY)#clearingConnection';
logReceived: 'STORE_RESPONSE';
mergeIncomingVc: 'STORE_RESPONSE';
prependReceivedVc: 'VC_RESPONSE';
storeVc: 'STORE_RESPONSE';
registerLoggers: 'DISMISS' | 'xstate.after(CLEAR_DELAY)#clearingConnection';
removeLoggers:
| 'DISMISS'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'SWITCH_PROTOCOL'
| 'xstate.after(CLEAR_DELAY)#clearingConnection'
| 'xstate.init';
requestExistingVc: 'VC_RESPONSE';
requestReceivedVcs: 'ACCEPT';
requestReceiverInfo: 'CONNECTED';
sendVcReceived: 'STORE_RESPONSE';
logReceived: 'STORE_RESPONSE';
setIncomingVc: 'VC_RECEIVED';
setReceiverInfo: 'RECEIVE_DEVICE_INFO';
setSenderInfo: 'EXCHANGE_DONE';
storeVc: 'STORE_RESPONSE';
switchProtocol: 'SWITCH_PROTOCOL';
};
'eventsCausingServices': {
checkConnection: 'SCREEN_BLUR' | 'SCREEN_FOCUS' | 'xstate.init';
checkBluetoothService: 'SCREEN_FOCUS';
requestBluetooth: 'BLUETOOTH_DISABLED';
advertiseDevice: 'xstate.after(CLEAR_DELAY)#clearingConnection' | 'DISMISS';
advertiseDevice: 'DISMISS' | 'xstate.after(CLEAR_DELAY)#clearingConnection';
checkBluetoothService: 'SCREEN_FOCUS' | 'SWITCH_PROTOCOL';
checkConnection:
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'SWITCH_PROTOCOL'
| 'xstate.init';
exchangeDeviceInfo: 'RECEIVE_DEVICE_INFO';
receiveVc: 'EXCHANGE_DONE';
sendVcResponse: 'STORE_RESPONSE' | 'REJECT' | 'CANCEL';
requestBluetooth: 'BLUETOOTH_DISABLED';
sendVcResponse: 'CANCEL' | 'REJECT' | 'STORE_RESPONSE';
};
'eventsCausingGuards': {
hasExistingVc: 'VC_RESPONSE';
@@ -73,43 +80,43 @@ export interface Typegen0 {
CLEAR_DELAY: '';
};
'matchesStates':
| 'inactive'
| 'bluetoothDenied'
| 'checkingBluetoothService'
| 'checkingBluetoothService.checking'
| 'checkingBluetoothService.requesting'
| 'checkingBluetoothService.enabled'
| 'bluetoothDenied'
| 'checkingBluetoothService.requesting'
| 'clearingConnection'
| 'waitingForConnection'
| 'preparingToExchangeInfo'
| 'disconnected'
| 'exchangingDeviceInfo'
| 'waitingForVc'
| 'inactive'
| 'preparingToExchangeInfo'
| 'reviewing'
| 'reviewing.idle'
| 'reviewing.accepted'
| 'reviewing.accepting'
| 'reviewing.accepting.requestingReceivedVcs'
| 'reviewing.accepting.requestingExistingVc'
| 'reviewing.accepting.mergingIncomingVc'
| 'reviewing.accepting.prependingReceivedVc'
| 'reviewing.accepting.requestingExistingVc'
| 'reviewing.accepting.requestingReceivedVcs'
| 'reviewing.accepting.storingVc'
| 'reviewing.accepted'
| 'reviewing.rejected'
| 'reviewing.idle'
| 'reviewing.navigatingToHome'
| 'disconnected'
| 'reviewing.rejected'
| 'waitingForConnection'
| 'waitingForVc'
| {
checkingBluetoothService?: 'checking' | 'requesting' | 'enabled';
checkingBluetoothService?: 'checking' | 'enabled' | 'requesting';
reviewing?:
| 'idle'
| 'accepting'
| 'accepted'
| 'rejected'
| 'accepting'
| 'idle'
| 'navigatingToHome'
| 'rejected'
| {
accepting?:
| 'requestingReceivedVcs'
| 'requestingExistingVc'
| 'mergingIncomingVc'
| 'prependingReceivedVc'
| 'requestingExistingVc'
| 'requestingReceivedVcs'
| 'storingVc';
};
};

View File

@@ -1,15 +1,13 @@
import SmartShare from '@idpass/smartshare-react-native';
import SmartshareReactNative from '@idpass/smartshare-react-native';
import { ConnectionParams } from '@idpass/smartshare-react-native/lib/typescript/IdpassSmartshare';
const { IdpassSmartshare, GoogleNearbyMessages } = SmartshareReactNative;
// import LocationEnabler from 'react-native-location-enabler';
const LocationEnabler = {};
import SystemSetting from 'react-native-system-setting';
import { assign, EventFrom, send, sendParent, StateFrom } from 'xstate';
import { createModel } from 'xstate/lib/model';
import {
EmitterSubscription,
Linking,
PermissionsAndroid,
Platform,
} from 'react-native';
import { EmitterSubscription, Linking, PermissionsAndroid } from 'react-native';
import { DeviceInfo } from '../components/DeviceInfoList';
import { Message } from '../shared/Message';
import { getDeviceNameSync } from 'react-native-device-info';
@@ -17,16 +15,14 @@ import { VC } from '../types/vc';
import { AppServices } from '../shared/GlobalContext';
import { ActivityLogEvents } from './activityLog';
import { GNM_API_KEY, VC_ITEM_STORE_KEY } from '../shared/constants';
import {
addOnErrorListener,
connect,
subscribe,
} from 'react-native-google-nearby-messages';
import { gnmSubscribe, issSubscribe } from '../shared/smartshare';
const checkingAirplaneMode = '#checkingAirplaneMode';
const checkingLocationService = '#checkingLocationService';
const findingConnection = '#scan.findingConnection';
type SharingProtocol = 'OFFLINE' | 'ONLINE';
const model = createModel(
{
serviceRefs: {} as AppServices,
@@ -41,6 +37,8 @@ const model = createModel(
needBle: true,
},
vcName: '',
sharingProtocol: 'OFFLINE' as SharingProtocol,
scannedQrParams: '',
},
{
events: {
@@ -83,7 +81,7 @@ export const scanMachine = model.createMachine(
id: 'scan',
initial: 'inactive',
invoke: {
src: 'checkConnection',
src: 'monitorConnection',
},
on: {
SCREEN_BLUR: 'inactive',
@@ -177,17 +175,19 @@ export const scanMachine = model.createMachine(
},
findingConnection: {
id: 'findingConnection',
entry: ['removeLoggers', 'registerLoggers'],
invoke: {
src: 'findConnection',
},
entry: ['removeLoggers', 'registerLoggers', 'clearScannedQrParams'],
on: {
SCAN: [
{
cond: 'isQrValid',
cond: 'isQrOffline',
target: 'preparingToConnect',
actions: ['setConnectionParams'],
},
{
cond: 'isQrOnline',
target: 'preparingToConnect',
actions: ['setScannedQrParams'],
},
{ target: 'invalid' },
],
FLIGHT_ENABLED: checkingAirplaneMode,
@@ -299,18 +299,31 @@ export const scanMachine = model.createMachine(
SystemSetting.switchAirplane();
},
disconnect: () => {
disconnect: (context) => {
try {
Platform.OS === 'android' && SmartShare.destroyConnection();
if (context.sharingProtocol === 'OFFLINE') {
IdpassSmartshare.destroyConnection();
} else {
GoogleNearbyMessages.disconnect();
}
} catch (e) {
//
}
},
setConnectionParams: (_, event) => {
SmartShare.setConnectionParameters(event.params);
setConnectionParams: (_context, event) => {
IdpassSmartshare.setConnectionParameters(event.params);
},
setScannedQrParams: model.assign({
scannedQrParams: (_context, event) => event.params,
sharingProtocol: 'ONLINE',
}),
clearScannedQrParams: assign({
scannedQrParams: '',
}),
setReceiverInfo: model.assign({
receiverInfo: (_, event) => event.receiverInfo,
}),
@@ -332,27 +345,27 @@ export const scanMachine = model.createMachine(
}),
registerLoggers: assign({
loggers: () => {
// if (__DEV__) {
// return [
// SmartShare.handleNearbyEvents((event) => {
// console.log(
// getDeviceNameSync(),
// '<Sender.Event>',
// JSON.stringify(event)
// );
// }),
// SmartShare.handleLogEvents((event) => {
// console.log(
// getDeviceNameSync(),
// '<Sender.Log>',
// JSON.stringify(event)
// );
// }),
// ];
// } else {
return [];
// }
loggers: (context) => {
if (context.sharingProtocol === 'OFFLINE' && __DEV__) {
return [
IdpassSmartshare.handleNearbyEvents((event) => {
console.log(
getDeviceNameSync(),
'<Sender.Event>',
JSON.stringify(event)
);
}),
IdpassSmartshare.handleLogEvents((event) => {
console.log(
getDeviceNameSync(),
'<Sender.Log>',
JSON.stringify(event)
);
}),
];
} else {
return [];
}
},
}),
@@ -382,16 +395,6 @@ export const scanMachine = model.createMachine(
},
services: {
checkConnection: () => (callback) => {
const subscription = SmartShare.handleNearbyEvents((event) => {
if (event.type === 'onDisconnected') {
callback({ type: 'DISCONNECT' });
}
});
return () => subscription.remove();
},
checkLocationPermission: () => async (callback) => {
try {
// wait a bit for animation to finish when app becomes active
@@ -418,7 +421,17 @@ export const scanMachine = model.createMachine(
}
},
checkLocationStatus: (context) => (callback) => {
monitorConnection: () => (callback) => {
const subscription = IdpassSmartshare.handleNearbyEvents((event) => {
if (event.type === 'onDisconnected') {
callback({ type: 'DISCONNECT' });
}
});
return () => subscription.remove();
},
checkLocationStatus: () => (callback) => {
// const listener = LocationEnabler.addListener(({ locationEnabled }) => {
// if (locationEnabled) {
// callback(model.events.LOCATION_ENABLED());
@@ -428,6 +441,7 @@ export const scanMachine = model.createMachine(
// });
// LocationEnabler.checkSettings(context.locationConfig);
// return () => listener.remove();
callback(model.events.LOCATION_ENABLED());
},
checkAirplaneMode: () => (callback) => {
@@ -440,30 +454,83 @@ export const scanMachine = model.createMachine(
});
},
discoverDevice: () => (callback) => {
SmartShare.createConnection('discoverer', () => {
callback({ type: 'CONNECTED' });
});
discoverDevice: (context) => (callback) => {
if (context.sharingProtocol === 'OFFLINE') {
IdpassSmartshare.createConnection('discoverer', () => {
callback({ type: 'CONNECTED' });
});
} else {
GoogleNearbyMessages.addOnErrorListener((kind, message) =>
console.log('\n\n[scan] GNM Error', kind, message)
);
GoogleNearbyMessages.connect({
apiKey: GNM_API_KEY,
discoveryMediums: ['ble'],
discoveryModes: ['scan'],
}).then(() => {
console.log('[scan] GNM connected!');
gnmSubscribe<string>('pairing', async (status) => {
await GoogleNearbyMessages.unpublish();
if (status === 'cid:matches') {
callback({ type: 'CONNECTED' });
}
});
const message = new Message(
'pairing',
JSON.parse(context.scannedQrParams)
);
GoogleNearbyMessages.publish(message.toString());
});
// GoogleNearbyMessages.subscribe(
// async (message) => {
// console.log('[scan] discoverDevice FOUND:', message);
// await GoogleNearbyMessages.unpublish();
// message === 'CID_MATCHED' && callback({ type: 'CONNECTED' });
// },
// (message) => console.log('[scan] discoverDevice LOST:', message)
// );
}
},
exchangeDeviceInfo: (context) => (callback) => {
let subscription: EmitterSubscription;
const message = new Message('exchange:sender-info', context.senderInfo);
SmartShare.send(message.toString(), () => {
subscription = SmartShare.handleNearbyEvents((event) => {
if (event.type !== 'msg') return;
const response = Message.fromString<DeviceInfo>(event.data);
if (response.type === 'exchange:receiver-info') {
callback({
type: 'EXCHANGE_DONE',
receiverInfo: response.data,
});
}
});
});
return () => subscription?.remove();
if (context.sharingProtocol === 'OFFLINE') {
let subscription: EmitterSubscription;
IdpassSmartshare.send(message.toString(), () => {
subscription = IdpassSmartshare.handleNearbyEvents((event) => {
if (event.type === 'onDisconnected') {
callback({ type: 'DISCONNECT' });
}
if (event.type !== 'msg') return;
const response = Message.fromString<DeviceInfo>(event.data);
if (response.type === 'exchange:receiver-info') {
callback({
type: 'EXCHANGE_DONE',
receiverInfo: response.data,
});
}
});
});
return () => subscription?.remove();
} else {
gnmSubscribe<DeviceInfo>(
'exchange:receiver-info',
async (receiverInfo) => {
await GoogleNearbyMessages.unpublish();
callback({ type: 'EXCHANGE_DONE', receiverInfo });
}
);
GoogleNearbyMessages.publish(message.toString());
}
},
sendVc: (context) => (callback) => {
@@ -476,39 +543,49 @@ export const scanMachine = model.createMachine(
const message = new Message<VC>('send:vc', vc);
SmartShare.send(message.toString(), () => {
subscription = SmartShare.handleNearbyEvents((event) => {
if (event.type === 'onDisconnected') {
callback({ type: 'DISCONNECT' });
}
if (event.type !== 'msg') return;
const response = Message.fromString<SendVcStatus>(event.data);
if (response.type === 'send:vc:response') {
callback({
type:
response.data.status === 'accepted'
? 'VC_ACCEPTED'
: 'VC_REJECTED',
});
}
const statusCallback = (data: SendVcStatus) => {
callback({
type: data.status === 'accepted' ? 'VC_ACCEPTED' : 'VC_REJECTED',
});
});
};
return () => subscription?.remove();
if (context.sharingProtocol === 'OFFLINE') {
IdpassSmartshare.send(message.toString(), () => {
subscription = issSubscribe<SendVcStatus>(
'send:vc:response',
statusCallback
);
});
return () => subscription?.remove();
} else {
gnmSubscribe<SendVcStatus>('send:vc:response', statusCallback);
GoogleNearbyMessages.publish(message.toString());
}
},
},
guards: {
isQrValid: (_, event) => {
// const param: SmartShare.ConnectionParams = Object.create(null);
// try {
// Object.assign(param, JSON.parse(event.params));
// return 'cid' in param && 'pk' in param;
// } catch (e) {
return false;
// }
isQrOffline: (_context, event) => {
console.log('isQrOffline', event.params);
const param: ConnectionParams = Object.create(null);
try {
Object.assign(param, JSON.parse(event.params));
return 'cid' in param && 'pk' in param && param.pk !== '';
} catch (e) {
return false;
}
},
isQrOnline: (_context, event) => {
console.log('isQrOnline', event.params);
const param: ConnectionParams = Object.create(null);
try {
Object.assign(param, JSON.parse(event.params));
return 'cid' in param && 'pk' in param && param.pk === '';
} catch (e) {
return false;
}
},
},

View File

@@ -3,134 +3,135 @@
export interface Typegen0 {
'@@xstate/typegen': true;
'internalEvents': {
'xstate.stop': { type: 'xstate.stop' };
'xstate.after(CLEAR_DELAY)#clearingConnection': {
type: 'xstate.after(CLEAR_DELAY)#clearingConnection';
};
'xstate.init': { type: 'xstate.init' };
'xstate.stop': { type: 'xstate.stop' };
};
'invokeSrcNameMap': {
checkConnection: 'done.invoke.scan:invocation[0]';
checkAirplaneMode: 'done.invoke.scan.checkingAirplaneMode.checkingStatus:invocation[0]';
checkLocationStatus: 'done.invoke.checkingLocationService:invocation[0]';
checkLocationPermission: 'done.invoke.scan.checkingLocationService.checkingPermission:invocation[0]';
findConnection: 'done.invoke.findingConnection:invocation[0]';
checkLocationStatus: 'done.invoke.checkingLocationService:invocation[0]';
discoverDevice: 'done.invoke.scan.connecting:invocation[0]';
exchangeDeviceInfo: 'done.invoke.scan.exchangingDeviceInfo:invocation[0]';
monitorConnection: 'done.invoke.scan:invocation[0]';
sendVc: 'done.invoke.scan.reviewing.sendingVc:invocation[0]';
};
'missingImplementations': {
actions: never;
services: 'findConnection';
services: never;
guards: never;
delays: never;
};
'eventsCausingActions': {
disconnect:
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop'
| 'CANCEL'
| 'DISMISS'
| 'DISCONNECT'
| 'LOCATION_ENABLED';
clearReason:
| 'CANCEL'
| 'DISCONNECT'
| 'DISMISS'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop'
| 'xstate.stop';
clearScannedQrParams:
| 'CANCEL'
| 'DISCONNECT'
| 'DISMISS'
| 'DISCONNECT';
| 'xstate.after(CLEAR_DELAY)#clearingConnection';
disconnect:
| 'CANCEL'
| 'DISCONNECT'
| 'DISMISS'
| 'LOCATION_ENABLED'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.stop';
logShared: 'VC_ACCEPTED';
openSettings: 'LOCATION_REQUEST';
setConnectionParams: 'SCAN';
setSenderInfo: 'RECEIVE_DEVICE_INFO';
setReceiverInfo: 'EXCHANGE_DONE';
setReason: 'UPDATE_REASON';
setSelectedVc: 'SELECT_VC';
registerLoggers:
| 'CANCEL'
| 'DISCONNECT'
| 'DISMISS'
| 'xstate.after(CLEAR_DELAY)#clearingConnection';
removeLoggers:
| 'CANCEL'
| 'DISCONNECT'
| 'DISMISS'
| 'SCREEN_BLUR'
| 'SCREEN_FOCUS'
| 'xstate.init'
| 'xstate.after(CLEAR_DELAY)#clearingConnection'
| 'CANCEL'
| 'DISMISS'
| 'DISCONNECT';
| 'xstate.init';
requestSenderInfo: 'SCAN';
requestToDisableFlightMode: 'FLIGHT_REQUEST';
requestToEnableLocation: 'LOCATION_DISABLED' | 'LOCATION_REQUEST';
registerLoggers:
| 'xstate.after(CLEAR_DELAY)#clearingConnection'
| 'CANCEL'
| 'DISMISS'
| 'DISCONNECT';
requestSenderInfo: 'SCAN';
logShared: 'VC_ACCEPTED';
setConnectionParams: 'SCAN';
setReason: 'UPDATE_REASON';
setReceiverInfo: 'EXCHANGE_DONE';
setScannedQrParams: 'SCAN';
setSelectedVc: 'SELECT_VC';
setSenderInfo: 'RECEIVE_DEVICE_INFO';
};
'eventsCausingServices': {
checkConnection: 'SCREEN_BLUR' | 'SCREEN_FOCUS' | 'xstate.init';
checkAirplaneMode: 'SCREEN_FOCUS' | 'FLIGHT_ENABLED' | 'APP_ACTIVE';
checkAirplaneMode: 'APP_ACTIVE' | 'FLIGHT_ENABLED' | 'SCREEN_FOCUS';
checkLocationPermission: 'APP_ACTIVE' | 'LOCATION_ENABLED';
checkLocationStatus: 'FLIGHT_DISABLED';
checkLocationPermission: 'LOCATION_ENABLED' | 'APP_ACTIVE';
findConnection:
| 'xstate.after(CLEAR_DELAY)#clearingConnection'
| 'CANCEL'
| 'DISMISS'
| 'DISCONNECT';
discoverDevice: 'RECEIVE_DEVICE_INFO';
exchangeDeviceInfo: 'CONNECTED';
monitorConnection: 'SCREEN_BLUR' | 'SCREEN_FOCUS' | 'xstate.init';
sendVc: 'SELECT_VC';
};
'eventsCausingGuards': {
isQrValid: 'SCAN';
isQrOffline: 'SCAN';
isQrOnline: 'SCAN';
};
'eventsCausingDelays': {
CLEAR_DELAY: 'LOCATION_ENABLED';
};
'matchesStates':
| 'inactive'
| 'checkingAirplaneMode'
| 'checkingAirplaneMode.checkingStatus'
| 'checkingAirplaneMode.requestingToDisable'
| 'checkingAirplaneMode.enabled'
| 'checkingAirplaneMode.requestingToDisable'
| 'checkingLocationService'
| 'checkingLocationService.checkingStatus'
| 'checkingLocationService.requestingToEnable'
| 'checkingLocationService.checkingPermission'
| 'checkingLocationService.checkingStatus'
| 'checkingLocationService.denied'
| 'checkingLocationService.disabled'
| 'checkingLocationService.requestingToEnable'
| 'clearingConnection'
| 'findingConnection'
| 'preparingToConnect'
| 'connecting'
| 'disconnected'
| 'exchangingDeviceInfo'
| 'findingConnection'
| 'inactive'
| 'invalid'
| 'preparingToConnect'
| 'reviewing'
| 'reviewing.accepted'
| 'reviewing.cancelled'
| 'reviewing.idle'
| 'reviewing.navigatingToHome'
| 'reviewing.rejected'
| 'reviewing.selectingVc'
| 'reviewing.sendingVc'
| 'reviewing.accepted'
| 'reviewing.rejected'
| 'reviewing.cancelled'
| 'reviewing.navigatingToHome'
| 'disconnected'
| 'invalid'
| {
checkingAirplaneMode?:
| 'checkingStatus'
| 'requestingToDisable'
| 'enabled';
| 'enabled'
| 'requestingToDisable';
checkingLocationService?:
| 'checkingStatus'
| 'requestingToEnable'
| 'checkingPermission'
| 'checkingStatus'
| 'denied'
| 'disabled';
| 'disabled'
| 'requestingToEnable';
reviewing?:
| 'idle'
| 'selectingVc'
| 'sendingVc'
| 'accepted'
| 'rejected'
| 'cancelled'
| 'navigatingToHome';
| 'idle'
| 'navigatingToHome'
| 'rejected'
| 'selectingVc'
| 'sendingVc';
};
'tags': never;
}

View File

@@ -1,148 +0,0 @@
import SmartShare from '@idpass/smartshare-react-native';
import { EmitterSubscription } from 'react-native';
import { createModel } from 'xstate/lib/model';
import { Message } from '../shared/Message';
import { EventFrom } from 'xstate';
const model = createModel(
{
eventChannel: {} as EmitterSubscription,
logChannel: {} as EmitterSubscription,
connectedTo: {} as DeviceInfo,
mode: '' as SmartShare.ConnectionMode,
},
{
events: {
DISCOVER: () => ({}),
ADVERTISE: (params: SmartShare.ConnectionParams) => ({ params }),
DEVICE_FOUND: (qrCode: string) => ({ qrCode }),
EVENT: (event: SmartShare.NearbyEvent) => ({ event }),
SEND: (message: Message<unknown>) => ({ message }),
SENT: () => ({}),
LOG: (message: string) => ({ message }),
DESTROY: () => ({}),
// $msg: () => ({}),
// $transferupdate: () => ({}),
// $onDisconnected: () => ({}),
},
}
);
type DeviceFoundEvent = EventFrom<typeof model, 'DEVICE_FOUND'>;
export const smartShareMachine = model.createMachine(
{
id: 'smartshare',
context: model.initialContext,
invoke: {
src: 'listenForLogs',
},
initial: 'idle',
states: {
idle: {
on: {
DISCOVER: {
target: 'connecting',
actions: ['setDiscoverer'],
},
ADVERTISE: {
target: 'connecting',
actions: ['setAdvertiser'],
},
},
},
connecting: {
invoke: {
src: 'connect',
},
on: {
DEVICE_FOUND: [
{
cond: 'isQrValid',
target: 'connected',
},
{ target: 'invalid' },
],
},
},
connected: {
invoke: {
src: 'listenForEvents',
},
on: {},
},
disconnected: {
type: 'final',
},
invalid: {
type: 'final',
},
},
},
{
actions: {
setAdvertiser: model.assign({ mode: 'advertiser' }),
setDiscoverer: model.assign({ mode: 'discoverer' }),
},
services: {
connect: (context) => (callback) => {
SmartShare.createConnection(context.mode, () => {
callback(model.events.DEVICE_FOUND());
});
},
listenForEvents: () => (callback, onReceive) => {
const subscription = SmartShare.handleNearbyEvents((event) => {
callback(model.events.EVENT(event));
});
onReceive((event: EventFrom<typeof model>) => {
switch (event.type) {
case 'SEND':
SmartShare.send(event.message.toString(), () => {
callback(model.events.SENT());
});
break;
case 'DESTROY':
SmartShare.destroyConnection();
break;
}
});
return () => subscription.remove();
},
listenForLogs: () => (callback) => {
const subscription = SmartShare.handleLogEvents((event) => {
callback(model.events.LOG(event.log));
});
return () => subscription.remove();
},
},
guards: {
isQrValid: (context, event: DeviceFoundEvent) => {
const params: SmartShare.ConnectionParams = Object.create(null);
try {
Object.assign(params, JSON.parse(event.qrCode));
return 'cid' in params && 'pk' in params;
} catch (e) {
return false;
}
},
},
delays: {
// TIMEOUT: 5000
},
}
);
export interface DeviceInfo {
deviceName: string;
name: string;
deviceId: string;
}

View File

@@ -2,19 +2,6 @@
export interface Typegen0 {
'@@xstate/typegen': true;
'eventsCausingActions': {
setEncryptionKey: 'KEY_RECEIVED';
forwardStoreRequest:
| 'GET'
| 'SET'
| 'APPEND'
| 'PREPEND'
| 'REMOVE'
| 'CLEAR';
notifyParent:
| 'KEY_RECEIVED'
| 'done.invoke.store.resettingStorage:invocation[0]';
};
'internalEvents': {
'error.platform.store.resettingStorage:invocation[0]': {
type: 'error.platform.store.resettingStorage:invocation[0]';
@@ -45,11 +32,24 @@ export interface Typegen0 {
guards: never;
delays: never;
};
'eventsCausingActions': {
setEncryptionKey: 'KEY_RECEIVED';
forwardStoreRequest:
| 'GET'
| 'SET'
| 'APPEND'
| 'PREPEND'
| 'REMOVE'
| 'CLEAR';
notifyParent:
| 'KEY_RECEIVED'
| 'done.invoke.store.resettingStorage:invocation[0]';
};
'eventsCausingServices': {
getEncryptionKey: 'xstate.init';
store: 'KEY_RECEIVED' | 'done.invoke.store.resettingStorage:invocation[0]';
generateEncryptionKey: 'ERROR';
clear: 'KEY_RECEIVED';
store: 'KEY_RECEIVED' | 'done.invoke.store.resettingStorage:invocation[0]';
};
'eventsCausingGuards': {};
'eventsCausingDelays': {};

412
package-lock.json generated
View File

@@ -16,7 +16,7 @@
"@digitalcredentials/vc": "^1.1.2",
"@expo-google-fonts/poppins": "^0.2.0",
"@expo/metro-config": "^0.3.12",
"@idpass/smartshare-react-native": "0.2.2",
"@idpass/smartshare-react-native": "idpass/smartshare-react-native#pmigueld/nearby-messages",
"@react-native-async-storage/async-storage": "~1.15.0",
"@react-native-community/netinfo": "7.1.3",
"@react-native-picker/picker": "2.2.1",
@@ -49,7 +49,6 @@
"react-native-device-info": "^8.4.8",
"react-native-elements": "^3.4.2",
"react-native-gesture-handler": "~2.1.0",
"react-native-google-nearby-messages": "^1.0.22",
"react-native-keychain": "^8.0.0",
"react-native-location-enabler": "^4.1.0",
"react-native-popable": "^0.4.3",
@@ -60,6 +59,7 @@
"react-native-simple-markdown": "^1.1.0",
"react-native-svg": "12.1.1",
"react-native-system-setting": "^1.7.6",
"react-native-uuid": "^2.0.1",
"react-native-vector-icons": "^8.1.0",
"xstate": "^4.26.0"
},
@@ -4257,7 +4257,7 @@
},
"node_modules/@idpass/smartshare-react-native": {
"version": "0.2.2",
"resolved": "git+ssh://git@github.com/idpass/smartshare-react-native.git#ba5b89bda5f2f394883e8579ab00243fcae73b29",
"resolved": "git+ssh://git@github.com/idpass/smartshare-react-native.git#c6199477299014d07f845bd6e5aacd1b55622441",
"license": "MIT",
"peerDependencies": {
"react": "*",
@@ -11468,6 +11468,20 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/expo-camera/node_modules/react": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/expo-cli": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/expo-cli/-/expo-cli-5.5.1.tgz",
@@ -22096,15 +22110,6 @@
"prop-types": "^15.7.2"
}
},
"node_modules/react-native-google-nearby-messages": {
"version": "1.0.22",
"resolved": "https://registry.npmjs.org/react-native-google-nearby-messages/-/react-native-google-nearby-messages-1.0.22.tgz",
"integrity": "sha512-uiBL6BR31fBnxccOM0KeQRCMI5YpYLOuLPo6xEoO92pNxsd09jDsqtOdexyLaXM0yWBdXM3ERyHNZTDDlvRhyg==",
"peerDependencies": {
"react": "^16.8.1",
"react-native": ">=0.60.0-rc.0 <1.0.x"
}
},
"node_modules/react-native-keychain": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-8.1.1.tgz",
@@ -22225,6 +22230,15 @@
"resolved": "https://registry.npmjs.org/react-native-system-setting/-/react-native-system-setting-1.7.6.tgz",
"integrity": "sha512-nBnIK5Xnyu8XRRA3BMzRI54oYlSBKc0oOTQdZOCEeOvn4ltS1nk2shj/vtMQe6khXvuhai3vIc+g7DcsOcr5+w=="
},
"node_modules/react-native-uuid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz",
"integrity": "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g==",
"engines": {
"node": ">=10.0.0",
"npm": ">=6.0.0"
}
},
"node_modules/react-native-vector-icons": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz",
@@ -26043,282 +26057,15 @@
"watchpack-chokidar2": "^2.0.1"
}
},
"node_modules/watchpack-chokidar2": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
"integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
"node_modules/watchpack/chokidar2": {
"version": "2.0.0",
"dev": true,
"optional": true,
"dependencies": {
"chokidar": "^2.1.8"
}
},
"node_modules/watchpack-chokidar2/node_modules/anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
"dev": true,
"optional": true,
"dependencies": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
}
},
"node_modules/watchpack-chokidar2/node_modules/anymatch/node_modules/normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
"dev": true,
"optional": true,
"dependencies": {
"remove-trailing-separator": "^1.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/braces": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"dev": true,
"optional": true,
"dependencies": {
"arr-flatten": "^1.1.0",
"array-unique": "^0.3.2",
"extend-shallow": "^2.0.1",
"fill-range": "^4.0.0",
"isobject": "^3.0.1",
"repeat-element": "^1.1.2",
"snapdragon": "^0.8.1",
"snapdragon-node": "^2.0.1",
"split-string": "^3.0.2",
"to-regex": "^3.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/braces/node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"optional": true,
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/chokidar": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies",
"dev": true,
"optional": true,
"dependencies": {
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"normalize-path": "^3.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.2.1",
"upath": "^1.1.1"
},
"optionalDependencies": {
"fsevents": "^1.2.7"
}
},
"node_modules/watchpack-chokidar2/node_modules/fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
"integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
"dev": true,
"optional": true,
"dependencies": {
"extend-shallow": "^2.0.1",
"is-number": "^3.0.0",
"repeat-string": "^1.6.1",
"to-regex-range": "^2.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/fill-range/node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"optional": true,
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/fsevents": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"dependencies": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
},
"engines": {
"node": ">= 4.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
"dev": true,
"optional": true,
"dependencies": {
"is-glob": "^3.1.0",
"path-dirname": "^1.0.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
"dev": true,
"optional": true,
"dependencies": {
"is-extglob": "^2.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
"dev": true,
"optional": true,
"dependencies": {
"binary-extensions": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"dev": true,
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
"dev": true,
"optional": true,
"dependencies": {
"kind-of": "^3.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/is-number/node_modules/kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
"dev": true,
"optional": true,
"dependencies": {
"is-buffer": "^1.1.5"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"dev": true,
"optional": true,
"dependencies": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack-chokidar2/node_modules/readdirp": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
"integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
"dev": true,
"optional": true,
"dependencies": {
"graceful-fs": "^4.1.11",
"micromatch": "^3.1.10",
"readable-stream": "^2.0.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/watchpack-chokidar2/node_modules/to-regex-range": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
"dev": true,
"optional": true,
"dependencies": {
"is-number": "^3.0.0",
"repeat-string": "^1.6.1"
},
"engines": {
"node": ">=0.10.0"
"node": "<8.10.0"
}
},
"node_modules/wbuf": {
@@ -31721,8 +31468,9 @@
"dev": true
},
"@idpass/smartshare-react-native": {
"version": "git+ssh://git@github.com/idpass/smartshare-react-native.git#ba5b89bda5f2f394883e8579ab00243fcae73b29",
"from": "@idpass/smartshare-react-native@0.2.2"
"version": "git+ssh://git@github.com/idpass/smartshare-react-native.git#c6199477299014d07f845bd6e5aacd1b55622441",
"from": "@idpass/smartshare-react-native@idpass/smartshare-react-native#pmigueld/nearby-messages",
"requires": {}
},
"@jest/create-cache-key-function": {
"version": "26.6.2",
@@ -32665,12 +32413,14 @@
"@react-native-community/netinfo": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-7.1.3.tgz",
"integrity": "sha512-E8q3yuges6NYhrXBDQdzwCnG0bBQXATRjs6fpTjRJ37nURmdpe4HLq1awvooG4ymGTpZhrx4elcs/aUM7PTgrA=="
"integrity": "sha512-E8q3yuges6NYhrXBDQdzwCnG0bBQXATRjs6fpTjRJ37nURmdpe4HLq1awvooG4ymGTpZhrx4elcs/aUM7PTgrA==",
"requires": {}
},
"@react-native-picker/picker": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.2.1.tgz",
"integrity": "sha512-EC7yv22QLHlTfnbC1ez9IUdXTOh1W31x96Oir0PfskSGFFJMWWdLTg4VrcE2DsGLzbfjjkBk123c173vf2a5MQ=="
"integrity": "sha512-EC7yv22QLHlTfnbC1ez9IUdXTOh1W31x96Oir0PfskSGFFJMWWdLTg4VrcE2DsGLzbfjjkBk123c173vf2a5MQ==",
"requires": {}
},
"@react-native/assets": {
"version": "1.0.0",
@@ -32712,7 +32462,8 @@
"@react-navigation/elements": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.3.tgz",
"integrity": "sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw=="
"integrity": "sha512-Lv2lR7si5gNME8dRsqz57d54m4FJtrwHRjNQLOyQO546ZxO+g864cSvoLC6hQedQU0+IJnPTsZiEI2hHqfpEpw==",
"requires": {}
},
"@react-navigation/native": {
"version": "6.0.11",
@@ -33484,7 +33235,8 @@
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true
"dev": true,
"requires": {}
},
"address": {
"version": "1.1.2",
@@ -33518,13 +33270,15 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
"dev": true
"dev": true,
"requires": {}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true
"dev": true,
"requires": {}
},
"alphanum-sort": {
"version": "1.0.2",
@@ -33960,7 +33714,8 @@
"babel-core": {
"version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
"integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg=="
"integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==",
"requires": {}
},
"babel-loader": {
"version": "8.1.0",
@@ -34849,6 +34604,12 @@
}
}
},
"chokidar2": {
"version": "file:node_modules/watchpack/chokidar2",
"requires": {
"chokidar": "^2.1.8"
}
},
"chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
@@ -36959,7 +36720,8 @@
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.13.0.tgz",
"integrity": "sha512-t3m7ta0EspzDxSOZh3cEOJIJVZgN/TlJYaBGnQlK6W/PZNbWep8q4RQskkJkA7/zwNpX0BaoEOSUUrqaADVoqA==",
"dev": true
"dev": true,
"requires": {}
},
"eslint-scope": {
"version": "5.1.1",
@@ -37713,7 +37475,8 @@
"expo-application": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-4.0.2.tgz",
"integrity": "sha512-ngTaFplTkWn0X45gMC+VNXGyJfGxX4wOwKmtr17rNMVWOQUhhLlyMkTj9bAamzsuwZh35l3S/eD/N1aMWWUwMw=="
"integrity": "sha512-ngTaFplTkWn0X45gMC+VNXGyJfGxX4wOwKmtr17rNMVWOQUhhLlyMkTj9bAamzsuwZh35l3S/eD/N1aMWWUwMw==",
"requires": {}
},
"expo-asset": {
"version": "8.4.6",
@@ -37753,6 +37516,17 @@
"requires": {
"dequal": "^1.0.0"
}
},
"react": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
"peer": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
}
}
}
},
@@ -38133,7 +37907,8 @@
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/expo-error-recovery/-/expo-error-recovery-3.0.5.tgz",
"integrity": "sha512-VM6OOecjt0aPu5/eCdGGJfNjvAZIemaQym0JF/+SA5IlLiPpEfbVCDTO/5yiS8Zb5fKpeABx+GCRmtfnFqvRRw==",
"optional": true
"optional": true,
"requires": {}
},
"expo-file-system": {
"version": "13.1.4",
@@ -38248,7 +38023,8 @@
"expo-image-loader": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-3.1.1.tgz",
"integrity": "sha512-ZX4Bh3K4CCX1aZflnmbOgFNLS+c0/GUys4wdvqxO+4A4KU1NNb3jE7RVa/OFYNPDcGhEw20c1QjyE/WsVURJpg=="
"integrity": "sha512-ZX4Bh3K4CCX1aZflnmbOgFNLS+c0/GUys4wdvqxO+4A4KU1NNb3jE7RVa/OFYNPDcGhEw20c1QjyE/WsVURJpg==",
"requires": {}
},
"expo-json-utils": {
"version": "0.2.1",
@@ -38258,7 +38034,8 @@
"expo-keep-awake": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-10.0.2.tgz",
"integrity": "sha512-Ro1lgyKldbFs4mxhWM+goX9sg0S2SRR8FiJJeOvaRzf8xNhrZfWA00Zpr+/3ocCoWQ3eEL+X9UF4PXXHf0KoOg=="
"integrity": "sha512-Ro1lgyKldbFs4mxhWM+goX9sg0S2SRR8FiJJeOvaRzf8xNhrZfWA00Zpr+/3ocCoWQ3eEL+X9UF4PXXHf0KoOg==",
"requires": {}
},
"expo-local-authentication": {
"version": "12.0.1",
@@ -39139,7 +38916,8 @@
"expo-updates-interface": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-0.5.1.tgz",
"integrity": "sha512-RLvC69o1BkhHP6hNaWiIvSiTgXABB9v4HnoietoXKFHlAyxlQCupy6ki164KpZNrOS/PFJ2WWqZOvKfiyDVO+w=="
"integrity": "sha512-RLvC69o1BkhHP6hNaWiIvSiTgXABB9v4HnoietoXKFHlAyxlQCupy6ki164KpZNrOS/PFJ2WWqZOvKfiyDVO+w==",
"requires": {}
},
"express": {
"version": "4.16.4",
@@ -45815,7 +45593,8 @@
"ws": {
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A=="
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
"requires": {}
}
}
},
@@ -45828,7 +45607,8 @@
"react-freeze": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.0.tgz",
"integrity": "sha512-yQaiOqDmoKqks56LN9MTgY06O0qQHgV4FUrikH357DydArSZHQhl0BJFqGKIZoTqi8JizF9Dxhuk1FIZD6qCaw=="
"integrity": "sha512-yQaiOqDmoKqks56LN9MTgY06O0qQHgV4FUrikH357DydArSZHQhl0BJFqGKIZoTqi8JizF9Dxhuk1FIZD6qCaw==",
"requires": {}
},
"react-i18next": {
"version": "11.18.3",
@@ -45911,7 +45691,8 @@
"react-native-bluetooth-state-manager": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/react-native-bluetooth-state-manager/-/react-native-bluetooth-state-manager-1.3.3.tgz",
"integrity": "sha512-hE4oG6/jFFIQMz9p0gitV90k61MAddJ0Ri86x9BvytMbdfreeeOU29eJwJWrM+PsNJWUH0w7ycbisj9i4RXp0A=="
"integrity": "sha512-hE4oG6/jFFIQMz9p0gitV90k61MAddJ0Ri86x9BvytMbdfreeeOU29eJwJWrM+PsNJWUH0w7ycbisj9i4RXp0A==",
"requires": {}
},
"react-native-codegen": {
"version": "0.0.6",
@@ -45926,7 +45707,8 @@
"react-native-device-info": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-8.7.0.tgz",
"integrity": "sha512-Zr0JNHSEPy2RWObWwUp9npTEWSG5HyY+nR/mRkf6ZTU5zd8oskarnPcCxAgwYhJbvshHSZbZIDRxCVCskXSpEA=="
"integrity": "sha512-Zr0JNHSEPy2RWObWwUp9npTEWSG5HyY+nR/mRkf6ZTU5zd8oskarnPcCxAgwYhJbvshHSZbZIDRxCVCskXSpEA==",
"requires": {}
},
"react-native-elements": {
"version": "3.4.2",
@@ -45971,11 +45753,6 @@
"prop-types": "^15.7.2"
}
},
"react-native-google-nearby-messages": {
"version": "1.0.22",
"resolved": "https://registry.npmjs.org/react-native-google-nearby-messages/-/react-native-google-nearby-messages-1.0.22.tgz",
"integrity": "sha512-uiBL6BR31fBnxccOM0KeQRCMI5YpYLOuLPo6xEoO92pNxsd09jDsqtOdexyLaXM0yWBdXM3ERyHNZTDDlvRhyg=="
},
"react-native-keychain": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-8.1.1.tgz",
@@ -45984,12 +45761,14 @@
"react-native-location-enabler": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/react-native-location-enabler/-/react-native-location-enabler-4.1.1.tgz",
"integrity": "sha512-1gXJ+NzH5JKpaR23t1P8afEB7TKKfBkdXk2avhNUuTBlhBrqa2HrL4uDwYHoc4ZcwchsVC2P0Q7gP9L5Ot+KJw=="
"integrity": "sha512-1gXJ+NzH5JKpaR23t1P8afEB7TKKfBkdXk2avhNUuTBlhBrqa2HrL4uDwYHoc4ZcwchsVC2P0Q7gP9L5Ot+KJw==",
"requires": {}
},
"react-native-popable": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/react-native-popable/-/react-native-popable-0.4.3.tgz",
"integrity": "sha512-khoK9TVLfJV+mBO5FTRx0eZip7djYVDfjaTRDhFPgVq2Exq9X6139Rfjg1sWHPvAQ2VCszTuC45o6iT373kFPw=="
"integrity": "sha512-khoK9TVLfJV+mBO5FTRx0eZip7djYVDfjaTRDhFPgVq2Exq9X6139Rfjg1sWHPvAQ2VCszTuC45o6iT373kFPw==",
"requires": {}
},
"react-native-qrcode-svg": {
"version": "6.1.2",
@@ -46011,7 +45790,8 @@
"react-native-safe-area-context": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz",
"integrity": "sha512-yOwiiPJ1rk+/nfK13eafbpW6sKW0jOnsRem2C1LPJjM3tfTof6hlvV5eWHATye3XOpu2cJ7N+HdkUvUDGwFD2Q=="
"integrity": "sha512-yOwiiPJ1rk+/nfK13eafbpW6sKW0jOnsRem2C1LPJjM3tfTof6hlvV5eWHATye3XOpu2cJ7N+HdkUvUDGwFD2Q==",
"requires": {}
},
"react-native-screens": {
"version": "3.10.2",
@@ -46042,7 +45822,8 @@
"react-native-size-matters": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
"integrity": "sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw=="
"integrity": "sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw==",
"requires": {}
},
"react-native-svg": {
"version": "12.1.1",
@@ -46058,6 +45839,11 @@
"resolved": "https://registry.npmjs.org/react-native-system-setting/-/react-native-system-setting-1.7.6.tgz",
"integrity": "sha512-nBnIK5Xnyu8XRRA3BMzRI54oYlSBKc0oOTQdZOCEeOvn4ltS1nk2shj/vtMQe6khXvuhai3vIc+g7DcsOcr5+w=="
},
"react-native-uuid": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz",
"integrity": "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g=="
},
"react-native-vector-icons": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-8.1.0.tgz",
@@ -48928,12 +48714,14 @@
"use-isomorphic-layout-effect": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
"requires": {}
},
"use-subscription": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.6.0.tgz",
"integrity": "sha512-0Y/cTLlZfw547tJhJMoRA16OUbVqRm6DmvGpiGbmLST6BIA5KU5cKlvlz8DVMrACnWpyEjCkgmhLatthP4jUbA=="
"integrity": "sha512-0Y/cTLlZfw547tJhJMoRA16OUbVqRm6DmvGpiGbmLST6BIA5KU5cKlvlz8DVMrACnWpyEjCkgmhLatthP4jUbA==",
"requires": {}
},
"util": {
"version": "0.11.1",

View File

@@ -20,7 +20,7 @@
"@digitalcredentials/vc": "^1.1.2",
"@expo-google-fonts/poppins": "^0.2.0",
"@expo/metro-config": "^0.3.12",
"@idpass/smartshare-react-native": "0.2.2",
"@idpass/smartshare-react-native": "idpass/smartshare-react-native#pmigueld/nearby-messages",
"@react-native-async-storage/async-storage": "~1.15.0",
"@react-native-community/netinfo": "7.1.3",
"@react-native-picker/picker": "2.2.1",
@@ -53,7 +53,6 @@
"react-native-device-info": "^8.4.8",
"react-native-elements": "^3.4.2",
"react-native-gesture-handler": "~2.1.0",
"react-native-google-nearby-messages": "^1.0.22",
"react-native-keychain": "^8.0.0",
"react-native-location-enabler": "^4.1.0",
"react-native-popable": "^0.4.3",
@@ -64,6 +63,7 @@
"react-native-simple-markdown": "^1.1.0",
"react-native-svg": "12.1.1",
"react-native-system-setting": "^1.7.6",
"react-native-uuid": "^2.0.1",
"react-native-vector-icons": "^8.1.0",
"xstate": "^4.26.0"
},

View File

@@ -1,12 +1,13 @@
import React from 'react';
import QRCode from 'react-native-qrcode-svg';
import { Centered, Column, Text } from '../../components/ui';
import { Centered, Column, Row, Text } from '../../components/ui';
import { Colors } from '../../components/ui/styleUtils';
import { MainRouteProps } from '../../routes/main';
import { ReceiveVcModal } from './ReceiveVcModal';
import { MessageOverlay } from '../../components/MessageOverlay';
import { useRequestScreen } from './RequestScreenController';
import { useTranslation } from 'react-i18next';
import { Switch } from 'react-native-elements';
export const RequestScreen: React.FC<MainRouteProps> = (props) => {
const { t } = useTranslation('RequestScreen');
@@ -39,6 +40,16 @@ export const RequestScreen: React.FC<MainRouteProps> = (props) => {
) : null}
</Centered>
<Row align="center" crossAlign="center" margin={[0, 0, 48, 0]}>
<Text margin={[0, 16, 0, 0]}>Offline</Text>
<Switch
value={controller.sharingProtocol === 'ONLINE'}
onValueChange={controller.SWITCH_PROTOCOL}
disabled={Platform.OS === 'ios'}
/>
<Text margin={[0, 0, 0, 16]}>Online</Text>
</Row>
{controller.statusMessage !== '' && (
<Column elevation={1} padding="16 24">
<Text>{controller.statusMessage}</Text>

View File

@@ -13,6 +13,7 @@ import {
selectIsWaitingForConnection,
selectIsExchangingDeviceInfo,
selectIsWaitingForVc,
selectSharingProtocol,
} from '../../machines/request';
import { selectVcLabel } from '../../machines/settings';
import { MainRouteProps } from '../../routes/main';
@@ -85,6 +86,7 @@ export function useRequestScreen({ navigation }: MainRouteProps) {
return {
vcLabel,
statusMessage,
sharingProtocol: useSelector(requestService, selectSharingProtocol),
isWaitingForConnection,
isExchangingDeviceInfo,
@@ -102,5 +104,7 @@ export function useRequestScreen({ navigation }: MainRouteProps) {
ACCEPT: () => requestService.send(RequestEvents.ACCEPT()),
REJECT: () => requestService.send(RequestEvents.REJECT()),
REQUEST: () => requestService.send(RequestEvents.SCREEN_FOCUS()),
SWITCH_PROTOCOL: (value: boolean) =>
requestService.send(RequestEvents.SWITCH_PROTOCOL(value)),
};
}

47
shared/smartshare.ts Normal file
View File

@@ -0,0 +1,47 @@
// TODO: fix export from smartshare library
// import {
// IdpassSmartshare,
// GoogleNearbyMessages,
// } from '@idpass/smartshare-react-native';
import Smartshare from '@idpass/smartshare-react-native';
const { IdpassSmartshare, GoogleNearbyMessages } = Smartshare;
import { Message } from './Message';
export function gnmSubscribe<T>(
messageType: string,
callback: (data: T) => void
) {
return GoogleNearbyMessages.subscribe(
(foundMessage) => {
if (__DEV__) {
console.log('\n[request] MESSAGE_FOUND', foundMessage);
}
const message = Message.fromString<T>(foundMessage);
if (message.type === messageType) {
GoogleNearbyMessages.unsubscribe();
callback(message.data);
}
},
(lostMessage) => {
if (__DEV__) {
console.log('\n[request] MESSAGE_LOST', lostMessage);
}
}
);
}
export function issSubscribe<T>(
messageType: string,
callback: (data: T) => void
) {
return IdpassSmartshare.handleNearbyEvents((event) => {
if (event.type !== 'msg') return;
const response = Message.fromString<T>(event.data);
if (response.type === messageType) {
callback(response.data);
}
});
}

View File

@@ -1,62 +0,0 @@
import { EmitterSubscription } from 'react-native';
import { BluetoothState } from 'react-native-bluetooth-state-manager';
declare module '@idpass/smartshare-react-native' {
class IdpassSmartshare {
getConnectionParameters: () => string;
setConnectionParameters: (params: string) => void;
getConnectionParametersDebug: () => string;
createConnection: (mode: ConnectionMode, callback: () => void) => void;
destroyConnection: () => void;
send: (message: string, callback: () => void) => void;
handleNearbyEvents: (
callback: (event: NearbyEvent) => void
) => EmitterSubscription;
handleLogEvents: (
callback: (event: NearbyLog) => void
) => EmitterSubscription;
}
export type ConnectionMode = 'dual' | 'advertiser' | 'discoverer';
export type TransferUpdateStatus =
| 'SUCCESS'
| 'FAILURE'
| 'IN_PROGRESS'
| 'CANCELED';
export type NearbyEvent =
| { type: 'msg'; data: string }
| { type: 'transferupdate'; data: TransferUpdateStatus }
| { type: 'onDisconnected'; data: string };
export interface NearbyLog {
log: string;
}
export interface ConnectionParams {
// appId: string;
cid: string;
pk: string;
}
export = new IdpassSmartshare();
}
declare module 'react-native-bluetooth-state-manager' {
type StateChangeCallback = (state: BluetoothState) => void;
type StateChangeEmitter = Pick<EmitterSubscription, 'remove'>;
export function onStateChange(
callback: StateChangeCallback,
emitCurrentState: boolean
): StateChangeEmitter;
}

View File

@@ -0,0 +1,13 @@
import { EmitterSubscription } from 'react-native';
import { BluetoothState } from 'react-native-bluetooth-state-manager';
declare module 'react-native-bluetooth-state-manager' {
type StateChangeCallback = (state: BluetoothState) => void;
type StateChangeEmitter = Pick<EmitterSubscription, 'remove'>;
export function onStateChange(
callback: StateChangeCallback,
emitCurrentState: boolean
): StateChangeEmitter;
}