19 package org.sleuthkit.autopsy.commandlineingest;
21 import java.beans.PropertyChangeListener;
22 import java.beans.PropertyChangeSupport;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.List;
30 import java.util.logging.Level;
31 import java.util.stream.Collectors;
32 import java.util.stream.Stream;
33 import org.apache.commons.lang3.ArrayUtils;
35 import org.netbeans.api.sendopts.CommandException;
36 import org.netbeans.spi.sendopts.Env;
37 import org.netbeans.spi.sendopts.Option;
38 import org.netbeans.spi.sendopts.OptionProcessor;
39 import org.openide.util.lookup.ServiceProvider;
45 @ServiceProvider(service = OptionProcessor.class)
49 private final Option caseNameOption = Option.requiredArgument(
'n',
"caseName");
50 private final Option caseTypeOption = Option.requiredArgument(
't',
"caseType");
51 private final Option caseBaseDirOption = Option.requiredArgument(
'o',
"caseBaseDir");
52 private final Option createCaseCommandOption = Option.withoutArgument(
'c',
"createCase");
53 private final Option dataSourcePathOption = Option.requiredArgument(
's',
"dataSourcePath");
54 private final Option dataSourceObjectIdOption = Option.requiredArgument(
'i',
"dataSourceObjectId");
55 private final Option addDataSourceCommandOption = Option.withoutArgument(
'a',
"addDataSource");
56 private final Option bitlockerKeyCommandOption = Option.requiredArgument(
'k',
"key");
57 private final Option runIngestCommandOption = Option.optionalArgument(
'r',
"runIngest");
58 private final Option listAllDataSourcesCommandOption = Option.withoutArgument(
'l',
"listAllDataSources");
59 private final Option generateReportsOption = Option.optionalArgument(
'g',
"generateReports");
60 private final Option listAllIngestProfileOption = Option.withoutArgument(
'p',
"listAllIngestProfiles");
61 private final Option defaultArgument = Option.defaultArguments();
63 private boolean runFromCommandLine =
false;
65 private final List<CommandLineCommand> commands =
new ArrayList<>();
67 final static String CASETYPE_MULTI =
"multi";
68 final static String CASETYPE_SINGLE =
"single";
70 private String defaultArgumentValue = null;
72 private PropertyChangeSupport changes =
new PropertyChangeSupport(
this);
73 public static String PROCESSING_STARTED =
"command line process started";
74 public static String PROCESSING_COMPLETED =
"command line process completed";
87 createCaseCommandOption,
92 addDataSourceCommandOption,
93 bitlockerKeyCommandOption,
94 dataSourceObjectIdOption,
95 runIngestCommandOption,
96 listAllDataSourcesCommandOption,
97 generateReportsOption,
98 listAllIngestProfileOption,
104 protected void process(Env env, Map<Option, String[]> values) throws CommandException {
105 logger.log(Level.INFO,
"Processing Autopsy command line options");
106 System.out.println(
"Processing Autopsy command line options");
108 changes.firePropertyChange(PROCESSING_STARTED,
false,
true);
110 if (values.containsKey(defaultArgument)) {
111 defaultArgumentValue = values.get(defaultArgument)[0];
112 runFromCommandLine(
true);
117 if (!(values.containsKey(createCaseCommandOption) || values.containsKey(addDataSourceCommandOption)
118 || values.containsKey(runIngestCommandOption) || values.containsKey(listAllDataSourcesCommandOption)
119 || values.containsKey(generateReportsOption) || values.containsKey(listAllIngestProfileOption))) {
121 handleError(
"Invalid command line, an input option must be supplied.");
126 String inputCaseName =
"";
128 if(values.containsKey(listAllIngestProfileOption)) {
129 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.LIST_ALL_INGEST_PROFILES);
130 commands.add(newCommand);
131 runFromCommandLine(
true);
133 if (values.containsKey(caseNameOption)) {
134 argDirs = values.get(caseNameOption);
135 if (argDirs.length < 1) {
136 handleError(
"Missing argument 'caseName'");
138 inputCaseName = argDirs[0];
140 if (inputCaseName == null || inputCaseName.isEmpty()) {
141 handleError(
"'caseName' argument is empty");
146 if (inputCaseName == null || inputCaseName.isEmpty()) {
147 handleError(
"'caseName' argument is empty");
150 String caseType =
"";
151 if (values.containsKey(caseTypeOption)) {
152 argDirs = values.get(caseTypeOption);
154 if (argDirs.length < 1) {
155 handleError(
"Missing argument 'caseType'");
157 caseType = argDirs[0];
159 if (caseType == null || caseType.isEmpty()) {
160 handleError(
"'caseType' argument is empty");
161 }
else if (!caseType.equalsIgnoreCase(CASETYPE_MULTI) && !caseType.equalsIgnoreCase(CASETYPE_SINGLE)) {
162 handleError(
"'caseType' argument is invalid");
164 handleError(
"Unable to create multi user case. Confirm that multi user settings are configured correctly.");
168 String caseBaseDir =
"";
169 if (values.containsKey(caseBaseDirOption)) {
170 argDirs = values.get(caseBaseDirOption);
171 if (argDirs.length < 1) {
172 handleError(
"Missing argument 'caseBaseDir'");
174 caseBaseDir = argDirs[0];
176 if (caseBaseDir == null || caseBaseDir.isEmpty()) {
177 handleError(
"Missing argument 'caseBaseDir' option");
180 if (!(
new File(caseBaseDir).exists()) || !(
new File(caseBaseDir).isDirectory())) {
181 handleError(
"'caseBaseDir' directory doesn't exist or is not a directory: " + caseBaseDir);
186 if (caseBaseDir == null || caseBaseDir.isEmpty()) {
187 handleError(
"Missing argument 'caseBaseDir' option");
190 String dataSourcePath =
"";
191 if (values.containsKey(dataSourcePathOption)) {
193 argDirs = values.get(dataSourcePathOption);
194 if (argDirs.length < 1) {
195 handleError(
"Missing argument 'dataSourcePath'");
197 dataSourcePath = argDirs[0];
200 if (dataSourcePath == null || dataSourcePath.isEmpty()) {
201 handleError(
"Missing argument 'dataSourcePath'");
204 if (!(
new File(dataSourcePath).exists())) {
205 handleError(
"Input data source file " + dataSourcePath +
" doesn't exist");
209 String[] keysArgs = values.get(bitlockerKeyCommandOption);
210 String bitlockerKey = ArrayUtils.isNotEmpty(keysArgs) ? keysArgs[0] : null;
212 String dataSourceId =
"";
213 if (values.containsKey(dataSourceObjectIdOption)) {
215 argDirs = values.get(dataSourceObjectIdOption);
216 if (argDirs.length < 1) {
217 handleError(
"Missing argument 'dataSourceObjectIdOption'");
219 dataSourceId = argDirs[0];
222 if (dataSourceId == null || dataSourceId.isEmpty()) {
223 handleError(
"Input data source id is empty");
229 if (values.containsKey(createCaseCommandOption)) {
232 if (inputCaseName == null || inputCaseName.isEmpty()) {
233 handleError(
"'caseName' argument is empty");
236 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.CREATE_CASE);
237 newCommand.addInputValue(CommandLineCommand.InputType.CASE_NAME.name(), inputCaseName);
238 newCommand.addInputValue(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name(), caseBaseDir);
239 newCommand.addInputValue(CommandLineCommand.InputType.CASE_TYPE.name(), caseType);
240 commands.add(newCommand);
241 runFromCommandLine(
true);
245 if (values.containsKey(addDataSourceCommandOption)) {
248 if (dataSourcePath == null || dataSourcePath.isEmpty()) {
249 handleError(
"'dataSourcePath' argument is empty");
252 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.ADD_DATA_SOURCE);
253 newCommand.addInputValue(CommandLineCommand.InputType.CASE_NAME.name(), inputCaseName);
254 newCommand.addInputValue(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name(), caseBaseDir);
255 newCommand.addInputValue(CommandLineCommand.InputType.DATA_SOURCE_PATH.name(), dataSourcePath);
257 if (bitlockerKey != null) {
258 newCommand.addInputValue(CommandLineCommand.InputType.BITLOCKER_KEY.name(), bitlockerKey);
261 commands.add(newCommand);
262 runFromCommandLine(
true);
265 String ingestProfile =
"";
267 if (values.containsKey(runIngestCommandOption)) {
269 argDirs = values.get(runIngestCommandOption);
270 if(argDirs != null && argDirs.length > 0) {
271 ingestProfile = argDirs[0];
275 if (!values.containsKey(addDataSourceCommandOption) && dataSourceId.isEmpty()) {
277 handleError(
"'dataSourceId' argument is empty");
280 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.RUN_INGEST);
281 newCommand.addInputValue(CommandLineCommand.InputType.CASE_NAME.name(), inputCaseName);
282 newCommand.addInputValue(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name(), caseBaseDir);
283 newCommand.addInputValue(CommandLineCommand.InputType.DATA_SOURCE_ID.name(), dataSourceId);
284 newCommand.addInputValue(CommandLineCommand.InputType.INGEST_PROFILE_NAME.name(), ingestProfile);
285 newCommand.addInputValue(CommandLineCommand.InputType.DATA_SOURCE_PATH.name(), dataSourcePath);
286 commands.add(newCommand);
287 runFromCommandLine(
true);
291 if (values.containsKey(listAllDataSourcesCommandOption)) {
293 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.LIST_ALL_DATA_SOURCES);
294 newCommand.addInputValue(CommandLineCommand.InputType.CASE_NAME.name(), inputCaseName);
295 newCommand.addInputValue(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name(), caseBaseDir);
296 commands.add(newCommand);
297 runFromCommandLine(
true);
301 if (values.containsKey(generateReportsOption)) {
302 List<String> reportProfiles;
303 argDirs = values.get(generateReportsOption);
304 if (argDirs.length > 0) {
306 reportProfiles = Stream.of(argDirs[0].split(
","))
308 .collect(Collectors.toList());
310 if (reportProfiles == null || reportProfiles.isEmpty()) {
311 handleError(
"'generateReports' argument is empty");
314 for (String reportProfile : reportProfiles) {
315 if (reportProfile.isEmpty()) {
316 handleError(
"Empty report profile name");
318 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.GENERATE_REPORTS);
319 newCommand.addInputValue(CommandLineCommand.InputType.CASE_NAME.name(), inputCaseName);
320 newCommand.addInputValue(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name(), caseBaseDir);
321 newCommand.addInputValue(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name(), reportProfile);
322 commands.add(newCommand);
326 CommandLineCommand newCommand =
new CommandLineCommand(CommandLineCommand.CommandType.GENERATE_REPORTS);
327 newCommand.addInputValue(CommandLineCommand.InputType.CASE_NAME.name(), inputCaseName);
328 newCommand.addInputValue(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name(), caseBaseDir);
329 commands.add(newCommand);
332 runFromCommandLine(
true);
337 System.out.println(
"Completed processing Autopsy command line options");
338 changes.firePropertyChange(PROCESSING_COMPLETED,
false,
true);
347 return runFromCommandLine;
351 this.runFromCommandLine = runFromCommandLine;
360 return defaultArgumentValue;
368 List<CommandLineCommand> getCommands() {
369 return Collections.unmodifiableList(commands);
379 private void handleError(String errorMessage)
throws CommandException {
380 logger.log(Level.SEVERE, errorMessage);
385 PropertyChangeListener l) {
386 changes.addPropertyChangeListener(l);
389 PropertyChangeListener l) {
390 changes.removePropertyChangeListener(l);
synchronized void runFromCommandLine(boolean runFromCommandLine)
synchronized boolean isRunFromCommandLine()
String getDefaultArgument()
void removePropertyChangeListener(PropertyChangeListener l)
void addPropertyChangeListener(PropertyChangeListener l)
synchronized void setState(ProcessState state)
void handleError(String errorMessage)
static boolean canCreateMultiUserCases()
synchronized static Logger getLogger(String name)
synchronized ProcessState getState()
Set< Option > getOptions()
void process(Env env, Map< Option, String[]> values)