Merge branch 'custom-release-march-2018' into 3632-IngestAfterUnzip
@ -349,7 +349,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDat
|
||||
//contents and replace the paths, if the contents can't be extracted return 0
|
||||
if (localFilePaths.size() == 1) {
|
||||
for (final String path : localFilePaths) {
|
||||
if (LOGICAL_EVIDENCE_FILTER.accept(new File(path))) {
|
||||
if (new File(path).isFile() && LOGICAL_EVIDENCE_FILTER.accept(new File(path))) {
|
||||
try {
|
||||
//if the L01 option was chosen
|
||||
localFilePaths = extractLogicalEvidenceFileContents(localFilePaths);
|
||||
|
@ -155,7 +155,7 @@ public class FileManager implements Closeable {
|
||||
* is for full or partial matches and is case insensitive (a case
|
||||
* insensitive SQL LIKE clause is used to query the case database).
|
||||
*
|
||||
* @param fileName The full or partial file name.
|
||||
* @param fileName The full name or a pattern to match on part of the name
|
||||
*
|
||||
* @return The matching files and directories.
|
||||
*
|
||||
@ -180,22 +180,22 @@ public class FileManager implements Closeable {
|
||||
* case insensitive (a case insensitive SQL LIKE clause is used to query the
|
||||
* case database).
|
||||
*
|
||||
* @param fileName The full or partial file name.
|
||||
* @param parentName The full or partial parent file or directory name.
|
||||
* @param fileName The full name or a pattern to match on part of the name
|
||||
* @param parentSubString Substring that must exist in parent path. Will be surrounded by % in LIKE query.
|
||||
*
|
||||
* @return The matching files and directories.
|
||||
*
|
||||
* @throws TskCoreException if there is a problem querying the case
|
||||
* database.
|
||||
*/
|
||||
public synchronized List<AbstractFile> findFiles(String fileName, String parentName) throws TskCoreException {
|
||||
public synchronized List<AbstractFile> findFiles(String fileName, String parentSubString) throws TskCoreException {
|
||||
if (null == caseDb) {
|
||||
throw new TskCoreException("File manager has been closed");
|
||||
}
|
||||
List<AbstractFile> result = new ArrayList<>();
|
||||
List<Content> dataSources = caseDb.getRootObjects();
|
||||
for (Content dataSource : dataSources) {
|
||||
result.addAll(findFiles(dataSource, fileName, parentName));
|
||||
result.addAll(findFiles(dataSource, fileName, parentSubString));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -206,7 +206,7 @@ public class FileManager implements Closeable {
|
||||
* insensitive (a case insensitive SQL LIKE clause is used to query the case
|
||||
* database).
|
||||
*
|
||||
* @param fileName The full or partial file name.
|
||||
* @param fileName The full name or a pattern to match on part of the name
|
||||
* @param parent The parent file or directory.
|
||||
*
|
||||
* @return The matching files and directories.
|
||||
@ -233,7 +233,7 @@ public class FileManager implements Closeable {
|
||||
* LIKE clause is used to query the case database).
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param fileName The full or partial file name.
|
||||
* @param fileName The full name or a pattern to match on part of the name
|
||||
*
|
||||
* @return The matching files and directories.
|
||||
*
|
||||
@ -255,19 +255,19 @@ public class FileManager implements Closeable {
|
||||
* database).
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param fileName The full or partial file name.
|
||||
* @param parentName The full or partial parent file or directory name.
|
||||
* @param fileName The full name or a pattern to match on part of the name
|
||||
* @param parentSubString Substring that must exist in parent path. Will be surrounded by % in LIKE query.
|
||||
*
|
||||
* @return The matching files and directories.
|
||||
*
|
||||
* @throws TskCoreException if there is a problem querying the case
|
||||
* database.
|
||||
*/
|
||||
public synchronized List<AbstractFile> findFiles(Content dataSource, String fileName, String parentName) throws TskCoreException {
|
||||
public synchronized List<AbstractFile> findFiles(Content dataSource, String fileName, String parentSubString) throws TskCoreException {
|
||||
if (null == caseDb) {
|
||||
throw new TskCoreException("File manager has been closed");
|
||||
}
|
||||
return caseDb.findFiles(dataSource, fileName, parentName);
|
||||
return caseDb.findFiles(dataSource, fileName, parentSubString);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,7 +278,7 @@ public class FileManager implements Closeable {
|
||||
* database).
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param fileName The full or partial file name.
|
||||
* @param fileName The full name or a pattern to match on part of the name
|
||||
* @param parent The parent file or directory.
|
||||
*
|
||||
* @return The matching files and directories.
|
||||
|
@ -387,7 +387,12 @@ public final class CoordinationService {
|
||||
* @return
|
||||
*/
|
||||
private String getFullyQualifiedNodePath(CategoryNode category, String nodePath) {
|
||||
return categoryNodeToPath.get(category.getDisplayName()) + "/" + nodePath.toUpperCase();
|
||||
// nodePath on Unix systems starts with a "/" and ZooKeeper doesn't like two slashes in a row
|
||||
if(nodePath.startsWith("/")){
|
||||
return categoryNodeToPath.get(category.getDisplayName()) + nodePath.toUpperCase();
|
||||
}else{
|
||||
return categoryNodeToPath.get(category.getDisplayName()) + "/" + nodePath.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,9 +238,6 @@ public final class UserPreferences {
|
||||
}
|
||||
|
||||
public static boolean getIsMultiUserModeEnabled() {
|
||||
if (!IS_WINDOWS_OS) {
|
||||
return false;
|
||||
}
|
||||
return preferences.getBoolean(IS_MULTI_USER_MODE_ENABLED, false);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
private static final String INVALID_DB_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort");
|
||||
private static final String INVALID_MESSAGE_SERVICE_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidMessageServicePort");
|
||||
private static final String INVALID_INDEXING_SERVER_PORT_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.validationErrMsg.invalidIndexingServerPort");
|
||||
private static final String NON_WINDOWS_OS_MSG = NbBundle.getMessage(MultiUserSettingsPanel.class, "MultiUserSettingsPanel.nonWindowsOs.msg");
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final MultiUserSettingsPanelController controller;
|
||||
private final Collection<JTextField> textBoxes = new ArrayList<>();
|
||||
@ -124,10 +123,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
addDocumentListeners(textBoxes, textBoxChangedListener);
|
||||
goodIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/good.png", false));
|
||||
badIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/bad.png", false));
|
||||
if (!isWindowsOS) {
|
||||
cbEnableMultiUser.setEnabled(false);
|
||||
cbEnableMultiUser.setSelected(false);
|
||||
}
|
||||
enableMultiUserComponents(textBoxes, cbEnableMultiUser.isSelected());
|
||||
}
|
||||
|
||||
@ -491,11 +486,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
|
||||
private void cbEnableMultiUserItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_cbEnableMultiUserItemStateChanged
|
||||
if (!cbEnableMultiUser.isSelected()) {
|
||||
if (!isWindowsOS) {
|
||||
tbOops.setText(NON_WINDOWS_OS_MSG);
|
||||
} else {
|
||||
tbOops.setText("");
|
||||
}
|
||||
tbOops.setText("");
|
||||
bnTestDatabase.setEnabled(false);
|
||||
lbTestDatabase.setIcon(null);
|
||||
bnTestSolr.setEnabled(false);
|
||||
@ -684,9 +675,6 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
void store() {
|
||||
if (!isWindowsOS) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean multiUserCasesEnabled = cbEnableMultiUser.isSelected();
|
||||
UserPreferences.setIsMultiUserModeEnabled(multiUserCasesEnabled);
|
||||
@ -741,11 +729,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
* @return true if it's okay, false otherwise.
|
||||
*/
|
||||
boolean valid() {
|
||||
if (!isWindowsOS) {
|
||||
tbOops.setText(NON_WINDOWS_OS_MSG);
|
||||
} else {
|
||||
tbOops.setText("");
|
||||
}
|
||||
tbOops.setText("");
|
||||
|
||||
if (cbEnableMultiUser.isSelected()) {
|
||||
return checkFieldsAndEnableButtons()
|
||||
|
@ -191,6 +191,12 @@ public class RawDSProcessor implements DataSourceProcessor, AutoIngestDataSource
|
||||
|
||||
@Override
|
||||
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||
|
||||
// only accept files
|
||||
if (!new File(dataSourcePath.toString()).isFile()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check file extension for supported types
|
||||
if (!isAcceptedByFiler(dataSourcePath.toFile(), filtersList)) {
|
||||
return 0;
|
||||
|
@ -65,7 +65,7 @@ public class ExtractArchiveWithPasswordAction extends AbstractAction {
|
||||
super(Bundle.ExtractArchiveWithPasswordAction_name_text());
|
||||
archiveFile = file;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String password = getPassword(Bundle.ExtractArchiveWithPasswordAction_prompt_title(), "");
|
||||
@ -161,7 +161,6 @@ public class ExtractArchiveWithPasswordAction extends AbstractAction {
|
||||
RunIngestModulesAction runIngest = new RunIngestModulesAction(archive);
|
||||
runIngest.actionPerformed(null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +285,6 @@ class SevenZipExtractor {
|
||||
if (archiveFile.hasChildren() && new File(moduleDirAbsolute, EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)).exists()) {
|
||||
return Case.getOpenCase().getServices().getFileManager().findFilesByParentPath(getRootArchiveId(archiveFile), archiveFilePath);
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@ -367,7 +366,6 @@ class SevenZipExtractor {
|
||||
pathInArchive = "/" + archName + "/" + Integer.toString(itemNumber);
|
||||
} else {
|
||||
pathInArchive = "/" + useName;
|
||||
|
||||
}
|
||||
String msg = NbBundle.getMessage(SevenZipExtractor.class,
|
||||
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg",
|
||||
@ -603,7 +601,6 @@ class SevenZipExtractor {
|
||||
//this is additional to zip bomb prevention mechanism
|
||||
if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && item.getSize() != null && item.getSize() > 0) { //if free space is known and file is not empty.
|
||||
long newDiskSpace = freeDiskSpace - item.getSize();
|
||||
|
||||
if (newDiskSpace < MIN_FREE_DISK_SPACE) {
|
||||
String msg = NbBundle.getMessage(SevenZipExtractor.class,
|
||||
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg",
|
||||
@ -733,7 +730,6 @@ class SevenZipExtractor {
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error creating blackboard artifact for encryption detected for file: " + escapedArchiveFilePath, ex); //NON-NLS
|
||||
|
||||
}
|
||||
|
||||
String msg = NbBundle.getMessage(SevenZipExtractor.class,
|
||||
@ -753,7 +749,6 @@ class SevenZipExtractor {
|
||||
}
|
||||
}
|
||||
return unpackSuccessful;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,9 +363,9 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
|
||||
// display warning if there is one (but don't disable "next" button)
|
||||
warnIfPathIsInvalid(path);
|
||||
|
||||
boolean isExist = new File(path).exists();
|
||||
boolean isFile = new File(path).isFile();
|
||||
|
||||
return (isExist);
|
||||
return (isFile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,7 +171,7 @@ class VolatilityProcessor {
|
||||
|
||||
// add the output to the case
|
||||
final Case currentCase = Case.getCurrentCase();
|
||||
Report report = currentCase.getSleuthkitCase().addReport(outputFile, "Volatility", "Volatility " + pluginToRun + " Module", dataSource);
|
||||
Report report = currentCase.getSleuthkitCase().addReport(outputFile, "Volatility", "Volatility " + pluginToRun + " Module");
|
||||
|
||||
KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class);
|
||||
if (null == searchService) {
|
||||
@ -458,26 +458,29 @@ class VolatilityProcessor {
|
||||
while ((line = br.readLine()) != null) {
|
||||
|
||||
String TAG = "Command line : ";
|
||||
if (line.startsWith(TAG)) {
|
||||
String file_path;
|
||||
if (line.startsWith(TAG)) {
|
||||
|
||||
// Command line : "C:\Program Files\VMware\VMware Tools\vmacthlp.exe"
|
||||
// grab whats inbetween the quotes
|
||||
if (line.charAt(TAG.length()) == '\"') {
|
||||
file_path = line.substring(TAG.length() + 1);
|
||||
if (file_path.contains("\"")) {
|
||||
file_path = file_path.substring(0, file_path.indexOf("\""));
|
||||
}
|
||||
}
|
||||
// Command line : C:\WINDOWS\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512
|
||||
// grab everything before the next space - we don't want arguments
|
||||
else {
|
||||
file_path = line.substring(TAG.length());
|
||||
if (file_path.contains(" ")) {
|
||||
file_path = file_path.substring(0, file_path.indexOf(" "));
|
||||
if(line.length() > TAG.length()) {
|
||||
String file_path;
|
||||
|
||||
// Command line : "C:\Program Files\VMware\VMware Tools\vmacthlp.exe"
|
||||
// grab whats inbetween the quotes
|
||||
if (line.charAt(TAG.length()) == '\"') {
|
||||
file_path = line.substring(TAG.length() + 1);
|
||||
if (file_path.contains("\"")) {
|
||||
file_path = file_path.substring(0, file_path.indexOf("\""));
|
||||
}
|
||||
}
|
||||
// Command line : C:\WINDOWS\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512
|
||||
// grab everything before the next space - we don't want arguments
|
||||
else {
|
||||
file_path = line.substring(TAG.length());
|
||||
if (file_path.contains(" ")) {
|
||||
file_path = file_path.substring(0, file_path.indexOf(" "));
|
||||
}
|
||||
}
|
||||
fileSet.add(normalizePath(file_path));
|
||||
}
|
||||
fileSet.add(normalizePath(file_path));
|
||||
}
|
||||
// 0x4a680000 0x5000 0xffff \??\C:\WINDOWS\system32\csrss.exe
|
||||
// 0x7c900000 0xb2000 0xffff C:\WINDOWS\system32\ntdll.dll
|
||||
|
@ -1,27 +1,72 @@
|
||||
/*! \page content_viewer_page Content Viewer
|
||||
|
||||
The Content Viewer lives in the lower right-hand side of the Autopsy main screen and show pictures, video, hex, text, extracted strings, metadata, etc. They are enabled when you select a file in the file list above it.
|
||||
The Content Viewer lives in the lower right-hand side of the Autopsy main screen and shows pictures, video, hex, text, extracted strings, metadata, etc. The Content Viewer is enabled when you select an entry in the \ref ui_results.
|
||||
|
||||
The Content Viewer is context-aware, meaning it will present different views of the content based on the type of file selected. For example, a .JPG would show up as a picture, a text file would show up as text, and a .bin file would show up as hex output.
|
||||
The Content Viewer is context-aware, meaning different tabs will be enabled depending on the type of content selected and which ingest modules have been run. It will default to what it considers the "most specific" tab. For example, selecting a JPG will cause the Content Viewer to automatically select the "Application" tab and will display the image there. If you instead would like the Content Viewer to stay on the previously selected tab when you change to a different content object, go to Tools->Options->Application Tab and select the "Stay on the same file viewer" option.
|
||||
|
||||
The screenshots below show some examples of content viewers in action.
|
||||
<br>
|
||||
\image html content-viewer-1.PNG
|
||||
<br>
|
||||
<br>
|
||||
\image html content-viewer-2.PNG
|
||||
<br>
|
||||
<br>
|
||||
\image html content-viewer-3.PNG
|
||||
<br>
|
||||
<br>
|
||||
\image html content-viewer-4.PNG
|
||||
<br>
|
||||
<br>
|
||||
\image html content-viewer-5.PNG
|
||||
<br>
|
||||
<br>
|
||||
\image html central_repo_content_viewer.png
|
||||
Note that the \ref central_repo_page must be enabled to use the Other Data Sources tab.
|
||||
\image html content_viewer_options_panel.png
|
||||
|
||||
When a Result type is selected in the Result Viewer (as opposed to a file), most of the tabs will correspond to the file associated with the result and not the result itself. For example, when selecting a Keyword Hit, the "Hex", "Strings", and "File Metadata" tabs will show data from the file where the keyword was found. The descriptions below will generally assume a file has been selected, but most also apply when we have a file associated with a selected result.
|
||||
|
||||
\section cv_hex Hex
|
||||
|
||||
The Hex tab is nearly always available and shows the contents of the file.
|
||||
|
||||
\image html content_viewer_hex.png
|
||||
|
||||
\section cv_strings Strings
|
||||
|
||||
The Strings tab shows all text strings found in the file. Different scripts can be chosen from the drop-down menu to display results for non-Latin alphabets.
|
||||
|
||||
\image html content_viewer_strings_cyrillic.png
|
||||
|
||||
\section cv_app Application
|
||||
|
||||
For certain file types, the Application tab can display the contents in a user friendly format. The following screenshots show some examples of what the Application tab will display.
|
||||
|
||||
It will display most image types:
|
||||
|
||||
\image html content_viewer_app_image.png
|
||||
|
||||
It also allows you to browse SQLite tables:
|
||||
|
||||
\image html content_viewer_app_sqlite.png
|
||||
|
||||
And plist file data will be shown and can be exported:
|
||||
|
||||
\image html content_viewer_app_plist.png
|
||||
|
||||
\section cv_indexed_text Indexed Text
|
||||
|
||||
The Indexed Text tab shows the text that has been indexed by the Keyword Search module. You can switch the "Text Source" Field to "Result Text" to see which text has been indexed for associated results.
|
||||
|
||||
\image html content_viewer_indexed_text.png
|
||||
|
||||
\section cv_message Message
|
||||
|
||||
The Message tab shows details of emails and SMS messages.
|
||||
|
||||
\image html content_viewer_message.png
|
||||
|
||||
\section cv_metadata File Metadata
|
||||
|
||||
The File Metadata tab displays basic information about the file, such as type, size, and hash. It also displays the output of the Sleuth Kit istat tool.
|
||||
|
||||
\image html content_viewer_metadata.png
|
||||
|
||||
\section cv_results Results
|
||||
|
||||
The Results tab is active when selecting entries that are part of the Results tree, such as keyword hits, call logs, and messages. It is also active when looking at a file that has results associated with it. The exact fields displayed depend on the type of entry. The two images below show the Results tab for a call log and a web bookmark.
|
||||
|
||||
\image html content_viewer_results_call.png
|
||||
<br>
|
||||
\image html content_viewer_results_bookmark.png
|
||||
|
||||
\section cv_other_occurrences Other Occurrences
|
||||
|
||||
The Other Occurrences tab shows what other cases/data sources this file or result has appeared in. The \ref central_repo_page must be enabled to access this tab. See the \ref cr_content_viewer section for more information.
|
||||
|
||||
\image html content_viewer_other_occurrences.png
|
||||
|
||||
|
||||
*/
|
||||
|
Before Width: | Height: | Size: 998 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 245 KiB |
BIN
docs/doxygen-user/images/content_viewer_app_image.png
Normal file
After Width: | Height: | Size: 187 KiB |
BIN
docs/doxygen-user/images/content_viewer_app_plist.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/doxygen-user/images/content_viewer_app_sqlite.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
docs/doxygen-user/images/content_viewer_hex.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
docs/doxygen-user/images/content_viewer_indexed_text.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
docs/doxygen-user/images/content_viewer_message.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
docs/doxygen-user/images/content_viewer_metadata.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
docs/doxygen-user/images/content_viewer_options_panel.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
docs/doxygen-user/images/content_viewer_other_occurrences.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
docs/doxygen-user/images/content_viewer_results_bookmark.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
docs/doxygen-user/images/content_viewer_results_call.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
docs/doxygen-user/images/content_viewer_strings_cyrillic.png
Normal file
After Width: | Height: | Size: 39 KiB |
@ -635,14 +635,17 @@ def build_id_obj_path_table(files_table, objects_table, artifacts_table, reports
|
||||
# make a copy of files_table and update it with new data from artifacts_table and reports_table
|
||||
mapping = files_table.copy()
|
||||
for k, v in objects_table.items():
|
||||
if k not in mapping.keys(): # If the mapping table doesn't have data for obj_id(k) i.e. the object is not a file...
|
||||
if k not in mapping.keys(): # If the mapping table doesn't have data for obj_id
|
||||
if k in reports_table.keys(): # For a report we use the report path
|
||||
par_obj_id = v[0]
|
||||
if par_obj_id is not None:
|
||||
mapping[k] = reports_table[k]
|
||||
elif k in artifacts_table.keys(): # For an artifact we use it's par_obj_id's path+name plus it's artifact_type name
|
||||
par_obj_id = v[0]
|
||||
path = mapping[par_obj_id]
|
||||
par_obj_id = v[0] # The parent of an artifact can be a file or a report
|
||||
if par_obj_id in mapping.keys():
|
||||
path = mapping[par_obj_id]
|
||||
elif par_obj_id in reports_table.keys():
|
||||
path = reports_table[par_obj_id]
|
||||
mapping[k] = path + "/" + artifacts_table[k]
|
||||
elif v[0] not in mapping.keys():
|
||||
if v[0] in artifacts_table.keys():
|
||||
|