# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023 Eduardo Aguiar
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import pymobius
import mobius
import traceback
import pymobius.app.chromium
import pymobius.app.gecko
import pymobius.registry.main
import pymobius.registry.wordwheelquery
import pymobius.registry.search_assistant

ANT_ID = 'text-autocomplete'
ANT_NAME = 'Autocomplete Text'
ANT_VERSION = '1.1'

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief Ant: text-autocomplete
# @author Eduardo Aguiar
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class Ant (object):

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Initialize object
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __init__ (self, item):
    self.id = ANT_ID
    self.name = ANT_NAME
    self.version = ANT_VERSION
    self.__item = item

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Run ant
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def run (self):
    if not self.__item.has_vfs ():
      return

    self.__entries = []
    self.__retrieve_chromium ()
    self.__retrieve_gecko ()
    self.__retrieve_win_registry ()
    self.__save_data ()

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Retrieve data from Chromium based browsers
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __retrieve_chromium (self):

    try:
      model = pymobius.app.chromium.model (self.__item)

      for profile in model.get_profiles ():
        for h in profile.get_form_history ():
          if not h.is_encrypted:
            entry = pymobius.Data ()
            entry.fieldname = h.fieldname
            entry.value = h.value
            entry.app_id = profile.app_id
            entry.app_name = profile.app_name
            entry.username = profile.username

            entry.metadata = mobius.pod.map ()
            entry.metadata.set ('first_used_time', h.first_used_time)
            entry.metadata.set ('last_used_time', h.last_used_time)
            entry.metadata.set ('app_id', profile.app_id)
            entry.metadata.set ('profile_name', profile.name)
            entry.metadata.set ('profile_path', profile.path)

          self.__entries.append (entry)

    except Exception as e:
      mobius.core.logf ('WRN %s %s' % (str (e), traceback.format_exc ()))

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Retrieve data from Gecko based browsers
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __retrieve_gecko (self):

    try:
      model = pymobius.app.gecko.model (self.__item)

      for profile in model.get_profiles ():
        for h in profile.get_form_history ():
          entry = pymobius.Data ()
          entry.fieldname = h.fieldname
          entry.value = h.value
          entry.app_id = profile.app_id
          entry.app_name = profile.app_name
          entry.username = profile.username

          entry.metadata = mobius.pod.map ()
          entry.metadata.set ('first_used_time', h.first_used_time)
          entry.metadata.set ('last_used_time', h.last_used_time)
          entry.metadata.set ('app_id', profile.app_id)
          entry.metadata.set ('profile_name', profile.name)
          entry.metadata.set ('profile_path', profile.path)

          self.__entries.append (entry)
    except Exception as e:
      mobius.core.logf ('WRN %s %s' % (str (e), traceback.format_exc ()))

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Retrieve data from Windows' Registry
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __retrieve_win_registry (self):

    try:
      ant = pymobius.registry.main.Ant (self.__item)
      for reg in ant.get_data ():

        # WordWheelQuery
        for entry in pymobius.registry.wordwheelquery.get (reg):
          entry.metadata = mobius.pod.map ()
          entry.metadata.set ('mrulistex_index', entry.idx)
          entry.metadata.set ('app_id', entry.app_id)
          self.__entries.append (entry)

        # Search Assistant
        for entry in pymobius.registry.search_assistant.get (reg):
          entry.metadata = mobius.pod.map ()
          entry.metadata.set ('app_id', entry.app_id)
          self.__entries.append (entry)

    except Exception as e:
      mobius.core.logf ('WRN %s %s' % (str (e), traceback.format_exc ()))

  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  # @brief Save data into model
  # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  def __save_data (self):
    case = self.__item.case
    transaction = case.new_transaction ()

    # remove old data
    self.__item.remove_text_autocompletes ()

    # save entries
    for e in self.__entries:
      try:
        c = self.__item.new_text_autocomplete (e.fieldname, e.value)
        c.app = e.app_name
        c.username = e.username
        c.metadata = e.metadata
      except Exception as e:
        mobius.core.logf ('WRN %s %s' % (str (e), traceback.format_exc ()))

    # set ant run
    self.__item.set_ant (ANT_ID, ANT_NAME, ANT_VERSION)
    transaction.commit ()
