Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CyberTriageData.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2026 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.datamodel;
20
21import com.google.gson.JsonElement;
22import com.google.gson.JsonObject;
23import com.google.gson.JsonParseException;
24import com.google.gson.JsonParser;
25import com.google.gson.JsonPrimitive;
26import java.sql.ResultSet;
27import java.sql.SQLException;
28import java.text.SimpleDateFormat;
29import java.util.Date;
30import java.util.List;
31import java.util.Map;
32import java.util.logging.Level;
33import org.openide.nodes.ChildFactory;
34import org.openide.nodes.Children;
35import org.openide.nodes.Node;
36import org.openide.nodes.Sheet;
37import org.openide.util.lookup.Lookups;
38import org.sleuthkit.autopsy.coreutils.Logger;
39import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
40import org.sleuthkit.datamodel.SleuthkitCase;
41import org.sleuthkit.datamodel.TskCoreException;
42
48public class CyberTriageData implements AutopsyVisitableItem {
49
50 private final SleuthkitCase skCase;
51
52 public CyberTriageData(SleuthkitCase skCase) {
53 this.skCase = skCase;
54 }
55
56 public SleuthkitCase getSleuthkitCase() {
57 return skCase;
58 }
59
60 @Override
61 public <T> T accept(AutopsyItemVisitor<T> visitor) {
62 return visitor.visit(this);
63 }
64
69 public static final String CT_JSON_ATTRIBUTE_TYPE_NAME = "CT_JSON_DATA_ATTRIBUTE";
70
75 public static boolean isCyberTriageDatabase(SleuthkitCase skCase) {
76 try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(
77 "SELECT name FROM sqlite_master WHERE type='table' AND name='ct_errors'")) {
78 return dbQuery.getResultSet().next();
79 } catch (TskCoreException | SQLException ex) {
80 return false;
81 }
82 }
83
94 public static void addCtJsonProperties(Map<String, Object> map, String json) {
95 if (json == null || json.isEmpty()) {
96 return;
97 }
98 try {
99 JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
100 for (Map.Entry<String, JsonElement> entry : obj.entrySet()) {
101 JsonElement value = entry.getValue();
102 if (value.isJsonNull()) {
103 continue;
104 }
105 String key = "CT " + entry.getKey();
106 if (value.isJsonPrimitive()) {
107 JsonPrimitive primitive = value.getAsJsonPrimitive();
108 if (primitive.isNumber()) {
109 String lowerName = entry.getKey().toLowerCase();
110 if (lowerName.contains("date") || lowerName.contains("time")) {
111 long numVal = primitive.getAsLong();
112 // CT stores some timestamps in milliseconds; values > 10^10
113 // are ms and must be converted to seconds for TimeZoneUtils.
114 long seconds = (numVal > 10_000_000_000L) ? numVal / 1000 : numVal;
115 map.put(key, TimeZoneUtils.getFormattedTime(seconds));
116 } else {
117 map.put(key, primitive.getAsNumber());
118 }
119 } else if (primitive.isBoolean()) {
120 map.put(key, primitive.getAsBoolean());
121 } else {
122 map.put(key, primitive.getAsString());
123 }
124 } else {
125 // Nested object or array — store as string
126 map.put(key, value.toString());
127 }
128 }
129 } catch (JsonParseException | IllegalStateException ex) {
130 Logger.getLogger(CyberTriageData.class.getName())
131 .log(Level.WARNING, "Failed to parse CT_JSON_DATA_ATTRIBUTE value", ex);
132 }
133 }
134
135 // -------------------------------------------------------------------------
136 // Root node
137 // -------------------------------------------------------------------------
138
142 public static class RootNode extends DisplayableItemNode {
143
144 private static final String DISPLAY_NAME = "Addl. Cyber Triage Data";
145 private static final String ICON_PATH = "org/sleuthkit/autopsy/images/extracted_content.png";
146
147 public RootNode(SleuthkitCase skCase) {
148 super(Children.create(new RootChildFactory(skCase), true),
149 Lookups.singleton(DISPLAY_NAME));
150 setName(DISPLAY_NAME);
151 setDisplayName(DISPLAY_NAME);
152 setIconBaseWithExtension(ICON_PATH);
153 }
154
155 @Override
156 public boolean isLeafTypeNode() {
157 return false;
158 }
159
160 @Override
161 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
162 return visitor.visit(this);
163 }
164
165 @Override
166 public String getItemType() {
167 return getClass().getName();
168 }
169 }
170
175 private static class RootChildFactory extends ChildFactory<String> {
176
177 private final SleuthkitCase skCase;
178
179 RootChildFactory(SleuthkitCase skCase) {
180 this.skCase = skCase;
181 }
182
183 @Override
184 protected boolean createKeys(List<String> list) {
185 list.add("ERRORS");
186 return true;
187 }
188
189 @Override
190 protected Node createNodeForKey(String key) {
191 if ("ERRORS".equals(key)) {
192 return new ErrorsNode(skCase);
193 }
194 return null;
195 }
196 }
197
198 // -------------------------------------------------------------------------
199 // Errors node
200 // -------------------------------------------------------------------------
201
205 public static class ErrorsNode extends DisplayableItemNode {
206
207 private static final String DISPLAY_NAME = "Errors";
208 private static final String ICON_PATH = "org/sleuthkit/autopsy/images/error-icon-16.png";
209
210 public ErrorsNode(SleuthkitCase skCase) {
211 super(Children.create(new ErrorsChildFactory(skCase), true),
212 Lookups.singleton(DISPLAY_NAME));
213 setName(DISPLAY_NAME);
214 setDisplayName(DISPLAY_NAME);
215 setIconBaseWithExtension(ICON_PATH);
216 }
217
218 @Override
219 public boolean isLeafTypeNode() {
220 return false;
221 }
222
223 @Override
224 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
225 return visitor.visit(this);
226 }
227
228 @Override
229 public String getItemType() {
230 return getClass().getName();
231 }
232 }
233
234 // -------------------------------------------------------------------------
235 // Error data and leaf nodes
236 // -------------------------------------------------------------------------
237
241 public static class CtError {
242
243 public final long id;
244 public final String title;
245 public final String description;
246 public final String stackTrace;
247 public final long timestamp;
248 public final String severity;
249
250 CtError(long id, String title, String description,
251 String stackTrace, long timestamp, String severity) {
252 this.id = id;
253 this.title = title;
254 this.description = description;
255 this.stackTrace = stackTrace;
256 this.timestamp = timestamp;
257 this.severity = severity;
258 }
259 }
260
264 private static class ErrorsChildFactory extends ChildFactory<CtError> {
265
266 private static final Logger logger = Logger.getLogger(ErrorsChildFactory.class.getName());
267 private final SleuthkitCase skCase;
268
269 ErrorsChildFactory(SleuthkitCase skCase) {
270 this.skCase = skCase;
271 }
272
273 @Override
274 protected boolean createKeys(List<CtError> list) {
275 String query = "SELECT id, title, description, stack_trace, time_stamp, severity "
276 + "FROM ct_errors ORDER BY time_stamp DESC";
277 try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) {
278 ResultSet rs = dbQuery.getResultSet();
279 while (rs.next()) {
280 list.add(new CtError(
281 rs.getLong("id"),
282 rs.getString("title"),
283 rs.getString("description"),
284 rs.getString("stack_trace"),
285 rs.getLong("time_stamp"),
286 rs.getString("severity")));
287 }
288 } catch (TskCoreException | SQLException ex) {
289 logger.log(Level.WARNING, "Failed to query ct_errors table", ex);
290 }
291 return true;
292 }
293
294 @Override
295 protected Node createNodeForKey(CtError error) {
296 return new ErrorNode(error);
297 }
298 }
299
303 public static class ErrorNode extends DisplayableItemNode {
304
305 private static final String ICON_PATH = "org/sleuthkit/autopsy/images/warning-icon-16.png";
306 private static final SimpleDateFormat DATE_FORMAT
307 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
308
309 private final CtError error;
310
311 ErrorNode(CtError error) {
312 super(Children.LEAF, Lookups.singleton(error));
313 this.error = error;
314 setName(Long.toString(error.id));
315 setDisplayName(error.title);
316 setIconBaseWithExtension(ICON_PATH);
317 }
318
319 @Override
320 public boolean isLeafTypeNode() {
321 return true;
322 }
323
324 @Override
325 public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
326 return visitor.visit(this);
327 }
328
329 @Override
330 public String getItemType() {
331 return getClass().getName();
332 }
333
334 @Override
335 protected Sheet createSheet() {
336 Sheet sheet = super.createSheet();
337 Sheet.Set props = sheet.get(Sheet.PROPERTIES);
338 if (props == null) {
339 props = Sheet.createPropertiesSet();
340 sheet.put(props);
341 }
342 props.put(new NodeProperty<>("Severity", "Severity", "Severity of the error",
343 error.severity != null ? error.severity : ""));
344 props.put(new NodeProperty<>("Title", "Title", "Error title",
345 error.title != null ? error.title : ""));
346 props.put(new NodeProperty<>("Description", "Description", "Error description",
347 error.description != null ? error.description : ""));
348 props.put(new NodeProperty<>("Timestamp", "Timestamp", "When the error occurred",
349 DATE_FORMAT.format(new Date(error.timestamp * 1000))));
350 props.put(new NodeProperty<>("StackTrace", "Stack Trace", "Error stack trace",
351 error.stackTrace != null ? error.stackTrace : ""));
352 return sheet;
353 }
354 }
355}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static String getFormattedTime(long epochTime)
static boolean isCyberTriageDatabase(SleuthkitCase skCase)
static void addCtJsonProperties(Map< String, Object > map, String json)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.