Browser extension for SecureBit Chat — a P2P messenger with military-grade cryptography.

This commit is contained in:
SecureBitChat
2025-10-10 00:06:58 -04:00
commit 6eedc0fa55
69 changed files with 31889 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
import { EnhancedSecureCryptoUtils } from '../crypto/EnhancedSecureCryptoUtils.js';
import { EnhancedSecureWebRTCManager } from '../network/EnhancedSecureWebRTCManager.js';
import { EnhancedSecureFileTransfer } from '../transfer/EnhancedSecureFileTransfer.js';
// Import UI components (side-effect: they attach themselves to window.*)
import '../components/ui/SessionTimer.jsx';
import '../components/ui/Header.jsx';
import '../components/ui/DownloadApps.jsx';
import '../components/ui/UniqueFeatureSlider.jsx';
import '../components/ui/SecurityFeatures.jsx';
import '../components/ui/Testimonials.jsx';
import '../components/ui/ComparisonTable.jsx';
import '../components/ui/Roadmap.jsx';
import '../components/ui/FileTransfer.jsx';
// Expose to global for legacy usage inside app code
window.EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils;
window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager;
window.EnhancedSecureFileTransfer = EnhancedSecureFileTransfer;
// Mount application once DOM and modules are ready
const start = () => {
if (typeof window.initializeApp === 'function') {
window.initializeApp();
} else if (window.DEBUG_MODE) {
console.error('initializeApp is not defined on window');
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
+55
View File
@@ -0,0 +1,55 @@
// Temporary bootstrap that still uses eval for JSX components fetched as text.
// Next step is to replace this with proper ESM imports of prebuilt JS.
(async () => {
try {
const timestamp = Date.now();
const [cryptoModule, webrtcModule, paymentModule, fileTransferModule] = await Promise.all([
import(`../crypto/EnhancedSecureCryptoUtils.js?v=${timestamp}`),
import(`../network/EnhancedSecureWebRTCManager.js?v=${timestamp}`),
import(`../session/PayPerSessionManager.js?v=${timestamp}`),
import(`../transfer/EnhancedSecureFileTransfer.js?v=${timestamp}`),
]);
const { EnhancedSecureCryptoUtils } = cryptoModule;
window.EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils;
const { EnhancedSecureWebRTCManager } = webrtcModule;
window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager;
const { PayPerSessionManager } = paymentModule;
window.PayPerSessionManager = PayPerSessionManager;
const { EnhancedSecureFileTransfer } = fileTransferModule;
window.EnhancedSecureFileTransfer = EnhancedSecureFileTransfer;
async function loadReactComponent(path) {
const response = await fetch(`${path}?v=${timestamp}`);
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
const code = await response.text();
// eslint-disable-next-line no-eval
eval(code);
}
await Promise.all([
loadReactComponent('../components/ui/SessionTimer.jsx'),
loadReactComponent('../components/ui/Header.jsx'),
loadReactComponent('../components/ui/SessionTypeSelector.jsx'),
loadReactComponent('../components/ui/LightningPayment.jsx'),
loadReactComponent('../components/ui/PaymentModal.jsx'),
loadReactComponent('../components/ui/DownloadApps.jsx'),
loadReactComponent('../components/ui/ComparisonTable.jsx'),
loadReactComponent('../components/ui/UniqueFeatureSlider.jsx'),
loadReactComponent('../components/ui/SecurityFeatures.jsx'),
loadReactComponent('../components/ui/Testimonials.jsx'),
loadReactComponent('../components/ui/Roadmap.jsx'),
loadReactComponent('../components/ui/FileTransfer.jsx'),
]);
if (typeof window.initializeApp === 'function') {
window.initializeApp();
} else {
console.error('❌ Function initializeApp not found');
}
} catch (error) {
console.error('❌ Module loading error:', error);
}
})();
+44
View File
@@ -0,0 +1,44 @@
// Global logging and function settings
window.DEBUG_MODE = true;
// Fake function settings (for stability)
window.DISABLE_FAKE_TRAFFIC = false; // Set true to disable fake messages
window.DISABLE_DECOY_CHANNELS = false; // Set true to disable decoy channels
// Enhanced icon loading fallback
document.addEventListener('DOMContentLoaded', function () {
// Check if Font Awesome loaded properly
function checkFontAwesome() {
const testIcon = document.createElement('i');
testIcon.className = 'fas fa-shield-halved';
testIcon.style.position = 'absolute';
testIcon.style.left = '-9999px';
testIcon.style.visibility = 'hidden';
document.body.appendChild(testIcon);
const computedStyle = window.getComputedStyle(testIcon, '::before');
const content = computedStyle.content;
const fontFamily = computedStyle.fontFamily;
document.body.removeChild(testIcon);
if (!content || content === 'none' || content === 'normal' || (!fontFamily.includes('Font Awesome') && !fontFamily.includes('fa-solid'))) {
console.warn('Font Awesome not loaded properly, using fallback icons');
document.body.classList.add('fa-fallback');
return false;
}
return true;
}
if (!checkFontAwesome()) {
setTimeout(function () {
if (!checkFontAwesome()) {
console.warn('Font Awesome still not loaded, using fallback icons');
document.body.classList.add('fa-fallback');
}
}, 2000);
}
});
+193
View File
@@ -0,0 +1,193 @@
// Local QR generator and scanner with COSE compression (no external CDNs)
// Exposes:
// - window.generateQRCode(text, { size?: number, margin?: number, errorCorrectionLevel?: 'L'|'M'|'Q'|'H' })
// - window.generateCOSEQRCode(data, senderKey?, recipientKey?) - COSE-based compression
// - window.Html5Qrcode (for scanning QR codes)
// - window.packSecurePayload, window.receiveAndProcess (COSE functions)
import * as QRCode from 'qrcode';
import { Html5Qrcode } from 'html5-qrcode';
import { gzip, ungzip, deflate, inflate } from 'pako';
import * as cbor from 'cbor-js';
import { packSecurePayload, receiveAndProcess } from '../crypto/cose-qr.js';
// Compact payload prefix to signal gzip+base64 content
const COMPRESSION_PREFIX = 'SB1:gz:';
const BINARY_PREFIX = 'SB1:bin:'; // CBOR + deflate + base64url
function uint8ToBase64(bytes) {
let binary = '';
const chunkSize = 0x8000;
for (let i = 0; i < bytes.length; i += chunkSize) {
const chunk = bytes.subarray(i, i + chunkSize);
binary += String.fromCharCode.apply(null, chunk);
}
return btoa(binary);
}
function base64ToUint8(b64) {
const binary = atob(b64);
const len = binary.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) bytes[i] = binary.charCodeAt(i);
return bytes;
}
function compressStringToBase64Gzip(text) {
const utf8 = new TextEncoder().encode(text);
const gz = gzip(utf8);
return uint8ToBase64(gz);
}
function decompressBase64GzipToString(b64) {
const gz = base64ToUint8(b64);
const out = ungzip(gz);
return new TextDecoder().decode(out);
}
async function generateQRCode(text, opts = {}) {
const size = opts.size || 512;
const margin = opts.margin ?? 2;
const errorCorrectionLevel = opts.errorCorrectionLevel || 'M';
return await QRCode.toDataURL(text, { width: size, margin, errorCorrectionLevel });
}
// Generate QR with gzip+base64 payload and recognizable prefix for scanners
async function generateCompressedQRCode(text, opts = {}) {
try {
const compressedB64 = compressStringToBase64Gzip(text);
const payload = COMPRESSION_PREFIX + compressedB64;
return await generateQRCode(payload, opts);
} catch (e) {
console.warn('generateCompressedQRCode failed, falling back to plain:', e?.message || e);
return await generateQRCode(text, opts);
}
}
// ---- Binary (CBOR) encode/decode helpers ----
function base64ToBase64Url(b64) {
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
function base64UrlToBase64(b64url) {
let b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
const pad = b64.length % 4;
if (pad) b64 += '='.repeat(4 - pad);
return b64;
}
function encodeObjectToBinaryBase64Url(obj) {
const cborBytes = cbor.encode(obj);
const compressed = deflate(new Uint8Array(cborBytes));
const b64 = uint8ToBase64(compressed);
return base64ToBase64Url(b64);
}
function decodeBinaryBase64UrlToObject(b64url) {
const b64 = base64UrlToBase64(b64url);
const compressed = base64ToUint8(b64);
const decompressed = inflate(compressed);
const ab = decompressed.buffer.slice(decompressed.byteOffset, decompressed.byteOffset + decompressed.byteLength);
return cbor.decode(ab);
}
async function generateBinaryQRCodeFromObject(obj, opts = {}) {
try {
const b64url = encodeObjectToBinaryBase64Url(obj);
const payload = BINARY_PREFIX + b64url;
return await generateQRCode(payload, opts);
} catch (e) {
console.warn('generateBinaryQRCodeFromObject failed, falling back to JSON compressed:', e?.message || e);
const text = JSON.stringify(obj);
return await generateCompressedQRCode(text, opts);
}
}
// COSE-based QR generation for large data
async function generateCOSEQRCode(data, senderKey = null, recipientKey = null) {
try {
console.log('🔐 Generating COSE-based QR code...');
// Pack data using COSE
const chunks = await packSecurePayload(data, senderKey, recipientKey);
if (chunks.length === 1) {
// Single QR code
return await generateQRCode(chunks[0]);
} else {
// Enforce single-QR policy: let caller fallback to template/reference
console.warn(`📊 COSE packing produced ${chunks.length} chunks; falling back to non-COSE strategy`);
throw new Error('COSE QR would require multiple chunks');
}
} catch (error) {
console.error('Error generating COSE QR code:', error);
throw error;
}
}
// Expose functions to global scope
window.generateQRCode = generateQRCode;
window.generateCompressedQRCode = generateCompressedQRCode;
window.generateBinaryQRCodeFromObject = generateBinaryQRCodeFromObject;
window.generateCOSEQRCode = generateCOSEQRCode;
window.Html5Qrcode = Html5Qrcode;
window.packSecurePayload = packSecurePayload;
window.receiveAndProcess = receiveAndProcess;
// Expose helper to transparently decompress scanner payloads
window.decompressIfNeeded = function (scannedText) {
try {
if (typeof scannedText === 'string' && scannedText.startsWith(COMPRESSION_PREFIX)) {
const b64 = scannedText.slice(COMPRESSION_PREFIX.length);
return decompressBase64GzipToString(b64);
}
} catch (e) {
console.warn('decompressIfNeeded failed:', e?.message || e);
}
return scannedText;
};
// Expose helper to get compressed string with prefix for copy/paste flows
window.compressToPrefixedGzip = function (text) {
try {
const payload = String(text || '');
const compressedB64 = compressStringToBase64Gzip(payload);
return COMPRESSION_PREFIX + compressedB64;
} catch (e) {
console.warn('compressToPrefixedGzip failed:', e?.message || e);
return String(text || '');
}
};
// Expose helpers for binary payloads in copy/paste
window.encodeBinaryToPrefixed = function (objOrJson) {
try {
const obj = typeof objOrJson === 'string' ? JSON.parse(objOrJson) : objOrJson;
const b64url = encodeObjectToBinaryBase64Url(obj);
return BINARY_PREFIX + b64url;
} catch (e) {
console.warn('encodeBinaryToPrefixed failed:', e?.message || e);
return typeof objOrJson === 'string' ? objOrJson : JSON.stringify(objOrJson);
}
};
window.decodeAnyPayload = function (scannedText) {
try {
if (typeof scannedText === 'string') {
if (scannedText.startsWith(BINARY_PREFIX)) {
const b64url = scannedText.slice(BINARY_PREFIX.length);
return decodeBinaryBase64UrlToObject(b64url); // returns object
}
if (scannedText.startsWith(COMPRESSION_PREFIX)) {
const s = window.decompressIfNeeded(scannedText);
return s; // returns JSON string
}
// Not prefixed: return as-is
return scannedText;
}
} catch (e) {
console.warn('decodeAnyPayload failed:', e?.message || e);
}
return scannedText;
};
console.log('QR libraries loaded: generateQRCode, generateCompressedQRCode, generateBinaryQRCodeFromObject, Html5Qrcode, COSE functions');