cattle_grid 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. cattle_grid-0.2.0/.behaverc +3 -0
  2. cattle_grid-0.2.0/.gitignore +13 -0
  3. cattle_grid-0.2.0/.readthedocs.yaml +15 -0
  4. cattle_grid-0.2.0/.woodpecker/publish.yml +13 -0
  5. cattle_grid-0.2.0/.woodpecker/test.yml +23 -0
  6. cattle_grid-0.2.0/.woodpecker/website.yml +27 -0
  7. cattle_grid-0.2.0/LICENSE +21 -0
  8. cattle_grid-0.2.0/PKG-INFO +109 -0
  9. cattle_grid-0.2.0/README.md +83 -0
  10. cattle_grid-0.2.0/cattle_grid/__init__.py +84 -0
  11. cattle_grid-0.2.0/cattle_grid/__main__.py +150 -0
  12. cattle_grid-0.2.0/cattle_grid/account/__init__.py +0 -0
  13. cattle_grid-0.2.0/cattle_grid/account/account.py +39 -0
  14. cattle_grid-0.2.0/cattle_grid/account/cli.py +39 -0
  15. cattle_grid-0.2.0/cattle_grid/account/models.py +37 -0
  16. cattle_grid-0.2.0/cattle_grid/account/rabbit.py +119 -0
  17. cattle_grid-0.2.0/cattle_grid/account/router/__init__.py +26 -0
  18. cattle_grid-0.2.0/cattle_grid/account/router/annotations.py +87 -0
  19. cattle_grid-0.2.0/cattle_grid/account/router/exception.py +33 -0
  20. cattle_grid-0.2.0/cattle_grid/account/router/exchange.py +3 -0
  21. cattle_grid-0.2.0/cattle_grid/account/router/info.py +9 -0
  22. cattle_grid-0.2.0/cattle_grid/account/router/router.py +222 -0
  23. cattle_grid-0.2.0/cattle_grid/account/router/schema.py +47 -0
  24. cattle_grid-0.2.0/cattle_grid/account/router/test_annotations.py +5 -0
  25. cattle_grid-0.2.0/cattle_grid/account/router/test_exception.py +52 -0
  26. cattle_grid-0.2.0/cattle_grid/account/router/test_handlers.py +53 -0
  27. cattle_grid-0.2.0/cattle_grid/account/router/test_router.py +122 -0
  28. cattle_grid-0.2.0/cattle_grid/account/server/__init__.py +50 -0
  29. cattle_grid-0.2.0/cattle_grid/account/server/account.py +109 -0
  30. cattle_grid-0.2.0/cattle_grid/account/server/actor.py +82 -0
  31. cattle_grid-0.2.0/cattle_grid/account/server/app.py +33 -0
  32. cattle_grid-0.2.0/cattle_grid/account/server/dependencies.py +23 -0
  33. cattle_grid-0.2.0/cattle_grid/account/server/requests.py +43 -0
  34. cattle_grid-0.2.0/cattle_grid/account/server/responses.py +56 -0
  35. cattle_grid-0.2.0/cattle_grid/account/server/test_account.py +59 -0
  36. cattle_grid-0.2.0/cattle_grid/account/server/test_actor.py +89 -0
  37. cattle_grid-0.2.0/cattle_grid/account/server/test_methods.py +12 -0
  38. cattle_grid-0.2.0/cattle_grid/account/server/test_signin.py +57 -0
  39. cattle_grid-0.2.0/cattle_grid/account/server/testing.py +51 -0
  40. cattle_grid-0.2.0/cattle_grid/account/test_account.py +36 -0
  41. cattle_grid-0.2.0/cattle_grid/account/test_rabbit.py +70 -0
  42. cattle_grid-0.2.0/cattle_grid/activity_pub/__init__.py +42 -0
  43. cattle_grid-0.2.0/cattle_grid/activity_pub/activity.py +34 -0
  44. cattle_grid-0.2.0/cattle_grid/activity_pub/actor.py +294 -0
  45. cattle_grid-0.2.0/cattle_grid/activity_pub/enqueuer.py +62 -0
  46. cattle_grid-0.2.0/cattle_grid/activity_pub/models.py +163 -0
  47. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/__init__.py +34 -0
  48. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/common.py +52 -0
  49. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/incoming.py +166 -0
  50. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/outgoing.py +156 -0
  51. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/remote.py +64 -0
  52. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/store_activity.py +43 -0
  53. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/test_incoming.py +213 -0
  54. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/test_outgoing.py +255 -0
  55. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/test_remote.py +158 -0
  56. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/test_store_activity.py +23 -0
  57. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/test_util.py +96 -0
  58. cattle_grid-0.2.0/cattle_grid/activity_pub/processing/util.py +28 -0
  59. cattle_grid-0.2.0/cattle_grid/activity_pub/server/__init__.py +78 -0
  60. cattle_grid-0.2.0/cattle_grid/activity_pub/server/router.py +103 -0
  61. cattle_grid-0.2.0/cattle_grid/activity_pub/server/router_inbox.py +75 -0
  62. cattle_grid-0.2.0/cattle_grid/activity_pub/server/router_object.py +33 -0
  63. cattle_grid-0.2.0/cattle_grid/activity_pub/server/test_init.py +59 -0
  64. cattle_grid-0.2.0/cattle_grid/activity_pub/server/test_router.py +199 -0
  65. cattle_grid-0.2.0/cattle_grid/activity_pub/server/test_router_inbox.py +120 -0
  66. cattle_grid-0.2.0/cattle_grid/activity_pub/server/test_router_object.py +148 -0
  67. cattle_grid-0.2.0/cattle_grid/activity_pub/test_activity.py +17 -0
  68. cattle_grid-0.2.0/cattle_grid/activity_pub/test_actor.py +198 -0
  69. cattle_grid-0.2.0/cattle_grid/activity_pub/test_actor_valid_requester.py +49 -0
  70. cattle_grid-0.2.0/cattle_grid/activity_pub/test_enqueuer.py +27 -0
  71. cattle_grid-0.2.0/cattle_grid/auth/__init__.py +33 -0
  72. cattle_grid-0.2.0/cattle_grid/auth/__main__.py +39 -0
  73. cattle_grid-0.2.0/cattle_grid/auth/block_cli.py +108 -0
  74. cattle_grid-0.2.0/cattle_grid/auth/key_cli.py +35 -0
  75. cattle_grid-0.2.0/cattle_grid/auth/model.py +11 -0
  76. cattle_grid-0.2.0/cattle_grid/auth/public_key_cache.py +75 -0
  77. cattle_grid-0.2.0/cattle_grid/auth/router.py +157 -0
  78. cattle_grid-0.2.0/cattle_grid/auth/templates/index.html +15 -0
  79. cattle_grid-0.2.0/cattle_grid/auth/test_app.py +146 -0
  80. cattle_grid-0.2.0/cattle_grid/auth/test_block_cli.py +65 -0
  81. cattle_grid-0.2.0/cattle_grid/auth/test_key_cli.py +42 -0
  82. cattle_grid-0.2.0/cattle_grid/auth/test_public_key_cache.py +109 -0
  83. cattle_grid-0.2.0/cattle_grid/auth/test_router.py +17 -0
  84. cattle_grid-0.2.0/cattle_grid/auth/test_util.py +15 -0
  85. cattle_grid-0.2.0/cattle_grid/auth/util.py +52 -0
  86. cattle_grid-0.2.0/cattle_grid/config/__init__.py +21 -0
  87. cattle_grid-0.2.0/cattle_grid/config/auth.py +91 -0
  88. cattle_grid-0.2.0/cattle_grid/config/messaging.py +42 -0
  89. cattle_grid-0.2.0/cattle_grid/config/settings.py +19 -0
  90. cattle_grid-0.2.0/cattle_grid/config/test_auth.py +26 -0
  91. cattle_grid-0.2.0/cattle_grid/config/test_config.py +17 -0
  92. cattle_grid-0.2.0/cattle_grid/config/test_messaging.py +23 -0
  93. cattle_grid-0.2.0/cattle_grid/config/test_validators.py +61 -0
  94. cattle_grid-0.2.0/cattle_grid/config/validators.py +54 -0
  95. cattle_grid-0.2.0/cattle_grid/database.py +94 -0
  96. cattle_grid-0.2.0/cattle_grid/dependencies/__init__.py +60 -0
  97. cattle_grid-0.2.0/cattle_grid/dependencies/fastapi.py +21 -0
  98. cattle_grid-0.2.0/cattle_grid/dependencies/globals.py +65 -0
  99. cattle_grid-0.2.0/cattle_grid/dependencies/test_globals.py +8 -0
  100. cattle_grid-0.2.0/cattle_grid/exchange/__init__.py +99 -0
  101. cattle_grid-0.2.0/cattle_grid/exchange/actor_update.py +89 -0
  102. cattle_grid-0.2.0/cattle_grid/exchange/handlers.py +85 -0
  103. cattle_grid-0.2.0/cattle_grid/exchange/info.py +19 -0
  104. cattle_grid-0.2.0/cattle_grid/exchange/message_handlers.py +45 -0
  105. cattle_grid-0.2.0/cattle_grid/exchange/server/__init__.py +34 -0
  106. cattle_grid-0.2.0/cattle_grid/exchange/server/account.py +54 -0
  107. cattle_grid-0.2.0/cattle_grid/exchange/server/test_account.py +111 -0
  108. cattle_grid-0.2.0/cattle_grid/exchange/shovel.py +138 -0
  109. cattle_grid-0.2.0/cattle_grid/exchange/test_actor_update.py +49 -0
  110. cattle_grid-0.2.0/cattle_grid/exchange/test_handlers.py +92 -0
  111. cattle_grid-0.2.0/cattle_grid/exchange/test_message_handlers.py +32 -0
  112. cattle_grid-0.2.0/cattle_grid/exchange/test_shovel.py +216 -0
  113. cattle_grid-0.2.0/cattle_grid/extensions/__init__.py +161 -0
  114. cattle_grid-0.2.0/cattle_grid/extensions/examples/__init__.py +0 -0
  115. cattle_grid-0.2.0/cattle_grid/extensions/examples/cache/__init__.py +66 -0
  116. cattle_grid-0.2.0/cattle_grid/extensions/examples/cache/config.py +9 -0
  117. cattle_grid-0.2.0/cattle_grid/extensions/examples/cache/dependencies.py +32 -0
  118. cattle_grid-0.2.0/cattle_grid/extensions/examples/cache/lookup.py +23 -0
  119. cattle_grid-0.2.0/cattle_grid/extensions/examples/cache/test_lookup.py +30 -0
  120. cattle_grid-0.2.0/cattle_grid/extensions/examples/cache/testing.py +11 -0
  121. cattle_grid-0.2.0/cattle_grid/extensions/examples/recipients.py +35 -0
  122. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/__init__.py +201 -0
  123. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/config.py +36 -0
  124. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/database.py +40 -0
  125. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/message_types.py +41 -0
  126. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/models.py +43 -0
  127. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/test_api.py +135 -0
  128. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/test_config.py +18 -0
  129. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/test_handlers.py +132 -0
  130. cattle_grid-0.2.0/cattle_grid/extensions/examples/simple_storage/test_init.py +16 -0
  131. cattle_grid-0.2.0/cattle_grid/extensions/examples/test_examples.py +20 -0
  132. cattle_grid-0.2.0/cattle_grid/extensions/examples/test_recipients.py +14 -0
  133. cattle_grid-0.2.0/cattle_grid/extensions/examples/webfinger_lookup.py +77 -0
  134. cattle_grid-0.2.0/cattle_grid/extensions/helper.py +31 -0
  135. cattle_grid-0.2.0/cattle_grid/extensions/load/__init__.py +116 -0
  136. cattle_grid-0.2.0/cattle_grid/extensions/load/lifespan.py +23 -0
  137. cattle_grid-0.2.0/cattle_grid/extensions/load/lookup.py +16 -0
  138. cattle_grid-0.2.0/cattle_grid/extensions/load/test_init.py +30 -0
  139. cattle_grid-0.2.0/cattle_grid/extensions/load/test_lifespan.py +36 -0
  140. cattle_grid-0.2.0/cattle_grid/extensions/load/test_load.py +29 -0
  141. cattle_grid-0.2.0/cattle_grid/extensions/load/test_lookup.py +36 -0
  142. cattle_grid-0.2.0/cattle_grid/extensions/load/test_util.py +38 -0
  143. cattle_grid-0.2.0/cattle_grid/extensions/load/types.py +22 -0
  144. cattle_grid-0.2.0/cattle_grid/extensions/load/util.py +56 -0
  145. cattle_grid-0.2.0/cattle_grid/extensions/test_init.py +80 -0
  146. cattle_grid-0.2.0/cattle_grid/extensions/test_init_api_router.py +29 -0
  147. cattle_grid-0.2.0/cattle_grid/extensions/util.py +23 -0
  148. cattle_grid-0.2.0/cattle_grid/migrations/ap_models/0_20241226112941_init.py +106 -0
  149. cattle_grid-0.2.0/cattle_grid/model/__init__.py +39 -0
  150. cattle_grid-0.2.0/cattle_grid/model/account.py +187 -0
  151. cattle_grid-0.2.0/cattle_grid/model/exchange.py +82 -0
  152. cattle_grid-0.2.0/cattle_grid/model/extension.py +23 -0
  153. cattle_grid-0.2.0/cattle_grid/model/lookup.py +26 -0
  154. cattle_grid-0.2.0/cattle_grid/model/messages.py +35 -0
  155. cattle_grid-0.2.0/cattle_grid/model/processing.py +17 -0
  156. cattle_grid-0.2.0/cattle_grid/model/test_exchange.py +17 -0
  157. cattle_grid-0.2.0/cattle_grid/processor.py +70 -0
  158. cattle_grid-0.2.0/cattle_grid/statistics.py +12 -0
  159. cattle_grid-0.2.0/cattle_grid/test_database.py +23 -0
  160. cattle_grid-0.2.0/cattle_grid/test_init.py +7 -0
  161. cattle_grid-0.2.0/cattle_grid/testing/__init__.py +0 -0
  162. cattle_grid-0.2.0/cattle_grid/testing/extensions/__init__.py +0 -0
  163. cattle_grid-0.2.0/cattle_grid/testing/extensions/lookup.py +24 -0
  164. cattle_grid-0.2.0/cattle_grid/testing/extensions/one.py +6 -0
  165. cattle_grid-0.2.0/cattle_grid/testing/extensions/two.py +6 -0
  166. cattle_grid-0.2.0/cattle_grid/testing/features/__init__.py +119 -0
  167. cattle_grid-0.2.0/cattle_grid/testing/features/reporting.py +26 -0
  168. cattle_grid-0.2.0/cattle_grid/testing/features/steps/__init__.py +5 -0
  169. cattle_grid-0.2.0/cattle_grid/testing/features/steps/block.py +72 -0
  170. cattle_grid-0.2.0/cattle_grid/testing/features/steps/collection.py +61 -0
  171. cattle_grid-0.2.0/cattle_grid/testing/features/steps/follow.py +173 -0
  172. cattle_grid-0.2.0/cattle_grid/testing/features/steps/messaging.py +194 -0
  173. cattle_grid-0.2.0/cattle_grid/testing/features/steps/user.py +117 -0
  174. cattle_grid-0.2.0/cattle_grid/testing/fixtures.py +31 -0
  175. cattle_grid-0.2.0/cattle_grid/testing/reporter.py +120 -0
  176. cattle_grid-0.2.0/cattle_grid/version.py +1 -0
  177. cattle_grid-0.2.0/cattle_grid.toml +45 -0
  178. cattle_grid-0.2.0/docker-compose.yml +102 -0
  179. cattle_grid-0.2.0/docs/.pages +15 -0
  180. cattle_grid-0.2.0/docs/apis.md +32 -0
  181. cattle_grid-0.2.0/docs/architecture/.pages +11 -0
  182. cattle_grid-0.2.0/docs/architecture/activity_pub.md +9 -0
  183. cattle_grid-0.2.0/docs/architecture/activity_pub.models.md +3 -0
  184. cattle_grid-0.2.0/docs/architecture/activity_pub.processing.md +5 -0
  185. cattle_grid-0.2.0/docs/architecture/activity_pub.server.md +5 -0
  186. cattle_grid-0.2.0/docs/architecture/activitypub.md +67 -0
  187. cattle_grid-0.2.0/docs/architecture/exchange.md +5 -0
  188. cattle_grid-0.2.0/docs/architecture/index.md +74 -0
  189. cattle_grid-0.2.0/docs/architecture/usage.md +9 -0
  190. cattle_grid-0.2.0/docs/assets/.gitignore +1 -0
  191. cattle_grid-0.2.0/docs/assets/asyncapi.html +82 -0
  192. cattle_grid-0.2.0/docs/assets/redoc.html +17 -0
  193. cattle_grid-0.2.0/docs/assets/redoc_auth.html +6 -0
  194. cattle_grid-0.2.0/docs/authentication/blocking.md +7 -0
  195. cattle_grid-0.2.0/docs/authentication/configuration.md +133 -0
  196. cattle_grid-0.2.0/docs/authentication/index.md +127 -0
  197. cattle_grid-0.2.0/docs/authentication/request_flow.md +117 -0
  198. cattle_grid-0.2.0/docs/cattle_drive.md +383 -0
  199. cattle_grid-0.2.0/docs/extensions/.pages +9 -0
  200. cattle_grid-0.2.0/docs/extensions/cache.md +4 -0
  201. cattle_grid-0.2.0/docs/extensions/dependencies.md +4 -0
  202. cattle_grid-0.2.0/docs/extensions/index.md +55 -0
  203. cattle_grid-0.2.0/docs/extensions/recipients.md +3 -0
  204. cattle_grid-0.2.0/docs/extensions/reference.md +7 -0
  205. cattle_grid-0.2.0/docs/extensions/simple_storage.md +4 -0
  206. cattle_grid-0.2.0/docs/extensions/webfinger_lookup.md +3 -0
  207. cattle_grid-0.2.0/docs/index.md +218 -0
  208. cattle_grid-0.2.0/docs/installation.md +86 -0
  209. cattle_grid-0.2.0/docs/methods.md +5 -0
  210. cattle_grid-0.2.0/docs/reference/auth.md +5 -0
  211. cattle_grid-0.2.0/docs/reference/config.md +5 -0
  212. cattle_grid-0.2.0/docs/reference/model.md +5 -0
  213. cattle_grid-0.2.0/docs/reference/rabbitmq.md +13 -0
  214. cattle_grid-0.2.0/docs/testing/feature.md +3 -0
  215. cattle_grid-0.2.0/docs/testing/index.md +5 -0
  216. cattle_grid-0.2.0/docs/testing/reporting.md +52 -0
  217. cattle_grid-0.2.0/docs/testing/steps.md +17 -0
  218. cattle_grid-0.2.0/docs/tool.md +7 -0
  219. cattle_grid-0.2.0/dummy_woodpecker.yml +8 -0
  220. cattle_grid-0.2.0/features/.gitignore +2 -0
  221. cattle_grid-0.2.0/features/authorization.feature +39 -0
  222. cattle_grid-0.2.0/features/basic.feature +39 -0
  223. cattle_grid-0.2.0/features/environment.py +8 -0
  224. cattle_grid-0.2.0/features/simple_storage.feature +9 -0
  225. cattle_grid-0.2.0/features/steps/authorization.py +44 -0
  226. cattle_grid-0.2.0/features/steps/import.py +1 -0
  227. cattle_grid-0.2.0/features/steps/messaging.py +44 -0
  228. cattle_grid-0.2.0/features/steps/my_steps.py +57 -0
  229. cattle_grid-0.2.0/features/steps/server.py +58 -0
  230. cattle_grid-0.2.0/features/steps/simple_storage.py +27 -0
  231. cattle_grid-0.2.0/fediverse-features.toml +10 -0
  232. cattle_grid-0.2.0/jskitten/Dockerfile +3 -0
  233. cattle_grid-0.2.0/jskitten/app.js +162 -0
  234. cattle_grid-0.2.0/jskitten/package-lock.json +1096 -0
  235. cattle_grid-0.2.0/jskitten/package.json +19 -0
  236. cattle_grid-0.2.0/jskitten/startup.sh +11 -0
  237. cattle_grid-0.2.0/mastodon.png +0 -0
  238. cattle_grid-0.2.0/mkdocs.yml +72 -0
  239. cattle_grid-0.2.0/pyproject.toml +83 -0
  240. cattle_grid-0.2.0/resources/activity_message.schema.json +43 -0
  241. cattle_grid-0.2.0/resources/dev/03_http_auth.conf +8 -0
  242. cattle_grid-0.2.0/resources/dev/nginx.conf +88 -0
  243. cattle_grid-0.2.0/resources/dev/rabbit_enabled_plugins +1 -0
  244. cattle_grid-0.2.0/resources/dev/startup.sh +7 -0
  245. cattle_grid-0.2.0/resources/docker/Dockerfile +4 -0
  246. cattle_grid-0.2.0/resources/docker/build.sh +19 -0
  247. cattle_grid-0.2.0/resources/docker/cattle_grid.toml +223 -0
  248. cattle_grid-0.2.0/resources/docker_dev/Dockerfile +6 -0
  249. cattle_grid-0.2.0/resources/generate_models.sh +44 -0
  250. cattle_grid-0.2.0/resources/managing.schema.json +65 -0
  251. cattle_grid-0.2.0/resources/packages/Dockerfile +8 -0
  252. cattle_grid-0.2.0/resources/packages/build.sh +9 -0
  253. cattle_grid-0.2.0/resources/packages/cattle_grid.toml +19 -0
  254. cattle_grid-0.2.0/resources/packages/cattle_grid_auth.toml +45 -0
  255. cattle_grid-0.2.0/resources/packages/docker-compose.yml +75 -0
  256. cattle_grid-0.2.0/resources/schema/activity_pub/activity.schema.json +41 -0
  257. cattle_grid-0.2.0/resources/schema/activity_pub/base.schema.json +52 -0
  258. cattle_grid-0.2.0/resources/schema/activity_pub/object.schema.json +49 -0
  259. cattle_grid-0.2.0/resources/schema/activity_pub.schema.json +7 -0
  260. cattle_grid-0.2.0/resources/schema/gateway/gateway_message.schema.json +31 -0
  261. cattle_grid-0.2.0/resources/schema/gateway/gateway_message_result.schema.json +23 -0
  262. cattle_grid-0.2.0/resources/schema/gateway.schema.json +9 -0
  263. cattle_grid-0.2.0/uv.lock +3423 -0
@@ -0,0 +1,3 @@
1
+ [behave]
2
+ show_skipped = 0
3
+ default_tags = ~@wishlist
@@ -0,0 +1,13 @@
1
+ .coverage
2
+ *.sqlite*
3
+ *.whl
4
+ /cattle_grid_auth.toml
5
+ /cattle_grid_block_list.toml
6
+ cattle_grid.db*
7
+ *.pem
8
+ dist
9
+ reports
10
+ build
11
+ cattle_grid.egg-info
12
+ docs/assets/openapi.json
13
+ requirements.txt
@@ -0,0 +1,15 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: "ubuntu-22.04"
5
+ tools:
6
+ python: "3.11"
7
+ jobs:
8
+ post_create_environment:
9
+ - pip install poetry
10
+ - poetry config virtualenvs.create false
11
+ post_install:
12
+ - poetry install --with=dev,doc --all-extras -vvv
13
+
14
+ mkdocs:
15
+ configuration: docs/mkdocs.yml
@@ -0,0 +1,13 @@
1
+ when:
2
+ - event: tag
3
+ branch: main
4
+ steps:
5
+ bovine:
6
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
7
+ commands:
8
+ - uv sync --frozen
9
+ - uv build
10
+ - uv publish --token $PYPI_API_KEY
11
+ environment:
12
+ PYPI_API_KEY:
13
+ from_secret: pypi_api_key
@@ -0,0 +1,23 @@
1
+ when:
2
+ - branch: [main]
3
+ event: [pull_request, push]
4
+
5
+ steps:
6
+ build:
7
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
8
+ commands:
9
+ - uv sync --frozen
10
+ test_format:
11
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
12
+ commands:
13
+ - uv run ruff format .
14
+ - uv run ruff check .
15
+ test_pytest:
16
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
17
+ commands:
18
+ - uv run pytest
19
+ build_docs:
20
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
21
+ commands:
22
+ - uv run mkdocs build
23
+
@@ -0,0 +1,27 @@
1
+ when:
2
+ branch: main
3
+ event: push
4
+
5
+ steps:
6
+ build:
7
+ image: ghcr.io/astral-sh/uv:python3.11-alpine
8
+ commands:
9
+ - mkdir -p docs/assets/schemas
10
+ - uv sync --frozen
11
+ - uv run python -mcattle_grid.auth new-config http://localhost/cattle_grid_actor
12
+ - uv run python -mcattle_grid openapi --filename docs/assets/schemas/openapi.json
13
+ - uv run python -mcattle_grid openapi --filename docs/assets/schemas/openapi_ap.json --component ap
14
+ - uv run python -mcattle_grid openapi --filename docs/assets/schemas/openapi_autn.json --component auth
15
+ - uv run python -mcattle_grid async-api --filename docs/assets/schemas/asyncapi_ap.json --component ap
16
+ - uv run python -mcattle_grid async-api --filename docs/assets/schemas/asyncapi_exchange.json
17
+ - uv run python -mcattle_grid openapi --component account --filename docs/assets/schemas/openapi_account.json
18
+ - uv run python -mcattle_grid openapi --component account --filename docs/assets/schemas/openapi_account_ap.json --component ap
19
+ - uv run python -mcattle_grid async-api --component account --filename docs/assets/schemas/asyncapi_account.json
20
+ - uv run python -mcattle_grid openapi --component rabbit --filename docs/assets/schemas/openapi_rabbit.json
21
+ - uv run mkdocs build
22
+ deploy:
23
+ image: codeberg.org/xfix/plugin-codeberg-pages-deploy:1
24
+ settings:
25
+ folder: site
26
+ ssh_key:
27
+ from_secret: deploy_ssh_key
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Helge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,109 @@
1
+ Metadata-Version: 2.4
2
+ Name: cattle_grid
3
+ Version: 0.2.0
4
+ Summary: Middleware for the Fediverse
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: aerich>=0.8.0
8
+ Requires-Dist: almabtrieb>=0.1.0a1
9
+ Requires-Dist: argon2-cffi>=23.1.0
10
+ Requires-Dist: bleach>=6.2.0
11
+ Requires-Dist: bovine>=0.5.13
12
+ Requires-Dist: dynaconf>=3.2.6
13
+ Requires-Dist: fastapi>=0.115.4
14
+ Requires-Dist: faststream[cli,rabbit]>=0.5.25
15
+ Requires-Dist: fediverse-pasture>=0.2.14
16
+ Requires-Dist: python-multipart>=0.0.17
17
+ Requires-Dist: quart>=0.19.6
18
+ Requires-Dist: sqlalchemy-utils>=0.41.2
19
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.36
20
+ Requires-Dist: tomli-w>=1.0.0
21
+ Requires-Dist: tortoise-orm[asyncpg]>=0.21.6
22
+ Requires-Dist: uuid6>=2024.7.10
23
+ Provides-Extra: cache
24
+ Requires-Dist: redis>=5.2.1; extra == 'cache'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # cattle_grid
28
+
29
+ THIS README needs to be updated for cattle_grid 0.2.0
30
+
31
+ cattle_grid is meant to simplify handling authentication in server to
32
+ server communication of the Fediverse. cattle_grid checks the HTTP
33
+ signatures based on the headers. For this public keys are retrieved
34
+ and cached.
35
+
36
+ For installation instructions see the [documentation](https://bovine.codeberg.page/cattle_grid/).
37
+
38
+ ## Running
39
+
40
+ After creating a configuration file, one can run cattle_grid via
41
+
42
+ ```bash
43
+ poetry run uvicorn cattle_grid:create_app
44
+ ```
45
+
46
+ ## Development
47
+
48
+ One can run the pytest tests via
49
+
50
+ ```bash
51
+ poetry install
52
+ poetry run pytest
53
+ ```
54
+
55
+ ## Development with Fediverse pasture
56
+
57
+ In your Funfedi.dev directory (see [here](https://funfedi.dev/testing_tools/verify_actor/)
58
+ for details), run
59
+
60
+ ```bash
61
+ cd fediverse-pasture
62
+ docker compose --file pasture.yml up pasture_verify_actor
63
+ ```
64
+
65
+ Now in the cattle grid directory, run
66
+
67
+ ```bash
68
+ poetry run python -mcattle_grid.config --actor_id http://cattle_grid/actor
69
+ ```
70
+
71
+ to create a `cattle_grid.toml` file. Then start the docker containers via
72
+
73
+ ```bash
74
+ docker compose up
75
+ ```
76
+
77
+ By opening [http://localhost:2909/?actor_uri=jskitten@cattle_grid_demo](http://localhost:2909/?actor_uri=jskitten%40cattle_grid_demo), you should then be able to view the verify actor result. By refreshing the page and inspecting the log files, you can also check that the requests only ran once.
78
+
79
+ ### Creating an user
80
+
81
+ By running
82
+
83
+ ```bash
84
+ docker compose run runner
85
+ ```
86
+
87
+ one can start a shell in the docker environment. By then running in it
88
+
89
+ ```bash
90
+ curl abel/admin/create -X POST -F username=name -F password=secret
91
+ ```
92
+
93
+ one can create the user with handle `@name@abel`.
94
+
95
+ ## Running GUI tests with the pasture
96
+
97
+ Start mastodon accessible through your browser
98
+
99
+ ```bash
100
+ cd fediverse-pasture
101
+ docker compose --file mastodon42.yml --profile nginx up
102
+ ```
103
+
104
+ See [Fun Fediverse Development](https://funfedi.dev/fediverse_pasture/applications/mastodon_4_2/) for instructions.
105
+
106
+ Then you can open [mastodon42web](http://mastodon42web) and lookup `jskitten@cattle_grid_demo`.
107
+ When you send a message to this kitten, it should reply with a meow, e.g.
108
+
109
+ ![Kitten meows](mastodon.png)
@@ -0,0 +1,83 @@
1
+ # cattle_grid
2
+
3
+ THIS README needs to be updated for cattle_grid 0.2.0
4
+
5
+ cattle_grid is meant to simplify handling authentication in server to
6
+ server communication of the Fediverse. cattle_grid checks the HTTP
7
+ signatures based on the headers. For this public keys are retrieved
8
+ and cached.
9
+
10
+ For installation instructions see the [documentation](https://bovine.codeberg.page/cattle_grid/).
11
+
12
+ ## Running
13
+
14
+ After creating a configuration file, one can run cattle_grid via
15
+
16
+ ```bash
17
+ poetry run uvicorn cattle_grid:create_app
18
+ ```
19
+
20
+ ## Development
21
+
22
+ One can run the pytest tests via
23
+
24
+ ```bash
25
+ poetry install
26
+ poetry run pytest
27
+ ```
28
+
29
+ ## Development with Fediverse pasture
30
+
31
+ In your Funfedi.dev directory (see [here](https://funfedi.dev/testing_tools/verify_actor/)
32
+ for details), run
33
+
34
+ ```bash
35
+ cd fediverse-pasture
36
+ docker compose --file pasture.yml up pasture_verify_actor
37
+ ```
38
+
39
+ Now in the cattle grid directory, run
40
+
41
+ ```bash
42
+ poetry run python -mcattle_grid.config --actor_id http://cattle_grid/actor
43
+ ```
44
+
45
+ to create a `cattle_grid.toml` file. Then start the docker containers via
46
+
47
+ ```bash
48
+ docker compose up
49
+ ```
50
+
51
+ By opening [http://localhost:2909/?actor_uri=jskitten@cattle_grid_demo](http://localhost:2909/?actor_uri=jskitten%40cattle_grid_demo), you should then be able to view the verify actor result. By refreshing the page and inspecting the log files, you can also check that the requests only ran once.
52
+
53
+ ### Creating an user
54
+
55
+ By running
56
+
57
+ ```bash
58
+ docker compose run runner
59
+ ```
60
+
61
+ one can start a shell in the docker environment. By then running in it
62
+
63
+ ```bash
64
+ curl abel/admin/create -X POST -F username=name -F password=secret
65
+ ```
66
+
67
+ one can create the user with handle `@name@abel`.
68
+
69
+ ## Running GUI tests with the pasture
70
+
71
+ Start mastodon accessible through your browser
72
+
73
+ ```bash
74
+ cd fediverse-pasture
75
+ docker compose --file mastodon42.yml --profile nginx up
76
+ ```
77
+
78
+ See [Fun Fediverse Development](https://funfedi.dev/fediverse_pasture/applications/mastodon_4_2/) for instructions.
79
+
80
+ Then you can open [mastodon42web](http://mastodon42web) and lookup `jskitten@cattle_grid_demo`.
81
+ When you send a message to this kitten, it should reply with a meow, e.g.
82
+
83
+ ![Kitten meows](mastodon.png)
@@ -0,0 +1,84 @@
1
+ import logging
2
+ from typing import List
3
+
4
+ from fastapi import FastAPI
5
+ from faststream.rabbit import RabbitBroker
6
+ from contextlib import asynccontextmanager
7
+
8
+ from .activity_pub.server import router as ap_router
9
+ from .auth.router import create_auth_router
10
+
11
+ from .config import load_settings, default_filenames
12
+ from .config.messaging import broker
13
+ from .config.auth import get_auth_config
14
+ from .exchange.server import create_exchange_api_router
15
+ from .account.server import router as fe_router
16
+ from .account.rabbit import rabbit_router
17
+ from .extensions.load import load_extensions, add_routes_to_api, set_globals
18
+ from .dependencies.globals import alchemy_database
19
+
20
+ from .version import __version__
21
+ from .database import database, upgrade
22
+
23
+ logging.basicConfig(level=logging.INFO)
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ tags_description = [
28
+ {
29
+ "name": "activity_pub",
30
+ "description": "Endpoints used and consumed by other Fediverse applications to communicate through cattle_grid",
31
+ },
32
+ {
33
+ "name": "auth",
34
+ "description": """Authentication endpoints
35
+
36
+ The auth endpoint allows one to check the HTTP Signature
37
+ and reject requests with an invalid one, only based on the
38
+ headers. This step then occurs before the request is passed
39
+ to the application. Furthermore, this behavior can be shared
40
+ accross many services.""",
41
+ },
42
+ ]
43
+
44
+
45
+ def create_app(filenames: List[str] = default_filenames) -> FastAPI:
46
+ logger.info("Running cattle grid version %s", __version__)
47
+
48
+ base_config = load_settings(filenames=filenames)
49
+
50
+ extensions = load_extensions(base_config)
51
+ set_globals(extensions)
52
+
53
+ @asynccontextmanager
54
+ async def lifespan(app: FastAPI, broker: RabbitBroker = broker()):
55
+ await upgrade(base_config)
56
+
57
+ await broker.start()
58
+ async with database(base_config.db_uri, generate_schemas=False):
59
+ async with alchemy_database(base_config.db_uri):
60
+ yield
61
+ await broker.close()
62
+
63
+ app = FastAPI(
64
+ lifespan=lifespan,
65
+ title="cattle_grid",
66
+ description="middle ware for the Fediverse",
67
+ version=__version__,
68
+ openapi_tags=tags_description,
69
+ )
70
+
71
+ app.include_router(ap_router)
72
+ app.include_router(create_exchange_api_router(base_config))
73
+ app.include_router(create_auth_router(get_auth_config(base_config)), prefix="/auth")
74
+
75
+ app.include_router(fe_router, prefix="/fe")
76
+ app.include_router(rabbit_router)
77
+
78
+ add_routes_to_api(app, extensions)
79
+
80
+ @app.get("/")
81
+ async def main() -> str:
82
+ return "cattle_grid"
83
+
84
+ return app
@@ -0,0 +1,150 @@
1
+ import click
2
+ import os
3
+ import asyncio
4
+ import logging
5
+
6
+ from cattle_grid.config import load_settings, default_filenames
7
+ from .statistics import statistics
8
+ from .auth.block_cli import add_block_command
9
+ from .auth.key_cli import add_keys_command
10
+
11
+ from .extensions.helper import add_extension_commands
12
+ from .account.cli import add_account_commands
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @click.group()
18
+ @click.option("--config_file", default="cattle_grid.toml")
19
+ @click.pass_context
20
+ def main(ctx, config_file):
21
+ ctx.ensure_object(dict)
22
+ ctx.obj["config_file"] = config_file
23
+
24
+ try:
25
+ ctx.obj["config"] = load_settings(config_file)
26
+ except Exception as e:
27
+ logger.Exception(e)
28
+
29
+
30
+ @main.command()
31
+ @click.option(
32
+ "--force",
33
+ help="Used to override the old configuration file",
34
+ is_flag=True,
35
+ default=False,
36
+ )
37
+ @click.pass_context
38
+ def new_config(ctx, force):
39
+ """Creates a new configuration file"""
40
+ filename = ctx.obj["config_file"]
41
+
42
+ if os.path.exists(filename) and not force:
43
+ print("Configuration file already exists! Use --force to overwrite.")
44
+ exit(1)
45
+
46
+ # FIXME
47
+
48
+ exit(1)
49
+
50
+
51
+ @main.command()
52
+ @click.pass_context
53
+ def stat(ctx):
54
+ """Displays statistical information about cattle_grid"""
55
+ asyncio.run(statistics(ctx.obj["config"]))
56
+
57
+
58
+ @main.command()
59
+ @click.option("--db_uri")
60
+ @click.option("--name")
61
+ @click.pass_context
62
+ def create_db_migration(ctx, db_uri, name):
63
+ """Creates a database migration; run after editing models"""
64
+ from .database import migrate
65
+
66
+ config = ctx.obj["config"]
67
+
68
+ if db_uri:
69
+ config.db_uri = db_uri
70
+
71
+ asyncio.run(migrate(config, name))
72
+
73
+
74
+ @main.command()
75
+ @click.option("--db_uri")
76
+ @click.pass_context
77
+ def upgrade_db(ctx, db_uri):
78
+ from .database import upgrade
79
+
80
+ config = ctx.obj["config"]
81
+
82
+ if db_uri:
83
+ config.db_uri = db_uri
84
+
85
+ asyncio.run(upgrade(config))
86
+
87
+
88
+ @main.command()
89
+ @click.option("--filename", default="asyncapi.json")
90
+ @click.option(
91
+ "--component",
92
+ default=None,
93
+ help="Restrict to a component. Currently allowed ap",
94
+ )
95
+ def async_api(filename, component):
96
+ if component == "ap":
97
+ from .activity_pub import get_async_api_schema
98
+ elif component == "account":
99
+ from .account.router.schema import get_async_api_schema
100
+ else:
101
+ from .exchange import get_async_api_schema
102
+
103
+ schema = get_async_api_schema().to_json()
104
+
105
+ with open(filename, "w") as fp:
106
+ fp.write(schema)
107
+
108
+
109
+ @main.command()
110
+ @click.option("--filename", default="openapi.json")
111
+ @click.option(
112
+ "--component",
113
+ default=None,
114
+ help="Restrict to a component. Currently allowed auth or ap",
115
+ )
116
+ @click.pass_context
117
+ def openapi(ctx, filename, component):
118
+ import json
119
+
120
+ match component:
121
+ case "auth":
122
+ from .auth import create_app
123
+
124
+ app = create_app(default_filenames)
125
+ case "ap":
126
+ from .activity_pub import get_fastapi_app
127
+
128
+ app = get_fastapi_app()
129
+ case "account":
130
+ from .account.server.app import app
131
+ case "rabbit":
132
+ from .account.rabbit import app_for_schema
133
+
134
+ app = app_for_schema()
135
+ case _:
136
+ from . import create_app
137
+
138
+ # app = create_app(ctx.obj["config_file"])
139
+ app = create_app()
140
+ with open(filename, "w") as fp:
141
+ json.dump(app.openapi(), fp)
142
+
143
+
144
+ add_block_command(main)
145
+ add_keys_command(main)
146
+ add_extension_commands(main)
147
+ add_account_commands(main)
148
+
149
+ if __name__ == "__main__":
150
+ main()
File without changes
@@ -0,0 +1,39 @@
1
+ import argon2
2
+ import logging
3
+
4
+
5
+ from .models import Account
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+ password_hasher = argon2.PasswordHasher()
10
+
11
+
12
+ async def create_account(username: str, password: str) -> Account | None:
13
+ """Creates a new account for username and password"""
14
+ if await Account.get_or_none(name=username):
15
+ return None
16
+
17
+ return await Account.create(
18
+ name=username, password_hash=password_hasher.hash(password)
19
+ )
20
+
21
+
22
+ async def account_with_username_password(
23
+ username: str, password: str
24
+ ) -> Account | None:
25
+ """Retrieves account for given username and password"""
26
+ account = await Account.get_or_none(name=username)
27
+ if account is None:
28
+ return None
29
+
30
+ try:
31
+ password_hasher.verify(account.password_hash, password)
32
+ except argon2.exceptions.VerifyMismatchError:
33
+ logger.warning("Got wrong password for %s", username)
34
+ return None
35
+
36
+ # Implement rehash?
37
+ # https://argon2-cffi.readthedocs.io/en/stable/howto.html
38
+
39
+ return account
@@ -0,0 +1,39 @@
1
+ import click
2
+ import asyncio
3
+
4
+
5
+ from cattle_grid.database import database
6
+ from .models import Account
7
+ from .account import create_account
8
+
9
+
10
+ async def new_account(config, name, password):
11
+ async with database(db_uri=config.db_uri):
12
+ await create_account(name, password)
13
+
14
+
15
+ async def list_accounts(config):
16
+ async with database(db_uri=config.db_uri):
17
+ accounts = await Account.all()
18
+ for account in accounts:
19
+ print(account.name)
20
+
21
+
22
+ def add_account_commands(main):
23
+ @main.group()
24
+ def account():
25
+ """Used to manage accounts associated with cattle_grid"""
26
+
27
+ @account.command()
28
+ @click.argument("name")
29
+ @click.argument("password")
30
+ @click.pass_context
31
+ def new(cfg, name, password):
32
+ """Creates a new account"""
33
+ asyncio.run(new_account(cfg.obj["config"], name, password))
34
+
35
+ @account.command()
36
+ @click.pass_context
37
+ def list(cfg):
38
+ """Lists existing accounts"""
39
+ asyncio.run(list_accounts(cfg.obj["config"]))
@@ -0,0 +1,37 @@
1
+ from tortoise import fields
2
+ from tortoise.models import Model
3
+
4
+
5
+ class Account(Model):
6
+ """Represents an Account"""
7
+
8
+ id = fields.IntField(primary_key=True)
9
+
10
+ name = fields.CharField(max_length=255)
11
+ """The account name"""
12
+
13
+ password_hash = fields.CharField(max_length=255)
14
+ """The hashed password"""
15
+
16
+ actors: fields.ReverseRelation["ActorForAccount"]
17
+ """Actors associated with this account"""
18
+
19
+ token: fields.ReverseRelation["AuthenticationToken"]
20
+ """Authentication tokens for this account"""
21
+
22
+
23
+ class ActorForAccount(Model):
24
+ id = fields.IntField(primary_key=True)
25
+
26
+ account: fields.ForeignKeyRelation[Account] = fields.ForeignKeyField(
27
+ "gateway_models.Account", related_name="actors"
28
+ )
29
+ actor = fields.CharField(max_length=255)
30
+
31
+
32
+ class AuthenticationToken(Model):
33
+ token = fields.CharField(max_length=64, primary_key=True)
34
+
35
+ account: fields.ForeignKeyRelation[Account] = fields.ForeignKeyField(
36
+ "gateway_models.Account", related_name="tokens"
37
+ )