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.
- checksums.yaml +7 -0
- data/LICENSE +200 -0
- data/README.md +108 -0
- data/data/discord-api-spec/openapi.json +40404 -0
- data/data/matrix-spec/api/client-server/account-data.yaml +389 -0
- data/data/matrix-spec/api/client-server/account_deactivation.yaml +149 -0
- data/data/matrix-spec/api/client-server/admin.yaml +512 -0
- data/data/matrix-spec/api/client-server/administrative_contact.yaml +620 -0
- data/data/matrix-spec/api/client-server/appservice_ping.yaml +183 -0
- data/data/matrix-spec/api/client-server/appservice_room_directory.yaml +104 -0
- data/data/matrix-spec/api/client-server/authed-content-repo.yaml +590 -0
- data/data/matrix-spec/api/client-server/banning.yaml +177 -0
- data/data/matrix-spec/api/client-server/capabilities.yaml +235 -0
- data/data/matrix-spec/api/client-server/content-repo.yaml +887 -0
- data/data/matrix-spec/api/client-server/create_room.yaml +306 -0
- data/data/matrix-spec/api/client-server/cross_signing.yaml +300 -0
- data/data/matrix-spec/api/client-server/definitions/auth_data.yaml +34 -0
- data/data/matrix-spec/api/client-server/definitions/auth_response.yaml +62 -0
- data/data/matrix-spec/api/client-server/definitions/client_device.yaml +44 -0
- data/data/matrix-spec/api/client-server/definitions/client_event.yaml +49 -0
- data/data/matrix-spec/api/client-server/definitions/client_event_without_room_id.yaml +147 -0
- data/data/matrix-spec/api/client-server/definitions/cross_signing_key.yaml +57 -0
- data/data/matrix-spec/api/client-server/definitions/device_keys.yaml +70 -0
- data/data/matrix-spec/api/client-server/definitions/errors/error.yaml +26 -0
- data/data/matrix-spec/api/client-server/definitions/errors/rate_limited.yaml +34 -0
- data/data/matrix-spec/api/client-server/definitions/event_batch.yaml +22 -0
- data/data/matrix-spec/api/client-server/definitions/event_filter.yaml +55 -0
- data/data/matrix-spec/api/client-server/definitions/invite_3pid.yaml +45 -0
- data/data/matrix-spec/api/client-server/definitions/key_backup_auth_data.yaml +36 -0
- data/data/matrix-spec/api/client-server/definitions/key_backup_data.yaml +50 -0
- data/data/matrix-spec/api/client-server/definitions/key_backup_session_data.yaml +57 -0
- data/data/matrix-spec/api/client-server/definitions/m.login.terms_params.yaml +83 -0
- data/data/matrix-spec/api/client-server/definitions/m.mentions.yaml +33 -0
- data/data/matrix-spec/api/client-server/definitions/m.oauth_params.yaml +30 -0
- data/data/matrix-spec/api/client-server/definitions/m.relates_to.yaml +45 -0
- data/data/matrix-spec/api/client-server/definitions/megolm_export_session_data.yaml +39 -0
- data/data/matrix-spec/api/client-server/definitions/olm_payload.yaml +88 -0
- data/data/matrix-spec/api/client-server/definitions/one_time_keys.yaml +27 -0
- data/data/matrix-spec/api/client-server/definitions/openid_token.yaml +37 -0
- data/data/matrix-spec/api/client-server/definitions/protocol.yaml +44 -0
- data/data/matrix-spec/api/client-server/definitions/public_rooms_chunk.yaml +74 -0
- data/data/matrix-spec/api/client-server/definitions/public_rooms_response.yaml +59 -0
- data/data/matrix-spec/api/client-server/definitions/push_condition.yaml +53 -0
- data/data/matrix-spec/api/client-server/definitions/push_rule.yaml +53 -0
- data/data/matrix-spec/api/client-server/definitions/push_ruleset.yaml +206 -0
- data/data/matrix-spec/api/client-server/definitions/recent_emoji.yaml +29 -0
- data/data/matrix-spec/api/client-server/definitions/request_email_validation.yaml +36 -0
- data/data/matrix-spec/api/client-server/definitions/request_msisdn_validation.yaml +36 -0
- data/data/matrix-spec/api/client-server/definitions/request_token_response.yaml +46 -0
- data/data/matrix-spec/api/client-server/definitions/room_event_filter.yaml +60 -0
- data/data/matrix-spec/api/client-server/definitions/room_key_backup.yaml +37 -0
- data/data/matrix-spec/api/client-server/definitions/room_summary.yaml +44 -0
- data/data/matrix-spec/api/client-server/definitions/security.yaml +47 -0
- data/data/matrix-spec/api/client-server/definitions/sso_login_flow.yaml +98 -0
- data/data/matrix-spec/api/client-server/definitions/state_event_batch.yaml +21 -0
- data/data/matrix-spec/api/client-server/definitions/sync_filter.yaml +86 -0
- data/data/matrix-spec/api/client-server/definitions/tag.yaml +24 -0
- data/data/matrix-spec/api/client-server/definitions/third_party_signed.yaml +45 -0
- data/data/matrix-spec/api/client-server/definitions/timeline_batch.yaml +36 -0
- data/data/matrix-spec/api/client-server/definitions/user_identifier.yaml +27 -0
- data/data/matrix-spec/api/client-server/definitions/wellknown/full.yaml +38 -0
- data/data/matrix-spec/api/client-server/definitions/wellknown/homeserver.yaml +25 -0
- data/data/matrix-spec/api/client-server/definitions/wellknown/identity_server.yaml +25 -0
- data/data/matrix-spec/api/client-server/device_management.yaml +314 -0
- data/data/matrix-spec/api/client-server/directory.yaml +318 -0
- data/data/matrix-spec/api/client-server/event_context.yaml +161 -0
- data/data/matrix-spec/api/client-server/filter.yaml +224 -0
- data/data/matrix-spec/api/client-server/inviting.yaml +149 -0
- data/data/matrix-spec/api/client-server/joining.yaml +238 -0
- data/data/matrix-spec/api/client-server/key_backup.yaml +993 -0
- data/data/matrix-spec/api/client-server/keys.yaml +482 -0
- data/data/matrix-spec/api/client-server/kicking.yaml +110 -0
- data/data/matrix-spec/api/client-server/knocking.yaml +152 -0
- data/data/matrix-spec/api/client-server/leaving.yaml +163 -0
- data/data/matrix-spec/api/client-server/list_joined_rooms.yaml +68 -0
- data/data/matrix-spec/api/client-server/list_public_rooms.yaml +280 -0
- data/data/matrix-spec/api/client-server/login.yaml +321 -0
- data/data/matrix-spec/api/client-server/login_token.yaml +138 -0
- data/data/matrix-spec/api/client-server/logout.yaml +86 -0
- data/data/matrix-spec/api/client-server/message_pagination.yaml +194 -0
- data/data/matrix-spec/api/client-server/notifications.yaml +152 -0
- data/data/matrix-spec/api/client-server/oauth_server_metadata.yaml +238 -0
- data/data/matrix-spec/api/client-server/old_sync.yaml +379 -0
- data/data/matrix-spec/api/client-server/openid.yaml +98 -0
- data/data/matrix-spec/api/client-server/password_management.yaml +246 -0
- data/data/matrix-spec/api/client-server/peeking_events.yaml +122 -0
- data/data/matrix-spec/api/client-server/policy_server.yaml +82 -0
- data/data/matrix-spec/api/client-server/presence.yaml +169 -0
- data/data/matrix-spec/api/client-server/profile.yaml +366 -0
- data/data/matrix-spec/api/client-server/pusher.yaml +303 -0
- data/data/matrix-spec/api/client-server/pushrules.yaml +633 -0
- data/data/matrix-spec/api/client-server/read_markers.yaml +103 -0
- data/data/matrix-spec/api/client-server/receipts.yaml +139 -0
- data/data/matrix-spec/api/client-server/redaction.yaml +116 -0
- data/data/matrix-spec/api/client-server/refresh.yaml +119 -0
- data/data/matrix-spec/api/client-server/registration.yaml +488 -0
- data/data/matrix-spec/api/client-server/registration_tokens.yaml +93 -0
- data/data/matrix-spec/api/client-server/relations.yaml +382 -0
- data/data/matrix-spec/api/client-server/report_content.yaml +283 -0
- data/data/matrix-spec/api/client-server/room_event_by_timestamp.yaml +147 -0
- data/data/matrix-spec/api/client-server/room_initial_sync.yaml +188 -0
- data/data/matrix-spec/api/client-server/room_send.yaml +130 -0
- data/data/matrix-spec/api/client-server/room_state.yaml +159 -0
- data/data/matrix-spec/api/client-server/room_summary.yaml +138 -0
- data/data/matrix-spec/api/client-server/room_upgrades.yaml +130 -0
- data/data/matrix-spec/api/client-server/rooms.yaml +380 -0
- data/data/matrix-spec/api/client-server/search.yaml +385 -0
- data/data/matrix-spec/api/client-server/space_hierarchy.yaml +237 -0
- data/data/matrix-spec/api/client-server/sso_login_redirect.yaml +135 -0
- data/data/matrix-spec/api/client-server/support.yaml +142 -0
- data/data/matrix-spec/api/client-server/sync.yaml +692 -0
- data/data/matrix-spec/api/client-server/tags.yaml +183 -0
- data/data/matrix-spec/api/client-server/third_party_lookup.yaml +324 -0
- data/data/matrix-spec/api/client-server/third_party_membership.yaml +139 -0
- data/data/matrix-spec/api/client-server/threads_list.yaml +167 -0
- data/data/matrix-spec/api/client-server/to_device.yaml +104 -0
- data/data/matrix-spec/api/client-server/typing.yaml +103 -0
- data/data/matrix-spec/api/client-server/users.yaml +136 -0
- data/data/matrix-spec/api/client-server/versions.yaml +108 -0
- data/data/matrix-spec/api/client-server/voip.yaml +93 -0
- data/data/matrix-spec/api/client-server/wellknown.yaml +60 -0
- data/data/matrix-spec/api/client-server/whoami.yaml +121 -0
- data/data/matrix-spec/event-schemas/examples/core/event.json +6 -0
- data/data/matrix-spec/event-schemas/examples/core/room_edu.json +3 -0
- data/data/matrix-spec/event-schemas/examples/core/room_event.json +11 -0
- data/data/matrix-spec/event-schemas/examples/core/state_event.json +4 -0
- data/data/matrix-spec/event-schemas/examples/invite_room_state.json +18 -0
- data/data/matrix-spec/event-schemas/examples/knock_room_state.json +18 -0
- data/data/matrix-spec/event-schemas/examples/m.accepted_terms.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.call.answer.yaml +21 -0
- data/data/matrix-spec/event-schemas/examples/m.call.candidates.yaml +16 -0
- data/data/matrix-spec/event-schemas/examples/m.call.hangup.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.call.invite.yaml +22 -0
- data/data/matrix-spec/event-schemas/examples/m.call.negotiate.yaml +22 -0
- data/data/matrix-spec/event-schemas/examples/m.call.reject.yaml +9 -0
- data/data/matrix-spec/event-schemas/examples/m.call.sdp_stream_metadata_changed.yaml +16 -0
- data/data/matrix-spec/event-schemas/examples/m.call.select_answer.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.direct.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.dummy.yaml +4 -0
- data/data/matrix-spec/event-schemas/examples/m.forwarded_room_key.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.fully_read.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.identity_server.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.ignored_user_list.yaml +9 -0
- data/data/matrix-spec/event-schemas/examples/m.invite_permission_config.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.accept.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.cancel.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.done.yaml +6 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.key.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.mac.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.ready.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.request.yaml +11 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.start$m.sas.v1.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.key.verification.start.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.key_backup.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.marked_unread.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.policy.rule.room.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.policy.rule.server.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.policy.rule.user.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.presence.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.push_rules.yaml +177 -0
- data/data/matrix-spec/event-schemas/examples/m.reaction.yaml +11 -0
- data/data/matrix-spec/event-schemas/examples/m.receipt.yaml +18 -0
- data/data/matrix-spec/event-schemas/examples/m.recent_emoji.yaml +16 -0
- data/data/matrix-spec/event-schemas/examples/m.room.avatar.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.room.canonical_alias.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.room.create.yaml +13 -0
- data/data/matrix-spec/event-schemas/examples/m.room.encrypted$megolm.yaml +11 -0
- data/data/matrix-spec/event-schemas/examples/m.room.encrypted$olm.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.room.encryption.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.room.guest_access.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room.history_visibility.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room.join_rules$restricted.yaml +18 -0
- data/data/matrix-spec/event-schemas/examples/m.room.join_rules.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room.member$invite_room_state.yaml +15 -0
- data/data/matrix-spec/event-schemas/examples/m.room.member$join_authorised_via_users_server.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.room.member$knock_room_state.yaml +15 -0
- data/data/matrix-spec/event-schemas/examples/m.room.member$third_party_invite.yaml +20 -0
- data/data/matrix-spec/event-schemas/examples/m.room.member.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.audio.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.emote.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.file.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.image.yaml +16 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.key.verification.request.yaml +19 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.location.yaml +18 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.notice.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.server_notice.yaml +11 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.text.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.room.message$m.video.yaml +23 -0
- data/data/matrix-spec/event-schemas/examples/m.room.name.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room.pinned_events.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room.policy.yaml +11 -0
- data/data/matrix-spec/event-schemas/examples/m.room.power_levels.yaml +24 -0
- data/data/matrix-spec/event-schemas/examples/m.room.redaction.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room.server_acl.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.room.third_party_invite.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.room.tombstone.yaml +9 -0
- data/data/matrix-spec/event-schemas/examples/m.room.topic.yaml +16 -0
- data/data/matrix-spec/event-schemas/examples/m.room_key.withheld.yaml +12 -0
- data/data/matrix-spec/event-schemas/examples/m.room_key.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.room_key_request$cancel_request.yaml +8 -0
- data/data/matrix-spec/event-schemas/examples/m.room_key_request$request.yaml +14 -0
- data/data/matrix-spec/event-schemas/examples/m.secret.request.yaml +9 -0
- data/data/matrix-spec/event-schemas/examples/m.secret.send.yaml +7 -0
- data/data/matrix-spec/event-schemas/examples/m.space.child.yaml +10 -0
- data/data/matrix-spec/event-schemas/examples/m.space.parent.yaml +9 -0
- data/data/matrix-spec/event-schemas/examples/m.sticker.yaml +22 -0
- data/data/matrix-spec/event-schemas/examples/m.tag.yaml +9 -0
- data/data/matrix-spec/event-schemas/examples/m.typing.yaml +7 -0
- data/data/matrix-spec/event-schemas/moderation_policy_rule.yaml +32 -0
- data/data/matrix-spec/event-schemas/schema/components/m_text_content_block.yaml +28 -0
- data/data/matrix-spec/event-schemas/schema/components/sdp_stream_metadata.yaml +43 -0
- data/data/matrix-spec/event-schemas/schema/components/signed_third_party_invite.yaml +48 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/call_event.yaml +27 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/event.yaml +16 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/avatar_info.yaml +30 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +52 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/msgtype_infos/thumbnail_info.yaml +22 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/room_event.yaml +17 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/state_event.yaml +8 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/stripped_state.yaml +48 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/sync_room_event.yaml +49 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/sync_state_event.yaml +36 -0
- data/data/matrix-spec/event-schemas/schema/core-event-schema/unsigned_prop.yaml +23 -0
- data/data/matrix-spec/event-schemas/schema/m.accepted_terms.yaml +25 -0
- data/data/matrix-spec/event-schemas/schema/m.call.answer.yaml +44 -0
- data/data/matrix-spec/event-schemas/schema/m.call.candidates.yaml +52 -0
- data/data/matrix-spec/event-schemas/schema/m.call.hangup.yaml +57 -0
- data/data/matrix-spec/event-schemas/schema/m.call.invite.yaml +53 -0
- data/data/matrix-spec/event-schemas/schema/m.call.negotiate.yaml +78 -0
- data/data/matrix-spec/event-schemas/schema/m.call.reject.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.call.sdp_stream_metadata_changed.yaml +24 -0
- data/data/matrix-spec/event-schemas/schema/m.call.select_answer.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.direct.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.dummy.yaml +25 -0
- data/data/matrix-spec/event-schemas/schema/m.forwarded_room_key.yaml +70 -0
- data/data/matrix-spec/event-schemas/schema/m.fully_read.yaml +26 -0
- data/data/matrix-spec/event-schemas/schema/m.identity_server.yaml +28 -0
- data/data/matrix-spec/event-schemas/schema/m.ignored_user_list.yaml +30 -0
- data/data/matrix-spec/event-schemas/schema/m.invite_permission_config.yaml +21 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.accept.yaml +63 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.cancel.yaml +72 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.done.yaml +24 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.key.yaml +31 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.m.relates_to.yaml +23 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.mac.yaml +43 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.ready.yaml +41 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.request.yaml +47 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.start$m.reciprocate.v1.yaml +45 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.start$m.sas.v1.yaml +76 -0
- data/data/matrix-spec/event-schemas/schema/m.key.verification.start.yaml +46 -0
- data/data/matrix-spec/event-schemas/schema/m.key_backup.yaml +24 -0
- data/data/matrix-spec/event-schemas/schema/m.marked_unread.yaml +26 -0
- data/data/matrix-spec/event-schemas/schema/m.policy.rule.room.yaml +17 -0
- data/data/matrix-spec/event-schemas/schema/m.policy.rule.server.yaml +17 -0
- data/data/matrix-spec/event-schemas/schema/m.policy.rule.user.yaml +17 -0
- data/data/matrix-spec/event-schemas/schema/m.presence.yaml +50 -0
- data/data/matrix-spec/event-schemas/schema/m.push_rules.yaml +23 -0
- data/data/matrix-spec/event-schemas/schema/m.reaction.yaml +45 -0
- data/data/matrix-spec/event-schemas/schema/m.receipt.yaml +65 -0
- data/data/matrix-spec/event-schemas/schema/m.recent_emoji.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.room.avatar.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.room.canonical_alias.yaml +40 -0
- data/data/matrix-spec/event-schemas/schema/m.room.create.yaml +86 -0
- data/data/matrix-spec/event-schemas/schema/m.room.encrypted.yaml +91 -0
- data/data/matrix-spec/event-schemas/schema/m.room.encryption.yaml +38 -0
- data/data/matrix-spec/event-schemas/schema/m.room.guest_access.yaml +28 -0
- data/data/matrix-spec/event-schemas/schema/m.room.history_visibility.yaml +30 -0
- data/data/matrix-spec/event-schemas/schema/m.room.join_rules.yaml +78 -0
- data/data/matrix-spec/event-schemas/schema/m.room.member.yaml +174 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.audio.yaml +73 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.emote.yaml +36 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.file.yaml +85 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.image.yaml +63 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.key.verification.request.yaml +70 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.location.yaml +50 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.notice.yaml +36 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.server_notice.yaml +41 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.text.yaml +36 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message$m.video.yaml +95 -0
- data/data/matrix-spec/event-schemas/schema/m.room.message.yaml +25 -0
- data/data/matrix-spec/event-schemas/schema/m.room.name.yaml +35 -0
- data/data/matrix-spec/event-schemas/schema/m.room.pinned_events.yaml +27 -0
- data/data/matrix-spec/event-schemas/schema/m.room.policy.yaml +41 -0
- data/data/matrix-spec/event-schemas/schema/m.room.power_levels.yaml +139 -0
- data/data/matrix-spec/event-schemas/schema/m.room.redaction.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.room.server_acl.yaml +88 -0
- data/data/matrix-spec/event-schemas/schema/m.room.third_party_invite.yaml +79 -0
- data/data/matrix-spec/event-schemas/schema/m.room.tombstone.yaml +29 -0
- data/data/matrix-spec/event-schemas/schema/m.room.topic.yaml +53 -0
- data/data/matrix-spec/event-schemas/schema/m.room_key.withheld.yaml +88 -0
- data/data/matrix-spec/event-schemas/schema/m.room_key.yaml +38 -0
- data/data/matrix-spec/event-schemas/schema/m.room_key_request.yaml +73 -0
- data/data/matrix-spec/event-schemas/schema/m.secret.request.yaml +42 -0
- data/data/matrix-spec/event-schemas/schema/m.secret.send.yaml +35 -0
- data/data/matrix-spec/event-schemas/schema/m.space.child.yaml +50 -0
- data/data/matrix-spec/event-schemas/schema/m.space.parent.yaml +36 -0
- data/data/matrix-spec/event-schemas/schema/m.sticker.yaml +36 -0
- data/data/matrix-spec/event-schemas/schema/m.tag.yaml +28 -0
- data/data/matrix-spec/event-schemas/schema/m.typing.yaml +29 -0
- data/lib/async/matrix/3.3/async_matrix_e2ee.so +0 -0
- data/lib/async/matrix/3.4/async_matrix_e2ee.so +0 -0
- data/lib/async/matrix/4.0/async_matrix_e2ee.so +0 -0
- data/lib/async/matrix/api/chain.rb +604 -0
- data/lib/async/matrix/api/concat.rb +107 -0
- data/lib/async/matrix/api/path_tree.rb +232 -0
- data/lib/async/matrix/api.rb +205 -0
- data/lib/async/matrix/auth_error.rb +20 -0
- data/lib/async/matrix/bad_json_error.rb +20 -0
- data/lib/async/matrix/client.rb +966 -0
- data/lib/async/matrix/config/vivify.rb +107 -0
- data/lib/async/matrix/config.rb +184 -0
- data/lib/async/matrix/connection.rb +19 -0
- data/lib/async/matrix/content.rb +106 -0
- data/lib/async/matrix/double_puppet_client.rb +82 -0
- data/lib/async/matrix/e2ee.rb +129 -0
- data/lib/async/matrix/endpoint.rb +57 -0
- data/lib/async/matrix/error.rb +40 -0
- data/lib/async/matrix/error_response.rb +37 -0
- data/lib/async/matrix/event.rb +197 -0
- data/lib/async/matrix/homeserver_error.rb +20 -0
- data/lib/async/matrix/invalid_endpoint_error.rb +20 -0
- data/lib/async/matrix/media_client.rb +181 -0
- data/lib/async/matrix/not_found_error.rb +20 -0
- data/lib/async/matrix/notifier.rb +108 -0
- data/lib/async/matrix/response_too_large_error.rb +20 -0
- data/lib/async/matrix/schema/registry.rb +381 -0
- data/lib/async/matrix/schema/validation_error.rb +232 -0
- data/lib/async/matrix/schema.rb +170 -0
- data/lib/async/matrix/server.rb +18 -0
- data/lib/async/matrix/stream.rb +18 -0
- data/lib/async/matrix/version.rb +10 -0
- data/lib/async/matrix.rb +15 -0
- 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
|