Skip to content

Commit 7ac9b23

Browse files
authored
Merge pull request #194 from psiinon/autodownload
Auto-download the script if stopped from the notification panel.
2 parents 03b8cf5 + d801c17 commit 7ac9b23

File tree

7 files changed

+108
-9
lines changed

7 files changed

+108
-9
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88
### Added
99
- Help screen
1010

11+
### Changed
12+
- Auto-download the script if stopped from the notification panel.
13+
1114
## 0.0.15 - 2025-05-28
1215

1316
### Added

CHANGELOG.rec.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88
### Added
99
- Help screen
1010

11+
### Changed
12+
- Auto-download the script if stopped from the notification panel.
13+
1114
## 0.0.3 - 2025-05-28
1215

1316
### Added

source/Background/index.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ import {ReportedStorage} from '../types/ReportedModel';
2323
import {ZestScript, ZestScriptMessage} from '../types/zestScript/ZestScript';
2424
import {ZestStatementWindowClose} from '../types/zestScript/ZestStatement';
2525
import {
26+
DOWNLOAD_RECORDING,
27+
GET_ZEST_SCRIPT,
2628
IS_FULL_EXTENSION,
2729
LOCAL_STORAGE,
2830
REPORT_EVENT,
2931
REPORT_OBJECT,
3032
RESET_ZEST_SCRIPT,
31-
SAVE_ZEST_SCRIPT,
3233
SESSION_STORAGE,
3334
SET_SAVE_SCRIPT_ENABLE,
3435
STOP_RECORDING,
@@ -172,6 +173,33 @@ function sendZestScriptToZAP(
172173
}
173174
}
174175

176+
function downloadZestScript(zestScriptJSON: string, title: string): void {
177+
const blob = new Blob([zestScriptJSON], {type: 'application/json'});
178+
const url = URL.createObjectURL(blob);
179+
180+
const link = document.createElement('a');
181+
link.href = url;
182+
link.download = title + (title.slice(-4) === '.zst' ? '' : '.zst');
183+
link.style.display = 'none';
184+
185+
document.body.appendChild(link);
186+
link.click();
187+
document.body.removeChild(link);
188+
189+
URL.revokeObjectURL(url);
190+
}
191+
192+
function pad(i: number): string {
193+
return `${i}`.padStart(2, `0`);
194+
}
195+
196+
function getDateString(): string {
197+
const now = new Date();
198+
return `${now.getFullYear()}-${pad(now.getMonth())}-${pad(
199+
now.getDay()
200+
)}-${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
201+
}
202+
175203
async function handleMessage(
176204
request: MessageEvent,
177205
zapurl: string,
@@ -229,7 +257,7 @@ async function handleMessage(
229257
break;
230258
}
231259

232-
case SAVE_ZEST_SCRIPT:
260+
case GET_ZEST_SCRIPT:
233261
return zestScript.getZestScript();
234262

235263
case RESET_ZEST_SCRIPT:
@@ -249,7 +277,17 @@ async function handleMessage(
249277
}
250278
break;
251279
}
252-
280+
case DOWNLOAD_RECORDING: {
281+
zestScript.getZestScript().then((items) => {
282+
const msg = items as ZestScriptMessage;
283+
let site = '';
284+
if (request.data) {
285+
site = `${request.data}-`;
286+
}
287+
downloadZestScript(msg.script, `zap-rec-${site}${getDateString()}.zst`);
288+
});
289+
break;
290+
}
253291
case SET_SAVE_SCRIPT_ENABLE:
254292
Browser.storage.sync.set({
255293
zapenablesavescript: zestScript.getZestStatementCount() > 0,

source/ContentScript/recorder.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ import {
3030
ZestStatementSwitchToFrame,
3131
} from '../types/zestScript/ZestStatement';
3232
import {getPath} from './util';
33-
import {STOP_RECORDING, ZEST_SCRIPT} from '../utils/constants';
33+
import {
34+
DOWNLOAD_RECORDING,
35+
STOP_RECORDING,
36+
ZEST_SCRIPT,
37+
} from '../utils/constants';
38+
39+
const STOP_RECORDING_ID = 'ZAP-stop-recording-button';
40+
const STOP_RECORDING_TEXT = 'Stop and Download Recording';
3441

3542
class Recorder {
3643
readonly timeAdjustmentMillis: number = 3000;
@@ -344,7 +351,16 @@ class Recorder {
344351
}
345352

346353
initializationScript(loginUrl = ''): void {
347-
Browser.storage.sync.set({initScript: false, loginUrl: ''});
354+
Browser.storage.sync.set({
355+
initScript: false,
356+
loginUrl: '',
357+
downloadScript: true,
358+
});
359+
const stopRecordingButton = document.getElementById(STOP_RECORDING_ID);
360+
if (stopRecordingButton) {
361+
// Can happen if recording restarted in browser launched from ZAP recorder
362+
stopRecordingButton.textContent = STOP_RECORDING_TEXT;
363+
}
348364

349365
this.sendZestScriptToZAP(
350366
new ZestStatementComment(
@@ -445,6 +461,7 @@ class Recorder {
445461
textElement.textContent = 'ZAP Browser Extension is Recording...';
446462

447463
const buttonElement = document.createElement('button');
464+
buttonElement.id = STOP_RECORDING_ID;
448465
buttonElement.style.all = 'initial';
449466
buttonElement.className = 'ZapfloatingDivElements';
450467
buttonElement.style.marginTop = '10px';
@@ -457,10 +474,32 @@ class Recorder {
457474
buttonElement.style.cursor = 'pointer';
458475
buttonElement.style.fontFamily = 'Roboto';
459476
buttonElement.textContent = 'Stop Recording';
477+
Browser.storage.sync
478+
.get({
479+
downloadScript: false,
480+
})
481+
.then((items) => {
482+
if (items.downloadScript) {
483+
buttonElement.textContent = STOP_RECORDING_TEXT;
484+
}
485+
});
460486

461487
buttonElement.addEventListener('click', () => {
462488
this.stopRecordingUserInteractions();
463489
Browser.runtime.sendMessage({type: STOP_RECORDING});
490+
Browser.storage.sync
491+
.get({
492+
downloadScript: false,
493+
})
494+
.then((items) => {
495+
if (items.downloadScript) {
496+
Browser.runtime.sendMessage({
497+
type: DOWNLOAD_RECORDING,
498+
data: window.location.hostname,
499+
});
500+
Browser.storage.sync.set({downloadScript: false});
501+
}
502+
});
464503
});
465504

466505
floatingDiv.appendChild(textElement);

source/Popup/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import './styles.scss';
2222
import i18n from './i18n';
2323

2424
import {
25+
GET_ZEST_SCRIPT,
2526
IS_FULL_EXTENSION,
2627
RESET_ZEST_SCRIPT,
27-
SAVE_ZEST_SCRIPT,
2828
SET_SAVE_SCRIPT_ENABLE,
2929
STOP_RECORDING,
3030
UPDATE_TITLE,
@@ -220,7 +220,7 @@ async function handleSaveScript(): Promise<void> {
220220
if (storageItems.zaprecordingactive) {
221221
await Browser.runtime.sendMessage({type: STOP_RECORDING});
222222
}
223-
Browser.runtime.sendMessage({type: SAVE_ZEST_SCRIPT}).then((items) => {
223+
Browser.runtime.sendMessage({type: GET_ZEST_SCRIPT}).then((items) => {
224224
const msg = items as ZestScriptMessage;
225225
downloadZestScript(msg.script, msg.title);
226226
});

source/utils/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ export const ZAP_START_RECORDING = 'zapStartRecording';
4141
export const SET_SAVE_SCRIPT_ENABLE = 'setSaveScriptEnable';
4242
export const ZEST_SCRIPT = 'zestScript';
4343

44+
export const DOWNLOAD_RECORDING = 'downloadRecording';
4445
export const STOP_RECORDING = 'stopRecording';
4546
export const RESET_ZEST_SCRIPT = 'resetZestScript';
46-
export const SAVE_ZEST_SCRIPT = 'saveZestScript';
47+
export const GET_ZEST_SCRIPT = 'getZestScript';
4748
export const UPDATE_TITLE = 'updateTitle';
4849

4950
export const REPORT_EVENT = 'reportEvent';

views/help.html

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ <h2>Summary</h2>
1313
This extension allows you to record all of the actions you take in the browser as a Zest script.
1414
It can be used to record things like authentication scripts or other complex interactions.
1515
Zest scripts can be replayed in ZAP, whether in the desktop or in automation.
16+
<p>
17+
When the extension is recording then a notification panel will be shown at the bottom of the page.
18+
Clicking on the "Stop and Download Recording" button will stop the recording and automatically download the
19+
recording using a filename based on the hostname of the current page and the current date / time.
20+
<p>
21+
You can also stop the recording via the extension dialog and then download the recording using a filename you specify.
22+
<p>
23+
If you are using the full ZAP extension and start recording in ZAP then the Zest script will be automatically updated in
24+
the ZAP Script Console so you do not need to download it manually.
1625

1726
<h2>Recorder Advice and Guidance</h2>
1827
If you are going to use the recorded script for authentication then you need to make sure that the browser
@@ -27,6 +36,9 @@ <h2>Recorder Advice and Guidance</h2>
2736
<p>
2837
It is often better to use private/incognito mode when recording so that the browser will not have any existing
2938
application state.
39+
<p>
40+
The 'buttons' on some modern web apps can be complicated HTML components that are sometimes hard to click on using automation.
41+
If your forms can be submitted using the RETURN key then that is often a better option to use when recording.
3042

3143
<h2>Recorder Dialog</h2>
3244
Clicking on the ZAP Extension icon will display the Recorder Dialog.<br>
@@ -45,7 +57,10 @@ <h3>Login URL Field</h3>
4557
the URL you have given and open it in a new tab.
4658

4759
<h3>Script Name Field</h3>
48-
The name of the script that the recorder will download.
60+
The name of the script that the recorder will download from this dialog.
61+
<p>
62+
If you stop recording via the "Stop and Download Recording" button in the notification panel then the extension will
63+
automatically download the recording using an auto-generated filename.
4964

5065
<h3>Download Script Button</h3>
5166
Clicking on this button will download any recorded script using the name in the above field.

0 commit comments

Comments
 (0)