From ff75515fab9f5eb0b0beb3ced320ee322744835b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Nov 2025 21:20:40 +0000 Subject: [PATCH] Security: Remove mock features and demo mode bypass - Delete LimitOrders.tsx (no blockchain pallet) - Delete P2PMarket.tsx (no blockchain pallet) - Remove P2P Market from AppLayout navigation - Remove LimitOrders from TokenSwap component - Delete FOUNDER_ACCOUNT hardcoded credentials - Delete DEMO_MODE_ENABLED bypass logic - Remove localStorage demo_user persistence - All authentication now goes through Supabase only SECURITY FIX: Closes critical authentication bypass vulnerability --- web/src/components/AppLayout.tsx | 26 +- web/src/components/TokenSwap.tsx | 8 - web/src/components/p2p/P2PMarket.tsx | 798 --------------------- web/src/components/trading/LimitOrders.tsx | 306 -------- web/src/contexts/AuthContext.tsx | 64 -- 5 files changed, 1 insertion(+), 1201 deletions(-) delete mode 100644 web/src/components/p2p/P2PMarket.tsx delete mode 100644 web/src/components/trading/LimitOrders.tsx diff --git a/web/src/components/AppLayout.tsx b/web/src/components/AppLayout.tsx index f7c57f2b..45bd5737 100644 --- a/web/src/components/AppLayout.tsx +++ b/web/src/components/AppLayout.tsx @@ -27,7 +27,6 @@ import RewardDistribution from './RewardDistribution'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { useWebSocket } from '@/contexts/WebSocketContext'; import { StakingDashboard } from './staking/StakingDashboard'; -import { P2PMarket } from './p2p/P2PMarket'; import { MultiSigWallet } from './wallet/MultiSigWallet'; import { useWallet } from '@/contexts/WalletContext'; import { supabase } from '@/lib/supabase'; @@ -45,7 +44,6 @@ const AppLayout: React.FC = () => { const [showTreasury, setShowTreasury] = useState(false); const [treasuryTab, setTreasuryTab] = useState('overview'); const [showStaking, setShowStaking] = useState(false); - const [showP2P, setShowP2P] = useState(false); const [showMultiSig, setShowMultiSig] = useState(false); const [showDEX, setShowDEX] = useState(false); const { t } = useTranslation(); @@ -182,13 +180,6 @@ const AppLayout: React.FC = () => { DEX Pools - - - - - - {/* Basic Filters */} -
- setActiveTab(v as 'buy' | 'sell')} className="flex-1"> - - Buy - Sell - - - - - -
-
- - setSearchTerm(e.target.value)} - className="pl-10 bg-gray-800 border-gray-700" - /> -
-
- - {/* Sort Selector */} - -
- - {/* Advanced Filters Panel (Binance P2P style) */} - {showFilters && ( - -
-

- - Advanced Filters -

- -
- {/* Payment Method Filter */} -
- - -
- - {/* Min Price Filter */} -
- - setMinPrice(e.target.value)} - className="bg-gray-900 border-gray-700" - /> -
- - {/* Max Price Filter */} -
- - setMaxPrice(e.target.value)} - className="bg-gray-900 border-gray-700" - /> -
-
- - {/* Clear Filters Button */} - -
-
- )} - - {/* Offers List */} -
- {filteredOffers.map((offer) => ( - - -
-
-
- -
-
-
- {offer.seller.name} - {offer.seller.verified && ( - - - Verified - - )} -
-
- ⭐ {offer.seller.rating} - {offer.seller.completedTrades} trades - {offer.paymentMethod} -
-
-
- -
-
- ${offer.price} / {offer.token} -
-
- Available: {offer.amount.toLocaleString()} {offer.token} -
-
- Limits: {offer.minOrder} - {offer.maxOrder} {offer.token} -
-
- - -
-
-
- ))} -
- - - - - {/* Trade Modal */} - {selectedOffer && ( - - - - {activeTab === 'buy' ? 'Buy' : 'Sell'} {selectedOffer.token} from {selectedOffer.seller.name} - - Complete your P2P trade - - -
- - setTradeAmount(e.target.value)} - className="bg-gray-800 border-gray-700" - /> -
- -
-
- Price per {selectedOffer.token} - ${selectedOffer.price} -
-
- Total Amount - - ${(parseFloat(tradeAmount || '0') * selectedOffer.price).toFixed(2)} - -
-
- Payment Method - {selectedOffer.paymentMethod} -
-
- Time Limit - {selectedOffer.timeLimit} minutes -
-
- -
- - -
-
-
- )} - - {/* Create Order Modal (Binance P2P style) */} - {showCreateOrder && ( - - -
- Create P2P Order - -
- - Create a {activeTab === 'buy' ? 'buy' : 'sell'} order for {selectedToken} - -
- -
- - setActiveTab(v as 'buy' | 'sell')}> - - Buy - Sell - - -
- -
- - -
- -
- - setNewOrderAmount(e.target.value)} - className="bg-gray-800 border-gray-700" - /> -
- -
- - setNewOrderPrice(e.target.value)} - className="bg-gray-800 border-gray-700" - /> -
- -
- - -
- -
-
- Total Value - - ${(parseFloat(newOrderAmount || '0') * parseFloat(newOrderPrice || '0')).toFixed(2)} - -
-
- -
- - -
- -
- Note: Blockchain integration for P2P orders is coming soon -
-
-
- )} - - {/* Escrow Modal (Binance P2P Escrow style) */} - {showEscrow && escrowOffer && ( - - -
- - - Secure Escrow Trade - - -
- - Trade safely with escrow protection • {activeTab === 'buy' ? 'Buying' : 'Selling'} {escrowOffer.token} - -
- - {/* Escrow Steps Indicator */} -
- {[ - { step: 'funding', label: 'Fund Escrow', icon: Lock }, - { step: 'confirmation', label: 'Payment', icon: Clock }, - { step: 'release', label: 'Complete', icon: CheckCircle } - ].map((item, idx) => ( -
-
idx ? 'bg-green-600' : 'bg-gray-700' - }`}> - -
- {item.label} - {idx < 2 && ( -
idx ? 'bg-green-600' : 'bg-gray-700' - }`} style={{ left: `calc(${(idx + 1) * 33.33}% - 64px)` }}>
- )} -
- ))} -
- - {/* Trade Details Card */} - -

Trade Details

-
-
- Seller - {escrowOffer.seller.name} -
-
- Amount - {tradeAmount} {escrowOffer.token} -
-
- Price per {escrowOffer.token} - ${escrowOffer.price} -
-
- Payment Method - {escrowOffer.paymentMethod} -
-
- Total - - ${(parseFloat(tradeAmount || '0') * escrowOffer.price).toFixed(2)} - -
-
-
- - {/* Step Content */} - {escrowStep === 'funding' && ( -
-
-
- -
- Escrow Protection: Your funds will be held securely in smart contract escrow until both parties confirm the trade. This protects both buyer and seller. -
-
-
- -
- 1. Fund the escrow with {tradeAmount} {escrowOffer.token}
- 2. Wait for seller to provide payment details
- 3. Complete payment via {escrowOffer.paymentMethod}
- 4. Confirm payment to release escrow -
- - -
- )} - - {escrowStep === 'confirmation' && ( -
-
-
- -
- Waiting for Payment: Complete your {escrowOffer.paymentMethod} payment and click confirm when done. Do not release escrow until payment is verified! -
-
-
- - -

Payment Instructions

-
-

• Payment Method: {escrowOffer.paymentMethod}

-

• Amount: ${(parseFloat(tradeAmount || '0') * escrowOffer.price).toFixed(2)}

-

• Time Limit: {escrowOffer.timeLimit} minutes

-
-
- -
- - -
-
- )} - - {escrowStep === 'release' && ( -
-
-
- -
- Payment Confirmed: Your payment has been verified. The escrow will be released to the seller automatically. -
-
-
- - -

Trade Summary

-
-

✅ Escrow Funded: {tradeAmount} {escrowOffer.token}

-

✅ Payment Sent: ${(parseFloat(tradeAmount || '0') * escrowOffer.price).toFixed(2)}

-

✅ Payment Verified

-

🎉 Trade Completed Successfully!

-
-
- - -
- )} - -
- Note: Smart contract escrow integration coming soon -
-
-
- )} - - {/* Overlay */} - {(showCreateOrder || selectedOffer || showEscrow) && ( -
{ - setShowCreateOrder(false); - setSelectedOffer(null); - setShowEscrow(false); - }}>
- )} - - ); -}; \ No newline at end of file diff --git a/web/src/components/trading/LimitOrders.tsx b/web/src/components/trading/LimitOrders.tsx deleted file mode 100644 index 4b7aaa10..00000000 --- a/web/src/components/trading/LimitOrders.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import React, { useState } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Label } from '@/components/ui/label'; -import { Badge } from '@/components/ui/badge'; -import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { X, Clock, CheckCircle, AlertCircle } from 'lucide-react'; - -interface LimitOrder { - id: string; - type: 'buy' | 'sell'; - fromToken: string; - toToken: string; - fromAmount: number; - limitPrice: number; - currentPrice: number; - status: 'pending' | 'filled' | 'cancelled' | 'expired'; - createdAt: number; - expiresAt: number; -} - -interface LimitOrdersProps { - fromToken: string; - toToken: string; - currentPrice: number; - onCreateOrder?: (order: Omit) => void; -} - -export const LimitOrders: React.FC = ({ - fromToken, - toToken, - currentPrice, - onCreateOrder -}) => { - const [orderType, setOrderType] = useState<'buy' | 'sell'>('buy'); - const [amount, setAmount] = useState(''); - const [limitPrice, setLimitPrice] = useState(''); - const [showCreateForm, setShowCreateForm] = useState(false); - - // Mock orders (in production, fetch from blockchain) - const [orders, setOrders] = useState([ - { - id: '1', - type: 'buy', - fromToken: 'PEZ', - toToken: 'HEZ', - fromAmount: 100, - limitPrice: 0.98, - currentPrice: 1.02, - status: 'pending', - createdAt: Date.now() - 3600000, - expiresAt: Date.now() + 82800000 - }, - { - id: '2', - type: 'sell', - fromToken: 'HEZ', - toToken: 'PEZ', - fromAmount: 50, - limitPrice: 1.05, - currentPrice: 1.02, - status: 'pending', - createdAt: Date.now() - 7200000, - expiresAt: Date.now() + 79200000 - } - ]); - - const handleCreateOrder = () => { - const newOrder: Omit = { - type: orderType, - fromToken: orderType === 'buy' ? toToken : fromToken, - toToken: orderType === 'buy' ? fromToken : toToken, - fromAmount: parseFloat(amount), - limitPrice: parseFloat(limitPrice), - currentPrice - }; - - console.log('Creating limit order:', newOrder); - - // Add to orders list (mock) - const order: LimitOrder = { - ...newOrder, - id: Date.now().toString(), - status: 'pending', - createdAt: Date.now(), - expiresAt: Date.now() + 86400000 // 24 hours - }; - - setOrders([order, ...orders]); - setShowCreateForm(false); - setAmount(''); - setLimitPrice(''); - - if (onCreateOrder) { - onCreateOrder(newOrder); - } - }; - - const handleCancelOrder = (orderId: string) => { - setOrders(orders.map(order => - order.id === orderId ? { ...order, status: 'cancelled' as const } : order - )); - }; - - const getStatusBadge = (status: LimitOrder['status']) => { - switch (status) { - case 'pending': - return - - Pending - ; - case 'filled': - return - - Filled - ; - case 'cancelled': - return - - Cancelled - ; - case 'expired': - return - - Expired - ; - } - }; - - const getPriceDistance = (order: LimitOrder) => { - const distance = ((order.limitPrice - order.currentPrice) / order.currentPrice) * 100; - return distance; - }; - - return ( - - -
-
- Limit Orders - - Set orders to execute at your target price - -
- -
-
- - {showCreateForm && ( - -
-
- - setOrderType(v as 'buy' | 'sell')}> - - Buy {fromToken} - Sell {fromToken} - - -
- -
- - setAmount(e.target.value)} - className="bg-gray-900 border-gray-700" - /> -
- -
- - setLimitPrice(e.target.value)} - className="bg-gray-900 border-gray-700" - /> -
- Current market price: ${currentPrice.toFixed(4)} -
-
- -
-
- You will {orderType} - - {amount || '0'} {orderType === 'buy' ? fromToken : toToken} - -
-
- When price reaches - - ${limitPrice || '0'} per {fromToken} - -
-
- Estimated total - - {((parseFloat(amount || '0') * parseFloat(limitPrice || '0'))).toFixed(2)} {orderType === 'buy' ? toToken : fromToken} - -
-
- - - -
- Order will expire in 24 hours if not filled -
-
-
- )} - - {/* Orders List */} -
- {orders.length === 0 ? ( -
- No limit orders yet. Create one to get started! -
- ) : ( - orders.map(order => { - const priceDistance = getPriceDistance(order); - return ( - -
-
- - {order.type.toUpperCase()} - - - {order.fromToken} → {order.toToken} - -
- {getStatusBadge(order.status)} -
- -
-
-
Amount
-
- {order.fromAmount} {order.fromToken} -
-
-
-
Limit Price
-
- ${order.limitPrice.toFixed(4)} -
-
-
-
Current Price
-
- ${order.currentPrice.toFixed(4)} -
-
-
-
Distance
-
0 ? 'text-green-400' : 'text-red-400'}> - {priceDistance > 0 ? '+' : ''}{priceDistance.toFixed(2)}% -
-
-
- -
- - Created {new Date(order.createdAt).toLocaleString()} - - {order.status === 'pending' && ( - - )} -
-
- ); - }) - )} -
- -
- Note: Limit orders require blockchain integration to execute automatically -
-
-
- ); -}; diff --git a/web/src/contexts/AuthContext.tsx b/web/src/contexts/AuthContext.tsx index e1401f5d..3894dc4a 100644 --- a/web/src/contexts/AuthContext.tsx +++ b/web/src/contexts/AuthContext.tsx @@ -12,23 +12,6 @@ interface AuthContextType { checkAdminStatus: () => Promise; } -// Demo/Founder account credentials from environment variables -// ⚠️ SECURITY: Never hardcode credentials in source code! -const FOUNDER_ACCOUNT = { - email: import.meta.env.VITE_DEMO_FOUNDER_EMAIL || '', - password: import.meta.env.VITE_DEMO_FOUNDER_PASSWORD || '', - id: import.meta.env.VITE_DEMO_FOUNDER_ID || 'founder-001', - user_metadata: { - full_name: 'Satoshi Qazi Muhammed', - phone: '+9647700557978', - recovery_email: 'satoshi@pezkuwichain.io', - founder: true - } -}; - -// Check if demo mode is enabled -const DEMO_MODE_ENABLED = import.meta.env.VITE_ENABLE_DEMO_MODE === 'true'; - const AuthContext = createContext(undefined); export const useAuth = () => { @@ -89,42 +72,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }; const signIn = async (email: string, password: string) => { - // Check if demo mode is enabled and this is the founder account - if (DEMO_MODE_ENABLED && email === FOUNDER_ACCOUNT.email && password === FOUNDER_ACCOUNT.password) { - // Try Supabase first - try { - const { data, error } = await supabase.auth.signInWithPassword({ - email, - password, - }); - - if (!error && data.user) { - await checkAdminStatus(); - return { error: null }; - } - } catch { - // Supabase not available - } - - // Fallback to demo mode for founder account - const demoUser = { - id: FOUNDER_ACCOUNT.id, - email: FOUNDER_ACCOUNT.email, - user_metadata: FOUNDER_ACCOUNT.user_metadata, - email_confirmed_at: new Date().toISOString(), - created_at: new Date().toISOString(), - } as User; - - setUser(demoUser); - setIsAdmin(true); - - // Store in localStorage for persistence - localStorage.setItem('demo_user', JSON.stringify(demoUser)); - - return { error: null }; - } - - // For other accounts, use Supabase try { const { data, error } = await supabase.auth.signInWithPassword({ email, @@ -186,21 +133,10 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }; const signOut = async () => { - localStorage.removeItem('demo_user'); setIsAdmin(false); await supabase.auth.signOut(); }; - // Check for demo user on mount - useEffect(() => { - const demoUser = localStorage.getItem('demo_user'); - if (demoUser && !user) { - const parsedUser = JSON.parse(demoUser); - setUser(parsedUser); - setIsAdmin(true); - } - }, []); - return (