1 | package com.jsql.model.injection.method; | |
2 | ||
3 | import com.jsql.model.InjectionModel; | |
4 | import com.jsql.model.exception.JSqlException; | |
5 | import com.jsql.model.exception.StoppedByUserSlidingException; | |
6 | import com.jsql.util.JsonUtil; | |
7 | import com.jsql.util.LogLevelUtil; | |
8 | import org.apache.commons.lang3.StringUtils; | |
9 | import org.apache.logging.log4j.LogManager; | |
10 | import org.apache.logging.log4j.Logger; | |
11 | import org.json.JSONException; | |
12 | ||
13 | import java.io.Serializable; | |
14 | import java.util.AbstractMap.SimpleEntry; | |
15 | import java.util.List; | |
16 | import java.util.regex.Pattern; | |
17 | ||
18 | public abstract class AbstractMethodInjection implements Serializable { | |
19 | | |
20 | /** | |
21 | * Log4j logger sent to view. | |
22 | */ | |
23 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
24 | | |
25 | protected final InjectionModel injectionModel; | |
26 | | |
27 | protected AbstractMethodInjection(InjectionModel injectionModel) { | |
28 | this.injectionModel = injectionModel; | |
29 | } | |
30 | | |
31 | public abstract boolean isCheckingAllParam(); | |
32 | public abstract String getParamsAsString(); | |
33 | public abstract List<SimpleEntry<String, String>> getParams(); | |
34 | public abstract String name(); | |
35 | | |
36 | public boolean testParameters(boolean hasFoundInjection) throws JSqlException { | |
37 | ||
38 |
1
1. testParameters : negated conditional → NO_COVERAGE |
if (!hasFoundInjection) { |
39 | ||
40 | LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking {} params...", () -> name().toLowerCase()); | |
41 |
2
1. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE 2. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return this.testParameters(); |
42 | } | |
43 | ||
44 |
1
1. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return true; |
45 | } | |
46 | ||
47 | /** | |
48 | * Verify if injection works for specific Method using 3 modes: standard (last param), injection point | |
49 | * and full params injection. Special injections like JSON and SOAP are checked. | |
50 | * @return true if injection didn't fail | |
51 | * @throws JSqlException when no params' integrity, process stopped by user, or injection failure | |
52 | */ | |
53 | public boolean testParameters() throws JSqlException { | |
54 | ||
55 | var hasFoundInjection = false; | |
56 | | |
57 | // Injects URL, Request or Header params only if user tests every params | |
58 | // or method is selected by user. | |
59 | if ( | |
60 |
1
1. testParameters : negated conditional → NO_COVERAGE |
!this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllParam() |
61 |
1
1. testParameters : negated conditional → NO_COVERAGE |
&& this.injectionModel.getMediatorUtils().getConnectionUtil().getMethodInjection() != this |
62 | ) { | |
63 |
1
1. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return false; |
64 | } | |
65 | | |
66 | // Force injection method of model to current running method | |
67 |
1
1. testParameters : removed call to com/jsql/util/ConnectionUtil::setMethodInjection → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getConnectionUtil().setMethodInjection(this); |
68 | | |
69 | // Injection by injection point in params or in path | |
70 | if ( | |
71 |
1
1. testParameters : negated conditional → NO_COVERAGE |
this.getParamsAsString().contains(InjectionModel.STAR) |
72 |
1
1. testParameters : negated conditional → NO_COVERAGE |
|| this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlBase().contains(InjectionModel.STAR) |
73 | ) { | |
74 | hasFoundInjection = this.checkParamWithStar(); | |
75 |
1
1. testParameters : negated conditional → NO_COVERAGE |
} else if (!this.isCheckingAllParam()) { |
76 | hasFoundInjection = this.checkLastParam(); | |
77 | } else { | |
78 | hasFoundInjection = this.checkAllParams(); | |
79 | } | |
80 | | |
81 |
2
1. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE 2. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return hasFoundInjection; |
82 | } | |
83 | ||
84 | private boolean checkParamWithStar() throws JSqlException { | |
85 | | |
86 | SimpleEntry<String, String> parameterToInject = this.getParams().stream() | |
87 |
2
1. lambda$checkParamWithStar$1 : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkParamWithStar$1 → NO_COVERAGE 2. lambda$checkParamWithStar$1 : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkParamWithStar$1 → NO_COVERAGE |
.filter(entry -> entry.getValue().contains("*")) |
88 | .findFirst() | |
89 | .orElse(null); | |
90 | ||
91 |
2
1. checkParamWithStar : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkParamWithStar → NO_COVERAGE 2. checkParamWithStar : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkParamWithStar → NO_COVERAGE |
return this.injectionModel.getMediatorStrategy().testStrategies(parameterToInject); |
92 | } | |
93 | ||
94 | /** | |
95 | * Default injection: last param tested only | |
96 | */ | |
97 | private boolean checkLastParam() throws JSqlException { | |
98 | | |
99 | // Will check param value by user. | |
100 | // Notice options 'Inject each URL params' and 'inject JSON' must be checked both | |
101 | // for JSON injection of last param | |
102 | SimpleEntry<String, String> parameterToInject = this.getParams().stream() | |
103 |
1
1. lambda$checkLastParam$2 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkLastParam$2 → NO_COVERAGE |
.reduce((a, b) -> b) |
104 | .orElseThrow(NullPointerException::new); | |
105 | ||
106 |
2
1. checkLastParam : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkLastParam → NO_COVERAGE 2. checkLastParam : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkLastParam → NO_COVERAGE |
return this.injectionModel.getMediatorStrategy().testStrategies(parameterToInject); |
107 | } | |
108 | ||
109 | /** | |
110 | * Injection of every params: isCheckingAllParam() == true. | |
111 | * Params are tested one by one in two loops: | |
112 | * - inner loop erases * from previous param | |
113 | * - outer loop adds * to current param | |
114 | * @throws StoppedByUserSlidingException | |
115 | */ | |
116 | private boolean checkAllParams() throws StoppedByUserSlidingException { | |
117 | | |
118 | // This param will be marked by * if injection is found, | |
119 | // inner loop will erase mark * otherwise | |
120 | for (SimpleEntry<String, String> paramBase: this.getParams()) { | |
121 | // This param is the current tested one. | |
122 | // For JSON value attributes are traversed one by one to test every values. | |
123 | // For standard value mark * is simply added to the end of its value. | |
124 | for (SimpleEntry<String, String> paramStar: this.getParams()) { | |
125 |
1
1. checkAllParams : negated conditional → NO_COVERAGE |
if (paramStar == paramBase) { |
126 | try { | |
127 |
1
1. checkAllParams : negated conditional → NO_COVERAGE |
if (this.isParamInjectable(paramStar)) { |
128 |
1
1. checkAllParams : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE |
return true; |
129 | } | |
130 | } catch (JSONException e) { | |
131 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
132 | } | |
133 | } | |
134 | } | |
135 | } | |
136 | | |
137 |
1
1. checkAllParams : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE |
return false; |
138 | } | |
139 | ||
140 | private boolean isParamInjectable(SimpleEntry<String, String> paramStar) throws StoppedByUserSlidingException { | |
141 | | |
142 | boolean hasFoundInjection; | |
143 | | |
144 | // Will test if current value is a JSON entity | |
145 | Object jsonEntity = JsonUtil.getJson(paramStar.getValue()); | |
146 | | |
147 | // Define a tree of JSON attributes with path as the key: root.a => value of a | |
148 | List<SimpleEntry<String, String>> attributesJson = JsonUtil.createEntries(jsonEntity, "root", null); | |
149 | | |
150 | // When option 'Inject JSON' is selected and there's a JSON entity to inject | |
151 | // then loop through each paths to add * at the end of value and test each strategies. | |
152 | // Marks * are erased between each tests. | |
153 |
2
1. isParamInjectable : negated conditional → NO_COVERAGE 2. isParamInjectable : negated conditional → NO_COVERAGE |
if (!attributesJson.isEmpty() && this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllJsonParam()) { |
154 | hasFoundInjection = this.injectionModel.getMediatorUtils().getJsonUtil().testJsonParam(this, paramStar); | |
155 | } else { | |
156 | hasFoundInjection = this.testJsonlessParam(paramStar); // Standard non JSON injection | |
157 | } | |
158 | | |
159 |
2
1. isParamInjectable : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE 2. isParamInjectable : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE |
return hasFoundInjection; |
160 | } | |
161 | | |
162 | public boolean testJsonlessParam(SimpleEntry<String, String> paramStar) throws StoppedByUserSlidingException { | |
163 | ||
164 | var hasFoundInjection = false; | |
165 | ||
166 | paramStar.setValue(paramStar.getValue() + InjectionModel.STAR); | |
167 | | |
168 | try { | |
169 | LOGGER.log( | |
170 | LogLevelUtil.CONSOLE_INFORM, | |
171 | "Checking {} parameter {}={}", | |
172 | this::name, | |
173 | paramStar::getKey, | |
174 |
1
1. lambda$testJsonlessParam$3 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$3 → NO_COVERAGE |
() -> paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY) |
175 | ); | |
176 | | |
177 | // Test current standard value marked with * for injection | |
178 | // Keep original param | |
179 | hasFoundInjection = this.injectionModel.getMediatorStrategy().testStrategies(paramStar); | |
180 | | |
181 | } catch (StoppedByUserSlidingException e) { // Break all params processing in upper methods | |
182 | throw e; | |
183 | } catch (JSqlException e) { // Injection failure | |
184 | LOGGER.log( | |
185 | LogLevelUtil.CONSOLE_ERROR, | |
186 | "No {} injection found for parameter {}={} ({})", | |
187 | this.name(), | |
188 | paramStar.getKey(), | |
189 | paramStar.getValue().replaceAll("\\+.?$|\\" + InjectionModel.STAR, StringUtils.EMPTY), | |
190 | e.getMessage() | |
191 | ); | |
192 | } finally { | |
193 |
1
1. testJsonlessParam : negated conditional → NO_COVERAGE |
if (!hasFoundInjection) { // Erase * from JSON if failure |
194 | | |
195 | // Erase * at the end of each params | |
196 |
1
1. testJsonlessParam : removed call to java/util/List::forEach → NO_COVERAGE |
this.getParams().forEach(e -> |
197 | e.setValue( | |
198 | e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY) | |
199 | ) | |
200 | ); | |
201 | | |
202 | // TODO It erases STAR from value => * can't be used in parameter | |
203 | paramStar.setValue(paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)); | |
204 | } | |
205 | } | |
206 | | |
207 |
2
1. testJsonlessParam : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testJsonlessParam → NO_COVERAGE 2. testJsonlessParam : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testJsonlessParam → NO_COVERAGE |
return hasFoundInjection; |
208 | } | |
209 | } | |
Mutations | ||
38 |
1.1 |
|
41 |
1.1 2.2 |
|
44 |
1.1 |
|
60 |
1.1 |
|
61 |
1.1 |
|
63 |
1.1 |
|
67 |
1.1 |
|
71 |
1.1 |
|
72 |
1.1 |
|
75 |
1.1 |
|
81 |
1.1 2.2 |
|
87 |
1.1 2.2 |
|
91 |
1.1 2.2 |
|
103 |
1.1 |
|
106 |
1.1 2.2 |
|
125 |
1.1 |
|
127 |
1.1 |
|
128 |
1.1 |
|
137 |
1.1 |
|
153 |
1.1 2.2 |
|
159 |
1.1 2.2 |
|
174 |
1.1 |
|
193 |
1.1 |
|
196 |
1.1 |
|
207 |
1.1 2.2 |