From 7b12bb95f77d5014df89070c69102f50f7dd66ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Sun, 1 Jun 2025 23:48:21 +0200 Subject: [PATCH 01/10] Add support for the new Compiler options I.e. `output_format`, `bundle_format`, and `type_check`. --- frida/_frida/extension.c | 62 +++++++++++++++++++++++++++++++++------- frida/core.py | 24 ++++++++++++++-- 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index ee5b9ce..1be4a63 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -500,8 +500,8 @@ static void frida_python_authentication_service_do_authenticate (GTask * task, F static int PyCompiler_init (PyCompiler * self, PyObject * args, PyObject * kw); static PyObject * PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw); static PyObject * PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw); -static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * source_maps_value, - const gchar * compression_value); +static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * output_format_value, + const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value); static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw); static PyObject * PyFileMonitor_enable (PyFileMonitor * self); @@ -4768,20 +4768,26 @@ static PyObject * PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw) { PyObject * result; - static char * keywords[] = { "entrypoint", "project_root", "source_maps", "compression", NULL }; + static char * keywords[] = + { "entrypoint", "project_root", "output_format", "bundle_format", "type_check", "source_maps", "compression", NULL }; const char * entrypoint; const char * project_root = NULL; + const char * output_format = NULL; + const char * bundle_format = NULL; + const char * type_check = NULL; const char * source_maps = NULL; const char * compression = NULL; FridaBuildOptions * options; GError * error = NULL; gchar * bundle; - if (!PyArg_ParseTupleAndKeywords (args, kw, "s|sss", keywords, &entrypoint, &project_root, &source_maps, &compression)) + if (!PyArg_ParseTupleAndKeywords (args, kw, "s|ssssss", keywords, &entrypoint, &project_root, &output_format, &bundle_format, &type_check, + &source_maps, &compression)) return NULL; options = frida_build_options_new (); - if (!PyCompiler_set_options (FRIDA_COMPILER_OPTIONS (options), project_root, source_maps, compression)) + if (!PyCompiler_set_options (FRIDA_COMPILER_OPTIONS (options), project_root, output_format, bundle_format, type_check, source_maps, + compression)) goto invalid_option_value; Py_BEGIN_ALLOW_THREADS @@ -4808,19 +4814,25 @@ PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw) static PyObject * PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw) { - static char * keywords[] = { "entrypoint", "project_root", "source_maps", "compression", NULL }; + static char * keywords[] = + { "entrypoint", "project_root", "output_format", "bundle_format", "type_check", "source_maps", "compression", NULL }; const char * entrypoint; const char * project_root = NULL; + const char * output_format = NULL; + const char * bundle_format = NULL; + const char * type_check = NULL; const char * source_maps = NULL; const char * compression = NULL; FridaWatchOptions * options; GError * error = NULL; - if (!PyArg_ParseTupleAndKeywords (args, kw, "s|sss", keywords, &entrypoint, &project_root, &source_maps, &compression)) + if (!PyArg_ParseTupleAndKeywords (args, kw, "s|ssssss", keywords, &entrypoint, &project_root, &output_format, &bundle_format, &type_check, + &source_maps, &compression)) return NULL; options = frida_watch_options_new (); - if (!PyCompiler_set_options (FRIDA_COMPILER_OPTIONS (options), project_root, source_maps, compression)) + if (!PyCompiler_set_options (FRIDA_COMPILER_OPTIONS (options), project_root, output_format, bundle_format, type_check, source_maps, + compression)) goto invalid_option_value; Py_BEGIN_ALLOW_THREADS @@ -4842,12 +4854,42 @@ PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw) } static gboolean -PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * source_maps_value, - const gchar * compression_value) +PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * output_format_value, + const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value) { if (project_root_value != NULL) frida_compiler_options_set_project_root (options, project_root_value); + if (output_format_value != NULL) + { + FridaOutputFormat output_format; + + if (!PyGObject_unmarshal_enum (output_format_value, FRIDA_TYPE_OUTPUT_FORMAT, &output_format)) + return FALSE; + + frida_compiler_options_set_output_format (options, output_format); + } + + if (bundle_format_value != NULL) + { + FridaBundleFormat bundle_format; + + if (!PyGObject_unmarshal_enum (bundle_format_value, FRIDA_TYPE_BUNDLE_FORMAT, &bundle_format)) + return FALSE; + + frida_compiler_options_set_bundle_format (options, bundle_format); + } + + if (type_check_value != NULL) + { + FridaTypeCheckMode type_check; + + if (!PyGObject_unmarshal_enum (type_check_value, FRIDA_TYPE_TYPE_CHECK_MODE, &type_check)) + return FALSE; + + frida_compiler_options_set_type_check (options, type_check); + } + if (source_maps_value != NULL) { FridaSourceMaps source_maps; diff --git a/frida/core.py b/frida/core.py index 0c65155..a9933ee 100644 --- a/frida/core.py +++ b/frida/core.py @@ -1567,10 +1567,20 @@ def build( self, entrypoint: str, project_root: Optional[str] = None, + output_format: Optional[str] = None, + bundle_format: Optional[str] = None, + type_check: Optional[str] = None, source_maps: Optional[str] = None, compression: Optional[str] = None, ) -> str: - kwargs = {"project_root": project_root, "source_maps": source_maps, "compression": compression} + kwargs = { + "project_root": project_root, + "output_format": output_format, + "bundle_format": bundle_format, + "type_check": type_check, + "source_maps": source_maps, + "compression": compression, + } _filter_missing_kwargs(kwargs) return self._impl.build(entrypoint, **kwargs) @@ -1579,10 +1589,20 @@ def watch( self, entrypoint: str, project_root: Optional[str] = None, + output_format: Optional[str] = None, + bundle_format: Optional[str] = None, + type_check: Optional[str] = None, source_maps: Optional[str] = None, compression: Optional[str] = None, ) -> None: - kwargs = {"project_root": project_root, "source_maps": source_maps, "compression": compression} + kwargs = { + "project_root": project_root, + "output_format": output_format, + "bundle_format": bundle_format, + "type_check": type_check, + "source_maps": source_maps, + "compression": compression, + } _filter_missing_kwargs(kwargs) return self._impl.watch(entrypoint, **kwargs) From e9a9e4bc0243b945a426beb537c2431a6c0766c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 18 Jun 2025 17:47:20 +0200 Subject: [PATCH 02/10] Add PackageManager bindings --- frida/__init__.py | 1 + frida/_frida/__init__.pyi | 74 ++++++++ frida/_frida/extension.c | 351 ++++++++++++++++++++++++++++++++++++++ frida/core.py | 78 +++++++++ 4 files changed, 504 insertions(+) diff --git a/frida/__init__.py b/frida/__init__.py index a8af9ae..483a51b 100644 --- a/frida/__init__.py +++ b/frida/__init__.py @@ -23,6 +23,7 @@ PortalService = core.PortalService EndpointParameters = core.EndpointParameters Compiler = core.Compiler +PackageManager = core.PackageManager FileMonitor = _frida.FileMonitor Cancellable = core.Cancellable diff --git a/frida/_frida/__init__.pyi b/frida/_frida/__init__.pyi index c2d3a9b..b5abab1 100644 --- a/frida/_frida/__init__.pyi +++ b/frida/_frida/__init__.pyi @@ -774,4 +774,78 @@ class Compiler(Object): """ ... +class PackageManager(Object): + def search( + self, + query: str, + offset: Optional[int] = None, + limit: Optional[int] = None, + ) -> PackageSearchResult: + """ + Search for packages to install. + """ + ... + + def install( + self, + project_root: Optional[str] = None, + specs: Optional[Sequence[str]] = None, + ) -> PackageInstallResult: + """ + Install one or more packages. + """ + ... + +class Package(Object): + @property + def name(self) -> str: + """ + Package name. + """ + ... + + @property + def version(self) -> str: + """ + Package version. + """ + ... + + @property + def description(self) -> Optional[str]: + """ + Package description. + """ + ... + + @property + def url(self) -> Optional[str]: + """ + Package URL. + """ + ... + +class PackageSearchResult(Object): + @property + def packages(self) -> List[Package]: + """ + Batch of matching packages. + """ + ... + + @property + def total(self) -> int: + """ + Total matching packages. + """ + ... + +class PackageInstallResult(Object): + @property + def packages(self) -> List[Package]: + """ + The toplevel packages that are installed. + """ + ... + __version__: str diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index 1be4a63..c80a02d 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -145,6 +145,10 @@ typedef struct _PyPortalMembership PyPortalMembership; typedef struct _PyPortalService PyPortalService; typedef struct _PyEndpointParameters PyEndpointParameters; typedef struct _PyCompiler PyCompiler; +typedef struct _PyPackageManager PyPackageManager; +typedef struct _PyPackage PyPackage; +typedef struct _PyPackageSearchResult PyPackageSearchResult; +typedef struct _PyPackageInstallResult PyPackageInstallResult; typedef struct _PyFileMonitor PyFileMonitor; typedef struct _PyIOStream PyIOStream; typedef struct _PyCancellable PyCancellable; @@ -298,6 +302,33 @@ struct _PyCompiler PyGObject parent; }; +struct _PyPackageManager +{ + PyGObject parent; +}; + +struct _PyPackage +{ + PyGObject parent; + PyObject * name; + PyObject * version; + PyObject * description; + PyObject * url; +}; + +struct _PyPackageSearchResult +{ + PyGObject parent; + PyObject * packages; + guint total; +}; + +struct _PyPackageInstallResult +{ + PyGObject parent; + PyObject * packages; +}; + struct _PyFileMonitor { PyGObject parent; @@ -503,6 +534,26 @@ static PyObject * PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * output_format_value, const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value); +static int PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw); +static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw); +static PyObject * PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw); +static FridaPackageInstallOptions * PyPackageManager_parse_install_options (const gchar * project_root, PyObject * specs_value); + +static PyObject * PyPackage_new_take_handle (FridaPackage * handle); +static int PyPackage_init (PyPackage * self, PyObject * args, PyObject * kw); +static void PyPackage_init_from_handle (PyPackage * self, FridaPackage * handle); +static void PyPackage_dealloc (PyPackage * self); + +static PyObject * PyPackageSearchResult_new_take_handle (FridaPackageSearchResult * handle); +static int PyPackageSearchResult_init (PyPackageSearchResult * self, PyObject * args, PyObject * kw); +static void PyPackageSearchResult_init_from_handle (PyPackageSearchResult * self, FridaPackageSearchResult * handle); +static void PyPackageSearchResult_dealloc (PyPackageSearchResult * self); + +static PyObject * PyPackageInstallResult_new_take_handle (FridaPackageInstallResult * handle); +static int PyPackageInstallResult_init (PyPackageInstallResult * self, PyObject * args, PyObject * kw); +static void PyPackageInstallResult_init_from_handle (PyPackageInstallResult * self, FridaPackageInstallResult * handle); +static void PyPackageInstallResult_dealloc (PyPackageInstallResult * self); + static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw); static PyObject * PyFileMonitor_enable (PyFileMonitor * self); static PyObject * PyFileMonitor_disable (PyFileMonitor * self); @@ -725,6 +776,35 @@ static PyMethodDef PyCompiler_methods[] = { NULL } }; +static PyMethodDef PyPackageManager_methods[] = +{ + { "search", (PyCFunction) PyPackageManager_search, METH_VARARGS | METH_KEYWORDS, "Search for packages to install." }, + { "install", (PyCFunction) PyPackageManager_install, METH_VARARGS | METH_KEYWORDS, "Install one or more packages." }, + { NULL } +}; + +static PyMemberDef PyPackage_members[] = +{ + { "name", T_OBJECT_EX, G_STRUCT_OFFSET (PyPackage, name), READONLY, "Package name." }, + { "version", T_OBJECT_EX, G_STRUCT_OFFSET (PyPackage, version), READONLY, "Package version." }, + { "description", T_OBJECT_EX, G_STRUCT_OFFSET (PyPackage, description), READONLY, "Package description." }, + { "url", T_OBJECT_EX, G_STRUCT_OFFSET (PyPackage, url), READONLY, "Package URL." }, + { NULL } +}; + +static PyMemberDef PyPackageSearchResult_members[] = +{ + { "packages", T_OBJECT_EX, G_STRUCT_OFFSET (PyPackageSearchResult, packages), READONLY, "Batch of matching packages." }, + { "total", T_UINT, G_STRUCT_OFFSET (PyPackageSearchResult, total), READONLY, "Total matching packages." }, + { NULL } +}; + +static PyMemberDef PyPackageInstallResult_members[] = +{ + { "packages", T_OBJECT_EX, G_STRUCT_OFFSET (PyPackageInstallResult, packages), READONLY, "The toplevel packages that are installed." }, + { NULL } +}; + static PyMethodDef PyFileMonitor_methods[] = { { "enable", (PyCFunction) PyFileMonitor_enable, METH_NOARGS, "Enable the file monitor." }, @@ -876,6 +956,33 @@ PYFRIDA_DEFINE_TYPE ("_frida.Compiler", Compiler, GObject, NULL, frida_unref, { Py_tp_methods, PyCompiler_methods }, ); +PYFRIDA_DEFINE_TYPE ("_frida.PackageManager", PackageManager, GObject, NULL, frida_unref, + { Py_tp_doc, "Frida Package Manager" }, + { Py_tp_init, PyPackageManager_init }, + { Py_tp_methods, PyPackageManager_methods }, +); + +PYFRIDA_DEFINE_TYPE ("_frida.Package", Package, GObject, PyPackage_init_from_handle, g_object_unref, + { Py_tp_doc, "Frida Package" }, + { Py_tp_init, PyPackage_init }, + { Py_tp_dealloc, PyPackage_dealloc }, + { Py_tp_members, PyPackage_members }, +); + +PYFRIDA_DEFINE_TYPE ("_frida.PackageSearchResult", PackageSearchResult, GObject, PyPackageSearchResult_init_from_handle, g_object_unref, + { Py_tp_doc, "Frida Package Search Result" }, + { Py_tp_init, PyPackageSearchResult_init }, + { Py_tp_dealloc, PyPackageSearchResult_dealloc }, + { Py_tp_members, PyPackageSearchResult_members }, +); + +PYFRIDA_DEFINE_TYPE ("_frida.PackageInstallResult", PackageInstallResult, GObject, PyPackageInstallResult_init_from_handle, g_object_unref, + { Py_tp_doc, "Frida Package Install Result" }, + { Py_tp_init, PyPackageInstallResult_init }, + { Py_tp_dealloc, PyPackageInstallResult_dealloc }, + { Py_tp_members, PyPackageInstallResult_members }, +); + PYFRIDA_DEFINE_TYPE ("_frida.FileMonitor", FileMonitor, GObject, NULL, frida_unref, { Py_tp_doc, "Frida File Monitor" }, { Py_tp_init, PyFileMonitor_init }, @@ -4914,6 +5021,246 @@ PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_ro } +static int +PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw) +{ + if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + PyGObject_take_handle (&self->parent, frida_package_manager_new (), PYFRIDA_TYPE (PackageManager)); + + return 0; +} + +static PyObject * +PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw) +{ + FridaPackageSearchResult * result; + static char * keywords[] = { "query", "offset", "limit", NULL }; + const char * query; + guint offset = G_MAXUINT; + guint limit = G_MAXUINT; + FridaPackageSearchOptions * options; + GError * error = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kw, "s|II", keywords, &query, &offset, &limit)) + return NULL; + + options = frida_package_search_options_new (); + + if (offset != G_MAXUINT) + frida_package_search_options_set_offset (options, offset); + + if (limit != G_MAXUINT) + frida_package_search_options_set_limit (options, limit); + + Py_BEGIN_ALLOW_THREADS + result = frida_package_manager_search_sync (PY_GOBJECT_HANDLE (self), query, options, g_cancellable_get_current (), &error); + Py_END_ALLOW_THREADS + + g_object_unref (options); + + if (error != NULL) + return PyFrida_raise (error); + + return PyPackageSearchResult_new_take_handle (result); +} + +static PyObject * +PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw) +{ + FridaPackageInstallResult * result; + static char * keywords[] = { "project_root", "specs", NULL }; + const char * project_root = NULL; + PyObject * specs = NULL; + FridaPackageInstallOptions * options; + GError * error = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kw, "|sO", keywords, &project_root, &specs)) + return NULL; + + options = PyPackageManager_parse_install_options (project_root, specs); + + Py_BEGIN_ALLOW_THREADS + result = frida_package_manager_install_sync (PY_GOBJECT_HANDLE (self), options, g_cancellable_get_current (), &error); + Py_END_ALLOW_THREADS + + g_object_unref (options); + + if (error != NULL) + return PyFrida_raise (error); + + return PyPackageInstallResult_new_take_handle (result); +} + +static FridaPackageInstallOptions * +PyPackageManager_parse_install_options (const gchar * project_root, PyObject * specs_value) +{ + FridaPackageInstallOptions * options; + + options = frida_package_install_options_new (); + + if (project_root != NULL) + frida_package_install_options_set_project_root (options, project_root); + + if (specs_value != NULL) + { + gint n, i; + + n = PySequence_Size (specs_value); + if (n == -1) + goto propagate_error; + + for (i = 0; i != n; i++) + { + PyObject * element; + gchar * spec = NULL; + + element = PySequence_GetItem (specs_value, i); + if (element == NULL) + goto propagate_error; + PyGObject_unmarshal_string (element, &spec); + Py_DecRef (element); + if (spec == NULL) + goto propagate_error; + + frida_package_install_options_add_spec (options, spec); + } + } + + return options; + +propagate_error: + { + g_object_unref (options); + + return NULL; + } +} + + +static PyObject * +PyPackage_new_take_handle (FridaPackage * handle) +{ + return PyGObject_new_take_handle (handle, PYFRIDA_TYPE (Package)); +} + +static int +PyPackage_init (PyPackage * self, PyObject * args, PyObject * kw) +{ + if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + self->name = NULL; + self->version = NULL; + self->description = NULL; + self->url = NULL; + + return 0; +} + +static void +PyPackage_init_from_handle (PyPackage * self, FridaPackage * handle) +{ + self->name = PyUnicode_FromString (frida_package_get_name (handle)); + self->version = PyUnicode_FromString (frida_package_get_version (handle)); + self->description = PyGObject_marshal_string (frida_package_get_description (handle)); + self->url = PyGObject_marshal_string (frida_package_get_url (handle)); +} + +static void +PyPackage_dealloc (PyPackage * self) +{ + Py_DecRef (self->url); + Py_DecRef (self->description); + Py_DecRef (self->version); + Py_DecRef (self->name); + + PyGObject_tp_dealloc ((PyObject *) self); +} + + +static PyObject * +PyPackageList_marshal (FridaPackageList * list) +{ + PyObject * result; + gint n, i; + + n = frida_package_list_size (list); + result = PyList_New (n); + for (i = 0; i != n; i++) + PyList_SetItem (result, i, PyPackage_new_take_handle (frida_package_list_get (list, i))); + + return result; +} + + +static PyObject * +PyPackageSearchResult_new_take_handle (FridaPackageSearchResult * handle) +{ + return PyGObject_new_take_handle (handle, PYFRIDA_TYPE (PackageSearchResult)); +} + +static int +PyPackageSearchResult_init (PyPackageSearchResult * self, PyObject * args, PyObject * kw) +{ + if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + self->packages = NULL; + self->total = 0; + + return 0; +} + +static void +PyPackageSearchResult_init_from_handle (PyPackageSearchResult * self, FridaPackageSearchResult * handle) +{ + self->packages = PyPackageList_marshal (frida_package_search_result_get_packages (handle)); + self->total = frida_package_search_result_get_total (handle); +} + +static void +PyPackageSearchResult_dealloc (PyPackageSearchResult * self) +{ + Py_DecRef (self->packages); + + PyGObject_tp_dealloc ((PyObject *) self); +} + + +static PyObject * +PyPackageInstallResult_new_take_handle (FridaPackageInstallResult * handle) +{ + return PyGObject_new_take_handle (handle, PYFRIDA_TYPE (PackageInstallResult)); +} + +static int +PyPackageInstallResult_init (PyPackageInstallResult * self, PyObject * args, PyObject * kw) +{ + if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) + return -1; + + self->packages = NULL; + + return 0; +} + +static void +PyPackageInstallResult_init_from_handle (PyPackageInstallResult * self, FridaPackageInstallResult * handle) +{ + self->packages = PyPackageList_marshal (frida_package_install_result_get_packages (handle)); +} + +static void +PyPackageInstallResult_dealloc (PyPackageInstallResult * self) +{ + Py_DecRef (self->packages); + + PyGObject_tp_dealloc ((PyObject *) self); +} + + static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw) { @@ -5480,6 +5827,10 @@ PyInit__frida (void) PYFRIDA_REGISTER_TYPE (PortalService, FRIDA_TYPE_PORTAL_SERVICE); PYFRIDA_REGISTER_TYPE (EndpointParameters, FRIDA_TYPE_ENDPOINT_PARAMETERS); PYFRIDA_REGISTER_TYPE (Compiler, FRIDA_TYPE_COMPILER); + PYFRIDA_REGISTER_TYPE (PackageManager, FRIDA_TYPE_PACKAGE_MANAGER); + PYFRIDA_REGISTER_TYPE (Package, FRIDA_TYPE_PACKAGE); + PYFRIDA_REGISTER_TYPE (PackageSearchResult, FRIDA_TYPE_PACKAGE_SEARCH_RESULT); + PYFRIDA_REGISTER_TYPE (PackageInstallResult, FRIDA_TYPE_PACKAGE_INSTALL_RESULT); PYFRIDA_REGISTER_TYPE (FileMonitor, FRIDA_TYPE_FILE_MONITOR); PYFRIDA_REGISTER_TYPE (IOStream, G_TYPE_IO_STREAM); PYFRIDA_REGISTER_TYPE (Cancellable, G_TYPE_CANCELLABLE); diff --git a/frida/core.py b/frida/core.py index a9933ee..c12a900 100644 --- a/frida/core.py +++ b/frida/core.py @@ -1643,6 +1643,84 @@ def off(self, signal: str, callback: Callable[..., Any]) -> None: self._impl.off(signal, callback) +PackageManagerInstallProgressCallback = Callable[ + [ + Literal[ + "initializing", + "preparing-dependencies", + "resolving-package", + "using-lockfile-data", + "metadata-fetched", + "fetching-resource", + "package-already-installed", + "downloading-package", + "package-installed", + "resolving-and-installing-all", + "awaiting-completion", + "dependencies-processed", + "finalizing-manifests", + "complete", + ], + float, + Optional[str], + ], + None, +] + + +class PackageManager: + def __init__(self) -> None: + self._impl = _frida.PackageManager() + + def __repr__(self) -> str: + return repr(self._impl) + + @cancellable + def search( + self, + query: str, + offset: Optional[int] = None, + limit: Optional[int] = None, + ) -> _frida.PackageSearchResult: + kwargs = { + "offset": offset, + "limit": limit, + } + _filter_missing_kwargs(kwargs) + return self._impl.search(query, **kwargs) + + @cancellable + def install( + self, + project_root: Optional[str] = None, + specs: Optional[Sequence[str]] = None, + ) -> _frida.PackageInstallResult: + kwargs: Dict[str, Any] = { + "project_root": project_root, + "specs": specs, + } + _filter_missing_kwargs(kwargs) + return self._impl.install(**kwargs) + + @overload + def on(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None: ... + + @overload + def on(self, signal: str, callback: Callable[..., Any]) -> None: ... + + def on(self, signal: str, callback: Callable[..., Any]) -> None: + self._impl.on(signal, callback) + + @overload + def off(self, signal: Literal["install-progress"], callback: PackageManagerInstallProgressCallback) -> None: ... + + @overload + def off(self, signal: str, callback: Callable[..., Any]) -> None: ... + + def off(self, signal: str, callback: Callable[..., Any]) -> None: + self._impl.off(signal, callback) + + class CancellablePollFD: def __init__(self, cancellable: _Cancellable) -> None: self.handle = cancellable.get_fd() From 486c149afe188fea06d3efe825bc8bbc2de1ab78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 18 Jun 2025 22:47:58 +0200 Subject: [PATCH 03/10] extension: Fix the Compiler docstring --- frida/_frida/extension.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index c80a02d..a9613c8 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -951,7 +951,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.EndpointParameters", EndpointParameters, GObject, N ); PYFRIDA_DEFINE_TYPE ("_frida.Compiler", Compiler, GObject, NULL, frida_unref, - { Py_tp_doc, "Frida File Monitor" }, + { Py_tp_doc, "Frida Compiler" }, { Py_tp_init, PyCompiler_init }, { Py_tp_methods, PyCompiler_methods }, ); From 7a1d62f7576d90c44549c89e3ee5e42d5763f460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 18 Jun 2025 22:48:44 +0200 Subject: [PATCH 04/10] extension: Simplify the Compiler constructor The DeviceManager is no longer needed. --- frida/_frida/extension.c | 7 +------ frida/core.py | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index a9613c8..55aec14 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -4858,15 +4858,10 @@ frida_python_authentication_service_do_authenticate (GTask * task, FridaPythonAu static int PyCompiler_init (PyCompiler * self, PyObject * args, PyObject * kw) { - PyDeviceManager * manager; - if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) return -1; - if (!PyArg_ParseTuple (args, "O!", PYFRIDA_TYPE_OBJECT (DeviceManager), &manager)) - return -1; - - PyGObject_take_handle (&self->parent, frida_compiler_new (PY_GOBJECT_HANDLE (manager)), PYFRIDA_TYPE (Compiler)); + PyGObject_take_handle (&self->parent, frida_compiler_new (NULL), PYFRIDA_TYPE (Compiler)); return 0; } diff --git a/frida/core.py b/frida/core.py index c12a900..b426336 100644 --- a/frida/core.py +++ b/frida/core.py @@ -1557,7 +1557,7 @@ class CompilerDiagnostic(TypedDict): class Compiler: def __init__(self) -> None: - self._impl = _frida.Compiler(get_device_manager()._impl) + self._impl = _frida.Compiler() def __repr__(self) -> str: return repr(self._impl) From e04e93360ecd7328663ca0a753f94caea3683446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Thu, 19 Jun 2025 11:42:24 +0200 Subject: [PATCH 05/10] extension: Add __repr__ to PackageManager types --- frida/_frida/extension.c | 106 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index 55aec14..353fe14 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -535,6 +535,7 @@ static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gc const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value); static int PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw); +static PyObject * PyPackageManager_repr (PyPackageManager * self); static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw); static PyObject * PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw); static FridaPackageInstallOptions * PyPackageManager_parse_install_options (const gchar * project_root, PyObject * specs_value); @@ -543,16 +544,19 @@ static PyObject * PyPackage_new_take_handle (FridaPackage * handle); static int PyPackage_init (PyPackage * self, PyObject * args, PyObject * kw); static void PyPackage_init_from_handle (PyPackage * self, FridaPackage * handle); static void PyPackage_dealloc (PyPackage * self); +static PyObject * PyPackage_repr (PyPackage * self); static PyObject * PyPackageSearchResult_new_take_handle (FridaPackageSearchResult * handle); static int PyPackageSearchResult_init (PyPackageSearchResult * self, PyObject * args, PyObject * kw); static void PyPackageSearchResult_init_from_handle (PyPackageSearchResult * self, FridaPackageSearchResult * handle); static void PyPackageSearchResult_dealloc (PyPackageSearchResult * self); +static PyObject * PyPackageSearchResult_repr (PyPackageSearchResult * self); static PyObject * PyPackageInstallResult_new_take_handle (FridaPackageInstallResult * handle); static int PyPackageInstallResult_init (PyPackageInstallResult * self, PyObject * args, PyObject * kw); static void PyPackageInstallResult_init_from_handle (PyPackageInstallResult * self, FridaPackageInstallResult * handle); static void PyPackageInstallResult_dealloc (PyPackageInstallResult * self); +static PyObject * PyPackageInstallResult_repr (PyPackageInstallResult * self); static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw); static PyObject * PyFileMonitor_enable (PyFileMonitor * self); @@ -959,6 +963,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.Compiler", Compiler, GObject, NULL, frida_unref, PYFRIDA_DEFINE_TYPE ("_frida.PackageManager", PackageManager, GObject, NULL, frida_unref, { Py_tp_doc, "Frida Package Manager" }, { Py_tp_init, PyPackageManager_init }, + { Py_tp_repr, PyPackageManager_repr }, { Py_tp_methods, PyPackageManager_methods }, ); @@ -966,6 +971,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.Package", Package, GObject, PyPackage_init_from_han { Py_tp_doc, "Frida Package" }, { Py_tp_init, PyPackage_init }, { Py_tp_dealloc, PyPackage_dealloc }, + { Py_tp_repr, PyPackage_repr }, { Py_tp_members, PyPackage_members }, ); @@ -973,6 +979,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.PackageSearchResult", PackageSearchResult, GObject, { Py_tp_doc, "Frida Package Search Result" }, { Py_tp_init, PyPackageSearchResult_init }, { Py_tp_dealloc, PyPackageSearchResult_dealloc }, + { Py_tp_repr, PyPackageSearchResult_repr }, { Py_tp_members, PyPackageSearchResult_members }, ); @@ -980,6 +987,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.PackageInstallResult", PackageInstallResult, GObjec { Py_tp_doc, "Frida Package Install Result" }, { Py_tp_init, PyPackageInstallResult_init }, { Py_tp_dealloc, PyPackageInstallResult_dealloc }, + { Py_tp_repr, PyPackageInstallResult_repr }, { Py_tp_members, PyPackageInstallResult_members }, ); @@ -5027,6 +5035,19 @@ PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw) return 0; } +static PyObject * +PyPackageManager_repr (PyPackageManager * self) +{ + PyObject * result; + gchar * repr; + + repr = g_strdup_printf ("PackageManager(registry=\"%s\")", frida_package_manager_get_registry (PY_GOBJECT_HANDLE (self))); + result = PyUnicode_FromString (repr); + g_free (repr); + + return result; +} + static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw) { @@ -5174,6 +5195,43 @@ PyPackage_dealloc (PyPackage * self) PyGObject_tp_dealloc ((PyObject *) self); } +static PyObject * +PyPackage_repr (PyPackage * self) +{ + PyObject * result; + FridaPackage * handle; + GString * repr; + const gchar * description, * url; + + handle = PY_GOBJECT_HANDLE (self); + + repr = g_string_sized_new (256); + + g_string_append_printf (repr, "Package(name=\"%s\", version=\"%s\"", + frida_package_get_name (handle), + frida_package_get_version (handle)); + + description = frida_package_get_description (handle); + if (description != NULL) + { + gchar * escaped = g_strescape (description, NULL); + g_string_append_printf (repr, ", description=\"%s\"", escaped); + g_free (escaped); + } + + url = frida_package_get_url (handle); + if (url != NULL) + g_string_append_printf (repr, ", url=\"%s\"", url); + + g_string_append (repr, ")"); + + result = PyUnicode_FromString (repr->str); + + g_string_free (repr, TRUE); + + return result; +} + static PyObject * PyPackageList_marshal (FridaPackageList * list) @@ -5223,6 +5281,30 @@ PyPackageSearchResult_dealloc (PyPackageSearchResult * self) PyGObject_tp_dealloc ((PyObject *) self); } +static PyObject * +PyPackageSearchResult_repr (PyPackageSearchResult * self) +{ + PyObject * result; + GString * repr; + gint num_packages; + + repr = g_string_new ("PackageSearchResult(packages="); + + num_packages = frida_package_list_size (frida_package_search_result_get_packages (PY_GOBJECT_HANDLE (self))); + if (num_packages != 0) + g_string_append_printf (repr, "[<%u package%s>]", num_packages, (num_packages == 1) ? "" : "s"); + else + g_string_append (repr, "[]"); + + g_string_append_printf (repr, ", total=%u)", self->total); + + result = PyUnicode_FromString (repr->str); + + g_string_free (repr, TRUE); + + return result; +} + static PyObject * PyPackageInstallResult_new_take_handle (FridaPackageInstallResult * handle) @@ -5255,6 +5337,30 @@ PyPackageInstallResult_dealloc (PyPackageInstallResult * self) PyGObject_tp_dealloc ((PyObject *) self); } +static PyObject * +PyPackageInstallResult_repr (PyPackageInstallResult * self) +{ + PyObject * result; + GString * repr; + gint num_packages; + + repr = g_string_new ("PackageInstallResult(packages="); + + num_packages = frida_package_list_size (frida_package_install_result_get_packages (PY_GOBJECT_HANDLE (self))); + if (num_packages != 0) + g_string_append_printf (repr, "[<%u package%s>]", num_packages, (num_packages == 1) ? "" : "s"); + else + g_string_append (repr, "[]"); + + g_string_append (repr, ")"); + + result = PyUnicode_FromString (repr->str); + + g_string_free (repr, TRUE); + + return result; +} + static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw) From 32deb0f4fa9af4f542453d7c711d8a0381bfb029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Thu, 19 Jun 2025 11:48:04 +0200 Subject: [PATCH 06/10] extension: Add missing toplevel counter logic We previously only bumped it when instantiating DeviceManager and PortalService objects. We also need to do it for Compiler, PackageManager, and FileMonitor. Otherwise signal emissions won't work in some applications. --- frida/_frida/extension.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index 353fe14..648c5a9 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -529,12 +529,14 @@ static gchar * frida_python_authentication_service_authenticate_finish (FridaAut static void frida_python_authentication_service_do_authenticate (GTask * task, FridaPythonAuthenticationService * self); static int PyCompiler_init (PyCompiler * self, PyObject * args, PyObject * kw); +static void PyCompiler_dealloc (PyCompiler * self); static PyObject * PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw); static PyObject * PyCompiler_watch (PyCompiler * self, PyObject * args, PyObject * kw); static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gchar * project_root_value, const gchar * output_format_value, const gchar * bundle_format_value, const gchar * type_check_value, const gchar * source_maps_value, const gchar * compression_value); static int PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw); +static void PyPackageManager_dealloc (PyPackageManager * self); static PyObject * PyPackageManager_repr (PyPackageManager * self); static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw); static PyObject * PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw); @@ -559,6 +561,7 @@ static void PyPackageInstallResult_dealloc (PyPackageInstallResult * self); static PyObject * PyPackageInstallResult_repr (PyPackageInstallResult * self); static int PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw); +static void PyFileMonitor_dealloc (PyFileMonitor * self); static PyObject * PyFileMonitor_enable (PyFileMonitor * self); static PyObject * PyFileMonitor_disable (PyFileMonitor * self); @@ -957,12 +960,14 @@ PYFRIDA_DEFINE_TYPE ("_frida.EndpointParameters", EndpointParameters, GObject, N PYFRIDA_DEFINE_TYPE ("_frida.Compiler", Compiler, GObject, NULL, frida_unref, { Py_tp_doc, "Frida Compiler" }, { Py_tp_init, PyCompiler_init }, + { Py_tp_dealloc, PyCompiler_dealloc }, { Py_tp_methods, PyCompiler_methods }, ); PYFRIDA_DEFINE_TYPE ("_frida.PackageManager", PackageManager, GObject, NULL, frida_unref, { Py_tp_doc, "Frida Package Manager" }, { Py_tp_init, PyPackageManager_init }, + { Py_tp_dealloc, PyPackageManager_dealloc }, { Py_tp_repr, PyPackageManager_repr }, { Py_tp_methods, PyPackageManager_methods }, ); @@ -994,6 +999,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.PackageInstallResult", PackageInstallResult, GObjec PYFRIDA_DEFINE_TYPE ("_frida.FileMonitor", FileMonitor, GObject, NULL, frida_unref, { Py_tp_doc, "Frida File Monitor" }, { Py_tp_init, PyFileMonitor_init }, + { Py_tp_dealloc, PyFileMonitor_dealloc }, { Py_tp_methods, PyFileMonitor_methods }, ); @@ -4869,11 +4875,21 @@ PyCompiler_init (PyCompiler * self, PyObject * args, PyObject * kw) if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) return -1; + g_atomic_int_inc (&toplevel_objects_alive); + PyGObject_take_handle (&self->parent, frida_compiler_new (NULL), PYFRIDA_TYPE (Compiler)); return 0; } +static void +PyCompiler_dealloc (PyCompiler * self) +{ + g_atomic_int_dec_and_test (&toplevel_objects_alive); + + PyGObject_tp_dealloc ((PyObject *) self); +} + static PyObject * PyCompiler_build (PyCompiler * self, PyObject * args, PyObject * kw) { @@ -5030,11 +5046,21 @@ PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw) if (PyGObject_tp_init ((PyObject *) self, args, kw) < 0) return -1; + g_atomic_int_inc (&toplevel_objects_alive); + PyGObject_take_handle (&self->parent, frida_package_manager_new (), PYFRIDA_TYPE (PackageManager)); return 0; } +static void +PyPackageManager_dealloc (PyPackageManager * self) +{ + g_atomic_int_dec_and_test (&toplevel_objects_alive); + + PyGObject_tp_dealloc ((PyObject *) self); +} + static PyObject * PyPackageManager_repr (PyPackageManager * self) { @@ -5373,11 +5399,21 @@ PyFileMonitor_init (PyFileMonitor * self, PyObject * args, PyObject * kw) if (!PyArg_ParseTuple (args, "s", &path)) return -1; + g_atomic_int_inc (&toplevel_objects_alive); + PyGObject_take_handle (&self->parent, frida_file_monitor_new (path), PYFRIDA_TYPE (FileMonitor)); return 0; } +static void +PyFileMonitor_dealloc (PyFileMonitor * self) +{ + g_atomic_int_dec_and_test (&toplevel_objects_alive); + + PyGObject_tp_dealloc ((PyObject *) self); +} + static PyObject * PyFileMonitor_enable (PyFileMonitor * self) { From a6c466fccca6e5c0a4ffcc9e70b84d52055f39e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Thu, 19 Jun 2025 12:15:20 +0200 Subject: [PATCH 07/10] extension: Expose PackageManager.registry --- frida/_frida/__init__.pyi | 14 ++++++++++++++ frida/_frida/extension.c | 28 ++++++++++++++++++++++++++++ frida/core.py | 8 ++++++++ 3 files changed, 50 insertions(+) diff --git a/frida/_frida/__init__.pyi b/frida/_frida/__init__.pyi index b5abab1..7e5111f 100644 --- a/frida/_frida/__init__.pyi +++ b/frida/_frida/__init__.pyi @@ -775,6 +775,20 @@ class Compiler(Object): ... class PackageManager(Object): + @property + def registry(self) -> str: + """ + The registry being used. + """ + ... + + @registry.setter + def registry(self, value: str) -> None: + """ + Change the registry to use. + """ + ... + def search( self, query: str, diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index 648c5a9..b5a0295 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -538,6 +538,8 @@ static gboolean PyCompiler_set_options (FridaCompilerOptions * options, const gc static int PyPackageManager_init (PyPackageManager * self, PyObject * args, PyObject * kw); static void PyPackageManager_dealloc (PyPackageManager * self); static PyObject * PyPackageManager_repr (PyPackageManager * self); +static PyObject * PyPackageManager_get_registry (PyPackageManager * self, void * closure); +static int PyPackageManager_set_registry (PyPackageManager * self, PyObject * val, void * closure); static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw); static PyObject * PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw); static FridaPackageInstallOptions * PyPackageManager_parse_install_options (const gchar * project_root, PyObject * specs_value); @@ -783,6 +785,12 @@ static PyMethodDef PyCompiler_methods[] = { NULL } }; +static PyGetSetDef PyPackageManager_getset[] = +{ + { "registry", (getter) PyPackageManager_get_registry, (setter) PyPackageManager_set_registry, "The registry to use.", NULL }, + { NULL } +}; + static PyMethodDef PyPackageManager_methods[] = { { "search", (PyCFunction) PyPackageManager_search, METH_VARARGS | METH_KEYWORDS, "Search for packages to install." }, @@ -969,6 +977,7 @@ PYFRIDA_DEFINE_TYPE ("_frida.PackageManager", PackageManager, GObject, NULL, fri { Py_tp_init, PyPackageManager_init }, { Py_tp_dealloc, PyPackageManager_dealloc }, { Py_tp_repr, PyPackageManager_repr }, + { Py_tp_getset, PyPackageManager_getset }, { Py_tp_methods, PyPackageManager_methods }, ); @@ -5074,6 +5083,25 @@ PyPackageManager_repr (PyPackageManager * self) return result; } +static PyObject * +PyPackageManager_get_registry (PyPackageManager * self, void * closure) +{ + return PyUnicode_FromString (frida_package_manager_get_registry (PY_GOBJECT_HANDLE (self))); +} + +static int +PyPackageManager_set_registry (PyPackageManager * self, PyObject * val, void * closure) +{ + gchar * registry; + + if (!PyGObject_unmarshal_string (val, ®istry)) + return -1; + frida_package_manager_set_registry (PY_GOBJECT_HANDLE (self), registry); + g_free (registry); + + return 0; +} + static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw) { diff --git a/frida/core.py b/frida/core.py index b426336..b183b7a 100644 --- a/frida/core.py +++ b/frida/core.py @@ -1675,6 +1675,14 @@ def __init__(self) -> None: def __repr__(self) -> str: return repr(self._impl) + @property + def registry(self): + return self._impl.registry + + @registry.setter + def registry(self, value): + self._impl.registry = value + @cancellable def search( self, From c362630443fe7d49568dd3fdfafe66b320ff8e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Fri, 20 Jun 2025 11:48:08 +0200 Subject: [PATCH 08/10] package-manager: Remove unused install phase --- frida/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frida/core.py b/frida/core.py index b183b7a..3c0dfe3 100644 --- a/frida/core.py +++ b/frida/core.py @@ -1656,7 +1656,6 @@ def off(self, signal: str, callback: Callable[..., Any]) -> None: "downloading-package", "package-installed", "resolving-and-installing-all", - "awaiting-completion", "dependencies-processed", "finalizing-manifests", "complete", From a2491bc4ca6555f1235e33decbdfbdadae1c3f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Tue, 1 Jul 2025 21:13:14 +0200 Subject: [PATCH 09/10] package-manager: Update to the new API --- frida/_frida/__init__.pyi | 6 ++++- frida/_frida/extension.c | 52 +++++++++++++++++++++++++++++++++++---- frida/core.py | 9 ++++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/frida/_frida/__init__.pyi b/frida/_frida/__init__.pyi index 7e5111f..23b4e5b 100644 --- a/frida/_frida/__init__.pyi +++ b/frida/_frida/__init__.pyi @@ -1,4 +1,4 @@ -from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union +from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Union # Exceptions class AddressInUseError(Exception): ... @@ -774,6 +774,8 @@ class Compiler(Object): """ ... +PackageRole = Literal["runtime", "development", "optional", "peer"] + class PackageManager(Object): @property def registry(self) -> str: @@ -803,7 +805,9 @@ class PackageManager(Object): def install( self, project_root: Optional[str] = None, + role: Optional[PackageRole] = None, specs: Optional[Sequence[str]] = None, + omits: Optional[Sequence[PackageRole]] = None, ) -> PackageInstallResult: """ Install one or more packages. diff --git a/frida/_frida/extension.c b/frida/_frida/extension.c index b5a0295..218238e 100644 --- a/frida/_frida/extension.c +++ b/frida/_frida/extension.c @@ -542,7 +542,8 @@ static PyObject * PyPackageManager_get_registry (PyPackageManager * self, void * static int PyPackageManager_set_registry (PyPackageManager * self, PyObject * val, void * closure); static PyObject * PyPackageManager_search (PyPackageManager * self, PyObject * args, PyObject * kw); static PyObject * PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw); -static FridaPackageInstallOptions * PyPackageManager_parse_install_options (const gchar * project_root, PyObject * specs_value); +static FridaPackageInstallOptions * PyPackageManager_parse_install_options (const gchar * project_root, const char * role_value, + PyObject * specs_value, PyObject * omits_value); static PyObject * PyPackage_new_take_handle (FridaPackage * handle); static int PyPackage_init (PyPackage * self, PyObject * args, PyObject * kw); @@ -5140,16 +5141,18 @@ static PyObject * PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * kw) { FridaPackageInstallResult * result; - static char * keywords[] = { "project_root", "specs", NULL }; + static char * keywords[] = { "project_root", "role", "specs", "omits", NULL }; const char * project_root = NULL; + const char * role_value = NULL; PyObject * specs = NULL; + PyObject * omits = NULL; FridaPackageInstallOptions * options; GError * error = NULL; - if (!PyArg_ParseTupleAndKeywords (args, kw, "|sO", keywords, &project_root, &specs)) + if (!PyArg_ParseTupleAndKeywords (args, kw, "|ssOO", keywords, &project_root, &role_value, &specs, &omits)) return NULL; - options = PyPackageManager_parse_install_options (project_root, specs); + options = PyPackageManager_parse_install_options (project_root, role_value, specs, omits); Py_BEGIN_ALLOW_THREADS result = frida_package_manager_install_sync (PY_GOBJECT_HANDLE (self), options, g_cancellable_get_current (), &error); @@ -5164,7 +5167,7 @@ PyPackageManager_install (PyPackageManager * self, PyObject * args, PyObject * k } static FridaPackageInstallOptions * -PyPackageManager_parse_install_options (const gchar * project_root, PyObject * specs_value) +PyPackageManager_parse_install_options (const gchar * project_root, const char * role_value, PyObject * specs_value, PyObject * omits_value) { FridaPackageInstallOptions * options; @@ -5173,6 +5176,16 @@ PyPackageManager_parse_install_options (const gchar * project_root, PyObject * s if (project_root != NULL) frida_package_install_options_set_project_root (options, project_root); + if (role_value != NULL) + { + FridaPackageRole role; + + if (!PyGObject_unmarshal_enum (role_value, FRIDA_TYPE_PACKAGE_ROLE, &role)) + goto propagate_error; + + frida_package_install_options_set_role (options, role); + } + if (specs_value != NULL) { gint n, i; @@ -5198,6 +5211,35 @@ PyPackageManager_parse_install_options (const gchar * project_root, PyObject * s } } + if (omits_value != NULL) + { + gint n, i; + + n = PySequence_Size (omits_value); + if (n == -1) + goto propagate_error; + + for (i = 0; i != n; i++) + { + PyObject * element; + gchar * str = NULL; + FridaPackageRole role; + + element = PySequence_GetItem (omits_value, i); + if (element == NULL) + goto propagate_error; + PyGObject_unmarshal_string (element, &str); + Py_DecRef (element); + if (str == NULL) + goto propagate_error; + + if (!PyGObject_unmarshal_enum (str, FRIDA_TYPE_PACKAGE_ROLE, &role)) + goto propagate_error; + + frida_package_install_options_add_omit (options, role); + } + } + return options; propagate_error: diff --git a/frida/core.py b/frida/core.py index 3c0dfe3..a83c0ca 100644 --- a/frida/core.py +++ b/frida/core.py @@ -46,6 +46,7 @@ ProcessTarget = Union[int, str] Spawn = _frida.Spawn +PackageRole = _frida.PackageRole @dataclasses.dataclass @@ -1649,15 +1650,11 @@ def off(self, signal: str, callback: Callable[..., Any]) -> None: "initializing", "preparing-dependencies", "resolving-package", - "using-lockfile-data", - "metadata-fetched", "fetching-resource", "package-already-installed", "downloading-package", "package-installed", "resolving-and-installing-all", - "dependencies-processed", - "finalizing-manifests", "complete", ], float, @@ -1700,11 +1697,15 @@ def search( def install( self, project_root: Optional[str] = None, + role: Optional[PackageRole] = None, specs: Optional[Sequence[str]] = None, + omits: Optional[Sequence[PackageRole]] = None, ) -> _frida.PackageInstallResult: kwargs: Dict[str, Any] = { "project_root": project_root, + "role": role, "specs": specs, + "omits": omits, } _filter_missing_kwargs(kwargs) return self._impl.install(**kwargs) From 8de70e7d67d5a9639ea0a93ac7a9a167f1f00d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Tue, 1 Jul 2025 21:25:39 +0200 Subject: [PATCH 10/10] package-manager: Fix the PackageRole declaration --- frida/_frida/__init__.pyi | 8 +++----- frida/core.py | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frida/_frida/__init__.pyi b/frida/_frida/__init__.pyi index 23b4e5b..8d1d152 100644 --- a/frida/_frida/__init__.pyi +++ b/frida/_frida/__init__.pyi @@ -1,4 +1,4 @@ -from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Union +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union # Exceptions class AddressInUseError(Exception): ... @@ -774,8 +774,6 @@ class Compiler(Object): """ ... -PackageRole = Literal["runtime", "development", "optional", "peer"] - class PackageManager(Object): @property def registry(self) -> str: @@ -805,9 +803,9 @@ class PackageManager(Object): def install( self, project_root: Optional[str] = None, - role: Optional[PackageRole] = None, + role: Optional[str] = None, specs: Optional[Sequence[str]] = None, - omits: Optional[Sequence[PackageRole]] = None, + omits: Optional[Sequence[str]] = None, ) -> PackageInstallResult: """ Install one or more packages. diff --git a/frida/core.py b/frida/core.py index a83c0ca..830ccee 100644 --- a/frida/core.py +++ b/frida/core.py @@ -46,7 +46,6 @@ ProcessTarget = Union[int, str] Spawn = _frida.Spawn -PackageRole = _frida.PackageRole @dataclasses.dataclass @@ -1663,6 +1662,8 @@ def off(self, signal: str, callback: Callable[..., Any]) -> None: None, ] +PackageRole = Literal["runtime", "development", "optional", "peer"] + class PackageManager: def __init__(self) -> None: