Compare commits

...

215 Commits

Author SHA1 Message Date
Ole André Vadla Ravnås ee92ba7dea Wire up some more 2026-01-18 11:17:14 +01:00
Ole André Vadla Ravnås 9f0ce44424 Wire up some more 2026-01-18 11:17:14 +01:00
Ole André Vadla Ravnås bbea00ce9f Wire up some more 2026-01-18 11:17:14 +01:00
Ole André Vadla Ravnås 8527e5f830 [WIP] Auto-generate from .gir 2026-01-18 11:17:12 +01:00
Ole André Vadla Ravnås 985410b6ff subprojects: Prepare for release 2026-01-17 08:43:35 +01:00
Ole André Vadla Ravnås 21c7b9ee6a subprojects: Bump outdated 2026-01-17 00:24:37 +01:00
Ole André Vadla Ravnås 7fba1cdc67 subprojects: Bump outdated 2026-01-16 15:32:05 +01:00
Ole André Vadla Ravnås a709856e2a subprojects: Bump outdated 2026-01-16 13:44:50 +01:00
Ole André Vadla Ravnås c3afe6089d submodules: Bump releng 2026-01-16 13:44:49 +01:00
Ole André Vadla Ravnås 6435a78d13 subprojects: Bump outdated 2026-01-15 18:08:16 +01:00
Ole André Vadla Ravnås 09175036ea submodules: Bump releng 2026-01-15 18:08:16 +01:00
Ole André Vadla Ravnås e0c90c5203 subprojects: Bump outdated 2026-01-11 00:48:16 +01:00
Abhi 9f463fb602 Fix regressions reported by mypi and black (#269) 2026-01-07 09:14:51 +01:00
Ole André Vadla Ravnås 9fdee2270f subprojects: Bump outdated 2026-01-06 22:40:32 +01:00
Ole André Vadla Ravnås 6e536a56b1 submodules: Bump releng 2026-01-06 22:40:32 +01:00
Ole André Vadla Ravnås 74925d082e subprojects: Prepare for release 2025-12-15 21:28:40 +01:00
Etienne Maheux bf1245ddb0 typing: Remove generic @overload on handlers
Generic @overload definitions on signal handlers were masking
type-checking errors.
2025-12-15 21:23:57 +01:00
Etienne Maheux 0f247e9439 typing: Improve @cancellable; add flag literals
Refine @cancellable typing to better model control flow and
introduce Literal types for optional Compiler flags to
improve static checking and autocomplete.
2025-12-15 21:23:57 +01:00
Ole André Vadla Ravnås 17aae5fe5c subprojects: Bump outdated 2025-12-15 21:17:51 +01:00
Ole André Vadla Ravnås 477a90534e submodules: Bump releng 2025-12-15 21:17:51 +01:00
Ole André Vadla Ravnås c87cdca293 subprojects: Prepare for release 2025-11-05 18:59:11 +01:00
Ole André Vadla Ravnås 30968b3805 subprojects: Bump outdated 2025-11-05 18:57:30 +01:00
Ole André Vadla Ravnås 5e3f27d0cb subprojects: Prepare for release 2025-11-04 10:30:58 +01:00
Ole André Vadla Ravnås 904461eb01 subprojects: Bump outdated 2025-11-04 10:29:40 +01:00
Ole André Vadla Ravnås dc652faa90 package-manager: Plug leak in specs option parsing 2025-11-04 10:23:37 +01:00
Ole André Vadla Ravnås f5ba22ad36 compiler: Expose platform and externals options 2025-11-04 10:23:00 +01:00
Ole André Vadla Ravnås dccb6810ca subprojects: Prepare for release 2025-11-01 00:38:17 +01:00
Ole André Vadla Ravnås 82441c6d61 subprojects: Bump outdated 2025-11-01 00:36:38 +01:00
Ole André Vadla Ravnås 323dca48c2 subprojects: Prepare for release 2025-10-31 20:24:11 +01:00
Ole André Vadla Ravnås ef71f0fa92 subprojects: Bump outdated 2025-10-31 20:21:50 +01:00
Ole André Vadla Ravnås e92e829f6d subprojects: Prepare for release 2025-10-29 16:48:00 +01:00
Ole André Vadla Ravnås 5793fb5528 subprojects: Bump outdated 2025-10-29 16:45:57 +01:00
Ole André Vadla Ravnås cac6993d87 subprojects: Prepare for release 2025-10-24 15:25:21 +02:00
Ole André Vadla Ravnås 714b7f8626 subprojects: Bump outdated 2025-10-24 15:23:52 +02:00
Ole André Vadla Ravnås ab0b9e98ae submodules: Bump releng 2025-10-24 15:23:52 +02:00
Ole André Vadla Ravnås 19a7fa4f45 subprojects: Prepare for release 2025-10-11 19:22:55 +02:00
Ole André Vadla Ravnås 38552a368a subprojects: Bump outdated 2025-10-11 11:47:08 +02:00
Ole André Vadla Ravnås 38724cab58 subprojects: Bump outdated 2025-10-11 11:09:13 +02:00
Ole André Vadla Ravnås b60d085ad9 subprojects: Bump outdated 2025-10-01 10:53:01 +02:00
Ole André Vadla Ravnås 1a4afbcc62 subprojects: Bump outdated 2025-10-01 10:50:11 +02:00
Ole André Vadla Ravnås 9e15cab647 subprojects: Prepare for release 2025-09-19 17:16:25 +02:00
Ole André Vadla Ravnås 9ef1c9c1f7 subprojects: Bump outdated 2025-09-19 17:14:35 +02:00
Ole André Vadla Ravnås 3da6af4759 subprojects: Prepare for release 2025-09-18 07:39:44 +02:00
Ole André Vadla Ravnås a9075822b1 subprojects: Bump outdated 2025-09-17 22:10:34 +02:00
Ole André Vadla Ravnås 2e61509c04 submodules: Bump releng 2025-09-17 22:10:34 +02:00
Ole André Vadla Ravnås aa9396c6b0 subprojects: Prepare for release 2025-09-15 22:57:06 +02:00
Ole André Vadla Ravnås 6530b2a7d4 subprojects: Bump outdated 2025-09-15 22:12:16 +02:00
Ole André Vadla Ravnås 2d833af062 subprojects: Bump outdated 2025-09-11 10:32:08 +02:00
Ole André Vadla Ravnås 9f6ab2d384 subprojects: Prepare for release 2025-08-20 12:07:22 +02:00
Ole André Vadla Ravnås a005f1bf4c subprojects: Bump outdated 2025-08-20 12:06:15 +02:00
Ole André Vadla Ravnås 59a24aa48f subprojects: Prepare for release 2025-08-12 10:15:48 +02:00
Ole André Vadla Ravnås 782d626419 subprojects: Bump outdated 2025-08-12 09:48:45 +02:00
Ole André Vadla Ravnås 3aa122f4fd subprojects: Prepare for release 2025-08-02 09:42:51 +02:00
Ole André Vadla Ravnås ef315fc0ad subprojects: Bump outdated 2025-08-02 08:53:40 +02:00
Ole André Vadla Ravnås daf93eea54 subprojects: Bump outdated 2025-08-01 20:21:16 +02:00
Ole André Vadla Ravnås 5d02a36906 submodules: Bump releng 2025-08-01 20:21:16 +02:00
Ole André Vadla Ravnås ba8daa423d subprojects: Bump outdated 2025-08-01 18:18:22 +02:00
Ole André Vadla Ravnås afb27bfa7c subprojects: Bump outdated 2025-08-01 15:48:53 +02:00
Ole André Vadla Ravnås 93a201acf2 submodules: Bump releng 2025-08-01 15:48:53 +02:00
Ole André Vadla Ravnås ca1cdad96a subprojects: Prepare for release 2025-07-24 11:16:46 +02:00
Ole André Vadla Ravnås fbc83cc9bf subprojects: Bump outdated 2025-07-24 11:15:23 +02:00
Ole André Vadla Ravnås b838e1df9a subprojects: Prepare for release 2025-07-21 15:06:22 +02:00
Ole André Vadla Ravnås e2409be987 subprojects: Bump outdated 2025-07-21 15:04:50 +02:00
Ole André Vadla Ravnås b061ea43d2 subprojects: Prepare for release 2025-07-18 10:32:24 +02:00
Ole André Vadla Ravnås a50a62999a subprojects: Bump outdated 2025-07-18 10:28:42 +02:00
Ole André Vadla Ravnås 3a47d33ee8 submodules: Bump releng 2025-07-18 10:28:42 +02:00
Ole André Vadla Ravnås ea93d827bb subprojects: Prepare for release 2025-07-03 16:10:18 +02:00
Ole André Vadla Ravnås 8d4c05f664 subprojects: Bump outdated 2025-07-03 16:09:28 +02:00
Ole André Vadla Ravnås 2f78c96622 subprojects: Prepare for release 2025-07-03 12:57:05 +02:00
Ole André Vadla Ravnås 4b5aa28119 subprojects: Bump outdated 2025-07-03 12:55:57 +02:00
Ole André Vadla Ravnås 4f87afa0f1 subprojects: Prepare for release 2025-07-02 12:59:12 +02:00
Ole André Vadla Ravnås 82272945ac subprojects: Bump outdated 2025-07-02 12:56:24 +02:00
Ole André Vadla Ravnås bf496a81d9 subprojects: Prepare for release 2025-07-02 00:09:19 +02:00
Ole André Vadla Ravnås c2dcae3ff4 subprojects: Bump outdated 2025-07-02 00:08:44 +02:00
Ole André Vadla Ravnås 0cb42c47dc subprojects: Prepare for release 2025-07-01 23:40:07 +02:00
Ole André Vadla Ravnås 0e3a9fb551 subprojects: Bump outdated 2025-07-01 23:39:09 +02:00
Ole André Vadla Ravnås 4e16e5c667 package-manager: Fix the PackageRole declaration 2025-07-01 21:25:59 +02:00
Ole André Vadla Ravnås 09d6c7b044 package-manager: Update to the new API 2025-07-01 21:22:01 +02:00
Ole André Vadla Ravnås e11efce5c2 subprojects: Prepare for release 2025-06-27 15:59:55 +02:00
Ole André Vadla Ravnås e174be9998 subprojects: Bump outdated 2025-06-27 15:58:47 +02:00
Ole André Vadla Ravnås eae3d1dc65 subprojects: Bump outdated 2025-06-27 15:50:40 +02:00
Ole André Vadla Ravnås 2d26b94c7d subprojects: Prepare for release 2025-06-23 18:44:30 +02:00
Ole André Vadla Ravnås f396958dfe subprojects: Bump outdated 2025-06-23 18:41:22 +02:00
Ole André Vadla Ravnås 93fb33206f subprojects: Prepare for release 2025-06-20 15:45:37 +02:00
Ole André Vadla Ravnås aed3c1b7bf subprojects: Bump outdated 2025-06-20 15:44:21 +02:00
Ole André Vadla Ravnås 690da0652d package-manager: Remove unused install phase 2025-06-20 11:48:08 +02:00
Ole André Vadla Ravnås bec6221c02 subprojects: Prepare for release 2025-06-20 01:13:59 +02:00
Ole André Vadla Ravnås 53479e1814 subprojects: Bump outdated 2025-06-20 01:12:37 +02:00
Ole André Vadla Ravnås 68bc65ecd4 subprojects: Prepare for release 2025-06-19 23:25:49 +02:00
Ole André Vadla Ravnås 6492081c92 subprojects: Bump outdated 2025-06-19 23:23:57 +02:00
Ole André Vadla Ravnås 262b984e23 subprojects: Prepare for release 2025-06-19 21:03:48 +02:00
Ole André Vadla Ravnås 730ec03652 subprojects: Bump outdated 2025-06-19 21:01:50 +02:00
Ole André Vadla Ravnås 25f96f92d3 subprojects: Bump outdated 2025-06-19 20:19:02 +02:00
Ole André Vadla Ravnås dec23f9ef5 extension: Expose PackageManager.registry 2025-06-19 12:17:09 +02:00
Ole André Vadla Ravnås 906d27bcb7 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.
2025-06-19 11:51:38 +02:00
Ole André Vadla Ravnås b0018c9812 extension: Add __repr__ to PackageManager types 2025-06-19 11:51:38 +02:00
Ole André Vadla Ravnås 5e011e6d64 subprojects: Prepare for release 2025-06-18 23:35:02 +02:00
Ole André Vadla Ravnås b68dda4eb5 subprojects: Bump outdated 2025-06-18 23:33:55 +02:00
Ole André Vadla Ravnås 6fbe238c1a extension: Simplify the Compiler constructor
The DeviceManager is no longer needed.
2025-06-18 22:49:42 +02:00
Ole André Vadla Ravnås 4d750dfe58 extension: Fix the Compiler docstring 2025-06-18 22:49:42 +02:00
Ole André Vadla Ravnås fe1c61ce5d Add PackageManager bindings 2025-06-18 22:49:42 +02:00
Ole André Vadla Ravnås ea91df0d77 subprojects: Prepare for release 2025-06-13 16:28:23 +02:00
Ole André Vadla Ravnås b78ae7555f subprojects: Bump outdated 2025-06-13 16:27:32 +02:00
Ole André Vadla Ravnås b456683f2d subprojects: Prepare for release 2025-06-10 22:09:55 +02:00
Ole André Vadla Ravnås ddfe2b1a3b subprojects: Bump outdated 2025-06-10 22:06:06 +02:00
Ole André Vadla Ravnås 329795dbfc subprojects: Prepare for release 2025-06-07 13:32:31 +02:00
Ole André Vadla Ravnås e9c62fd581 subprojects: Bump outdated 2025-06-07 13:30:37 +02:00
Ole André Vadla Ravnås 40e945107d subprojects: Bump outdated 2025-06-07 11:23:25 +02:00
Ole André Vadla Ravnås 6c27bf0da7 subprojects: Prepare for release 2025-06-06 22:11:42 +02:00
Ole André Vadla Ravnås d37451f3bc subprojects: Bump outdated 2025-06-06 22:10:42 +02:00
Ole André Vadla Ravnås 6d4e4e27ee subprojects: Prepare for release 2025-06-06 14:11:20 +02:00
Ole André Vadla Ravnås 33a9c51387 subprojects: Bump outdated 2025-06-06 13:27:32 +02:00
Ole André Vadla Ravnås 4344eb9220 subprojects: Bump outdated 2025-06-06 12:38:36 +02:00
Ole André Vadla Ravnås 3a94e642d7 subprojects: Prepare for release 2025-06-05 22:05:26 +02:00
Ole André Vadla Ravnås 7a5948a95a subprojects: Bump outdated 2025-06-05 21:11:38 +02:00
Ole André Vadla Ravnås bbe926c606 subprojects: Bump outdated 2025-06-05 19:40:13 +02:00
Ole André Vadla Ravnås b653958fa4 subprojects: Bump outdated 2025-06-05 19:22:52 +02:00
Ole André Vadla Ravnås bca5146b74 subprojects: Bump outdated 2025-06-05 17:02:30 +02:00
Ole André Vadla Ravnås 2bd254702c submodules: Bump releng 2025-06-05 17:02:30 +02:00
Ole André Vadla Ravnås 82ee16d299 subprojects: Bump outdated 2025-06-02 00:10:05 +02:00
Ole André Vadla Ravnås 51501ceacb Add support for the new Compiler options
I.e. `output_format`, `bundle_format`, and `type_check`.
2025-06-01 23:48:37 +02:00
Ole André Vadla Ravnås ef45347385 subprojects: Bump outdated 2025-06-01 11:05:11 +02:00
Ole André Vadla Ravnås 0024f6719a submodules: Bump releng 2025-06-01 11:05:11 +02:00
Ole André Vadla Ravnås 87de091250 subprojects: Prepare for release 2025-05-29 17:32:12 +02:00
Ole André Vadla Ravnås cf4870e13d subprojects: Bump outdated 2025-05-29 17:30:22 +02:00
Ole André Vadla Ravnås 2ac00cb1e2 subprojects: Prepare for release 2025-05-28 23:17:06 +02:00
Ole André Vadla Ravnås dd94c73d4f subprojects: Bump outdated 2025-05-28 23:16:30 +02:00
Ole André Vadla Ravnås 40eb2dae38 subprojects: Prepare for release 2025-05-24 21:03:25 +02:00
Ole André Vadla Ravnås 73004f9598 subprojects: Bump outdated 2025-05-24 21:02:11 +02:00
Ole André Vadla Ravnås a0e9e64346 subprojects: Prepare for release 2025-05-22 21:39:37 +02:00
Ole André Vadla Ravnås 2706e19615 subprojects: Bump outdated 2025-05-22 21:22:51 +02:00
Ole André Vadla Ravnås 6edaf679ac subprojects: Bump outdated 2025-05-22 18:22:49 +02:00
Ole André Vadla Ravnås c2c45ce231 subprojects: Prepare for release 2025-05-20 23:12:16 +02:00
Ole André Vadla Ravnås 0180450178 subprojects: Bump outdated 2025-05-20 23:10:29 +02:00
Ole André Vadla Ravnås e07370158d subprojects: Prepare for release 2025-05-20 22:40:56 +02:00
Ole André Vadla Ravnås f73fdff4ee subprojects: Bump outdated 2025-05-20 22:40:02 +02:00
Ole André Vadla Ravnås b565fa19dc subprojects: Bump outdated 2025-05-20 22:06:51 +02:00
Ole André Vadla Ravnås 58d5ea9e2f submodules: Bump releng 2025-05-20 22:06:51 +02:00
Ole André Vadla Ravnås 91826487e1 subprojects: Prepare for release 2025-05-17 23:48:16 +02:00
Ole André Vadla Ravnås b1abfd53fa subprojects: Bump outdated 2025-05-17 23:47:03 +02:00
Ole André Vadla Ravnås 1afde6cb34 subprojects: Prepare for release 2025-05-17 19:45:41 +02:00
Ole André Vadla Ravnås 6bee5f45f3 subprojects: Bump outdated 2025-05-17 19:10:59 +02:00
Ole André Vadla Ravnås efc1009ece subprojects: Bump outdated 2025-05-17 11:46:46 +02:00
Ole André Vadla Ravnås 3def865cf8 subprojects: Prepare for release 2025-05-14 15:26:52 +02:00
Ole André Vadla Ravnås 3c41862ac5 subprojects: Bump outdated 2025-05-14 15:25:41 +02:00
Ole André Vadla Ravnås 4bd11602d7 subprojects: Bump outdated 2025-05-14 09:40:31 +02:00
Ole André Vadla Ravnås d07c8a16cd submodules: Bump releng 2025-05-14 09:40:31 +02:00
Ole André Vadla Ravnås 4e6d28cba7 subprojects: Prepare for release 2025-05-09 17:43:33 +02:00
Ole André Vadla Ravnås e0562ed0bc subprojects: Bump outdated 2025-05-09 17:42:35 +02:00
Ole André Vadla Ravnås 9dc17772cd subprojects: Prepare for release 2025-05-09 11:56:01 +02:00
Ole André Vadla Ravnås 0f9f4a5da8 subprojects: Bump outdated 2025-05-09 11:55:02 +02:00
Ole André Vadla Ravnås 4a9fb75adf subprojects: Prepare for release 2025-05-08 22:43:18 +02:00
Ole André Vadla Ravnås c37ef15695 subprojects: Bump outdated 2025-05-08 22:41:37 +02:00
Ole André Vadla Ravnås f6ad8a504d subprojects: Prepare for release 2025-05-08 21:31:01 +02:00
Ole André Vadla Ravnås 808e4ab6b5 subprojects: Bump outdated 2025-05-08 20:05:50 +02:00
Ole André Vadla Ravnås 50ee91f63f subprojects: Bump outdated 2025-05-08 17:06:37 +02:00
Ole André Vadla Ravnås 56dc49b5fb subprojects: Prepare for release 2025-04-25 22:36:01 +02:00
Ole André Vadla Ravnås 4cbb5881bd subprojects: Bump outdated 2025-04-25 22:34:39 +02:00
Ole André Vadla Ravnås 6ff0e34ca3 subprojects: Bump outdated 2025-04-17 18:37:11 +02:00
Ole André Vadla Ravnås 4df903dca5 subprojects: Bump outdated 2025-04-17 18:15:50 +02:00
Ole André Vadla Ravnås 6ed81cbfb6 subprojects: Prepare for release 2025-04-17 13:53:50 +02:00
Ole André Vadla Ravnås 98cc4c44bc subprojects: Bump outdated 2025-04-17 13:52:19 +02:00
Ole André Vadla Ravnås 6190b3c57b subprojects: Prepare for release 2025-04-16 20:26:51 +02:00
Ole André Vadla Ravnås 212973bbc1 subprojects: Bump outdated 2025-04-16 20:25:40 +02:00
Ole André Vadla Ravnås 79f7ae1deb subprojects: Bump outdated 2025-04-16 20:16:58 +02:00
Ole André Vadla Ravnås 522366a55e subprojects: Prepare for release 2025-04-14 17:59:52 +02:00
Ole André Vadla Ravnås 8017d10e3e subprojects: Bump outdated 2025-04-14 17:58:34 +02:00
Ole André Vadla Ravnås e78a5fd3b3 subprojects: Prepare for release 2025-04-09 21:50:24 +02:00
Ole André Vadla Ravnås 5cbef2fb1f subprojects: Bump outdated 2025-04-09 21:48:51 +02:00
Ole André Vadla Ravnås 8694918de7 subprojects: Prepare for release 2025-04-07 19:32:49 +02:00
Ole André Vadla Ravnås ab16fe04c5 subprojects: Bump outdated 2025-04-07 19:32:05 +02:00
Ole André Vadla Ravnås a1d1740541 subprojects: Prepare for release 2025-04-07 10:09:01 +02:00
Ole André Vadla Ravnås 09d2a1aa54 subprojects: Bump outdated 2025-04-07 10:08:15 +02:00
Ole André Vadla Ravnås 215669c151 subprojects: Prepare for release 2025-04-05 14:47:05 +02:00
Ole André Vadla Ravnås f7b08f8375 subprojects: Bump outdated 2025-04-05 11:14:26 +02:00
Ole André Vadla Ravnås 133687aafc subprojects: Prepare for release 2025-04-05 11:10:39 +02:00
Ole André Vadla Ravnås 06130770e1 subprojects: Bump outdated 2025-04-05 09:38:46 +02:00
Ole André Vadla Ravnås 2d72d0be57 subprojects: Prepare for release 2025-04-05 08:52:21 +02:00
Ole André Vadla Ravnås d463d7f2f2 subprojects: Bump outdated 2025-04-05 08:51:11 +02:00
Ole André Vadla Ravnås 11613adee6 subprojects: Prepare for release 2025-03-31 21:22:58 +02:00
Ole André Vadla Ravnås 8dc6509929 subprojects: Bump outdated 2025-03-31 20:17:46 +02:00
Ole André Vadla Ravnås 3f8b122ce7 extension: Fix IOStream.read_all() EOS handling 2025-03-30 22:27:27 +02:00
Ole André Vadla Ravnås 29abf88e31 subprojects: Prepare for release 2025-03-21 14:20:56 +01:00
Ole André Vadla Ravnås 5370147e85 subprojects: Bump outdated 2025-03-21 14:19:38 +01:00
Ole André Vadla Ravnås 507917744d subprojects: Prepare for release 2025-03-21 13:57:19 +01:00
Ole André Vadla Ravnås 8f2858fd8d subprojects: Bump outdated 2025-03-20 20:39:04 +01:00
Ole André Vadla Ravnås c2cf7fa951 subprojects: Bump outdated 2025-03-20 17:00:38 +01:00
Ole André Vadla Ravnås 9ff0651481 submodules: Bump releng 2025-03-20 17:00:38 +01:00
Ole André Vadla Ravnås 2674d6ef7d subprojects: Bump outdated 2025-03-19 10:51:49 +01:00
Ole André Vadla Ravnås 5d65919693 submodules: Bump releng 2025-03-19 10:51:49 +01:00
Ole André Vadla Ravnås d453cdd5ba subprojects: Bump outdated 2025-03-18 19:51:22 +01:00
Ole André Vadla Ravnås e8fd88f3d4 submodules: Bump releng 2025-03-18 19:51:22 +01:00
Ole André Vadla Ravnås 414cf0e029 subprojects: Prepare for release 2025-03-13 19:09:44 +01:00
Ole André Vadla Ravnås 76825537e8 subprojects: Bump outdated 2025-03-13 19:08:40 +01:00
Ole André Vadla Ravnås 2ab18cf80f subprojects: Bump outdated 2025-03-13 15:07:51 +01:00
Ole André Vadla Ravnås aaa703436b subprojects: Bump outdated 2025-03-13 14:44:41 +01:00
Ole André Vadla Ravnås 387962ab9d subprojects: Bump outdated 2025-03-13 14:09:34 +01:00
Ole André Vadla Ravnås 97f4c236a6 submodules: Bump releng 2025-03-13 14:09:34 +01:00
Ole André Vadla Ravnås 88cb2c97b8 subprojects: Bump outdated 2025-02-18 11:15:28 +01:00
Ole André Vadla Ravnås ec5035fd96 submodules: Bump releng 2025-02-18 11:15:28 +01:00
Ole André Vadla Ravnås bd883147ed subprojects: Prepare for release 2025-01-27 20:54:34 +01:00
Ole André Vadla Ravnås f7c32b2772 subprojects: Bump outdated 2025-01-27 20:52:06 +01:00
Ole André Vadla Ravnås 68009a8df9 subprojects: Prepare for release 2025-01-23 20:47:04 +01:00
Ole André Vadla Ravnås 85d56a0e45 subprojects: Bump outdated 2025-01-23 20:31:44 +01:00
Ole André Vadla Ravnås 228610a79c subprojects: Prepare for release 2025-01-17 16:49:13 +01:00
Ole André Vadla Ravnås d4b1b6aa8b subprojects: Bump outdated 2025-01-17 16:47:08 +01:00
Ole André Vadla Ravnås 29661c6b3b subprojects: Prepare for release 2025-01-14 19:35:35 +01:00
Ole André Vadla Ravnås d5b2a6fd18 subprojects: Bump outdated 2025-01-14 19:33:30 +01:00
Ole André Vadla Ravnås b862e9ae82 submodules: Bump releng 2025-01-14 19:33:30 +01:00
Ole André Vadla Ravnås 6e6f84969d subprojects: Prepare for release 2025-01-13 22:20:45 +01:00
Ole André Vadla Ravnås d6933eccf3 subprojects: Bump outdated 2025-01-13 22:18:15 +01:00
Ole André Vadla Ravnås 3bee61ffdb subprojects: Prepare for release 2025-01-10 02:04:13 +01:00
Ole André Vadla Ravnås 647e45f8bf subprojects: Bump outdated 2025-01-10 02:02:15 +01:00
Ole André Vadla Ravnås 5b6cfeba8b subprojects: Bump outdated 2025-01-09 23:35:35 +01:00
Ole André Vadla Ravnås c2b8043d8d submodules: Bump releng 2025-01-09 23:35:35 +01:00
30 changed files with 5643 additions and 8201 deletions
-172
View File
@@ -1,172 +0,0 @@
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
try:
from . import _frida
except Exception as ex:
print("")
print("***")
if str(ex).startswith("No module named "):
print("Frida native extension not found")
print("Please check your PYTHONPATH.")
else:
print(f"Failed to load the Frida native extension: {ex}")
print("Please ensure that the extension was compiled correctly")
print("***")
print("")
raise ex
from . import core
__version__: str = _frida.__version__
get_device_manager = core.get_device_manager
Relay = _frida.Relay
PortalService = core.PortalService
EndpointParameters = core.EndpointParameters
Compiler = core.Compiler
FileMonitor = _frida.FileMonitor
Cancellable = core.Cancellable
ServerNotRunningError = _frida.ServerNotRunningError
ExecutableNotFoundError = _frida.ExecutableNotFoundError
ExecutableNotSupportedError = _frida.ExecutableNotSupportedError
ProcessNotFoundError = _frida.ProcessNotFoundError
ProcessNotRespondingError = _frida.ProcessNotRespondingError
InvalidArgumentError = _frida.InvalidArgumentError
InvalidOperationError = _frida.InvalidOperationError
PermissionDeniedError = _frida.PermissionDeniedError
AddressInUseError = _frida.AddressInUseError
TimedOutError = _frida.TimedOutError
NotSupportedError = _frida.NotSupportedError
ProtocolError = _frida.ProtocolError
TransportError = _frida.TransportError
OperationCancelledError = _frida.OperationCancelledError
def query_system_parameters() -> Dict[str, Any]:
"""
Returns a dictionary of information about the host system
"""
return get_local_device().query_system_parameters()
def spawn(
program: Union[str, List[Union[str, bytes]], Tuple[Union[str, bytes]]],
argv: Union[None, List[Union[str, bytes]], Tuple[Union[str, bytes]]] = None,
envp: Optional[Dict[str, str]] = None,
env: Optional[Dict[str, str]] = None,
cwd: Optional[str] = None,
stdio: Optional[str] = None,
**kwargs: Any,
) -> int:
"""
Spawn a process into an attachable state
"""
return get_local_device().spawn(program=program, argv=argv, envp=envp, env=env, cwd=cwd, stdio=stdio, **kwargs)
def resume(target: core.ProcessTarget) -> None:
"""
Resume a process from the attachable state
:param target: the PID or name of the process
"""
get_local_device().resume(target)
def kill(target: core.ProcessTarget) -> None:
"""
Kill a process
:param target: the PID or name of the process
"""
get_local_device().kill(target)
def attach(
target: core.ProcessTarget, realm: Optional[str] = None, persist_timeout: Optional[int] = None
) -> core.Session:
"""
Attach to a process
:param target: the PID or name of the process
"""
return get_local_device().attach(target, realm=realm, persist_timeout=persist_timeout)
def inject_library_file(target: core.ProcessTarget, path: str, entrypoint: str, data: str) -> int:
"""
Inject a library file to a process.
:param target: the PID or name of the process
"""
return get_local_device().inject_library_file(target, path, entrypoint, data)
def inject_library_blob(target: core.ProcessTarget, blob: bytes, entrypoint: str, data: str) -> int:
"""
Inject a library blob to a process
:param target: the PID or name of the process
"""
return get_local_device().inject_library_blob(target, blob, entrypoint, data)
def get_local_device() -> core.Device:
"""
Get the local device
"""
return get_device_manager().get_local_device()
def get_remote_device() -> core.Device:
"""
Get the first remote device in the devices list
"""
return get_device_manager().get_remote_device()
def get_usb_device(timeout: int = 0) -> core.Device:
"""
Get the first device connected over USB in the devices list
"""
return get_device_manager().get_usb_device(timeout)
def get_device(id: Optional[str], timeout: int = 0) -> core.Device:
"""
Get a device by its id
"""
return get_device_manager().get_device(id, timeout)
def get_device_matching(predicate: Callable[[core.Device], bool], timeout: int = 0) -> core.Device:
"""
Get device matching predicate.
:param predicate: a function to filter the devices
:param timeout: operation timeout in seconds
"""
return get_device_manager().get_device_matching(predicate, timeout)
def enumerate_devices() -> List[core.Device]:
"""
Enumerate all the devices from the device manager
"""
return get_device_manager().enumerate_devices()
@core.cancellable
def shutdown() -> None:
"""
Shutdown the main device manager
"""
get_device_manager()._impl.close()
-777
View File
@@ -1,777 +0,0 @@
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
# Exceptions
class AddressInUseError(Exception): ...
class ExecutableNotFoundError(Exception): ...
class ExecutableNotSupportedError(Exception): ...
class ServerNotRunningError(Exception): ...
class TimedOutError(Exception): ...
class TransportError(Exception): ...
class ProcessNotFoundError(Exception): ...
class ProcessNotRespondingError(Exception): ...
class ProtocolError(Exception): ...
class InvalidArgumentError(Exception): ...
class InvalidOperationError(Exception): ...
class NotSupportedError(Exception): ...
class OperationCancelledError(Exception): ...
class PermissionDeniedError(Exception): ...
class Object:
def __init__(self, *args: Any, **kwargs: Any) -> None: ...
def on(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Add a signal handler.
"""
...
def off(self, signal: str, callback: Callable[..., Any]) -> None:
"""
Remove a signal handler.
"""
...
class Application(Object):
@property
def identifier(self) -> str:
"""
Application identifier.
"""
...
@property
def name(self) -> str:
"""
Human-readable application name.
"""
...
@property
def parameters(self) -> Dict[str, Any]:
"""
Parameters.
"""
...
@property
def pid(self) -> int:
"""
Process ID, or 0 if not running.
"""
...
class Bus(Object):
def attach(self) -> None:
"""
Attach to the bus.
"""
...
def post(self, message: str, data: Optional[Union[bytes, str]]) -> None:
"""
Post a JSON-encoded message to the bus.
"""
...
class Cancellable(Object):
def cancel(self) -> None:
"""
Set cancellable to cancelled.
"""
...
def connect(self, callback: Callable[..., Any]) -> int:
"""
Register notification callback.
"""
...
def disconnect(self, handler_id: int) -> None:
"""
Unregister notification callback.
"""
...
@classmethod
def get_current(cls) -> "Cancellable":
"""
Get the top cancellable from the stack.
"""
...
def get_fd(self) -> int:
"""
Get file descriptor for integrating with an event loop.
"""
...
def is_cancelled(self) -> bool:
"""
Query whether cancellable has been cancelled.
"""
...
def pop_current(self) -> None:
"""
Pop cancellable off the cancellable stack.
"""
...
def push_current(self) -> None:
"""
Push cancellable onto the cancellable stack.
"""
...
def raise_if_cancelled(self) -> None:
"""
Raise an exception if cancelled.
"""
...
def release_fd(self) -> None:
"""
Release a resource previously allocated by get_fd().
"""
...
class Child(Object):
@property
def argv(self) -> List[str]:
"""
Argument vector.
"""
...
@property
def envp(self) -> Dict[str, str]:
"""
Environment vector.
"""
...
@property
def identifier(self) -> str:
"""
Application identifier.
"""
...
@property
def origin(self) -> str:
"""
Origin.
"""
...
@property
def parent_pid(self) -> int:
"""
Parent Process ID.
"""
...
@property
def path(self) -> str:
"""
Path of executable.
"""
...
@property
def pid(self) -> int:
"""
Process ID.
"""
...
class Crash(Object):
@property
def parameters(self) -> Dict[str, Any]:
"""
Parameters.
"""
...
@property
def pid(self) -> int:
"""
Process ID.
"""
...
@property
def process_name(self) -> str:
"""
Process name.
"""
...
@property
def report(self) -> str:
"""
Human-readable crash report.
"""
...
@property
def summary(self) -> str:
"""
Human-readable crash summary.
"""
...
class Device(Object):
@property
def id(self) -> Optional[str]:
"""
Device ID.
"""
...
@property
def name(self) -> Optional[str]:
"""
Human-readable device name.
"""
...
@property
def icon(self) -> Optional[Any]:
"""
Icon.
"""
...
@property
def type(self) -> Optional[str]:
"""
Device type. One of: local, remote, usb.
"""
...
@property
def bus(self) -> Optional[Bus]:
"""
Message bus.
"""
...
def attach(self, pid: int, realm: Optional[str] = None, persist_timeout: Optional[int] = None) -> "Session":
"""
Attach to a PID.
"""
...
def disable_spawn_gating(self) -> None:
"""
Disable spawn gating.
"""
...
def enable_spawn_gating(self) -> None:
"""
Enable spawn gating.
"""
...
def enumerate_applications(
self, identifiers: Optional[Sequence[str]] = None, scope: Optional[str] = None
) -> List[Application]:
"""
Enumerate applications.
"""
...
def enumerate_pending_children(self) -> List[Child]:
"""
Enumerate pending children.
"""
...
def enumerate_pending_spawn(self) -> List["Spawn"]:
"""
Enumerate pending spawn.
"""
...
def enumerate_processes(self, pids: Optional[Sequence[int]] = None, scope: Optional[str] = None) -> List[Process]:
"""
Enumerate processes.
"""
...
def get_frontmost_application(self, scope: Optional[str] = None) -> Optional[Application]:
"""
Get details about the frontmost application.
"""
...
def inject_library_blob(self, pid: int, blob_buffer: bytes, entrypoint: str, data: str) -> int:
"""
Inject a library blob to a PID.
"""
...
def inject_library_file(self, pid: int, path: str, entrypoint: str, data: str) -> int:
"""
Inject a library file to a PID.
"""
...
def input(self, pid: int, data: bytes) -> None:
"""
Input data on stdin of a spawned process.
"""
...
def is_lost(self) -> bool:
"""
Query whether the device has been lost.
"""
...
def kill(self, pid: int) -> None:
"""
Kill a PID.
"""
...
def open_channel(self, address: str) -> "IOStream":
"""
Open a device-specific communication channel.
"""
...
def open_service(self, address: str) -> Service:
"""
Open a device-specific service.
"""
...
def unpair(self) -> None:
"""
Unpair device.
"""
...
def query_system_parameters(self) -> Dict[str, Any]:
"""
Returns a dictionary of information about the host system.
"""
...
def resume(self, pid: int) -> None:
"""
Resume a process from the attachable state.
"""
...
def spawn(
self,
program: str,
argv: Union[None, List[Union[str, bytes]], Tuple[Union[str, bytes]]] = None,
envp: Optional[Dict[str, str]] = None,
env: Optional[Dict[str, str]] = None,
cwd: Optional[str] = None,
stdio: Optional[str] = None,
**kwargs: Any,
) -> int:
"""
Spawn a process into an attachable state.
"""
...
class DeviceManager(Object):
def add_remote_device(
self,
address: str,
certificate: Optional[str] = None,
origin: Optional[str] = None,
token: Optional[str] = None,
keepalive_interval: Optional[int] = None,
) -> Device:
"""
Add a remote device.
"""
...
def close(self) -> None:
"""
Close the device manager.
"""
...
def enumerate_devices(self) -> List[Device]:
"""
Enumerate devices.
"""
...
def get_device_matching(self, predicate: Callable[[Device], bool], timeout: int) -> Device:
"""
Get device matching predicate.
"""
...
def remove_remote_device(self, address: str) -> None:
"""
Remove a remote device.
"""
...
class EndpointParameters(Object): ...
class FileMonitor(Object):
def disable(self) -> None:
"""
Disable the file monitor.
"""
...
def enable(self) -> None:
"""
Enable the file monitor.
"""
...
class IOStream(Object):
def close(self) -> None:
"""
Close the stream.
"""
...
def is_closed(self) -> bool:
"""
Query whether the stream is closed.
"""
...
def read(self, size: int) -> bytes:
"""
Read up to the specified number of bytes from the stream.
"""
...
def read_all(self, size: int) -> bytes:
"""
Read exactly the specified number of bytes from the stream.
"""
...
def write(self, data: bytes) -> int:
"""
Write as much as possible of the provided data to the stream.
"""
...
def write_all(self, data: bytes) -> None:
"""
Write all of the provided data to the stream.
"""
...
class PortalMembership(Object):
def terminate(self) -> None:
"""
Terminate the membership.
"""
...
class PortalService(Object):
@property
def device(self) -> Device:
"""
Device for in-process control.
"""
...
def broadcast(self, message: str, data: Optional[Union[str, bytes]] = None) -> None:
"""
Broadcast a message to all control channels.
"""
...
def enumerate_tags(self, connection_id: int) -> List[str]:
"""
Enumerate tags of a specific connection.
"""
...
def kick(self, connection_id: int) -> None:
"""
Kick out a specific connection.
"""
...
def narrowcast(self, tag: str, message: str, data: Optional[Union[str, bytes]] = None) -> None:
"""
Post a message to control channels with a specific tag.
"""
...
def post(self, connection_id: int, message: str, data: Optional[Union[str, bytes]] = None) -> None:
"""
Post a message to a specific control channel.
"""
...
def start(self) -> None:
"""
Start listening for incoming connections.
"""
...
def stop(self) -> None:
"""
Stop listening for incoming connections, and kick any connected clients.
"""
...
def tag(self, connection_id: int, tag: str) -> None:
"""
Tag a specific control channel.
"""
...
def untag(self, connection_id: int, tag: str) -> None:
"""
Untag a specific control channel.
"""
...
class Process(Object):
@property
def pid(self) -> int:
"""
Process ID.
"""
...
@property
def name(self) -> str:
"""
Human-readable process name.
"""
...
@property
def parameters(self) -> Dict[str, Any]:
"""
Parameters.
"""
...
class Relay(Object):
def __init__(self, address: str, username: str, password: str, kind: str) -> None: ...
@property
def address(self) -> str:
"""
Network address or address:port of the TURN server.
"""
...
@property
def kind(self) -> str:
"""
Relay kind. One of: turn-udp, turn-tcp, turn-tls.
"""
...
@property
def password(self) -> str:
"""
The TURN password to use for the allocate request.
"""
...
@property
def username(self) -> str:
"""
The TURN username to use for the allocate request.
"""
...
class Script(Object):
def eternalize(self) -> None:
"""
Eternalize the script.
"""
...
def is_destroyed(self) -> bool:
"""
Query whether the script has been destroyed.
"""
...
def load(self) -> None:
"""
Load the script.
"""
...
def post(self, message: str, data: Optional[Union[str, bytes]] = None) -> None:
"""
Post a JSON-encoded message to the script.
"""
...
def unload(self) -> None:
"""
Unload the script.
"""
...
def enable_debugger(self, port: Optional[int]) -> None:
"""
Enable the Node.js compatible script debugger
"""
...
def disable_debugger(self) -> None:
"""
Disable the Node.js compatible script debugger
"""
...
class Service(Object):
def activate(self) -> None:
"""
Activate the service.
"""
...
def cancel(self) -> None:
"""
Cancel the service.
"""
...
def request(self, parameters: Any) -> Any:
"""
Perform a request.
"""
...
class Session(Object):
@property
def pid(self) -> int:
"""
Process ID.
"""
...
def compile_script(self, source: str, name: Optional[str] = None, runtime: Optional[str] = None) -> bytes:
"""
Compile script source code to bytecode.
"""
...
def create_script(self, source: str, name: Optional[str] = None, runtime: Optional[str] = None) -> Script:
"""
Create a new script.
"""
...
def create_script_from_bytes(
self, data: bytes, name: Optional[str] = None, runtime: Optional[str] = None
) -> Script:
"""
Create a new script from bytecode.
"""
...
def snapshot_script(self, embed_script: str, warmup_script: Optional[str], runtime: Optional[str] = None) -> bytes:
"""
Evaluate script and snapshot the resulting VM state
"""
...
def detach(self) -> None:
"""
Detach session from the process.
"""
...
def disable_child_gating(self) -> None:
"""
Disable child gating.
"""
...
def enable_child_gating(self) -> None:
"""
Enable child gating.
"""
...
def is_detached(self) -> bool:
"""
Query whether the session is detached.
"""
...
def join_portal(
self, address: str, certificate: Optional[str] = None, token: Optional[str] = None, acl: Optional[Any] = None
) -> PortalMembership:
"""
Join a portal.
"""
...
def resume(self) -> None:
"""
Resume session after network error.
"""
...
def setup_peer_connection(
self, stun_server: Optional[str] = None, relays: Optional[Sequence[Relay]] = None
) -> None:
"""
Set up a peer connection with the target process.
"""
...
class Spawn(Object):
@property
def identifier(self) -> str:
"""
Application identifier.
"""
...
@property
def pid(self) -> int:
"""
Process ID.
"""
...
class Compiler(Object):
def build(
self,
entrypoint: str,
project_root: Optional[str] = None,
source_maps: Optional[str] = None,
compression: Optional[str] = None,
) -> str:
"""
Build an agent.
"""
...
def watch(
self,
entrypoint: str,
project_root: Optional[str] = None,
source_maps: Optional[str] = None,
compression: Optional[str] = None,
) -> None:
"""
Continuously build an agent.
"""
...
__version__: str
File diff suppressed because it is too large Load Diff
-21
View File
@@ -1,21 +0,0 @@
py_sources = [
'__init__.pyi',
'py.typed',
]
python.install_sources(py_sources, subdir: 'frida' / '_frida', pure: false)
extra_link_args = []
if host_os_family == 'darwin'
extra_link_args += '-Wl,-exported_symbol,_PyInit__frida'
elif host_os_family != 'windows'
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / 'extension.version'
endif
extension = python.extension_module('_frida', 'extension.c',
limited_api: '3.7',
c_args: frida_component_cflags,
link_args: extra_link_args,
dependencies: [python_dep, frida_core_dep, os_deps],
install: true,
subdir: 'frida',
)
-1747
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
from .cli import main
if __name__ == "__main__":
main()
@@ -0,0 +1 @@
static GHashTable * pygobject_type_spec_by_type;
@@ -0,0 +1,77 @@
static void
PyGObject_class_init (void)
{
pygobject_type_spec_by_type = g_hash_table_new_full (NULL, NULL, NULL, NULL);
}
static int
PyGObject_init (PyGObject * self)
{
self->handle = NULL;
self->type = PYFRIDA_TYPE (GObject);
self->signal_closures = NULL;
return 0;
}
static void
PyGObject_dealloc (PyGObject * self)
{
gpointer handle;
handle = PyGObject_steal_handle (self);
if (handle != NULL)
{
Py_BEGIN_ALLOW_THREADS
self->type->destroy (handle);
Py_END_ALLOW_THREADS
}
((freefunc) PyType_GetSlot (Py_TYPE (self), Py_tp_free)) (self);
}
static void
PyGObject_take_handle (PyGObject * self,
gpointer handle,
const PyGObjectType * type)
{
self->handle = handle;
self->type = type;
if (handle != NULL)
g_object_set_data (G_OBJECT (handle), "pyobject", self);
}
static gpointer
PyGObject_steal_handle (PyGObject * self)
{
gpointer handle = self->handle;
GSList * entry;
if (handle == NULL)
return NULL;
for (entry = self->signal_closures; entry != NULL; entry = entry->next)
{
PyGObjectSignalClosure * closure = entry->data;
G_GNUC_UNUSED guint num_matches;
num_matches = g_signal_handlers_disconnect_matched (handle, G_SIGNAL_MATCH_CLOSURE, closure->signal_id, 0, &closure->parent, NULL, NULL);
g_assert (num_matches == 1);
}
g_clear_pointer (&self->signal_closures, g_slist_free);
g_object_set_data (G_OBJECT (handle), "pyobject", NULL);
self->handle = NULL;
return handle;
}
static void
PyGObject_register_type (GType instance_type,
PyGObjectType * python_type)
{
g_hash_table_insert (pygobject_type_spec_by_type, GSIZE_TO_POINTER (instance_type), python_type);
}
@@ -0,0 +1,5 @@
static void PyGObject_class_init (void);
static int PyGObject_init (PyGObject * self);
static void PyGObject_dealloc (PyGObject * self);
static gpointer PyGObject_steal_handle (PyGObject * self);
static void PyGObject_register_type (GType instance_type, PyGObjectType * python_type);
@@ -0,0 +1,100 @@
type SignalTransformer<
Source extends SignalHandler,
Target extends SignalHandler
> = (...args: Parameters<Source>) => Parameters<Target>;
type SignalInterceptor<H extends SignalHandler> = (...args: Parameters<H>) => boolean;
interface SignalWrapperOptionsNoTransform<H extends SignalHandler> {
transform?: undefined;
intercept?: SignalInterceptor<H>;
}
interface SignalWrapperOptionsTransform<
Source extends SignalHandler,
Target extends SignalHandler
> {
transform: SignalTransformer<Source, Target>;
intercept?: SignalInterceptor<Target>;
}
type SignalWrapperOptions<
Source extends SignalHandler,
Target extends SignalHandler
> =
| SignalWrapperOptionsNoTransform<Source & Target>
| SignalWrapperOptionsTransform<Source, Target>;
class SignalWrapper<
SourceHandler extends SignalHandler,
TargetHandler extends SignalHandler
> {
#source: Signal<SourceHandler>;
#transform?: SignalTransformer<SourceHandler, TargetHandler>;
#intercept?: SignalInterceptor<any>;
#handlers = new Set<TargetHandler>();
constructor(
source: Signal<SourceHandler>,
options?: SignalWrapperOptions<SourceHandler, TargetHandler>
) {
this.#source = source;
if (options === undefined || options.transform === undefined) {
this.#intercept = options?.intercept;
} else {
this.#transform = options.transform;
this.#intercept = options.intercept;
}
}
connect(handler: TargetHandler): void {
this.#handlers.add(handler);
if (this.#handlers.size === 1) {
this.#source.connect(this.#wrappedHandler);
}
}
disconnect(handler: TargetHandler): void {
this.#handlers.delete(handler);
if (this.#handlers.size === 0) {
this.#source.disconnect(this.#wrappedHandler);
}
}
#wrappedHandler = ((...sourceArgs: Parameters<SourceHandler>) => {
let targetArgs: Parameters<TargetHandler>;
const transform = this.#transform;
if (transform === undefined) {
targetArgs = sourceArgs as unknown as Parameters<TargetHandler>;
} else {
targetArgs = transform(...sourceArgs);
}
const intercept = this.#intercept;
if (intercept !== undefined) {
if (!intercept(...targetArgs)) {
return;
}
}
for (const handler of this.#handlers) {
handler(...targetArgs);
}
}) as SourceHandler;
}
function inspectWrapper(object: any, name: string, properties: string[], depth: number, options: util.InspectOptionsStylized): string {
if (depth < 0) {
return options.stylize(`[${name}]`, "special");
}
const summary = Object.fromEntries(properties.map(name => [name, object[name]]));
const nextOptions = Object.assign({}, options, {
depth: (options.depth === null) ? null : depth - 1
});
return name + " " + inspect(summary, nextOptions);
}
@@ -0,0 +1,60 @@
#define PYFRIDA_TYPE(name) \
(&_PYFRIDA_TYPE_VAR (name, type))
#define PYFRIDA_TYPE_OBJECT(name) \
PYFRIDA_TYPE (name)->object
#define _PYFRIDA_TYPE_VAR(name, var) \
G_PASTE (G_PASTE (G_PASTE (Py, name), _), var)
#define PYFRIDA_DEFINE_BASETYPE(pyname, cname, ...) \
_PYFRIDA_DEFINE_TYPE_SLOTS (cname, __VA_ARGS__); \
_PYFRIDA_DEFINE_TYPE_SPEC (cname, pyname, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); \
static PyGObjectType _PYFRIDA_TYPE_VAR (cname, type) = \
{ \
.parent = NULL, \
.object = NULL, \
}
#define PYFRIDA_DEFINE_TYPE(pyname, cname, parent_cname, ...) \
_PYFRIDA_DEFINE_TYPE_SLOTS (cname, __VA_ARGS__); \
_PYFRIDA_DEFINE_TYPE_SPEC (cname, pyname, Py_TPFLAGS_DEFAULT); \
static PyGObjectType _PYFRIDA_TYPE_VAR (cname, type) = \
{ \
.parent = PYFRIDA_TYPE (parent_cname), \
.object = NULL, \
}
#define PYFRIDA_REGISTER_TYPE(cname, gtype) \
G_BEGIN_DECLS \
{ \
PyGObjectType * t = PYFRIDA_TYPE (cname); \
t->object = PyType_FromSpecWithBases (&_PYFRIDA_TYPE_VAR (cname, spec), \
(t->parent != NULL) ? PyTuple_Pack (1, t->parent->object) : NULL); \
PyGObject_register_type (gtype, t); \
Py_IncRef (t->object); \
PyModule_AddObject (module, G_STRINGIFY (cname), t->object); \
} \
G_END_DECLS
#define _PYFRIDA_DEFINE_TYPE_SPEC(cname, pyname, type_flags) \
static PyType_Spec _PYFRIDA_TYPE_VAR (cname, spec) = \
{ \
.name = pyname, \
.basicsize = sizeof (G_PASTE (Py, cname)), \
.itemsize = 0, \
.flags = type_flags, \
.slots = _PYFRIDA_TYPE_VAR (cname, slots), \
}
#define _PYFRIDA_DEFINE_TYPE_SLOTS(cname, ...) \
static PyType_Slot _PYFRIDA_TYPE_VAR (cname, slots)[] = \
{ \
__VA_ARGS__ \
{ 0 }, \
}
#define PY_GOBJECT(o) ((PyGObject *) (o))
#define PY_GOBJECT_HANDLE(o) (PY_GOBJECT (o)->handle)
#define PY_GOBJECT_SIGNAL_CLOSURE(o) ((PyGObjectSignalClosure *) (o))
#define PyFrida_RETURN_NONE \
G_STMT_START \
{ \
Py_IncRef (Py_None); \
return Py_None; \
} \
G_STMT_END
@@ -0,0 +1,78 @@
G_GNUC_UNUSED static gboolean fdn_is_null (napi_env env, napi_value value);
static gboolean fdn_is_undefined_or_null (napi_env env, napi_value value);
static gboolean fdn_is_function (napi_env env, napi_value value);
static gboolean fdn_boolean_from_value (napi_env env, napi_value value, gboolean * b);
static napi_value fdn_boolean_to_value (napi_env env, gboolean b);
static gboolean fdn_size_from_value (napi_env env, napi_value value, gsize * s);
static napi_value fdn_size_to_value (napi_env env, gsize s);
static napi_value fdn_ssize_to_value (napi_env env, gssize s);
static gboolean fdn_int_from_value (napi_env env, napi_value value, gint * i);
static napi_value fdn_int_to_value (napi_env env, gint i);
static gboolean fdn_uint_from_value (napi_env env, napi_value value, guint * u);
static napi_value fdn_uint_to_value (napi_env env, guint u);
static gboolean fdn_uint16_from_value (napi_env env, napi_value value, guint16 * u);
static napi_value fdn_uint16_to_value (napi_env env, guint16 u);
static napi_value fdn_uint32_to_value (napi_env env, guint32 u);
static gboolean fdn_int64_from_value (napi_env env, napi_value value, gint64 * i);
static napi_value fdn_int64_to_value (napi_env env, gint64 i);
static napi_value fdn_uint64_to_value (napi_env env, guint64 u);
static gboolean fdn_ulong_from_value (napi_env env, napi_value value, gulong * u);
static gboolean fdn_double_from_value (napi_env env, napi_value value, gdouble * d);
static napi_value fdn_double_to_value (napi_env env, gdouble d);
static gboolean fdn_enum_from_value (napi_env env, GType enum_type, napi_value value, gint * e);
static napi_value fdn_enum_to_value (napi_env env, GType enum_type, gint e);
static gboolean fdn_utf8_from_value (napi_env env, napi_value value, gchar ** str);
static napi_value fdn_utf8_to_value (napi_env env, const gchar * str);
static gboolean fdn_strv_from_value (napi_env env, napi_value value, gchar *** strv);
static napi_value fdn_strv_to_value (napi_env env, gchar ** strv);
static napi_value fdn_buffer_to_value (napi_env env, const guint8 * data, gsize size);
static gboolean fdn_bytes_from_value (napi_env env, napi_value value, GBytes ** bytes);
static napi_value fdn_bytes_to_value (napi_env env, GBytes * bytes);
static gboolean fdn_vardict_from_value (napi_env env, napi_value value, GHashTable ** vardict);
static napi_value fdn_vardict_to_value (napi_env env, GHashTable * vardict);
static gboolean fdn_variant_from_value (napi_env env, napi_value value, GVariant ** variant);
static napi_value fdn_variant_to_value (napi_env env, GVariant * variant);
static gboolean fdn_gvalue_from_value (napi_env env, GType type, napi_value js_value, GValue * value);
static napi_value fdn_gvalue_to_value (napi_env env, GValue * value);
static gboolean fdn_error_from_value (napi_env env, napi_value value, GError ** error);
static napi_value fdn_error_to_value (napi_env env, GError * error);
static gboolean fdn_file_from_value (napi_env env, napi_value value, GFile ** file);
static napi_value fdn_file_to_value (napi_env env, GFile * file);
static gboolean fdn_tls_certificate_from_value (napi_env env, napi_value value, GTlsCertificate ** certificate);
static napi_value fdn_tls_certificate_to_value (napi_env env, GTlsCertificate * certificate);
static gboolean fdn_options_from_value (napi_env env, GType object_type, napi_value value, gpointer * options);
static napi_value fdn_object_subclass_to_value (napi_env env, GObject * object);
static napi_value fdn_object_new (napi_env env, GObject * handle, napi_ref constructor);
static gboolean fdn_object_wrap (napi_env env, napi_value wrapper, GObject * handle, napi_finalize finalizer);
static gboolean fdn_object_unwrap (napi_env env, napi_value wrapper, GType expected_type, GObject ** handle);
static void fdn_object_finalize (napi_env env, void * finalize_data, void * finalize_hint);
static napi_value fdn_object_get_signal (napi_env env, napi_callback_info info, const gchar * name, const gchar * js_storage_name, FdnSignalBehavior behavior);
static napi_value fdn_signal_new (napi_env env, GObject * handle, const gchar * name, FdnSignalBehavior behavior);
static void fdn_signal_register (napi_env env, napi_value exports);
static napi_value fdn_signal_construct (napi_env env, napi_callback_info info);
static void fdn_signal_finalize (napi_env env, void * finalize_data, void * finalize_hint);
static napi_value fdn_signal_connect (napi_env env, napi_callback_info info);
static napi_value fdn_signal_disconnect (napi_env env, napi_callback_info info);
static void fdn_signal_disconnect_closure (FdnSignal * self, FdnSignalClosure * closure);
static gboolean fdn_signal_parse_arguments (napi_env env, napi_callback_info info, FdnSignal ** self, napi_value * js_self, napi_value * handler);
static FdnSignalClosure * fdn_signal_closure_new (napi_env env, FdnSignal * sig, napi_value js_sig, napi_value handler);
static void fdn_signal_closure_finalize (gpointer data, GClosure * closure);
static void fdn_signal_closure_marshal (GClosure * closure, GValue * return_gvalue, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data);
static void fdn_signal_closure_deliver (napi_env env, napi_value js_cb, void * context, void * data);
static void fdn_keep_alive_until (napi_env env, napi_value js_object, GObject * handle, FdnIsDestroyedFunc is_destroyed, const gchar * destroy_signal_name);
static void fdn_keep_alive_on_finalize (napi_env env, void * finalize_data, void * finalize_hint);
static void fdn_keep_alive_on_destroy_signal (GObject * handle, gpointer user_data);
static void fdn_keep_alive_on_destroy_signal_handler_detached (gpointer data, GClosure * closure);
static void fdn_keep_alive_schedule_cleanup (FdnKeepAliveContext * context);
static void fdn_keep_alive_on_tsfn_invoke (napi_env env, napi_value js_cb, void * context, void * data);
static void fdn_inherit_val_val (napi_env env, napi_value sub_ctor, napi_value super_ctor, napi_value object_ctor, napi_value set_proto);
G_GNUC_UNUSED static void fdn_inherit_val_ref (napi_env env, napi_value sub_ctor, napi_ref super_ctor, napi_value object_ctor, napi_value set_proto);
static void fdn_inherit_ref_val (napi_env env, napi_ref sub_ctor, napi_value super_ctor, napi_value object_ctor, napi_value set_proto);
static void fdn_inherit_ref_ref (napi_env env, napi_ref sub_ctor, napi_ref super_ctor, napi_value object_ctor, napi_value set_proto);
static gchar * fdn_camel_case_to_kebab_case (const gchar * name);
@@ -0,0 +1,24 @@
struct _PyGObject
{
PyObject_HEAD
gpointer handle;
const PyGObjectType * type;
GSList * signal_closures;
};
struct _PyGObjectType
{
PyGObjectType * parent;
PyObject * object;
PyGObjectInitFromHandleFunc init_from_handle;
GDestroyNotify destroy;
};
struct _PyGObjectSignalClosure
{
GClosure parent;
guint signal_id;
guint max_arg_count;
};
@@ -0,0 +1,4 @@
typedef struct _PyGObject PyGObject;
typedef void (* PyGObjectInitFromHandleFunc) (PyObject * self, gpointer handle);
typedef struct _PyGObjectType PyGObjectType;
typedef struct _PyGObjectSignalClosure PyGObjectSignalClosure;
@@ -0,0 +1,13 @@
querySystemParameters
spawn
resume
kill
attach
injectLibraryFile
injectLibraryBlob
enumerateDevices
getDeviceManager
getLocalDevice
getRemoteDevice
getUsbDevice
getDevice
@@ -0,0 +1,157 @@
let sharedDeviceManager: DeviceManager | null = null;
export async function querySystemParameters(cancellable?: Cancellable | null): Promise<SystemParameters> {
const device = await getLocalDevice(cancellable);
return await device.querySystemParameters(cancellable);
}
export async function spawn(program: string | string[], options?: SpawnOptions, cancellable?: Cancellable | null): Promise<number> {
const device = await getLocalDevice(cancellable);
return await device.spawn(program, options, cancellable);
}
export async function resume(target: TargetProcess, cancellable?: Cancellable | null): Promise<void> {
const device = await getLocalDevice(cancellable);
await device.resume(target, cancellable);
}
export async function kill(target: TargetProcess, cancellable?: Cancellable | null): Promise<void> {
const device = await getLocalDevice(cancellable);
await device.kill(target, cancellable);
}
export async function attach(target: TargetProcess, options?: SessionOptions, cancellable?: Cancellable | null): Promise<Session> {
const device = await getLocalDevice(cancellable);
return await device.attach(target, options, cancellable);
}
export async function injectLibraryFile(target: TargetProcess, path: string, entrypoint: string, data: string,
cancellable?: Cancellable | null): Promise<number> {
const device = await getLocalDevice(cancellable);
return await device.injectLibraryFile(target, path, entrypoint, data, cancellable);
}
export async function injectLibraryBlob(target: TargetProcess, blob: Buffer, entrypoint: string, data: string,
cancellable?: Cancellable | null): Promise<number> {
const device = await getLocalDevice(cancellable);
return await device.injectLibraryBlob(target, blob, entrypoint, data, cancellable);
}
export async function enumerateDevices(cancellable?: Cancellable | null): Promise<Device[]> {
const deviceManager = getDeviceManager();
return await deviceManager.enumerateDevices(cancellable);
};
export function getDeviceManager(): DeviceManager {
if (sharedDeviceManager === null) {
sharedDeviceManager = new DeviceManager();
}
return sharedDeviceManager;
}
export function getLocalDevice(cancellable?: Cancellable | null): Promise<Device> {
return getMatchingDevice(device => device.type === DeviceType.Local, {}, cancellable);
}
export function getRemoteDevice(cancellable?: Cancellable | null): Promise<Device> {
return getMatchingDevice(device => device.type === DeviceType.Remote, {}, cancellable);
}
export function getUsbDevice(options?: GetDeviceOptions, cancellable?: Cancellable | null): Promise<Device> {
return getMatchingDevice(device => device.type === DeviceType.Usb, options, cancellable);
}
export function getDevice(id: string, options?: GetDeviceOptions, cancellable?: Cancellable | null): Promise<Device> {
return getMatchingDevice(device => device.id === id, options, cancellable);
}
export interface GetDeviceOptions {
timeout?: number | null;
}
async function getMatchingDevice(predicate: DevicePredicate, options: GetDeviceOptions = {}, cancellable: Cancellable | null = null): Promise<Device> {
const device = await findMatchingDevice(predicate, cancellable);
if (device !== null) {
return device;
}
const { timeout = 0 } = options;
if (timeout === 0) {
throw new Error("Device not found");
}
const getDeviceEventually = new Promise((resolve: (device: Device) => void, reject: (error: Error) => void) => {
const deviceManager = getDeviceManager();
deviceManager.added.connect(onDeviceAdded);
const timer = (timeout !== null) ? setTimeout(onTimeout, timeout) : null;
if (cancellable !== null) {
cancellable.cancelled.connect(onCancel);
if (cancellable.isCancelled) {
onCancel();
return;
}
}
findMatchingDevice(predicate, cancellable)
.then(device => {
if (device !== null) {
onSuccess(device);
}
})
.catch(onError);
function onDeviceAdded(device: Device): void {
if (predicate(device)) {
onSuccess(device);
}
}
function onSuccess(device: Device): void {
stopMonitoring();
resolve(device);
}
function onError(error: Error): void {
stopMonitoring();
reject(error);
}
function onTimeout(): void {
onError(new Error("Timed out while waiting for device to appear"));
}
function onCancel(): void {
onError(new Error("Operation was cancelled"));
}
function stopMonitoring(): void {
cancellable?.cancelled.disconnect(onCancel);
if (timer !== null) {
clearTimeout(timer);
}
deviceManager.added.disconnect(onDeviceAdded);
}
});
return await getDeviceEventually;
}
async function findMatchingDevice(predicate: DevicePredicate, cancellable?: Cancellable | null): Promise<Device | null> {
const deviceManager = getDeviceManager();
const devices = await deviceManager.enumerateDevices(cancellable);
const matching = devices.filter(predicate);
if (matching.length === 0) {
return null;
}
return matching[0];
}
type DevicePredicate = (device: Device) => boolean;
@@ -0,0 +1,2 @@
import { Minimatch } from "minimatch";
import { Duplex } from "stream";
@@ -0,0 +1,396 @@
const STANDARD_SPAWN_OPTION_NAMES = new Set<keyof SpawnOptions>([
"argv",
"envp",
"env",
"cwd",
"stdio",
]);
interface LogMessage {
type: "log";
level: LogLevel;
payload: string;
}
class ScriptServices implements RpcController {
exportsProxy = new ScriptExportsProxy(this);
#script: Script;
#pendingRequests = new Map<number, (error: Error | null, result?: any) => void>();
#nextRequestId = 1;
constructor(script: Script) {
this.#script = script;
process.nextTick(() => {
script.message.connect(() => {});
});
}
handleMessageIntercept = (message: Message, data: Buffer | null): boolean => {
if (message.type === MessageType.Send && isRpcSendMessage(message)) {
const [ , id, operation, ...params ] = message.payload;
this.#onRpcMessage(id, operation, params, data);
return false;
} else if (isLogMessage(message)) {
const opaqueMessage: any = message;
const logMessage: LogMessage = opaqueMessage;
this.#script.logHandler(logMessage.level, logMessage.payload);
return false;
}
return true;
};
request(operation: string, params: any[], data: Buffer | null, cancellable: Cancellable | null = null): Promise<any> {
return new Promise((resolve, reject) => {
const id = this.#nextRequestId++;
const complete = (error: Error | null, result?: any): void => {
if (cancellable !== null) {
cancellable.cancelled.disconnect(onOperationCancelled);
}
this.#script.destroyed.disconnect(onScriptDestroyed);
this.#pendingRequests.delete(id);
if (error === null) {
resolve(result);
} else {
reject(error);
}
};
function onScriptDestroyed(): void {
complete(new Error("Script is destroyed"));
}
function onOperationCancelled(): void {
complete(new Error("Operation was cancelled"));
}
this.#pendingRequests.set(id, complete);
this.#script.post(["frida:rpc", id, operation, ...params], data);
this.#script.destroyed.connect(onScriptDestroyed);
if (cancellable !== null) {
cancellable.cancelled.connect(onOperationCancelled);
if (cancellable.isCancelled) {
onOperationCancelled();
return;
}
}
if (this.#script.isDestroyed) {
onScriptDestroyed();
}
});
}
#onRpcMessage(id: number, operation: RpcOperation, params: any[], data: Buffer | null) {
if (operation === RpcOperation.Ok || operation === RpcOperation.Error) {
const callback = this.#pendingRequests.get(id);
if (callback === undefined) {
return;
}
let value = null;
let error = null;
if (operation === RpcOperation.Ok) {
if (data !== null) {
value = (params.length > 1) ? [params[1], data] : data;
} else {
value = params[0];
}
} else {
const [message, name, stack, rawErr] = params;
error = new Error(message);
error.name = name;
error.stack = stack;
Object.assign(error, rawErr);
}
callback(error, value);
}
}
}
class ScriptExportsProxy implements ScriptExports {
[name: string]: (...args: any[]) => Promise<any>;
constructor(rpcController: RpcController) {
return new Proxy(this, {
has(target, property) {
return !isReservedMethodName(property);
},
get(target, property, receiver) {
if (typeof property === "symbol") {
if (property === inspect.custom) {
return inspectProxy;
}
return undefined;
}
if (property in target) {
return target[property];
}
if (isReservedMethodName(property)) {
return undefined;
}
return (...args: any[]): Promise<any> => {
let cancellable: Cancellable | null = null;
if (args[args.length - 1] instanceof Cancellable) {
cancellable = args.pop();
}
let data: Buffer | null = null;
if (Buffer.isBuffer(args[args.length - 1])) {
data = args.pop();
}
return rpcController.request("call", [property, args], data, cancellable);
};
},
set(target, property, value, receiver) {
if (typeof property === "symbol") {
return false;
}
target[property] = value;
return true;
},
ownKeys(target) {
return Object.getOwnPropertyNames(target);
},
getOwnPropertyDescriptor(target, property) {
if (property in target) {
return Object.getOwnPropertyDescriptor(target, property);
}
if (isReservedMethodName(property)) {
return undefined;
}
return {
writable: true,
configurable: true,
enumerable: true
};
},
});
}
}
function inspectProxy() {
return "ScriptExportsProxy {}";
}
interface RpcController {
request(operation: string, params: any[], data: ArrayBuffer | null, cancellable: Cancellable | null): Promise<any>;
}
enum RpcOperation {
Ok = "ok",
Error = "error"
}
function isInternalMessage(message: Message): boolean {
return isRpcMessage(message) || isLogMessage(message);
}
function isRpcMessage(message: Message): boolean {
return message.type === MessageType.Send && isRpcSendMessage(message);
}
function isRpcSendMessage(message: SendMessage): boolean {
const payload = message.payload;
if (!Array.isArray(payload)) {
return false;
}
return payload[0] === "frida:rpc";
}
function isLogMessage(message: Message): boolean {
return message.type as string === "log";
}
function log(level: LogLevel, text: string): void {
switch (level) {
case LogLevel.Info:
console.log(text);
break;
case LogLevel.Warning:
console.warn(text);
break;
case LogLevel.Error:
console.error(text);
break;
}
}
const reservedMethodNames = new Set<string>([
"then",
"catch",
"finally",
]);
function isReservedMethodName(name: string | number | symbol): boolean {
return reservedMethodNames.has(name.toString());
}
const IO_PRIORITY_DEFAULT = 0;
class IOStreamAdapter extends Duplex {
#impl: IOStream;
#input: InputStream;
#output: OutputStream;
#pending = new Set<Promise<void>>();
#cancellable = new Cancellable();
constructor(impl: IOStream) {
super({});
this.#impl = impl;
this.#input = impl.inputStream;
this.#output = impl.outputStream;
}
async _destroy(error: Error | null, callback: (error: Error | null) => void): Promise<void> {
this.#cancellable.cancel();
for (const operation of this.#pending) {
try {
await operation;
} catch (e) {
}
}
try {
await this.#impl.close(IO_PRIORITY_DEFAULT);
} catch (e) {
}
callback(error);
}
_read(size: number): void {
const operation = this.#input.read(size, IO_PRIORITY_DEFAULT, this.#cancellable)
.then((data: Buffer): void => {
const isEof = data.length === 0;
if (isEof) {
this.push(null);
return;
}
this.push(data);
})
.catch((error: Error): void => {
if (this.#impl.closed) {
this.push(null);
}
this.emit("error", error);
});
this.#track(operation);
}
_write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void {
let data: Buffer;
if (Buffer.isBuffer(chunk)) {
data = chunk;
} else {
data = Buffer.from(chunk, encoding);
}
const operation = this.#writeAll(data)
.then((): void => {
callback(null);
})
.catch((error: Error): void => {
callback(error);
});
this.#track(operation);
}
async #writeAll(data: Buffer): Promise<void> {
let offset = 0;
do {
const n = await this.#output.write(data.slice(offset), IO_PRIORITY_DEFAULT, this.#cancellable);
offset += n;
} while (offset !== data.length);
}
#track(operation: Promise<void>): void {
this.#pending.add(operation);
operation
.catch(_ => {})
.finally(() => {
this.#pending.delete(operation);
});
}
}
class CallbackAuthenticationService extends binding.AbstractAuthenticationService {
#callback: AuthenticationCallback;
constructor(callback: AuthenticationCallback) {
super();
this.#callback = callback;
}
async authenticate(token: string, cancellable: Cancellable | null): Promise<string> {
const info = await this.#callback(token);
return JSON.stringify(info);
}
}
function parseSocketAddress(address: BaseSocketAddress): SocketAddress {
const family = address.family;
switch (family) {
case SocketFamily.Unix: {
const addr = address as UnixSocketAddress;
switch (addr.addressType) {
case UnixSocketAddressType.Anonymous:
return {
family: "unix:anonymous",
};
case UnixSocketAddressType.Path:
return {
family: "unix:path",
path: addr.path.toString(),
};
case UnixSocketAddressType.Abstract:
case UnixSocketAddressType.AbstractPadded:
return {
family: "unix:abstract",
path: addr.path,
};
}
break;
}
case SocketFamily.Ipv4: {
const addr = address as InetSocketAddress;
return {
family: "ipv4",
address: addr.address.toString(),
port: addr.port,
};
}
case SocketFamily.Ipv6: {
const addr = address as InetSocketAddress;
return {
family: "ipv6",
address: addr.address.toString(),
port: addr.port,
flowlabel: addr.flowinfo,
scopeid: addr.scopeId,
};
}
}
throw new Error("invalid BaseSocketAddress");
}
function objectToStrv(object: { [name: string]: string }): string[] {
return Object.entries(object).map(([k, v]) => `${k}=${v}`);
}
+96
View File
@@ -0,0 +1,96 @@
from __future__ import annotations
import argparse
from io import StringIO
from pathlib import Path
from . import codegen
from .customization import load_customizations
from .loader import compute_model
def main():
run(build_arguments())
def build_arguments() -> argparse.Namespace:
p = argparse.ArgumentParser(
description="Generate TypeScript and Node-API bindings for Frida."
)
p.add_argument(
"--frida-gir",
required=True,
type=Path,
help="Path to the Frida .gir file.",
)
p.add_argument(
"--glib-gir",
required=True,
type=Path,
help="Path to the GLib .gir file.",
)
p.add_argument(
"--gobject-gir",
required=True,
type=Path,
help="Path to the GObject .gir file.",
)
p.add_argument(
"--gio-gir",
required=True,
type=Path,
help="Path to the GIO .gir file.",
)
p.add_argument(
"--output-py",
required=True,
type=Path,
help="Path to the output .py file.",
)
p.add_argument(
"--output-pyi",
required=True,
type=Path,
help="Path to the output .pyi file.",
)
p.add_argument(
"--output-c",
required=True,
type=Path,
help="Path to the output C file for the Python extension.",
)
return p.parse_args()
def run(args: argparse.Namespace) -> None:
customizations = load_customizations()
model = compute_model(
args.frida_gir, args.glib_gir, args.gobject_gir, args.gio_gir, customizations
)
artefacts = codegen.generate_all(model)
with OutputFile(args.output_py) as f:
f.write(artefacts["py"])
with OutputFile(args.output_pyi) as f:
f.write(artefacts["pyi"])
with OutputFile(args.output_c) as f:
f.write(artefacts["c"])
class OutputFile:
def __init__(self, output_path):
self._output_path = output_path
self._io = StringIO()
def __enter__(self):
return self._io
def __exit__(self, *exc):
result = self._io.getvalue()
if self._output_path.exists():
existing_contents = self._output_path.read_text(encoding="utf-8")
if existing_contents == result:
return False
self._output_path.write_text(result, encoding="utf-8")
return False
File diff suppressed because it is too large Load Diff
+924
View File
@@ -0,0 +1,924 @@
from __future__ import annotations
from pathlib import Path
from typing import List, Mapping
from .model import (ConstructorCustomizations, CustomCode, CustomDeclaration,
Customizations, CustomMethod, CustomType, CustomTypeKind,
EnumerationCustomizations, EnumerationMemberCustomizations,
KeepAliveCustomization, MethodCustomizations,
ObjectTypeCustomizations, PropertyCustomizations,
SignalCustomizations, TypeCustomizations)
ASSETS_DIR = Path(__file__).resolve().parent / "assets"
CUSTOMIZATION_FACADE_EXPORTS = (
(ASSETS_DIR / "customization_facade.exports")
.read_text(encoding="utf-8")
.strip()
.split("\n")
)
CUSTOMIZATION_FACADE_TS = (ASSETS_DIR / "customization_facade.ts").read_text(
encoding="utf-8"
)
CUSTOMIZATION_HELPERS_IMPORTS = (
(ASSETS_DIR / "customization_helpers.imports")
.read_text(encoding="utf-8")
.strip()
.split("\n")
)
CUSTOMIZATION_HELPERS_TS = (ASSETS_DIR / "customization_helpers.ts").read_text(
encoding="utf-8"
)
def load_customizations() -> Customizations:
custom_types: List[CustomType] = {
"TargetProcess": CustomType(CustomTypeKind.TYPE, "ProcessID | ProcessName"),
"ProcessID": CustomType(CustomTypeKind.TYPE, "number"),
"InjecteeID": CustomType(CustomTypeKind.TYPE, "number"),
"FileDescriptor": CustomType(CustomTypeKind.TYPE, "number"),
"ProcessName": CustomType(CustomTypeKind.TYPE, "string"),
"SystemParameters": CustomType(
CustomTypeKind.INTERFACE,
"""
/**
* Operating System details.
*/
os: {
/**
* ID, e.g.: windows, macos, linux, ios, android, qnx, fedora, ubuntu, etc.
*/
id: string;
/**
* Human-readable name, e.g. `"macOS"`.
*/
name: string;
/**
* Human-readable version string, e.g. `"11.2.2"`.
*/
version?: string;
/**
* Build version, e.g. `"21B91"`.
*/
build?: string;
}
/**
* Platform, same as `Process.platform` in GumJS.
*/
platform: "windows" | "darwin" | "linux" | "freebsd" | "qnx";
/**
* Architecture, same as `Process.arch` in GumJS.
*/
arch: "ia32" | "x64" | "arm" | "arm64" | "mips";
/**
* Hardware details.
*/
hardware?: {
/**
* Product type, e.g. `"iPad6,3"`.
*/
product?: string;
/**
* Hardware platform, e.g. `"t8010"`.
*/
platform?: string;
/**
* Hardware model, e.g. `"J71bAP"`.
*/
model?: string;
}
/**
* Level of access.
*/
access: "full" | "jailed";
/**
* System name, e.g. `"Ole André’s iPhone"`.
*/
name?: string;
/**
* iOS UDID (Unique Device ID).
*/
udid?: string;
/**
* Details about cellular and networking interfaces.
*/
interfaces?: SystemInterface[];
/**
* Android API level, e.g.: `30`.
*/
apiLevel?: number;
[name: string]: any;
""",
),
"SystemInterface": CustomType(
CustomTypeKind.TYPE, "NetworkInterface | CellularInterface"
),
"NetworkInterface": CustomType(
CustomTypeKind.INTERFACE,
"""
type: "ethernet" | "wifi" | "bluetooth";
/**
* MAC address, e.g.: `"aa:bb:cc:dd:ee:ff"`.
*/
address: string;
""",
),
"CellularInterface": CustomType(
CustomTypeKind.INTERFACE,
"""
type: "cellular";
/**
* Phone number, e.g. `"+47 123 45 678"`.
*/
phoneNumber: string;
""",
),
"SpawnOptions": CustomType(
CustomTypeKind.INTERFACE,
"""
argv?: string[];
envp?: { [name: string]: string };
env?: { [name: string]: string };
cwd?: string;
stdio?: Stdio;
[name: string]: any;
""",
),
"RelayProperties": CustomType(
CustomTypeKind.INTERFACE,
"""
address: string;
username: string;
password: string;
kind: RelayKind;
""",
),
"Message": CustomType(CustomTypeKind.TYPE, "SendMessage | ErrorMessage"),
"MessageType": CustomType(
CustomTypeKind.ENUM,
"""
Send = "send",
Error = "error"
""",
),
"SendMessage": CustomType(
CustomTypeKind.INTERFACE,
"""
type: MessageType.Send;
payload: any;
""",
),
"ErrorMessage": CustomType(
CustomTypeKind.INTERFACE,
"""
type: MessageType.Error;
description: string;
stack?: string;
fileName?: string;
lineNumber?: number;
columnNumber?: number;
""",
),
"ScriptLogHandler": CustomType(
CustomTypeKind.TYPE, "(level: LogLevel, text: string) => void"
),
"ScriptExports": CustomType(
CustomTypeKind.INTERFACE,
"""
[name: string]: (...args: any[]) => Promise<any>;
""",
),
"LogLevel": CustomType(
CustomTypeKind.ENUM,
"""
Info = "info",
Warning = "warning",
Error = "error",
""",
),
"EnableDebuggerOptions": CustomType(
CustomTypeKind.INTERFACE,
"""
port?: number;
""",
),
"PortalServiceOptions": CustomType(
CustomTypeKind.INTERFACE,
"""
clusterParams?: EndpointParameters;
controlParams?: EndpointParameters;
""",
),
"PortalConnectionId": CustomType(CustomTypeKind.TYPE, "number"),
"PortalConnectionTag": CustomType(CustomTypeKind.TYPE, "string"),
"EndpointParametersSubset": CustomType(
CustomTypeKind.INTERFACE,
"""
address?: string;
port?: number;
certificate?: string;
origin?: string;
authentication?: AuthenticationScheme;
assetRoot?: string;
""",
),
"AuthenticationScheme": CustomType(
CustomTypeKind.TYPE,
"TokenAuthenticationScheme | CallbackAuthenticationScheme",
),
"TokenAuthenticationScheme": CustomType(
CustomTypeKind.INTERFACE,
"""
scheme: "token";
token: string;
""",
),
"CallbackAuthenticationScheme": CustomType(
CustomTypeKind.INTERFACE,
"""
scheme: "callback";
callback: AuthenticationCallback;
""",
),
"AuthenticationCallback": CustomType(
CustomTypeKind.TYPE,
"(token: string) => Promise<AuthenticatedSessionInfo>",
),
"AuthenticatedSessionInfo": CustomType(
CustomTypeKind.INTERFACE,
"""
[key: string]: any;
""",
),
"SocketAddress": CustomType(
CustomTypeKind.TYPE,
"IPV4SocketAddress | IPV6SocketAddress | AnonymousUnixSocketAddress | PathUnixSocketAddress | AbstractUnixSocketAddress",
),
"IPV4SocketAddress": CustomType(
CustomTypeKind.INTERFACE,
"""
family: "ipv4";
address: string;
port: number;
""",
),
"IPV6SocketAddress": CustomType(
CustomTypeKind.INTERFACE,
"""
family: "ipv6";
address: string;
port: number;
flowlabel: number;
scopeid: number;
""",
),
"AnonymousUnixSocketAddress": CustomType(
CustomTypeKind.INTERFACE,
"""
family: "unix:anonymous";
""",
),
"PathUnixSocketAddress": CustomType(
CustomTypeKind.INTERFACE,
"""
family: "unix:path";
path: string;
""",
),
"AbstractUnixSocketAddress": CustomType(
CustomTypeKind.INTERFACE,
"""
family: "unix:abstract";
path: Buffer;
""",
),
"Variant": CustomType(
CustomTypeKind.TYPE, "VariantValue | [type: symbol, value: VariantValue]"
),
"VariantValue": CustomType(
CustomTypeKind.TYPE,
"""
| boolean
| number
| string
| Buffer
| Variant[]
| VariantDict
""",
),
"VariantDict": CustomType(
CustomTypeKind.INTERFACE,
"""
[key: string]: Variant;
""",
),
}
type_customizations: Mapping[str, TypeCustomizations] = {
"DeviceManager": ObjectTypeCustomizations(
signals={
"added": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"removed": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"changed": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
},
cleanup="close",
),
"Device": ObjectTypeCustomizations(
methods={
"query_system_parameters": MethodCustomizations(
return_typing="Promise<SystemParameters>",
return_wrapper="as SystemParameters",
),
"spawn": MethodCustomizations(
param_typings=[
"programOrArgv: string | string[]",
"opts?: SpawnOptions",
"cancellable?: Cancellable | null",
],
return_typing="Promise<ProcessID>",
custom_logic="""
const options: RawSpawnOptions = {};
let program: string;
let argv;
if (typeof programOrArgv === "string") {
program = programOrArgv;
argv = opts?.argv;
} else {
program = programOrArgv[0];
argv = programOrArgv;
if (argv.length === 1) {
argv = undefined;
}
}
if (argv !== undefined) {
options.argv = argv;
}
if (opts !== undefined) {
const envp = opts.envp;
if (envp !== undefined) {
options.envp = objectToStrv(envp);
}
const env = opts.env;
if (env !== undefined) {
options.env = objectToStrv(env);
}
const cwd = opts.cwd;
if (cwd !== undefined) {
options.cwd = cwd;
}
options.aux = Object.fromEntries(Object.entries(opts).filter(([k, v]) => !STANDARD_SPAWN_OPTION_NAMES.has(k)));
}
""",
),
"input": MethodCustomizations(
param_typings=[
"target: TargetProcess",
"data: Buffer",
"cancellable?: Cancellable | null",
],
custom_logic="const pid = await this.#getPid(target, cancellable);",
),
"resume": MethodCustomizations(
param_typings=[
"target: TargetProcess",
"cancellable?: Cancellable | null",
],
custom_logic="const pid = await this.#getPid(target, cancellable);",
),
"kill": MethodCustomizations(
param_typings=[
"target: TargetProcess",
"cancellable?: Cancellable | null",
],
custom_logic="const pid = await this.#getPid(target, cancellable);",
),
"attach": MethodCustomizations(
param_typings=[
"target: TargetProcess",
"options?: SessionOptions",
"cancellable?: Cancellable | null",
],
custom_logic="const pid = await this.#getPid(target, cancellable);",
),
"inject_library_file": MethodCustomizations(
param_typings=[
"target: TargetProcess",
"path: string",
"entrypoint: string",
"data: string",
"cancellable?: Cancellable | null",
],
return_typing="Promise<InjecteeID>",
custom_logic="const pid = await this.#getPid(target, cancellable);",
),
"inject_library_blob": MethodCustomizations(
param_typings=[
"target: TargetProcess",
"blob: Buffer",
"entrypoint: string",
"data: string",
"cancellable?: Cancellable | null",
],
return_typing="Promise<InjecteeID>",
custom_logic="const pid = await this.#getPid(target, cancellable);",
),
"open_channel": MethodCustomizations(
return_typing='Promise<import("stream").Duplex>',
return_wrapper="new IOStreamAdapter",
),
},
properties={
"dtype": PropertyCustomizations(
js_name="type",
),
},
signals={
"spawn-added": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"spawn-removed": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"child-added": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"child-removed": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"process-crashed": SignalCustomizations(
behavior="FDN_SIGNAL_KEEP_ALIVE"
),
"output": SignalCustomizations(
behavior="FDN_SIGNAL_KEEP_ALIVE",
transform={
0: ("pid: ProcessID", None),
1: ("fd: FileDescriptor", None),
},
),
"uninjected": SignalCustomizations(
behavior="FDN_SIGNAL_KEEP_ALIVE",
transform={
0: ("id: InjecteeID", None),
},
),
},
custom_code=CustomCode(
methods=[
CustomMethod(
typing="getProcess(name: string, options?: ProcessMatchOptions, cancellable?: Cancellable | null): Promise<Process>",
code="""
async getProcess(name: string, options: ProcessMatchOptions = {}, cancellable?: Cancellable | null): Promise<Process> {
const {
scope = Scope.Minimal,
} = options;
const processes = await this.enumerateProcesses({ scope }, cancellable);
const mm = new Minimatch(name.toLowerCase());
const matching = processes.filter(process => mm.match(process.name.toLowerCase()));
if (matching.length === 1) {
return matching[0];
} else if (matching.length > 1) {
throw new Error("Ambiguous name; it matches: " + matching.map(process => `${process.name} (pid: ${process.pid})`).join(", "));
} else {
throw new Error("Process not found");
}
}
""",
),
CustomMethod(
typing=None,
code="""
async #getPid(target: TargetProcess, cancellable?: Cancellable | null): Promise<ProcessID> {
if (typeof target === "number") {
return target;
}
const process = await this.getProcess(target, {}, cancellable);
return process.pid;
}
""",
),
],
),
),
"SpawnOptions": ObjectTypeCustomizations(js_name="RawSpawnOptions"),
"Bus": ObjectTypeCustomizations(
methods={
"post": MethodCustomizations(
param_typings=[
"message: any",
"data?: Buffer | null",
],
custom_logic="const json = JSON.stringify(message);",
),
},
signals={
"detached": SignalCustomizations(behavior="FDN_SIGNAL_KEEP_ALIVE"),
"message": SignalCustomizations(
behavior="FDN_SIGNAL_KEEP_ALIVE",
transform={
0: ("message: any", "JSON.parse"),
},
),
},
),
"Service": ObjectTypeCustomizations(
keep_alive=KeepAliveCustomization(
is_destroyed_function="is_closed", destroy_signal_name="close"
),
),
"Relay": ObjectTypeCustomizations(
constructor=ConstructorCustomizations(
param_typings=[
"properties: RelayProperties",
],
custom_logic="const { address, username, password, kind } = properties;",
),
),
"RelayKind": EnumerationCustomizations(
members={
"turn_udp": EnumerationMemberCustomizations(js_name="TurnUDP"),
"turn_tcp": EnumerationMemberCustomizations(js_name="TurnTCP"),
"turn_tls": EnumerationMemberCustomizations(js_name="TurnTLS"),
},
),
"Script": ObjectTypeCustomizations(
methods={
"is_destroyed": MethodCustomizations(hide=True),
"post": MethodCustomizations(
param_typings=[
"message: any",
"data?: Buffer | null",
],
custom_logic="const json = JSON.stringify(message);",
),
"enable_debugger": MethodCustomizations(
param_typings=[
"options?: EnableDebuggerOptions",
"cancellable?: Cancellable | null",
],
custom_logic="const port = options?.port ?? 0;",
),
},
signals={
"message": SignalCustomizations(
transform={
0: ("message: Message", "JSON.parse"),
},
intercept="this.#services.handleMessageIntercept",
),
},
custom_code=CustomCode(
declarations=[
CustomDeclaration(
typing=None, code="#services = new ScriptServices(this);"
),
CustomDeclaration(
typing="logHandler: ScriptLogHandler",
code="logHandler: ScriptLogHandler = log;",
),
],
methods=[
CustomMethod(
typing="readonly isDestroyed: boolean",
code="""
get isDestroyed(): boolean {
return this._isDestroyed();
}
""",
),
CustomMethod(
typing="readonly exports: ScriptExports",
code="""
get exports(): ScriptExports {
return this.#services.exportsProxy;
}
""",
),
CustomMethod(
typing="readonly defaultLogHandler: ScriptLogHandler",
code="""
get defaultLogHandler(): ScriptLogHandler {
return log;
}
""",
),
],
),
keep_alive=KeepAliveCustomization(
is_destroyed_function="is_destroyed", destroy_signal_name="destroyed"
),
),
"ScriptRuntime": EnumerationCustomizations(
members={
"qjs": EnumerationMemberCustomizations(js_name="QJS"),
},
),
"ControlService": ObjectTypeCustomizations(
methods={
"start": MethodCustomizations(ref_keep_alive=True),
"stop": MethodCustomizations(unref_keep_alive=True),
"get_endpoint_params": MethodCustomizations(drop=True),
},
properties={
"endpoint-params": PropertyCustomizations(drop=True),
},
),
"PortalService": ObjectTypeCustomizations(
constructor=ConstructorCustomizations(
param_typings=[
"options?: PortalServiceOptions",
],
custom_logic="""
const clusterParams = options?.clusterParams ?? new EndpointParameters();
const controlParams = options?.controlParams ?? null;
""",
),
methods={
"start": MethodCustomizations(ref_keep_alive=True),
"stop": MethodCustomizations(unref_keep_alive=True),
"kick": MethodCustomizations(
param_typings=[
"connectionId: PortalConnectionId",
],
),
"post": MethodCustomizations(
param_typings=[
"connectionId: PortalConnectionId",
"message: any",
"data?: Buffer | null",
],
custom_logic="const json = JSON.stringify(message);",
),
"narrowcast": MethodCustomizations(
param_typings=[
"tag: string",
"message: any",
"data?: Buffer | null",
],
custom_logic="const json = JSON.stringify(message);",
),
"broadcast": MethodCustomizations(
param_typings=[
"message: any",
"data?: Buffer | null",
],
custom_logic="const json = JSON.stringify(message);",
),
"enumerate_tags": MethodCustomizations(
param_typings=[
"connectionId: PortalConnectionId",
],
),
"tag": MethodCustomizations(
param_typings=[
"connectionId: PortalConnectionId",
"tag: string",
],
),
"untag": MethodCustomizations(
param_typings=[
"connectionId: PortalConnectionId",
"tag: string",
],
),
},
signals={
"node-connected": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
1: ("remoteAddress: SocketAddress", "parseSocketAddress"),
},
),
"node-joined": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
},
),
"node-left": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
},
),
"node-disconnected": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
1: ("remoteAddress: SocketAddress", "parseSocketAddress"),
},
),
"controller-connected": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
1: ("remoteAddress: SocketAddress", "parseSocketAddress"),
},
),
"controller-disconnected": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
1: ("remoteAddress: SocketAddress", "parseSocketAddress"),
},
),
"authenticated": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
1: ("sessionInfo: AuthenticatedSessionInfo", "JSON.parse"),
},
),
"subscribe": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
},
),
"message": SignalCustomizations(
transform={
0: ("connectionId: PortalConnectionId", None),
1: ("message: any", "JSON.parse"),
},
),
},
),
"EndpointParameters": ObjectTypeCustomizations(
constructor=ConstructorCustomizations(
param_typings=[
"params?: EndpointParametersSubset",
],
custom_logic="""
const address = params?.address ?? null;
const port = params?.port ?? 0;
const certificate = params?.certificate ?? null;
const origin = params?.origin ?? null;
let authService: AuthenticationService | null = null;
const auth = params?.authentication;
if (auth !== undefined) {
if (auth.scheme === "token") {
authService = new StaticAuthenticationService(auth.token);
} else {
authService = new CallbackAuthenticationService(auth.callback);
}
}
const assetRoot = params?.assetRoot ?? null;
""",
),
),
"Injector": ObjectTypeCustomizations(drop=True),
"RpcClient": ObjectTypeCustomizations(drop=True),
"RpcPeer": ObjectTypeCustomizations(drop=True),
"Cancellable": ObjectTypeCustomizations(
methods={
"is_cancelled": MethodCustomizations(hide=True),
"set_error_if_cancelled": MethodCustomizations(
js_name="throwIfCancelled",
return_typing="void",
),
"make_pollfd": MethodCustomizations(drop=True),
"release_fd": MethodCustomizations(drop=True),
"source_new": MethodCustomizations(drop=True),
},
custom_code=CustomCode(
methods=[
CustomMethod(
typing="readonly isCancelled: boolean",
code="""
get isCancelled(): boolean {
return this._isCancelled();
}
""",
),
],
),
),
"IOStream": ObjectTypeCustomizations(
methods={
"close": MethodCustomizations(drop=True),
"close_async": MethodCustomizations(js_name="close"),
"splice_async": MethodCustomizations(drop=True),
"has_pending": MethodCustomizations(drop=True),
"set_pending": MethodCustomizations(drop=True),
"clear_pending": MethodCustomizations(drop=True),
},
),
"InputStream": ObjectTypeCustomizations(
methods={
"close": MethodCustomizations(drop=True),
"close_async": MethodCustomizations(js_name="close"),
"read": MethodCustomizations(drop=True),
"read_async": MethodCustomizations(drop=True),
"read_all": MethodCustomizations(drop=True),
"read_all_async": MethodCustomizations(drop=True),
"read_bytes": MethodCustomizations(drop=True),
"read_bytes_async": MethodCustomizations(js_name="read"),
"skip": MethodCustomizations(drop=True),
"skip_async": MethodCustomizations(js_name="skip"),
"is_closed": MethodCustomizations(drop=True),
"has_pending": MethodCustomizations(drop=True),
"set_pending": MethodCustomizations(drop=True),
"clear_pending": MethodCustomizations(drop=True),
},
),
"OutputStream": ObjectTypeCustomizations(
methods={
"close": MethodCustomizations(drop=True),
"close_async": MethodCustomizations(js_name="close"),
"flush": MethodCustomizations(drop=True),
"flush_async": MethodCustomizations(js_name="flush"),
"write": MethodCustomizations(drop=True),
"write_async": MethodCustomizations(drop=True),
"write_all": MethodCustomizations(drop=True),
"write_all_async": MethodCustomizations(drop=True),
"write_bytes": MethodCustomizations(drop=True),
"write_bytes_async": MethodCustomizations(js_name="write"),
"writev": MethodCustomizations(drop=True),
"writev_async": MethodCustomizations(drop=True),
"writev_all": MethodCustomizations(drop=True),
"writev_all_async": MethodCustomizations(drop=True),
"splice": MethodCustomizations(drop=True),
"splice_async": MethodCustomizations(drop=True),
"is_closing": MethodCustomizations(drop=True),
"is_closed": MethodCustomizations(drop=True),
"has_pending": MethodCustomizations(drop=True),
"set_pending": MethodCustomizations(drop=True),
"clear_pending": MethodCustomizations(drop=True),
},
),
"UnixSocketAddress": ObjectTypeCustomizations(
methods={
"get_path": MethodCustomizations(
return_typing="Buffer",
return_cconversion="fdn_buffer_to_value (env, (const guint8 *) retval, g_unix_socket_address_get_path_len (handle))",
),
"get_path_len": MethodCustomizations(drop=True),
"get_is_abstract": MethodCustomizations(drop=True),
},
properties={
"path": PropertyCustomizations(typing="path: Buffer"),
"abstract": PropertyCustomizations(drop=True),
"path-as-array": PropertyCustomizations(drop=True),
},
),
"SocketAddress": ObjectTypeCustomizations(
js_name="BaseSocketAddress",
constructor=ConstructorCustomizations(drop=True),
methods={
"to_native": MethodCustomizations(drop=True),
},
),
"SocketConnectable": ObjectTypeCustomizations(drop_abstract_base=True),
"InetAddress": ObjectTypeCustomizations(
properties={
"bytes": PropertyCustomizations(drop=True),
},
),
"Object": ObjectTypeCustomizations(
js_name="BaseObject",
methods={
"is_floating": MethodCustomizations(drop=True),
"ref": MethodCustomizations(drop=True),
"ref_sink": MethodCustomizations(drop=True),
"unref": MethodCustomizations(drop=True),
"getv": MethodCustomizations(drop=True),
"get_property": MethodCustomizations(drop=True),
"set_property": MethodCustomizations(drop=True),
"notify_by_pspec": MethodCustomizations(drop=True),
"freeze_notify": MethodCustomizations(drop=True),
"thaw_notify": MethodCustomizations(drop=True),
"bind_property": MethodCustomizations(drop=True),
"bind_property_full": MethodCustomizations(drop=True),
"bind_property_with_closures": MethodCustomizations(drop=True),
"force_floating": MethodCustomizations(drop=True),
"get_data": MethodCustomizations(drop=True),
"get_qdata": MethodCustomizations(drop=True),
"run_dispose": MethodCustomizations(drop=True),
"set_data": MethodCustomizations(drop=True),
"steal_data": MethodCustomizations(drop=True),
"steal_qdata": MethodCustomizations(drop=True),
"watch_closure": MethodCustomizations(drop=True),
},
signals={
"notify": SignalCustomizations(drop=True),
},
),
}
return Customizations(
custom_types,
type_customizations,
CUSTOMIZATION_FACADE_EXPORTS,
CUSTOMIZATION_FACADE_TS,
CUSTOMIZATION_HELPERS_IMPORTS,
CUSTOMIZATION_HELPERS_TS,
)
+61
View File
@@ -0,0 +1,61 @@
from __future__ import annotations
from collections import OrderedDict
from pathlib import Path
from .model import Customizations, Model, parse_gir
INCLUDED_GIO_OBJECT_TYPES = [
"Cancellable",
"IOStream",
"InputStream",
"OutputStream",
"SocketAddress",
"SocketAddressEnumerator",
"SocketConnectable",
"InetSocketAddress",
"InetAddress",
"UnixSocketAddress",
]
INCLUDED_GIO_ENUMERATIONS = [
"FileMonitorEvent",
"SocketFamily",
"UnixSocketAddressType",
]
def compute_model(
frida_gir: Path,
glib_gir: Path,
gobject_gir: Path,
gio_gir: Path,
customizations: Customizations,
) -> Model:
glib = parse_gir(glib_gir, [])
gobject = parse_gir(gobject_gir, [glib])
gio = parse_gir(gio_gir, [glib, gobject])
frida = parse_gir(frida_gir, [glib, gobject, gio])
object_types = OrderedDict()
object_types["Object"] = gobject.object_types["Object"]
object_types.update(frida.object_types)
for t in INCLUDED_GIO_OBJECT_TYPES:
object_types[t] = gio.object_types[t]
enumerations = OrderedDict(frida.enumerations)
for t in INCLUDED_GIO_ENUMERATIONS:
enumerations[t] = gio.enumerations[t]
model = Model(
frida.namespace,
object_types,
enumerations,
customizations,
)
for t in object_types.values():
t.model = model
for t in enumerations.values():
t.model = model
return model
File diff suppressed because it is too large Load Diff
+90 -3
View File
@@ -1,8 +1,95 @@
subdir('_frida')
if frida_core_dep.type_name() == 'internal'
frida_core_subprj = subproject('frida-core')
frida_gir = frida_core_subprj.get_variable('core_public_gir')
glib_gir = frida_core_subprj.get_variable('glib_gir')
gobject_gir = frida_core_subprj.get_variable('gobject_gir')
gio_gir = frida_core_subprj.get_variable('gio_gir')
else
girdir = frida_core_dep.get_variable('frida_girdir')
frida_gir = girdir / 'Frida-1.0.gir'
glib_gir = girdir / 'GLib-2.0.gir'
gobject_gir = girdir / 'GObject-2.0.gir'
gio_gir = girdir / 'Gio-2.0.gir'
endif
env = environment()
env.set('PYTHONPATH', meson.current_source_dir())
code = custom_target('binding-code',
output: [
'__init__.py',
'__init__.pyi',
'extension.c',
],
input: [
frida_gir,
glib_gir,
gobject_gir,
gio_gir,
files(
'frida_bindgen' / '__init__.py',
'frida_bindgen' / '__main__.py',
'frida_bindgen' / 'cli.py',
'frida_bindgen' / 'codegen.py',
'frida_bindgen' / 'customization.py',
'frida_bindgen' / 'loader.py',
'frida_bindgen' / 'model.py',
'frida_bindgen' / 'assets' / 'codegen_gobject_globals.c',
'frida_bindgen' / 'assets' / 'codegen_gobject_methods.c',
'frida_bindgen' / 'assets' / 'codegen_gobject_prototypes.h',
'frida_bindgen' / 'assets' / 'codegen_helpers.c',
'frida_bindgen' / 'assets' / 'codegen_helpers.ts',
'frida_bindgen' / 'assets' / 'codegen_macros.h',
'frida_bindgen' / 'assets' / 'codegen_prototypes.h',
'frida_bindgen' / 'assets' / 'codegen_structs.h',
'frida_bindgen' / 'assets' / 'codegen_typedefs.h',
'frida_bindgen' / 'assets' / 'customization_facade.exports',
'frida_bindgen' / 'assets' / 'customization_facade.ts',
'frida_bindgen' / 'assets' / 'customization_helpers.imports',
'frida_bindgen' / 'assets' / 'customization_helpers.ts',
)
],
command: [
python, '-m', 'frida_bindgen',
'--frida-gir=@INPUT0@',
'--glib-gir=@INPUT1@',
'--gobject-gir=@INPUT2@',
'--gio-gir=@INPUT3@',
'--output-py=@OUTPUT0@',
'--output-pyi=@OUTPUT1@',
'--output-c=@OUTPUT2@',
],
env: env,
install: true,
install_dir: [
python.get_install_dir() / 'frida',
python.get_install_dir() / 'frida' / '_frida',
false,
]
)
py_sources = [
'__init__.py',
'core.py',
'py.typed',
]
python.install_sources(py_sources, subdir: 'frida', pure: false)
extension_py_sources = [
'py.typed',
]
python.install_sources(extension_py_sources, subdir: 'frida' / '_frida', pure: false)
extra_link_args = []
if host_os_family == 'darwin'
extra_link_args += '-Wl,-exported_symbol,_PyInit__frida'
elif host_os_family != 'windows'
extra_link_args += '-Wl,--version-script,' + meson.current_source_dir() / 'extension.version'
endif
extension = python.extension_module('_frida', code[2],
limited_api: '3.7',
c_args: frida_component_cflags,
link_args: extra_link_args,
dependencies: [python_dep, frida_core_dep, os_deps],
install: true,
subdir: 'frida',
)
+6 -6
View File
@@ -32,9 +32,9 @@ endif
subdir('frida')
test('frida-python', python,
args: ['-m', 'unittest', 'discover'],
workdir: meson.current_source_dir(),
env: {'PYTHONPATH': meson.current_build_dir() / 'src'},
timeout: 30,
)
#test('frida-python', python,
# args: ['-m', 'unittest', 'discover'],
# workdir: meson.current_source_dir(),
# env: {'PYTHONPATH': meson.current_build_dir() / 'src'},
# timeout: 30,
#)
+1 -1
Submodule releng updated: 4918345281...71f828f7c8
+1 -1
View File
@@ -1,6 +1,6 @@
[wrap-git]
url = https://github.com/frida/frida-core.git
revision = 16.6.0
revision = 17.6.0
depth = 1
[provide]