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