mirror of
https://github.com/elisspace/autopsy.git
synced 2026-08-30 08:01:57 +00:00
GPX internal python module update
GPX internal pythong module update for open source and geoartifacthelper
This commit is contained in:
253
InternalPythonModules/GPX_Module/GPX_Parser_Module.py
Normal file
253
InternalPythonModules/GPX_Module/GPX_Parser_Module.py
Normal file
@@ -0,0 +1,253 @@
|
||||
"""
|
||||
Autopsy Forensic Browser
|
||||
|
||||
Copyright 2019-2020 Basis Technology Corp.
|
||||
Contact: carrier <at> sleuthkit <dot> org
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import os
|
||||
import jarray
|
||||
import inspect
|
||||
import time
|
||||
import calendar
|
||||
from datetime import datetime
|
||||
|
||||
from java.lang import System
|
||||
from java.util.logging import Level
|
||||
from java.io import File
|
||||
from java.util import ArrayList
|
||||
|
||||
from org.sleuthkit.datamodel import SleuthkitCase
|
||||
from org.sleuthkit.datamodel import AbstractFile
|
||||
from org.sleuthkit.datamodel import ReadContentInputStream
|
||||
from org.sleuthkit.datamodel import Blackboard
|
||||
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||
from org.sleuthkit.datamodel import TskCoreException
|
||||
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
|
||||
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||
from org.sleuthkit.autopsy.ingest import IngestModule
|
||||
from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException
|
||||
from org.sleuthkit.autopsy.ingest import DataSourceIngestModule
|
||||
from org.sleuthkit.autopsy.ingest import FileIngestModule
|
||||
from org.sleuthkit.autopsy.ingest import IngestModuleFactoryAdapter
|
||||
from org.sleuthkit.autopsy.ingest import IngestMessage
|
||||
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||
from org.sleuthkit.autopsy.coreutils import Logger
|
||||
from org.sleuthkit.autopsy.casemodule import Case
|
||||
from org.sleuthkit.autopsy.casemodule.services import Services
|
||||
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||
|
||||
# Based on gpxpy module: https://github.com/tkrajina/gpxpy
|
||||
import gpxpy
|
||||
import gpxpy.gpx
|
||||
|
||||
# Factory that defines the name and details of the module and allows Autopsy
|
||||
# to create instances of the modules that will do the analysis.
|
||||
class GPXParserDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
|
||||
|
||||
moduleName = "GPX Parser Module"
|
||||
|
||||
# True - Verbose debugging messages sent to log file.
|
||||
# False - Verbose debugging turned off.
|
||||
debuglevel = True
|
||||
|
||||
def getModuleDisplayName(self):
|
||||
return self.moduleName
|
||||
|
||||
# TODO: Give it a description
|
||||
def getModuleDescription(self):
|
||||
return "Module that extracts GEO data from GPX files."
|
||||
|
||||
def getModuleVersionNumber(self):
|
||||
return "1.1"
|
||||
|
||||
def isDataSourceIngestModuleFactory(self):
|
||||
return True
|
||||
|
||||
def createDataSourceIngestModule(self, ingestOptions):
|
||||
return GPXParserDataSourceIngestModule()
|
||||
|
||||
|
||||
# Data Source-level ingest module. One gets created per data source.
|
||||
class GPXParserDataSourceIngestModule(DataSourceIngestModule):
|
||||
|
||||
_logger = Logger.getLogger(GPXParserDataSourceIngestModuleFactory.moduleName)
|
||||
|
||||
def log(self, level, msg):
|
||||
self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
|
||||
|
||||
def __init__(self):
|
||||
self.context = None
|
||||
|
||||
# Where any setup and configuration is done.
|
||||
def startUp(self, context):
|
||||
self.context = context
|
||||
|
||||
# Where the analysis is done.
|
||||
def process(self, dataSource, progressBar):
|
||||
|
||||
# We don't know how much work there is yet.
|
||||
progressBar.switchToIndeterminate()
|
||||
|
||||
# This will work in 4.0.1 and beyond.
|
||||
# Use blackboard class to index blackboard artifacts for keyword search.
|
||||
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||
|
||||
# Get the sleuthkitcase
|
||||
skcase = Case.getCurrentCase().getSleuthkitCase()
|
||||
|
||||
# In the name and then count and read them.
|
||||
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
||||
|
||||
files = fileManager.findFiles(dataSource, "%.gpx")
|
||||
# TODO: Would like to change this to find files based on mimetype rather than extension.
|
||||
#files = findFiles(dataSource, "text/xml")
|
||||
#if (file.isMimeType('text/xml') == False):
|
||||
|
||||
numFiles = len(files)
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "found " + str(numFiles) + " files")
|
||||
progressBar.switchToDeterminate(numFiles)
|
||||
fileCount = 0;
|
||||
|
||||
# Get module name for adding attributes
|
||||
modulename = GPXParserDataSourceIngestModuleFactory.moduleName
|
||||
|
||||
for file in files:
|
||||
|
||||
# Get the GeoArtifactsHelper
|
||||
geoartifacthelper = GeoArtifactsHelper(skcase, modulename, file)
|
||||
|
||||
# Check if the user pressed cancel while we were busy.
|
||||
if self.context.isJobCancelled():
|
||||
return IngestModule.ProcessResult.OK
|
||||
|
||||
#self.log(Level.INFO, "GPX: Processing file: " + file.getName())
|
||||
fileCount += 1
|
||||
|
||||
# Check if module folder is present. If not, create it.
|
||||
dirname = os.path.join(Case.getCurrentCase().getTempDirectory(), "GPX_Parser_Module")
|
||||
try:
|
||||
os.stat(dirname)
|
||||
except:
|
||||
os.mkdir(dirname)
|
||||
filename = os.path.join(dirname, "tmp.gpx")
|
||||
|
||||
# Check to see if temporary file exists. If it does, remove it.
|
||||
if os.path.exists(filename):
|
||||
try:
|
||||
os.remove(filename)
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE DELETED " + filename )
|
||||
except:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE NOT DELETED " + filename)
|
||||
|
||||
# This writes the file to the local file system.
|
||||
localFile = File(filename)
|
||||
ContentUtils.writeToFile(file, localFile)
|
||||
|
||||
# Send to gpxpy for parsing.
|
||||
gpxfile = open(filename)
|
||||
try:
|
||||
gpx = gpxpy.parse(gpxfile)
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE PARSED")
|
||||
except:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX:\t" + file.getName() + " - FILE NOT PARSED")
|
||||
continue
|
||||
|
||||
if gpx:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX: TRACKS")
|
||||
for track in gpx.tracks:
|
||||
for segment in track.segments:
|
||||
for point in segment.points:
|
||||
# Make an Array to add attributes to allows to use bulk add attributes
|
||||
otherattributes = ArrayList()
|
||||
|
||||
# Evelation may be None so why it is in a try block
|
||||
try:
|
||||
otherattributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), modulename, point.elevation))
|
||||
except:
|
||||
pass
|
||||
|
||||
otherattributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG.getTypeID(), modulename, "Tracks"))
|
||||
|
||||
datetime = 0
|
||||
try:
|
||||
if (point.time != None):
|
||||
datetime = long(time.mktime(point.time.timetuple()))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Add the trackpoint using the helper class
|
||||
geoartifact = geoartifacthelper.addGPSTrackpoint(point.latitude, point.longitude, datetime, "Trackpoint", "GPXParser", otherattributes)
|
||||
except Blackboard.BlackboardException as e:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard " )
|
||||
except TskCoreException as e:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper tskcoreexception" )
|
||||
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX: WAYPOINTS")
|
||||
for waypoint in gpx.waypoints:
|
||||
attributes = ArrayList()
|
||||
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
|
||||
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), modulename, waypoint.latitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), modulename, waypoint.longitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG.getTypeID(), modulename, "Waypoint"))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), modulename, waypoint.name))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), modulename, "GPXParser"))
|
||||
|
||||
art.addAttributes(attributes)
|
||||
|
||||
try:
|
||||
# Post the artifact to blackboard
|
||||
skcase.getBlackboard().postArtifact(art, modulename)
|
||||
except Blackboard.BlackboardException as e:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard for waypoints" )
|
||||
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX: ROUTES")
|
||||
for route in gpx.routes:
|
||||
for point in route.points:
|
||||
otherattributes = ArrayList()
|
||||
|
||||
otherattributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG.getTypeID(), modulename, "Route"))
|
||||
|
||||
# Evelation may be None so why it is in a try block
|
||||
try:
|
||||
otherattributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), modulename, point.elevation))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Add the artifact using the geoArtifactHelper.
|
||||
geoartifact = geoartifacthelper.addGPSTrackpoint(point.latitude, point.longitude, 0, "Trackpoint", "GPXParser", otherattributes)
|
||||
except Blackboard.BlackboardException as e:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard for Routes")
|
||||
except TskCoreException as e:
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper tskcoreexception for routes" )
|
||||
|
||||
# Update the progress bar.
|
||||
progressBar.progress(fileCount)
|
||||
if os.path.exists(filename):
|
||||
try:
|
||||
os.remove(filename)
|
||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE DELETED")
|
||||
except:
|
||||
self.log(Level.SEVERE, "GPX:\t" + "FILE NOT DELETED")
|
||||
|
||||
# Post a message to the ingest messages inbox.
|
||||
message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, "GPX Parser Data Source Ingest Module", "Found %d files" % fileCount)
|
||||
IngestServices.getInstance().postMessage(message)
|
||||
return IngestModule.ProcessResult.OK;
|
||||
Reference in New Issue
Block a user