1 package com.jsql.util;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.model.exception.JSqlException;
5 import com.jsql.model.injection.method.AbstractMethodInjection;
6 import org.apache.commons.lang3.StringUtils;
7 import org.apache.logging.log4j.LogManager;
8 import org.apache.logging.log4j.Logger;
9 import org.json.JSONArray;
10 import org.json.JSONException;
11 import org.json.JSONObject;
12
13 import java.util.AbstractMap.SimpleEntry;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.regex.Pattern;
18
19 public class JsonUtil {
20
21
22
23
24 private static final Logger LOGGER = LogManager.getRootLogger();
25
26 private final InjectionModel injectionModel;
27
28 public JsonUtil(InjectionModel injectionModel) {
29 this.injectionModel = injectionModel;
30 }
31
32 public static boolean isJson(String param) {
33
34 var isJson = false;
35
36 try {
37
38 new JSONObject(param);
39 isJson = true;
40
41 } catch (JSONException exceptionJSONObject) {
42 try {
43
44 new JSONArray(param);
45 isJson = true;
46
47 } catch (JSONException exceptionJSONArray) {
48
49 }
50 }
51
52 return isJson;
53 }
54
55 public static Object getJson(String param) {
56
57 Object jsonEntity;
58
59 try {
60 jsonEntity = new JSONObject(param);
61 } catch (JSONException exceptionJSONObject) {
62 try {
63 jsonEntity = new JSONArray(param);
64 } catch (JSONException exceptionJSONArray) {
65 jsonEntity = new Object();
66 }
67 }
68
69 return jsonEntity;
70 }
71
72 public static List<SimpleEntry<String, String>> createEntries(Object jsonEntity, String parentName, SimpleEntry<String, String> parentXPath) {
73
74 List<SimpleEntry<String, String>> attributesXPath = new ArrayList<>();
75
76 if (jsonEntity instanceof JSONObject) {
77 JsonUtil.scanJsonObject(jsonEntity, parentName, parentXPath, attributesXPath);
78 } else if (jsonEntity instanceof JSONArray) {
79 JsonUtil.scanJsonArray(jsonEntity, parentName, parentXPath, attributesXPath);
80 }
81
82 return attributesXPath;
83 }
84
85 private static void scanJsonArray(Object jsonEntity, String parentName, SimpleEntry<String, String> parentXPath, List<SimpleEntry<String, String>> attributesXPath) {
86
87 var jsonArrayEntity = (JSONArray) jsonEntity;
88
89 for (var i = 0; i < jsonArrayEntity.length(); i++) {
90
91 Object value = jsonArrayEntity.get(i);
92 String xpath = parentName +"["+ i +"]";
93
94
95 if (value instanceof JSONArray || value instanceof JSONObject) {
96 attributesXPath.addAll(JsonUtil.createEntries(value, xpath, parentXPath));
97 } else if (value instanceof String) {
98
99 SimpleEntry<String, String> stringValue = new SimpleEntry<>(xpath, (String) value);
100 attributesXPath.add(stringValue);
101
102 if (parentXPath == null) {
103 jsonArrayEntity.put(i, value.toString().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY));
104 } else if (stringValue.equals(parentXPath)) {
105 jsonArrayEntity.put(i, value + InjectionModel.STAR);
106 }
107 }
108 }
109 }
110
111 private static void scanJsonObject(Object jsonEntity, String parentName, SimpleEntry<String, String> parentXPath, List<SimpleEntry<String, String>> attributesXPath) {
112
113 var jsonObjectEntity = (JSONObject) jsonEntity;
114
115 Iterator<?> keys = jsonObjectEntity.keys();
116
117 while (keys.hasNext()) {
118
119 String key = (String) keys.next();
120 var value = jsonObjectEntity.get(key);
121 String xpath = parentName +"."+ key;
122
123
124 if (value instanceof JSONArray || value instanceof JSONObject) {
125 attributesXPath.addAll(JsonUtil.createEntries(value, xpath, parentXPath));
126 } else if (value instanceof String) {
127
128 SimpleEntry<String, String> stringValue = new SimpleEntry<>(xpath, (String) value);
129 attributesXPath.add(stringValue);
130
131 if (parentXPath == null) {
132 jsonObjectEntity.put(key, value.toString().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY));
133 } else if (stringValue.equals(parentXPath)) {
134 jsonObjectEntity.put(key, value + InjectionModel.STAR);
135 }
136 }
137 }
138 }
139
140 public boolean testJsonParam(AbstractMethodInjection methodInjection, SimpleEntry<String, String> paramStar) {
141
142 var hasFoundInjection = false;
143
144
145 paramStar.setValue(paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY));
146
147
148 Object jsonEntity = JsonUtil.getJson(paramStar.getValue());
149
150
151 List<SimpleEntry<String, String>> attributesJson = JsonUtil.createEntries(jsonEntity, "root", null);
152
153
154 for (SimpleEntry<String, String> parentXPath: attributesJson) {
155
156 JsonUtil.createEntries(jsonEntity, "root", null);
157 JsonUtil.createEntries(jsonEntity, "root", parentXPath);
158
159 paramStar.setValue(jsonEntity.toString());
160
161 try {
162 LOGGER.log(
163 LogLevelUtil.CONSOLE_INFORM,
164 "Checking JSON {} parameter {}={}",
165 methodInjection::name,
166 parentXPath::getKey,
167 () -> parentXPath.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
168 );
169
170
171
172 hasFoundInjection = this.injectionModel.getMediatorStrategy().testStrategies(paramStar);
173
174
175 break;
176
177 } catch (JSqlException e) {
178
179
180 LOGGER.log(
181 LogLevelUtil.CONSOLE_ERROR,
182 String.format(
183 "No injection found for JSON %s parameter %s=%s",
184 methodInjection.name(),
185 parentXPath.getKey(),
186 parentXPath.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
187 )
188 );
189 } finally {
190
191
192
193 methodInjection.getParams()
194 .forEach(e -> e.setValue(
195 e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY)
196 ));
197
198
199 if (!hasFoundInjection) {
200 paramStar.setValue(
201 paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
202 );
203 }
204 }
205 }
206
207 return hasFoundInjection;
208 }
209 }