diff --git a/ruma-appservice-api/.builds/beta.yml b/ruma-appservice-api/.builds/beta.yml new file mode 100644 index 00000000..ec105e03 --- /dev/null +++ b/ruma-appservice-api/.builds/beta.yml @@ -0,0 +1,27 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-appservice-api +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install beta --profile minimal -c rustfmt -c clippy + rustup default beta + - test: | + cd ruma-appservice-api + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + cargo fmt -- --check + fmt_exit=$? + + cargo clippy --all-targets --all-features -- -D warnings + clippy_exit=$? + + cargo test --verbose + test_exit=$? + + exit $(( $fmt_exit || $clippy_exit || $test_exit )) diff --git a/ruma-appservice-api/.builds/msrv.yml b/ruma-appservice-api/.builds/msrv.yml new file mode 100644 index 00000000..635bffdb --- /dev/null +++ b/ruma-appservice-api/.builds/msrv.yml @@ -0,0 +1,16 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-appservice-api +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install 1.39.0 --profile minimal + rustup default 1.39.0 + - test: | + cd ruma-appservice-api + + # Only make sure the code builds with the MSRV. Tests can require later + # Rust versions, don't compile or run them. + cargo build --verbose diff --git a/ruma-appservice-api/.builds/nightly.yml b/ruma-appservice-api/.builds/nightly.yml new file mode 100644 index 00000000..72c98254 --- /dev/null +++ b/ruma-appservice-api/.builds/nightly.yml @@ -0,0 +1,32 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-appservice-api +tasks: + - rustup: | + rustup toolchain install nightly --profile minimal + rustup default nightly + + # Try installing rustfmt & clippy for nightly, but don't fail the build + # if they are not available + rustup component add rustfmt || true + rustup component add clippy || true + - test: | + cd ruma-appservice-api + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + if ( rustup component list | grep -q rustfmt ); then + cargo fmt -- --check + fi + fmt_exit=$? + + if ( rustup component list | grep -q clippy ); then + cargo clippy --all-targets --all-features -- -D warnings + fi + clippy_exit=$? + + exit $(( $fmt_exit || $clippy_exit )) diff --git a/ruma-appservice-api/.builds/stable.yml b/ruma-appservice-api/.builds/stable.yml new file mode 100644 index 00000000..28b8f0ff --- /dev/null +++ b/ruma-appservice-api/.builds/stable.yml @@ -0,0 +1,29 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-appservice-api +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install stable --profile minimal -c rustfmt -c clippy + rustup default stable + - test: | + cd ruma-appservice-api + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + cargo fmt -- --check + fmt_exit=$? + + cargo clippy --all-targets --all-features -- -D warnings + clippy_exit=$? + + cargo test --verbose + test_exit=$? + + exit $(( $fmt_exit || $clippy_exit || $test_exit )) + # TODO: Add audit task once cargo-audit binary releases are available. + # See https://github.com/RustSec/cargo-audit/issues/66 diff --git a/ruma-appservice-api/.gitignore b/ruma-appservice-api/.gitignore new file mode 100644 index 00000000..fa8d85ac --- /dev/null +++ b/ruma-appservice-api/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target diff --git a/ruma-appservice-api/CHANGELOG.md b/ruma-appservice-api/CHANGELOG.md new file mode 100644 index 00000000..69afd520 --- /dev/null +++ b/ruma-appservice-api/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.1.0 + +Initial release. diff --git a/ruma-appservice-api/Cargo.toml b/ruma-appservice-api/Cargo.toml new file mode 100644 index 00000000..6aa3f802 --- /dev/null +++ b/ruma-appservice-api/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["Wim de With "] +categories = ["api-bindings", "web-programming"] +description = "Types for the endpoints in the Matrix application service API." +homepage = "https://github.com/ruma/ruma-appservice-api" +keywords = ["matrix", "chat", "messaging", "ruma"] +license = "MIT" +name = "ruma-appservice-api" +readme = "README.md" +repository = "https://github.com/ruma/ruma-appservice-api" +version = "0.1.0" +edition = "2018" + +[dependencies] +ruma-api = "0.16.0" +ruma-events = "0.21.0" +ruma-identifiers = "0.16.1" +serde = { version = "1.0.106", features = ["derive"] } +serde_json = "1.0.52" +url = { version = "2.1.1", features = ["serde"] } diff --git a/ruma-appservice-api/LICENSE b/ruma-appservice-api/LICENSE new file mode 100644 index 00000000..da7c1156 --- /dev/null +++ b/ruma-appservice-api/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Wim de With + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ruma-appservice-api/README.md b/ruma-appservice-api/README.md new file mode 100644 index 00000000..7d010ee5 --- /dev/null +++ b/ruma-appservice-api/README.md @@ -0,0 +1,16 @@ +# ruma-appservice-api + +**ruma-appservice-api** contains serializable types for the requests and responses for each endpoint in the [Matrix](https://matrix.org/) application service API specification. +These types can be shared by application service and server code. + +## Minimum Rust version + +ruma-appservice-api requires Rust 1.39.0 or later. + +## Status + +This project is currently experimental and is very likely to change drastically. + +## License + +[MIT](http://opensource.org/licenses/MIT) diff --git a/ruma-appservice-api/src/lib.rs b/ruma-appservice-api/src/lib.rs new file mode 100644 index 00000000..a6372d51 --- /dev/null +++ b/ruma-appservice-api/src/lib.rs @@ -0,0 +1,13 @@ +//! Crate ruma_appservice_api contains serializable types for the requests and responses for each +//! endpoint in the [Matrix](https://matrix.org/) application service API specification. These +//! types can be shared by application service and server code. + +#![deny( + missing_copy_implementations, + missing_debug_implementations, + missing_docs +)] +// Since we support Rust 1.34.2, we can't apply this suggestion yet +#![allow(clippy::use_self)] + +pub mod v1; diff --git a/ruma-appservice-api/src/v1.rs b/ruma-appservice-api/src/v1.rs new file mode 100644 index 00000000..75499ade --- /dev/null +++ b/ruma-appservice-api/src/v1.rs @@ -0,0 +1,5 @@ +//! Endpoints for the r0.x.x versions of the application service API specification + +pub mod event; +pub mod query; +pub mod thirdparty; diff --git a/ruma-appservice-api/src/v1/event.rs b/ruma-appservice-api/src/v1/event.rs new file mode 100644 index 00000000..8721e54f --- /dev/null +++ b/ruma-appservice-api/src/v1/event.rs @@ -0,0 +1,3 @@ +//! Endpoint for sending events. + +pub mod push_events; diff --git a/ruma-appservice-api/src/v1/event/push_events.rs b/ruma-appservice-api/src/v1/event/push_events.rs new file mode 100644 index 00000000..bef1ec46 --- /dev/null +++ b/ruma-appservice-api/src/v1/event/push_events.rs @@ -0,0 +1,28 @@ +//! [PUT /_matrix/app/v1/transactions/{txnId}](https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-app-v1-transactions-txnid) + +use ruma_api::ruma_api; +use ruma_events::{collections::all, EventJson}; + +ruma_api! { + metadata { + description: "This API is called by the homeserver when it wants to push an event (or batch of events) to the application service.", + method: PUT, + name: "push_events", + path: "/_matrix/app/v1/transactions/:txn_id", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The transaction ID for this set of events. + /// + /// Homeservers generate these IDs and they are used to ensure idempotency of results. + #[ruma_api(path)] + pub txn_id: String, + /// A list of events. + #[ruma_api(body)] + pub events: Vec>, + } + + response {} +} diff --git a/ruma-appservice-api/src/v1/query.rs b/ruma-appservice-api/src/v1/query.rs new file mode 100644 index 00000000..ee67d7b8 --- /dev/null +++ b/ruma-appservice-api/src/v1/query.rs @@ -0,0 +1,4 @@ +//! Endpoints for querying user IDs and room aliases + +pub mod query_room_alias; +pub mod query_user_id; diff --git a/ruma-appservice-api/src/v1/query/query_room_alias.rs b/ruma-appservice-api/src/v1/query/query_room_alias.rs new file mode 100644 index 00000000..ea0e17fe --- /dev/null +++ b/ruma-appservice-api/src/v1/query/query_room_alias.rs @@ -0,0 +1,23 @@ +//! [GET /_matrix/app/v1/rooms/{roomAlias}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-rooms-roomalias) + +use ruma_api::ruma_api; +use ruma_identifiers::RoomAliasId; + +ruma_api! { + metadata { + description: "This endpoint is invoked by the homeserver on an application service to query the existence of a given room alias.", + method: GET, + name: "query_room_alias", + path: "/_matrix/app/v1/rooms/:room_alias", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The room alias being queried. + #[ruma_api(path)] + pub room_alias: RoomAliasId, + } + + response {} +} diff --git a/ruma-appservice-api/src/v1/query/query_user_id.rs b/ruma-appservice-api/src/v1/query/query_user_id.rs new file mode 100644 index 00000000..d45cccc3 --- /dev/null +++ b/ruma-appservice-api/src/v1/query/query_user_id.rs @@ -0,0 +1,23 @@ +//! [GET /_matrix/app/v1/users/{userId}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-users-userid) + +use ruma_api::ruma_api; +use ruma_identifiers::UserId; + +ruma_api! { + metadata { + description: "This endpoint is invoked by the homeserver on an application service to query the existence of a given user ID.", + method: GET, + name: "query_user_id", + path: "/_matrix/app/v1/users/:user_id", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The user ID being queried. + #[ruma_api(path)] + pub user_id: UserId, + } + + response {} +} diff --git a/ruma-appservice-api/src/v1/thirdparty.rs b/ruma-appservice-api/src/v1/thirdparty.rs new file mode 100644 index 00000000..16e40245 --- /dev/null +++ b/ruma-appservice-api/src/v1/thirdparty.rs @@ -0,0 +1,73 @@ +//! Endpoints for third party lookups + +pub mod get_location_for_protocol; +pub mod get_location_for_room_alias; +pub mod get_protocol; +pub mod get_user_for_protocol; +pub mod get_user_for_user_id; + +use std::collections::BTreeMap; + +use ruma_identifiers::{RoomAliasId, UserId}; + +use serde::{Deserialize, Serialize}; + +/// Metadata about a third party protocol. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Protocol { + /// Fields which may be used to identify a third party user. + pub user_fields: Vec, + /// Fields which may be used to identify a third party location. + pub location_fields: Vec, + /// A content URI representing an icon for the third party protocol. + pub icon: String, + /// The type definitions for the fields defined in `user_fields` and `location_fields`. + pub field_types: BTreeMap, + /// A list of objects representing independent instances of configuration. + pub instances: Vec, +} + +/// Metadata about an instance of a third party protocol. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct ProtocolInstance { + /// A human-readable description for the protocol, such as the name. + pub desc: String, + /// An optional content URI representing the protocol. + #[serde(skip_serializing_if = "Option::is_none")] + pub icon: Option, + /// Preset values for `fields` the client may use to search by. + pub fields: BTreeMap, + /// A unique identifier across all instances. + pub network_id: String, +} + +/// A type definition for a field used to identify third party users or locations. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct FieldType { + /// A regular expression for validation of a field's value. + pub regexp: String, + /// A placeholder serving as a valid example of the field value. + pub placeholder: String, +} + +/// A third party network location. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Location { + /// An alias for a matrix room. + pub alias: RoomAliasId, + /// The protocol ID that the third party location is a part of. + pub protocol: String, + /// Information used to identify this third party location. + pub fields: BTreeMap, +} + +/// A third party network user. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct User { + /// A matrix user ID representing a third party user. + pub userid: UserId, + /// The protocol ID that the third party user is a part of. + pub protocol: String, + /// Information used to identify this third party user. + pub fields: BTreeMap, +} diff --git a/ruma-appservice-api/src/v1/thirdparty/get_location_for_protocol.rs b/ruma-appservice-api/src/v1/thirdparty/get_location_for_protocol.rs new file mode 100644 index 00000000..6c791fd3 --- /dev/null +++ b/ruma-appservice-api/src/v1/thirdparty/get_location_for_protocol.rs @@ -0,0 +1,34 @@ +//! [GET /_matrix/app/v1/thirdparty/location/{protocol}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-location-protocol) + +use std::collections::BTreeMap; + +use ruma_api::ruma_api; + +use super::Location; + +ruma_api! { + metadata { + description: "Fetches third party locations for a protocol.", + method: GET, + name: "get_location_for_protocol", + path: "/_matrix/app/v1/thirdparty/location/:protocol", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The protocol used to communicate to the third party network. + #[ruma_api(path)] + pub protocol: String, + /// One or more custom fields to help identify the third party location. + // The specification is incorrect for this parameter. See matrix-org/matrix-doc#2352. + #[ruma_api(query_map)] + pub fields: BTreeMap, + } + + response { + /// List of matched third party locations. + #[ruma_api(body)] + pub locations: Vec, + } +} diff --git a/ruma-appservice-api/src/v1/thirdparty/get_location_for_room_alias.rs b/ruma-appservice-api/src/v1/thirdparty/get_location_for_room_alias.rs new file mode 100644 index 00000000..270e2661 --- /dev/null +++ b/ruma-appservice-api/src/v1/thirdparty/get_location_for_room_alias.rs @@ -0,0 +1,29 @@ +//! [GET /_matrix/app/v1/thirdparty/location](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-location) + +use ruma_api::ruma_api; +use ruma_identifiers::RoomAliasId; + +use super::Location; + +ruma_api! { + metadata { + description: "Retrieve an array of third party network locations from a Matrix room alias.", + method: GET, + name: "get_location_for_room_alias", + path: "/_matrix/app/v1/thirdparty/location", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The Matrix room alias to look up. + #[ruma_api(query)] + pub alias: RoomAliasId, + } + + response { + /// List of matched third party locations. + #[ruma_api(body)] + pub locations: Vec, + } +} diff --git a/ruma-appservice-api/src/v1/thirdparty/get_protocol.rs b/ruma-appservice-api/src/v1/thirdparty/get_protocol.rs new file mode 100644 index 00000000..726336c6 --- /dev/null +++ b/ruma-appservice-api/src/v1/thirdparty/get_protocol.rs @@ -0,0 +1,28 @@ +//! [GET /_matrix/app/v1/thirdparty/protocol/{protocol}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-protocol-protocol) + +use ruma_api::ruma_api; + +use super::Protocol; + +ruma_api! { + metadata { + description: "Fetches the metadata from the homeserver about a particular third party protocol.", + method: GET, + name: "get_protocol", + path: "/_matrix/app/v1/thirdparty/protocol/:protocol", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The name of the protocol. + #[ruma_api(path)] + pub protocol: String, + } + + response { + /// Metadata about the protocol. + #[ruma_api(body)] + pub protocol: Protocol, + } +} diff --git a/ruma-appservice-api/src/v1/thirdparty/get_user_for_protocol.rs b/ruma-appservice-api/src/v1/thirdparty/get_user_for_protocol.rs new file mode 100644 index 00000000..f9fb14a2 --- /dev/null +++ b/ruma-appservice-api/src/v1/thirdparty/get_user_for_protocol.rs @@ -0,0 +1,34 @@ +//! [GET /_matrix/app/v1/thirdparty/user/{protocol}](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-user-protocol) + +use std::collections::BTreeMap; + +use ruma_api::ruma_api; + +use super::User; + +ruma_api! { + metadata { + description: "Fetches third party users for a protocol.", + method: GET, + name: "get_user_for_protocol", + path: "/_matrix/app/v1/thirdparty/user/:protocol", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The protocol used to communicate to the third party network. + #[ruma_api(path)] + pub protocol: String, + /// One or more custom fields that are passed to the AS to help identify the user. + // The specification is incorrect for this parameter. See matrix-org/matrix-doc#2352. + #[ruma_api(query_map)] + pub fields: BTreeMap, + } + + response { + /// List of matched third party users. + #[ruma_api(body)] + pub users: Vec, + } +} diff --git a/ruma-appservice-api/src/v1/thirdparty/get_user_for_user_id.rs b/ruma-appservice-api/src/v1/thirdparty/get_user_for_user_id.rs new file mode 100644 index 00000000..7ac655ef --- /dev/null +++ b/ruma-appservice-api/src/v1/thirdparty/get_user_for_user_id.rs @@ -0,0 +1,29 @@ +//! [GET /_matrix/app/v1/thirdparty/user](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-user) + +use ruma_api::ruma_api; +use ruma_identifiers::UserId; + +use super::User; + +ruma_api! { + metadata { + description: "Retrieve an array of third party users from a Matrix User ID.", + method: GET, + name: "get_user_for_user_id", + path: "/_matrix/app/v1/thirdparty/user", + rate_limited: false, + requires_authentication: true, + } + + request { + /// The Matrix User ID to look up. + #[ruma_api(query)] + pub userid: UserId, + } + + response { + /// List of matched third party users. + #[ruma_api(body)] + pub users: Vec, + } +}