# Mobile Verification Toolkit (MVT)
# Copyright (c) 2021 The MVT Project Authors.
# Use of this software is governed by the MVT License 1.1 that can be found at
#   https://license.mvt.re/1.1/

import logging
import os

import pkg_resources

from .base import AndroidExtraction

log = logging.getLogger(__name__)

class Packages(AndroidExtraction):
    """This module extracts the list of installed packages."""

    def __init__(self, file_path=None, base_folder=None, output_folder=None,
                 fast_mode=False, log=None, results=[]):
        super().__init__(file_path=file_path, base_folder=base_folder,
                         output_folder=output_folder, fast_mode=fast_mode,
                         log=log, results=results)

    def serialize(self, record):
        records = []

        timestamps = [
            {"event": "package_install", "timestamp": record["timestamp"]},
            {"event": "package_first_install", "timestamp": record["first_install_time"]},
            {"event": "package_last_update", "timestamp": record["last_update_time"]},
        ]

        for ts in timestamps:
            records.append({
                "timestamp": ts["timestamp"],
                "module": self.__class__.__name__,
                "event": ts["event"],
                "data": f"{record['package_name']} (system: {record['system']}, third party: {record['third_party']})",
            })

        return records

    def check_indicators(self):
        root_packages_path = os.path.join("..", "..", "data", "root_packages.txt")
        root_packages_string = pkg_resources.resource_string(__name__, root_packages_path)
        root_packages = root_packages_string.decode("utf-8").split("\n")

        for root_package in root_packages:
            root_package = root_package.strip()
            if not root_package:
                continue

            if root_package in self.results:
                self.log.warning("Found an installed package related to rooting/jailbreaking: \"%s\"",
                                 root_package)
                self.detected.append(root_package)

    def run(self):
        self._adb_connect()

        packages = self._adb_command("pm list packages -U -u -i -f")
        for line in packages.split("\n"):
            line = line.strip()
            if not line.startswith("package:"):
                continue

            fields = line.split()
            file_name, package_name = fields[0].split(":")[1].rsplit("=", 1)
            installer = fields[1].split("=")[1].strip()
            if installer == "null":
                installer = None
            uid = fields[2].split(":")[1].strip()

            dumpsys = self._adb_command(f"dumpsys package {package_name} | grep -A2 timeStamp").split("\n")
            timestamp = dumpsys[0].split("=")[1].strip()
            first_install = dumpsys[1].split("=")[1].strip()
            last_update = dumpsys[2].split("=")[1].strip()

            self.results.append(dict(
                package_name=package_name,
                file_name=file_name,
                installer=installer,
                timestamp=timestamp,
                first_install_time=first_install,
                last_update_time=last_update,
                uid=uid,
                disabled=False,
                system=False,
                third_party=False,
            ))

        cmds = [
            {"field": "disabled", "arg": "-d"},
            {"field": "system", "arg": "-s"},
            {"field": "third_party", "arg": "-3"},
        ]
        for cmd in cmds:
            output = self._adb_command(f"pm list packages {cmd['arg']}")
            for line in output.split("\n"):
                line = line.strip()
                if not line.startswith("package:"):
                    continue

                package_name = line.split(":", 1)[1]
                for i, result in enumerate(self.results):
                    if result["package_name"] == package_name:
                        self.results[i][cmd["field"]] = True

        self.log.info("Extracted at total of %d installed package names",
                      len(self.results))

        self._adb_disconnect()
