Skip to content

Commit a3ff7cc

Browse files
committed
Merge branch 'release/0.3.3'
2 parents 05f6475 + dd65d3c commit a3ff7cc

9 files changed

Lines changed: 102 additions & 19 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "droidground",
3-
"version": "0.3.2",
3+
"version": "0.3.3",
44
"type": "module",
55
"author": "Angelo Delicato",
66
"scripts": {

src/client/layout/Header.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useState } from "react";
1+
import { useEffect, useMemo, useRef, useState } from "react";
22
import { useLocation, useNavigate } from "@tanstack/react-router";
33
import { motion } from "motion/react";
44
import toast from "react-hot-toast";
@@ -56,14 +56,18 @@ const Navbar: React.FC = () => {
5656
{ label: "Exploit Server", to: PAGES.EXPLOIT_SERVER, routeEnabled: teamModeEnabled },
5757
];
5858

59+
const suffix = useMemo(() => {
60+
const suffix = featuresConfig.basePath.length > 0 ? featuresConfig.basePath : "";
61+
return suffix;
62+
}, [featuresConfig]);
63+
5964
useEffect(() => {
6065
if (!appManagerEnabled) {
6166
return;
6267
}
6368

6469
const isHttps = typeof window !== "undefined" && window.location.protocol === "https:";
6570
const prefix = isHttps ? "wss" : "ws";
66-
const suffix = featuresConfig.basePath.length > 0 ? featuresConfig.basePath : "";
6771
const wsBaseUrl = `${prefix}://${window.location.host}${suffix}`;
6872
const socket = new WebSocket(`${wsBaseUrl}${WEBSOCKET_ENDPOINTS.NOTIFICATIONS}`);
6973

@@ -187,7 +191,7 @@ const Navbar: React.FC = () => {
187191
className="cursor-pointer relative z-10 px-3 py-2 rounded-md transition-colors text-gray-300"
188192
>
189193
{item.label}
190-
{location.pathname === item.to && (
194+
{location.pathname === `${suffix}${item.to}` && (
191195
<motion.div
192196
layoutId="underline"
193197
className="absolute -bottom-4.5 left-0 right-0 h-0.5 bg-info rounded z-20"

src/client/layout/Renderer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const VideoRenderer: React.FC = () => {
183183

184184
return (
185185
<div
186-
className={`m-auto w-3/4 min-w-3/4 sm:w-1/2 sm:min-w-1/2 lg:w-1/4 lg:min-w-1/4 rounded-2xl border-10 border-black shadow-2xl flex items-center justify-center relative overflow-hidden ${streamingPhase !== StreamingPhase.RENDER ? "aspect-9/16 bg-gray-950" : "bg-transparent "}`}
186+
className={`mx-auto w-3/4 min-w-3/4 sm:w-1/2 sm:min-w-1/2 lg:w-1/4 lg:min-w-1/4 rounded-2xl border-10 border-black shadow-2xl flex items-center justify-center relative overflow-hidden ${streamingPhase !== StreamingPhase.RENDER ? "aspect-9/16 bg-gray-950" : "bg-transparent "}`}
187187
>
188188
{/* Speaker + Camera Dot */}
189189
<div className="absolute top-2 w-full flex justify-center items-center z-10">

src/client/views/AppManager.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const AppManager: React.FC = () => {
104104
</div>
105105
<div className="card bg-base-300 border border-base-300">
106106
<div className="card-body p-4 max-h-screen">
107-
<div className="card-title justify-between mb-2 select-none">
107+
<div className="card-title items-start justify-between mb-2 select-none flex flex-col lg:flex-row">
108108
<h2>Third-party Apps</h2>
109109
<div className="flex gap-2">
110110
<button className="btn btn-info" onClick={getPackageInfos}>

src/client/views/Debug.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ export const Debug: React.FC = () => {
4040
<h2>Attack Surface</h2>
4141
</div>
4242
<div className="flex gap-2">
43-
<form onSubmit={handleSubmit(retrieveAttackSurface)} className="flex flex-1 gap-4 space-y-4">
43+
<form
44+
onSubmit={handleSubmit(retrieveAttackSurface)}
45+
className="flex flex-1 space-y-4 flex-col lg:flex-row lg:gap-4"
46+
>
4447
<input
4548
type="text"
4649
placeholder="Debug Token in server logs"
@@ -50,8 +53,8 @@ export const Debug: React.FC = () => {
5053
{errors.debugToken && <p className="text-error text-sm">Debug Token is required.</p>}
5154

5255
{/* Submit */}
53-
<div className="flex justify-end">
54-
<input className="btn btn-primary" type="submit" value="Get Attack Surface" />
56+
<div className="flex w-full lg:w-auto justify-end">
57+
<input className="btn btn-primary w-full" type="submit" value="Get Attack Surface" />
5558
</div>
5659
</form>
5760
</div>

src/client/views/ExploitServer.tsx

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,79 @@
1-
import { useRef, useState } from "react";
1+
import { useEffect, useId, useRef, useState } from "react";
22
import { SubmitHandler, useForm } from "react-hook-form";
33
import toast from "react-hot-toast";
44
import { BiSolidServer } from "react-icons/bi";
5+
import { FaCopy } from "react-icons/fa";
56
import { useAPI } from "@client/context/API";
67
import { TeamTokenGenericRequest } from "@shared/api";
78
import { WEBSOCKET_ENDPOINTS } from "@shared/endpoints";
89

10+
type CopyButtonProps = {
11+
text: string;
12+
tooltip?: string;
13+
copiedTooltip?: string;
14+
ariaLabel?: string;
15+
buttonClassName?: string;
16+
className?: string;
17+
};
18+
19+
async function copyToClipboard(text: string) {
20+
if (navigator.clipboard?.writeText) {
21+
await navigator.clipboard.writeText(text);
22+
return;
23+
}
24+
}
25+
26+
export function CopyIconButton({
27+
text,
28+
tooltip = "Copy",
29+
copiedTooltip = "Copied!",
30+
ariaLabel = "Copy to clipboard",
31+
buttonClassName = "btn btn-ghost btn-sm",
32+
className = "",
33+
}: CopyButtonProps) {
34+
const [copied, setCopied] = useState(false);
35+
const liveId = useId();
36+
const timerRef = useRef<number | null>(null);
37+
38+
useEffect(() => {
39+
return () => {
40+
if (timerRef.current) window.clearTimeout(timerRef.current);
41+
};
42+
}, []);
43+
44+
async function handleCopy() {
45+
try {
46+
await copyToClipboard(text);
47+
setCopied(true);
48+
49+
if (timerRef.current) window.clearTimeout(timerRef.current);
50+
timerRef.current = window.setTimeout(() => setCopied(false), 1200);
51+
} catch (err) {
52+
console.error(err);
53+
}
54+
}
55+
56+
return (
57+
<span className={`inline-flex items-center gap-2 ${className}`}>
58+
<div className="tooltip tooltip-bottom" data-tip={copied ? copiedTooltip : tooltip}>
59+
<button
60+
type="button"
61+
className={buttonClassName}
62+
onClick={handleCopy}
63+
aria-label={ariaLabel}
64+
aria-describedby={liveId}
65+
>
66+
<FaCopy size={16} />
67+
</button>
68+
</div>
69+
70+
<span id={liveId} className="sr-only" aria-live="polite">
71+
{copied ? copiedTooltip : ""}
72+
</span>
73+
</span>
74+
);
75+
}
76+
977
export const ExploitServer: React.FC = () => {
1078
const { featuresConfig } = useAPI();
1179
const [isConnected, setIsConnected] = useState<boolean>(false);
@@ -57,14 +125,20 @@ export const ExploitServer: React.FC = () => {
57125

58126
return (
59127
<div className="w-full flex flex-col gap-2">
60-
<div className="flex items-center justify-between mb-2">
128+
<div className="flex items-start gap-2 justify-between mb-2 flex-col lg:flex-row">
61129
<div className="flex items-center gap-2">
62130
<BiSolidServer size={32} />
63131
<h1 className="text-2xl font-semibold select-none">Exploit Server</h1>
64132
</div>
65133
{featuresConfig.ipAddress.length > 0 && (
66-
<span className="indicator-item badge badge-primary">
67-
<b>IP Address:</b> <code>{featuresConfig.ipAddress}</code>
134+
<span className="indicator-item badge badge-primary py-4">
135+
<b>Host:</b> <code>{featuresConfig.ipAddress}</code>
136+
<CopyIconButton
137+
text={featuresConfig.ipAddress}
138+
buttonClassName="btn btn-ghost hover:bg-white hover:text-primary btn-square btn-xs"
139+
tooltip="Copy Host"
140+
copiedTooltip="Copied!"
141+
/>
68142
</span>
69143
)}
70144
</div>
@@ -77,8 +151,9 @@ export const ExploitServer: React.FC = () => {
77151
suggest you to <b>keep this page open</b>.
78152
</p>
79153
<p className="text-info">
80-
You will be able to visualize all the network interactions made to <code>/exploit/&lt;teamToken&gt;</code>.
81-
Type your <i>team token</i> and click on <i>Connect</i> to start.
154+
You will be able to visualize all the network interactions made to{" "}
155+
<code>http://&lt;host&gt;/exploit/&lt;teamToken&gt;</code>. Type your <i>team token</i> and click on{" "}
156+
<i>Connect</i> to start.
82157
</p>
83158
<div className="flex gap-2 mt-4">
84159
<form onSubmit={handleSubmit(connectToExploitServer)} className="flex flex-1 gap-4 space-y-4">

src/client/views/Logs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const Logs: React.FC = () => {
3434
</div>
3535
<div className="card bg-base-300 border border-base-300">
3636
<div className="card-body p-4">
37-
<div className="card-title justify-between select-none">
37+
<div className="card-title items-start justify-between mb-2 select-none flex flex-col lg:flex-row">
3838
<h2>Logcat</h2>
3939
<div className="flex gap-2">
4040
<button className="btn btn-info" onClick={dump}>

src/server/manager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export class ManagerSingleton {
5353
const ipStatic = process.env.DROIDGROUND_IP_STATIC ?? undefined;
5454
const iface = process.env.DROIDGROUND_IP_IFACE ?? "";
5555
const ipAddress = ipStatic && ipStatic.length > 0 ? ipStatic : getIP(iface); // Either an empty string or the IP address
56+
const backendPort = process.env.DROIDGROUND_PORT || 4242;
5657
// Check team-mode
5758
const teamNumEnv: any = process.env.DROIDGROUND_NUM_TEAMS ?? "";
5859
const teamNum: number = isNaN(teamNumEnv) || teamNumEnv.trim().length === 0 ? 0 : parseInt(teamNumEnv);
@@ -89,7 +90,7 @@ export class ManagerSingleton {
8990
fridaType: process.env.DROIDGROUND_FRIDA_TYPE === "full" ? "full" : "jail",
9091
exploitAppDuration:
9192
isNaN(exploitAppDuration) || exploitAppDuration.trim().length === 0 ? 10 : parseInt(exploitAppDuration),
92-
ipAddress: ipAddress,
93+
ipAddress: `${ipAddress}:${backendPort}`,
9394
},
9495
teams: teams,
9596
debugToken: crypto.randomBytes(64).toString("hex"),

0 commit comments

Comments
 (0)