Skip to content

Commit 154e04e

Browse files
authored
Merge pull request #7946 from eugene7646/tags_fix
Fix to support legacy tag set definition files
2 parents f58ca23 + 09e1b3e commit 154e04e

File tree

1 file changed

+83
-2
lines changed

1 file changed

+83
-2
lines changed

Core/src/org/sleuthkit/autopsy/casemodule/services/TagSetDefinition.java

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
package org.sleuthkit.autopsy.casemodule.services;
77

88
import com.google.gson.Gson;
9+
import com.google.gson.GsonBuilder;
10+
import com.google.gson.JsonArray;
11+
import com.google.gson.JsonDeserializationContext;
12+
import com.google.gson.JsonDeserializer;
13+
import com.google.gson.JsonElement;
14+
import com.google.gson.JsonObject;
15+
import com.google.gson.JsonParseException;
16+
import com.google.gson.JsonSyntaxException;
17+
import java.lang.reflect.Type;
918
import java.io.File;
1019
import java.io.FileWriter;
1120
import java.io.IOException;
@@ -17,13 +26,19 @@
1726
import javax.annotation.concurrent.Immutable;
1827
import java.io.FileFilter;
1928
import java.io.FileReader;
29+
import java.util.logging.Level;
30+
import org.sleuthkit.autopsy.coreutils.Logger;
2031
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
32+
import org.sleuthkit.datamodel.TagName;
33+
import org.sleuthkit.datamodel.TskData;
2134

2235
/**
2336
* Definition of a tag set.
2437
*/
2538
@Immutable
2639
final public class TagSetDefinition {
40+
41+
private static final Logger LOGGER = Logger.getLogger(TagSetDefinition.class.getName());
2742

2843
private final static String FILE_NAME_TEMPLATE = "%s-tag-set.json";
2944
private final static Path TAGS_USER_CONFIG_DIR = Paths.get(PlatformUtil.getUserConfigDirectory(), "tags");
@@ -102,10 +117,24 @@ static synchronized List<TagSetDefinition> readTagSetDefinitions() throws IOExce
102117
}
103118

104119
File[] fileList = dir.listFiles(new TagSetJsonFileFilter());
105-
Gson gson = new Gson();
120+
if (fileList == null) {
121+
return tagSetList;
122+
}
123+
124+
Gson gson = new GsonBuilder()
125+
.registerTypeAdapter(TagSetDefinition.class, new TagSetDefinitionDeserializer()) // Use custom deserializer
126+
.create();
127+
106128
for (File file : fileList) {
107129
try (FileReader reader = new FileReader(file)) {
108-
tagSetList.add(gson.fromJson(reader, TagSetDefinition.class));
130+
TagSetDefinition tagSet = gson.fromJson(reader, TagSetDefinition.class);
131+
if (tagSet != null) {
132+
tagSetList.add(tagSet);
133+
}
134+
} catch (JsonSyntaxException e) {
135+
LOGGER.log(Level.SEVERE, "Skipping invalid JSON file: " + file.getName() + " - " + e.getMessage());
136+
} catch (IOException e) {
137+
LOGGER.log(Level.SEVERE, "Error reading file: " + file.getName() + " - " + e.getMessage());
109138
}
110139
}
111140

@@ -132,4 +161,56 @@ public boolean accept(File file) {
132161
}
133162

134163
}
164+
165+
// Custom JSON Deserializer for TagSetDefinition to support legacy user tags and tag set JSON files.
166+
// In TSK release 4.13.0 and Autopsy release 4.22.0 we:
167+
// 1) renamed "TskData.KnownStatus" to "TskData.TagType"
168+
// 2) renamed "TagSetDefinition.knownStatus" to "TagSetDefinition.tagType"
169+
// 3) "TskData.KnownStatus" of "unknown" used to carry a score of "suspicious".
170+
// Now "TskData.TagType" of "unknown" carries a score of "unknown".
171+
//
172+
private static class TagSetDefinitionDeserializer implements JsonDeserializer<TagSetDefinition> {
173+
174+
@Override
175+
public TagSetDefinition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
176+
JsonObject jsonObject = json.getAsJsonObject();
177+
178+
String name = jsonObject.has("name") ? jsonObject.get("name").getAsString() : null;
179+
JsonArray tagArray = jsonObject.has("tagNameDefinitionList") ? jsonObject.getAsJsonArray("tagNameDefinitionList") : new JsonArray();
180+
List<TagNameDefinition> tagNameDefinitions = new ArrayList<>();
181+
182+
for (JsonElement element : tagArray) {
183+
JsonObject tagObject = element.getAsJsonObject();
184+
185+
String displayName = tagObject.has("displayName") ? tagObject.get("displayName").getAsString() : null;
186+
String description = tagObject.has("description") ? tagObject.get("description").getAsString() : null;
187+
TagName.HTML_COLOR color = context.deserialize(tagObject.get("color"), TagName.HTML_COLOR.class);
188+
189+
TskData.TagType tagType = null;
190+
// Handle tagType vs knownStatus
191+
if (tagObject.has("tagType") && !tagObject.get("tagType").isJsonNull()) {
192+
tagType = context.deserialize(tagObject.get("tagType"), TskData.TagType.class);
193+
} else if (tagObject.has("knownStatus") && !tagObject.get("knownStatus").isJsonNull()) {
194+
TskData.TagType legacyStatus = context.deserialize(tagObject.get("knownStatus"), TskData.TagType.class);
195+
196+
// "UNKNOWN" tag type used to carry an automatic "SUSPICIOUS" score.
197+
// If knownStatus was "UNKNOWN", use "SUSPICIOUS" instead
198+
if (legacyStatus == TskData.TagType.UNKNOWN) {
199+
tagType = TskData.TagType.SUSPICIOUS;
200+
} else {
201+
tagType = legacyStatus;
202+
}
203+
}
204+
205+
if (tagType == null) {
206+
LOGGER.log(Level.SEVERE, "Failed to initialize tagType for tag: {0}. Skipping entry.", displayName);
207+
continue;
208+
}
209+
210+
tagNameDefinitions.add(new TagNameDefinition(displayName, description, color, tagType));
211+
}
212+
213+
return new TagSetDefinition(name, tagNameDefinitions);
214+
}
215+
}
135216
}

0 commit comments

Comments
 (0)