added back icons for Scanned Data box. Pending to verify all dynamic ScannedDataBox views. (Incomplete Testing)
This commit is contained in:
@@ -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,101 +139,91 @@ 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>
|
||||||
<Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" />
|
<Ionicons name="chevron-forward" size={screenWidth * 0.045} color="#ff69b4" />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : (
|
) : (
|
||||||
<View style={styles.displayCheck}>
|
<View style={styles.displayCheck}>
|
||||||
<MaterialCommunityIcons name="shield-off" size={screenWidth * 0.045} color="#ffa500" />
|
<MaterialCommunityIcons name="shield-off" size={screenWidth * 0.045} color="#ffa500" />
|
||||||
<Text style={styles.moreInfoButtonText}>No Security Headers</Text>
|
<Text style={styles.moreInfoButtonText}>No Security Headers</Text>
|
||||||
</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)}
|
</TouchableOpacity>
|
||||||
>
|
</View>
|
||||||
<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>
|
|
||||||
</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" />
|
||||||
</TouchableOpacity>
|
<Text style={styles.iconText}>Copy</Text>
|
||||||
|
</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)}
|
||||||
</TouchableOpacity>
|
>
|
||||||
|
<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>
|
||||||
|
</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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user