JsonUtil.java

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
     * Log4j logger sent to view.
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
            // Test for JSON Object
38
            new JSONObject(param);
39
            isJson = true;
40
            
41
        } catch (JSONException exceptionJSONObject) {
42
            try {
43
                // Test for JSON Array
44
                new JSONArray(param);
45
                isJson = true;
46
                
47
            } catch (JSONException exceptionJSONArray) {
48
                // Not a JSON entity
49
            }
50
        }
51
        
52 2 1. isJson : replaced boolean return with false for com/jsql/util/JsonUtil::isJson → KILLED
2. isJson : replaced boolean return with true for com/jsql/util/JsonUtil::isJson → KILLED
        return isJson;
53
    }
54
55
    public static Object getJson(String param) {
56
57
        Object jsonEntity;  // Will test if current value is a JSON entity
58
        
59
        try {
60
            jsonEntity = new JSONObject(param);  // Test for JSON Object
61
        } catch (JSONException exceptionJSONObject) {
62
            try {
63
                jsonEntity = new JSONArray(param);  // Test for JSON Array
64
            } catch (JSONException exceptionJSONArray) {
65
                jsonEntity = new Object();  // Not a JSON entity
66
            }
67
        }
68
        
69 1 1. getJson : replaced return value with null for com/jsql/util/JsonUtil::getJson → KILLED
        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 1 1. createEntries : negated conditional → KILLED
        if (jsonEntity instanceof JSONObject) {
77 1 1. createEntries : removed call to com/jsql/util/JsonUtil::scanJsonObject → KILLED
            JsonUtil.scanJsonObject(jsonEntity, parentName, parentXPath, attributesXPath);
78 1 1. createEntries : negated conditional → KILLED
        } else if (jsonEntity instanceof JSONArray) {
79 1 1. createEntries : removed call to com/jsql/util/JsonUtil::scanJsonArray → KILLED
            JsonUtil.scanJsonArray(jsonEntity, parentName, parentXPath, attributesXPath);
80
        }
81
        
82 1 1. createEntries : replaced return value with Collections.emptyList for com/jsql/util/JsonUtil::createEntries → KILLED
        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 2 1. scanJsonArray : negated conditional → KILLED
2. scanJsonArray : changed conditional boundary → KILLED
        for (var i = 0; i < jsonArrayEntity.length(); i++) {
90
            
91
            Object value = jsonArrayEntity.get(i);
92
            String xpath = parentName +"["+ i +"]";
93
            
94
            // Not possible to make generic with scanJsonObject() because of JSONArray.put(int) != JSONObject.put(String)
95 2 1. scanJsonArray : negated conditional → KILLED
2. scanJsonArray : negated conditional → KILLED
            if (value instanceof JSONArray || value instanceof JSONObject) {
96
                attributesXPath.addAll(JsonUtil.createEntries(value, xpath, parentXPath));
97 1 1. scanJsonArray : negated conditional → KILLED
            } else if (value instanceof String) {
98
                
99
                SimpleEntry<String, String> stringValue = new SimpleEntry<>(xpath, (String) value);
100
                attributesXPath.add(stringValue);
101
                
102 1 1. scanJsonArray : negated conditional → SURVIVED
                if (parentXPath == null) {
103
                    jsonArrayEntity.put(i, value.toString().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY));
104 1 1. scanJsonArray : negated conditional → NO_COVERAGE
                } 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 1 1. scanJsonObject : negated conditional → KILLED
        while (keys.hasNext()) {
118
            
119
            String key = (String) keys.next();
120
            var value = jsonObjectEntity.get(key);
121
            String xpath = parentName +"."+ key;
122
            
123
            // Not possible to make generic with scanJsonObject() because of JSONArray.put(int) != JSONObject.put(String)
124 2 1. scanJsonObject : negated conditional → KILLED
2. scanJsonObject : negated conditional → KILLED
            if (value instanceof JSONArray || value instanceof JSONObject) {
125
                attributesXPath.addAll(JsonUtil.createEntries(value, xpath, parentXPath));
126 1 1. scanJsonObject : negated conditional → KILLED
            } else if (value instanceof String) {
127
                
128
                SimpleEntry<String, String> stringValue = new SimpleEntry<>(xpath, (String) value);
129
                attributesXPath.add(stringValue);
130
                
131 1 1. scanJsonObject : negated conditional → KILLED
                if (parentXPath == null) {
132
                    jsonObjectEntity.put(key, value.toString().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY));
133 1 1. scanJsonObject : negated conditional → KILLED
                } 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
        // Remove STAR at the end of parameter, STAR will be added inside json data instead
145
        paramStar.setValue(paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY));
146
        
147
        // Will test if current value is a JSON entity
148
        Object jsonEntity = JsonUtil.getJson(paramStar.getValue());
149
        
150
        // Define a tree of JSON attributes with path as the key: root.a => value of a
151
        List<SimpleEntry<String, String>> attributesJson = JsonUtil.createEntries(jsonEntity, "root", null);
152
        
153
        // Loop through each JSON values
154
        for (SimpleEntry<String, String> parentXPath: attributesJson) {
155
            
156
            JsonUtil.createEntries(jsonEntity, "root", null);  // Erase previously defined *
157
            JsonUtil.createEntries(jsonEntity, "root", parentXPath);  // Add * to current parameter's value
158
159
            paramStar.setValue(jsonEntity.toString());  // Replace param value by marked one
160
            
161
            try {
162
                LOGGER.log(
163
                    LogLevelUtil.CONSOLE_INFORM,
164
                    "Checking JSON {} parameter {}={}",
165
                    methodInjection::name,
166
                    parentXPath::getKey,
167 1 1. lambda$testJsonParam$0 : replaced return value with null for com/jsql/util/JsonUtil::lambda$testJsonParam$0 → NO_COVERAGE
                    () -> parentXPath.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
168
                );
169
                
170
                // Test current JSON value marked with * for injection
171
                // Keep original param
172
                hasFoundInjection = this.injectionModel.getMediatorStrategy().testStrategies(paramStar);
173
                
174
                // Injection successful
175
                break;
176
                
177
            } catch (JSqlException e) {
178
                
179
                // Injection failure
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
                // Erase * at the end of each params
192
                // TODO useless
193
                methodInjection.getParams()
194 1 1. testJsonParam : removed call to java/util/List::forEach → NO_COVERAGE
                    .forEach(e -> e.setValue(
195
                        e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY)
196
                    ));
197
                
198
                // Erase * from JSON if failure
199 1 1. testJsonParam : negated conditional → NO_COVERAGE
                if (!hasFoundInjection) {
200
                    paramStar.setValue(
201
                        paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)
202
                    );
203
                }
204
            }
205
        }
206
        
207 2 1. testJsonParam : replaced boolean return with true for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE
2. testJsonParam : replaced boolean return with false for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE
        return hasFoundInjection;
208
    }
209
}

Mutations

52

1.1
Location : isJson
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_4]
replaced boolean return with false for com/jsql/util/JsonUtil::isJson → KILLED

2.2
Location : isJson
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_4]
replaced boolean return with true for com/jsql/util/JsonUtil::isJson → KILLED

69

1.1
Location : getJson
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_3]
replaced return value with null for com/jsql/util/JsonUtil::getJson → KILLED

76

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

77

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
removed call to com/jsql/util/JsonUtil::scanJsonObject → KILLED

78

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

79

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
removed call to com/jsql/util/JsonUtil::scanJsonArray → KILLED

82

1.1
Location : createEntries
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
replaced return value with Collections.emptyList for com/jsql/util/JsonUtil::createEntries → KILLED

89

1.1
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

2.2
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
changed conditional boundary → KILLED

95

1.1
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

2.2
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

97

1.1
Location : scanJsonArray
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

102

1.1
Location : scanJsonArray
Killed by : none
negated conditional → SURVIVED

104

1.1
Location : scanJsonArray
Killed by : none
negated conditional → NO_COVERAGE

117

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

124

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

2.2
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

126

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_2]/[iteration:0]
negated conditional → KILLED

131

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_0]/[iteration:0]
negated conditional → KILLED

133

1.1
Location : scanJsonObject
Killed by : JsonUtilSpock.[engine:spock]/[spec:JsonUtilSpock]/[feature:$spock_feature_0_0]/[iteration:0]
negated conditional → KILLED

167

1.1
Location : lambda$testJsonParam$0
Killed by : none
replaced return value with null for com/jsql/util/JsonUtil::lambda$testJsonParam$0 → NO_COVERAGE

194

1.1
Location : testJsonParam
Killed by : none
removed call to java/util/List::forEach → NO_COVERAGE

199

1.1
Location : testJsonParam
Killed by : none
negated conditional → NO_COVERAGE

207

1.1
Location : testJsonParam
Killed by : none
replaced boolean return with true for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE

2.2
Location : testJsonParam
Killed by : none
replaced boolean return with false for com/jsql/util/JsonUtil::testJsonParam → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.16.1