v2
424c17b ยท 1 year ago 26 commits
  1import { useEffect, useRef, useState } from "react"
  2import { Toaster, toast } from "react-hot-toast"
  3import { network, encryption, password, notifyStyle, handshake } from "./lib/config"
  4import NavSlider from "./components/ui/nav-slider"
  5import NetworkScreen from "./screens/NetworkScreen"
  6import { Button } from "./components/ui/button"
  7import SetupScreen from "./screens/SetupScreen"
  8import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from "./components/ui/sheet"
  9import LogsScreen from "./screens/LogsScreen"
 10
 11function App() {
 12	const [networks, setNetworks] = useState<network[] | null>(null)
 13	const [networksWithHandshakes, setnetworksWithHandshakes] = useState<network[]>([])
 14	const [section, setSection] = useState<number>(0)
 15	const [logs, setLogs] = useState<string[]>([])
 16	const ws = useRef<WebSocket | null>(null)
 17	const connected = useRef<boolean>(false)
 18	const initialConnection = useRef<boolean>(true)
 19
 20	async function retryConnection() {
 21		let style: any = notifyStyle
 22		style.style["textAlign"] = "center"
 23		try {
 24			ws.current = new WebSocket("ws://172.0.0.1:81/attack")
 25			ws.current.onopen = () => {
 26				connected.current = true
 27				initialConnection.current = false
 28				toast.dismiss()
 29				toast.success("Connected to device")
 30				setNetworks(null)
 31				setSection(0)
 32				fetchData()
 33				ws.current?.send("ping")
 34			}
 35
 36			ws.current.onmessage = (event) => {
 37				if (event.data === "Victim connected") {
 38					setLogs((prev) => [...prev,"Victim connected"]);
 39					return toast.success("Victim connected")
 40				}
 41				if (event.data === "Victim disconnected") {
 42					setLogs((prev) => [...prev, "Victim disconnected"]);
 43					return toast.error("Victim disconnected")
 44				}
 45				const data = JSON.parse(event.data)
 46				if (data) {
 47					if (data.type === "password") {
 48						setLogs((prev) => [...prev, "Victim entered password : " + data.password]);
 49						return toast.success("Victim entered password");
 50					}
 51					if (data.type === "message") {
 52						setLogs((prev) => [...prev, data.message]);
 53						return
 54					}
 55					setLogs((prev) => {
 56						return [...prev, data];
 57					});
 58				}
 59			}
 60			ws.current.onclose = () => {
 61				if (initialConnection.current) {
 62					toast.loading("Could not connect to device", style)
 63					initialConnection.current = false
 64				} else if (connected.current) {
 65					toast.error("Connection to device lost", style)
 66					connected.current = false
 67					initialConnection.current = true
 68					setNetworks(null)
 69					setSection(0)
 70				}
 71				retryConnection()
 72			}
 73
 74			setTimeout(() => {
 75				if (ws.current?.readyState !== 1) {
 76					ws.current?.close()
 77				}
 78			}, 15000)
 79		} catch (err) {
 80			console.log(err, "WebSocket error")
 81		}
 82	}
 83
 84	const checkHandshake = (datas: handshake[], bssid: string): boolean => {
 85		for (let i in datas) {
 86			let incoming = bssid.replaceAll(":", "").toLowerCase()
 87			if (incoming === datas[i].dstAddress) {
 88				return true
 89			}
 90		}
 91		return false
 92	}
 93	const checkPassword = (datas: any, ssid: string): password[] => {
 94		let passwords: password[] = []
 95		for (let i in datas) {
 96			if (ssid === datas[i].ssid) {
 97				let valid = false
 98				if (datas[i].handshakes && datas[i].matched) {
 99					valid = true
100				}
101				passwords.push({
102					password: datas[i].password,
103					valid: valid,
104				})
105			}
106		}
107		return passwords
108	}
109
110	const fetchData = async () => {
111		const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
112		await sleep(1000)
113		const get_networks = await fetch("http://172.0.0.1/get_networks")
114		const get_datas = await fetch("http://172.0.0.1/get_datas")
115		// const get_networks = await fetch("/temp/temp-networks.json")
116		// const get_datas = await fetch("/temp/temp-datas.json")
117		const data = await get_networks.json()
118		const datas = await get_datas.json()
119		if (data.length === 0) {
120			console.log("No networks found")
121			setNetworks([])
122			setnetworksWithHandshakes([])
123		}
124		for (let i in data) {
125			let new_network: network = {
126				ssid: data[i].ssid,
127				bssid: data[i].bssid,
128				signal: parseInt(data[i].signal),
129				channel: parseInt(data[i].channel),
130				encryption: data[i].encryption,
131				deauthState: data[i].deauthState === "1" ? true : false,
132				handshake: checkHandshake(datas.handshakes, data[i].bssid),
133				password: checkPassword(datas.passwords, data[i].ssid),
134				handshakeData: datas.handshakes.filter(
135					(handshake: handshake) =>
136						handshake.dstAddress === data[i].bssid.replaceAll(":", "").toLowerCase()
137				),
138			}
139			setNetworks((prev) => {
140				return prev ? [...prev, new_network] : [new_network]
141			})
142		}
143		for (let i in datas.handshakes) {
144			let newNetwork: network = {
145				ssid: datas.handshakes[i].ssid,
146				bssid: datas.handshakes[i].dstAddress,
147				signal: 0,
148				channel: 0,
149				encryption: encryption.UNKNOWN,
150				deauthState: false,
151				handshake: true,
152				password: checkPassword(datas.passwords, datas.handshakes[i].ssid),
153				handshakeData: [datas.handshakes[i]],
154			}
155			setnetworksWithHandshakes((prev) => {
156				if (prev) {
157					let found = prev.find((network) => network.bssid === newNetwork.bssid)
158					if (found) {
159						return prev
160					}
161				}
162				return prev ? [...prev, newNetwork] : [newNetwork]
163			})
164		}
165	}
166	useEffect(() => {
167		retryConnection()
168		document.title = "Portal-Xtend"
169	}, [])
170
171	return (
172		<div className="flex flex-col h-screen bg-[#040a1b] justify-center items-center overflow-hidden">
173			<h1 className="text-[#77AADD] font-semibold text-[50px] mb-2">Portal-Xtend</h1>
174			<Toaster position="bottom-center" />
175			<div className="flex flex-col justify-center items-center">
176				{networks != null ? (
177					<>
178						<NavSlider
179							activeNav={section}
180							setActiveNav={setSection}
181							children={["Networks", "Setup","Logs"]}
182						/>
183						{section === 0 ? (
184							<>
185								<NetworkScreen networks={networks} />
186								<Button
187									variant="link"
188									onClick={() => {
189										setNetworks(null)
190										setSection(0)
191										fetchData()
192									}}
193									>
194									Refresh
195								</Button>
196							</>
197						) : section === 1 ? (
198							<SetupScreen networks={networksWithHandshakes} />
199						) : 
200						<LogsScreen logs={logs} setLogs={setLogs}/>
201						}
202					</>
203				) : (
204					<div className="loading">
205						<svg width="64px" height="48px">
206							<polyline
207								points="0.157 23.954, 14 23.954, 21.843 48, 43 0, 50 24, 64 24"
208								id="back"
209							></polyline>
210							<polyline
211								points="0.157 23.954, 14 23.954, 21.843 48, 43 0, 50 24, 64 24"
212								id="front"
213							></polyline>
214						</svg>
215					</div>
216				)}
217			</div>
218		</div>
219	)
220}
221
222export default App