added back icons for Scanned Data box. Pending to verify all dynamic ScannedDataBox views. (Incomplete Testing)

This commit is contained in:
2024-08-12 02:08:34 +08:00
parent e4cc584924
commit fcb710a888
2 changed files with 129 additions and 107 deletions

View File

@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Image, TouchableOpacity, Modal, ActivityIndicator, ScrollView, Dimensions } from 'react-native'; import { View, Text, StyleSheet, Image, TouchableOpacity, Modal, ActivityIndicator, ScrollView, Dimensions, Linking, Clipboard } from 'react-native';
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
import { Feather, Ionicons, MaterialCommunityIcons, SimpleLineIcons } from '@expo/vector-icons'; import { Ionicons, MaterialCommunityIcons, SimpleLineIcons } from '@expo/vector-icons';
import { getQRCodeDetails } from '../api/qrCodeAPI'; import { getQRCodeDetails } from '../api/qrCodeAPI';
import SecureWebView from '../components/SecureWebView'; import SecureWebView from '../components/SecureWebView';
@@ -20,7 +20,6 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
const [isWebViewVisible, setIsWebViewVisible] = useState(false); const [isWebViewVisible, setIsWebViewVisible] = useState(false);
const [webViewUrl, setWebViewUrl] = useState(''); const [webViewUrl, setWebViewUrl] = useState('');
// Fetch QR code details on component mount or qrCodeId change
useEffect(() => { useEffect(() => {
const fetchQRDetails = async () => { const fetchQRDetails = async () => {
try { try {
@@ -49,17 +48,16 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
const details = qrDetails.details || {}; const details = qrDetails.details || {};
const type = data.info?.type || 'Undefined'; const type = data.info?.type || 'Undefined';
const contents = data.contents || 'Undefined'; const contents = data.contents || 'Undefined';
const secureConnection = details.hstsHeader?.some((header: string) => header.includes('HSTS Header')); const result = data.result || 'Unknown';
const redirects = details.redirect || 0; const ssid = details.ssid || 'Undefined';
const securityHeaders = details.hstsHeader && details.hstsHeader.length > 0 ? details.hstsHeader : []; const encryption = details.encryption || 'NO';
const hidden = details.hidden ? 'Hidden' : 'Visible';
const redirectChain = details.redirectChain || ['No Redirects'];
// Determine the result text based on the security status // Determine the result text based on the security status
const getResultText = () => { const getResultText = () => {
if (!secureConnection || redirects > 0) { if (result === 'UNSAFE') {
return 'DANGEROUS'; return 'DANGEROUS';
} else if (secureConnection && redirects === 0) { } else if (result === 'SAFE') {
return 'SAFE'; return 'SAFE';
} else { } else {
return 'WARNING'; return 'WARNING';
@@ -68,35 +66,18 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
// Get color corresponding to the result text // Get color corresponding to the result text
const getResultColor = () => { const getResultColor = () => {
const result = getResultText(); const resultText = getResultText();
if (result === 'DANGEROUS') { if (resultText === 'DANGEROUS') {
return '#ff0000'; // Red return '#ff0000'; // Red
} else if (result === 'WARNING') { } else if (resultText === 'WARNING') {
return '#ffa500'; // Orange return '#ffa500'; // Orange
} else if (result === 'SAFE') { } else if (resultText === 'SAFE') {
return '#44c167'; // Green return '#44c167'; // Green
} else { } else {
return '#000000'; // Black for unknown return '#000000'; // Black for unknown
} }
}; };
// Get icon based on the number of redirects
const getSheildIcon = () => {
if (redirects === 0) {
return <Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" />;
} else if (redirects <= 2) {
return <Ionicons name="shield" size={screenWidth * 0.045} color="#ffa500" />;
} else {
return <MaterialCommunityIcons name="shield-alert" size={screenWidth * 0.045} color="#ff0000" />;
}
};
// Open URL in a WebView
const openWebView = (url: string) => {
setWebViewUrl(url);
setIsWebViewVisible(true);
};
// Truncate content string to specified length // Truncate content string to specified length
const truncateContent = (content: string, length: number) => { const truncateContent = (content: string, length: number) => {
if (content.length > length) { if (content.length > length) {
@@ -105,6 +86,28 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
return content; return content;
}; };
// Function to open the Wi-Fi configuration in the OS
const handleOpenUrl = (url: string) => {
Linking.openURL(url).catch(err => console.error('Error opening URL:', err));
};
// Function to copy text content to clipboard
const handleCopyToClipboard = () => {
Clipboard.setString(contents);
};
// Function to send SMS
const handleSendSMS = () => {
const smsUrl = `sms:${contents}`;
Linking.openURL(smsUrl).catch(err => console.error('Error sending SMS:', err));
};
// Function to make a phone call
const handleMakeCall = () => {
const telUrl = `tel:${contents}`;
Linking.openURL(telUrl).catch(err => console.error('Error making call:', err));
};
return ( return (
<View style={styles.dataBox}> <View style={styles.dataBox}>
<TouchableOpacity style={styles.closeButton} onPress={clearScanData}> <TouchableOpacity style={styles.closeButton} onPress={clearScanData}>
@@ -128,7 +131,6 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
<View style={styles.detailsSection}> <View style={styles.detailsSection}>
<Text style={styles.timestampText}>{data.createdAt ? new Date(data.createdAt).toLocaleString() : 'Invalid Date'}</Text> <Text style={styles.timestampText}>{data.createdAt ? new Date(data.createdAt).toLocaleString() : 'Invalid Date'}</Text>
<Text style={styles.typeText}>Description: {type}</Text> <Text style={styles.typeText}>Description: {type}</Text>
<Text>{'\n'}</Text>
</View> </View>
</View> </View>
@@ -137,25 +139,25 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
Result: {getResultText()} Result: {getResultText()}
</Text> </Text>
{/* Change the UI based on Type */} {/* URL Type */}
{type === 'URL' && ( {type === 'URL' && (
<> <>
<View style={styles.displayCheck}> <View style={styles.displayCheck}>
{secureConnection ? ( {details.redirectChain?.length === 0 ? (
<> <>
<Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" /> <Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" />
<Text style={styles.moreInfoButtonText}>Secure Connection</Text> <Text style={styles.moreInfoButtonText}>No Redirects</Text>
</> </>
) : ( ) : (
<> <>
<SimpleLineIcons name="shield" size={screenWidth * 0.045} color="#ff0000" /> <SimpleLineIcons name="shield" size={screenWidth * 0.045} color="#ff0000" />
<Text style={styles.moreInfoButtonText}>Not Secure</Text> <Text style={styles.moreInfoButtonText}>Redirects</Text>
</> </>
)} )}
</View> </View>
{/* Security Headers Button */} {/* Security Headers Button */}
{securityHeaders.length > 0 ? ( {details.securityHeaders?.length > 0 ? (
<TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsModalVisible(true)}> <TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsModalVisible(true)}>
<Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" /> <Ionicons name="shield-checkmark" size={screenWidth * 0.045} color="#44c167" />
<Text style={styles.moreInfoButtonText}>Security Headers</Text> <Text style={styles.moreInfoButtonText}>Security Headers</Text>
@@ -168,70 +170,60 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
</View> </View>
)} )}
{/* Redirects Button */} {/* Redirects Button */}
<TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsRedirectModalVisible(true)}> <TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsRedirectModalVisible(true)}>
{getSheildIcon()} <Ionicons name="shield" size={screenWidth * 0.045} color="#ffa500" />
<Text style={styles.moreInfoButtonText}>Redirects</Text> <Text style={styles.moreInfoButtonText}>Redirects</Text>
<Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" /> <Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" />
</TouchableOpacity> </TouchableOpacity>
{/* Security Headers Modal */} {/* URL Open Button */}
<Modal <View style={styles.iconContainer}>
visible={isModalVisible} <TouchableOpacity style={styles.iconButton} onPress={() => handleOpenUrl(contents)}>
transparent={true} <Ionicons name="open" size={screenWidth * 0.045} color="#2196F3" />
animationType="fade" <Text style={styles.iconText}>Open</Text>
onRequestClose={() => setIsModalVisible(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Security Headers</Text>
{securityHeaders.map((header, index) => (
<Text key={index} style={styles.modalText}>{header}</Text>
))}
<TouchableOpacity style={styles.closeModalButton} onPress={() => setIsModalVisible(false)}>
<Text style={styles.closeModalButtonText}>Close</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View>
</Modal>
{/* Redirect Chain Modal */}
<Modal
visible={isRedirectModalVisible}
transparent={true}
animationType="fade"
onRequestClose={() => setIsRedirectModalVisible(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Redirect Chain</Text>
{redirectChain.map((redirect, index) => (
<Text key={index} style={styles.modalText}>{redirect}</Text>
))}
<TouchableOpacity style={styles.closeModalButton} onPress={() => setIsRedirectModalVisible(false)}>
<Text style={styles.closeModalButtonText}>Close</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</> </>
)} )}
{/* SMS Type */} {/* WIFI Type */}
{type === 'SMS' && ( {type === 'WIFI' && (
<> <>
<Text style={styles.moreInfoButton}>Recipient Phone Number: {details.phone || 'Undefined'}</Text> <Text style={styles.moreInfoButton}>SSID: {ssid}</Text>
<Text style={styles.moreInfoButton}>Message Content: {details.message || 'Undefined'}</Text> <Text style={styles.moreInfoButton}>Encryption: {encryption}</Text>
<Text style={styles.moreInfoButton}>Visibility: {hidden === 'Hidden' ? '✔️' : '❌'}</Text>
</> </>
)} )}
{/* TEXT Type */} {/* TEXT Type */}
{type === 'TEXT' && ( {type === 'TEXT' && (
<TouchableOpacity style={styles.moreInfoButton} onPress={() => setIsContentModalVisible(true)}> <View style={styles.iconContainer}>
<Text>Content: {truncateContent(contents, 30)}</Text> <TouchableOpacity style={styles.iconButton} onPress={handleCopyToClipboard}>
<Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" /> <Ionicons name="clipboard-outline" size={screenWidth * 0.045} color="#2196F3" />
<Text style={styles.iconText}>Copy</Text>
</TouchableOpacity> </TouchableOpacity>
</View>
)}
{/* SMS Type */}
{type === 'SMS' && (
<View style={styles.iconContainer}>
<TouchableOpacity style={styles.iconButton} onPress={handleSendSMS}>
<Ionicons name="chatbubble-outline" size={screenWidth * 0.045} color="#2196F3" />
<Text style={styles.iconText}>Send SMS</Text>
</TouchableOpacity>
</View>
)}
{/* TEL Type */}
{type === 'TEL' && (
<View style={styles.iconContainer}>
<TouchableOpacity style={styles.iconButton} onPress={handleMakeCall}>
<Ionicons name="call-outline" size={screenWidth * 0.045} color="#2196F3" />
<Text style={styles.iconText}>Call</Text>
</TouchableOpacity>
</View>
)} )}
{/* Full Content Modal */} {/* Full Content Modal */}
@@ -254,15 +246,45 @@ const ScannedDataBox: React.FC<ScannedDataBoxProps> = ({ qrCodeId, clearScanData
</View> </View>
</Modal> </Modal>
{/* URL Open Button */} {/* Security Headers Modal */}
{type === 'URL' && ( <Modal
<View style={styles.iconContainer}> visible={isModalVisible}
<TouchableOpacity style={styles.iconButton} onPress={() => openWebView(contents)}> transparent={true}
<Ionicons name="open" size={screenWidth * 0.045} color="#2196F3" /> animationType="fade"
<Text style={styles.iconText}>Open</Text> onRequestClose={() => setIsModalVisible(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Security Headers</Text>
{details.securityHeaders?.map((header: string, index: number) => (
<Text key={index} style={styles.modalText}>{header}</Text>
))}
<TouchableOpacity style={styles.closeModalButton} onPress={() => setIsModalVisible(false)}>
<Text style={styles.closeModalButtonText}>Close</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
)} </View>
</Modal>
{/* Redirect Chain Modal */}
<Modal
visible={isRedirectModalVisible}
transparent={true}
animationType="fade"
onRequestClose={() => setIsRedirectModalVisible(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Redirect Chain</Text>
{details.redirectChain?.map((redirect: string, index: number) => (
<Text key={index} style={styles.modalText}>{redirect}</Text>
))}
<TouchableOpacity style={styles.closeModalButton} onPress={() => setIsRedirectModalVisible(false)}>
<Text style={styles.closeModalButtonText}>Close</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
{/* WebView Modal */} {/* WebView Modal */}
<Modal <Modal

View File

@@ -59,7 +59,7 @@ const QRScannerScreen: React.FC = () => {
const { uri } = result.assets[0]; const { uri } = result.assets[0];
try { try {
// If using expo-camera or similar packages: // If using expo-camera or similar packages:
const scannedResult = await scanQRCodeFromURL(uri); // Function to scan QR code from the selected image URL const scannedResult = await scanQRCodeFromImage(uri); // Function to scan QR code from the selected image URL
if (scannedResult) { if (scannedResult) {
handlePayload(scannedResult); handlePayload(scannedResult);
} else { } else {
@@ -71,7 +71,7 @@ const QRScannerScreen: React.FC = () => {
} }
}; };
const scanQRCodeFromURL = async (uri: string) => { const scanQRCodeFromImage = async (uri: string) => {
// This method can vary depending on the package used for scanning // This method can vary depending on the package used for scanning
// For example, using expo-camera or other available options to scan QR code from an image URL // For example, using expo-camera or other available options to scan QR code from an image URL
// Implement scanFromURLAsync if using expo-camera // Implement scanFromURLAsync if using expo-camera