async-matrix 3.0.0-arm-linux-musl

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 (333) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +200 -0
  3. data/README.md +108 -0
  4. data/data/discord-api-spec/openapi.json +40404 -0
  5. data/data/matrix-spec/api/client-server/account-data.yaml +389 -0
  6. data/data/matrix-spec/api/client-server/account_deactivation.yaml +149 -0
  7. data/data/matrix-spec/api/client-server/admin.yaml +512 -0
  8. data/data/matrix-spec/api/client-server/administrative_contact.yaml +620 -0
  9. data/data/matrix-spec/api/client-server/appservice_ping.yaml +183 -0
  10. data/data/matrix-spec/api/client-server/appservice_room_directory.yaml +104 -0
  11. data/data/matrix-spec/api/client-server/authed-content-repo.yaml +590 -0
  12. data/data/matrix-spec/api/client-server/banning.yaml +177 -0
  13. data/data/matrix-spec/api/client-server/capabilities.yaml +235 -0
  14. data/data/matrix-spec/api/client-server/content-repo.yaml +887 -0
  15. data/data/matrix-spec/api/client-server/create_room.yaml +306 -0
  16. data/data/matrix-spec/api/client-server/cross_signing.yaml +300 -0
  17. data/data/matrix-spec/api/client-server/definitions/auth_data.yaml +34 -0
  18. data/data/matrix-spec/api/client-server/definitions/auth_response.yaml +62 -0
  19. data/data/matrix-spec/api/client-server/definitions/client_device.yaml +44 -0
  20. data/data/matrix-spec/api/client-server/definitions/client_event.yaml +49 -0
  21. data/data/matrix-spec/api/client-server/definitions/client_event_without_room_id.yaml +147 -0
  22. data/data/matrix-spec/api/client-server/definitions/cross_signing_key.yaml +57 -0
  23. data/data/matrix-spec/api/client-server/definitions/device_keys.yaml +70 -0
  24. data/data/matrix-spec/api/client-server/definitions/errors/error.yaml +26 -0
  25. data/data/matrix-spec/api/client-server/definitions/errors/rate_limited.yaml +34 -0
  26. data/data/matrix-spec/api/client-server/definitions/event_batch.yaml +22 -0
  27. data/data/matrix-spec/api/client-server/definitions/event_filter.yaml +55 -0
  28. data/data/matrix-spec/api/client-server/definitions/invite_3pid.yaml +45 -0
  29. data/data/matrix-spec/api/client-server/definitions/key_backup_auth_data.yaml +36 -0
  30. data/data/matrix-spec/api/client-server/definitions/key_backup_data.yaml +50 -0
  31. data/data/matrix-spec/api/client-server/definitions/key_backup_session_data.yaml +57 -0
  32. data/data/matrix-spec/api/client-server/definitions/m.login.terms_params.yaml +83 -0
  33. data/data/matrix-spec/api/client-server/definitions/m.mentions.yaml +33 -0
  34. data/data/matrix-spec/api/client-server/definitions/m.oauth_params.yaml +30 -0
  35. data/data/matrix-spec/api/client-server/definitions/m.relates_to.yaml +45 -0
  36. data/data/matrix-spec/api/client-server/definitions/megolm_export_session_data.yaml +39 -0
  37. data/data/matrix-spec/api/client-server/definitions/olm_payload.yaml +88 -0
  38. data/data/matrix-spec/api/client-server/definitions/one_time_keys.yaml +27 -0
  39. data/data/matrix-spec/api/client-server/definitions/openid_token.yaml +37 -0
  40. data/data/matrix-spec/api/client-server/definitions/protocol.yaml +44 -0
  41. data/data/matrix-spec/api/client-server/definitions/public_rooms_chunk.yaml +74 -0
  42. data/data/matrix-spec/api/client-server/definitions/public_rooms_response.yaml +59 -0
  43. data/data/matrix-spec/api/client-server/definitions/push_condition.yaml +53 -0
  44. data/data/matrix-spec/api/client-server/definitions/push_rule.yaml +53 -0
  45. data/data/matrix-spec/api/client-server/definitions/push_ruleset.yaml +206 -0
  46. data/data/matrix-spec/api/client-server/definitions/recent_emoji.yaml +29 -0
  47. data/data/matrix-spec/api/client-server/definitions/request_email_validation.yaml +36 -0
  48. data/data/matrix-spec/api/client-server/definitions/request_msisdn_validation.yaml +36 -0
  49. data/data/matrix-spec/api/client-server/definitions/request_token_response.yaml +46 -0
  50. data/data/matrix-spec/api/client-server/definitions/room_event_filter.yaml +60 -0
  51. data/data/matrix-spec/api/client-server/definitions/room_key_backup.yaml +37 -0
  52. data/data/matrix-spec/api/client-server/definitions/room_summary.yaml +44 -0
  53. data/data/matrix-spec/api/client-server/definitions/security.yaml +47 -0
  54. data/data/matrix-spec/api/client-server/definitions/sso_login_flow.yaml +98 -0
  55. data/data/matrix-spec/api/client-server/definitions/state_event_batch.yaml +21 -0
  56. data/data/matrix-spec/api/client-server/definitions/sync_filter.yaml +86 -0
  57. data/data/matrix-spec/api/client-server/definitions/tag.yaml +24 -0
  58. data/data/matrix-spec/api/client-server/definitions/third_party_signed.yaml +45 -0
  59. data/data/matrix-spec/api/client-server/definitions/timeline_batch.yaml +36 -0
  60. data/data/matrix-spec/api/client-server/definitions/user_identifier.yaml +27 -0
  61. data/data/matrix-spec/api/client-server/definitions/wellknown/full.yaml +38 -0
  62. data/data/matrix-spec/api/client-server/definitions/wellknown/homeserver.yaml +25 -0
  63. data/data/matrix-spec/api/client-server/definitions/wellknown/identity_server.yaml +25 -0
  64. data/data/matrix-spec/api/client-server/device_management.yaml +314 -0
  65. data/data/matrix-spec/api/client-server/directory.yaml +318 -0
  66. data/data/matrix-spec/api/client-server/event_context.yaml +161 -0
  67. data/data/matrix-spec/api/client-server/filter.yaml +224 -0
  68. data/data/matrix-spec/api/client-server/inviting.yaml +149 -0
  69. data/data/matrix-spec/api/client-server/joining.yaml +238 -0
  70. data/data/matrix-spec/api/client-server/key_backup.yaml +993 -0
  71. data/data/matrix-spec/api/client-server/keys.yaml +482 -0
  72. data/data/matrix-spec/api/client-server/kicking.yaml +110 -0
  73. data/data/matrix-spec/api/client-server/knocking.yaml +152 -0
  74. data/data/matrix-spec/api/client-server/leaving.yaml +163 -0
  75. data/data/matrix-spec/api/client-server/list_joined_rooms.yaml +68 -0
  76. data/data/matrix-spec/api/client-server/list_public_rooms.yaml +280 -0
  77. data/data/matrix-spec/api/client-server/login.yaml +321 -0
  78. data/data/matrix-spec/api/client-server/login_token.yaml +138 -0
  79. data/data/matrix-spec/api/client-server/logout.yaml +86 -0
  80. data/data/matrix-spec/api/client-server/message_pagination.yaml +194 -0
  81. data/data/matrix-spec/api/client-server/notifications.yaml +152 -0
  82. data/data/matrix-spec/api/client-server/oauth_server_metadata.yaml +238 -0
  83. data/data/matrix-spec/api/client-server/old_sync.yaml +379 -0
  84. data/data/matrix-spec/api/client-server/openid.yaml +98 -0
  85. data/data/matrix-spec/api/client-server/password_management.yaml +246 -0
  86. data/data/matrix-spec/api/client-server/peeking_events.yaml +122 -0
  87. data/data/matrix-spec/api/client-server/policy_server.yaml +82 -0
  88. data/data/matrix-spec/api/client-server/presence.yaml +169 -0
  89. data/data/matrix-spec/api/client-server/profile.yaml +366 -0
  90. data/data/matrix-spec/api/client-server/pusher.yaml +303 -0
  91. data/data/matrix-spec/api/client-server/pushrules.yaml +633 -0
  92. data/data/matrix-spec/api/client-server/read_markers.yaml +103 -0
  93. data/data/matrix-spec/api/client-server/receipts.yaml +139 -0
  94. data/data/matrix-spec/api/client-server/redaction.yaml +116 -0
  95. data/data/matrix-spec/api/client-server/refresh.yaml +119 -0
  96. data/data/matrix-spec/api/client-server/registration.yaml +488 -0
  97. data/data/matrix-spec/api/client-server/registration_tokens.yaml +93 -0
  98. data/data/matrix-spec/api/client-server/relations.yaml +382 -0
  99. data/data/matrix-spec/api/client-server/report_content.yaml +283 -0
  100. data/data/matrix-spec/api/client-server/room_event_by_timestamp.yaml +147 -0
  101. data/data/matrix-spec/api/client-server/room_initial_sync.yaml +188 -0
  102. data/data/matrix-spec/api/client-server/room_send.yaml +130 -0
  103. data/data/matrix-spec/api/client-server/room_state.yaml +159 -0
  104. data/data/matrix-spec/api/client-server/room_summary.yaml +138 -0
  105. data/data/matrix-spec/api/client-server/room_upgrades.yaml +130 -0
  106. data/data/matrix-spec/api/client-server/rooms.yaml +380 -0
  107. data/data/matrix-spec/api/client-server/search.yaml +385 -0
  108. data/data/matrix-spec/api/client-server/space_hierarchy.yaml +237 -0
  109. data/data/matrix-spec/api/client-server/sso_login_redirect.yaml +135 -0
  110. data/data/matrix-spec/api/client-server/support.yaml +142 -0
  111. data/data/matrix-spec/api/client-server/sync.yaml +692 -0
  112. data/data/matrix-spec/api/client-server/tags.yaml +183 -0
  113. data/data/matrix-spec/api/client-server/third_party_lookup.yaml +324 -0
  114. data/data/matrix-spec/api/client-server/third_party_membership.yaml +139 -0
  115. data/data/matrix-spec/api/client-server/threads_list.yaml +167 -0
  116. data/data/matrix-spec/api/client-server/to_device.yaml +104 -0
  117. data/data/matrix-spec/api/client-server/typing.yaml +103 -0
  118. data/data/matrix-spec/api/client-server/users.yaml +136 -0
  119. data/data/matrix-spec/api/client-server/versions.yaml +108 -0
  120. data/data/matrix-spec/api/client-server/voip.yaml +93 -0
  121. data/data/matrix-spec/api/client-server/wellknown.yaml +60 -0
  122. data/data/matrix-spec/api/client-server/whoami.yaml +121 -0
  123. data/data/matrix-spec/event-schemas/examples/core/event.json +6 -0
  124. data/data/matrix-spec/event-schemas/examples/core/room_edu.json +3 -0
  125. data/data/matrix-spec/event-schemas/examples/core/room_event.json +11 -0
  126. data/data/matrix-spec/event-schemas/examples/core/state_event.json +4 -0
  127. data/data/matrix-spec/event-schemas/examples/invite_room_state.json +18 -0
  128. data/data/matrix-spec/event-schemas/examples/knock_room_state.json +18 -0
  129. data/data/matrix-spec/event-schemas/examples/m.accepted_terms.yaml +10 -0
  130. data/data/matrix-spec/event-schemas/examples/m.call.answer.yaml +21 -0
  131. data/data/matrix-spec/event-schemas/examples/m.call.candidates.yaml +16 -0
  132. data/data/matrix-spec/event-schemas/examples/m.call.hangup.yaml +10 -0
  133. data/data/matrix-spec/event-schemas/examples/m.call.invite.yaml +22 -0
  134. data/data/matrix-spec/event-schemas/examples/m.call.negotiate.yaml +22 -0
  135. data/data/matrix-spec/event-schemas/examples/m.call.reject.yaml +9 -0
  136. data/data/matrix-spec/event-schemas/examples/m.call.sdp_stream_metadata_changed.yaml +16 -0
  137. data/data/matrix-spec/event-schemas/examples/m.call.select_answer.yaml +10 -0
  138. data/data/matrix-spec/event-schemas/examples/m.direct.yaml +10 -0
  139. data/data/matrix-spec/event-schemas/examples/m.dummy.yaml +4 -0
  140. data/data/matrix-spec/event-schemas/examples/m.forwarded_room_key.yaml +14 -0
  141. data/data/matrix-spec/event-schemas/examples/m.fully_read.yaml +7 -0
  142. data/data/matrix-spec/event-schemas/examples/m.identity_server.yaml +7 -0
  143. data/data/matrix-spec/event-schemas/examples/m.ignored_user_list.yaml +9 -0
  144. data/data/matrix-spec/event-schemas/examples/m.invite_permission_config.yaml +7 -0
  145. data/data/matrix-spec/event-schemas/examples/m.key.verification.accept.yaml +12 -0
  146. data/data/matrix-spec/event-schemas/examples/m.key.verification.cancel.yaml +8 -0
  147. data/data/matrix-spec/event-schemas/examples/m.key.verification.done.yaml +6 -0
  148. data/data/matrix-spec/event-schemas/examples/m.key.verification.key.yaml +7 -0
  149. data/data/matrix-spec/event-schemas/examples/m.key.verification.mac.yaml +10 -0
  150. data/data/matrix-spec/event-schemas/examples/m.key.verification.ready.yaml +10 -0
  151. data/data/matrix-spec/event-schemas/examples/m.key.verification.request.yaml +11 -0
  152. data/data/matrix-spec/event-schemas/examples/m.key.verification.start$m.sas.v1.yaml +12 -0
  153. data/data/matrix-spec/event-schemas/examples/m.key.verification.start.yaml +8 -0
  154. data/data/matrix-spec/event-schemas/examples/m.key_backup.yaml +7 -0
  155. data/data/matrix-spec/event-schemas/examples/m.marked_unread.yaml +7 -0
  156. data/data/matrix-spec/event-schemas/examples/m.policy.rule.room.yaml +10 -0
  157. data/data/matrix-spec/event-schemas/examples/m.policy.rule.server.yaml +10 -0
  158. data/data/matrix-spec/event-schemas/examples/m.policy.rule.user.yaml +10 -0
  159. data/data/matrix-spec/event-schemas/examples/m.presence.yaml +12 -0
  160. data/data/matrix-spec/event-schemas/examples/m.push_rules.yaml +177 -0
  161. data/data/matrix-spec/event-schemas/examples/m.reaction.yaml +11 -0
  162. data/data/matrix-spec/event-schemas/examples/m.receipt.yaml +18 -0
  163. data/data/matrix-spec/event-schemas/examples/m.recent_emoji.yaml +16 -0
  164. data/data/matrix-spec/event-schemas/examples/m.room.avatar.yaml +14 -0
  165. data/data/matrix-spec/event-schemas/examples/m.room.canonical_alias.yaml +12 -0
  166. data/data/matrix-spec/event-schemas/examples/m.room.create.yaml +13 -0
  167. data/data/matrix-spec/event-schemas/examples/m.room.encrypted$megolm.yaml +11 -0
  168. data/data/matrix-spec/event-schemas/examples/m.room.encrypted$olm.yaml +14 -0
  169. data/data/matrix-spec/event-schemas/examples/m.room.encryption.yaml +10 -0
  170. data/data/matrix-spec/event-schemas/examples/m.room.guest_access.yaml +8 -0
  171. data/data/matrix-spec/event-schemas/examples/m.room.history_visibility.yaml +8 -0
  172. data/data/matrix-spec/event-schemas/examples/m.room.join_rules$restricted.yaml +18 -0
  173. data/data/matrix-spec/event-schemas/examples/m.room.join_rules.yaml +8 -0
  174. data/data/matrix-spec/event-schemas/examples/m.room.member$invite_room_state.yaml +15 -0
  175. data/data/matrix-spec/event-schemas/examples/m.room.member$join_authorised_via_users_server.yaml +12 -0
  176. data/data/matrix-spec/event-schemas/examples/m.room.member$knock_room_state.yaml +15 -0
  177. data/data/matrix-spec/event-schemas/examples/m.room.member$third_party_invite.yaml +20 -0
  178. data/data/matrix-spec/event-schemas/examples/m.room.member.yaml +12 -0
  179. data/data/matrix-spec/event-schemas/examples/m.room.message$m.audio.yaml +14 -0
  180. data/data/matrix-spec/event-schemas/examples/m.room.message$m.emote.yaml +10 -0
  181. data/data/matrix-spec/event-schemas/examples/m.room.message$m.file.yaml +14 -0
  182. data/data/matrix-spec/event-schemas/examples/m.room.message$m.image.yaml +16 -0
  183. data/data/matrix-spec/event-schemas/examples/m.room.message$m.key.verification.request.yaml +19 -0
  184. data/data/matrix-spec/event-schemas/examples/m.room.message$m.location.yaml +18 -0
  185. data/data/matrix-spec/event-schemas/examples/m.room.message$m.notice.yaml +10 -0
  186. data/data/matrix-spec/event-schemas/examples/m.room.message$m.server_notice.yaml +11 -0
  187. data/data/matrix-spec/event-schemas/examples/m.room.message$m.text.yaml +10 -0
  188. data/data/matrix-spec/event-schemas/examples/m.room.message$m.video.yaml +23 -0
  189. data/data/matrix-spec/event-schemas/examples/m.room.name.yaml +8 -0
  190. data/data/matrix-spec/event-schemas/examples/m.room.pinned_events.yaml +8 -0
  191. data/data/matrix-spec/event-schemas/examples/m.room.policy.yaml +11 -0
  192. data/data/matrix-spec/event-schemas/examples/m.room.power_levels.yaml +24 -0
  193. data/data/matrix-spec/event-schemas/examples/m.room.redaction.yaml +8 -0
  194. data/data/matrix-spec/event-schemas/examples/m.room.server_acl.yaml +10 -0
  195. data/data/matrix-spec/event-schemas/examples/m.room.third_party_invite.yaml +14 -0
  196. data/data/matrix-spec/event-schemas/examples/m.room.tombstone.yaml +9 -0
  197. data/data/matrix-spec/event-schemas/examples/m.room.topic.yaml +16 -0
  198. data/data/matrix-spec/event-schemas/examples/m.room_key.withheld.yaml +12 -0
  199. data/data/matrix-spec/event-schemas/examples/m.room_key.yaml +10 -0
  200. data/data/matrix-spec/event-schemas/examples/m.room_key_request$cancel_request.yaml +8 -0
  201. data/data/matrix-spec/event-schemas/examples/m.room_key_request$request.yaml +14 -0
  202. data/data/matrix-spec/event-schemas/examples/m.secret.request.yaml +9 -0
  203. data/data/matrix-spec/event-schemas/examples/m.secret.send.yaml +7 -0
  204. data/data/matrix-spec/event-schemas/examples/m.space.child.yaml +10 -0
  205. data/data/matrix-spec/event-schemas/examples/m.space.parent.yaml +9 -0
  206. data/data/matrix-spec/event-schemas/examples/m.sticker.yaml +22 -0
  207. data/data/matrix-spec/event-schemas/examples/m.tag.yaml +9 -0
  208. data/data/matrix-spec/event-schemas/examples/m.typing.yaml +7 -0
  209. data/data/matrix-spec/event-schemas/moderation_policy_rule.yaml +32 -0
  210. data/data/matrix-spec/event-schemas/schema/components/m_text_content_block.yaml +28 -0
  211. data/data/matrix-spec/event-schemas/schema/components/sdp_stream_metadata.yaml +43 -0
  212. data/data/matrix-spec/event-schemas/schema/components/signed_third_party_invite.yaml +48 -0
  213. data/data/matrix-spec/event-schemas/schema/core-event-schema/call_event.yaml +27 -0
  214. data/data/matrix-spec/event-schemas/schema/core-event-schema/event.yaml +16 -0
  215. data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/avatar_info.yaml +30 -0
  216. data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +52 -0
  217. data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml +22 -0
  218. data/data/matrix-spec/event-schemas/schema/core-event-schema/room_event.yaml +17 -0
  219. data/data/matrix-spec/event-schemas/schema/core-event-schema/state_event.yaml +8 -0
  220. data/data/matrix-spec/event-schemas/schema/core-event-schema/stripped_state.yaml +48 -0
  221. data/data/matrix-spec/event-schemas/schema/core-event-schema/sync_room_event.yaml +49 -0
  222. data/data/matrix-spec/event-schemas/schema/core-event-schema/sync_state_event.yaml +36 -0
  223. data/data/matrix-spec/event-schemas/schema/core-event-schema/unsigned_prop.yaml +23 -0
  224. data/data/matrix-spec/event-schemas/schema/m.accepted_terms.yaml +25 -0
  225. data/data/matrix-spec/event-schemas/schema/m.call.answer.yaml +44 -0
  226. data/data/matrix-spec/event-schemas/schema/m.call.candidates.yaml +52 -0
  227. data/data/matrix-spec/event-schemas/schema/m.call.hangup.yaml +57 -0
  228. data/data/matrix-spec/event-schemas/schema/m.call.invite.yaml +53 -0
  229. data/data/matrix-spec/event-schemas/schema/m.call.negotiate.yaml +78 -0
  230. data/data/matrix-spec/event-schemas/schema/m.call.reject.yaml +29 -0
  231. data/data/matrix-spec/event-schemas/schema/m.call.sdp_stream_metadata_changed.yaml +24 -0
  232. data/data/matrix-spec/event-schemas/schema/m.call.select_answer.yaml +29 -0
  233. data/data/matrix-spec/event-schemas/schema/m.direct.yaml +29 -0
  234. data/data/matrix-spec/event-schemas/schema/m.dummy.yaml +25 -0
  235. data/data/matrix-spec/event-schemas/schema/m.forwarded_room_key.yaml +70 -0
  236. data/data/matrix-spec/event-schemas/schema/m.fully_read.yaml +26 -0
  237. data/data/matrix-spec/event-schemas/schema/m.identity_server.yaml +28 -0
  238. data/data/matrix-spec/event-schemas/schema/m.ignored_user_list.yaml +30 -0
  239. data/data/matrix-spec/event-schemas/schema/m.invite_permission_config.yaml +21 -0
  240. data/data/matrix-spec/event-schemas/schema/m.key.verification.accept.yaml +63 -0
  241. data/data/matrix-spec/event-schemas/schema/m.key.verification.cancel.yaml +72 -0
  242. data/data/matrix-spec/event-schemas/schema/m.key.verification.done.yaml +24 -0
  243. data/data/matrix-spec/event-schemas/schema/m.key.verification.key.yaml +31 -0
  244. data/data/matrix-spec/event-schemas/schema/m.key.verification.m.relates_to.yaml +23 -0
  245. data/data/matrix-spec/event-schemas/schema/m.key.verification.mac.yaml +43 -0
  246. data/data/matrix-spec/event-schemas/schema/m.key.verification.ready.yaml +41 -0
  247. data/data/matrix-spec/event-schemas/schema/m.key.verification.request.yaml +47 -0
  248. data/data/matrix-spec/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml +45 -0
  249. data/data/matrix-spec/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml +76 -0
  250. data/data/matrix-spec/event-schemas/schema/m.key.verification.start.yaml +46 -0
  251. data/data/matrix-spec/event-schemas/schema/m.key_backup.yaml +24 -0
  252. data/data/matrix-spec/event-schemas/schema/m.marked_unread.yaml +26 -0
  253. data/data/matrix-spec/event-schemas/schema/m.policy.rule.room.yaml +17 -0
  254. data/data/matrix-spec/event-schemas/schema/m.policy.rule.server.yaml +17 -0
  255. data/data/matrix-spec/event-schemas/schema/m.policy.rule.user.yaml +17 -0
  256. data/data/matrix-spec/event-schemas/schema/m.presence.yaml +50 -0
  257. data/data/matrix-spec/event-schemas/schema/m.push_rules.yaml +23 -0
  258. data/data/matrix-spec/event-schemas/schema/m.reaction.yaml +45 -0
  259. data/data/matrix-spec/event-schemas/schema/m.receipt.yaml +65 -0
  260. data/data/matrix-spec/event-schemas/schema/m.recent_emoji.yaml +29 -0
  261. data/data/matrix-spec/event-schemas/schema/m.room.avatar.yaml +29 -0
  262. data/data/matrix-spec/event-schemas/schema/m.room.canonical_alias.yaml +40 -0
  263. data/data/matrix-spec/event-schemas/schema/m.room.create.yaml +86 -0
  264. data/data/matrix-spec/event-schemas/schema/m.room.encrypted.yaml +91 -0
  265. data/data/matrix-spec/event-schemas/schema/m.room.encryption.yaml +38 -0
  266. data/data/matrix-spec/event-schemas/schema/m.room.guest_access.yaml +28 -0
  267. data/data/matrix-spec/event-schemas/schema/m.room.history_visibility.yaml +30 -0
  268. data/data/matrix-spec/event-schemas/schema/m.room.join_rules.yaml +78 -0
  269. data/data/matrix-spec/event-schemas/schema/m.room.member.yaml +174 -0
  270. data/data/matrix-spec/event-schemas/schema/m.room.message$m.audio.yaml +73 -0
  271. data/data/matrix-spec/event-schemas/schema/m.room.message$m.emote.yaml +36 -0
  272. data/data/matrix-spec/event-schemas/schema/m.room.message$m.file.yaml +85 -0
  273. data/data/matrix-spec/event-schemas/schema/m.room.message$m.image.yaml +63 -0
  274. data/data/matrix-spec/event-schemas/schema/m.room.message$m.key.verification.request.yaml +70 -0
  275. data/data/matrix-spec/event-schemas/schema/m.room.message$m.location.yaml +50 -0
  276. data/data/matrix-spec/event-schemas/schema/m.room.message$m.notice.yaml +36 -0
  277. data/data/matrix-spec/event-schemas/schema/m.room.message$m.server_notice.yaml +41 -0
  278. data/data/matrix-spec/event-schemas/schema/m.room.message$m.text.yaml +36 -0
  279. data/data/matrix-spec/event-schemas/schema/m.room.message$m.video.yaml +95 -0
  280. data/data/matrix-spec/event-schemas/schema/m.room.message.yaml +25 -0
  281. data/data/matrix-spec/event-schemas/schema/m.room.name.yaml +35 -0
  282. data/data/matrix-spec/event-schemas/schema/m.room.pinned_events.yaml +27 -0
  283. data/data/matrix-spec/event-schemas/schema/m.room.policy.yaml +41 -0
  284. data/data/matrix-spec/event-schemas/schema/m.room.power_levels.yaml +139 -0
  285. data/data/matrix-spec/event-schemas/schema/m.room.redaction.yaml +29 -0
  286. data/data/matrix-spec/event-schemas/schema/m.room.server_acl.yaml +88 -0
  287. data/data/matrix-spec/event-schemas/schema/m.room.third_party_invite.yaml +79 -0
  288. data/data/matrix-spec/event-schemas/schema/m.room.tombstone.yaml +29 -0
  289. data/data/matrix-spec/event-schemas/schema/m.room.topic.yaml +53 -0
  290. data/data/matrix-spec/event-schemas/schema/m.room_key.withheld.yaml +88 -0
  291. data/data/matrix-spec/event-schemas/schema/m.room_key.yaml +38 -0
  292. data/data/matrix-spec/event-schemas/schema/m.room_key_request.yaml +73 -0
  293. data/data/matrix-spec/event-schemas/schema/m.secret.request.yaml +42 -0
  294. data/data/matrix-spec/event-schemas/schema/m.secret.send.yaml +35 -0
  295. data/data/matrix-spec/event-schemas/schema/m.space.child.yaml +50 -0
  296. data/data/matrix-spec/event-schemas/schema/m.space.parent.yaml +36 -0
  297. data/data/matrix-spec/event-schemas/schema/m.sticker.yaml +36 -0
  298. data/data/matrix-spec/event-schemas/schema/m.tag.yaml +28 -0
  299. data/data/matrix-spec/event-schemas/schema/m.typing.yaml +29 -0
  300. data/lib/async/matrix/3.3/async_matrix_e2ee.so +0 -0
  301. data/lib/async/matrix/3.4/async_matrix_e2ee.so +0 -0
  302. data/lib/async/matrix/4.0/async_matrix_e2ee.so +0 -0
  303. data/lib/async/matrix/api/chain.rb +604 -0
  304. data/lib/async/matrix/api/concat.rb +107 -0
  305. data/lib/async/matrix/api/path_tree.rb +232 -0
  306. data/lib/async/matrix/api.rb +205 -0
  307. data/lib/async/matrix/auth_error.rb +20 -0
  308. data/lib/async/matrix/bad_json_error.rb +20 -0
  309. data/lib/async/matrix/client.rb +966 -0
  310. data/lib/async/matrix/config/vivify.rb +107 -0
  311. data/lib/async/matrix/config.rb +184 -0
  312. data/lib/async/matrix/connection.rb +19 -0
  313. data/lib/async/matrix/content.rb +106 -0
  314. data/lib/async/matrix/double_puppet_client.rb +82 -0
  315. data/lib/async/matrix/e2ee.rb +129 -0
  316. data/lib/async/matrix/endpoint.rb +57 -0
  317. data/lib/async/matrix/error.rb +40 -0
  318. data/lib/async/matrix/error_response.rb +37 -0
  319. data/lib/async/matrix/event.rb +197 -0
  320. data/lib/async/matrix/homeserver_error.rb +20 -0
  321. data/lib/async/matrix/invalid_endpoint_error.rb +20 -0
  322. data/lib/async/matrix/media_client.rb +181 -0
  323. data/lib/async/matrix/not_found_error.rb +20 -0
  324. data/lib/async/matrix/notifier.rb +108 -0
  325. data/lib/async/matrix/response_too_large_error.rb +20 -0
  326. data/lib/async/matrix/schema/registry.rb +381 -0
  327. data/lib/async/matrix/schema/validation_error.rb +232 -0
  328. data/lib/async/matrix/schema.rb +170 -0
  329. data/lib/async/matrix/server.rb +18 -0
  330. data/lib/async/matrix/stream.rb +18 -0
  331. data/lib/async/matrix/version.rb +10 -0
  332. data/lib/async/matrix.rb +15 -0
  333. metadata +494 -0
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ module Async
7
+ module Matrix
8
+ class Config
9
+ # Mixin that gives a Hash dot-notation accessors with autovivification.
10
+ #
11
+ # Not applied globally — only extended onto the validated config hash
12
+ # and its nested children so the rest of the world is unaffected.
13
+ #
14
+ # h = {}.extend(Vivify)
15
+ # h.foo.bar.baz = 42
16
+ # h # => { foo: { bar: { baz: 42 } } }
17
+ #
18
+ module Vivify
19
+ def method_missing(name, *args)
20
+ key = name.to_s
21
+
22
+ if key.end_with?("=")
23
+ self[key.chomp("=").to_sym] = args.first
24
+ elsif key?(name.to_sym)
25
+ self[name.to_sym]
26
+ elsif key.start_with?("to_")
27
+ super
28
+ else
29
+ self[name.to_sym] = {}.extend(Vivify)
30
+ end
31
+ end
32
+
33
+ def respond_to_missing?(name, _priv = false)
34
+ name.to_s.end_with?("=") || key?(name.to_sym) || super
35
+ end
36
+
37
+ # Recursively symbolize keys and extend every nested Hash with Vivify.
38
+ #
39
+ # Call this on the raw (string-keyed) hash that comes out of
40
+ # YAML.safe_load before wrapping it in Config.
41
+ def self.deep_vivify(obj)
42
+ case obj
43
+ when Hash
44
+ result = {}
45
+ obj.each { |k, v| result[k.to_s.to_sym] = deep_vivify(v) }
46
+ result.extend(Vivify)
47
+ when Array
48
+ obj.map { |v| deep_vivify(v) }
49
+ else
50
+ obj
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ __END__
59
+ V = Async::Matrix::Config::Vivify
60
+
61
+ describe "Vivify" do
62
+ it "provides dot-notation read access to symbol keys" do
63
+ h = { foo: "bar" }.extend(V)
64
+ h.foo.should == "bar"
65
+ end
66
+
67
+ it "provides dot-notation write access" do
68
+ h = {}.extend(V)
69
+ h.foo = 42
70
+ h[:foo].should == 42
71
+ end
72
+
73
+ it "autovivifies missing keys as vivified hashes" do
74
+ h = {}.extend(V)
75
+ h.a.b.c = "deep"
76
+ h[:a][:b][:c].should == "deep"
77
+ end
78
+
79
+ it "delegates to_* methods to super (no autovivify)" do
80
+ h = { x: 1 }.extend(V)
81
+ h.to_a.should == [[:x, 1]]
82
+ end
83
+ end
84
+
85
+ describe "Vivify.deep_vivify" do
86
+ it "symbolizes string keys" do
87
+ result = V.deep_vivify({"a" => 1})
88
+ result[:a].should == 1
89
+ end
90
+
91
+ it "recursively vivifies nested hashes" do
92
+ result = V.deep_vivify({"outer" => {"inner" => "val"}})
93
+ result.outer.inner.should == "val"
94
+ end
95
+
96
+ it "vivifies hashes inside arrays" do
97
+ result = V.deep_vivify({"list" => [{"name" => "x"}]})
98
+ result.list.first.name.should == "x"
99
+ end
100
+
101
+ it "passes scalars through unchanged" do
102
+ result = V.deep_vivify({"n" => 42, "s" => "hi", "b" => true})
103
+ result.n.should == 42
104
+ result.s.should == "hi"
105
+ result.b.should == true
106
+ end
107
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ require "forwardable"
7
+ require "yaml"
8
+ require "pathname"
9
+ require_relative "config/vivify"
10
+
11
+ module Async
12
+ module Matrix
13
+ # Dot-notation access to a Matrix service's YAML configuration.
14
+ #
15
+ # {Client} only reads two fields — `homeserver.address` and
16
+ # `appservice.as_token` — so this class validates nothing: it vivifies
17
+ # whatever hash (or YAML file) it is handed and exposes every nested field
18
+ # as a method call.
19
+ #
20
+ # config = Config.load("config/appservice.yml")
21
+ # config.homeserver.address # => "http://synapse:8008"
22
+ # config.appservice.as_token # => "secret..."
23
+ # config.appservice.bot.username # => "bot"
24
+ # config.bot_mxid # => "@bot:localhost"
25
+ #
26
+ # A subclass layers validation on by overriding {.validate!}; that is how
27
+ # async-matrix-bridge's Config applies the mautrix bridgev2 JSON Schema
28
+ # suite without reimplementing any of the loading below.
29
+ class Config
30
+ extend Forwardable
31
+
32
+ # Delegate every top-level config section to the vivified data hash. An
33
+ # explicit list, not a method_missing forward: a typo'd section should
34
+ # raise NoMethodError rather than autovivify into an empty hash.
35
+ def_delegators :@data,
36
+ :network,
37
+ :bridge,
38
+ :database,
39
+ :homeserver,
40
+ :appservice,
41
+ :matrix,
42
+ :analytics,
43
+ :provisioning,
44
+ :public_media,
45
+ :direct_media,
46
+ :backfill,
47
+ :double_puppet,
48
+ :encryption,
49
+ :logging,
50
+ :management_room_texts,
51
+ :env_config_prefix
52
+
53
+ def initialize(data)
54
+ self.class.validate!(data)
55
+ @data = Vivify.deep_vivify(data)
56
+ end
57
+
58
+ # Load a YAML config file from disk.
59
+ def self.load(path)
60
+ unless File.exist?(path)
61
+ raise Async::Matrix::NotFoundError.new(
62
+ "M_NOT_FOUND",
63
+ "Config not found: #{path}",
64
+ )
65
+ end
66
+
67
+ data = YAML.safe_load_file(path, permitted_classes: [Symbol])
68
+ new(data)
69
+ end
70
+
71
+ # Validation hook, called with the raw (string-keyed) hash before it is
72
+ # vivified. A no-op here; subclasses override it to raise on bad input,
73
+ # and may mutate `data` to insert defaults.
74
+ def self.validate!(data)
75
+ nil
76
+ end
77
+
78
+ # Convenience: derive the bot's full Matrix ID from
79
+ # appservice.bot.username + homeserver.domain.
80
+ def bot_mxid
81
+ "@#{appservice.bot.username}:#{homeserver.domain}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ __END__
88
+ require "tempfile"
89
+
90
+ describe "Async::Matrix::Config" do
91
+ def minimal_data
92
+ {
93
+ "homeserver" => {
94
+ "address" => "http://localhost:8008",
95
+ "domain" => "localhost",
96
+ },
97
+ "appservice" => {
98
+ "as_token" => "as_secret_token_value",
99
+ "hs_token" => "hs_secret_token_value",
100
+ "bot" => {"username" => "bot"},
101
+ },
102
+ }
103
+ end
104
+
105
+ it "exposes top-level sections" do
106
+ config = Async::Matrix::Config.new(minimal_data)
107
+ config.homeserver.address.should == "http://localhost:8008"
108
+ config.homeserver.domain.should == "localhost"
109
+ config.appservice.as_token.should == "as_secret_token_value"
110
+ config.appservice.hs_token.should == "hs_secret_token_value"
111
+ config.appservice.bot.username.should == "bot"
112
+ end
113
+
114
+ it "derives bot_mxid from appservice.bot.username and homeserver.domain" do
115
+ Async::Matrix::Config.new(minimal_data).bot_mxid.should == "@bot:localhost"
116
+ end
117
+
118
+ it "provides dot-notation access to deeply nested fields" do
119
+ data = minimal_data.merge(
120
+ "encryption" => {
121
+ "allow" => true,
122
+ "rotation" => {"messages" => 200},
123
+ },
124
+ )
125
+ config = Async::Matrix::Config.new(data)
126
+ config.encryption.allow.should == true
127
+ config.encryption.rotation.messages.should == 200
128
+ end
129
+
130
+ it "autovivifies missing optional sections as empty hashes" do
131
+ config = Async::Matrix::Config.new(minimal_data)
132
+ config.analytics.should.be.kind_of Hash
133
+ config.analytics.should.be.empty?
134
+ end
135
+
136
+ it "raises NoMethodError for sections it does not delegate" do
137
+ config = Async::Matrix::Config.new(minimal_data)
138
+ lambda { config.bogus }.should.raise(NoMethodError)
139
+ end
140
+
141
+ it "validates nothing by default" do
142
+ lambda { Async::Matrix::Config.new({}) }.should.not.raise
143
+ end
144
+
145
+ it "loads from a YAML file" do
146
+ file = Tempfile.new(["config", ".yml"])
147
+ file.write(<<~YAML)
148
+ homeserver:
149
+ address: "http://localhost:8008"
150
+ domain: "localhost"
151
+ appservice:
152
+ as_token: "as123_secret"
153
+ hs_token: "hs456_secret"
154
+ bot:
155
+ username: "testbot"
156
+ YAML
157
+ file.close
158
+
159
+ config = Async::Matrix::Config.load(file.path)
160
+ config.homeserver.address.should == "http://localhost:8008"
161
+ config.bot_mxid.should == "@testbot:localhost"
162
+ ensure
163
+ file.unlink
164
+ end
165
+
166
+ it "raises NotFoundError for a missing file" do
167
+ lambda {
168
+ Async::Matrix::Config.load("/nonexistent/path.yml")
169
+ }.should.raise(Async::Matrix::NotFoundError)
170
+ end
171
+
172
+ it "runs the validate! hook a subclass overrides" do
173
+ strict = Class.new(Async::Matrix::Config) do
174
+ def self.validate!(data)
175
+ unless data.key?("homeserver")
176
+ raise Async::Matrix::BadJsonError.new("M_BAD_JSON", "no homeserver")
177
+ end
178
+ end
179
+ end
180
+
181
+ lambda { strict.new({}) }.should.raise(Async::Matrix::BadJsonError)
182
+ strict.new(minimal_data).homeserver.domain.should == "localhost"
183
+ end
184
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ require "async/http"
7
+
8
+ module Async
9
+ module Matrix
10
+ module Connection
11
+ include Async::HTTP::Protocol::HTTP2::Connection
12
+ end
13
+ end
14
+ end
15
+
16
+ __END__
17
+ it "includes Async::HTTP::Protocol::HTTP2::Connection" do
18
+ Async::Matrix::Connection.ancestors.should.include Async::HTTP::Protocol::HTTP2::Connection
19
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ module Async
7
+ module Matrix
8
+ # Wraps the content object of a Matrix event, providing typed access to
9
+ # schema-defined properties via method_missing.
10
+ #
11
+ # Common fields like `msgtype`, `body`, and `membership` have dedicated
12
+ # accessors for convenience. Any other field defined in the event's schema
13
+ # (or present in the raw hash) is accessible as a method call:
14
+ #
15
+ # content.msgtype # => "m.text"
16
+ # content.body # => "hello"
17
+ # content.membership # => "join"
18
+ # content.avatar_url # => "mxc://example.org/abc"
19
+ # content["custom"] # => direct hash access for non-standard fields
20
+ #
21
+ class Content
22
+ attr_reader :msgtype, :body, :membership
23
+
24
+ def initialize(data)
25
+ @data = data
26
+ @msgtype = data["msgtype"]
27
+ @body = data["body"]
28
+ @membership = data["membership"]
29
+ end
30
+
31
+ def to_h = @data
32
+ def to_s = @body.to_s
33
+ def to_str = to_s
34
+
35
+ # Direct hash access for any content field.
36
+ def [](key) = @data[key.to_s]
37
+
38
+ # Dynamic access to any content field present in the raw data.
39
+ def method_missing(name, *args)
40
+ key = name.to_s
41
+
42
+ if @data.key?(key)
43
+ @data[key]
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def respond_to_missing?(name, include_private = false)
50
+ @data.key?(name.to_s) || super
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ __END__
57
+ describe "Async::Matrix::Content" do
58
+ it "parses msgtype, body, and membership" do
59
+ content = Async::Matrix::Content.new({
60
+ "msgtype" => "m.text",
61
+ "body" => "hello",
62
+ "membership" => "join"
63
+ })
64
+ content.msgtype.should == "m.text"
65
+ content.body.should == "hello"
66
+ content.membership.should == "join"
67
+ end
68
+
69
+ it "handles missing fields gracefully" do
70
+ content = Async::Matrix::Content.new({})
71
+ content.msgtype.should.be.nil
72
+ content.body.should.be.nil
73
+ content.membership.should.be.nil
74
+ end
75
+
76
+ it "provides hash access via []" do
77
+ content = Async::Matrix::Content.new({"custom_field" => "value"})
78
+ content["custom_field"].should == "value"
79
+ end
80
+
81
+ it "provides dynamic access via method_missing" do
82
+ content = Async::Matrix::Content.new({
83
+ "avatar_url" => "mxc://example.org/abc",
84
+ "displayname" => "Alice"
85
+ })
86
+ content.avatar_url.should == "mxc://example.org/abc"
87
+ content.displayname.should == "Alice"
88
+ end
89
+
90
+ it "returns nil for unknown fields via method_missing" do
91
+ content = Async::Matrix::Content.new({})
92
+ content.nonexistent.should.be.nil
93
+ end
94
+
95
+ it "returns the raw hash via to_h" do
96
+ data = {"msgtype" => "m.text", "body" => "hi"}
97
+ content = Async::Matrix::Content.new(data)
98
+ content.to_h.should == data
99
+ end
100
+
101
+ it "responds to keys present in the data" do
102
+ content = Async::Matrix::Content.new({"avatar_url" => "mxc://x/y"})
103
+ content.respond_to?(:avatar_url).should == true
104
+ content.respond_to?(:nonexistent).should == false
105
+ end
106
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ require_relative "client"
7
+
8
+ module Async
9
+ module Matrix
10
+ # A Client subclass that authenticates with a user's double puppet token
11
+ # instead of the appservice's as_token.
12
+ #
13
+ # This allows the bridge to send events as the real Matrix user rather
14
+ # than as the appservice bot or a ghost user.
15
+ #
16
+ # puppet = DoublePuppetClient.new(config, double_puppet_token: "syt_...")
17
+ # puppet.send_text("!room:example.com", "sent as the real user")
18
+ # puppet.whoami # => {"user_id" => "@alice:example.com"}
19
+ #
20
+ class DoublePuppetClient < Client
21
+ def initialize(config, double_puppet_token:, **kwargs)
22
+ super(config, **kwargs)
23
+ @headers[0] = ["authorization", "Bearer #{double_puppet_token}"]
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ __END__
30
+ describe "Async::Matrix::DoublePuppetClient" do
31
+ def make_config
32
+ Async::Matrix::Config.new({
33
+ "homeserver" => { "address" => "http://localhost:8008", "domain" => "localhost" },
34
+ "appservice" => { "as_token" => "as_token_value", "hs_token" => "hs_secret", "bot" => { "username" => "bot" } }
35
+ })
36
+ end
37
+
38
+ it "uses the double_puppet_token for authorization" do
39
+ puppet = Async::Matrix::DoublePuppetClient.new(make_config, double_puppet_token: "syt_puppet_token")
40
+ auth_header = puppet.instance_variable_get(:@headers).find { |k, _| k == "authorization" }
41
+ auth_header[1].should == "Bearer syt_puppet_token"
42
+ end
43
+
44
+ it "does not use the as_token from config" do
45
+ puppet = Async::Matrix::DoublePuppetClient.new(make_config, double_puppet_token: "syt_puppet_token")
46
+ auth_header = puppet.instance_variable_get(:@headers).find { |k, _| k == "authorization" }
47
+ auth_header[1].should.not.include "as_token_value"
48
+ end
49
+
50
+ it "inherits retry defaults from Client" do
51
+ puppet = Async::Matrix::DoublePuppetClient.new(make_config, double_puppet_token: "syt_puppet_token")
52
+ puppet.config.appservice.as_token.should == "as_token_value"
53
+ end
54
+
55
+ it "accepts custom retry configuration" do
56
+ puppet = Async::Matrix::DoublePuppetClient.new(
57
+ make_config,
58
+ double_puppet_token: "syt_puppet_token",
59
+ max_retries: 5,
60
+ retry_base_delay: 1.0,
61
+ max_retry_delay: 60
62
+ )
63
+ auth_header = puppet.instance_variable_get(:@headers).find { |k, _| k == "authorization" }
64
+ auth_header[1].should == "Bearer syt_puppet_token"
65
+ end
66
+
67
+ it "responds to all Client methods" do
68
+ puppet = Async::Matrix::DoublePuppetClient.new(make_config, double_puppet_token: "syt_puppet_token")
69
+ puppet.should.respond_to :send_text
70
+ puppet.should.respond_to :send_html
71
+ puppet.should.respond_to :send_notice
72
+ puppet.should.respond_to :join_room
73
+ puppet.should.respond_to :leave_room
74
+ puppet.should.respond_to :whoami
75
+ puppet.should.respond_to :api
76
+ end
77
+
78
+ it "is a subclass of Client" do
79
+ puppet = Async::Matrix::DoublePuppetClient.new(make_config, double_puppet_token: "syt_puppet_token")
80
+ puppet.should.be.kind_of Async::Matrix::Client
81
+ end
82
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ # Loads the native vodozemac binding (ext/async_matrix_e2ee) and namespaces the
7
+ # Olm/Megolm primitives under Async::Matrix::E2EE.
8
+ #
9
+ # The native classes (Account, Session, GroupSession, InboundGroupSession) and
10
+ # the module function verify_signature are defined by the Rust #[magnus::init].
11
+ # This file only locates and requires the compiled object.
12
+ #
13
+ # account = Async::Matrix::E2EE::Account.new
14
+ # account.curve25519_key # => base64 string
15
+ # group = Async::Matrix::E2EE::GroupSession.new
16
+ # msg = group.encrypt("hello") # => base64 megolm message
17
+ # inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
18
+ # inbound.decrypt(msg) # => ["hello", 0]
19
+
20
+ module Async
21
+ module Matrix
22
+ module E2EE
23
+ end
24
+ end
25
+ end
26
+
27
+ # Precompiled ("fat") gems ship one .so per Ruby minor version under a versioned
28
+ # subdir (lib/async/matrix/3.3/async_matrix_e2ee.so). A locally source-compiled
29
+ # build lands flat, alongside this file. Try the versioned path first, then fall
30
+ # back to the flat one.
31
+ begin
32
+ RUBY_VERSION =~ /(\d+\.\d+)/
33
+ require_relative "#{Regexp.last_match(1)}/async_matrix_e2ee"
34
+ rescue LoadError
35
+ require_relative "async_matrix_e2ee"
36
+ end
37
+
38
+ __END__
39
+ describe "Async::Matrix::E2EE" do
40
+ it "exposes account identity keys as base64" do
41
+ account = Async::Matrix::E2EE::Account.new
42
+ account.curve25519_key.should.be.kind_of String
43
+ account.ed25519_key.should.be.kind_of String
44
+ account.curve25519_key.length.should.be > 0
45
+ end
46
+
47
+ it "round-trips a megolm group message" do
48
+ group = Async::Matrix::E2EE::GroupSession.new
49
+ inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
50
+
51
+ message = group.encrypt("hello world")
52
+ plaintext, index = inbound.decrypt(message)
53
+
54
+ plaintext.should == "hello world"
55
+ index.should == 0
56
+ inbound.session_id.should == group.session_id
57
+ end
58
+
59
+ it "imports an exported session key" do
60
+ # The path room keys take out of server-side key backup and out of
61
+ # m.forwarded_room_key. Without .import these are unusable, and a client
62
+ # can never read history it did not get a live m.room_key for.
63
+ group = Async::Matrix::E2EE::GroupSession.new
64
+ inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
65
+ message = group.encrypt("restored from backup")
66
+
67
+ exported = inbound.export_at_first_known_index
68
+ restored = Async::Matrix::E2EE::InboundGroupSession.import(exported)
69
+
70
+ restored.session_id.should == group.session_id
71
+ restored.decrypt(message).first.should == "restored from backup"
72
+ end
73
+
74
+ it "rejects an exported key passed to .new, which requires a signature" do
75
+ # .new takes a version-2 SessionKey and verifies its signature; an exported
76
+ # key is version 1 and unsigned, so it must go through .import instead.
77
+ group = Async::Matrix::E2EE::GroupSession.new
78
+ inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
79
+ exported = inbound.export_at_first_known_index
80
+
81
+ lambda {
82
+ Async::Matrix::E2EE::InboundGroupSession.new(exported)
83
+ }.should.raise(RuntimeError)
84
+ end
85
+
86
+ it "exports at a given message index" do
87
+ group = Async::Matrix::E2EE::GroupSession.new
88
+ inbound = Async::Matrix::E2EE::InboundGroupSession.new(group.session_key)
89
+ 3.times { |i| group.encrypt("msg #{i}") }
90
+
91
+ Async::Matrix::E2EE::InboundGroupSession
92
+ .import(inbound.export_at(0))
93
+ .first_known_index.should == 0
94
+ end
95
+
96
+ it "round-trips an olm 1:1 message" do
97
+ alice = Async::Matrix::E2EE::Account.new
98
+ bob = Async::Matrix::E2EE::Account.new
99
+ bob.generate_one_time_keys(1)
100
+ bob_otk = bob.one_time_keys.values.first
101
+
102
+ outbound = alice.create_outbound_session(bob.curve25519_key, bob_otk)
103
+ type, body = outbound.encrypt("yo g")
104
+ type.should == 0 # pre-key message
105
+
106
+ session, plaintext = bob.create_inbound_session(alice.curve25519_key, body)
107
+ plaintext.should == "yo g"
108
+
109
+ reply_type, reply_body = session.encrypt("hello back")
110
+ outbound.decrypt(reply_type, reply_body).should == "hello back"
111
+ end
112
+
113
+ it "verifies a valid ed25519 signature and rejects a bad one" do
114
+ account = Async::Matrix::E2EE::Account.new
115
+ signature = account.sign("payload")
116
+
117
+ Async::Matrix::E2EE.verify_signature(account.ed25519_key, "payload", signature).should == true
118
+ Async::Matrix::E2EE.verify_signature(account.ed25519_key, "tampered", signature).should == false
119
+ end
120
+
121
+ it "survives a pickle round-trip" do
122
+ key = "0" * 32
123
+ group = Async::Matrix::E2EE::GroupSession.new
124
+ pickled = group.pickle(key)
125
+
126
+ restored = Async::Matrix::E2EE::GroupSession.from_pickle(pickled, key)
127
+ restored.session_id.should == group.session_id
128
+ end
129
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ require "json"
7
+ require "async/http"
8
+
9
+ module Async
10
+ module Matrix
11
+ # Extends Async::HTTP::Endpoint with Matrix well-known discovery.
12
+ # spec.matrix.org/v1.9/client-server-api/#well-known-uri
13
+ #
14
+ # A server at example.com may serve clients from a completely
15
+ # different origin — e.g. https://matrix.example.com:8448.
16
+ # #discover resolves that indirection as a proper async I/O
17
+ # operation before constructing the Endpoint, so every downstream
18
+ # caller gets a correctly-pointed connection pool for free.
19
+ class Endpoint < Async::HTTP::Endpoint
20
+ WELL_KNOWN = "/.well-known/matrix/client"
21
+
22
+ # Resolves homeserver base URL, falls back to https://domain.
23
+ # Must be called inside an Async block — uses the running scheduler.
24
+ def self.discover(domain, **options)
25
+ internet = Async::HTTP::Internet.new
26
+ data = JSON.parse(internet.get("https://#{domain}#{WELL_KNOWN}").read)
27
+ base_url = data.dig("m.homeserver", "base_url") || "https://#{domain}"
28
+ parse(base_url, **options)
29
+ rescue StandardError
30
+ # Well-known is optional per spec — fall back gracefully
31
+ parse("https://#{domain}", **options)
32
+ ensure
33
+ internet&.close
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ __END__
40
+ it "defines the WELL_KNOWN constant" do
41
+ Async::Matrix::Endpoint::WELL_KNOWN.should == "/.well-known/matrix/client"
42
+ end
43
+
44
+ it "responds to .discover" do
45
+ Async::Matrix::Endpoint.should.respond_to :discover
46
+ end
47
+
48
+ it "inherits from Async::HTTP::Endpoint" do
49
+ Async::Matrix::Endpoint.ancestors.should.include Async::HTTP::Endpoint
50
+ end
51
+
52
+ it "falls back to https://domain when well-known fails" do
53
+ Async do
54
+ endpoint = Async::Matrix::Endpoint.discover("nonexistent.invalid")
55
+ endpoint.to_s.should =~ /nonexistent\.invalid/
56
+ end.wait
57
+ end