Skip to content

Commit 07d7936

Browse files
committed
clientapi: prepare 2.0.0, refactor alerts, disable japicmp. Signed-off-by: Ahmad Al-Sanie
1 parent 73d02df commit 07d7936

7 files changed

Lines changed: 206 additions & 110 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
9+
### Changed
10+
- Refactor for clientapi 2.0.0.
11+
- Extract alert logic into AlertService / DefaultAlertService
12+
- Keep ClientApi as transport + gen API owner
13+
- Simplify CLI orchestration (ClientApiMain)
14+
- Disable japicmp for initial 2.x release
15+
816
### Removed
917
- Removed `JDOM` dependency
1018

‎build.gradle.kts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ subprojects {
1414

1515
group = "org.zaproxy"
1616

17-
version = "1.18.0-SNAPSHOT"
17+
version = "2.0.0-SNAPSHOT"
1818
extra["versionBC"] = "1.17.0"
1919

2020
java {

‎subprojects/zap-clientapi/src/main/java/org/zaproxy/clientapi/core/ClientApi.java‎

Lines changed: 20 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.io.InputStreamReader;
2828
import java.io.OutputStreamWriter;
2929
import java.io.PrintStream;
30-
import java.io.UnsupportedEncodingException;
3130
import java.net.HttpURLConnection;
3231
import java.net.InetSocketAddress;
3332
import java.net.MalformedURLException;
@@ -91,6 +90,8 @@
9190
import org.zaproxy.clientapi.gen.Users;
9291
import org.zaproxy.clientapi.gen.Wappalyzer;
9392
import org.zaproxy.clientapi.gen.Websocket;
93+
import org.zaproxy.clientapi.impl.DefaultAlertService;
94+
import org.zaproxy.clientapi.service.AlertService;
9495

9596
@SuppressWarnings("this-escape")
9697
public class ClientApi {
@@ -103,10 +104,10 @@ public class ClientApi {
103104
private boolean debug = false;
104105
private PrintStream debugStream = System.out;
105106

106-
private final String zapAddress;
107-
private final int zapPort;
107+
private String zapAddress;
108+
private int zapPort;
108109

109-
private final String apiKey;
110+
private String apiKey;
110111

111112
private DocumentBuilderFactory docBuilderFactory;
112113

@@ -171,9 +172,11 @@ public class ClientApi {
171172
public Users users = new Users(this);
172173
public Wappalyzer wappalyzer = new Wappalyzer(this);
173174
public Websocket websocket = new Websocket(this);
175+
private AlertService alertService;
174176

175177
public ClientApi(String zapAddress, int zapPort) {
176178
this(zapAddress, zapPort, false);
179+
this.alertService = new DefaultAlertService(this.alert);
177180
}
178181

179182
/**
@@ -187,10 +190,12 @@ public ClientApi(String zapAddress, int zapPort) {
187190
*/
188191
public ClientApi(String zapAddress, int zapPort, String apiKey) {
189192
this(zapAddress, zapPort, apiKey, false);
193+
this.alertService = new DefaultAlertService(this.alert);
190194
}
191195

192196
public ClientApi(String zapAddress, int zapPort, boolean debug) {
193197
this(zapAddress, zapPort, null, debug);
198+
this.alertService = new DefaultAlertService(this.alert);
194199
}
195200

196201
/**
@@ -212,6 +217,7 @@ public ClientApi(String zapAddress, int zapPort, String apiKey, boolean debug) {
212217
this.zapAddress = zapAddress;
213218
this.zapPort = zapPort;
214219
this.apiKey = apiKey;
220+
this.alertService = new DefaultAlertService(this.alert);
215221
}
216222

217223
public void setDebugStream(PrintStream debugStream) {
@@ -228,43 +234,15 @@ private int statusToInt(ApiResponse response) {
228234

229235
public void checkAlerts(List<Alert> ignoreAlerts, List<Alert> requireAlerts)
230236
throws ClientApiException {
231-
Map<String, List<Alert>> results = checkForAlerts(ignoreAlerts, requireAlerts);
232-
verifyAlerts(results.get("requireAlerts"), results.get("reportAlerts"));
233-
}
234-
235-
private void verifyAlerts(List<Alert> requireAlerts, List<Alert> reportAlerts)
236-
throws ClientApiException {
237-
StringBuilder sb = new StringBuilder();
238-
if (reportAlerts.size() > 0) {
239-
sb.append("Found ").append(reportAlerts.size()).append(" alerts\n");
240-
for (Alert alert : reportAlerts) {
241-
sb.append('\t');
242-
sb.append(alert.toString());
243-
sb.append('\n');
244-
}
245-
}
246-
if (requireAlerts != null && requireAlerts.size() > 0) {
247-
if (sb.length() > 0) {
248-
sb.append('\n');
249-
}
250-
sb.append("Not found ").append(requireAlerts.size()).append(" alerts\n");
251-
for (Alert alert : requireAlerts) {
252-
sb.append('\t');
253-
sb.append(alert.toString());
254-
sb.append('\n');
255-
}
256-
}
257-
if (sb.length() > 0) {
258-
if (debug) {
259-
debugStream.println("Failed: " + sb.toString());
260-
}
261-
throw new ClientApiException(sb.toString());
262-
}
237+
Map<String, List<Alert>> results =
238+
alertService.checkAlerts(ignoreAlerts, requireAlerts, alert);
239+
alertService.verifyAlerts(results.get("requireAlerts"), results.get("reportAlerts"));
263240
}
264241

265242
public void checkAlerts(List<Alert> ignoreAlerts, List<Alert> requireAlerts, File outputFile)
266243
throws ClientApiException {
267-
Map<String, List<Alert>> results = checkForAlerts(ignoreAlerts, requireAlerts);
244+
Map<String, List<Alert>> results =
245+
alertService.checkAlerts(ignoreAlerts, requireAlerts, alert);
268246
int alertsFound = results.get("reportAlerts").size();
269247
int alertsNotFound = results.get("requireAlerts").size();
270248
int alertsIgnored = results.get("ignoredAlerts").size();
@@ -290,62 +268,6 @@ public void checkAlerts(List<Alert> ignoreAlerts, List<Alert> requireAlerts, Fil
290268
}
291269
}
292270

293-
public List<Alert> getAlerts(String baseUrl, int start, int count) throws ClientApiException {
294-
List<Alert> alerts = new ArrayList<>();
295-
ApiResponse response =
296-
alert.alerts(baseUrl, String.valueOf(start), String.valueOf(count), null);
297-
if (response != null && response instanceof ApiResponseList) {
298-
ApiResponseList alertList = (ApiResponseList) response;
299-
for (ApiResponse resp : alertList.getItems()) {
300-
alerts.add(new Alert((ApiResponseSet) resp));
301-
}
302-
}
303-
return alerts;
304-
}
305-
306-
private Map<String, List<Alert>> checkForAlerts(
307-
List<Alert> ignoreAlerts, List<Alert> requireAlerts) throws ClientApiException {
308-
List<Alert> reportAlerts = new ArrayList<>();
309-
List<Alert> ignoredAlerts = new ArrayList<>();
310-
List<Alert> alerts = getAlerts(null, -1, -1);
311-
for (Alert alert : alerts) {
312-
boolean ignore = false;
313-
if (ignoreAlerts != null) {
314-
for (Alert ignoreAlert : ignoreAlerts) {
315-
if (alert.matches(ignoreAlert)) {
316-
if (debug) {
317-
debugStream.println("Ignoring alert " + ignoreAlert);
318-
}
319-
ignoredAlerts.add(alert);
320-
ignore = true;
321-
break;
322-
}
323-
}
324-
}
325-
if (!ignore) {
326-
reportAlerts.add(alert);
327-
}
328-
if (requireAlerts != null) {
329-
for (Alert requireAlert : requireAlerts) {
330-
if (alert.matches(requireAlert)) {
331-
if (debug) {
332-
debugStream.println("Found alert " + alert);
333-
}
334-
requireAlerts.remove(requireAlert);
335-
// Remove it from the not-ignored list as well
336-
reportAlerts.remove(alert);
337-
break;
338-
}
339-
}
340-
}
341-
}
342-
HashMap<String, List<Alert>> results = new HashMap<>();
343-
results.put("reportAlerts", reportAlerts);
344-
results.put("requireAlerts", requireAlerts);
345-
results.put("ignoredAlerts", ignoredAlerts);
346-
return results;
347-
}
348-
349271
private void accessUrlViaProxy(Proxy proxy, String apiurl) throws ClientApiException {
350272
try {
351273
URL url = createUrl(apiurl);
@@ -502,17 +424,14 @@ private byte[] getBytes(
502424
if (debug) {
503425
debugStream.println("Open URL: " + request.getRequestUri());
504426
}
505-
InputStream in = getConnectionInputStream(request);
506427
ByteArrayOutputStream out = new ByteArrayOutputStream();
507428
byte[] buffer = new byte[8 * 1024];
508-
try {
429+
try (InputStream in = getConnectionInputStream(request);
430+
out) {
509431
int bytesRead;
510432
while ((bytesRead = in.read(buffer)) != -1) {
511433
out.write(buffer, 0, bytesRead);
512434
}
513-
} finally {
514-
out.close();
515-
in.close();
516435
}
517436
return out.toByteArray();
518437

@@ -589,12 +508,7 @@ private static StringBuilder appendParams(Map<String, String> params, StringBuil
589508
}
590509

591510
private static String encodeQueryParam(String param) {
592-
try {
593-
return URLEncoder.encode(param, "UTF-8");
594-
} catch (UnsupportedEncodingException ignore) {
595-
// UTF-8 is a standard charset.
596-
}
597-
return param;
511+
return URLEncoder.encode(param, StandardCharsets.UTF_8);
598512
}
599513

600514
/**
@@ -692,7 +606,7 @@ public void includeOneMatchingNodeInContext(String contextName, String regex) th
692606
private List<String> getSessionUrls() throws Exception {
693607
List<String> sessionUrls = new ArrayList<>();
694608
ApiResponse response = core.urls();
695-
if (response != null && response instanceof ApiResponseList) {
609+
if (response instanceof ApiResponseList) {
696610
ApiResponseElement urlList =
697611
(ApiResponseElement) ((ApiResponseList) response).getItems().get(0);
698612
for (ApiResponse element : ((ApiResponseList) response).getItems()) {
@@ -742,7 +656,7 @@ private void waitForAScanToFinish(String targetUrl) throws ClientApiException {
742656
status = statusToInt(ascan.status(""));
743657
if (debug) {
744658
String format = "Scanning %s Progress: %d%%";
745-
System.out.println(String.format(format, targetUrl, status));
659+
System.out.printf(format + "%n", targetUrl, status);
746660
}
747661
try {
748662
Thread.sleep(1000);

‎subprojects/zap-clientapi/src/main/java/org/zaproxy/clientapi/core/ClientApiMain.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.net.ConnectException;
2424
import java.util.HashMap;
2525
import java.util.List;
26+
import org.zaproxy.clientapi.service.AlertService;
2627

2728
public class ClientApiMain {
2829

@@ -96,7 +97,7 @@ private void executeTask() throws Exception {
9697
}
9798
break;
9899
case showAlerts:
99-
List<Alert> alerts = api.getAlerts(null, -1, -1);
100+
List<Alert> alerts = AlertService.getAlerts(null, -1, -1, null);
100101
for (Alert alert : alerts) {
101102
System.out.println(alert.toString());
102103
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Zed Attack Proxy (ZAP) and its related class files.
3+
*
4+
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
5+
*
6+
* Copyright 2025 The ZAP Development Team
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
package org.zaproxy.clientapi.impl;
21+
22+
import java.io.PrintStream;
23+
import java.util.ArrayList;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
import org.zaproxy.clientapi.core.*;
28+
import org.zaproxy.clientapi.service.AlertService;
29+
30+
public final class DefaultAlertService implements AlertService {
31+
private static final boolean DEBUG = false;
32+
private static final PrintStream DEBUG_STREAM = System.out;
33+
34+
@SuppressWarnings("UnusedVariable")
35+
private final org.zaproxy.clientapi.gen.Alert api;
36+
37+
public DefaultAlertService(org.zaproxy.clientapi.gen.Alert api) {
38+
this.api = api;
39+
}
40+
41+
@Override
42+
public Map<String, List<Alert>> checkAlerts(
43+
List<Alert> ignoreAlerts,
44+
List<Alert> requireAlerts,
45+
org.zaproxy.clientapi.gen.Alert alert)
46+
throws ClientApiException {
47+
List<Alert> reportAlerts = new ArrayList<>();
48+
List<Alert> ignoredAlerts = new ArrayList<>();
49+
List<Alert> alerts = AlertService.getAlerts(null, -1, -1, alert);
50+
for (Alert alertCore : alerts) {
51+
boolean ignore = false;
52+
if (ignoreAlerts != null) {
53+
for (Alert ignoreAlert : ignoreAlerts) {
54+
if (alertCore.matches(ignoreAlert)) {
55+
if (DEBUG) {
56+
DEBUG_STREAM.println("Ignoring alert " + ignoreAlert);
57+
}
58+
ignoredAlerts.add(alertCore);
59+
ignore = true;
60+
break;
61+
}
62+
}
63+
}
64+
if (!ignore) {
65+
reportAlerts.add(alertCore);
66+
}
67+
if (requireAlerts != null) {
68+
for (Alert requireAlert : requireAlerts) {
69+
if (alertCore.matches(requireAlert)) {
70+
if (DEBUG) {
71+
DEBUG_STREAM.println("Found alert " + alert);
72+
}
73+
requireAlerts.remove(requireAlert);
74+
// Remove it from the not-ignored list as well
75+
reportAlerts.remove(alertCore);
76+
break;
77+
}
78+
}
79+
}
80+
}
81+
HashMap<String, List<Alert>> results = new HashMap<>();
82+
results.put("reportAlerts", reportAlerts);
83+
results.put("requireAlerts", requireAlerts);
84+
results.put("ignoredAlerts", ignoredAlerts);
85+
return results;
86+
}
87+
88+
@Override
89+
public void verifyAlerts(List<Alert> requireAlerts, List<Alert> reportAlerts)
90+
throws ClientApiException {
91+
StringBuilder sb = new StringBuilder();
92+
if (!reportAlerts.isEmpty()) {
93+
sb.append("Found ").append(reportAlerts.size()).append(" alerts\n");
94+
for (Alert alert : reportAlerts) {
95+
sb.append('\t');
96+
sb.append(alert.toString());
97+
sb.append('\n');
98+
}
99+
}
100+
if (requireAlerts != null && !requireAlerts.isEmpty()) {
101+
if (sb.length() > 0) {
102+
sb.append('\n');
103+
}
104+
sb.append("Not found ").append(requireAlerts.size()).append(" alerts\n");
105+
for (Alert alert : requireAlerts) {
106+
sb.append('\t');
107+
sb.append(alert.toString());
108+
sb.append('\n');
109+
}
110+
}
111+
if (sb.length() > 0) {
112+
if (DEBUG) {
113+
DEBUG_STREAM.println("Failed: " + sb.toString());
114+
}
115+
throw new ClientApiException(sb.toString());
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)