Added API calls for Secure Connection,Virus Total Check and Redirects

This commit is contained in:
2024-07-07 21:54:10 +08:00
parent 304d5932f7
commit bca444d56d
5 changed files with 118 additions and 74 deletions

31
api/qrCodeAPI.tsx Normal file
View File

@@ -0,0 +1,31 @@
import axios from 'axios';
const API_BASE_URL = 'http://192.168.10.247:8080/v1/api/qrcodetypes';
export const detectQRCodeType = async (data: string) => {
console.log('API Call - Detect QR Code Type:', data);
const response = await axios.post(`${API_BASE_URL}/detect`, { data });
console.log('API Response - QR Code Type:', response.data);
return response.data;
};
export const verifyURL = async (data: string) => {
console.log('API Call - Verify URL:', data);
const response = await axios.post(`${API_BASE_URL}/verifyURL`, { data });
console.log('API Response - Verify URL:', response.data);
return response.data;
};
export const virusTotalCheck = async (data: string) => {
console.log('API Call - Virus Total Check:', data);
const response = await axios.post(`${API_BASE_URL}/virusTotalCheck`, { data });
console.log('API Response - Virus Total Check:', response.data);
return response.data;
};
export const checkRedirects = async (data: string) => {
console.log('API Call - Check Redirects:', data);
const response = await axios.post(`${API_BASE_URL}/checkRedirects`, { data });
console.log('API Response - Check Redirects:', response.data);
return response.data;
};

View File

@@ -1,47 +1,34 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Image, TouchableOpacity, Modal, Share } from 'react-native'; import { View, Text, StyleSheet, Image, TouchableOpacity, Modal } from 'react-native';
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
import SecureWebView from './SecureWebView'; // Import the SecureWebView component import * as Sharing from 'expo-sharing';
import { WebView } from 'react-native-webview';
// Define Props for ScannedDataBox component // Define Props for ScannedDataBox component
interface ScannedDataBoxProps { interface ScannedDataBoxProps {
data: string; data: string;
dataType: string; dataType: string;
clearScanData: () => void; clearScanData: () => void;
scanResult: {
secureConnection: boolean;
virusTotalCheck: boolean;
redirects: number;
};
} }
// Define ScanResult interface const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ data, dataType, clearScanData, scanResult }) => {
interface ScanResult {
secureConnection: boolean;
virusTotalCheck: boolean;
redirects: number;
}
const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ data, dataType, clearScanData }) => {
const [scanResult, setScanResult] = useState<ScanResult | null>(null);
const [isModalVisible, setIsModalVisible] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false);
const [isWebViewVisible, setIsWebViewVisible] = useState(false); // State to control WebView modal visibility const [isWebViewVisible, setIsWebViewVisible] = useState(false);
console.log("ScannedDataBox -> Data", data); console.log("ScannedDataBox -> Data", data);
console.log("DataType", dataType); console.log("DataType", dataType);
// Set scan result based on data
useEffect(() => { useEffect(() => {
// Assuming scanResult is directly related to data
setScanResult({
secureConnection: data.includes('https'), // Example logic
virusTotalCheck: !data.includes('danger'), // Example logic
redirects: data.includes('redirect') ? 1 : 0, // Example logic
});
console.log("Scan result set:", scanResult); console.log("Scan result set:", scanResult);
}, [data]); }, [data]);
// Determine the result text based on scan result // Determine the result text based on scan result
const getResultText = () => { const getResultText = () => {
if (!scanResult) {
return 'UNKNOWN';
}
if (!scanResult.secureConnection && !scanResult.virusTotalCheck) { if (!scanResult.secureConnection && !scanResult.virusTotalCheck) {
return 'DANGEROUS'; return 'DANGEROUS';
} else if (scanResult.redirects > 0) { } else if (scanResult.redirects > 0) {
@@ -65,22 +52,16 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ data, dataType, clearSc
} }
}; };
// Handle sharing the data const shareQRCodeData = async () => {
const handleShare = async () => {
try { try {
await Share.share({ await Sharing.shareAsync(data);
message: data,
});
console.log('Data shared:', data);
} catch (error) { } catch (error) {
console.error('Error sharing the data:', error); console.error('Error sharing QR code data:', error);
} }
}; };
// Handle opening the data in a sandboxed WebView const openWebView = () => {
const handleOpen = () => {
setIsWebViewVisible(true); setIsWebViewVisible(true);
console.log('Opening data in WebView:', data);
}; };
return ( return (
@@ -111,17 +92,17 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ data, dataType, clearSc
{/* Display scan checks */} {/* Display scan checks */}
<Text style={styles.checksText}>Checks</Text> <Text style={styles.checksText}>Checks</Text>
<Text style={styles.checksText}>Secure Connection: {scanResult?.secureConnection ? '✔️' : '✘'}</Text> <Text style={styles.checksText}>Secure Connection: {scanResult.secureConnection ? '✔️' : '✘'}</Text>
<Text style={styles.checksText}>Virus Total Check: {scanResult?.virusTotalCheck ? '✔️' : '✘'}</Text> <Text style={styles.checksText}>Virus Total Check: {scanResult.virusTotalCheck ? '✔️' : '✘'}</Text>
<Text style={styles.checksText}>Redirects: {scanResult ? scanResult.redirects : 'N/A'}</Text> <Text style={styles.checksText}>Redirects: {scanResult.redirects}</Text>
{/* Action buttons */} {/* Action buttons */}
<View style={styles.iconContainer}> <View style={styles.iconContainer}>
<TouchableOpacity style={styles.iconButton} onPress={handleShare}> <TouchableOpacity style={styles.iconButton} onPress={shareQRCodeData}>
<Ionicons name="share-social" size={18} color="#2196F3" /> <Ionicons name="share-social" size={18} color="#2196F3" />
<Text style={styles.iconText}>Share</Text> <Text style={styles.iconText}>Share</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.iconButton} onPress={handleOpen}> <TouchableOpacity style={styles.iconButton} onPress={openWebView}>
<Ionicons name="open" size={18} color="#2196F3" /> <Ionicons name="open" size={18} color="#2196F3" />
<Text style={styles.iconText}>Open</Text> <Text style={styles.iconText}>Open</Text>
</TouchableOpacity> </TouchableOpacity>
@@ -160,19 +141,26 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ data, dataType, clearSc
</View> </View>
</View> </View>
</Modal> </Modal>
{/* Modal for SecureWebView */}
<Modal <Modal
visible={isWebViewVisible} visible={isWebViewVisible}
transparent={true} transparent={true}
animationType="fade" animationType="slide"
onRequestClose={() => setIsWebViewVisible(false)} onRequestClose={() => setIsWebViewVisible(false)}
> >
<View style={styles.webViewContainer}> <View style={styles.modalContainer}>
<TouchableOpacity style={styles.closeWebViewButton} onPress={() => setIsWebViewVisible(false)}> <View style={styles.webViewContainer}>
<Ionicons name="close-circle-outline" size={24} color="#fff" /> <WebView
</TouchableOpacity> source={{ uri: data }}
<SecureWebView url={data} /> javaScriptEnabled={false}
domStorageEnabled={false}
allowFileAccess={false}
originWhitelist={['*']}
onShouldStartLoadWithRequest={(request) => true}
/>
<TouchableOpacity style={styles.closeModalButton} onPress={() => setIsWebViewVisible(false)}>
<Text style={styles.closeModalButtonText}>Close</Text>
</TouchableOpacity>
</View>
</View> </View>
</Modal> </Modal>
</View> </View>
@@ -316,18 +304,11 @@ const styles = StyleSheet.create({
color: '#fff', color: '#fff',
}, },
webViewContainer: { webViewContainer: {
flex: 1, width: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.5)', height: '80%',
}, backgroundColor: 'white',
webView: { borderRadius: 7.5,
flex: 1, overflow: 'hidden'
marginTop: 40,
},
closeWebViewButton: {
position: 'absolute',
top: 10,
right: 10,
zIndex: 1,
}, },
}); });

9
package-lock.json generated
View File

@@ -17,6 +17,7 @@
"expo-camera": "~15.0.10", "expo-camera": "~15.0.10",
"expo-image-manipulator": "^12.0.5", "expo-image-manipulator": "^12.0.5",
"expo-image-picker": "~15.0.5", "expo-image-picker": "~15.0.5",
"expo-sharing": "~12.0.1",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~1.12.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.74.2", "react-native": "0.74.2",
@@ -7882,6 +7883,14 @@
"invariant": "^2.2.4" "invariant": "^2.2.4"
} }
}, },
"node_modules/expo-sharing": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-12.0.1.tgz",
"integrity": "sha512-wBT+WeXwapj/9NWuLJO01vi9bdlchYu/Q/xD8slL/Ls4vVYku8CPqzkTtDFcjLrjtlJqyeHsdQXwKLvORmBIew==",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-status-bar": { "node_modules/expo-status-bar": {
"version": "1.12.1", "version": "1.12.1",
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.12.1.tgz", "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.12.1.tgz",

View File

@@ -25,7 +25,8 @@
"react-native-safe-area-context": "^4.10.4", "react-native-safe-area-context": "^4.10.4",
"react-native-webview": "^13.10.4", "react-native-webview": "^13.10.4",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"redux": "^5.0.1" "redux": "^5.0.1",
"expo-sharing": "~12.0.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",

View File

@@ -1,23 +1,24 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Alert, Image } from 'react-native'; import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Alert, Image } from 'react-native';
import { Camera, CameraView, scanFromURLAsync } from 'expo-camera'; import { Camera, CameraView, scanFromURLAsync } from 'expo-camera';
import { useDispatch } from 'react-redux'; import { QRCodeContext } from '../types';
import axios from 'axios'; // For URL calls import axios from 'axios'; // For URL calls
import { Ionicons } from '@expo/vector-icons'; // For icons import { Ionicons } from '@expo/vector-icons'; // For icons
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import * as ImagePicker from 'expo-image-picker'; import * as ImagePicker from 'expo-image-picker';
import ScannedDataBox from '../components/ScannedDataBox'; import ScannedDataBox from '../components/ScannedDataBox';
import { addQRCode } from '../actions/qrCodeActions'; import { useDispatch } from 'react-redux';
import { addQRCode } from '../actions/qrCodeActions'; // Assuming you have actions defined for Redux
interface QRScannerScreenProps { import { detectQRCodeType, verifyURL, checkRedirects } from '../api/qrCodeAPI'; // Import utility functions
clearScanData: () => void;
}
// Main Function // Main Function
const QRScannerScreen: React.FC<QRScannerScreenProps> = ({ clearScanData }) => { const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanData }) => {
const navigation = useNavigation(); // call Navigation bar const navigation = useNavigation(); // call Navigation bar
const dispatch = useDispatch(); // Use dispatch for Redux actions
const [showSplash, setShowSplash] = useState<boolean>(true); // call splash screen const [showSplash, setShowSplash] = useState<boolean>(true); // call splash screen
const dispatch = useDispatch(); const qrCodeContext = useContext(QRCodeContext); // From ./types.ts
const { qrCodes, setQrCodes } = qrCodeContext || { qrCodes: [], setQrCodes: () => {} };
const [hasPermission, setHasPermission] = useState<boolean | null>(null); const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [scanned, setScanned] = useState<boolean>(false); const [scanned, setScanned] = useState<boolean>(false);
@@ -25,6 +26,11 @@ const QRScannerScreen: React.FC<QRScannerScreenProps> = ({ clearScanData }) => {
const [dataType, setDataType] = useState<string>(''); // State for data type const [dataType, setDataType] = useState<string>(''); // State for data type
const [enableTorch, setEnableTorch] = useState<boolean>(false); // State for torch const [enableTorch, setEnableTorch] = useState<boolean>(false); // State for torch
// Add state variables for scan results
const [secureConnection, setSecureConnection] = useState<boolean | null>(null);
const [virusTotalCheck, setVirusTotalCheck] = useState<boolean | null>(null);
const [redirects, setRedirects] = useState<number | null>(null);
// Request Camera Permission and initialize the app // Request Camera Permission and initialize the app
useEffect(() => { useEffect(() => {
const initializeApp = async () => { const initializeApp = async () => {
@@ -49,17 +55,24 @@ const QRScannerScreen: React.FC<QRScannerScreenProps> = ({ clearScanData }) => {
const handlePayload = async (payload: string) => { const handlePayload = async (payload: string) => {
setScanned(true); setScanned(true);
console.log("Scanning Completed. Payload is:", payload); console.log("Scanning Completed. Payload is:", payload);
const type = await sendToAPIServer(payload);
const type = await detectQRCodeType(payload);
const secureConnectionResult = await verifyURL(payload);
const redirectResult = await checkRedirects(payload);
setSecureConnection(secureConnectionResult.isSecure);
setVirusTotalCheck(!secureConnectionResult.isMalicious); // Assuming you have virusTotalCheck logic integrated here
setRedirects(redirectResult.redirects);
const qrCode = { const qrCode = {
data: payload, data: payload,
type, type,
scanResult: { scanResult: {
secureConnection: true, // Placeholder, replace with actual logic secureConnection: secureConnectionResult.isSecure,
virusTotalCheck: true, // Placeholder, replace with actual logic virusTotalCheck: !secureConnectionResult.isMalicious,
redirects: 0 // Placeholder, replace with actual logic redirects: redirectResult.redirects
}, },
bookmarked: false, // Add the bookmarked property bookmarked: false // by default
}; };
setScannedData(payload); setScannedData(payload);
@@ -185,7 +198,16 @@ const QRScannerScreen: React.FC<QRScannerScreenProps> = ({ clearScanData }) => {
{scannedData !== '' && ( {scannedData !== '' && (
<View style={styles.scannedDataBox}> <View style={styles.scannedDataBox}>
<ScannedDataBox data={scannedData} dataType={dataType} clearScanData={clearScanDataInternal} /> <ScannedDataBox
data={scannedData}
dataType={dataType}
clearScanData={clearScanDataInternal}
scanResult={{
secureConnection,
virusTotalCheck,
redirects
}}
/>
</View> </View>
)} )}
</View> </View>