| 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 | public static final String LOG_CHECKING = "LOG_CHECKING"; | |
| 23 | ||
| 24 | protected final InjectionModel injectionModel; | |
| 25 | | |
| 26 | protected AbstractMethodInjection(InjectionModel injectionModel) { | |
| 27 | this.injectionModel = injectionModel; | |
| 28 | } | |
| 29 | | |
| 30 | public abstract boolean isCheckingAllParam(); | |
| 31 | public abstract String getParamsAsString(); | |
| 32 | public abstract List<SimpleEntry<String, String>> getParams(); | |
| 33 | public abstract String name(); | |
| 34 | | |
| 35 | public boolean testParameters(boolean hasFoundInjection) throws JSqlException { | |
| 36 |
1
1. testParameters : negated conditional → NO_COVERAGE |
if (!hasFoundInjection) { |
| 37 | LOGGER.log( | |
| 38 | LogLevelUtil.CONSOLE_DEFAULT, | |
| 39 | "{} [{}] params...", | |
| 40 |
1
1. lambda$testParameters$0 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testParameters$0 → NO_COVERAGE |
() -> I18nUtil.valueByKey(AbstractMethodInjection.LOG_CHECKING), |
| 41 |
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() |
| 42 | ); | |
| 43 |
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(); |
| 44 | } | |
| 45 |
1
1. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return true; |
| 46 | } | |
| 47 | ||
| 48 | /** | |
| 49 | * Verify if injection works for specific Method using 3 modes: standard (last param), injection point | |
| 50 | * and full params injection. Special injections like JSON and SOAP are checked. | |
| 51 | * @return true if injection didn't fail | |
| 52 | * @throws JSqlException when no params integrity, process stopped by user, or injection failure | |
| 53 | */ | |
| 54 | public boolean testParameters() throws JSqlException { | |
| 55 |
1
1. testParameters : removed call to com/jsql/model/InjectionModel::setAnalysisReport → NO_COVERAGE |
this.injectionModel.setAnalysisReport(StringUtils.EMPTY); // force reset to prevent aggregating report when testing all params |
| 56 | var hasFoundInjection = false; | |
| 57 | ||
| 58 | // Injects URL, Request or Header params only if user tests every params | |
| 59 | // or method is selected by user. | |
| 60 | if ( | |
| 61 |
1
1. testParameters : negated conditional → NO_COVERAGE |
this != this.injectionModel.getMediatorUtils().connectionUtil().getMethodInjection() |
| 62 |
1
1. testParameters : negated conditional → NO_COVERAGE |
&& !this.isCheckingAllParam() |
| 63 |
1
1. testParameters : negated conditional → NO_COVERAGE |
|| this.getParams().isEmpty() |
| 64 | ) { | |
| 65 |
1
1. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return false; |
| 66 | } | |
| 67 | | |
| 68 | // Force injection method of model to current running method | |
| 69 | this.injectionModel.getMediatorUtils().connectionUtil().withMethodInjection(this); | |
| 70 | | |
| 71 | // Injection by injection point in params or in path | |
| 72 | if ( | |
| 73 |
1
1. testParameters : negated conditional → NO_COVERAGE |
this.getParamsAsString().contains(InjectionModel.STAR) |
| 74 |
1
1. testParameters : negated conditional → NO_COVERAGE |
|| this.injectionModel.getMediatorUtils().connectionUtil().getUrlBase().contains(InjectionModel.STAR) |
| 75 | ) { | |
| 76 | hasFoundInjection = this.checkParamWithStar(); | |
| 77 |
1
1. testParameters : negated conditional → NO_COVERAGE |
} else if (!this.isCheckingAllParam()) { |
| 78 | hasFoundInjection = this.checkLastParam(); | |
| 79 | } else { | |
| 80 | hasFoundInjection = this.checkAllParams(); | |
| 81 | } | |
| 82 |
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 hasFoundInjection; |
| 83 | } | |
| 84 | ||
| 85 | private boolean checkParamWithStar() throws JSqlException { | |
| 86 | SimpleEntry<String, String> parameterToInject = this.getParams().stream() | |
| 87 |
3
1. lambda$checkParamWithStar$2 : negated conditional → NO_COVERAGE 2. lambda$checkParamWithStar$2 : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkParamWithStar$2 → NO_COVERAGE 3. lambda$checkParamWithStar$2 : negated conditional → NO_COVERAGE |
.filter(entry -> entry.getValue().contains("*") || entry.getKey().contains("*")) // key when soap |
| 88 | .findFirst() | |
| 89 | .orElse(null); | |
| 90 |
1
1. checkParamWithStar : negated conditional → NO_COVERAGE |
if (parameterToInject != null) { |
| 91 | LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking selected param [{}]...", parameterToInject.getKey()); | |
| 92 | } | |
| 93 |
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); |
| 94 | } | |
| 95 | ||
| 96 | /** | |
| 97 | * Default injection: last param tested only | |
| 98 | */ | |
| 99 | private boolean checkLastParam() throws JSqlException { | |
| 100 | // Will check param value by user. | |
| 101 | // Notice options 'Inject each URL params' and 'inject JSON' must be checked both | |
| 102 | // for JSON injection of last param | |
| 103 | SimpleEntry<String, String> parameterToInject = this.getParams().stream() | |
| 104 |
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) |
| 105 |
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")); |
| 106 | LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking default last param [{}]. Use address bar button or preferences to check other params...", parameterToInject.getKey()); | |
| 107 |
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); |
| 108 | } | |
| 109 | ||
| 110 | /** | |
| 111 | * Injection of every params: isCheckingAllParam() == true. | |
| 112 | * Params are tested one by one in two loops: | |
| 113 | * - inner loop erases * from previous param | |
| 114 | * - outer loop adds * to current param | |
| 115 | */ | |
| 116 | private boolean checkAllParams() throws StoppedByUserSlidingException { | |
| 117 | LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Checking all params..."); | |
| 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 value. | |
| 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 |
1
1. checkAllParams : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE |
return false; |
| 137 | } | |
| 138 | ||
| 139 | private boolean isParamInjectable(SimpleEntry<String, String> paramStar) throws StoppedByUserSlidingException { | |
| 140 | boolean hasFoundInjection; | |
| 141 | | |
| 142 | // Will test if current value is a JSON entity | |
| 143 | Object jsonEntity = JsonUtil.getJson(paramStar.getValue()); | |
| 144 | | |
| 145 | // Define a tree of JSON attributes with path as the key: root.a => value of a | |
| 146 | List<SimpleEntry<String, String>> attributesJson = JsonUtil.createEntries(jsonEntity, "root", null); | |
| 147 | | |
| 148 | // When option 'Inject JSON' is selected and there's a JSON entity to inject | |
| 149 | // then loop through each path to add * at the end of value and test each strategy. | |
| 150 | // Marks * are erased between each test. | |
| 151 |
2
1. isParamInjectable : negated conditional → NO_COVERAGE 2. isParamInjectable : negated conditional → NO_COVERAGE |
if (!attributesJson.isEmpty() && this.injectionModel.getMediatorUtils().preferencesUtil().isCheckingAllJsonParam()) { |
| 152 | LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "{} [JSON] params...", () -> I18nUtil.valueByKey(AbstractMethodInjection.LOG_CHECKING)); | |
| 153 | hasFoundInjection = this.injectionModel.getMediatorUtils().jsonUtil().testJsonParam(this, paramStar); | |
| 154 | } else { | |
| 155 | hasFoundInjection = this.testJsonlessParam(paramStar); // Standard non JSON injection | |
| 156 | } | |
| 157 |
2
1. isParamInjectable : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE 2. isParamInjectable : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE |
return hasFoundInjection; |
| 158 | } | |
| 159 | | |
| 160 | public boolean testJsonlessParam(SimpleEntry<String, String> paramStar) throws StoppedByUserSlidingException { | |
| 161 | var hasFoundInjection = false; | |
| 162 | ||
| 163 | paramStar.setValue(paramStar.getValue() + InjectionModel.STAR); | |
| 164 | | |
| 165 | try { | |
| 166 | LOGGER.log( | |
| 167 | LogLevelUtil.CONSOLE_INFORM, | |
| 168 | "{} {} param [key:{}, value:{}]", | |
| 169 |
1
1. lambda$testJsonlessParam$6 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$6 → NO_COVERAGE |
() -> I18nUtil.valueByKey(AbstractMethodInjection.LOG_CHECKING), |
| 170 |
1
1. lambda$testJsonlessParam$7 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$7 → NO_COVERAGE |
() -> this.name().toLowerCase(), |
| 171 | paramStar::getKey, | |
| 172 |
1
1. lambda$testJsonlessParam$8 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$8 → NO_COVERAGE |
() -> paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY) |
| 173 | ); | |
| 174 | | |
| 175 | // Test current standard value marked with * for injection | |
| 176 | // Keep original param | |
| 177 | hasFoundInjection = this.injectionModel.getMediatorStrategy().testStrategies(paramStar); | |
| 178 | | |
| 179 | } catch (StoppedByUserSlidingException e) { // Break all params processing in upper methods | |
| 180 | throw e; | |
| 181 | } catch (JSqlException e) { // Injection failure | |
| 182 | LOGGER.log( | |
| 183 | LogLevelUtil.CONSOLE_ERROR, | |
| 184 | "No {} injection found for parameter {}={} ({})", | |
| 185 | this.name(), | |
| 186 | paramStar.getKey(), | |
| 187 | paramStar.getValue().replaceAll("\\+.?$|\\" + InjectionModel.STAR, StringUtils.EMPTY), | |
| 188 | e.getMessage() | |
| 189 | ); | |
| 190 | } finally { | |
| 191 |
1
1. testJsonlessParam : negated conditional → NO_COVERAGE |
if (!hasFoundInjection) { // Erase * from JSON if failure |
| 192 | | |
| 193 | // Erase * at the end of each params | |
| 194 |
1
1. testJsonlessParam : removed call to java/util/List::forEach → NO_COVERAGE |
this.getParams().forEach(e -> |
| 195 | e.setValue( | |
| 196 | e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY) | |
| 197 | ) | |
| 198 | ); | |
| 199 | | |
| 200 | // TODO It erases STAR from value => * can't be used in parameter | |
| 201 | paramStar.setValue(paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)); | |
| 202 | } | |
| 203 | } | |
| 204 |
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; |
| 205 | } | |
| 206 | } | |
Mutations | ||
| 36 |
1.1 |
|
| 40 |
1.1 |
|
| 41 |
1.1 |
|
| 43 |
1.1 2.2 |
|
| 45 |
1.1 |
|
| 55 |
1.1 |
|
| 61 |
1.1 |
|
| 62 |
1.1 |
|
| 63 |
1.1 |
|
| 65 |
1.1 |
|
| 73 |
1.1 |
|
| 74 |
1.1 |
|
| 77 |
1.1 |
|
| 82 |
1.1 2.2 |
|
| 87 |
1.1 2.2 3.3 |
|
| 90 |
1.1 |
|
| 93 |
1.1 2.2 |
|
| 104 |
1.1 |
|
| 105 |
1.1 |
|
| 107 |
1.1 2.2 |
|
| 125 |
1.1 |
|
| 127 |
1.1 |
|
| 128 |
1.1 |
|
| 136 |
1.1 |
|
| 151 |
1.1 2.2 |
|
| 157 |
1.1 2.2 |
|
| 169 |
1.1 |
|
| 170 |
1.1 |
|
| 172 |
1.1 |
|
| 191 |
1.1 |
|
| 194 |
1.1 |
|
| 204 |
1.1 2.2 |