With VT score and Clear History

This commit is contained in:
2024-06-08 12:05:22 +08:00
parent e70202b7e2
commit 283adbf07e
3 changed files with 150 additions and 21 deletions

122
App.tsx
View File

@@ -4,37 +4,97 @@ import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { CameraView, Camera } from 'expo-camera'; import { CameraView, Camera } from 'expo-camera';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
import axios from 'axios'; // Import Axios for HTTP requests
// Create a Context for QR code data // Create a Context for QR code data
const QRCodeContext = createContext(); const QRCodeContext = createContext();
const Tab = createBottomTabNavigator(); const Tab = createBottomTabNavigator();
// Component for QR Scanner Screen
function QRScannerScreen() { function QRScannerScreen() {
const { qrCodes, setQrCodes } = useContext(QRCodeContext); // Access context const { qrCodes, setQrCodes } = useContext(QRCodeContext); // Access context
const [hasPermission, setHasPermission] = useState(null); const [hasPermission, setHasPermission] = useState(null); // State for camera permission
const [scanned, setScanned] = useState(false); const [scanned, setScanned] = useState(false); // State for scanned status
const [showSplash, setShowSplash] = useState(true); const [showSplash, setShowSplash] = useState(true); // State for splash screen
const [scannedData, setScannedData] = useState(''); const [scannedData, setScannedData] = useState(''); // State for scanned data
const [scanResult, setScanResult] = useState(null); // State for VirusTotal scan result
useEffect(() => { useEffect(() => {
const initializeApp = async () => { const initializeApp = async () => {
const { status } = await Camera.requestCameraPermissionsAsync(); const { status } = await Camera.requestCameraPermissionsAsync(); // Request camera permissions
setHasPermission(status === 'granted'); setHasPermission(status === 'granted'); // Set permission status
setShowSplash(false); // Hide splash screen after initializing setShowSplash(false); // Hide splash screen
}; };
initializeApp(); initializeApp(); // Initialize app
}, []); }, []);
const handleBarCodeScanned = ({ type, data }) => { // Function to handle barcode scanned event
setScanned(true); // Mark as scanned const handleBarCodeScanned = async ({ type, data }) => {
const newScannedData = `Type: ${type}\nData: ${data}`; setScanned(true); // Mark as scanned
setScannedData(newScannedData); // Save scanned data
setQrCodes([...qrCodes, newScannedData]); // Add scanned data to history // Determine the type of data (URL, text, or just numbers)
alert(`Bar code with type ${type} and data ${data} has been scanned!`); // Show an alert let dataType;
if (/^(http|https):\/\//.test(data)) {
dataType = 'URL';
} else if (/^[0-9]+$/.test(data)) {
dataType = 'Numbers';
} else {
dataType = 'Text';
}
// Construct the scanned data with the data type
let newScannedData = `Type: ${dataType}\nData: ${data}`; // Initialize with type and data
try {
const scanId = await scanWithVirusTotal(data); // Send data to VirusTotal and get scan ID
const positive = await getScanResult(scanId); // Get scan result and extract positive score
newScannedData += `\nScore: ${positive}`; // Append positive score to newScannedData
} catch (error) {
console.error('Error handling barcode scan:', error); // Handle error
}
setScannedData(newScannedData); // Save scanned data
setQrCodes([...qrCodes, newScannedData]); // Add scanned data to history
};
// Function to send data to VirusTotal and get the scan ID
const scanWithVirusTotal = async (data) => {
const apiKey = '3566a17933bb36dd97cb35e84d0446e5ab8ad623e6de968d34b655c79485251e'; // Replace with your VirusTotal API key
const url = 'https://www.virustotal.com/vtapi/v2/url/scan';
const params = {
apikey: apiKey,
url: data
}; };
try {
const response = await axios.post(url, null, { params }); // Send URL scan request
return response.data.scan_id; // Return scan ID
} catch (error) {
console.error('Error scanning with VirusTotal:', error); // Handle error
throw error; // Propagate error
}
};
// Function to get scan result from VirusTotal and return the positive score
const getScanResult = async (scanId) => {
const apiKey = '3566a17933bb36dd97cb35e84d0446e5ab8ad623e6de968d34b655c79485251e'; // Replace with your VirusTotal API key
const url = 'https://www.virustotal.com/vtapi/v2/url/report';
const params = {
apikey: apiKey,
resource: scanId
};
try {
const response = await axios.get(url, { params }); // Get scan result
return response.data.positives; // Return positive score
} catch (error) {
console.error('Error getting scan result:', error); // Handle error
throw error; // Propagate error
}
};
if (showSplash) { if (showSplash) {
return ( return (
<View style={styles.splashContainer}> <View style={styles.splashContainer}>
@@ -67,21 +127,19 @@ function QRScannerScreen() {
style={styles.camera} // Apply styles style={styles.camera} // Apply styles
/> />
</View> </View>
{/* Display scanned data */}
{/* Display scanned data */} {scannedData !== '' && (
{scannedData !== '' && (
<View style={styles.dataBox}> <View style={styles.dataBox}>
<Text style={styles.dataText}>{scannedData}</Text> <Text style={styles.dataText}>{scannedData}</Text>
{scanResult && <Text style={styles.dataText}>{JSON.stringify(scanResult)}</Text>}
</View> </View>
)} )}
{/* Button to scan again */} {/* Button to scan again */}
{scanned && ( {scanned && (
<TouchableOpacity style={styles.button} onPress={() => setScanned(false)}> <TouchableOpacity style={styles.button} onPress={() => setScanned(false)}>
<Text style={styles.buttonText}>Tap to Scan Again</Text> <Text style={styles.buttonText}>Tap to Scan Again</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
{/* Menu (Placeholder for additional menu items) */} {/* Menu (Placeholder for additional menu items) */}
<View style={styles.menu}> <View style={styles.menu}>
{/* Your existing menu items */} {/* Your existing menu items */}
@@ -90,6 +148,7 @@ function QRScannerScreen() {
); );
} }
// Component for History Screen
function HistoryScreen() { function HistoryScreen() {
const { qrCodes } = useContext(QRCodeContext); // Access context const { qrCodes } = useContext(QRCodeContext); // Access context
@@ -97,26 +156,38 @@ function HistoryScreen() {
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.welcomeText}>History Screen</Text> <Text style={styles.welcomeText}>History Screen</Text>
<FlatList <FlatList
data={qrCodes} data={qrCodes} // Data for FlatList
renderItem={({ item }) => ( renderItem={({ item }) => (
<View style={styles.dataBox}> <View style={styles.dataBox}>
<Text style={styles.dataText}>{item}</Text> <Text style={styles.dataText}>{item}</Text>
</View> </View>
)} )}
keyExtractor={(item, index) => index.toString()} keyExtractor={(item, index) => index.toString()} // Key extractor for FlatList
/> />
</View> </View>
); );
} }
// Component for Settings Screen
function SettingsScreen() { function SettingsScreen() {
const { setQrCodes } = useContext(QRCodeContext); // Access context
// Function to clear history
const clearHistory = () => {
setQrCodes([]);
};
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.welcomeText}>Settings Screen</Text> <Text style={styles.welcomeText}>Settings Screen</Text>
<TouchableOpacity style={styles.button} onPress={clearHistory}>
<Text style={styles.buttonText}>Clear History</Text>
</TouchableOpacity>
</View> </View>
); );
} }
// Component for Profile Screen
function ProfileScreen() { function ProfileScreen() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
@@ -235,4 +306,13 @@ const styles = StyleSheet.create({
backgroundColor: "#ff69b4", // pink background backgroundColor: "#ff69b4", // pink background
paddingVertical: 10, paddingVertical: 10,
}, },
// Additional styles for green and red boxes
greenBox: {
backgroundColor: '#00FF00', // Green color
},
redBox: {
backgroundColor: '#FF0000', // Red color
},
}); });

48
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"@expo/vector-icons": "^14.0.2", "@expo/vector-icons": "^14.0.2",
"@react-navigation/bottom-tabs": "^6.5.20", "@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.17", "@react-navigation/native": "^6.1.17",
"axios": "^1.7.2",
"expo": "~51.0.11", "expo": "~51.0.11",
"expo-camera": "~15.0.10", "expo-camera": "~15.0.10",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~1.12.1",
@@ -5997,6 +5998,29 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/axios": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/axios/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/babel-core": { "node_modules/babel-core": {
"version": "7.0.0-bridge.0", "version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@@ -7853,6 +7877,25 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/fontfaceobserver": { "node_modules/fontfaceobserver": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz",
@@ -11549,6 +11592,11 @@
"react-is": "^16.13.1" "react-is": "^16.13.1"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pump": { "node_modules/pump": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",

View File

@@ -12,6 +12,7 @@
"@expo/vector-icons": "^14.0.2", "@expo/vector-icons": "^14.0.2",
"@react-navigation/bottom-tabs": "^6.5.20", "@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.17", "@react-navigation/native": "^6.1.17",
"axios": "^1.7.2",
"expo": "~51.0.11", "expo": "~51.0.11",
"expo-camera": "~15.0.10", "expo-camera": "~15.0.10",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~1.12.1",