mirror of
https://github.com/mvt-project/mvt
synced 2025-11-13 01:37:36 +01:00
Compare commits
2 Commits
dependabot
...
feature/an
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d82e55e12c | ||
|
|
981371bd8b |
@@ -31,7 +31,7 @@ dependencies = [
|
|||||||
"PyYAML>=6.0.2",
|
"PyYAML>=6.0.2",
|
||||||
"pyahocorasick==2.2.0",
|
"pyahocorasick==2.2.0",
|
||||||
"betterproto==1.2.5",
|
"betterproto==1.2.5",
|
||||||
"pydantic==2.12.3",
|
"pydantic==2.11.7",
|
||||||
"pydantic-settings==2.10.1",
|
"pydantic-settings==2.10.1",
|
||||||
"NSKeyedUnArchiver==1.5.2",
|
"NSKeyedUnArchiver==1.5.2",
|
||||||
"python-dateutil==2.9.0.post0",
|
"python-dateutil==2.9.0.post0",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from mvt.common.help import (
|
|||||||
)
|
)
|
||||||
from mvt.common.logo import logo
|
from mvt.common.logo import logo
|
||||||
from mvt.common.updates import IndicatorsUpdates
|
from mvt.common.updates import IndicatorsUpdates
|
||||||
from mvt.common.utils import init_logging, set_verbose_logging
|
from mvt.common.utils import init_logging, set_verbose_logging, CommandWrapperGroup
|
||||||
|
|
||||||
from .cmd_check_adb import CmdAndroidCheckADB
|
from .cmd_check_adb import CmdAndroidCheckADB
|
||||||
from .cmd_check_androidqf import CmdAndroidCheckAndroidQF
|
from .cmd_check_androidqf import CmdAndroidCheckAndroidQF
|
||||||
@@ -68,7 +68,7 @@ def _get_disable_flags(ctx):
|
|||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Main
|
# Main
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
@click.group(invoke_without_command=False)
|
@click.group(invoke_without_command=False, cls=CommandWrapperGroup)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--disable-update-check", is_flag=True, help=HELP_MSG_DISABLE_UPDATE_CHECK
|
"--disable-update-check", is_flag=True, help=HELP_MSG_DISABLE_UPDATE_CHECK
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
import json
|
import json
|
||||||
|
import uuid
|
||||||
|
|
||||||
from typing import Tuple, Type, Optional
|
from typing import Tuple, Type, Optional
|
||||||
from appdirs import user_config_dir
|
from appdirs import user_config_dir
|
||||||
from pydantic import AnyHttpUrl, Field
|
from pydantic import AnyHttpUrl, BaseModel, Field
|
||||||
from pydantic_settings import (
|
from pydantic_settings import (
|
||||||
BaseSettings,
|
BaseSettings,
|
||||||
InitSettingsSource,
|
InitSettingsSource,
|
||||||
@@ -17,6 +18,22 @@ MVT_CONFIG_FOLDER = user_config_dir("mvt")
|
|||||||
MVT_CONFIG_PATH = os.path.join(MVT_CONFIG_FOLDER, "config.yaml")
|
MVT_CONFIG_PATH = os.path.join(MVT_CONFIG_FOLDER, "config.yaml")
|
||||||
|
|
||||||
|
|
||||||
|
class TelemetrySettings(BaseModel):
|
||||||
|
"""
|
||||||
|
Settings used by the Telemetry module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ENABLED: bool = Field(True, description="Flag for telemetry collection")
|
||||||
|
ENDPOINT: AnyHttpUrl = Field(
|
||||||
|
"https://t.mvt.re/events", description="Telemetry collection endpoint"
|
||||||
|
)
|
||||||
|
DEVICE_ID: str | None = Field(
|
||||||
|
default=None,
|
||||||
|
required=True,
|
||||||
|
description="Anonymous Unique ID for use in telemetry",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MVTSettings(BaseSettings):
|
class MVTSettings(BaseSettings):
|
||||||
model_config = SettingsConfigDict(
|
model_config = SettingsConfigDict(
|
||||||
env_prefix="MVT_",
|
env_prefix="MVT_",
|
||||||
@@ -24,7 +41,7 @@ class MVTSettings(BaseSettings):
|
|||||||
extra="ignore",
|
extra="ignore",
|
||||||
nested_model_default_partial_updates=True,
|
nested_model_default_partial_updates=True,
|
||||||
)
|
)
|
||||||
# Allow to decided if want to load environment variables
|
# Flag to enable or disable loading of environment variables.
|
||||||
load_env: bool = Field(True, exclude=True)
|
load_env: bool = Field(True, exclude=True)
|
||||||
|
|
||||||
# General settings
|
# General settings
|
||||||
@@ -51,6 +68,9 @@ class MVTSettings(BaseSettings):
|
|||||||
PROFILE: bool = Field(False, description="Profile the execution of MVT modules")
|
PROFILE: bool = Field(False, description="Profile the execution of MVT modules")
|
||||||
HASH_FILES: bool = Field(False, description="Should MVT hash output files")
|
HASH_FILES: bool = Field(False, description="Should MVT hash output files")
|
||||||
|
|
||||||
|
# Telemetry settings
|
||||||
|
TELEMETRY: TelemetrySettings = TelemetrySettings(include=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def settings_customise_sources(
|
def settings_customise_sources(
|
||||||
cls,
|
cls,
|
||||||
@@ -95,6 +115,8 @@ class MVTSettings(BaseSettings):
|
|||||||
"""
|
"""
|
||||||
# Set invalid env prefix to avoid loading env variables.
|
# Set invalid env prefix to avoid loading env variables.
|
||||||
settings = MVTSettings(load_env=False)
|
settings = MVTSettings(load_env=False)
|
||||||
|
if not settings.TELEMETRY.DEVICE_ID:
|
||||||
|
settings.TELEMETRY.DEVICE_ID = str(uuid.uuid4())
|
||||||
settings.save_settings()
|
settings.save_settings()
|
||||||
|
|
||||||
# Load the settings again with any ENV variables.
|
# Load the settings again with any ENV variables.
|
||||||
|
|||||||
113
src/mvt/common/telemetry.py
Normal file
113
src/mvt/common/telemetry.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 The MVT 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 os
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from mvt.common.config import settings
|
||||||
|
from mvt.common.version import MVT_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Telemetry(object):
|
||||||
|
"""
|
||||||
|
MVT collects anonymous telemetry to understand how MVT is used.
|
||||||
|
|
||||||
|
This data is helpful to prioritize features, identify platforms and versions. It
|
||||||
|
will also how many users are using custom indicators, modules and packages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.endpoint = settings.TELEMETRY.ENDPOINT
|
||||||
|
self.device_id = settings.TELEMETRY.DEVICE_ID
|
||||||
|
|
||||||
|
def is_telemetry_enabled(self):
|
||||||
|
return settings.TELEMETRY.ENABLED
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _installation_type():
|
||||||
|
"""Check if MVT is installed via pip, docker or source."""
|
||||||
|
if "site-packages" in __file__:
|
||||||
|
return "pypi"
|
||||||
|
elif os.environ.get("MVT_DOCKER_IMAGE", None):
|
||||||
|
return "docker"
|
||||||
|
else:
|
||||||
|
return "source"
|
||||||
|
|
||||||
|
def _get_device_properties(self):
|
||||||
|
return {
|
||||||
|
"os_type": platform.system(),
|
||||||
|
"os_version": platform.platform(),
|
||||||
|
"python_version": f"{platform.python_version()}/{platform.python_implementation()}",
|
||||||
|
"mvt_version": MVT_VERSION,
|
||||||
|
"mvt_installation_type": self._installation_type(),
|
||||||
|
"mvt_package_name": __package__,
|
||||||
|
"mvt_command": os.path.basename(sys.argv[0]),
|
||||||
|
"telemetry_version": "0.0.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
def _build_event(self, event_name, event_properties):
|
||||||
|
return {
|
||||||
|
"event": event_name,
|
||||||
|
"distinct_id": self.device_id,
|
||||||
|
"properties": {
|
||||||
|
**self._get_device_properties(),
|
||||||
|
**event_properties,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def _send_event(self, event):
|
||||||
|
if not self.is_telemetry_enabled():
|
||||||
|
# Telemetry is disabled. Do not send any data.
|
||||||
|
return
|
||||||
|
|
||||||
|
event_json = json.dumps(event)
|
||||||
|
|
||||||
|
try:
|
||||||
|
telemetry_thread = threading.Thread(
|
||||||
|
target=self._send_event_thread, args=(event_json,)
|
||||||
|
)
|
||||||
|
telemetry_thread.start()
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Failed to send telemetry data in a thread: {e}")
|
||||||
|
|
||||||
|
def _send_event_thread(self, event):
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
self.endpoint,
|
||||||
|
data=json.dumps(event),
|
||||||
|
timeout=5,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": f"mvt/{MVT_VERSION}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
except requests.RequestException as e:
|
||||||
|
logger.debug(f"Failed to send telemetry data: {e}")
|
||||||
|
|
||||||
|
def send_cli_command_event(self, command_name):
|
||||||
|
event = self._build_event(
|
||||||
|
event_name="run_mvt_cli_command",
|
||||||
|
event_properties={"cli_command_name": command_name},
|
||||||
|
)
|
||||||
|
self._send_event(event)
|
||||||
|
|
||||||
|
def send_module_detections_event(self, module_name, detections):
|
||||||
|
event = self._build_event(
|
||||||
|
event_name="module_detections",
|
||||||
|
event_properties={"module_name": module_name, "detections": detections},
|
||||||
|
)
|
||||||
|
self._send_event(event)
|
||||||
|
|
||||||
|
|
||||||
|
telemetry = Telemetry()
|
||||||
@@ -10,12 +10,34 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import click
|
||||||
from typing import Any, Iterator, Union
|
from typing import Any, Iterator, Union
|
||||||
|
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
|
from mvt.common.telemetry import telemetry
|
||||||
from mvt.common.config import settings
|
from mvt.common.config import settings
|
||||||
|
|
||||||
|
|
||||||
|
class CommandWrapperGroup(click.Group):
|
||||||
|
"""Allow hooks to run before and after MVT CLI commands"""
|
||||||
|
|
||||||
|
def add_command(self, cmd, name=None):
|
||||||
|
click.Group.add_command(self, cmd, name=name)
|
||||||
|
cmd.invoke = self.build_command_invoke(cmd.invoke)
|
||||||
|
|
||||||
|
def build_command_invoke(self, original_invoke):
|
||||||
|
def command_invoke(ctx):
|
||||||
|
"""Invoke the Click command"""
|
||||||
|
|
||||||
|
# Run telemetry before the command
|
||||||
|
telemetry.send_cli_command_event(ctx.command.name)
|
||||||
|
|
||||||
|
# Run the original command
|
||||||
|
original_invoke(ctx)
|
||||||
|
|
||||||
|
return command_invoke
|
||||||
|
|
||||||
|
|
||||||
class CustomJSONEncoder(json.JSONEncoder):
|
class CustomJSONEncoder(json.JSONEncoder):
|
||||||
"""
|
"""
|
||||||
Custom JSON encoder to handle non-standard types.
|
Custom JSON encoder to handle non-standard types.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from mvt.common.utils import (
|
|||||||
generate_hashes_from_path,
|
generate_hashes_from_path,
|
||||||
init_logging,
|
init_logging,
|
||||||
set_verbose_logging,
|
set_verbose_logging,
|
||||||
|
CommandWrapperGroup,
|
||||||
)
|
)
|
||||||
from mvt.common.help import (
|
from mvt.common.help import (
|
||||||
HELP_MSG_VERSION,
|
HELP_MSG_VERSION,
|
||||||
@@ -68,7 +69,7 @@ def _get_disable_flags(ctx):
|
|||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Main
|
# Main
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
@click.group(invoke_without_command=False)
|
@click.group(invoke_without_command=False, cls=CommandWrapperGroup)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--disable-update-check", is_flag=True, help=HELP_MSG_DISABLE_UPDATE_CHECK
|
"--disable-update-check", is_flag=True, help=HELP_MSG_DISABLE_UPDATE_CHECK
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1156,6 +1156,10 @@
|
|||||||
"version": "18.7",
|
"version": "18.7",
|
||||||
"build": "22H20"
|
"build": "22H20"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"version": "18.7.2",
|
||||||
|
"build": "22H124"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "26",
|
"version": "26",
|
||||||
"build": "23A341"
|
"build": "23A341"
|
||||||
|
|||||||
Reference in New Issue
Block a user