Skip to content

Commit 7ea0cb2

Browse files
committed
Merge branch 'release/0.2.6'
2 parents 6c247f6 + 17de992 commit 7ea0cb2

File tree

14 files changed

+114
-43
lines changed

14 files changed

+114
-43
lines changed

package-lock.json

Lines changed: 9 additions & 9 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.2.5",
3+
"version": "0.2.6",
44
"type": "module",
55
"author": "Angelo Delicato",
66
"scripts": {

run.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ if [ "$DROIDGROUND_DEVICE_TYPE" == "network" ]; then
88
echo "DROIDGROUND_DEVICE_TYPE is set to 'network'. Trying to connect to the Android device..."
99

1010
while true; do
11+
adb kill-server
12+
adb start-server
1113
adb connect $DROIDGROUND_DEVICE_HOST:$DROIDGROUND_DEVICE_PORT
1214

1315
# List connected devices

src/client/api/rest.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { http } from "@client/api/axios";
22
import {
3+
ActionResponse,
34
BugreportzStatusResponse,
45
CompanionPackageInfos,
56
DeviceInfoResponse,
@@ -40,13 +41,13 @@ class RESTManager {
4041
return res;
4142
}
4243

43-
async startActivity(data: StartActivityRequest): Promise<AxiosResponse<IGenericResultRes>> {
44-
const res = await http.post<IGenericResultRes>(E.ACTIVITY, data);
44+
async startActivity(data: StartActivityRequest): Promise<AxiosResponse<ActionResponse>> {
45+
const res = await http.post<ActionResponse>(E.ACTIVITY, data);
4546
return res;
4647
}
4748

48-
async startBroadcast(data: StartBroadcastRequest): Promise<AxiosResponse<IGenericResultRes>> {
49-
const res = await http.post<IGenericResultRes>(E.BROADCAST, data);
49+
async startBroadcast(data: StartBroadcastRequest): Promise<AxiosResponse<ActionResponse>> {
50+
const res = await http.post<ActionResponse>(E.BROADCAST, data);
5051
return res;
5152
}
5253

@@ -55,8 +56,8 @@ class RESTManager {
5556
return res;
5657
}
5758

58-
async startService(data: StartServiceRequest): Promise<AxiosResponse<IGenericResultRes>> {
59-
const res = await http.post<IGenericResultRes>(E.SERVICE, data);
59+
async startService(data: StartServiceRequest): Promise<AxiosResponse<ActionResponse>> {
60+
const res = await http.post<ActionResponse>(E.SERVICE, data);
6061
return res;
6162
}
6263

src/client/components/StartActivityModal.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ export const StartActivityModal: React.FC<IModalProps> = ({ dialogRef }) => {
5151
const startActivity: SubmitHandler<StartActivityRequest> = async data => {
5252
try {
5353
const res = await RESTManagerInstance.startActivity(data);
54-
setActionResult(res.data.result.split("\n"));
54+
const resultLines = res.data.result.split("\n");
55+
setActionResult([`Command executed: ${res.data.command}`, ...resultLines]);
5556
} catch (e) {
5657
console.error(e);
5758
toast.error("Error while starting activity.");
@@ -119,7 +120,7 @@ export const StartActivityModal: React.FC<IModalProps> = ({ dialogRef }) => {
119120
<button
120121
type="button"
121122
className="btn btn-sm btn-outline"
122-
onClick={() => append({ key: "", type: IntentExtraType.STRING })}
123+
onClick={() => append({ key: "", type: IntentExtraType.STRING, value: "" })}
123124
>
124125
+ Add Extra
125126
</button>
@@ -146,7 +147,14 @@ export const StartActivityModal: React.FC<IModalProps> = ({ dialogRef }) => {
146147
</select>
147148
</div>
148149

149-
{/* Conditionally render value input */}
150+
<input
151+
{...register(`extras.${index}.value`, { required: true })}
152+
type="text"
153+
placeholder="Value"
154+
className="input input-bordered w-full"
155+
/>
156+
157+
{/* Conditionally render value input
150158
{startActivityForm.watch(`extras.${index}.type`) !== IntentExtraType.NULL && (
151159
<Controller
152160
name={`extras.${index}.value`}
@@ -158,6 +166,7 @@ export const StartActivityModal: React.FC<IModalProps> = ({ dialogRef }) => {
158166
}}
159167
/>
160168
)}
169+
*/}
161170

162171
<div className="text-right">
163172
<button type="button" className="btn btn-sm btn-error" onClick={() => remove(index)}>

src/client/components/StartBroadcastModal.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ export const StartBroadcastModal: React.FC<IModalProps> = ({ dialogRef }) => {
5454

5555
try {
5656
const res = await RESTManagerInstance.startBroadcast(data);
57-
setActionResult(res.data.result.split("\n"));
57+
const resultLines = res.data.result.split("\n");
58+
setActionResult([`Command executed: ${res.data.command}`, ...resultLines]);
5859
} catch (e) {
5960
console.error(e);
6061
toast.error("Failed to send broadcast intent.");
@@ -93,7 +94,7 @@ export const StartBroadcastModal: React.FC<IModalProps> = ({ dialogRef }) => {
9394
<button
9495
type="button"
9596
className="btn btn-sm btn-outline"
96-
onClick={() => append({ key: "", type: IntentExtraType.STRING })}
97+
onClick={() => append({ key: "", type: IntentExtraType.STRING, value: "" })}
9798
>
9899
+ Add Extra
99100
</button>
@@ -120,6 +121,14 @@ export const StartBroadcastModal: React.FC<IModalProps> = ({ dialogRef }) => {
120121
</select>
121122
</div>
122123

124+
<input
125+
{...register(`extras.${index}.value`, { required: true })}
126+
type="text"
127+
placeholder="Value"
128+
className="input input-bordered w-full"
129+
/>
130+
131+
{/*
123132
{watch(`extras.${index}.type`) !== IntentExtraType.NULL && (
124133
<Controller
125134
name={`extras.${index}.value`}
@@ -129,6 +138,7 @@ export const StartBroadcastModal: React.FC<IModalProps> = ({ dialogRef }) => {
129138
)}
130139
/>
131140
)}
141+
*/}
132142

133143
<div className="text-right">
134144
<button type="button" className="btn btn-sm btn-error" onClick={() => remove(index)}>

src/client/components/StartServiceModal.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export const StartServiceModal: React.FC<IModalProps> = ({ dialogRef }) => {
5050
const startService: SubmitHandler<StartServiceRequest> = async data => {
5151
try {
5252
const res = await RESTManagerInstance.startService(data);
53-
setActionResult(res.data.result.split("\n"));
53+
const resultLines = res.data.result.split("\n");
54+
setActionResult([`Command executed: ${res.data.command}`, ...resultLines]);
5455
} catch (e) {
5556
console.error(e);
5657
toast.error("Failed to start service.");
@@ -96,7 +97,7 @@ export const StartServiceModal: React.FC<IModalProps> = ({ dialogRef }) => {
9697
<button
9798
type="button"
9899
className="btn btn-sm btn-outline"
99-
onClick={() => append({ key: "", type: IntentExtraType.STRING })}
100+
onClick={() => append({ key: "", type: IntentExtraType.STRING, value: "" })}
100101
>
101102
+ Add Extra
102103
</button>
@@ -123,6 +124,14 @@ export const StartServiceModal: React.FC<IModalProps> = ({ dialogRef }) => {
123124
</select>
124125
</div>
125126

127+
<input
128+
{...register(`extras.${index}.value`, { required: true })}
129+
type="text"
130+
placeholder="Value"
131+
className="input input-bordered w-full"
132+
/>
133+
134+
{/*
126135
{watch(`extras.${index}.type`) !== IntentExtraType.NULL && (
127136
<Controller
128137
name={`extras.${index}.value`}
@@ -132,6 +141,7 @@ export const StartServiceModal: React.FC<IModalProps> = ({ dialogRef }) => {
132141
)}
133142
/>
134143
)}
144+
*/}
135145

136146
<div className="text-right">
137147
<button type="button" className="btn btn-sm btn-error" onClick={() => remove(index)}>

src/client/views/Overview.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,9 @@ export const Overview: React.FC = () => {
167167
</div>
168168
</div>
169169
{/* Actions */}
170-
<div className="collapse collapse-arrow bg-base-300 border border-base-300">
171-
<input type="checkbox" name="actions-accordion" className="peer" />
172-
<div className="collapse-title font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">Actions</div>
173-
<div className="collapse-content text-sm flex flex-col items-center justify-between gap-4">
170+
<div className="card bg-base-300 border border-base-300">
171+
<div className="card-body p-4">
172+
<div className="font-semibold text-lg peer-hover:bg-gray-600 peer-checked:mb-4">Actions</div>
174173
<div className="flex w-full justify-between items-center">
175174
<p>
176175
Restart <b>App</b>
@@ -235,7 +234,9 @@ export const Overview: React.FC = () => {
235234
{isPowerMenuEnabled && (
236235
<div className="collapse collapse-arrow bg-base-300 border border-base-300">
237236
<input type="checkbox" name="power-accordion" className="peer" />
238-
<div className="collapse-title font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">Power Menu</div>
237+
<div className="collapse-title text-lg font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">
238+
Power Menu
239+
</div>
239240
<div className="collapse-content text-sm flex items-center justify-between">
240241
<p>Power options let you shutdown or reboot the device.</p>
241242
<div className="flex gap-2">
@@ -257,7 +258,9 @@ export const Overview: React.FC = () => {
257258
{featuresConfig.bugReportEnabled && (
258259
<div className="collapse collapse-arrow bg-base-300 border border-base-300">
259260
<input type="checkbox" name="bug-report-accordion" className="peer" />
260-
<div className="collapse-title font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">Bug Report</div>
261+
<div className="collapse-title text-lg font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">
262+
Bug Report
263+
</div>
261264
<div className="collapse-content text-sm flex items-center justify-between">
262265
<span>
263266
Run the <pre className="inline">bugreportz</pre> tool and get the output file
@@ -280,7 +283,7 @@ export const Overview: React.FC = () => {
280283
{/* README */}
281284
<div className="collapse collapse-arrow bg-base-300 border border-base-300">
282285
<input type="checkbox" name="readme-accordion" className="peer" />
283-
<div className="collapse-title font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">README</div>
286+
<div className="collapse-title text-lg font-semibold peer-hover:bg-gray-600 peer-checked:mb-4">README</div>
284287
<div className="collapse-content text-sm leading-[1.5]">
285288
<h3 className="text-base font-semibold my-2">What is DroidGround?</h3>
286289
<p>

src/server/api/controller.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ReadableStream } from "@yume-chan/stream-extra";
1010
import Logger from "@shared/logger";
1111
import { ManagerSingleton } from "@server/manager";
1212
import {
13+
ActionResponse,
1314
BugreportzStatusResponse,
1415
CompanionPackageInfos,
1516
DeviceInfoResponse,
@@ -53,7 +54,7 @@ class APIController {
5354
Logger.info(`Received ${req.method} request on ${req.path}`);
5455
try {
5556
const singleton = ManagerSingleton.getInstance();
56-
const resetDone = singleton.resetCtf();
57+
const resetDone = await singleton.resetCtf();
5758
if (!resetDone) {
5859
res.status(500).json({ error: "An error occurred while resetting the CTF" }).end();
5960
return;
@@ -119,7 +120,7 @@ class APIController {
119120
}
120121
};
121122

122-
startActivity: RequestHandler = async (req: Request, res: Response<IGenericResultRes | IGenericErrRes>) => {
123+
startActivity: RequestHandler = async (req: Request, res: Response<ActionResponse | IGenericErrRes>) => {
123124
Logger.info(`Received ${req.method} request on ${req.path}`);
124125
try {
125126
const body = req.body as StartActivityRequest;
@@ -186,14 +187,14 @@ class APIController {
186187
Logger.debug(`Running command: "${command}"`);
187188
const adb = await ManagerSingleton.getInstance().getAdb();
188189
const result = await adb.subprocess.noneProtocol.spawnWaitText(command);
189-
res.json({ result: result }).end();
190+
res.json({ command, result }).end();
190191
} catch (error: any) {
191192
Logger.error(`Error starting activity: ${error}`);
192193
res.status(500).json({ error: "An error occurred while starting the activity." }).end();
193194
}
194195
};
195196

196-
startBroadcast: RequestHandler = async (req: Request, res: Response<IGenericResultRes | IGenericErrRes>) => {
197+
startBroadcast: RequestHandler = async (req: Request, res: Response<ActionResponse | IGenericErrRes>) => {
197198
Logger.info(`Received ${req.method} request on ${req.path}`);
198199
try {
199200
const body = req.body as StartBroadcastRequest;
@@ -237,14 +238,14 @@ class APIController {
237238
Logger.debug(`Running command: "${command}"`);
238239
const adb = await ManagerSingleton.getInstance().getAdb();
239240
const result = await adb.subprocess.noneProtocol.spawnWaitText(command);
240-
res.json({ result: result }).end();
241+
res.json({ command, result }).end();
241242
} catch (error: any) {
242243
Logger.error(`Error starting broadcast: ${error}`);
243244
res.status(500).json({ error: "An error occurred while starting the broadcast." }).end();
244245
}
245246
};
246247

247-
startService: RequestHandler = async (req: Request, res: Response<IGenericResultRes | IGenericErrRes>) => {
248+
startService: RequestHandler = async (req: Request, res: Response<ActionResponse | IGenericErrRes>) => {
248249
Logger.info(`Received ${req.method} request on ${req.path}`);
249250
try {
250251
const body = req.body as StartServiceRequest;
@@ -288,7 +289,7 @@ class APIController {
288289
Logger.debug(`Running command: "${command}"`);
289290
const adb = await ManagerSingleton.getInstance().getAdb();
290291
const result = await adb.subprocess.noneProtocol.spawnWaitText(command);
291-
res.json({ result: result }).end();
292+
res.json({ command, result }).end();
292293
} catch (error: any) {
293294
Logger.error(`Error starting service: ${error}`);
294295
res.status(500).json({ error: "An error occurred while starting the service." }).end();
@@ -531,6 +532,11 @@ class APIController {
531532
const duration = config.features.exploitAppDuration;
532533

533534
const { packageName: exploitApp } = body;
535+
536+
if (singleton.deviceApps.includes(exploitApp)) {
537+
throw new Error("This is not an exploit app!");
538+
}
539+
534540
await singleton.runAppByPackageName(exploitApp);
535541

536542
res.json({ result: `Exploit app correctly for ${duration} seconds` }).end();

src/server/api/middlewares.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ export const validateBody = <T>(schema: JSONSchemaType<T>) => {
1717
res.status(400).json({ message: "The body cannot be empty." }).end();
1818
return;
1919
}
20+
2021
const isValid = ajv.validate(schema, req.body);
22+
2123
isValid ? next() : res.status(400).json({ message: "Invalid body" }).end();
2224
};
2325
};

0 commit comments

Comments
 (0)