Compare commits
	
		
			145 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a112a5e57c | ||
|  | dbc764fe65 | ||
|  | d5680b2dfe | ||
|  | 5aad4fb81e | ||
|  | a1f64f5159 | ||
|  | a96920f533 | ||
|  | 9ca2ebdad0 | ||
|  | 7f284ac71e | ||
|  | 4d488a3fc8 | ||
|  | 7ee3e19de4 | ||
|  | 608938c084 | ||
|  | e6fec9199d | ||
|  | c3262a9f25 | ||
|  | 136563c61a | ||
|  | 3043cd4e61 | ||
|  | 21d9d0fda1 | ||
|  | a964b073bf | ||
|  | f85345bc97 | ||
|  | 29603682e5 | ||
|  | d54f1dcb88 | ||
|  | 92f10347d1 | ||
|  | 0298f66212 | ||
|  | 0ddd086bda | ||
|  | 544f8e59f0 | ||
|  | 917f87bf8c | ||
|  | 774795c203 | ||
|  | 27b2976e42 | ||
|  | f16f184253 | ||
|  | cd890d114a | ||
|  | 321ba1e325 | ||
|  | c3ce0a17f6 | ||
|  | 0fcc0d9bb2 | ||
|  | ce7f900543 | ||
|  | c7c009f9af | ||
|  | 3b01663245 | ||
|  | 9cc601d582 | ||
|  | e6272b1827 | ||
|  | 8243354f39 | ||
|  | 25968e0737 | ||
|  | 44a80461a0 | ||
|  | 85d9f9e704 | ||
|  | 6278301672 | ||
|  | 5ed0c66cfd | ||
|  | ea58b6985a | ||
|  | a44f781495 | ||
|  | 0d42ee695a | ||
|  | f331af0941 | ||
|  | e2c8a56135 | ||
|  | a67c5d7ae1 | ||
|  | 80352070f1 | ||
|  | 39447b8b8b | ||
|  | 9d4680f55a | ||
|  | d1ea0fbf0f | ||
|  | ee21f051fb | ||
|  | 6cc17abf2c | ||
|  | a7b5accd75 | ||
|  | 6bb0c93f57 | ||
|  | 9abdcc15ba | ||
|  | eb903bf226 | ||
|  | 1cbb0a135b | ||
|  | 1587103c0a | ||
|  | 838d79ae15 | ||
|  | 96c47ecf76 | ||
|  | c5cea933a4 | ||
|  | 57c7e4a91d | ||
|  | 1dce59a02e | ||
|  | de840b9d00 | ||
|  | 53c85d2248 | ||
|  | 254dc5684f | ||
|  | de92e98f7d | ||
|  | d5f9137056 | ||
|  | 1307e3aa43 | ||
|  | dfedde0df6 | ||
|  | 93bd7354c2 | ||
|  | c302789898 | ||
|  | 96155c1876 | ||
|  | 95ee328281 | ||
|  | 72a1794cc3 | ||
|  | 37ddd0e588 | ||
|  | 4d63bba251 | ||
|  | aadfae2965 | ||
|  | 2f7e5e4025 | ||
|  | 77dc75d383 | ||
|  | f3b528d1ba | ||
|  | 91e5e08e70 | ||
|  | acd8c7d7c5 | ||
|  | 249cc0ea92 | ||
|  | 99697d7c75 | ||
|  | e133e120d7 | ||
|  | e39d6bfa10 | ||
|  | 217bc423ed | ||
|  | 8f0654c34e | ||
|  | 8afdb3ed83 | ||
|  | bd4ccbc5e5 | ||
|  | 6d1c6ed109 | ||
|  | 1619f5311c | ||
|  | 6fa36ea092 | ||
|  | 471e06536b | ||
|  | 3a6b75996c | ||
|  | 566e4f3137 | ||
|  | a4c18dee5d | ||
|  | 8d6850d346 | ||
|  | 67bc18af7d | ||
|  | 5c660fdcaf | ||
|  | fbbafeb769 | ||
|  | 559f6a7401 | ||
|  | 3bebb33147 | ||
|  | 3e240fe34d | ||
|  | 635f6fdbe7 | ||
|  | 4237eeb3b6 | ||
|  | a0e91e7896 | ||
|  | aab0b86646 | ||
|  | 3e22301af7 | ||
|  | 2b202323c0 | ||
|  | 4ec05f518e | ||
|  | 6da68298b0 | ||
|  | aecaafdeca | ||
|  | d885932f45 | ||
|  | c689a3f161 | ||
|  | 7805112548 | ||
|  | 3e89f0bc5e | ||
|  | c6b8f7d48e | ||
|  | 83377ebee0 | ||
|  | 2aa6e4d142 | ||
|  | 82a1a3df68 | ||
|  | 7ec11ba8cf | ||
|  | 9317c11434 | ||
|  | b257a0275f | ||
|  | 2aaa04062f | ||
|  | 54c3014568 | ||
|  | c3ca73f576 | ||
|  | 4185b644b7 | ||
|  | ace5918342 | ||
|  | 7ad985fead | ||
|  | 6a376db322 | ||
|  | 950f7c931c | ||
|  | d160a44509 | ||
|  | 05493da27c | ||
|  | df44428a85 | ||
|  | e6f9c30611 | ||
|  | 06b2c787d3 | ||
|  | 5645f69208 | ||
|  | 92cf5c6b21 | ||
|  | ad1b91f370 | ||
|  | e9c29f1c03 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -7,7 +7,8 @@ out/ | |||||||
| .idea/ | .idea/ | ||||||
|  |  | ||||||
| # Local dev config | # Local dev config | ||||||
|  | /ma1sd.yaml | ||||||
| /application.yaml | /application.yaml | ||||||
|  |  | ||||||
| # Local dev storage | # Local dev storage | ||||||
| /mxisd.db | /ma1sd.db | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -2,16 +2,17 @@ FROM openjdk:8-jre-alpine | |||||||
|  |  | ||||||
| RUN apk update && apk add bash && rm -rf /var/lib/apk/* /var/cache/apk/* | RUN apk update && apk add bash && rm -rf /var/lib/apk/* /var/cache/apk/* | ||||||
|  |  | ||||||
| VOLUME /etc/mxisd | VOLUME /etc/ma1sd | ||||||
| VOLUME /var/mxisd | VOLUME /var/ma1sd | ||||||
| EXPOSE 8090 | EXPOSE 8090 | ||||||
|  |  | ||||||
| ENV JAVA_OPTS="" | ENV JAVA_OPTS="" | ||||||
| ENV CONF_FILE_PATH="/etc/mxisd/mxisd.yaml" | ENV CONF_FILE_PATH="/etc/ma1sd/ma1sd.yaml" | ||||||
| ENV SIGN_KEY_PATH="/var/mxisd/sign.key" | ENV SIGN_KEY_PATH="/var/ma1sd/sign.key" | ||||||
| ENV SQLITE_DATABASE_PATH="/var/mxisd/mxisd.db" | ENV SQLITE_DATABASE_PATH="/var/ma1sd/ma1sd.db" | ||||||
|  |  | ||||||
| CMD [ "/start.sh" ] | CMD [ "/start.sh" ] | ||||||
|  |  | ||||||
| ADD src/docker/start.sh /start.sh | ADD src/docker/start.sh /start.sh | ||||||
| ADD build/libs/mxisd.jar /mxisd.jar | ADD src/script/ma1sd /app/ma1sd | ||||||
|  | ADD build/libs/ma1sd.jar /app/ma1sd.jar | ||||||
|   | |||||||
							
								
								
									
										77
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| mxisd - Federated Matrix Identity Server | ma1sd - Federated Matrix Identity Server | ||||||
| ---------------------------------------- | ---------------------------------------- | ||||||
|    |    | ||||||
|  |  | ||||||
| - [Overview](#overview) | - [Overview](#overview) | ||||||
| - [Features](#features) | - [Features](#features) | ||||||
| @@ -8,20 +8,29 @@ mxisd - Federated Matrix Identity Server | |||||||
| - [Getting Started](#getting-started) | - [Getting Started](#getting-started) | ||||||
| - [Support](#support) | - [Support](#support) | ||||||
| - [Contribute](#contribute) | - [Contribute](#contribute) | ||||||
|  | - [Powered by ma1sd](#powered-by-ma1sd) | ||||||
| - [FAQ](#faq) | - [FAQ](#faq) | ||||||
|  | - [Migration from mxisd](#migration-from-mxisd) | ||||||
| - [Contact](#contact) | - [Contact](#contact) | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | * This project is a fork of the https://github.com/kamax-matrix/mxisd which has been archived and no longer supported. * | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
| # Overview | # Overview | ||||||
| mxisd is a Federated Matrix Identity server for self-hosted Matrix infrastructures with [enhanced features](#features). | ma1sd is a Federated Matrix Identity server for self-hosted Matrix infrastructures with [enhanced features](#features). | ||||||
| As an enhanced Identity service, it implements the [Matrix Identity service API](https://kamax.io/matrix/api/identity_service/unstable.html) | As an enhanced Identity service, it implements the [Identity service API](https://matrix.org/docs/spec/identity_service/r0.2.0.html) | ||||||
| and several [extra features](#features) that greatly enhance user experience within Matrix. | and several [extra features](#features) that greatly enhance user experience within Matrix. | ||||||
| It is the one stop shop for anything regarding Authentication, Directory and Identity management in Matrix built in a | It is the one stop shop for anything regarding Authentication, Directory and Identity management in Matrix built in a | ||||||
| single coherent product. | single coherent product. | ||||||
|    |  | ||||||
| mxisd is specifically designed to connect to an existing on-premise Identity store (AD/Samba/LDAP, SQL Database, |  | ||||||
| Web services/app, etc.) and ease the integration of a Matrix infrastructure within an existing one. |  | ||||||
|  |  | ||||||
| The core principle of mxisd is to map between Matrix IDs and 3PIDs (Third-Party IDentifiers) for the Homeserver and its | ma1sd is specifically designed to connect to an existing on-premise Identity store (AD/Samba/LDAP, SQL Database, | ||||||
|  | Web services/app, etc.) and ease the integration of a Matrix infrastructure within an existing one.   | ||||||
|  | Check [our FAQ entry](docs/faq.md#what-kind-of-setup-is-ma1sd-really-designed-for) to know if ma1sd is a good fit for you. | ||||||
|  |  | ||||||
|  | The core principle of ma1sd is to map between Matrix IDs and 3PIDs (Third-Party IDentifiers) for the Homeserver and its | ||||||
| users. 3PIDs can be anything that uniquely and globally identify a user, like: | users. 3PIDs can be anything that uniquely and globally identify a user, like: | ||||||
| - Email address | - Email address | ||||||
| - Phone number | - Phone number | ||||||
| @@ -29,18 +38,18 @@ users. 3PIDs can be anything that uniquely and globally identify a user, like: | |||||||
| - Twitter handle | - Twitter handle | ||||||
| - Facebook ID | - Facebook ID | ||||||
|  |  | ||||||
| If you are unfamiliar with the Identity vocabulary and concepts in Matrix, **please read this [introduction](docs/concepts.md)**. | If you are unfamiliar with the Identity vocabulary and concepts in Matrix, **please read this [introduction](docs/concepts.md)**.   | ||||||
|  |  | ||||||
| # Features | # Features | ||||||
| [Identity](docs/features/identity.md): As a [regular Matrix Identity service](https://kamax.io/matrix/api/identity_service/unstable.html#general-principles): | [Identity](docs/features/identity.md): As a [regular Matrix Identity service](https://matrix.org/docs/spec/identity_service/r0.2.0.html#general-principles): | ||||||
| - Search for people by 3PID using its own Identity stores | - Search for people by 3PID using its own Identity stores | ||||||
|   ([Spec](https://kamax.io/matrix/api/identity_service/unstable.html#association-lookup)) |   ([Spec](https://matrix.org/docs/spec/identity_service/r0.2.0.html#association-lookup)) | ||||||
| - Invite people to rooms by 3PID using its own Identity stores, with notifications to the invitee (Email, SMS, etc.) | - Invite people to rooms by 3PID using its own Identity stores, with notifications to the invitee (Email, SMS, etc.) | ||||||
|   ([Spec](https://kamax.io/matrix/api/identity_service/unstable.html#post-matrix-identity-api-v1-store-invite)) |   ([Spec](https://matrix.org/docs/spec/identity_service/r0.2.0.html#invitation-storage)) | ||||||
| - Allow users to add 3PIDs to their settings/profile | - Allow users to add/remove 3PIDs to their settings/profile via 3PID sessions | ||||||
|   ([Spec](https://kamax.io/matrix/api/identity_service/unstable.html#establishing-associations)) |   ([Spec](https://matrix.org/docs/spec/identity_service/r0.2.0.html#establishing-associations)) | ||||||
| - Register accounts on your Homeserver with 3PIDs | - Register accounts on your Homeserver with 3PIDs | ||||||
|   ([Spec](https://kamax.io/matrix/api/identity_service/unstable.html#establishing-associations)) |   ([Spec](https://matrix.org/docs/spec/identity_service/r0.2.0.html#establishing-associations)) | ||||||
|  |  | ||||||
| As an enhanced Identity service: | As an enhanced Identity service: | ||||||
| - [Federation](docs/features/federation.md): Use a recursive lookup mechanism when searching and inviting people by 3PID, | - [Federation](docs/features/federation.md): Use a recursive lookup mechanism when searching and inviting people by 3PID, | ||||||
| @@ -51,6 +60,7 @@ As an enhanced Identity service: | |||||||
|   - Central Matrix Identity servers |   - Central Matrix Identity servers | ||||||
| - [Session Control](docs/threepids/session/session.md): Extensive control of where 3PIDs are transmitted so they are not | - [Session Control](docs/threepids/session/session.md): Extensive control of where 3PIDs are transmitted so they are not | ||||||
|   leaked publicly by users |   leaked publicly by users | ||||||
|  | - [Registration control](docs/features/registration.md): Control and restrict user registration based on 3PID patterns or criterias, like a pending invite | ||||||
| - [Authentication](docs/features/authentication.md): Use your Identity stores to perform authentication in [synapse](https://github.com/matrix-org/synapse) | - [Authentication](docs/features/authentication.md): Use your Identity stores to perform authentication in [synapse](https://github.com/matrix-org/synapse) | ||||||
|   via the [REST password provider](https://github.com/kamax-io/matrix-synapse-rest-auth) |   via the [REST password provider](https://github.com/kamax-io/matrix-synapse-rest-auth) | ||||||
| - [Directory search](docs/features/directory.md) which allows you to search for users within your organisation, | - [Directory search](docs/features/directory.md) which allows you to search for users within your organisation, | ||||||
| @@ -66,40 +76,43 @@ As an enhanced Identity service: | |||||||
| - Users can directly find each other using whatever attribute is relevant within your Identity store | - Users can directly find each other using whatever attribute is relevant within your Identity store | ||||||
| - Federate your Identity server so you can discover others and/or others can discover you | - Federate your Identity server so you can discover others and/or others can discover you | ||||||
|  |  | ||||||
|  | Also, check [our FAQ entry](docs/faq.md#what-kind-of-setup-is-ma1sd-really-designed-for) to know if ma1sd is a good fit for you. | ||||||
|  |  | ||||||
| # Getting started | # Getting started | ||||||
| See the [dedicated document](docs/getting-started.md) | See the [dedicated document](docs/getting-started.md) | ||||||
|  |  | ||||||
| # Support | # Support | ||||||
| ## Community | ## Troubleshooting | ||||||
| Over Matrix: [#mxisd:kamax.io](https://matrix.to/#/#mxisd:kamax.io) ([Preview](https://view.matrix.org/room/!NPRUEisLjcaMtHIzDr:kamax.io/)) | A basic troubleshooting guide is available [here](docs/troubleshooting.md). | ||||||
|  |  | ||||||
| For more high-level discussion about the Identity Server architecture/API, go to  [#matrix-identity:kamax.io](https://matrix.to/#/#matrix-identity:kamax.io) | ## Community | ||||||
|  | Over Matrix: [#ma1sd:ru-matrix.org](https://matrix.to/#/#ma1sd:ru-matrix.org) ([Preview](https://view.matrix.org/room/!CxwBdgAlaphCARnKTA:ru-matrix.org/)) | ||||||
|  |  | ||||||
| ## Commercial | ## Commercial | ||||||
| If you would prefer professional support/custom development for mxisd and/or for Matrix in general, including other open | Sorry, I cannot provide commercial support (at least now). But always try to help you. | ||||||
| source technologies/products: |  | ||||||
| - Visit our [website](https://www.kamax.io/) to get in touch with us and get a quote. | Don't hesitate to ask about project and feel free to create issues at https://github.com/ma1uta/ma1sd | ||||||
| - Come in our general Matrix room: [#kamax-matrix:kamax.io](https://matrix.to/#/#kamax-matrix:kamax.io) |  | ||||||
|  |  | ||||||
| # Contribute  | # Contribute  | ||||||
| You can contribute as a community member by: | You can contribute as a community member by: | ||||||
| - Giving us feedback about your usage of mxisd, even if it seems unimportant or if all is working well! | - Giving us feedback about your usage of ma1sd, even if it seems unimportant or if all is working well! | ||||||
| - Opening issues for any weird behaviour or bug. mxisd should feel natural, let us know if it does not! | - Opening issues for any weird behaviour or bug. ma1sd should feel natural, let us know if it does not! | ||||||
| - Helping us improve the documentation: tell us what is good or not good (in an issue or in Matrix), or make a PR with | - Helping us improve the documentation: tell us what is good or not good (in an issue or in Matrix), or make a PR with | ||||||
| changes you feel improve the doc. | changes you feel improve the doc. | ||||||
| - Contribute code directly: we love contributors! All your contributions will be licensed under AGPLv3. | - Contribute code directly: we love contributors! All your contributions will be licensed under AGPLv3. | ||||||
| - [Donate!](https://liberapay.com/maximusdor/) Any donation is welcome, regardless how small or big, and will directly |  | ||||||
| be used for the fixed costs and developer time of mxisd. |  | ||||||
|  |  | ||||||
| You can contribute as an organisation/corporation by: | # Powered by ma1sd | ||||||
| - Get a [support contract](#commercial). This is the best way you can help us as it ensures mxisd is | The following projects can use ma1sd under the hood for some or all their features. Check them out! | ||||||
| maintained regularly and you get direct access to the support team. | - [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy) | ||||||
| - Sponsoring new features or bug fixes. [Get in touch](#contact) so we can discuss it further. | - [matrix-register-bot](https://github.com/krombel/matrix-register-bot) | ||||||
|  |  | ||||||
| # FAQ | # FAQ | ||||||
| See the [dedicated document](docs/faq.md) | See the [dedicated document](docs/faq.md) | ||||||
|  |  | ||||||
|  | # Migration from mxisd | ||||||
|  |  | ||||||
|  | See the [migration guide](docs/migration-from-mxisd.md) | ||||||
|  |  | ||||||
| # Contact | # Contact | ||||||
| Get in touch via: | Get in touch via: | ||||||
| - Matrix: [#mxisd:kamax.io](https://matrix.to/#/#mxisd:kamax.io) | - Matrix: [#ma1sd:ru-matrix.org](https://matrix.to/#/#ma1sd:ru-matrix.org) | ||||||
| - Email: see our website: [Kamax.io](https://www.kamax.io) |  | ||||||
|   | |||||||
| @@ -1,114 +0,0 @@ | |||||||
| # Sample configuration file explaining the minimum required keys to be set to run mxisd |  | ||||||
| # |  | ||||||
| # For a complete list of options, see https://github.com/kamax-matrix/mxisd |  | ||||||
|  |  | ||||||
| ####################### |  | ||||||
| # Matrix config items # |  | ||||||
| ####################### |  | ||||||
| # Matrix domain, same as the domain configure in your Homeserver configuration. |  | ||||||
| # (note: in Synapse Homeserver, the Matrix domain may be defined as 'server_name' in configuration file). |  | ||||||
| # |  | ||||||
| # This is used to build the various identifiers for identity, auth and directory. |  | ||||||
| matrix.domain: '' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ################ |  | ||||||
| # Signing keys # |  | ||||||
| ################ |  | ||||||
| # Absolute path for the Identity Server signing key. |  | ||||||
| # During testing, /var/tmp/mxisd.key is a possible value |  | ||||||
| # |  | ||||||
| # For production, recommended location shall be one of the following: |  | ||||||
| #   - /var/opt/mxisd/sign.key |  | ||||||
| #   - /var/local/mxisd/sign.key |  | ||||||
| #   - /var/lib/mxisd/sign.key |  | ||||||
| # |  | ||||||
| # The signing key is auto-generated during execution time if not present. |  | ||||||
| key.path: '' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ############################ |  | ||||||
| # Persistence config items # |  | ||||||
| ############################ |  | ||||||
|  |  | ||||||
| # Configure the storage backend, usually a DB |  | ||||||
| # Possible built-in values: |  | ||||||
| #   sqlite                      SQLite backend, default |  | ||||||
| # |  | ||||||
| #storage.backend: 'sqlite' |  | ||||||
|  |  | ||||||
| # Path to the SQLite DB file |  | ||||||
| # |  | ||||||
| # Examples: |  | ||||||
| #  - /var/opt/mxisd/mxisd.db |  | ||||||
| #  - /var/local/mxisd/mxisd.db |  | ||||||
| #  - /var/lib/mxisd/mxisd.db |  | ||||||
| # |  | ||||||
| storage.provider.sqlite.database: '/path/to/mxisd.db' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #################### |  | ||||||
| # Fallback servers # |  | ||||||
| #################### |  | ||||||
| # |  | ||||||
| # Root/Central servers to be used as final fallback when performing lookups. |  | ||||||
| # By default, for privacy reasons, matrix.org servers are not enabled anymore. |  | ||||||
| # See the following issue: https://github.com/kamax-matrix/mxisd/issues/76 |  | ||||||
| # |  | ||||||
| # If you would like to use them and trade away your privacy for convenience, uncomment the following option: |  | ||||||
| # |  | ||||||
| #forward.servers: ['matrix-org'] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ################ |  | ||||||
| # LDAP Backend # |  | ||||||
| ################ |  | ||||||
| # If you would like to integrate with your AD/Samba/LDAP server, |  | ||||||
| # see https://github.com/kamax-matrix/mxisd/blob/master/docs/stores/ldap.md |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ############### |  | ||||||
| # SQL Backend # |  | ||||||
| ############### |  | ||||||
| # If you would like to integrate with a MySQL/MariaDB/PostgreQL/SQLite DB, |  | ||||||
| # see https://github.com/kamax-matrix/mxisd/blob/master/docs/stores/sql.md |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ################ |  | ||||||
| # REST Backend # |  | ||||||
| ################ |  | ||||||
| # If you would like to integrate with an existing web service/webapp, |  | ||||||
| # see https://github.com/kamax-matrix/mxisd/blob/master/docs/stores/rest.md |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ################################################# |  | ||||||
| # Notifications for invites/addition to profile # |  | ||||||
| ################################################# |  | ||||||
| # If you would like to change the content, |  | ||||||
| # see https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/notification/template-generator.md |  | ||||||
| # |  | ||||||
| #### E-mail invite sender |  | ||||||
| # |  | ||||||
| # SMTP host |  | ||||||
| threepid.medium.email.connectors.smtp.host: "smtp.example.org" |  | ||||||
|  |  | ||||||
| # SMTP port |  | ||||||
| threepid.medium.email.connectors.smtp.port: 587 |  | ||||||
|  |  | ||||||
| # TLS mode for the connection. |  | ||||||
| # |  | ||||||
| # Possible values: |  | ||||||
| #  0    Disable TLS entirely |  | ||||||
| #  1    Enable TLS if supported by server (default) |  | ||||||
| #  2    Force TLS and fail if not available |  | ||||||
| # |  | ||||||
| #threepid.medium.email.connectors.smtp.tls: 1 |  | ||||||
|  |  | ||||||
| # Login for SMTP |  | ||||||
| threepid.medium.email.connectors.smtp.login: "matrix-identity@example.org" |  | ||||||
|  |  | ||||||
| # Password for the account |  | ||||||
| threepid.medium.email.connectors.smtp.password: "ThePassword" |  | ||||||
|  |  | ||||||
| # The e-mail to send as. |  | ||||||
| threepid.medium.email.identity.from: "matrix-identity@example.org" |  | ||||||
							
								
								
									
										167
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										167
									
								
								build.gradle
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| /* | /* | ||||||
|  * mxisd - Matrix Identity Server Daemon |  * ma1sd - Matrix Identity Server Daemon | ||||||
|  * Copyright (C) 2017 Kamax Sarl |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  * |  * | ||||||
|  * https://www.kamax.io/ |  * https://www.kamax.io/ | ||||||
| @@ -21,17 +21,21 @@ | |||||||
| import java.util.regex.Pattern | import java.util.regex.Pattern | ||||||
|  |  | ||||||
| apply plugin: 'java' | apply plugin: 'java' | ||||||
| apply plugin: 'org.springframework.boot' | apply plugin: 'application' | ||||||
|  | apply plugin: 'com.github.johnrengelman.shadow' | ||||||
|  | apply plugin: 'idea' | ||||||
|  | apply plugin: 'com.github.ben-manes.versions' | ||||||
|  |  | ||||||
| def confFileName = "application.example.yaml" | def confFileName = "ma1sd.example.yaml" | ||||||
| def distDir = "${project.buildDir}/dist" | def distDir = "${project.buildDir}/dist" | ||||||
|  |  | ||||||
| def debBinPath = "/usr/lib/mxisd" | def debBinPath = "/usr/lib/ma1sd" | ||||||
| def debConfPath = "/etc/mxisd" | def debConfPath = "/etc/ma1sd" | ||||||
| def debDataPath = "/var/lib/mxisd" | def debDataPath = "/var/lib/ma1sd" | ||||||
| def debSystemdPath = "/etc/systemd/system" | def debSystemdPath = "/etc/systemd/system" | ||||||
|  |  | ||||||
| def debConfFileName = "mxisd-sample.yaml" | def debConfFileName = confFileName | ||||||
|  | def debStartScriptFilename = "ma1sd" | ||||||
|  |  | ||||||
| def debBuildBasePath = "${project.buildDir}/tmp/debian" | def debBuildBasePath = "${project.buildDir}/tmp/debian" | ||||||
| def debBuildDebianPath = "${debBuildBasePath}/DEBIAN" | def debBuildDebianPath = "${debBuildBasePath}/DEBIAN" | ||||||
| @@ -40,13 +44,18 @@ def debBuildConfPath = "${debBuildBasePath}${debConfPath}" | |||||||
| def debBuildDataPath = "${debBuildBasePath}${debDataPath}" | def debBuildDataPath = "${debBuildBasePath}${debDataPath}" | ||||||
| def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}" | def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}" | ||||||
|  |  | ||||||
| def dockerImageName = "kamax/mxisd" | def dockerImageName = "ma1uta/ma1sd" | ||||||
| def dockerImageTag = "${dockerImageName}:${mxisdVersion()}" | def dockerImageTag = "${dockerImageName}:${ma1sdVersion()}" | ||||||
|  |  | ||||||
| String mxisdVersion() { | group = 'io.kamax' | ||||||
|  | mainClassName = 'io.kamax.mxisd.MxisdStandaloneExec' | ||||||
|  | sourceCompatibility = '1.8' | ||||||
|  | targetCompatibility = '1.8' | ||||||
|  |  | ||||||
|  | String ma1sdVersion() { | ||||||
|     def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?") |     def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?") | ||||||
|  |  | ||||||
|     String version = System.getenv('MXISD_BUILD_VERSION') |     String version = System.getenv('MA1SD_BUILD_VERSION') | ||||||
|     if (version == null || version.size() == 0) { |     if (version == null || version.size() == 0) { | ||||||
|         version = gitVersion() |         version = gitVersion() | ||||||
|     } |     } | ||||||
| @@ -59,128 +68,132 @@ String gitVersion() { | |||||||
|         commandLine = ['git', 'describe', '--tags', '--always', '--dirty'] |         commandLine = ['git', 'describe', '--tags', '--always', '--dirty'] | ||||||
|         standardOutput = out |         standardOutput = out | ||||||
|     } |     } | ||||||
|     return out.toString().replace(System.lineSeparator(), ''); |     return out.toString().replace(System.lineSeparator(), '') | ||||||
| } | } | ||||||
|  |  | ||||||
| buildscript { | buildscript { | ||||||
|     repositories { |     repositories { | ||||||
|         mavenCentral() |         jcenter() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     dependencies { |     dependencies { | ||||||
|         classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.3.RELEASE' |         classpath 'com.github.jengelman.gradle.plugins:shadow:5.1.0' | ||||||
|  |         classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0' | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| repositories { | repositories { | ||||||
|     mavenCentral() |     jcenter() | ||||||
|     maven { url "https://kamax.io/maven/releases/" } |  | ||||||
|     maven { url "https://kamax.io/maven/snapshots/" } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
|  |     // Logging | ||||||
|  |     compile 'org.slf4j:slf4j-simple:1.7.25' | ||||||
|  |  | ||||||
|     // Easy file management |     // Easy file management | ||||||
|     compile 'commons-io:commons-io:2.5' |     compile 'commons-io:commons-io:2.6' | ||||||
|  |  | ||||||
|     // Spring Boot - standalone app |     // Config management | ||||||
|     compile 'org.springframework.boot:spring-boot-starter-web:1.5.10.RELEASE' |     compile 'org.yaml:snakeyaml:1.24' | ||||||
|  |  | ||||||
|     // Thymeleaf for HTML templates |     // Dependencies from old Matrix-java-sdk | ||||||
|     compile "org.springframework.boot:spring-boot-starter-thymeleaf:1.5.10.RELEASE" |     compile 'org.apache.commons:commons-lang3:3.9' | ||||||
|  |     compile 'com.squareup.okhttp3:okhttp:4.0.1' | ||||||
|  |     compile 'commons-codec:commons-codec:1.12' | ||||||
|  |  | ||||||
|     // Matrix Java SDK |     // ORMLite | ||||||
|     compile 'io.kamax:matrix-java-sdk:0.0.14-8-g0e57ec6' |     compile 'com.j256.ormlite:ormlite-jdbc:5.1' | ||||||
|  |  | ||||||
|     // ed25519 handling |     // ed25519 handling | ||||||
|     compile 'net.i2p.crypto:eddsa:0.1.0' |     compile 'net.i2p.crypto:eddsa:0.3.0' | ||||||
|  |  | ||||||
|     // LDAP connector |     // LDAP connector | ||||||
|     compile 'org.apache.directory.api:api-all:1.0.0' |     compile 'org.apache.directory.api:api-all:1.0.0' | ||||||
|  |  | ||||||
|     // DNS lookups |     // DNS lookups | ||||||
|     compile 'dnsjava:dnsjava:2.1.8' |     compile 'dnsjava:dnsjava:2.1.9' | ||||||
|  |  | ||||||
|     // HTTP connections |     // HTTP connections | ||||||
|     compile 'org.apache.httpcomponents:httpclient:4.5.3' |     compile 'org.apache.httpcomponents:httpclient:4.5.9' | ||||||
|  |  | ||||||
|     // Phone numbers validation |     // Phone numbers validation | ||||||
|     compile 'com.googlecode.libphonenumber:libphonenumber:8.7.1' |     compile 'com.googlecode.libphonenumber:libphonenumber:8.10.15' | ||||||
|  |  | ||||||
|     // E-mail sending |     // E-mail sending | ||||||
|     compile 'com.sun.mail:javax.mail:1.6.2' |  | ||||||
|     compile 'javax.mail:javax.mail-api:1.6.2' |     compile 'javax.mail:javax.mail-api:1.6.2' | ||||||
|  |     compile 'com.sun.mail:javax.mail:1.6.2' | ||||||
|  |  | ||||||
|     // Google Firebase Authentication backend |     // Google Firebase Authentication backend | ||||||
|     compile 'com.google.firebase:firebase-admin:5.3.0' |     compile 'com.google.firebase:firebase-admin:5.3.0' | ||||||
|  |  | ||||||
|     // ORMLite |  | ||||||
|     compile 'com.j256.ormlite:ormlite-jdbc:5.0' |  | ||||||
|  |  | ||||||
|     // Connection Pool |     // Connection Pool | ||||||
|     compile 'com.mchange:c3p0:0.9.5.2' |     compile 'com.mchange:c3p0:0.9.5.4' | ||||||
|  |  | ||||||
|     // SQLite |     // SQLite | ||||||
|     compile 'org.xerial:sqlite-jdbc:3.20.0' |     compile 'org.xerial:sqlite-jdbc:3.28.0' | ||||||
|  |  | ||||||
|     // PostgreSQL |     // PostgreSQL | ||||||
|     compile 'org.postgresql:postgresql:42.1.4' |     compile 'org.postgresql:postgresql:42.2.6' | ||||||
|  |  | ||||||
|     // MariaDB/MySQL |     // MariaDB/MySQL | ||||||
|     compile 'org.mariadb.jdbc:mariadb-java-client:2.1.2' |     compile 'org.mariadb.jdbc:mariadb-java-client:2.4.2' | ||||||
|  |  | ||||||
|     // Twilio SDK for SMS |     // Twilio SDK for SMS | ||||||
|     compile 'com.twilio.sdk:twilio:7.14.5' |     compile 'com.twilio.sdk:twilio:7.40.1' | ||||||
|  |  | ||||||
|     // SendGrid SDK to send emails from GCE |     // SendGrid SDK to send emails from GCE | ||||||
|     compile 'com.sendgrid:sendgrid-java:2.2.2' |     compile 'com.sendgrid:sendgrid-java:2.2.2' | ||||||
|  |  | ||||||
|     // ZT-Exec for exec identity store |     // ZT-Exec for exec identity store | ||||||
|     compile 'org.zeroturnaround:zt-exec:1.10' |     compile 'org.zeroturnaround:zt-exec:1.11' | ||||||
|  |  | ||||||
|     testCompile 'junit:junit:4.12' |     // HTTP server | ||||||
|     testCompile 'com.github.tomakehurst:wiremock:2.8.0' |     compile 'io.undertow:undertow-core:2.0.22.Final' | ||||||
|  |  | ||||||
|  |     // Command parser for AS interface | ||||||
|  |     implementation 'commons-cli:commons-cli:1.4' | ||||||
|  |  | ||||||
|  |     testCompile 'junit:junit:4.13-beta-3' | ||||||
|  |     testCompile 'com.github.tomakehurst:wiremock:2.24.0' | ||||||
|  |     testCompile 'com.unboundid:unboundid-ldapsdk:4.0.11' | ||||||
|  |     testCompile 'com.icegreen:greenmail:1.5.10' | ||||||
| } | } | ||||||
|  |  | ||||||
| springBoot { | jar { | ||||||
|     executable = true |     manifest { | ||||||
|  |         attributes( | ||||||
|     embeddedLaunchScriptProperties = [ |                 'Implementation-Version': ma1sdVersion() | ||||||
|             confFolder: "/etc/default" |         ) | ||||||
|     ] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| processResources { |  | ||||||
|     doLast { |  | ||||||
|         copy { |  | ||||||
|             from('build/resources/main/application.yaml') { |  | ||||||
|                 rename 'application.yaml', 'mxisd.yaml' |  | ||||||
|             } |  | ||||||
|             into 'build/resources/main' |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| task buildDeb(dependsOn: build) { | shadowJar { | ||||||
|  |     baseName = project.name | ||||||
|  |     classifier = null | ||||||
|  |     version = null | ||||||
|  | } | ||||||
|  |  | ||||||
|  | task debBuild(dependsOn: shadowJar) { | ||||||
|     doLast { |     doLast { | ||||||
|         def v = mxisdVersion() |         String debVersion = ma1sdVersion() | ||||||
|         println "Version for package: ${v}" |         println "Version for package: ${debVersion}" | ||||||
|         mkdir distDir |         mkdir distDir | ||||||
|         mkdir debBuildBasePath |         mkdir debBuildBasePath | ||||||
|         mkdir "${debBuildBasePath}/DEBIAN" |         mkdir debBuildDebianPath | ||||||
|         mkdir debBuildBinPath |         mkdir debBuildBinPath | ||||||
|         mkdir debBuildConfPath |         mkdir debBuildConfPath | ||||||
|         mkdir debBuildDataPath |         mkdir debBuildDataPath | ||||||
|         mkdir debBuildSystemdPath |         mkdir debBuildSystemdPath | ||||||
|  |  | ||||||
|         copy { |         copy { | ||||||
|             from "${project.buildDir}/libs/mxisd.jar" |             from "${project.buildDir}/libs/ma1sd.jar" | ||||||
|             into debBuildBinPath |             into debBuildBinPath | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         ant.chmod( |         copy { | ||||||
|                 file: "${debBuildBinPath}/mxisd.jar", |             from "${project.file("src/script/" + debStartScriptFilename)}" | ||||||
|                 perm: 'a+x' |             into debBuildBinPath | ||||||
|         ) |         } | ||||||
|  |  | ||||||
|         copy { |         copy { | ||||||
|             from(project.file(confFileName)) { |             from(project.file(confFileName)) { | ||||||
| @@ -189,16 +202,16 @@ task buildDeb(dependsOn: build) { | |||||||
|             into debBuildConfPath |             into debBuildConfPath | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         ant.replaceregexp( |         ant.replaceregexp( // FIXME adapt to new config format | ||||||
|                 file: "${debBuildConfPath}/${debConfFileName}", |                 file: "${debBuildConfPath}/${debConfFileName}", | ||||||
|                 match: "key.path:(.*)", |                 match: "key:\\R  path:(.*)", | ||||||
|                 replace: "key.path: '${debDataPath}/signing.key'" |                 replace: "key:\n  path: '${debDataPath}/keys'" | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         ant.replaceregexp( |         ant.replaceregexp( // FIXME adapt to new config format | ||||||
|                 file: "${debBuildConfPath}/${debConfFileName}", |                 file: "${debBuildConfPath}/${debConfFileName}", | ||||||
|                 match: "storage.provider.sqlite.database:(.*)", |                 match: "storage:\\R  provider:\\R    sqlite:\\R      database:(.*)", | ||||||
|                 replace: "storage.provider.sqlite.database: '${debDataPath}/mxisd.db'" |                 replace: "storage:\n  provider:\n    sqlite:\n      database: '${debDataPath}/store.db'" | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         copy { |         copy { | ||||||
| @@ -209,7 +222,7 @@ task buildDeb(dependsOn: build) { | |||||||
|         ant.replace( |         ant.replace( | ||||||
|                 file: "${debBuildDebianPath}/control", |                 file: "${debBuildDebianPath}/control", | ||||||
|                 token: 'Version: 0', |                 token: 'Version: 0', | ||||||
|                 value: "Version: ${v}" |                 value: "Version: ${debVersion}" | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         ant.replace( |         ant.replace( | ||||||
| @@ -218,6 +231,12 @@ task buildDeb(dependsOn: build) { | |||||||
|                 value: debDataPath |                 value: debDataPath | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |         ant.replace( | ||||||
|  |                 file: "${debBuildDebianPath}/postinst", | ||||||
|  |                 token: '%DEB_CONF_FILE%', | ||||||
|  |                 value: "${debConfPath}/ma1sd.yaml" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|         ant.chmod( |         ant.chmod( | ||||||
|                 file: "${debBuildDebianPath}/postinst", |                 file: "${debBuildDebianPath}/postinst", | ||||||
|                 perm: 'a+x' |                 perm: 'a+x' | ||||||
| @@ -229,7 +248,7 @@ task buildDeb(dependsOn: build) { | |||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         copy { |         copy { | ||||||
|             from "${project.file('src/systemd/mxisd.service')}" |             from "${project.file('src/systemd/ma1sd.service')}" | ||||||
|             into debBuildSystemdPath |             into debBuildSystemdPath | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -245,7 +264,7 @@ task buildDeb(dependsOn: build) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| task dockerBuild(type: Exec, dependsOn: build) { | task dockerBuild(type: Exec, dependsOn: shadowJar) { | ||||||
|     commandLine 'docker', 'build', '-t', dockerImageTag, project.rootDir |     commandLine 'docker', 'build', '-t', dockerImageTag, project.rootDir | ||||||
|  |  | ||||||
|     doLast { |     doLast { | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| - Installation | - Installation | ||||||
|   - [Debian package](install/debian.md) |   - [Debian package](install/debian.md) | ||||||
|   - [ArchLinux](install/archlinux.md) |   - [ArchLinux](install/archlinux.md) | ||||||
|  |   - [NixOS](install/nixos.md) | ||||||
|   - [Docker](install/docker.md) |   - [Docker](install/docker.md) | ||||||
|   - [From source](install/source.md) |   - [From source](install/source.md) | ||||||
| - [Architecture overview](architecture.md) | - [Architecture overview](architecture.md) | ||||||
| @@ -22,4 +23,4 @@ | |||||||
|     - [SendGrid](threepids/notification/sendgrid-handler.md) |     - [SendGrid](threepids/notification/sendgrid-handler.md) | ||||||
| - [Sessions](threepids/session/session.md) | - [Sessions](threepids/session/session.md) | ||||||
|   - [Views](threepids/session/session-views.md) |   - [Views](threepids/session/session-views.md) | ||||||
| - [FAQ](faq.md) | - [FAQ](faq.md) | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| theme: jekyll-theme-cayman | theme: jekyll-theme-hacker | ||||||
| @@ -16,7 +16,7 @@ TCP 443 | |||||||
|           +<---------------------------------<+ |           +<---------------------------------<+ | ||||||
|           | |           | | ||||||
|           |   +-------------------+ |           |   +-------------------+ | ||||||
|  TCP 8090 +-> | mxisd             | |  TCP 8090 +-> | ma1sd             | | ||||||
|               |                   | |               |                   | | ||||||
|               | - Profile's 3PIDs | |               | - Profile's 3PIDs | | ||||||
|               | - 3PID Invites    | |               | - 3PID Invites    | | ||||||
| @@ -25,7 +25,7 @@ TCP 443 | |||||||
|              TCP 443 |              TCP 443 | ||||||
|                 |  +------------------------+ |                 |  +------------------------+ | ||||||
|                 |  | Remote Federated       | |                 |  | Remote Federated       | | ||||||
|                 |  | mxisd servers          | |                 |  | ma1sd servers          | | ||||||
|                 |  |                        | |                 |  |                        | | ||||||
|                 +--> - 3PID Invites         | |                 +--> - 3PID Invites         | | ||||||
|                    +------------------------+ |                    +------------------------+ | ||||||
|   | |||||||
| @@ -12,30 +12,31 @@ | |||||||
|  |  | ||||||
| ### Build | ### Build | ||||||
| ```bash | ```bash | ||||||
| git clone https://github.com/kamax-matrix/mxisd.git | git clone https://github.com/ma1uta/ma1sd.git | ||||||
| cd mxisd | cd ma1sd | ||||||
| ./gradlew build | ./gradlew build | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Create a new configuration file by coping `application.example.yaml` to `application.yaml` and edit to your needs.   | Create a new configuration file by coping `ma1sd.example.yaml` to `ma1sd.yaml` and edit to your needs.   | ||||||
| For advanced configuration, see the [Configure section](configure.md).   | For advanced configuration, see the [Configure section](configure.md). | ||||||
| **NOTE**: `application.yaml` is also called `mxisd.yaml` in some specific installations. |  | ||||||
|  |  | ||||||
| Start the server in foreground to validate the build and configuration: | Start the server in foreground to validate the build and configuration: | ||||||
| ```bash | ```bash | ||||||
| java -jar build/libs/mxisd.jar | java -jar build/libs/ma1sd.jar | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Ensure the signing key is available: | Ensure the signing key is available: | ||||||
| ```bash | ```bash | ||||||
| $ curl 'http://localhost:8090/_matrix/identity/api/v1/pubkey/ed25519:0' | $ curl 'http://localhost:8090/_matrix/identity/api/v1/pubkey/ed25519:0' | ||||||
|  |  | ||||||
| {"public_key":"..."} | {"public_key":"..."} | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Test basic recursive lookup (requires Internet connection with access to TCP 443): | Test basic recursive lookup (requires Internet connection with access to TCP 443): | ||||||
| ```bash | ```bash | ||||||
| $ curl 'http://localhost:8090/_matrix/identity/api/v1/lookup?medium=email&address=mxisd-federation-test@kamax.io' | $ curl 'http://localhost:8090/_matrix/identity/api/v1/lookup?medium=email&address=ma1sd-federation-test@kamax.io' | ||||||
| {"address":"mxisd-federation-test@kamax.io","medium":"email","mxid":"@mxisd-lookup-test:kamax.io",...} |  | ||||||
|  | {"address":"ma1sd-federation-test@kamax.io","medium":"email","mxid":"@ma1sd-lookup-test:kamax.io",...} | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| If you enabled LDAP, you can also validate your config with a similar request after replacing the `address` value with | If you enabled LDAP, you can also validate your config with a similar request after replacing the `address` value with | ||||||
| @@ -55,19 +56,19 @@ Requirements: | |||||||
| - fakeroot | - fakeroot | ||||||
| - dpkg-deb | - dpkg-deb | ||||||
|  |  | ||||||
| [Build mxisd](#build) then: | [Build ma1sd](#build) then: | ||||||
| ```bash | ```bash | ||||||
| ./gradlew buildDeb  | ./gradlew debBuild | ||||||
| ``` | ``` | ||||||
| You will find the debian package in `build/dist`.   | You will find the debian package in `build/dist`.   | ||||||
| Then follow the instruction in the [Debian package](install/debian.md) document. | Then follow the instruction in the [Debian package](install/debian.md) document. | ||||||
|  |  | ||||||
| ## Docker image | ## Docker image | ||||||
| [Build mxisd](#build) then: | [Build ma1sd](#build) then: | ||||||
| ```bash | ```bash | ||||||
| ./gradlew dockerBuild | ./gradlew dockerBuild | ||||||
| ``` | ``` | ||||||
| Then follow the instructions in the [Docker install](install/docker.md#configure) document. | Then follow the instructions in the [Docker install](install/docker.md#configure) document. | ||||||
|  |  | ||||||
| ## Next steps | ## Next steps | ||||||
| - [Integrate with your infrastructure](getting-started.md#integrate) | - [Integrate with your infrastructure](getting-started.md#integrate) | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| # Concepts | # Concepts | ||||||
| - [Matrix](#matrix) | - [Matrix](#matrix) | ||||||
| - [mxisd](#mxisd) | - [ma1sd](#ma1sd) | ||||||
|  |  | ||||||
| ## Matrix | ## Matrix | ||||||
| The following concepts are part of the Matrix ecosystem and specification. | The following concepts are part of the Matrix ecosystem and specification. | ||||||
| @@ -15,7 +15,7 @@ A 3PID is a globally unique canonical identifier which is made of: | |||||||
| - Medium, which describes what network it belongs to (Email, Phone, Twitter, Discord, etc.) | - Medium, which describes what network it belongs to (Email, Phone, Twitter, Discord, etc.) | ||||||
| - Address, the actual value people typically use on a daily basis. | - Address, the actual value people typically use on a daily basis. | ||||||
|  |  | ||||||
| mxisd core mission is to map those identifiers to Matrix User IDs. | ma1sd core mission is to map those identifiers to Matrix User IDs. | ||||||
|  |  | ||||||
| ### Homeserver | ### Homeserver | ||||||
| Where a user **account and data** are stored. | Where a user **account and data** are stored. | ||||||
| @@ -34,10 +34,10 @@ An Identity server: | |||||||
| ### 3PID session | ### 3PID session | ||||||
| The fact to validate a 3PID (email, phone number, etc.) via the introduction of a token which was sent to the 3PID address. | The fact to validate a 3PID (email, phone number, etc.) via the introduction of a token which was sent to the 3PID address. | ||||||
|  |  | ||||||
| ## mxisd | ## ma1sd | ||||||
| The following concepts are specific to mxisd. | The following concepts are specific to ma1sd. | ||||||
|  |  | ||||||
| ### Identity store | ### Identity store | ||||||
| Where your user accounts and 3PID mappings are stored. | Where your user accounts and 3PID mappings are stored. | ||||||
|  |  | ||||||
| mxisd itself **DOES NOT STORE** user accounts or 3PID mappings. | ma1sd itself **DOES NOT STORE** user accounts or 3PID mappings. | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| # Configuration | # Configuration | ||||||
| - [Concepts](#concepts) | - [Concepts](#concepts) | ||||||
|   - [Syntax](#syntax) |   - [Syntax](#syntax) | ||||||
|   - [Variables](#variables) |  | ||||||
| - [Matrix](#matrix) | - [Matrix](#matrix) | ||||||
| - [Server](#server) | - [Server](#server) | ||||||
| - [Storage](#storage) | - [Storage](#storage) | ||||||
| @@ -11,36 +10,15 @@ | |||||||
|  |  | ||||||
| ## Concepts | ## Concepts | ||||||
| ### Syntax | ### Syntax | ||||||
| The configuration file is [YAML](http://yaml.org/) based, allowing two types of syntax. | The configuration file is [YAML](http://yaml.org/) based: | ||||||
|  |  | ||||||
| Properties-like: |  | ||||||
| ```yaml |  | ||||||
| my.config.item: 'value' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Object-like: |  | ||||||
| ```yaml | ```yaml | ||||||
| my: | my: | ||||||
|   config: |   config: | ||||||
|     item: 'value' |     item: 'value' | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| These can also be combined within the same file.   |  | ||||||
| Both syntax will be used interchangeably in these documents. |  | ||||||
|  |  | ||||||
| ### Variables |  | ||||||
| It is possible to copy the value of a configuration item into another using the syntax `${config.key.item}`.   |  | ||||||
| Example that will copy the value of `matrix.domain` into `server.name`: |  | ||||||
| ```yaml |  | ||||||
| matrix: |  | ||||||
|   domain: 'example.org' |  | ||||||
|  |  | ||||||
| server: |  | ||||||
|   name: '${matrix.domain}' |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| **WARNING:** mxisd might overwrite/adapt some values during launch. Those changes will not be reflected into copied keys. |  | ||||||
|  |  | ||||||
|  | When referencing keys in all documents, a property-like shorthand will be used. The shorthand for the above example would be `my.config.item` | ||||||
|  |  | ||||||
| ## Matrix | ## Matrix | ||||||
| `matrix.domain` | `matrix.domain` | ||||||
| @@ -53,17 +31,27 @@ Namespace to create arbitrary list of Identity servers, usable in other parts of | |||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| matrix.identity.servers: | matrix: | ||||||
|   myOtherServers: |   identity: | ||||||
|     - 'https://other1.example.org' |     servers: | ||||||
|     - 'https://other2.example.org' |       myOtherServers: | ||||||
|  |         - 'https://other1.example.org' | ||||||
|  |         - 'https://other2.example.org' | ||||||
| ``` | ``` | ||||||
| Create a list under the label `root` containing a single Identity server, `https://matrix.org` | Create a list under the label `myOtherServers` containing two Identity servers: `https://other1.example.org` and `https://other2.example.org`. | ||||||
|  |  | ||||||
| ## Server | ## Server | ||||||
| - `server.name`: Public hostname of mxisd, if different from the Matrix domain. | - `server.name`: Public hostname of ma1sd, if different from the Matrix domain. | ||||||
| - `server.port`: HTTP port to listen on (unencrypted) | - `server.port`: HTTP port to listen on (unencrypted) | ||||||
| - `server.publicUrl`: Defaults to `https://${server.name}` | - `server.publicUrl`: Defaults to `https://{server.name}` | ||||||
|  |  | ||||||
|  | ## Unbind (MSC1915) | ||||||
|  | - `session.policy.unbind.enabled`: Enable or disable unbind functionality (MSC1915). (Defaults to true). | ||||||
|  |  | ||||||
|  | *Warning*: Unbind check incoming request by two ways: | ||||||
|  | - session validation. | ||||||
|  | - request signature via `X-Matrix` header and uses `server.publicUrl` property to construct the signing json; | ||||||
|  | Commonly the `server.publicUrl` should be the same value as the `trusted_third_party_id_servers` property in the synapse config. | ||||||
|  |  | ||||||
| ## Storage | ## Storage | ||||||
| ### SQLite | ### SQLite | ||||||
| @@ -82,19 +70,23 @@ See the dedicated documents: | |||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| notification.handler.email: 'sendgrid' | notification: | ||||||
| notification.handler.msisdn: 'raw' |   handler: | ||||||
|  |     email: 'sendgrid' | ||||||
|  |     msisdn: 'raw' | ||||||
| ``` | ``` | ||||||
| - Emails notifications would use the `sendgrid` handler, which define its own configuration under `notification.handlers.sendgrid` | - Emails notifications would use the `sendgrid` handler, which define its own configuration under `notification.handlers.sendgrid` | ||||||
| - Phone notification would use the `raw` handler, basic default built-in handler of mxisd | - Phone notification would use the `raw` handler, basic default built-in handler in ma1sd | ||||||
|  |  | ||||||
| ### Handlers | ### Handlers | ||||||
| - `notification.handers.<handler ID>`: Handler-specific configuration for the given handler ID. Repeatable. | - `notification.handers.<handler ID>`: Handler-specific configuration for the given handler ID. Repeatable. | ||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| notification.handlers.raw: ... | notification: | ||||||
| notification.handlers.sendgrid: ... |   handlers: | ||||||
|  |     raw: ... | ||||||
|  |     sendgrid: ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Built-in: | Built-in: | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								docs/faq.md
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								docs/faq.md
									
									
									
									
									
								
							| @@ -10,23 +10,32 @@ first basic setup running which relies on you reading the documentation in the r | |||||||
| - [Identity stores](stores/README.md) you wish to fetch data from. | - [Identity stores](stores/README.md) you wish to fetch data from. | ||||||
| - [Features](features) you are interested in that will use your Identity store(s) data. | - [Features](features) you are interested in that will use your Identity store(s) data. | ||||||
|  |  | ||||||
| **IMPORTANT**: Be aware that mxisd tries to fit within the current protocol and existing products and basic understanding | **IMPORTANT**: Be aware that ma1sd tries to fit within the current protocol and existing products and basic understanding | ||||||
| of the Matrix protocol is required for some advanced features. | of the Matrix protocol is required for some advanced features. | ||||||
|  |  | ||||||
| If all fails, come over to [the project room](https://matrix.to/#/#mxisd:kamax.io) and we'll do our best to get you | If all fails, come over to [the project room](https://matrix.to/#/#ma1sd:ru-matrix.org) and we'll do our best to get you | ||||||
| started and answer questions you might have. | started and answer questions you might have. | ||||||
|  |  | ||||||
| ### Do I need to use mxisd if I run a Homeserver? | ### What kind of setup is ma1sd really designed for? | ||||||
|  | ma1sd is primarily designed for setups that: | ||||||
|  | - [Care for their privacy](https://github.com/kamax-matrix/ma1sd/wiki/ma1sd-and-your-privacy) | ||||||
|  | - Have their own [domains](https://en.wikipedia.org/wiki/Domain_name) | ||||||
|  | - Use those domains for their email addresses and all other services | ||||||
|  | - Already have an [Identity store](stores/README.md), typically [LDAP-based](stores/ldap.md). | ||||||
|  |  | ||||||
|  | If you meet all the conditions, then you are the prime use case we designed ma1sd for.  | ||||||
|  |  | ||||||
|  | If you meet some of the conditions, but not all, ma1sd will still be a good fit for you but you won't fully enjoy all its | ||||||
|  | features. | ||||||
|  |  | ||||||
|  | ### Do I need to use ma1sd if I run a Homeserver? | ||||||
| No, but it is strongly recommended, even if you don't use any Identity store or integration. | No, but it is strongly recommended, even if you don't use any Identity store or integration. | ||||||
|  |  | ||||||
| In its default configuration, mxisd uses other federated public servers when performing queries.   | In its default configuration, ma1sd uses other federated public servers when performing queries.   | ||||||
| It can also [be configured](features/identity.md#lookups) to use the central matrix.org servers, giving you access to at | It can also [be configured](features/identity.md#lookups) to use the central matrix.org servers, giving you access to at | ||||||
| least the same information as if you were not running it. | least the same information as if you were not running it. | ||||||
|  |  | ||||||
| It will also give your users a choice to make their 3PIDs available publicly, ensuring they are made aware of the | So ma1sd is like your gatekeeper and guardian angel. It does not change what you already know, just adds some nice | ||||||
| privacy consequences, which is not the case with the central Matrix.org servers. |  | ||||||
|  |  | ||||||
| So mxisd is like your gatekeeper and guardian angel. It does not change what you already know, just adds some nice |  | ||||||
| simple features on top of it. | simple features on top of it. | ||||||
|  |  | ||||||
| ### I'm not sure I understand what an "Identity server" is supposed to be or do... | ### I'm not sure I understand what an "Identity server" is supposed to be or do... | ||||||
| @@ -35,27 +44,28 @@ what they want to do with that part of the ecosystem. Therefore, "Identity" is c | |||||||
| Given the scope of the current Identity Service API, it would be best called "Invitation service". | Given the scope of the current Identity Service API, it would be best called "Invitation service". | ||||||
|  |  | ||||||
| Because the current scope is so limited and no integration is done with the Homeserver, there was a big lack of features | Because the current scope is so limited and no integration is done with the Homeserver, there was a big lack of features | ||||||
| for groups/corporations/organisation. This is where mxisd comes in. | for groups/corporations/organisation. This is where ma1sd comes in. | ||||||
|  |  | ||||||
| mxisd implements the Identity Service API and also a set of features which are expected by regular users, truly living | ma1sd implements the Identity Service API and also a set of features which are expected by regular users, truly living | ||||||
| up to its "Identity server" name. | up to its "Identity server" name. | ||||||
|  |  | ||||||
| ### Can I migrate my existing account on another Matrix server with mxisd? | ### Can I migrate my existing account on another Matrix server with ma1sd? | ||||||
| No. | No. | ||||||
|  |  | ||||||
| Accounts cannot currently migrate/move from one server to another.   | Accounts cannot currently migrate/move from one server to another.   | ||||||
| See a [brief explanation document](concepts.md) about Matrix and mxisd concepts and vocabulary. | See a [brief explanation document](concepts.md) about Matrix and ma1sd concepts and vocabulary. | ||||||
|  |  | ||||||
| ### I already use the synapse LDAP3 auth provider. Why should I care about mxisd? | ### I already use the synapse LDAP3 auth provider. Why should I care about ma1sd? | ||||||
| The [synapse LDAP3 auth provider](https://github.com/matrix-org/matrix-synapse-ldap3) is not longer maintained and | The [synapse LDAP3 auth provider](https://github.com/matrix-org/matrix-synapse-ldap3) is not longer maintained despite | ||||||
| only handles on specific flow: validate credentials at login. | saying so and only handles on specific flow: validate credentials at login. | ||||||
|  |  | ||||||
| It does not: | It does not: | ||||||
| - Auto-provision user profiles | - Auto-provision user profiles | ||||||
| - Integrate with Identity management | - Integrate with Identity management | ||||||
| - Integrate with Directory searches | - Integrate with Directory searches | ||||||
|  | - Integrate with Profile data | ||||||
|  |  | ||||||
| mxisd is a replacement and enhancement of it, offering coherent results in all areas, which the LDAP3 auth provider | ma1sd is a replacement and enhancement of it, offering coherent results in all areas, which the LDAP3 auth provider | ||||||
| does not. | does not. | ||||||
|  |  | ||||||
| ### Sydent is the official Identity server implementation of the Matrix team. Why not use that? | ### Sydent is the official Identity server implementation of the Matrix team. Why not use that? | ||||||
| @@ -66,22 +76,22 @@ You can, but [sydent](https://github.com/matrix-org/sydent): | |||||||
| - forces you to duplicate all your identity data, so people can be found by 3PIDs | - forces you to duplicate all your identity data, so people can be found by 3PIDs | ||||||
| - forces users to enter all their emails and phone numbers manually in their profile | - forces users to enter all their emails and phone numbers manually in their profile | ||||||
|  |  | ||||||
| So really, you should go with mxisd. | So really, you should go with ma1sd. | ||||||
|  |  | ||||||
| ### Will I loose access to the central Matrix.org/Vector.im Identity data if I use mxisd? | ### Will I loose access to the central Matrix.org/Vector.im Identity data if I use ma1sd? | ||||||
| No. | No. | ||||||
|  |  | ||||||
| In its default configuration, mxisd does not talk to the central Identity server matrix.org to avoid leaking your private | In its default configuration, ma1sd does not talk to the central Identity server matrix.org to avoid leaking your private | ||||||
| data and those of people you might know. | data and those of people you might know. | ||||||
|  |  | ||||||
| mxisd [can be configured](features/identity.md#lookups) to talk to the central Identity servers if you wish. | [You can configure it](features/identity.md#lookups) to talk to the central Identity servers if you wish. | ||||||
|  |  | ||||||
| ### So mxisd is just a big hack! I don't want to use non-official features! | ### So ma1sd is just a big hack! I don't want to use non-official features! | ||||||
| mxisd primary concerns are your privacy and to always be compatible with the Matrix ecosystem and the Identity service API.   | ma1sd primary concerns are your privacy and to always be compatible with the Matrix ecosystem and the Identity service API.   | ||||||
| Whenever the API will be updated and/or enhanced, mxisd will follow, remaining 100% compatible with the ecosystem. | Whenever the API will be updated and/or enhanced, ma1sd will follow, remaining 100% compatible with the ecosystem. | ||||||
|  |  | ||||||
| ### Should I use mxisd if I don't host my own Homeserver? | ### Should I use ma1sd if I don't host my own Homeserver? | ||||||
| No. | No. | ||||||
|  |  | ||||||
| It is possible, but it is not supported and the scope of features will be extremely limited. | It is possible, but it is not supported and the scope of features will be extremely limited. | ||||||
| Please consider hosting your own Homeserver and using mxisd alongside it. | Please consider hosting your own Homeserver and using ma1sd alongside it. | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
| - [Basic](#basic) | - [Basic](#basic) | ||||||
|   - [Overview](#overview) |   - [Overview](#overview) | ||||||
|   - [synapse](#synapse) |   - [synapse](#synapse) | ||||||
|   - [mxisd](#mxisd) |   - [ma1sd](#ma1sd) | ||||||
|   - [Validate](#validate) |   - [Validate](#validate) | ||||||
|   - [Next steps](#next-steps) |   - [Next steps](#next-steps) | ||||||
|     - [Profile auto-fil](#profile-auto-fill) |     - [Profile auto-fil](#profile-auto-fill) | ||||||
| @@ -16,15 +16,15 @@ | |||||||
|     - [DNS Overwrite](#dns-overwrite) |     - [DNS Overwrite](#dns-overwrite) | ||||||
|  |  | ||||||
| ## Description | ## Description | ||||||
| Authentication is an enhanced feature of mxisd to ensure coherent and centralized identity management.   | Authentication is an enhanced feature of ma1sd to ensure coherent and centralized identity management.   | ||||||
| It allows to use Identity stores configured in mxisd to authenticate users on your Homeserver. | It allows to use Identity stores configured in ma1sd to authenticate users on your Homeserver. | ||||||
|  |  | ||||||
| Authentication is divided into two parts: | Authentication is divided into two parts: | ||||||
| - [Basic](#basic): authenticate with a regular username. | - [Basic](#basic): authenticate with a regular username. | ||||||
| - [Advanced](#advanced): same as basic with extra ability to authenticate using a 3PID. | - [Advanced](#advanced): same as basic with extra abilities like authenticate using a 3PID or do username rewrite. | ||||||
|  |  | ||||||
| ## Basic | ## Basic | ||||||
| Authentication by username is possible by linking synapse and mxisd together using a specific module for synapse, also | Authentication by username is possible by linking synapse and ma1sd together using a specific module for synapse, also | ||||||
| known as password provider. | known as password provider. | ||||||
|  |  | ||||||
| ### Overview | ### Overview | ||||||
| @@ -33,7 +33,7 @@ An overview of the Basic Authentication process: | |||||||
|                                                                                     Identity stores |                                                                                     Identity stores | ||||||
|  Client                                                                             +------+ |  Client                                                                             +------+ | ||||||
|    |                                            +-------------------------+    +--> | LDAP | |    |                                            +-------------------------+    +--> | LDAP | | ||||||
|    |   +---------------+  /_matrix/identity     | mxisd                   |    |    +------+ |    |   +---------------+  /_matrix/identity     | ma1sd                   |    |    +------+ | ||||||
|    +-> | Reverse proxy | >------------------+   |                         |    | |    +-> | Reverse proxy | >------------------+   |                         |    | | ||||||
|        +--|------------+                    |   |                         |    |    +--------+ |        +--|------------+                    |   |                         |    |    +--------+ | ||||||
|           |                                 +-----> Check ID stores     >------+--> | SQL DB | |           |                                 +-----> Check ID stores     >------+--> | SQL DB | | ||||||
| @@ -49,20 +49,20 @@ An overview of the Basic Authentication process: | |||||||
|               |   user profiles          |    If valid credentials and supported by Identity store(s) |               |   user profiles          |    If valid credentials and supported by Identity store(s) | ||||||
|               +--------------------------+ |               +--------------------------+ | ||||||
| ``` | ``` | ||||||
| Performed on [synapse with REST auth module](https://github.com/kamax-io/matrix-synapse-rest-auth/blob/master/README.md) | Performed on [synapse with REST auth module](https://github.com/ma1uta/matrix-synapse-rest-password-provider/blob/master/README.md) | ||||||
|  |  | ||||||
| ### Synapse | ### Synapse | ||||||
| - Install the [password provider](https://github.com/kamax-io/matrix-synapse-rest-auth) | - Install the [password provider](https://github.com/ma1uta/matrix-synapse-rest-password-provider) | ||||||
| - Edit your **synapse** configuration: | - Edit your **synapse** configuration: | ||||||
|   - As described by the auth module documentation |   - As described by the auth module documentation | ||||||
|   - Set `endpoint` to `http://mxisdAddress:8090` - Replace `mxisdAddress` by an IP/host name that provides a direct |   - Set `endpoint` to `http://ma1sdAddress:8090` - Replace `ma1sdAddress` by an IP/host name that provides a direct | ||||||
|   connection to mxisd.   |   connection to ma1sd.   | ||||||
|   This **MUST NOT** be a public address, and SHOULD NOT go through a reverse proxy. |   This **MUST NOT** be a public address, and SHOULD NOT go through a reverse proxy. | ||||||
| - Restart synapse | - Restart synapse | ||||||
|  |  | ||||||
| ### mxisd | ### ma1sd | ||||||
| - Configure and enable at least one [Identity store](../stores/README.md) | - Configure and enable at least one [Identity store](../stores/README.md) | ||||||
| - Restart mxisd | - Restart ma1sd | ||||||
|  |  | ||||||
| ### Validate | ### Validate | ||||||
| Login on the Homeserver using credentials present in one of your Identity stores. | Login on the Homeserver using credentials present in one of your Identity stores. | ||||||
| @@ -74,7 +74,15 @@ See your Identity store [documentation](../stores/README.md) on how to enable th | |||||||
|  |  | ||||||
|  |  | ||||||
| ## Advanced | ## Advanced | ||||||
| The Authentication feature allows users to login to their Homeserver by using their 3PIDs in a configured Identity store. | The Authentication feature allows users to: | ||||||
|  | - Rewrite usernames matching a pattern to be mapped to another username via a 3PID. | ||||||
|  | - login to their Homeserver by using their 3PIDs in a configured Identity store. | ||||||
|  |  | ||||||
|  | This feature also allows to work around the following issues: | ||||||
|  | - Lowercase all usernames for synapse, allowing case-insensitive login | ||||||
|  | - Unable to login on synapse if username is numerical | ||||||
|  | - Any generic transformation of username prior to sending to synapse, bypassing the restriction that password providers | ||||||
|  | cannot change the localpart being authenticated. | ||||||
|  |  | ||||||
| ### Overview | ### Overview | ||||||
| This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/login` as depicted below: | This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/login` as depicted below: | ||||||
| @@ -85,7 +93,7 @@ This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/lo | |||||||
|             |                            |     Step 1    +---------------------------+     Step 2 |             |                            |     Step 1    +---------------------------+     Step 2 | ||||||
|             |                            |               |                           | |             |                            |               |                           | | ||||||
| Client+---->| /_matrix/client/r0/login +---------------->|                           | Look up address  +---------+ | Client+---->| /_matrix/client/r0/login +---------------->|                           | Look up address  +---------+ | ||||||
|             |                      ^     |               |  mxisd - Identity server  +----------------->| Backend | |             |                      ^     |               |  ma1sd - Identity server  +----------------->| Backend | | ||||||
|             |                      |     |               |                           |                  +---------+ |             |                      |     |               |                           |                  +---------+ | ||||||
|             | /_matrix/* +--+      +---------------------+                           | |             | /_matrix/* +--+      +---------------------+                           | | ||||||
|             |               |            |               +---------------+-----------+ |             |               |            |               +---------------+-----------+ | ||||||
| @@ -102,17 +110,17 @@ Client+---->| /_matrix/client/r0/login +---------------->| | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Steps of user authentication using a 3PID: | Steps of user authentication using a 3PID: | ||||||
| 1. The intercepted login request is directly sent to mxisd instead of the Homeserver. | 1. The intercepted login request is directly sent to ma1sd instead of the Homeserver. | ||||||
| 2. Identity stores are queried for a matching user identity in order to modify the request to use the user name. | 2. Identity stores are queried for a matching user identity in order to modify the request to use the user name. | ||||||
| 3. The Homeserver, from which the request was intercepted, is queried using the request at previous step. | 3. The Homeserver, from which the request was intercepted, is queried using the request at previous step. | ||||||
|    Its address is resolved using the DNS Overwrite feature to reach its internal address on a non-encrypted port. |    Its address is resolved using the DNS Overwrite feature to reach its internal address on a non-encrypted port. | ||||||
| 4. The response from the Homeserver is sent back to the client, believing it was the HS which directly answered. | 4. The response from the Homeserver is sent back to the client, believing it was the HS which directly answered. | ||||||
|  |  | ||||||
| ### Requirements | ### Requirements | ||||||
| - [Basic Authentication configured and working](#basic) |  | ||||||
| - Reverse proxy setup |  | ||||||
| - Homeserver |  | ||||||
| - Compatible [Identity store](../stores/README.md) | - Compatible [Identity store](../stores/README.md) | ||||||
|  | - [Basic Authentication configured and working](#basic) | ||||||
|  | - Client and Homeserver using the [C2S API r0.4.x](https://matrix.org/docs/spec/client_server/r0.4.0.html) or later | ||||||
|  | - Reverse proxy setup | ||||||
|  |  | ||||||
| ### Configuration | ### Configuration | ||||||
| #### Reverse Proxy | #### Reverse Proxy | ||||||
| @@ -121,7 +129,7 @@ The specific configuration to put under the relevant `VirtualHost`: | |||||||
| ```apache | ```apache | ||||||
| ProxyPass /_matrix/client/r0/login http://localhost:8090/_matrix/client/r0/login | ProxyPass /_matrix/client/r0/login http://localhost:8090/_matrix/client/r0/login | ||||||
| ``` | ``` | ||||||
| `ProxyPreserveHost` or equivalent **must** be enabled to detect to which Homeserver mxisd should talk to when building results. | `ProxyPreserveHost` or equivalent **must** be enabled to detect to which Homeserver ma1sd should talk to when building results. | ||||||
|  |  | ||||||
| Your VirtualHost should now look similar to: | Your VirtualHost should now look similar to: | ||||||
| ```apache | ```apache | ||||||
| @@ -137,15 +145,60 @@ Your VirtualHost should now look similar to: | |||||||
| </VirtualHost> | </VirtualHost> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ##### nginx | ||||||
|  |  | ||||||
|  | The specific configuration to add under the relevant `server`: | ||||||
|  |  | ||||||
|  | ```nginx | ||||||
|  | location /_matrix/client/r0/login { | ||||||
|  |     proxy_pass http://localhost:8090; | ||||||
|  |     proxy_set_header Host $host; | ||||||
|  |     proxy_set_header X-Forwarded-For $remote_addr; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Your `server` section should now look similar to: | ||||||
|  |  | ||||||
|  | ```nginx | ||||||
|  | server { | ||||||
|  |     listen 443 ssl; | ||||||
|  |     server_name matrix.example.org; | ||||||
|  |      | ||||||
|  |     # ... | ||||||
|  |      | ||||||
|  |     location /_matrix/client/r0/login { | ||||||
|  |         proxy_pass http://localhost:8090; | ||||||
|  |         proxy_set_header Host $host; | ||||||
|  |         proxy_set_header X-Forwarded-For $remote_addr; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     location /_matrix/identity { | ||||||
|  |         proxy_pass http://localhost:8090/_matrix/identity; | ||||||
|  |         proxy_set_header Host $host; | ||||||
|  |         proxy_set_header X-Forwarded-For $remote_addr; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     location /_matrix { | ||||||
|  |         proxy_pass http://localhost:8008/_matrix; | ||||||
|  |         proxy_set_header Host $host; | ||||||
|  |         proxy_set_header X-Forwarded-For $remote_addr; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
| #### DNS Overwrite | #### DNS Overwrite | ||||||
| Just like you need to configure a reverse proxy to send client requests to mxisd, you also need to configure mxisd with |  | ||||||
|  | Just like you need to configure a reverse proxy to send client requests to ma1sd, you also need to configure ma1sd with | ||||||
| the internal IP of the Homeserver so it can talk to it directly to integrate its directory search. | the internal IP of the Homeserver so it can talk to it directly to integrate its directory search. | ||||||
|  |  | ||||||
| To do so, put the following configuration in your mxisd configuration: | To do so, put the following configuration in your ma1sd configuration: | ||||||
| ```yaml | ```yaml | ||||||
| dns.overwrite.homeserver.client: | dns: | ||||||
|   - name: 'example.org' |   overwrite: | ||||||
|     value: 'http://localhost:8008' |     homeserver: | ||||||
|  |       client: | ||||||
|  |         - name: 'example.org' | ||||||
|  |           value: 'http://localhost:8008' | ||||||
| ``` | ``` | ||||||
| `name` must be the hostname of the URL that clients use when connecting to the Homeserver. | `name` must be the hostname of the URL that clients use when connecting to the Homeserver. | ||||||
| You can use `${server.name}` to auto-populate the `value` using the `server.name` configuration option and avoid duplicating it. | You can use `${server.name}` to auto-populate the `value` using the `server.name` configuration option and avoid duplicating it. | ||||||
| @@ -153,3 +206,46 @@ In case the hostname is the same as your Matrix domain and `server.name` is not | |||||||
| `matrix.domain` and will still probably have the correct value. | `matrix.domain` and will still probably have the correct value. | ||||||
|  |  | ||||||
| `value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`. | `value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`. | ||||||
|  |  | ||||||
|  | ### Optional features | ||||||
|  |  | ||||||
|  | The following features are available after you have a working Advanced setup: | ||||||
|  |  | ||||||
|  | - Username rewrite: Allows you to rewrite the username of a regular login/pass authentication to a 3PID, that then gets resolved using the regular lookup process. Most common use case is to allow login with numerical usernames on synapse, which is not possible out of the box. | ||||||
|  |  | ||||||
|  | #### Username rewrite | ||||||
|  | In ma1sd config: | ||||||
|  | ```yaml | ||||||
|  | auth: | ||||||
|  |   rewrite: | ||||||
|  |     user: | ||||||
|  |       rules: | ||||||
|  |         - regex: <your regexp> | ||||||
|  |           medium: 'your.custom.medium.type' | ||||||
|  | ``` | ||||||
|  | `rules` takes a list of rules. Rules have two properties: | ||||||
|  | - `regexp`: The regex pattern to match. This **MUST** match the full string. See [Java regex](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) for syntax. | ||||||
|  | - `medium`: Custom 3PID type that will be used in the 3PID lookup. This can be anything you want and needs to be supported | ||||||
|  | by your Identity store config and/or code. | ||||||
|  |  | ||||||
|  | Rules are matched in listed order. | ||||||
|  |  | ||||||
|  | Common regexp patterns: | ||||||
|  | - Numerical usernames: `[0-9]+` | ||||||
|  |  | ||||||
|  | ##### LDAP Example | ||||||
|  | If your users use their numerical employee IDs, which cannot be used with synapse, you can make it work with (relevant config only): | ||||||
|  | ```yaml | ||||||
|  | auth: | ||||||
|  |   rewrite: | ||||||
|  |     user: | ||||||
|  |       rules: | ||||||
|  |         - regex: '[0-9]+' | ||||||
|  |           medium: 'kmx.employee.id' | ||||||
|  |            | ||||||
|  | ldap: | ||||||
|  |   attribute: | ||||||
|  |     threepid: | ||||||
|  |       kmx.employee.id: | ||||||
|  |         - 'ldapAttributeForEmployeeId' | ||||||
|  | ``` | ||||||
|   | |||||||
| @@ -1,20 +1,23 @@ | |||||||
| # Bridge Integration | # Bridge Integration | ||||||
| To help natural bridge integration into the regular usage of a Matrix client, mxisd provides a way for bridge to reply | To help natural bridge integration into the regular usage of a Matrix client, ma1sd provides a way for bridge to reply | ||||||
| to 3PID queries if no mapping was found, allowing seamless bridging to a network. | to 3PID queries if no mapping was found, allowing seamless bridging to a network. | ||||||
|  |  | ||||||
| This is performed by implementing a specific endpoint on the bridge to map a 3PID lookup to a virtual user. | This is performed by implementing a specific endpoint on the bridge to map a 3PID lookup to a virtual user. | ||||||
|  |  | ||||||
| **NOTE**: This document is incomplete and might be misleading. In doubt, come in our Matrix room.   | **NOTE**: This document is incomplete and might be misleading. In doubt, come in our Matrix room.   | ||||||
| You can also look at our [Email Bridge README](https://github.com/kamax-io/matrix-appservice-email#mxisd) for an example | You can also look at our [Email Bridge README](https://github.com/kamax-matrix/matrix-appservice-email#ma1sd) for an example | ||||||
| of working configuration. | of working configuration. | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| ```yaml | ```yaml | ||||||
| lookup.recursive.bridge.enabled: <boolean> | lookup: | ||||||
| lookup.recursive.bridge.recursiveOnly: <boolean> |   recursive: | ||||||
| lookup.recursive.bridge.server: <URL to the bridge endpoint for all 3PID medium> |     bridge: | ||||||
| lookup.recursive.bridge.mappings: |       enabled: <boolean> | ||||||
|   <3PID MEDIUM HERE>: <URL to dedicated bridge for that medium> |       recursiveOnly: <boolean> | ||||||
|  |       server: <URL to the bridge endpoint for all 3PID medium> | ||||||
|  |       mappings: | ||||||
|  |         <3PID MEDIUM HERE>: <URL to dedicated bridge for that medium> | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,9 +22,9 @@ By enabling this feature, you can by default: | |||||||
| - Search for users which you are not in contact with yet. Super useful for corporations who want to give Matrix access | - Search for users which you are not in contact with yet. Super useful for corporations who want to give Matrix access | ||||||
| internally, so users can just find themselves **prior** to having any common room(s) | internally, so users can just find themselves **prior** to having any common room(s) | ||||||
| - Add extra attributes of your backend to extend the search | - Add extra attributes of your backend to extend the search | ||||||
| - Include your homeserver search results to those found by mxisd | - Include your homeserver search results to those found by ma1sd | ||||||
|  |  | ||||||
| By integrating mxisd, you get the default behaviour and a bunch of extras, ensuring your users will always find each other. | By integrating ma1sd, you get the default behaviour and a bunch of extras, ensuring your users will always find each other. | ||||||
|  |  | ||||||
| ## Overview | ## Overview | ||||||
| This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/user_directory/search` like so: | This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/user_directory/search` like so: | ||||||
| @@ -33,7 +33,7 @@ This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/us | |||||||
| Client --> | Reverse proxy                                                                         Step 2 | Client --> | Reverse proxy                                                                         Step 2 | ||||||
|            |                                              Step 1    +-------------------------+ |            |                                              Step 1    +-------------------------+ | ||||||
|            |   /_matrix/client/r0/user_directory/search ----------> |                         |  Search in   +---------+ |            |   /_matrix/client/r0/user_directory/search ----------> |                         |  Search in   +---------+ | ||||||
|            |                        /\                              | mxisd - Identity server | -----------> | Backend | |            |                        /\                              | ma1sd - Identity server | -----------> | Backend | | ||||||
|            |   /_matrix/*            \----------------------------- |                         |  all users   +---------+ |            |   /_matrix/*            \----------------------------- |                         |  all users   +---------+ | ||||||
|            |        |            Step 4: Send back merged results   +-------------------------+ |            |        |            Step 4: Send back merged results   +-------------------------+ | ||||||
|            +        |                                                            | |            +        |                                                            | | ||||||
| @@ -44,7 +44,7 @@ Client --> | Reverse proxy | |||||||
|                          +------------+   /_matrix/client/r0/user_directory/search |                          +------------+   /_matrix/client/r0/user_directory/search | ||||||
| ``` | ``` | ||||||
| Steps: | Steps: | ||||||
| 1. The intercepted request is directly sent to mxisd instead of the Homeserver. | 1. The intercepted request is directly sent to ma1sd instead of the Homeserver. | ||||||
| 2. Identity stores are queried for any match on the search value sent by the client. | 2. Identity stores are queried for any match on the search value sent by the client. | ||||||
| 3. The Homeserver, from which the request was intercepted, is queried using the same request as the client. | 3. The Homeserver, from which the request was intercepted, is queried using the same request as the client. | ||||||
|    Its address is resolved using the DNS Overwrite feature to reach its internal address on a non-encrypted port. |    Its address is resolved using the DNS Overwrite feature to reach its internal address on a non-encrypted port. | ||||||
| @@ -52,7 +52,7 @@ Steps: | |||||||
| which directly answered the request. | which directly answered the request. | ||||||
|  |  | ||||||
| ## Requirements | ## Requirements | ||||||
| - Reverse proxy setup, which you should already have in place if you use mxisd | - Reverse proxy setup, which you should already have in place if you use ma1sd | ||||||
| - At least one compatible [Identity store](../stores/README.md) enabled | - At least one compatible [Identity store](../stores/README.md) enabled | ||||||
|    |    | ||||||
| ## Configuration | ## Configuration | ||||||
| @@ -62,7 +62,7 @@ The specific configuration to put under the relevant `VirtualHost`: | |||||||
| ```apache | ```apache | ||||||
| ProxyPass /_matrix/client/r0/user_directory/ http://0.0.0.0:8090/_matrix/client/r0/user_directory/ | ProxyPass /_matrix/client/r0/user_directory/ http://0.0.0.0:8090/_matrix/client/r0/user_directory/ | ||||||
| ``` | ``` | ||||||
| `ProxyPreserveHost` or equivalent must be enabled to detect to which Homeserver mxisd should talk to when building | `ProxyPreserveHost` or equivalent must be enabled to detect to which Homeserver ma1sd should talk to when building | ||||||
| results. | results. | ||||||
|  |  | ||||||
| Your `VirtualHost` should now look like this: | Your `VirtualHost` should now look like this: | ||||||
| @@ -118,32 +118,36 @@ server { | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### DNS Overwrite | ### DNS Overwrite | ||||||
| Just like you need to configure a reverse proxy to send client requests to mxisd, you also need to configure mxisd with | Just like you need to configure a reverse proxy to send client requests to ma1sd, you also need to configure ma1sd with | ||||||
| the internal IP of the Homeserver so it can talk to it directly to integrate its directory search. | the internal IP of the Homeserver so it can talk to it directly to integrate its directory search. | ||||||
|  |  | ||||||
| To do so, use the following configuration: | To do so, use the following configuration: | ||||||
| ```yaml | ```yaml | ||||||
| dns.overwrite.homeserver.client: | dns: | ||||||
|   - name: 'example.org' |   overwrite: | ||||||
|     value: 'http://localhost:8008' |     homeserver: | ||||||
|  |       client: | ||||||
|  |         - name: 'example.org' | ||||||
|  |           value: 'http://localhost:8008' | ||||||
| ``` | ``` | ||||||
| `name` must be the hostname of the URL that clients use when connecting to the Homeserver.   | - `name` must be the hostname of the URL that clients use when connecting to the Homeserver. | ||||||
| In case the hostname is the same as your Matrix domain, you can use `${matrix.domain}` to auto-populate the value using | - `value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`. | ||||||
| the `matrix.domain` configuration option and avoid duplicating it. |  | ||||||
|  |  | ||||||
| `value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`. |  | ||||||
|  |  | ||||||
| ## Next steps | ## Next steps | ||||||
| ### Homeserver results | ### Homeserver results | ||||||
| You can configure if the Homeserver should be queried at all when doing a directory search.   | You can configure if the Homeserver should be queried at all when doing a directory search.   | ||||||
| To disable Homeserver results, set the following in mxisd configuration file: | To disable Homeserver results, set the following in ma1sd configuration file: | ||||||
| ```yaml | ```yaml | ||||||
| directory.exclude.homeserver: true | directory: | ||||||
|  |   exclude: | ||||||
|  |     homeserver: true | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### 3PID exclusion in search | ### 3PID exclusion in search | ||||||
| You can configure if the 3PID should also be included when doing a directory search. | You can configure if the 3PID should also be included when doing a directory search. | ||||||
| By default, a search is performed on the 3PIDs. If you would like to not include them: | By default, a search is performed on the 3PIDs. If you would like to not include them: | ||||||
| ```yaml | ```yaml | ||||||
| directory.exclude.threepid: true | directory: | ||||||
|  |   exclude: | ||||||
|  |     threepid: true | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -1,72 +1,122 @@ | |||||||
| # Integration as an Application Service | # Application Service | ||||||
| **WARNING:** These features are currently highly experimental. They can be removed or modified without notice.   | **WARNING:** These features are currently highly experimental. They can be removed or modified without notice.   | ||||||
| All the features requires a Homeserver capable of connecting Application Services. | All the features requires a Homeserver capable of connecting [Application Services](https://matrix.org/docs/spec/application_service/r0.1.1.html). | ||||||
|  |  | ||||||
| ## Email notification for Room invites by Matrix ID | The following capabilities are provided in this feature: | ||||||
|  | - [Admin commands](#admin-commands) | ||||||
|  | - [Email Notification about room invites by Matrix IDs](#email-notification-about-room-invites-by-matrix-ids) | ||||||
|  | - [Auto-reject of expired 3PID invites](#auto-reject-of-expired-3pid-invites) | ||||||
|  |  | ||||||
|  | ## Setup | ||||||
|  | > **NOTE:** Make sure you are familiar with [configuration format and rules](../../configure.md). | ||||||
|  |  | ||||||
|  | Integration as an Application service is a three steps process: | ||||||
|  | 1. Create the baseline ma1sd configuration to allow integration. | ||||||
|  | 2. Integrate with the homeserver. | ||||||
|  | 3. Configure the specific capabilities, if applicable. | ||||||
|  |  | ||||||
|  | ### Configuration | ||||||
|  | #### Variables | ||||||
|  | Under the `appsvc` namespace: | ||||||
|  |  | ||||||
|  | | Key                   | Type    | Required | Default | Purpose                                                        | | ||||||
|  | |-----------------------|---------|----------|---------|----------------------------------------------------------------| | ||||||
|  | | `enabled`             | boolean | No       | `false` | Globally enable/disable the feature                            | | ||||||
|  | | `user.main`           | string  | No       | `ma1sd` | Localpart for the main appservice user                         | | ||||||
|  | | `endpoint.toHS.url`   | string  | Yes      | *None*  | Base URL to the Homeserver                                     | | ||||||
|  | | `endpoint.toHS.token` | string  | Yes      | *None*  | Token to use when sending requests to the Homeserver           | | ||||||
|  | | `endpoint.toAS.url`   | string  | Yes      | *None*  | Base URL to ma1sd from the Homeserver                          | | ||||||
|  | | `endpoint.toAS.token` | string  | Yes      | *None*  | Token for the Homeserver to use when sending requests to ma1sd | | ||||||
|  |  | ||||||
|  | #### Example | ||||||
|  | ```yaml | ||||||
|  | appsvc: | ||||||
|  |   enabled: true | ||||||
|  |   endpoint: | ||||||
|  |     toHS: | ||||||
|  |       url: 'http://localhost:8008' | ||||||
|  |       token: 'ExampleTokenToHS-ChangeMe!' | ||||||
|  |     toAS: | ||||||
|  |       url: 'http://localhost:8090' | ||||||
|  |       token: 'ExampleTokenToAS-ChangeMe!' | ||||||
|  | ``` | ||||||
|  | ### Integration | ||||||
|  | #### Synapse | ||||||
|  | Under the `appsvc.registration.synapse` namespace: | ||||||
|  |  | ||||||
|  | | Key    | Type   | Required | Default            | Purpose                                                                  | | ||||||
|  | |--------|--------|----------|--------------------|--------------------------------------------------------------------------| | ||||||
|  | | `id`   | string | No       | `appservice-ma1sd` | The unique, user-defined ID of this application service. See spec.       | | ||||||
|  | | `file` | string | Yes      | *None*             | If defined, the synapse registration file that should be created/updated | | ||||||
|  |  | ||||||
|  | ##### Example  | ||||||
|  | ```yaml | ||||||
|  | appsvc: | ||||||
|  |   registration: | ||||||
|  |     synapse: | ||||||
|  |       file: '/etc/matrix-synapse/ma1sd-appservice-registration.yaml' | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Edit your `homeserver.yaml` and add a new entry to the appservice config file, which should look something like this: | ||||||
|  | ```yaml | ||||||
|  | app_service_config_files: | ||||||
|  |   - '/etc/matrix-synapse/ma1sd-appservice-registration.yaml' | ||||||
|  |   - ... | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Restart synapse when done to register ma1sd. | ||||||
|  |  | ||||||
|  | #### Others | ||||||
|  | See your Homeserver documentation on how to integrate. | ||||||
|  |  | ||||||
|  | ## Capabilities | ||||||
|  | ### Admin commands | ||||||
|  | #### Setup | ||||||
|  | Min config: | ||||||
|  | ```yaml | ||||||
|  | appsvc: | ||||||
|  |   feature: | ||||||
|  |     admin: | ||||||
|  |       allowedRoles: | ||||||
|  |         - '+aMatrixCommunity:example.org' | ||||||
|  |         - 'SomeLdapGroup' | ||||||
|  |         - 'AnyOtherArbitraryRoleFromIdentityStores' | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | #### Use | ||||||
|  | The following steps assume: | ||||||
|  | - `matrix.domain` set to `example.org` | ||||||
|  | - `appsvc.user.main` set to `ma1sd` or not set | ||||||
|  |  | ||||||
|  | 1. Invite `@ma1sd:example.org` to a new direct chat | ||||||
|  | 2. Type `!help` to get all available commands | ||||||
|  |  | ||||||
|  | ### Email Notification about room invites by Matrix IDs | ||||||
| This feature allows for users found in Identity stores to be instantly notified about Room Invites, regardless if their | This feature allows for users found in Identity stores to be instantly notified about Room Invites, regardless if their | ||||||
| account was already provisioned on the Homeserver. | account was already provisioned on the Homeserver. | ||||||
|  |  | ||||||
| ### Requirements | #### Requirements | ||||||
| - [Identity store(s)](../../stores/README.md) supporting the Profile feature | - [Identity store(s)](../../stores/README.md) supporting the Profile feature | ||||||
| - At least one email entry in the identity store for each user that could be invited. | - At least one email entry in the identity store for each user that could be invited. | ||||||
|  |  | ||||||
| ### Configuration | #### Configuration | ||||||
| In your mxisd config file: | In your ma1sd config file: | ||||||
| ```yaml | ```yaml | ||||||
| matrix: |  | ||||||
|   listener: |  | ||||||
|     url:  '<URL TO THE CS API OF THE HOMESERVER>' |  | ||||||
|     localpart: 'appservice-mxisd' |  | ||||||
|     token: |  | ||||||
|       hs: 'HS_TOKEN_CHANGE_ME' |  | ||||||
|  |  | ||||||
| synapseSql: | synapseSql: | ||||||
|   enabled: false ## Do not use this line if Synapse is used as an Identity Store |   enabled: false ## Do not use this line if Synapse is used as an Identity Store | ||||||
|   type: '<DB TYPE>' |   type: '<DB TYPE>' | ||||||
|   connection: '<DB CONNECTION URL>' |   connection: '<DB CONNECTION URL>' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| The `synapseSql` section is used to retrieve display names which are not directly accessible in this mode. | The `synapseSql` section is optional. It is used to retrieve display names which are not directly accessible in this mode. | ||||||
| For details about `type` and `connection`, see the [relevant documentation](../../stores/synapse.md). | For details about `type` and `connection`, see the [relevant documentation](../../stores/synapse.md). | ||||||
| If you do not configure it, some placeholders will not be available in the notification, like the Room name. | If you do not configure it, some placeholders will not be available in the notification, like the Room name. | ||||||
|  |  | ||||||
| You can also change the default template of the notification using the `generic.matrixId` template option.   | You can also change the default template of the notification using the `generic.matrixId` template option.   | ||||||
| See [the Template generator documentation](../../threepids/notification/template-generator.md) for more info. | See [the Template generator documentation](../../threepids/notification/template-generator.md) for more info. | ||||||
|  |  | ||||||
| ### Homeserver integration | #### Test | ||||||
| #### Synapse |  | ||||||
| Create a new appservice registration file. Futher config will assume it is in `/etc/matrix-synapse/appservice-mxisd.yaml` |  | ||||||
| ```yaml |  | ||||||
| id: "appservice-mxisd" |  | ||||||
| url: "http://127.0.0.1:8090" |  | ||||||
| as_token: "AS_TOKEN_CHANGE_ME" |  | ||||||
| hs_token: "HS_TOKEN_CHANGE_ME" |  | ||||||
| sender_localpart: "appservice-mxisd" |  | ||||||
| namespaces: |  | ||||||
|   users: |  | ||||||
|     - regex: "@*" |  | ||||||
|       exclusive: false |  | ||||||
|   aliases: [] |  | ||||||
|   rooms: [] |  | ||||||
| ``` |  | ||||||
| `id`: An arbitrary unique string to identify the AS.   |  | ||||||
| `url`: mxisd to reach mxisd. This ideally should be HTTP and not going through any reverse proxy.   |  | ||||||
| `as_token`: Arbitrary value used by mxisd when talking to the HS. Not currently used.   |  | ||||||
| `hs_token`: Arbitrary value used by synapse when talking to mxisd. Must match `token.hs` in mxisd config. |  | ||||||
| `sender_localpart`: Username for the mxisd itself on the HS. Default configuration should be kept.   |  | ||||||
| `namespaces`: To be kept as is.   |  | ||||||
|  |  | ||||||
| Edit your `homeserver.yaml` and add a new entry to the appservice config file, which should look something like this: |  | ||||||
| ```yaml |  | ||||||
| app_service_config_files: |  | ||||||
|   - '/etc/matrix-synapse/appservice-mxisd.yaml' |  | ||||||
|   - ... |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Restart synapse when done to register mxisd. |  | ||||||
|  |  | ||||||
| #### Others |  | ||||||
| See your Homeserver documentation on how to integrate. |  | ||||||
|  |  | ||||||
| ### Test |  | ||||||
| Invite a user which is part of your domain while an appropriate Identity store is used. | Invite a user which is part of your domain while an appropriate Identity store is used. | ||||||
|  |  | ||||||
|  | ### Auto-reject of expired 3PID invites | ||||||
|  | *TBC* | ||||||
|   | |||||||
| @@ -1,12 +1,16 @@ | |||||||
| # Profile enhancement | # Profile | ||||||
| **WARNING**: Alpha feature, not officially supported. Do not use. | **WARNING**: The following sub-features are considered experimental and not officially supported. Use at your own peril. | ||||||
|  |  | ||||||
| This feature allows to enhance a profile query with more info than just Matrix ID and Display name, allowing for custom | ## Public Profile enhancement | ||||||
| applications to retrieve custom data not currently provided by synapse, per example. | This feature allows to enhance a public profile query with more info than just Matrix ID and Display name, allowing for | ||||||
|  | custom applications to retrieve custom data not currently provided by synapse, per example. | ||||||
|  |  | ||||||
| ## Configuration | **WARNING**: This information can be queried without authentication as per the specification. Do not enable unless in a | ||||||
| ### Reverse proxy | controlled environment. | ||||||
| #### Apache |  | ||||||
|  | ### Configuration | ||||||
|  | #### Reverse proxy | ||||||
|  | ##### Apache | ||||||
| ```apache | ```apache | ||||||
| ProxyPassMatch "^/_matrix/client/r0/profile/([^/]+)$" "http://127.0.0.1:8090/_matrix/client/r0/profile/$1" | ProxyPassMatch "^/_matrix/client/r0/profile/([^/]+)$" "http://127.0.0.1:8090/_matrix/client/r0/profile/$1" | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ Federated Identity server using the DNS domain part of the 3PID. | |||||||
| Emails are the best candidate for this kind of resolution which are DNS domain based already.   | Emails are the best candidate for this kind of resolution which are DNS domain based already.   | ||||||
| On the other hand, Phone numbers cannot be resolved this way. | On the other hand, Phone numbers cannot be resolved this way. | ||||||
|  |  | ||||||
| For 3PIDs which are not compatible with the DNS system, mxisd can be configured to talk to fallback Identity servers like | For 3PIDs which are not compatible with the DNS system, ma1sd can be configured to talk to fallback Identity servers like | ||||||
| the central matrix.org one. See the [Identity feature](identity.md#lookups) for instructions on how to enable it. | the central matrix.org one. See the [Identity feature](identity.md#lookups) for instructions on how to enable it. | ||||||
|  |  | ||||||
| Outbound federation is enabled by default while inbound federation is opt-in and require a specific DNS record. | Outbound federation is enabled by default while inbound federation is opt-in and require a specific DNS record. | ||||||
| @@ -13,7 +13,7 @@ Outbound federation is enabled by default while inbound federation is opt-in and | |||||||
| ## Overview | ## Overview | ||||||
| ``` | ``` | ||||||
|               +-------------------+   +-------------> +----------+ |               +-------------------+   +-------------> +----------+ | ||||||
|               | mxisd             |   |               | Backends | |               | ma1sd             |   |               | Backends | | ||||||
|               |                   |   |      +------> +----------+ |               |                   |   |      +------> +----------+ | ||||||
|               |                   |   |      | |               |                   |   |      | | ||||||
|               | Invites / Lookups |   |      | |               | Invites / Lookups |   |      | | ||||||
| @@ -23,7 +23,7 @@ Outbound federation is enabled by default while inbound federation is opt-in and | |||||||
|               |                   |          | |               |                   |          | | ||||||
|               | +--------+        |          |        +-------------------+ |               | +--------+        |          |        +-------------------+ | ||||||
|  Homeserver --->| Local  |>------------------+------> | Remote Federated  | |  Homeserver --->| Local  |>------------------+------> | Remote Federated  | | ||||||
|  and clients  | +--------+        |                   | mxisd servers     | |  and clients  | +--------+        |                   | ma1sd servers     | | ||||||
|               +-------------------+                   +-------------------+ |               +-------------------+                   +-------------------+ | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| @@ -34,16 +34,18 @@ If you would like to be reachable for lookups over federation, create the follow | |||||||
| _matrix-identity._tcp.example.com. 3600 IN SRV 10 0 443 matrix.example.com. | _matrix-identity._tcp.example.com. 3600 IN SRV 10 0 443 matrix.example.com. | ||||||
| ```  | ```  | ||||||
|  |  | ||||||
| The port must be HTTPS capable which is what you get in a regular setup with a reverse proxy from 443 to TCP 8090 of mxisd. | The port must be HTTPS capable which is what you get in a regular setup with a reverse proxy from 443 to TCP 8090 of ma1sd. | ||||||
|  |  | ||||||
| ## Outbound | ## Outbound | ||||||
| If you would like to disable outbound federation and isolate your identity server from the rest of the Matrix network, | If you would like to disable outbound federation and isolate your identity server from the rest of the Matrix network, | ||||||
| use the following mxisd configuration options: | use the following ma1sd configuration options: | ||||||
| ```yaml | ```yaml | ||||||
| lookup.recursive.enabled: false | lookup: | ||||||
| invite.resolution.recursive: false |   recursive: | ||||||
| session.policy.validation.forLocal.toRemote.enabled: false |     enabled: false | ||||||
| session.policy.validation.forRemote.toRemote.enabled: false | invite: | ||||||
|  |   resolution: | ||||||
|  |     recursive: false | ||||||
| ```  | ```  | ||||||
|  |  | ||||||
| There is currently no way to selectively disable federation towards specific servers, but this feature is planned. | There is currently no way to selectively disable federation towards specific servers, but this feature is planned. | ||||||
|   | |||||||
| @@ -1,20 +1,96 @@ | |||||||
| # Identity | # Identity | ||||||
| **WARNING**: This document is incomplete and can be missleading. | Implementation of the [Identity Service API r0.2.0](https://matrix.org/docs/spec/identity_service/r0.2.0.html). | ||||||
|  |  | ||||||
| Implementation of the [Unofficial Matrix Identity Service API](https://kamax.io/matrix/api/identity_service/unstable.html). | - [Lookups](#lookups) | ||||||
|  | - [Invitations](#invitations) | ||||||
|  |   - [Expiration](#expiration) | ||||||
|  |   - [Policies](#policies) | ||||||
|  |   - [Resolution](#resolution) | ||||||
|  | - [3PIDs Management](#3pids-management) | ||||||
|  |  | ||||||
| ## Lookups | ## Lookups | ||||||
| If you would like to use the central matrix.org Identity server to ensure maximum discovery at the cost of potentially | If you would like to use the central matrix.org Identity server to ensure maximum discovery at the cost of potentially | ||||||
| leaking all your contacts information, add the following to your configuration: | leaking all your contacts information, add the following to your configuration: | ||||||
| ```yaml | ```yaml | ||||||
| forward.servers: | forward: | ||||||
|   - 'matrix-org' |   servers: | ||||||
|  |     - 'matrix-org' | ||||||
| ``` | ``` | ||||||
| **NOTE:** You should carefully consider enabling this option, which is discouraged.   | **NOTE:** You should carefully consider enabling this option, which is discouraged.   | ||||||
| For more info, see the [relevant issue](https://github.com/kamax-matrix/mxisd/issues/76). | For more info, see the [relevant issue](https://github.com/kamax-matrix/ma1sd/issues/76). | ||||||
|  |  | ||||||
| ## Room Invitations | ## Invitations | ||||||
| Resolution can be customized using the following configuration: | ### Expiration | ||||||
|  | #### Overview | ||||||
|  | Matrix does not provide a mean to remove/cancel pending 3PID invitations with the APIs. The current reference | ||||||
|  | implementations also do not provide any mean to do so. This leads to 3PID invites forever stuck in rooms. | ||||||
|  |  | ||||||
|  | To provide this functionality, ma1sd uses a workaround: resolve the invite to a dedicated User ID, which can be | ||||||
|  | controlled by ma1sd or a bot/service that will then reject the invite. | ||||||
|  |  | ||||||
|  | If this dedicated User ID is to be controlled by ma1sd, the [Application Service](experimental/application-service.md) | ||||||
|  | feature must be configured and integrated with your Homeserver, as well as the *Auto-reject 3PID invite capability*. | ||||||
|  |  | ||||||
|  | #### Configuration | ||||||
|  | ```yaml | ||||||
|  | invite: | ||||||
|  |   expiration: | ||||||
|  |     enabled: true/false | ||||||
|  |     after: 5 | ||||||
|  |     resolveTo: '@john.doe:example.org' | ||||||
|  | ``` | ||||||
|  | `enabled` | ||||||
|  | - Purpose: Enable or disable the invite expiration feature. | ||||||
|  | - Default: `true` | ||||||
|  |  | ||||||
|  | `after`  | ||||||
|  | - Purpose: Amount of minutes before an invitation expires. | ||||||
|  | - Default: `10080` (7 days) | ||||||
|  |  | ||||||
|  | `resolveTo` | ||||||
|  | - Purpose: Matrix User ID to resolve the expired invitations to. | ||||||
|  | - Default: Computed from `appsvc.user.inviteExpired` and `matrix.domain` | ||||||
|  |  | ||||||
|  | ### Policies | ||||||
|  | 3PID invite policies are the companion feature of [Registration](registration.md). While the Registration feature acts on | ||||||
|  | requirements for the invitee/register, this feature acts on requirement for the one(s) performing 3PID invites, ensuring | ||||||
|  | a coherent system. | ||||||
|  |  | ||||||
|  | It relies on only allowing people with specific [Roles](profile.md) to perform 3PID invites. This would typically allow | ||||||
|  | a tight-control on a server setup with is "invite-only" or semi-open (relying on trusted people to invite new members). | ||||||
|  |  | ||||||
|  | It's a middle ground between a closed server, where every user must be created or already exists in an Identity store, | ||||||
|  | and an open server, where anyone can register. | ||||||
|  |   | ||||||
|  | #### Integration | ||||||
|  | Because Identity Servers do not control 3PID invites as per Matrix spec, ma1sd needs to intercept a set of Homeserver | ||||||
|  | endpoints to apply the policies. | ||||||
|  |  | ||||||
|  | ##### Reverse Proxy | ||||||
|  | ###### nginx | ||||||
|  | **IMPORTANT**: Must be placed before your global `/_matrix` entry: | ||||||
|  | ```nginx | ||||||
|  | location ~* ^/_matrix/client/r0/rooms/([^/]+)/invite$ { | ||||||
|  |     proxy_pass		    http://127.0.0.1:8090; | ||||||
|  |     proxy_set_header	Host $host; | ||||||
|  |     proxy_set_header	X-Forwarded-For $remote_addr; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | #### Configuration | ||||||
|  | The only policy currently available is to restrict 3PID invite to users having a specific (set of) role(s), like so: | ||||||
|  |  | ||||||
|  | ```yaml | ||||||
|  | invite: | ||||||
|  |   policy: | ||||||
|  |     ifSender: | ||||||
|  |       hasRole: | ||||||
|  |         - '<THIS_ROLE>' | ||||||
|  |         - '<OR_THIS_ROLE>' | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Resolution | ||||||
|  | Resolution of 3PID invitations can be customized using the following configuration: | ||||||
|  |  | ||||||
| `invite.resolution.recursive`   | `invite.resolution.recursive`   | ||||||
| - Default value: `true`   | - Default value: `true`   | ||||||
| @@ -25,7 +101,7 @@ Resolution can be customized using the following configuration: | |||||||
|  |  | ||||||
| `invite.resolution.timer`   | `invite.resolution.timer`   | ||||||
| - Default value: `1`   | - Default value: `1`   | ||||||
| - Description: How often, in minutes, mxisd should try to resolve pending invites. | - Description: How often, in minutes, ma1sd should try to resolve pending invites. | ||||||
|  |  | ||||||
| ## 3PID addition to user profile | ## 3PIDs Management | ||||||
| See the [3PID session documents](../threepids/session) | See the [3PID session documents](../threepids/session) | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								docs/features/profile.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								docs/features/profile.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | # Profile | ||||||
|  | The profile feature does not do anything on its own and acts as a support feature for others, allowing to retrieve | ||||||
|  | information about a user based on its Matrix ID by querying enabled [Identity stores](../stores/README.md). | ||||||
|  |  | ||||||
|  | Currently supported: | ||||||
|  | - Display name | ||||||
|  | - 3PIDs | ||||||
|  | - Roles/Groups | ||||||
|  |  | ||||||
|  | Experimental sub-features are also available. See [the dedicated document](experimental/profile.md). | ||||||
							
								
								
									
										111
									
								
								docs/features/registration.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								docs/features/registration.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | # Registration | ||||||
|  | - [Overview](#overview) | ||||||
|  | - [Integration](#integration) | ||||||
|  |   - [Reverse Proxy](#reverse-proxy) | ||||||
|  |     - [nginx](#nginx) | ||||||
|  |     - [Apache2](#apache2) | ||||||
|  |   - [Homeserver](#homeserver) | ||||||
|  |     - [synapse](#synapse) | ||||||
|  | - [Configuration](#configuration) | ||||||
|  |   - [Example](#example) | ||||||
|  | - [Usage](#usage) | ||||||
|  |  | ||||||
|  | ## Overview | ||||||
|  | **NOTE**: This feature is beta: it is considered stable enough for production but is incomplete and may contain bugs. | ||||||
|  |  | ||||||
|  | Registration is an enhanced feature of ma1sd to control registrations involving 3PIDs on a Homeserver based on policies: | ||||||
|  | - Match pending 3PID invites on the server | ||||||
|  | - Match 3PID pattern, like a specific set of domains for emails | ||||||
|  | - In further releases, use 3PIDs found in Identity stores | ||||||
|  |  | ||||||
|  | It aims to help open or invite-only registration servers control what is possible to do and ensure only approved people | ||||||
|  | can register on a given server in a implementation-agnostic manner. | ||||||
|  |  | ||||||
|  | **IMPORTANT:** This feature does not control registration in general. It only acts on endpoints related to 3PIDs during | ||||||
|  | the registration process.   | ||||||
|  | As such, it relies on the homeserver to require 3PIDs with the registration flows. | ||||||
|  |  | ||||||
|  | This feature is not part of the Matrix Identity Server spec. | ||||||
|  |  | ||||||
|  | ## Integration | ||||||
|  | ma1sd needs to be integrated at several levels for this feature to work: | ||||||
|  | - Reverse proxy: intercept the 3PID register endpoints and act on them | ||||||
|  | - Homeserver: require 3PID to be part of the registration data | ||||||
|  |  | ||||||
|  | Later version(s) of this feature may directly control registration itself to create a coherent experience | ||||||
|  | ### Reverse Proxy | ||||||
|  | #### nginx | ||||||
|  | ```nginx | ||||||
|  | location ~* ^/_matrix/client/r0/register/[^/]+/requestToken$ { | ||||||
|  | 	proxy_pass		http://localhost:8090; | ||||||
|  | 	proxy_set_header	Host $host; | ||||||
|  | 	proxy_set_header	X-Forwarded-For $remote_addr; | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | #### Apache2 | ||||||
|  | > TBC | ||||||
|  |  | ||||||
|  | ### Homeserver | ||||||
|  | #### Synapse | ||||||
|  | ```yaml | ||||||
|  | enable_registration: true | ||||||
|  | registrations_require_3pid: | ||||||
|  |   - email | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Configuration | ||||||
|  | See the [Configuration](../configure.md) introduction doc on how to read the configuration keys.   | ||||||
|  | An example of working configuration is available at the end of this section. | ||||||
|  | ### Enable/Disable | ||||||
|  | `register.allowed`, taking a boolean, can be used to enable/disable registration if the attempt is not 3PID-based.   | ||||||
|  | `false` is the default value to prevent open registration, as you must allow it on the homeserver side. | ||||||
|  |  | ||||||
|  | ### For invites | ||||||
|  | `register.invite`, taking a boolean, controls if registration can be made using a 3PID which matches a pending 3PID invite.   | ||||||
|  | `true` is the default value. | ||||||
|  |  | ||||||
|  | ### 3PID-specific | ||||||
|  | At this time, only `email` is supported with 3PID specific configuration with this feature. | ||||||
|  |  | ||||||
|  | #### Email | ||||||
|  | **Base key**: `register.threepid.email` | ||||||
|  |  | ||||||
|  | ##### Domain whitelist/blacklist | ||||||
|  | If you would like to control which domains are allowed to be used when registering with an email, the following sub-keys | ||||||
|  | are available: | ||||||
|  | - `domain.whitelist` | ||||||
|  | - `domain.blacklist` | ||||||
|  |  | ||||||
|  | The value format is an hybrid between glob patterns and postfix configuration files with the following syntax: | ||||||
|  | - `*<domain>` will match the domain and any sub-domain(s) | ||||||
|  | - `.<domain>` will only match sub-domain(s) | ||||||
|  | - `<domain>` will only match the exact domain | ||||||
|  |  | ||||||
|  | The following table illustrates pattern and matching status against example values: | ||||||
|  |  | ||||||
|  | | Config value   | Matches `example.org` | Matches `sub.example.org` | | ||||||
|  | |--------------- |-----------------------|---------------------------| | ||||||
|  | | `*example.org` | Yes                   | Yes                       | | ||||||
|  | | `.example.org` | No                    | Yes                       | | ||||||
|  | | `example.org`  | Yes                   | No                        | | ||||||
|  |  | ||||||
|  | ### Example | ||||||
|  | For the following example configuration: | ||||||
|  | ```yaml | ||||||
|  | register: | ||||||
|  |   policy: | ||||||
|  |     threepid: | ||||||
|  |       email: | ||||||
|  |         domain: | ||||||
|  |           whitelist: | ||||||
|  |             - '*example.org' | ||||||
|  |             - '.example.net' | ||||||
|  |             - 'example.com' | ||||||
|  | ``` | ||||||
|  | - Users can register using 3PIDs of pending invites, being allowed by default. | ||||||
|  | - Users can register using an email from `example.org` and any sub-domain, only sub-domains of `example.net` and `example.com` but not its sub-domains. | ||||||
|  | - Otherwise, user registration will be denied. | ||||||
|  |  | ||||||
|  | ## Usage | ||||||
|  | Nothing special is needed. Register using a regular Matrix client. | ||||||
| @@ -6,24 +6,36 @@ | |||||||
| 5. [Validate](#validate) | 5. [Validate](#validate) | ||||||
| 6. [Next steps](#next-steps) | 6. [Next steps](#next-steps) | ||||||
|  |  | ||||||
| Following these quick start instructions, you will have a basic setup that can perform recursive/federated lookups and | Following these quick start instructions, you will have a basic setup that can perform recursive/federated lookups.   | ||||||
| talk to the central Matrix.org Identity server.   |  | ||||||
| This will be a good ground work for further integration with features and your existing Identity stores. | This will be a good ground work for further integration with features and your existing Identity stores. | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | If you would like a more fully integrated setup out of the box, the [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy) | ||||||
|  | project provides a turn-key full-stack solution, including LDAP and the various ma1sd features enabled and ready.   | ||||||
|  | We work closely with the project owner so the latest ma1sd version is always supported. | ||||||
|  |  | ||||||
|  | If you choose to use it, this Getting Started guide is not applicable - See the project documentation. You may then | ||||||
|  | directly go to the [Next steps](#next-steps). | ||||||
|  |  | ||||||
| ## Preparation | ## Preparation | ||||||
| You will need: | You will need: | ||||||
| - Working Homeserver, ideally with working federation | - Working Homeserver, ideally with working federation | ||||||
| - Reverse proxy with regular TLS/SSL certificate (Let's encrypt) for your mxisd domain | - Reverse proxy with regular TLS/SSL certificate (Let's encrypt) for your ma1sd domain | ||||||
|  |  | ||||||
| As synapse requires an HTTPS connection when talking to an Identity service, **a reverse proxy is required** as mxisd does | If you use synapse: | ||||||
| not support HTTPS listener at this time. | - It requires an HTTPS connection when talking to an Identity service, **a reverse proxy is required** as ma1sd does | ||||||
|  |   not support HTTPS listener at this time. | ||||||
|  | - HTTPS is hardcoded when talking to the Identity server. If your Identity server URL in your client is `https://matrix.example.org/`, | ||||||
|  |   then you need to ensure `https://matrix.example.org/_matrix/identity/api/v1/...` will reach ma1sd if called from the synapse host. | ||||||
|  |   In doubt, test with `curl` or similar.  | ||||||
|  |  | ||||||
| For maximum integration, it is best to have your Homeserver and mxisd reachable via the same hostname. | For maximum integration, it is best to have your Homeserver and ma1sd reachable via the same public hostname. | ||||||
|  |  | ||||||
| Be aware of a [NAT/Reverse proxy gotcha](https://github.com/kamax-matrix/mxisd/wiki/Gotchas#nating) if you use the same | Be aware of a [NAT/Reverse proxy gotcha](https://github.com/ma1uta/ma1sd/wiki/Gotchas#nating) if you use the same | ||||||
| hostname. | host. | ||||||
|  |  | ||||||
| The following Quick Start guide assumes you will host the Homeserver and mxisd under the same hostname.   | The following Quick Start guide assumes you will host the Homeserver and ma1sd under the same hostname.   | ||||||
| If you would like a high-level view of the infrastructure and how each feature is integrated, see the | If you would like a high-level view of the infrastructure and how each feature is integrated, see the | ||||||
| [dedicated document](architecture.md) | [dedicated document](architecture.md) | ||||||
|  |  | ||||||
| @@ -35,30 +47,30 @@ Install via: | |||||||
| - [NixOS](install/nixos.md) | - [NixOS](install/nixos.md) | ||||||
| - [Sources](build.md) | - [Sources](build.md) | ||||||
|  |  | ||||||
| See the [Latest release](https://github.com/kamax-matrix/mxisd/releases/latest) for links to each. | See the [Latest release](https://github.com/ma1uta/ma1sd/releases/latest) for links to each. | ||||||
|  |  | ||||||
| ## Configure | ## Configure | ||||||
| **NOTE**: please view the install instruction for your platform, as this step might be optional or already handled for you. | > **NOTE**: Please view the install instruction for your platform, as this step might be optional or already handled for you. | ||||||
|  |    | ||||||
|  | > **NOTE**: Details about configuration syntax and format are described [here](configure.md) | ||||||
|  |  | ||||||
| Create/edit a minimal configuration (see installer doc for the location): | If you haven't created a configuration file yet, copy `ma1sd.example.yaml` to where the configuration file is stored given | ||||||
| ```yaml | your installation method and edit to your needs. | ||||||
| matrix.domain: 'example.org' |  | ||||||
| key.path: '/path/to/signing.key.file' | The following items must be at least configured: | ||||||
| storage.provider.sqlite.database: '/path/to/mxisd.db' |  | ||||||
| ```   |  | ||||||
| - `matrix.domain` should be set to your Homeserver domain (`server_name` in synapse configuration) | - `matrix.domain` should be set to your Homeserver domain (`server_name` in synapse configuration) | ||||||
| - `key.path` will store the signing keys, which must be kept safe! If the file does not exist, keys will be generated for you. | - `key.path` will store the signing keys, which must be kept safe! If the file does not exist, keys will be generated for you. | ||||||
| - `storage.provider.sqlite.database` is the location of the SQLite Database file which will hold state (invites, etc.) | - `storage.provider.sqlite.database` is the location of the SQLite Database file which will hold state (invites, etc.) | ||||||
|  |  | ||||||
| If your HS/mxisd hostname is not the same as your Matrix domain, configure `server.name`.   | If your HS/ma1sd hostname is not the same as your Matrix domain, configure `server.name`.   | ||||||
| Complete configuration guide is available [here](configure.md). | Complete configuration guide is available [here](configure.md). | ||||||
|  |  | ||||||
| ## Integrate | ## Integrate | ||||||
| For an overview of a typical mxisd infrastructure, see the [dedicated document](architecture.md) | For an overview of a typical ma1sd infrastructure, see the [dedicated document](architecture.md) | ||||||
| ### Reverse proxy | ### Reverse proxy | ||||||
| #### Apache2 | #### Apache2 | ||||||
| In the `VirtualHost` section handling the domain with SSL, add the following and replace `0.0.0.0` by the internal | In the `VirtualHost` section handling the domain with SSL, add the following and replace `0.0.0.0` by the internal | ||||||
| hostname/IP pointing to mxisd.   | hostname/IP pointing to ma1sd.   | ||||||
| **This line MUST be present before the one for the homeserver!** | **This line MUST be present before the one for the homeserver!** | ||||||
| ```apache | ```apache | ||||||
| ProxyPass /_matrix/identity http://0.0.0.0:8090/_matrix/identity | ProxyPass /_matrix/identity http://0.0.0.0:8090/_matrix/identity | ||||||
| @@ -67,9 +79,9 @@ ProxyPass /_matrix/identity http://0.0.0.0:8090/_matrix/identity | |||||||
| Typical configuration would look like: | Typical configuration would look like: | ||||||
| ```apache | ```apache | ||||||
| <VirtualHost *:443> | <VirtualHost *:443> | ||||||
|     ServerName example.org |     ServerName matrix.example.org | ||||||
|      |      | ||||||
|     ... |     # ... | ||||||
|      |      | ||||||
|     ProxyPreserveHost on |     ProxyPreserveHost on | ||||||
|     ProxyPass /_matrix/identity http://localhost:8090/_matrix/identity |     ProxyPass /_matrix/identity http://localhost:8090/_matrix/identity | ||||||
| @@ -79,7 +91,7 @@ Typical configuration would look like: | |||||||
|  |  | ||||||
| #### nginx | #### nginx | ||||||
| In the `server` section handling the domain with SSL, add the following and replace `0.0.0.0` with the internal | In the `server` section handling the domain with SSL, add the following and replace `0.0.0.0` with the internal | ||||||
| hostname/IP pointing to mxisd. | hostname/IP pointing to ma1sd. | ||||||
| **This line MUST be present before the one for the homeserver!** | **This line MUST be present before the one for the homeserver!** | ||||||
| ```nginx | ```nginx | ||||||
| location /_matrix/identity { | location /_matrix/identity { | ||||||
| @@ -91,9 +103,9 @@ Typical configuration would look like: | |||||||
| ```nginx | ```nginx | ||||||
| server { | server { | ||||||
|     listen 443 ssl; |     listen 443 ssl; | ||||||
|     server_name example.org; |     server_name matrix.example.org; | ||||||
|      |      | ||||||
|     ... |     # ... | ||||||
|      |      | ||||||
|     location /_matrix/identity { |     location /_matrix/identity { | ||||||
|         proxy_pass http://localhost:8090/_matrix/identity; |         proxy_pass http://localhost:8090/_matrix/identity; | ||||||
| @@ -110,33 +122,36 @@ server { | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Synapse | ### Synapse | ||||||
| Add your mxisd domain into the `homeserver.yaml` at `trusted_third_party_id_servers` and restart synapse.   | Add your ma1sd domain into the `homeserver.yaml` at `trusted_third_party_id_servers` and restart synapse.   | ||||||
| In a typical configuration, you would end up with something similar to: | In a typical configuration, you would end up with something similar to: | ||||||
| ```yaml | ```yaml | ||||||
| trusted_third_party_id_servers: | trusted_third_party_id_servers: | ||||||
|     - example.org |     - matrix.example.org | ||||||
| ``` | ``` | ||||||
| It is recommended to remove `matrix.org` and `vector.im` (or any other default entry) from your configuration so only | It is **highly recommended** to remove `matrix.org` and `vector.im` (or any other default entry) from your configuration | ||||||
| your own Identity server is authoritative for your HS. | so only your own Identity server is authoritative for your HS. | ||||||
|  |  | ||||||
| ## Validate | ## Validate (Under reconstruction) | ||||||
| **NOTE:** In case your homeserver has no working federation, step 5 will not happen. If step 4 took place, consider | **NOTE:** In case your homeserver has no working federation, step 5 will not happen. If step 4 took place, consider | ||||||
| your installation validated. | your installation validated. | ||||||
|  |  | ||||||
| 1. Log in using your Matrix client and set `https://example.org` as your Identity server URL, replacing `example.org` by | 1. Log in using your Matrix client and set `https://matrix.example.org` as your Identity server URL, replacing `matrix.example.org` | ||||||
| the relevant hostname which you configured in your reverse proxy. | by the relevant hostname which you configured in your reverse proxy. | ||||||
| 2. Create a new empty room. All further actions will take place in this room. | 2. Create a new empty room. All further actions will take place in this room. | ||||||
| 3. Invite `mxisd-federation-test@kamax.io` | 3. Invite `ma1sd-federation-test@kamax.io` | ||||||
| 4. The 3PID invite should be turned into a Matrix invite to `@mxisd-lookup-test:kamax.io`. | 4. The 3PID invite should be turned into a Matrix invite to `@ma1sd-lookup-test:kamax.io`. | ||||||
| 5. The invited test user will join the room, send a congratulation message and leave. | 5. The invited test user will join the room, send a congratulation message and leave. | ||||||
| **NOTE:** You might not see a suggestion for the e-mail address, which is normal. Still proceed with the invite. | **NOTE:** You might not see a suggestion for the e-mail address, which is normal. Still proceed with the invite. | ||||||
|    |    | ||||||
| If it worked, it means you are up and running and can enjoy mxisd in its basic mode! Congratulations!   | If it worked, it means you are up and running and can enjoy ma1sd in its basic mode! Congratulations!   | ||||||
| If it did not work, [get in touch](../README.md#support) and we'll do our best to get you started. | If it did not work, read the basic [troubleshooting guide](troubleshooting.md), [get in touch](../README.md#support) and | ||||||
|  | we'll do our best to get you started. | ||||||
|  |  | ||||||
| ## Next steps | ## Next steps | ||||||
| Once your mxisd server is up and running, there are several ways you can enhance and integrate further with your | Once your ma1sd server is up and running, there are several ways you can enhance and integrate further with your | ||||||
| infrastructure: | infrastructure: | ||||||
|  |  | ||||||
| - [Enable extra features](features/) | - [Enable extra features](features/) | ||||||
| - [Use your own Identity stores](stores/README.md) | - [Use your own Identity stores](stores/README.md) | ||||||
|  | - [Hardening your ma1sd installation](install/security.md) | ||||||
|  | - [Learn about day-to-day operations](operations.md) | ||||||
|   | |||||||
| @@ -1,3 +1,9 @@ | |||||||
|  | --- | ||||||
|  |  | ||||||
|  | ** Outdated due to migrating to fork. ** | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
| # Arch Linux package | # Arch Linux package | ||||||
| An Arch Linux package in the AUR repos is maintained by [r3pek](https://matrix.to/#/@r3pek:r3pek.org), a community member.   | An Arch Linux package in the AUR repos is maintained by [r3pek](https://matrix.to/#/@r3pek:r3pek.org), a community member.   | ||||||
| See https://aur.archlinux.org/packages/mxisd/ | See https://aur.archlinux.org/packages/mxisd/ | ||||||
|   | |||||||
| @@ -3,40 +3,40 @@ | |||||||
| - Any distribution that supports Java 8 | - Any distribution that supports Java 8 | ||||||
|  |  | ||||||
| ## Install | ## Install | ||||||
| 1. Download the [latest release](https://github.com/kamax-matrix/mxisd/releases/latest) | 1. Download the [latest release](https://github.com/ma1uta/ma1sd/releases/latest) | ||||||
| 2. Run: | 2. Run: | ||||||
| ```bash | ```bash | ||||||
| dpkg -i /path/to/downloaded/mxisd.deb | dpkg -i /path/to/downloaded/ma1sd.deb | ||||||
| ``` | ``` | ||||||
| ## Files | ## Files | ||||||
| | Location                            | Purpose                                      | | | Location                            | Purpose                                      | | ||||||
| |-------------------------------------|----------------------------------------------| | |-------------------------------------|----------------------------------------------| | ||||||
| | `/etc/mxisd`                        | Configuration directory                      | | | `/etc/ma1sd`                        | Configuration directory                      | | ||||||
| | `/etc/mxisd/mxisd.yaml`             | Main configuration file                      | | | `/etc/ma1sd/ma1sd.yaml`             | Main configuration file                      | | ||||||
| | `/etc/systemd/system/mxisd.service` | Systemd configuration file for mxisd service | | | `/etc/systemd/system/ma1sd.service` | Systemd configuration file for ma1sd service | | ||||||
| | `/usr/lib/mxisd`                    | Binaries                                     | | | `/usr/lib/ma1sd`                    | Binaries                                     | | ||||||
| | `/var/lib/mxisd`                    | Data                                         | | | `/var/lib/ma1sd`                    | Data                                         | | ||||||
| | `/var/lib/mxisd/signing.key`        | Default location for mxisd signing keys      | | | `/var/lib/ma1sd/signing.key`        | Default location for ma1sd signing keys      | | ||||||
|  |  | ||||||
| ## Control | ## Control | ||||||
| Start mxisd using: | Start ma1sd using: | ||||||
| ```bash | ```bash | ||||||
| sudo systemctl start mxisd | sudo systemctl start ma1sd | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Stop mxisd using: | Stop ma1sd using: | ||||||
| ```bash | ```bash | ||||||
| sudo systemctl stop mxisd | sudo systemctl stop ma1sd | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## Troubleshoot | ## Troubleshoot | ||||||
| All logs are sent to `STDOUT` which are saved in `/var/log/syslog` by default.   | All logs are sent to `STDOUT` which are saved in `/var/log/syslog` by default.   | ||||||
| You can: | You can: | ||||||
| - grep & tail using `mxisd`: | - grep & tail using `ma1sd`: | ||||||
| ``` | ``` | ||||||
| tail -n 99 -f /var/log/syslog | grep mxisd | tail -n 99 -f /var/log/syslog | grep ma1sd | ||||||
| ``` | ``` | ||||||
| - use Systemd's journal: | - use Systemd's journal: | ||||||
| ``` | ``` | ||||||
| journalctl -f -n 99 -u mxisd | journalctl -f -n 99 -u ma1sd | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -1,13 +1,19 @@ | |||||||
|  | --- | ||||||
|  |  | ||||||
|  | ** Outdated due to migrating to fork. ** | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
| # Docker | # Docker | ||||||
| ## Fetch | ## Fetch | ||||||
| Pull the latest stable image: | Pull the latest stable image: | ||||||
| ```bash | ```bash | ||||||
| docker pull kamax/mxisd | docker pull ma1uta/ma1sd | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## Configure | ## Configure | ||||||
| On first run, simply using `MATRIX_DOMAIN` as an environment variable will create a default config for you.   | On first run, simply using `MATRIX_DOMAIN` as an environment variable will create a default config for you.   | ||||||
| You can also provide a configuration file named `mxisd.yaml` in the volume mapped to `/etc/mxisd` before starting your | You can also provide a configuration file named `ma1sd.yaml` in the volume mapped to `/etc/ma1sd` before starting your | ||||||
| container. | container. | ||||||
|  |  | ||||||
| ## Run | ## Run | ||||||
| @@ -16,7 +22,10 @@ Use the following command after adapting to your needs: | |||||||
| - The volumes host paths | - The volumes host paths | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| docker run --rm -e MATRIX_DOMAIN=example.org -v /data/mxisd/etc:/etc/mxisd -v /data/mxisd/var:/var/mxisd -p 8090:8090 -t kamax/mxisd | docker run --rm -e MATRIX_DOMAIN=example.org -v /data/ma1sd/etc:/etc/ma1sd -v /data/ma1sd/var:/var/ma1sd -p 8090:8090 -t ma1uta/ma1sd | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| For more info, including the list of possible tags, see [the public repository](https://hub.docker.com/r/kamax/mxisd/) | For more info, including the list of possible tags, see [the public repository](https://hub.docker.com/r/ma1uta/ma1sd/) | ||||||
|  |  | ||||||
|  | ## Troubleshoot | ||||||
|  | Please read the [Troubleshooting guide](../troubleshooting.md). | ||||||
|   | |||||||
| @@ -1,3 +1,9 @@ | |||||||
|  | --- | ||||||
|  |  | ||||||
|  | ** Outdated due to migrating to fork. ** | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
| # NixOS package | # NixOS package | ||||||
| mxisd is available as a NixOS package in the official repos. | mxisd is available as a NixOS package in the official repos. | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								docs/install/security.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								docs/install/security.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | # Security hardening | ||||||
|  | ## Overview | ||||||
|  | This document outlines the various operations you may want to perform to increase the security of your installation and | ||||||
|  | avoid leak of credentials/key pairs | ||||||
|  |  | ||||||
|  | ## Configuration | ||||||
|  | Your config file should have the following ownership: | ||||||
|  | - Dedicated user for ma1sd, used to run the software | ||||||
|  | - Dedicated group for ma1sd, used by other applications to access and read configuration files | ||||||
|  |  | ||||||
|  | Your config file should have the following access: | ||||||
|  | - Read and write for the ma1sd user | ||||||
|  | - Read for the ma1sd group | ||||||
|  | - Nothing for others | ||||||
|  |  | ||||||
|  | This translates into `640` and be applied with `chmod 640 /path/to/config/file.yaml`. | ||||||
|  |  | ||||||
|  | ## Data | ||||||
|  | The only sensible place is the key store where ma1sd's signing keys are stored. You should therefore limit access to only | ||||||
|  | the ma1sd user, and deny access to anything else. | ||||||
|  |  | ||||||
|  | Your key store should have the following access: | ||||||
|  | - Read and write for the ma1sd user | ||||||
|  | - Nothing for the ma1sd group | ||||||
|  | - Nothing for others | ||||||
|  |  | ||||||
|  | The identity store can either be a file or a directory, depending on your version. v1.4 and higher are using a directory, | ||||||
|  | everything before is using a file. | ||||||
|  | - If your version is directory-based, you will want to apply chmod `700` on it. | ||||||
|  | - If your version is file-based, you will want to apply chmod `600` on it. | ||||||
| @@ -2,37 +2,43 @@ | |||||||
| ## Instructions | ## Instructions | ||||||
| Follow the [build instructions](../build.md) then: | Follow the [build instructions](../build.md) then: | ||||||
|  |  | ||||||
| 1. Prepare files and directories: | ### Prepare files and directories: | ||||||
| ```bash | ```bash | ||||||
| # Create a dedicated user | # Create a dedicated user | ||||||
| useradd -r mxisd | useradd -r ma1sd | ||||||
|  |  | ||||||
| # Create bin directory | # Create config directory | ||||||
| mkdir /opt/mxisd | mkdir -p /etc/ma1sd | ||||||
|  |  | ||||||
| # Create config directory and set ownership |  | ||||||
| mkdir -p /etc/opt/mxisd |  | ||||||
| chown -R mxisd /etc/opt/mxisd |  | ||||||
|  |  | ||||||
| # Create data directory and set ownership | # Create data directory and set ownership | ||||||
| mkdir -p /var/opt/mxisd | mkdir -p /var/lib/ma1sd | ||||||
| chown -R mxisd /var/opt/mxisd | chown -R ma1sd /var/lib/ma1sd | ||||||
|  |  | ||||||
| # Copy <repo root>/build/libs/mxisd.jar to bin directory | # Create bin directory, copy the jar and launch scriot to bin directory | ||||||
| cp ./build/libs/mxisd.jar /opt/mxisd/ | mkdir /usr/lib/ma1sd | ||||||
| chown mxisd /opt/mxisd/mxisd.jar | cp ./build/libs/ma1sd.jar /usr/lib/ma1sd/ | ||||||
| chmod a+x /opt/mxisd/mxisd.jar | cp ./src/script/ma1sd /usr/lib/ma1sd | ||||||
|  | chown -R ma1sd /usr/lib/ma1sd | ||||||
|  | chmod a+x /usr/lib/ma1sd/ma1sd | ||||||
|  |  | ||||||
| # Create symlink for easy exec | # Create symlink for easy exec | ||||||
| ln -s /opt/mxisd/mxisd.jar /usr/bin/mxisd | ln -s /usr/lib/ma1sd/ma1sd /usr/bin/ma1sd | ||||||
| ``` | ``` | ||||||
| 2. Copy the sample config file `./application.example.yaml` to `/etc/opt/mxisd/mxisd.yaml`, edit to your needs |  | ||||||
| 3. Copy `src/systemd/mxisd.service` to `/etc/systemd/system/` and edit if needed | ### Prepare config file | ||||||
| 4. Enable service for auto-startup | Copy the configuration file you've created following the build instructions to `/etc/ma1sd/ma1sd.yaml` | ||||||
|  |  | ||||||
|  | ### Prepare Systemd | ||||||
|  | 1. Copy `src/systemd/ma1sd.service` to `/etc/systemd/system/` and edit if needed | ||||||
|  | 2. Enable service for auto-startup | ||||||
| ```bash | ```bash | ||||||
| systemctl enable mxisd | systemctl enable ma1sd | ||||||
| ``` | ``` | ||||||
| 5. Start mxisd |  | ||||||
|  | ### Run | ||||||
| ```bash | ```bash | ||||||
| systemctl start mxisd | systemctl start ma1sd | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ## Debug | ||||||
|  | ma1sd logs to stdout, which is normally sent to `/var/log/syslog` or `/var/log/messages`. | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								docs/migration-from-mxisd.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								docs/migration-from-mxisd.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | # Migration from mxisd | ||||||
|  |  | ||||||
|  | Version 2.0.0 of the ma1sd uses the same format of the database schema and main configuration file as mxisd. | ||||||
|  |  | ||||||
|  | Migration from mxisd: | ||||||
|  | - install ma1sd via deb package, docker image or zip/tar archive | ||||||
|  | - stop mxisd | ||||||
|  | - copy configuration file (by default /etc/mxisd/mxisd.yaml to /etc/ma1sd/ma1sd.yaml) | ||||||
|  | - copy key store (by default /var/lib/mxisd/keys folder to /var/lib/ma1sd/keys) | ||||||
|  | - copy storage (by default /var/lib/mxisd/store.db to /var/lib/ma1sd/store.db) | ||||||
|  | - change paths in the new config file (ma1sd.yaml). There are options: `key.path` and `storage.provider.sqlite` | ||||||
|  | - start ma1sd | ||||||
|  |  | ||||||
|  | Due to ma1sd uses the same ports by default as mxisd it isn't necessary to change nginx/apache configuration. | ||||||
|  |  | ||||||
|  | If you have any troubles with migration don't hesitate to ask questions in [#ma1sd:ru-matrix.org](https://matrix.to/#/#ma1sd:ru-matrix.org) room. | ||||||
							
								
								
									
										21
									
								
								docs/operations.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								docs/operations.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | # Operations Guide | ||||||
|  | - [Overview](#overview) | ||||||
|  | - [Maintenance](#maintenance) | ||||||
|  | - [Backuo](#backup) | ||||||
|  |  | ||||||
|  | ## Overview | ||||||
|  | This document gives various information for the day-to-day management and operations of ma1sd. | ||||||
|  |  | ||||||
|  | ## Maintenance | ||||||
|  | ma1sd does not require any maintenance task to run at optimal performance. | ||||||
|  |  | ||||||
|  | ## Backup | ||||||
|  | ### Run | ||||||
|  | ma1sd requires all file in its configuration and data directory to be backed up.   | ||||||
|  | They are usually located at: | ||||||
|  | - `/etc/ma1sd` | ||||||
|  | - `/var/lib/ma1sd` | ||||||
|  |  | ||||||
|  | ### Restore | ||||||
|  | Reinstall ma1sd, restore the two folders above in the appropriate location (depending on your install method) and you | ||||||
|  | will be good to go. Simply start ma1sd to restore functionality. | ||||||
| @@ -39,10 +39,10 @@ | |||||||
| | [Authentication](../features/authentication.md) | Yes       | | | [Authentication](../features/authentication.md) | Yes       | | ||||||
| | [Directory](../features/directory.md)           | Yes       | | | [Directory](../features/directory.md)           | Yes       | | ||||||
| | [Identity](../features/identity.md)             | Yes       | | | [Identity](../features/identity.md)             | Yes       | | ||||||
| | [Profile](#profile)                             | Yes       | | | [Profile](../features/profile.md)               | Yes       | | ||||||
|  |  | ||||||
| This Identity Store lets you run arbitrary commands to handle the various requests in each support feature.   | This Identity Store lets you run arbitrary commands to handle the various requests in each support feature.   | ||||||
| It is the most versatile Identity store of mxisd, allowing you to connect any kind of logic with any executable/script. | It is the most versatile Identity store of ma1sd, allowing you to connect any kind of logic with any executable/script. | ||||||
|  |  | ||||||
| ## Overview | ## Overview | ||||||
| Each request can be mapping to a fully customizable command configuration.   | Each request can be mapping to a fully customizable command configuration.   | ||||||
| @@ -68,7 +68,8 @@ We will use the term `Executable` for each lookup/action and `Processor` for eac | |||||||
|  |  | ||||||
| ### Global | ### Global | ||||||
| ```yaml | ```yaml | ||||||
| exec.enabled: <boolean> | exec: | ||||||
|  |   enabled: <boolean> | ||||||
| ``` | ``` | ||||||
| Enable/disable the Identity store at a global/default level. Each feature can still be individually enabled/disabled. | Enable/disable the Identity store at a global/default level. Each feature can still be individually enabled/disabled. | ||||||
|  |  | ||||||
| @@ -79,7 +80,9 @@ Not all features use all tokens, and each feature might also have its own specif | |||||||
| They can be set within the following scope: | They can be set within the following scope: | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| exec.token.<token>: '<value>' | exec: | ||||||
|  |   token: | ||||||
|  |     <token>: '<value>' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
| @@ -184,16 +187,19 @@ The following types are available: | |||||||
| ### Examples | ### Examples | ||||||
| #### Basic | #### Basic | ||||||
| ```yaml | ```yaml | ||||||
| exec.auth.enabled: true | exec: | ||||||
| exec.auth.command: '/opt/mxisd-exec/auth.sh' |   auth: | ||||||
| exec.auth.args: ['{localpart}'] |     enabled: true | ||||||
| exec.auth.input.type: 'plain' |     command: '/opt/ma1sd-exec/auth.sh' | ||||||
| exec.auth.input.template: '{password}' |     args: ['{localpart}'] | ||||||
| exec.auth.env: |     input: | ||||||
|   DOMAIN: '{domain}' |       type: 'plain' | ||||||
|  |       template: '{password}' | ||||||
|  |   env: | ||||||
|  |     DOMAIN: '{domain}' | ||||||
| ``` | ``` | ||||||
| With Authentication enabled, run `/opt/mxisd-exec/auth.sh` when validating credentials, providing: | With Authentication enabled, run `/opt/ma1sd-exec/auth.sh` when validating credentials, providing: | ||||||
| - A single command-line argument to provide the `localoart` as username  | - A single command-line argument to provide the `localpart` as username  | ||||||
| - A plain text string with the password token for standard input, which will be replaced by the password to check | - A plain text string with the password token for standard input, which will be replaced by the password to check | ||||||
| - A single environment variable `DOMAIN` containing Matrix ID domain, if given | - A single environment variable `DOMAIN` containing Matrix ID domain, if given | ||||||
|  |  | ||||||
| @@ -201,26 +207,34 @@ The command will use the default values for: | |||||||
| - Success exit status of `0` | - Success exit status of `0` | ||||||
| - Failure exit status of `1` | - Failure exit status of `1` | ||||||
| - Any other exit status considered as error | - Any other exit status considered as error | ||||||
| - The standard output processing as not processed | - Standard output will not be processed | ||||||
|  |  | ||||||
| #### Advanced | #### Advanced | ||||||
| Given the fictional `placeholder` feature: | Given the fictional `placeholder` feature: | ||||||
| ```yaml | ```yaml | ||||||
| exec.enabled: true | exec: | ||||||
| exec.token.mxid: '{matrixId}' |   enabled: true | ||||||
|  |   token: | ||||||
| exec.placeholder.token.localpart: '{username}' |     mxid: '{matrixId}' | ||||||
| exec.placeholder.command: '/path/to/executable' |   auth: | ||||||
| exec.placeholder.args: |     token: | ||||||
|   - '-u' |       localpart: '{username}' | ||||||
|   - '{username}' |     command: '/path/to/executable' | ||||||
| exec.placeholder.env: |     args: | ||||||
|   MATRIX_DOMAIN: '{domain}' |       - '-u' | ||||||
|   MATRIX_USER_ID: '{matrixId}' |       - '{username}' | ||||||
|    |     env: | ||||||
| exec.placeholder.output.type: 'json' |       MATRIX_DOMAIN: '{domain}' | ||||||
| exec.placeholder.exit.success: [0, 128] |       MATRIX_USER_ID: '{matrixId}' | ||||||
| exec.placeholder.exit.failure: [1, 129] |     output: | ||||||
|  |       type: 'json' | ||||||
|  |     exit: | ||||||
|  |       success: | ||||||
|  |         - 0 | ||||||
|  |         - 128 | ||||||
|  |       failure: | ||||||
|  |         - 1 | ||||||
|  |         - 129 | ||||||
| ``` | ``` | ||||||
| With: | With: | ||||||
| - The Identity store enabled for all features | - The Identity store enabled for all features | ||||||
| @@ -243,14 +257,17 @@ See each dedicated [Feature](#features) section. | |||||||
| ## Authentication | ## Authentication | ||||||
| The Authentication feature can be enabled/disabled using: | The Authentication feature can be enabled/disabled using: | ||||||
| ```yaml | ```yaml | ||||||
| exec.auth.enabled: <true/false> | exec: | ||||||
|  |   auth: | ||||||
|  |     enabled: <true/false> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| This feature provides a single *Executable* under the namespace: | This feature provides a single *Executable* under the namespace: | ||||||
| ```yaml | ```yaml | ||||||
| exec.auth: | exec: | ||||||
|  |   auth: | ||||||
|   ... |   ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| @@ -294,7 +311,9 @@ Default template: | |||||||
| ## Directory | ## Directory | ||||||
| The Directory feature can be enabled/disabled using: | The Directory feature can be enabled/disabled using: | ||||||
| ```yaml | ```yaml | ||||||
| exec.directory.enabled: <true/false> | exec: | ||||||
|  |   directory: | ||||||
|  |     enabled: <true/false> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
| @@ -303,13 +322,19 @@ Two search types configuration namespace are available, using the same input/out | |||||||
|  |  | ||||||
| By name: | By name: | ||||||
| ```yaml | ```yaml | ||||||
| exec.directory.search.byName: | exec: | ||||||
|   ... |   directory: | ||||||
|  |     search: | ||||||
|  |       byName: | ||||||
|  |         ... | ||||||
| ``` | ``` | ||||||
| By 3PID: | By 3PID: | ||||||
| ```yaml | ```yaml | ||||||
| exec.directory.search.byThreepid: | exec: | ||||||
|   ... |   directory: | ||||||
|  |     search: | ||||||
|  |       byThreepid: | ||||||
|  |         ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Tokens | #### Tokens | ||||||
| @@ -386,8 +411,11 @@ The User ID type will default to `localpart` if: | |||||||
| ### Bulk lookup | ### Bulk lookup | ||||||
| Configuration namespace: | Configuration namespace: | ||||||
| ```yaml | ```yaml | ||||||
| exec.identity.lookup.bulk: | exec: | ||||||
|   ... |   identity: | ||||||
|  |     lookup: | ||||||
|  |       bulk: | ||||||
|  |         ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Tokens | #### Tokens | ||||||
| @@ -418,7 +446,9 @@ Same as the [REST Identity Store](rest.md). | |||||||
| ## Profile | ## Profile | ||||||
| The Profile feature can be enabled/disabled using: | The Profile feature can be enabled/disabled using: | ||||||
| ```yaml | ```yaml | ||||||
| exec.profile.enabled: <true/false> | exec: | ||||||
|  |   profile: | ||||||
|  |     enabled: <true/false> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
| @@ -427,20 +457,26 @@ The following *Executable*s namespace are available, share the same input/output | |||||||
|  |  | ||||||
| Get Display name: | Get Display name: | ||||||
| ```yaml | ```yaml | ||||||
| exec.profile.displayName: | exec: | ||||||
|   ... |   profile: | ||||||
|  |     displayName: | ||||||
|  |       ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Get 3PIDs: | Get 3PIDs: | ||||||
| ```yaml | ```yaml | ||||||
| exec.profile.threePid: | exec: | ||||||
|   ... |   profile: | ||||||
|  |     threePid: | ||||||
|  |       ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| Get Roles: | Get Roles: | ||||||
| ```yaml | ```yaml | ||||||
| exec.profile.role: | exec: | ||||||
|   ... |   profile: | ||||||
|  |     role: | ||||||
|  |       ... | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,12 +2,12 @@ | |||||||
| https://firebase.google.com/ | https://firebase.google.com/ | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| |      Name      | Supported? | | |                       Name                      | Supported | | ||||||
| |----------------|------------| | |-------------------------------------------------|-----------| | ||||||
| | Authentication | Yes        | | | [Authentication](../features/authentication.md) | Yes       | | ||||||
| | Directory      | No         | | | [Directory](../features/directory.md)           | No        | | ||||||
| | Identity       | Yes        | | | [Identity](../features/identity.md)             | Yes       | | ||||||
| | Profile        | No         | | | [Profile](../features/profile.md)               | No        | | ||||||
|  |  | ||||||
| ## Requirements | ## Requirements | ||||||
| This backend requires a suitable Matrix client capable of performing Firebase authentication and passing the following | This backend requires a suitable Matrix client capable of performing Firebase authentication and passing the following | ||||||
| @@ -19,35 +19,41 @@ If your client is Riot, you will need a custom version. | |||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| ```yaml | ```yaml | ||||||
| firebase.enabled: <boolean> | firebase: | ||||||
|  |   enabled: <boolean> | ||||||
| ``` | ``` | ||||||
| Enable/disable this identity store. | Enable/disable this identity store. | ||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| firebase.enabled: <boolean> | firebase: | ||||||
|  |   enabled: <boolean> | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| firebase.credentials: <string> | firebase: | ||||||
|  |   credentials: <string> | ||||||
| ``` | ``` | ||||||
| Path to the credentials file provided by Google Firebase to use with an external app. | Path to the credentials file provided by Google Firebase to use with an external app. | ||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| firebase.credentials: '/path/to/firebase/credentials.json' | firebase: | ||||||
|  |   credentials: '/path/to/firebase/credentials.json' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| firebase.database: <string> | firebase: | ||||||
|  |   database: <string> | ||||||
| ``` | ``` | ||||||
| URL to your Firebase database. | URL to your Firebase database. | ||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| firebase.database: 'https://my-project.firebaseio.com/' | firebase: | ||||||
|  |   database: 'https://my-project.firebaseio.com/' | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -8,37 +8,45 @@ | |||||||
| For NetIQ, replace all the `ldap` prefix in the configuration by `netiq`. | For NetIQ, replace all the `ldap` prefix in the configuration by `netiq`. | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| |      Name      | Supported? | | |                       Name                      | Supported | | ||||||
| |----------------|------------| | |-------------------------------------------------|-----------| | ||||||
| | Authentication | Yes        | | | [Authentication](../features/authentication.md) | Yes       | | ||||||
| | Directory      | Yes        | | | [Directory](../features/directory.md)           | Yes       | | ||||||
| | Identity       | Yes        | | | [Identity](../features/identity.md)             | Yes       | | ||||||
| | Profile        | Yes        | | | [Profile](../features/profile.md)               | Yes       | | ||||||
|  |  | ||||||
| ## Getting started | ## Getting started | ||||||
| ### Base | ### Base | ||||||
| To use your LDAP backend, add the bare minimum configuration in mxisd config file: | To use your LDAP backend, add the bare minimum configuration in ma1sd config file: | ||||||
| ```yaml | ```yaml | ||||||
| ldap.enabled: true | ldap: | ||||||
| ldap.connection.host: 'ldapHostnameOrIp' |   enabled: true | ||||||
| ldap.connection.port: 389 |   connection: | ||||||
| ldap.connection.bindDn: 'CN=My Mxisd User,OU=Users,DC=example,DC=org' |     host: 'ldapHostnameOrIp' | ||||||
| ldap.connection.bindPassword: 'TheUserPassword' |     port: 389 | ||||||
| ldap.connection.baseDn: 'OU=Users,DC=example,DC=org' |     bindDn: 'CN=My User,OU=Users,DC=example,DC=org' | ||||||
|  |     bindPassword: 'TheUserPassword' | ||||||
|  |     baseDNs: | ||||||
|  |       - 'OU=Users,DC=example,DC=org' | ||||||
| ``` | ``` | ||||||
| These are standard LDAP connection configuration. mxisd will try to connect on port default port 389 without encryption. | These are standard LDAP connection configuration. ma1sd will try to connect on port default port 389 without encryption. | ||||||
|  |  | ||||||
|  | If you would like to use several Base DNs, simply add more entries under `baseDNs`. | ||||||
|  |  | ||||||
| ### TLS/SSL connection | ### TLS/SSL connection | ||||||
| If you would like to use a TLS/SSL connection, use the following configuration options (STARTLS not supported): | If you would like to use a TLS/SSL connection, use the following configuration options (STARTLS not supported): | ||||||
| ```yaml | ```yaml | ||||||
| ldap.connection.tls: true | ldap: | ||||||
| ldap.connection.port: 12345 |   connection: | ||||||
|  |     tls: true | ||||||
|  |     port: 12345 | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Filter results | ### Filter results | ||||||
| You can also set a default global filter on any LDAP queries: | You can also set a default global filter on any LDAP queries: | ||||||
| ```yaml | ```yaml | ||||||
| ldap.filter: '(memberOf=CN=My Matrix Users,OU=Groups,DC=example,DC=org)' | ldap: | ||||||
|  |   filter: '(memberOf=CN=My Matrix Users,OU=Groups,DC=example,DC=org)' | ||||||
| ``` | ``` | ||||||
| This example would only return users part of the group called `My Matrix Users`. | This example would only return users part of the group called `My Matrix Users`. | ||||||
| This can be overwritten or append in each specific flow describe below. | This can be overwritten or append in each specific flow describe below. | ||||||
| @@ -61,8 +69,11 @@ most certainly configure those mappings. | |||||||
|  |  | ||||||
| The following example would set the `sAMAccountName` attribute as a Matrix User ID localpart: | The following example would set the `sAMAccountName` attribute as a Matrix User ID localpart: | ||||||
| ```yaml | ```yaml | ||||||
| ldap.attribute.uid.type: 'uid' | ldap: | ||||||
| ldap.attribute.uid.value: 'sAMAccountName' |   attribute: | ||||||
|  |     uid: | ||||||
|  |       type: 'uid' | ||||||
|  |       value: 'sAMAccountName' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Display name | #### Display name | ||||||
| @@ -70,22 +81,26 @@ Use `ldap.attribute.name`. | |||||||
|  |  | ||||||
| The following example would set the display name to the value of the `cn` attribute: | The following example would set the display name to the value of the `cn` attribute: | ||||||
| ```yaml | ```yaml | ||||||
| ldap.attribute.name: 'cn' | ldap: | ||||||
|  |   attribute: | ||||||
|  |     name: 'cn' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### 3PIDs | #### 3PIDs | ||||||
| You can also change the attribute lists for 3PID, like email or phone numbers. | You can also change the attribute lists for 3PID, like email or phone numbers. | ||||||
|  |  | ||||||
| The following example would overwrite the [default list of attributes](../../src/main/resources/application.yaml#L67) | The following example would overwrite the [default list of attributes](../../src/main/java/io/kamax/ma1sd/config/ldap/LdapConfig.java#L64) | ||||||
| for emails and phone number: | for emails and phone number: | ||||||
| ```yaml | ```yaml | ||||||
| ldap.attribute.threepid.email: | ldap: | ||||||
|   - 'mail' |   attribute: | ||||||
|   - 'otherMailAttribute' |     threepid: | ||||||
|  |       email: | ||||||
| ldap.attribute.threepid.msisdn: |         - 'mail' | ||||||
|   - 'phone' |         - 'otherMailAttribute' | ||||||
|   - 'otherPhoneAttribute' |       msisdn: | ||||||
|  |         - 'phone' | ||||||
|  |         - 'otherPhoneAttribute' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| @@ -98,24 +113,29 @@ configuration item is needed to get started. | |||||||
| - `ldap.identity.medium`: Namespace to overwrite generated queries from the list of attributes for each 3PID medium. | - `ldap.identity.medium`: Namespace to overwrite generated queries from the list of attributes for each 3PID medium. | ||||||
|  |  | ||||||
| ### Authentication | ### Authentication | ||||||
| No further configuration is needed to use the Authentication feature with LDAP once globally enabled and configured. | After you have configured and enabled the [feature itself](../features/authentication.md), no further configuration is | ||||||
|  | needed with this identity store to make it work. | ||||||
|  |  | ||||||
| Profile auto-fill is enabled by default. It will use the `ldap.attribute.name` and `ldap.attribute.threepid` configuration | Profile auto-fill is enabled by default. It will use the `ldap.attribute.name` and `ldap.attribute.threepid` configuration | ||||||
| options to get a lit of attributes to be used to build the user profile to pass on to synapse during authentication. | options to get a lit of attributes to be used to build the user profile to pass on to synapse during authentication. | ||||||
|  |  | ||||||
| #### Configuration | #### Configuration | ||||||
| - `ldap.auth.filter`: Specific user filter applied during identity search. Global filter is used if blank/not set. | - `ldap.auth.filter`: Specific user filter applied during username search. Global filter is used if blank/not set. | ||||||
|  |  | ||||||
| ### Directory | ### Directory | ||||||
| No further configuration is needed to use the Directory feature with LDAP once globally enabled and configured. | After you have configured and enabled the [feature itself](../features/directory.md), no further configuration is | ||||||
|  | needed with this identity store to make it work. | ||||||
|  |  | ||||||
| #### Configuration | #### Configuration | ||||||
| To set a specific filter applied during directory search, use `ldap.directory.filter` | To set a specific filter applied during directory search, use `ldap.directory.filter` | ||||||
|  |  | ||||||
| If you would like to use extra attributes in search that are not 3PIDs, like nicknames, group names, employee number: | If you would like to use extra attributes in search that are not 3PIDs, like nicknames, group names, employee number: | ||||||
| ```yaml | ```yaml | ||||||
| ldap.directory.attribute.other: | ldap: | ||||||
|   - 'myNicknameAttribute' |   directory: | ||||||
|   - 'memberOf' |     attribute: | ||||||
|   - 'employeeNumberAttribute' |       other: | ||||||
|  |         - 'myNicknameAttribute' | ||||||
|  |         - 'memberOf' | ||||||
|  |         - 'employeeNumberAttribute' | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -3,38 +3,45 @@ The REST backend allows you to query identity data in existing webapps, like: | |||||||
| - Forums (phpBB, Discourse, etc.) | - Forums (phpBB, Discourse, etc.) | ||||||
| - Custom Identity stores (Keycloak, ...) | - Custom Identity stores (Keycloak, ...) | ||||||
| - CRMs (Wordpress, ...) | - CRMs (Wordpress, ...) | ||||||
| - self-hosted clouds (Nextcloud, ownCloud, ...) | - Self-hosted clouds (Nextcloud, ownCloud, ...) | ||||||
|  |  | ||||||
| To integrate this backend with your webapp, you will need to implement three specific REST endpoints detailed below. | To integrate this backend with your webapp, you will need to implement the REST endpoints described below. | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| |      Name      | Supported? | | | Name                                            | Supported? | | ||||||
| |----------------|------------| | |-------------------------------------------------|------------| | ||||||
| | Authentication | Yes        | | | [Authentication](../features/authentication.md) | Yes        | | ||||||
| | Directory      | Yes        | | | [Directory](../features/directory.md)           | Yes        | | ||||||
| | Identity       | Yes        | | | [Identity](../features/identity.md)             | Yes        | | ||||||
| | Profile        | No         | | | [Profile](../features/profile.md)               | Yes        | | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| | Key                              | Default                                        | Description                                          | | | Key                                  | Default                                        | Description                                          | | ||||||
| |----------------------------------|------------------------------------------------|------------------------------------------------------| | |--------------------------------------|------------------------------------------------|------------------------------------------------------| | ||||||
| | `rest.enabled`                   | `false`                                        | Globally enable/disable the REST backend             | | | `rest.enabled`                       | `false`                                        | Globally enable/disable the REST backend             | | ||||||
| | `rest.host`                      | *None*                                        | Default base URL to use for the different endpoints. | | | `rest.host`                          | *None*                                         | Default base URL to use for the different endpoints. | | ||||||
| | `rest.endpoints.auth`            | `/_mxisd/backend/api/v1/auth/login`            | Validate credentials and get user profile            | | | `rest.endpoints.auth`                | `/_ma1sd/backend/api/v1/auth/login`            | Validate credentials and get user profile            | | ||||||
| | `rest.endpoints.directory`       | `/_mxisd/backend/api/v1/directory/user/search` | Search for users by arbitrary input                  | | | `rest.endpoints.directory`           | `/_ma1sd/backend/api/v1/directory/user/search` | Search for users by arbitrary input                  | | ||||||
| | `rest.endpoints.identity.single` | `/_mxisd/backend/api/v1/identity/single`       | Endpoint to query a single 3PID                      | | | `rest.endpoints.identity.single`     | `/_ma1sd/backend/api/v1/identity/single`       | Endpoint to query a single 3PID                      | | ||||||
| | `rest.endpoints.identity.bulk`   | `/_mxisd/backend/api/v1/identity/bulk`         | Endpoint to query a list of 3PID                     | | | `rest.endpoints.identity.bulk`       | `/_ma1sd/backend/api/v1/identity/bulk`         | Endpoint to query a list of 3PID                     | | ||||||
|  | | `rest.endpoints.profile.displayName` | `/_ma1sd/backend/api/v1/profile/displayName`   | Query the display name for a Matrix ID | ||||||
|  | | `rest.endpoints.profile.threepids`   | `/_ma1sd/backend/api/v1/profile/threepids`     | Query the 3PIDs for a Matrix ID | ||||||
|  | | `rest.endpoints.profile.roles`       | `/_ma1sd/backend/api/v1/profile/roles`         | Query the Roles for a Matrix ID | ||||||
|  |  | ||||||
| Endpoint values can handle two formats: | Endpoint values can handle two formats: | ||||||
| - URL Path starting with `/` that gets happened to the `rest.host` | - URL Path starting with `/` that gets happened to the `rest.host` | ||||||
| - Full URL, if you want each endpoint to go to a specific server/protocol/port | - Full URL, if you want each endpoint to go to a specific server/protocol/port | ||||||
|  |  | ||||||
|  | If an endpoint value is configured as an empty string, it will disable that specific feature, essentially bypassing the | ||||||
|  | Identity store for that specific query. | ||||||
|  |  | ||||||
| `rest.host` is mandatory if at least one endpoint is not a full URL. | `rest.host` is mandatory if at least one endpoint is not a full URL. | ||||||
|  |  | ||||||
| ## Endpoints | ## Endpoints | ||||||
| ### Authentication | ### Authentication | ||||||
| HTTP method: `POST`   | - Method: `POST` | ||||||
| Content-type: JSON UTF-8 | - Content-Type: `application/json` (JSON) | ||||||
|  | - Encoding: `UTF8` | ||||||
|    |    | ||||||
| #### Request Body | #### Request Body | ||||||
| ```json | ```json | ||||||
| @@ -87,8 +94,9 @@ If the authentication succeed: | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Directory | ### Directory | ||||||
| HTTP method: `POST` | - Method: `POST` | ||||||
| Content-type: JSON UTF-8 | - Content-Type: `application/json` (JSON) | ||||||
|  | - Encoding: `UTF8` | ||||||
|  |  | ||||||
| #### Request Body | #### Request Body | ||||||
| ```json | ```json | ||||||
| @@ -113,7 +121,7 @@ If users found: | |||||||
|       "user_id": "UserIdLocalpart" |       "user_id": "UserIdLocalpart" | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|       ... |       "...": "..." | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
| @@ -129,10 +137,11 @@ If no user found: | |||||||
|  |  | ||||||
| ### Identity | ### Identity | ||||||
| #### Single 3PID lookup | #### Single 3PID lookup | ||||||
| HTTP method: `POST`   | - Method: `POST` | ||||||
| Content-type: JSON UTF-8   | - Content-Type: `application/json` (JSON) | ||||||
|  | - Encoding: `UTF8` | ||||||
|    |    | ||||||
| #### Request Body | ##### Request Body | ||||||
| ```json | ```json | ||||||
| { | { | ||||||
|   "lookup": { |   "lookup": { | ||||||
| @@ -142,7 +151,7 @@ Content-type: JSON UTF-8 | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Response Body | ##### Response Body | ||||||
| If a match was found: | If a match was found: | ||||||
| - `lookup.id.type` supported values: `localpart`, `mxid` | - `lookup.id.type` supported values: `localpart`, `mxid` | ||||||
| ```json | ```json | ||||||
| @@ -164,10 +173,11 @@ If no match was found: | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Bulk 3PID lookup | #### Bulk 3PID lookup | ||||||
| HTTP method: `POST`   | - Method: `POST` | ||||||
| Content-type: JSON UTF-8   | - Content-Type: `application/json` (JSON) | ||||||
|  | - Encoding: `UTF8` | ||||||
|    |    | ||||||
| #### Request Body | ##### Request Body | ||||||
| ```json | ```json | ||||||
| { | { | ||||||
|   "lookup": [ |   "lookup": [ | ||||||
| @@ -183,7 +193,7 @@ Content-type: JSON UTF-8 | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| #### Response Body | ##### Response Body | ||||||
| For all entries where a match was found: | For all entries where a match was found: | ||||||
| - `lookup[].id.type` supported values: `localpart`, `mxid` | - `lookup[].id.type` supported values: `localpart`, `mxid` | ||||||
| ```json | ```json | ||||||
| @@ -215,3 +225,53 @@ If no match was found: | |||||||
|   "lookup": [] |   "lookup": [] | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ### Profile | ||||||
|  | #### Request Body | ||||||
|  | For all requests, the values are the same: | ||||||
|  | - Method: `POST` | ||||||
|  | - Content-Type: `application/json` (JSON) | ||||||
|  | - Encoding: `UTF8` | ||||||
|  |  | ||||||
|  | With body (example values): | ||||||
|  | ##### Request Body | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |     "mxid": "@john.doe:example.org", | ||||||
|  |     "localpart": "john.doe", | ||||||
|  |     "domain": "example.org" | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | #### Response Body | ||||||
|  | For all responses, the same object structure will be parsed, making the non-relevant fields as optional. | ||||||
|  |  | ||||||
|  | Structure with example values: | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |   "profile": { | ||||||
|  |     "display_name": "John Doe", | ||||||
|  |     "threepids": [ | ||||||
|  |       { | ||||||
|  |         "medium": "email", | ||||||
|  |         "address": "john.doe@example.org" | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "...": "..." | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     "roles": [ | ||||||
|  |       "DomainUsers", | ||||||
|  |       "SalesOrg", | ||||||
|  |       "..." | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | The base `profile` key is mandatory. `display_name`, `threepids` and `roles` are only to be returned on the relevant request. | ||||||
|  |  | ||||||
|  | If there is no profile, the following response is expected: | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |   "profile": {} | ||||||
|  | } | ||||||
|  | ``` | ||||||
|   | |||||||
| @@ -6,28 +6,30 @@ | |||||||
| - SQLite | - SQLite | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| |      Name      | Supported? | | |                       Name                      | Supported | | ||||||
| |----------------|------------| | |-------------------------------------------------|-----------| | ||||||
| | Authentication | No         | | | [Authentication](../features/authentication.md) | No        | | ||||||
| | Directory      | Yes        | | | [Directory](../features/directory.md)           | Yes       | | ||||||
| | Identity       | Yes        | | | [Identity](../features/identity.md)             | Yes       | | ||||||
| | Profile        | Yes        | | | [Profile](../features/profile.md)               | Yes       | | ||||||
|  |  | ||||||
| Due to the implementation complexity of supporting arbitrary hashing/encoding mechanisms or auth flow, Authentication | Due to the implementation complexity of supporting arbitrary hashing/encoding mechanisms or auth flow, Authentication | ||||||
| will be out of scope of SQL Identity stores and should be done via one of the other identity stores, typically | will be out of scope of SQL Identity stores and should be done via one of the other identity stores, typically | ||||||
| the [REST Identity store](rest.md). | the [Exec Identity Store](exec.md) or the [REST Identity Store](rest.md). | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| ### Basic | ### Basic | ||||||
| ```yaml | ```yaml | ||||||
| sql.enabled: <boolean> | sql: | ||||||
|  |   enabled: <boolean> | ||||||
| ``` | ``` | ||||||
| Enable/disable the identity store | Enable/disable the identity store | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| sql.type: <string> | sql: | ||||||
|  |   type: <string> | ||||||
| ``` | ``` | ||||||
| Set the SQL backend to use: | Set the SQL backend to use: | ||||||
| - `sqlite` | - `sqlite` | ||||||
| @@ -38,14 +40,16 @@ Set the SQL backend to use: | |||||||
| ### Connection | ### Connection | ||||||
| #### SQLite | #### SQLite | ||||||
| ```yaml | ```yaml | ||||||
| sql.connection: <string> | sql: | ||||||
|  |   connection: <string> | ||||||
| ``` | ``` | ||||||
| Set the value to the absolute path to the Synapse SQLite DB file. | Set the value to the absolute path to the Synapse SQLite DB file. | ||||||
| Example: `/path/to/sqlite/file.db` | Example: `/path/to/sqlite/file.db` | ||||||
|  |  | ||||||
| #### Others | #### Others | ||||||
| ```yaml | ```yaml | ||||||
| sql.connection: //<HOST[:PORT]/DB?user=USER&password=PASS | sql: | ||||||
|  |   connection: //<HOST[:PORT]/DB?user=USER&password=PASS | ||||||
| ``` | ``` | ||||||
| Set the connection info for the database by replacing the following values: | Set the connection info for the database by replacing the following values: | ||||||
| - `HOST`: Hostname of the SQL server | - `HOST`: Hostname of the SQL server | ||||||
| @@ -58,22 +62,25 @@ This follow the JDBC URI syntax. See [official website](https://docs.oracle.com/ | |||||||
|  |  | ||||||
| ### Directory | ### Directory | ||||||
| ```yaml | ```yaml | ||||||
| sql.directory.enabled: false | sql: | ||||||
|  |   directory: | ||||||
|  |     enabled: false | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| sql.directory.query: | sql: | ||||||
|   name: |   directory: | ||||||
|     type: <string> |     query: | ||||||
|     value: <string> |       name: | ||||||
|   threepid: |         type: <string> | ||||||
|     type: <string> |         value: <string> | ||||||
|     value: <string> |       threepid: | ||||||
|  |         type: <string> | ||||||
|  |         value: <string> | ||||||
| ``` | ``` | ||||||
| For each query, `type` can be used to tell mxisd how to process the ID column: | For each query, `type` can be used to tell ma1sd how to process the ID column: | ||||||
| - `localpart` will append the `matrix.domain` to it | - `localpart` will append the `matrix.domain` to it | ||||||
| - `mxid` will use the ID as-is. If it is not a valid Matrix ID, the search will fail. | - `mxid` will use the ID as-is. If it is not a valid Matrix ID, the search will fail. | ||||||
|  |  | ||||||
| @@ -83,17 +90,53 @@ For each query, `type` can be used to tell mxisd how to process the ID column: | |||||||
|  |  | ||||||
| Example: | Example: | ||||||
| ```yaml | ```yaml | ||||||
| sql.directory.query: | sql: | ||||||
|   name: |   directory: | ||||||
|     type: 'localpart' |     query: | ||||||
|     value: 'SELECT idColumn, displayNameColumn FROM table WHERE displayNameColumn LIKE ?' |       name: | ||||||
|   threepid: |         type: 'localpart' | ||||||
|     type: 'localpart' |         value: 'SELECT idColumn, displayNameColumn FROM table WHERE displayNameColumn LIKE ?' | ||||||
|     value: 'SELECT idColumn, displayNameColumn FROM table WHERE threepidColumn LIKE ?' |       threepid: | ||||||
|  |         type: 'localpart' | ||||||
|  |         value: 'SELECT idColumn, displayNameColumn FROM table WHERE threepidColumn LIKE ?' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| ### Identity | ### Identity | ||||||
|  | **NOTE**: Only single lookup is supported. Bulk lookup always returns no mapping. This is a restriction as the Matrix API | ||||||
|  | does not allow paging or otherwise limit of results of the API, potentially leading to thousands and thousands 3PIDs at once. | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| sql.identity.type: <string> | sql: | ||||||
| sql.identity.query: <string> |   identity: | ||||||
|  |     enabled: <boolean> | ||||||
|  |     type: <string> | ||||||
|  |     query: <string> | ||||||
|  |     medium: | ||||||
|  |      mediumTypeExample: <dedicated query> | ||||||
| ``` | ``` | ||||||
|  | `type` is used to tell ma1sd how to process the returned `uid` column containing the User ID: | ||||||
|  | - `localpart` will build a full Matrix ID using the `matrix.domain` value. | ||||||
|  | - `mxid` will use the ID as-is. If it is not a valid Matrix ID, lookup(s) will fail. | ||||||
|  |  | ||||||
|  | A specific query can also given per 3PID medium type. | ||||||
|  |  | ||||||
|  | ### Profile | ||||||
|  | ```yaml | ||||||
|  | sql: | ||||||
|  |   profile: | ||||||
|  |     enabled: <boolean> | ||||||
|  |     displayName: | ||||||
|  |       query: <string> | ||||||
|  |     threepid: | ||||||
|  |       query: <string> | ||||||
|  |     role: | ||||||
|  |       type: <string> | ||||||
|  |       query: <string> | ||||||
|  |      | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | For the `role` query, `type` can be used to tell ma1sd how to inject the User ID in the query: | ||||||
|  | - `localpart` will extract and set only the localpart. | ||||||
|  | - `mxid` will use the ID as-is. | ||||||
|  |  | ||||||
|  | On each query, the first parameter `?` is set as a string with the corresponding ID format. | ||||||
|   | |||||||
| @@ -1,27 +1,31 @@ | |||||||
| # Synapse Identity Store | # Synapse Identity Store | ||||||
| Synapse's Database itself can be used as an Identity store. | Synapse's Database itself can be used as an Identity store. This identity store is a regular SQL store with | ||||||
|  | built-in default queries that matches Synapse DB. | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| |      Name      | Supported? | | |                       Name                      | Supported | | ||||||
| |----------------|------------| | |-------------------------------------------------|-----------| | ||||||
| | Authentication | No         | | | [Authentication](../features/authentication.md) | No        | | ||||||
| | Directory      | Yes        | | | [Directory](../features/directory.md)           | Yes       | | ||||||
| | Identity       | Yes        | | | [Identity](../features/identity.md)             | Yes       | | ||||||
| | Profile        | Yes        | | | [Profile](../features/profile.md)               | Yes       | | ||||||
|  |  | ||||||
| Authentication is done by Synapse itself. | - Authentication is done by Synapse itself. | ||||||
|  | - Roles are mapped to communities. The Role name/ID uses the community ID in the form `+id:domain.tld` | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| ### Basic | ### Basic | ||||||
| ```yaml | ```yaml | ||||||
| synapseSql.enabled: <boolean> | synapseSql: | ||||||
|  |   enabled: <boolean> | ||||||
| ``` | ``` | ||||||
| Enable/disable the identity store | Enable/disable the identity store | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| synapseSql.type: <string> | synapseSql: | ||||||
|  |   type: <string> | ||||||
| ``` | ``` | ||||||
| Set the SQL backend to use which is configured in synapse: | Set the SQL backend to use which is configured in synapse: | ||||||
| - `sqlite` | - `sqlite` | ||||||
| @@ -29,14 +33,16 @@ Set the SQL backend to use which is configured in synapse: | |||||||
|  |  | ||||||
| ### SQLite | ### SQLite | ||||||
| ```yaml | ```yaml | ||||||
| synapseSql.connection: <string> | synapseSql: | ||||||
|  |   connection: <string> | ||||||
| ``` | ``` | ||||||
| Set the value to the absolute path to the Synapse SQLite DB file. | Set the value to the absolute path to the Synapse SQLite DB file. | ||||||
| Example: `/path/to/synapse/sqliteFile.db` | Example: `/path/to/synapse/sqliteFile.db` | ||||||
|  |  | ||||||
| ### PostgreSQL | ### PostgreSQL | ||||||
| ```yaml | ```yaml | ||||||
| synapseSql.connection: //<HOST[:PORT]/DB?user=USER&password=PASS | synapseSql: | ||||||
|  |   connection: //<HOST[:PORT]/DB?user=USER&password=PASS | ||||||
| ``` | ``` | ||||||
| Set the connection info for the database by replacing the following values: | Set the connection info for the database by replacing the following values: | ||||||
| - `HOST`: Hostname of the SQL server | - `HOST`: Hostname of the SQL server | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ Two types of connections are required for full support: | |||||||
| - Direct SQL access | - Direct SQL access | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| |      Name      | Supported? | | |                       Name                      | Supported | | ||||||
| |----------------|------------| | |-------------------------------------------------|-----------| | ||||||
| | Authentication | Yes        | | | [Authentication](../features/authentication.md) | Yes       | | ||||||
| | Directory      | Yes        | | | [Directory](../features/directory.md)           | Yes       | | ||||||
| | Identity       | Yes        | | | [Identity](../features/identity.md)             | Yes       | | ||||||
| | Profile        | No         | | | [Profile](../features/profile.md)               | No        | | ||||||
|  |  | ||||||
| ## Requirements | ## Requirements | ||||||
| - [Wordpress](https://wordpress.org/download/) >= 4.4 | - [Wordpress](https://wordpress.org/download/) >= 4.4 | ||||||
| @@ -29,27 +29,34 @@ define('JWT_AUTH_SECRET_KEY', 'your-top-secret-key'); | |||||||
|  |  | ||||||
| #### Rewrite of `index.php` | #### Rewrite of `index.php` | ||||||
| Wordpress is normally configured with rewrite of `index.php` so it does not appear in URLs.   | Wordpress is normally configured with rewrite of `index.php` so it does not appear in URLs.   | ||||||
| If this is not the case for your installation, the mxisd URL will need to be appended with `/index.php` | If this is not the case for your installation, the ma1sd URL will need to be appended with `/index.php` | ||||||
|  |  | ||||||
| ### mxisd | ### ma1sd | ||||||
| Enable in the configuration: | Enable in the configuration: | ||||||
| ```yaml | ```yaml | ||||||
| wordpress.enabled: true | wordpress: | ||||||
|  |   enabled: true | ||||||
| ``` | ``` | ||||||
| Configure the URL to your Wordpress installation - see above about added `/index.php`: | Configure the URL to your Wordpress installation - see above about added `/index.php`: | ||||||
| ```yaml | ```yaml | ||||||
| wordpress.rest.base: 'http://localhost:8080' | wordpress: | ||||||
|  |   rest: | ||||||
|  |     base: 'http://localhost:8080' | ||||||
| ``` | ``` | ||||||
| Configure the SQL connection to your Wordpress database: | Configure the SQL connection to your Wordpress database: | ||||||
| ```yaml | ```yaml | ||||||
| wordpress.sql.connection: '//127.0.0.1/wordpress?user=root&password=example' | wordpress: | ||||||
|  |   sql: | ||||||
|  |     connection: '//127.0.0.1/wordpress?user=root&password=example' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
| By default, MySQL database is expected. If you use another database, use: | By default, MySQL database is expected. If you use another database, use: | ||||||
| ```yaml | ```yaml | ||||||
| wordpress.sql.type: <string> | wordpress: | ||||||
|  |   sql: | ||||||
|  |     type: <string> | ||||||
| ``` | ``` | ||||||
| With possible values: | With possible values: | ||||||
| - `mysql` | - `mysql` | ||||||
| @@ -61,6 +68,8 @@ With possible values: | |||||||
|  |  | ||||||
| To configure the tables prefix for default queries, in case a custom value was set during Wordpress install: | To configure the tables prefix for default queries, in case a custom value was set during Wordpress install: | ||||||
| ```yaml | ```yaml | ||||||
| wordpress.sql.tablePrefix: <string> | wordpress: | ||||||
|  |   sql: | ||||||
|  |     tablePrefix: <string> | ||||||
| ``` | ``` | ||||||
| By default, the value is set to `wp_`. | By default, the value is set to `wp_`. | ||||||
|   | |||||||
| @@ -1,19 +1,19 @@ | |||||||
| # Email notifications - SMTP connector | # Email notifications - SMTP connector | ||||||
| Enabled by default. |  | ||||||
|  |  | ||||||
| Connector ID: `smtp` | Connector ID: `smtp` | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| ```yaml | ```yaml | ||||||
| threepid.medium.email: | threepid: | ||||||
|   identity: |   medium: | ||||||
|     from: 'identityServerEmail@example.org' |     email: | ||||||
|     name: 'My Identity Server' |       identity: | ||||||
|   connectors: |         from: 'identityServerEmail@example.org' | ||||||
|     smtp: |         name: 'My Identity Server' | ||||||
|       host: 'smtpHostname' |       connectors: | ||||||
|       port: 587 |         smtp: | ||||||
|       tls: 1 # 0 = no STARTLS, 1 = try, 2 = force |           host: 'smtpHostname' | ||||||
|       login: 'smtpLogin' |           tls: 1 # 0 = no STARTLS, 1 = try, 2 = force, 3 = TLS/SSL | ||||||
|       password: 'smtpPassword' |           port: 587 # Set appropriate value depending on your TLS setting | ||||||
|  |           login: 'smtpLogin' | ||||||
|  |           password: 'smtpPassword' | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -1,11 +1,14 @@ | |||||||
| # SMS notifications - Twilio connector | # SMS notifications - Twilio connector | ||||||
| Enabled by default. |  | ||||||
|  |  | ||||||
| Connector ID: `twilio` | Connector ID: `twilio` | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| ```yaml | ```yaml | ||||||
| threepid.medium.msisdn.connectors.twilio.accountSid: 'myAccountSid' | threepid: | ||||||
| threepid.medium.msisdn.connectors.twilio.authToken: 'myAuthToken' |   medium: | ||||||
| threepid.medium.msisdn.connectors.twilio.number: '+123456789' |     msisdn: | ||||||
|  |       connectors: | ||||||
|  |         twilio: | ||||||
|  |           account_sid: 'myAccountSid' | ||||||
|  |           auth_token: 'myAuthToken' | ||||||
|  |           number: '+123456789' | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -18,20 +18,23 @@ This handler can be used with the 3PID types: | |||||||
| ## Configuration | ## Configuration | ||||||
| Enabled by default or with: | Enabled by default or with: | ||||||
| ```yaml | ```yaml | ||||||
| notification.handler.email: 'raw' | notification: | ||||||
|  |   handler: | ||||||
|  |     email: 'raw' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| **WARNING:** Will be consolidated soon, prone to breaking changes.   | **WARNING:** Will be consolidated soon, prone to breaking changes.   | ||||||
| Structure and default values: | Structure and default values: | ||||||
| ```yaml | ```yaml | ||||||
| threepid.medium: | threepid: | ||||||
|   email: |   medium: | ||||||
|     identity: |     email: | ||||||
|       from: '' |       identity: | ||||||
|       name: '' |         from: '' | ||||||
|     connector: 'smtp' |         name: '' | ||||||
|     generator: 'template' |       connector: 'smtp' | ||||||
|   msisdn: |       generator: 'template' | ||||||
|     connector: 'twilio' |     msisdn: | ||||||
|     generator: 'template' |       connector: 'twilio' | ||||||
|  |       generator: 'template' | ||||||
| ``` | ``` | ||||||
|   | |||||||
| @@ -1,7 +1,39 @@ | |||||||
| # SendGrid Notification handler | # SendGrid Notification handler | ||||||
| To be completed. See [raw possible configuration items](https://github.com/kamax-matrix/mxisd/blob/master/src/main/resources/application.yaml#L172). | > **WARNING:** This section is incomplete and may be misleading. Contact us if guidance is needed. | ||||||
|  |  | ||||||
| Enabled with: | Enable with: | ||||||
| ```yaml | ```yaml | ||||||
| notification.handler.email: 'sendgrid' | notification: | ||||||
|  |   handler: | ||||||
|  |     email: 'sendgrid' | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | Available Configuration keys: | ||||||
|  | ```yaml | ||||||
|  | notification: | ||||||
|  |   handlers: | ||||||
|  |     sendgrid: | ||||||
|  |       api: | ||||||
|  |         key: <API key> | ||||||
|  |       identity: | ||||||
|  |         from: <Sender email address> | ||||||
|  |         name: <Sender name> | ||||||
|  |       templates: | ||||||
|  |         invite: | ||||||
|  |           subject: <Subject of the email notification sent for room invites> | ||||||
|  |           body: | ||||||
|  |             text: <Path to file containing the raw text part of the email. Do not set to not use one> | ||||||
|  |             html: <Path to file containing the HTML part of the email. Do not set to not use one> | ||||||
|  |         session: | ||||||
|  |           validation: | ||||||
|  |             subject: <Subject of the email notification sent for 3PID sessions> | ||||||
|  |             body: | ||||||
|  |               text: <Path to file containing the raw text part of the email. Do not set to not use one> | ||||||
|  |               html: <Path to file containing the HTML part of the email. Do not set to not use one> | ||||||
|  |           unbind: | ||||||
|  |             notification: | ||||||
|  |               subject: <Subject of the email notification sent for 3PID unbinds> | ||||||
|  |               body: | ||||||
|  |                 text: <Path to file containing the raw text part of the email. Do not set to not use one> | ||||||
|  |                 html: <Path to file containing the raw text part of the email. Do not set to not use one> | ||||||
|  | ```  | ||||||
|   | |||||||
| @@ -1,73 +1,113 @@ | |||||||
| # Notifications: Generate from templates | # Notifications: Template generator | ||||||
| To create notification content, you can use the `template` generator if supported for the 3PID medium which will read | Most of the Identity actions will trigger a notification of some kind, informing the user of some confirmation, next step | ||||||
| content from configured files. | or just informing them about the current state of things. | ||||||
|  |  | ||||||
| Placeholders can be integrated into the templates to dynamically populate such content with relevant information like | Those notifications are by default generated from templates and by replacing placeholder tokens in them with the relevant | ||||||
| the 3PID that was requested, the domain of your Identity server, etc. | values of the notification. It is possible to customize the value of some placeholders, making easy to set values in the builtin templates, and/or | ||||||
|  | provide your own custom templates. | ||||||
|  |  | ||||||
| Templates can be configured for each event that would send a notification to the end user. Events share a set of common | Templates for the following events/actions are available: | ||||||
| placeholders and also have their own individual set of placeholders. | - [3PID invite](../../features/identity.md) | ||||||
|  | - [3PID session: validation](../session/session.md) | ||||||
|  | - [3PID session: unbind](https://github.com/kamax-matrix/ma1sd/wiki/ma1sd-and-your-privacy#improving-your-privacy-one-commit-at-the-time) | ||||||
|  | - [Matrix ID invite](../../features/experimental/application-service.md#email-notification-about-room-invites-by-matrix-ids) | ||||||
|  |  | ||||||
|  | ## Placeholders | ||||||
|  | All placeholders **MUST** be surrounded with `%` in the template. Per example, the `DOMAIN` placeholder would become | ||||||
|  | `%DOMAIN%` within the template. This ensures replacement doesn't happen on non-placeholder strings. | ||||||
|  |  | ||||||
|  | ### Global | ||||||
|  | The following placeholders are available in every template: | ||||||
|  |  | ||||||
|  | | Placeholder                     | Purpose                                                                      | | ||||||
|  | |---------------------------------|------------------------------------------------------------------------------| | ||||||
|  | | `DOMAIN`                        | Identity server authoritative domain, as configured in `matrix.domain`       | | ||||||
|  | | `DOMAIN_PRETTY`                 | Same as `DOMAIN` with the first letter upper case and all other lower case   | | ||||||
|  | | `FROM_EMAIL`                    | Email address configured in `threepid.medium.<3PID medium>.identity.from`    | | ||||||
|  | | `FROM_NAME`                     | Name configured in `threepid.medium.<3PID medium>.identity.name`             | | ||||||
|  | | `RECIPIENT_MEDIUM`              | The 3PID medium, like `email` or `msisdn`                                    | | ||||||
|  | | `RECIPIENT_MEDIUM_URL_ENCODED`  | URL encoded value of `RECIPIENT_MEDIUM`                                      | | ||||||
|  | | `RECIPIENT_ADDRESS`             | The address to which the notification is sent                                | | ||||||
|  | | `RECIPIENT_ADDRESS_URL_ENCODED` | URL encoded value of `RECIPIENT_ADDRESS`                                     | | ||||||
|  |  | ||||||
|  | ### Room invitation | ||||||
|  | Specific placeholders: | ||||||
|  |  | ||||||
|  | | Placeholder                  | Purpose                                                                           | | ||||||
|  | |------------------------------|-----------------------------------------------------------------------------------| | ||||||
|  | | `SENDER_ID`                  | Matrix ID of the user who made the invite                                         | | ||||||
|  | | `SENDER_NAME`                | Display name of the user who made the invite, if not available/set, empty         | | ||||||
|  | | `SENDER_NAME_OR_ID`          | Display name of the user who made the invite. If not available/set, its Matrix ID | | ||||||
|  | | `INVITE_MEDIUM`              | The 3PID medium for the invite.                                                   | | ||||||
|  | | `INVITE_MEDIUM_URL_ENCODED`  | URL encoded value of `INVITE_MEDIUM`                                              | | ||||||
|  | | `INVITE_ADDRESS`             | The 3PID address for the invite.                                                  | | ||||||
|  | | `INVITE_ADDRESS_URL_ENCODED` | URL encoded value of `INVITE_ADDRESS`                                             | | ||||||
|  | | `ROOM_ID`                    | The Matrix ID of the Room in which the invite took place                          | | ||||||
|  | | `ROOM_NAME`                  | The Name of the room in which the invite took place. If not available/set, empty  | | ||||||
|  | | `ROOM_NAME_OR_ID`            | The Name of the room in which the invite took place. If not available/set, its ID | | ||||||
|  | | `REGISTER_URL`               | The URL to provide to the user allowing them to register their account, if needed | | ||||||
|  |  | ||||||
|  | ### Validation of 3PID Session | ||||||
|  | Specific placeholders: | ||||||
|  |  | ||||||
|  | | Placeholder        | Purpose                                                                              | | ||||||
|  | |--------------------|--------------------------------------------------------------------------------------| | ||||||
|  | | `VALIDATION_LINK`  | URL, including token, to validate the 3PID session.                                  | | ||||||
|  | | `VALIDATION_TOKEN` | The token needed to validate the session, in case the user cannot use the link.      | | ||||||
|  | | `NEXT_URL`         | URL to redirect to after the sessions has been validated.                            | | ||||||
|  |  | ||||||
|  | ## Templates | ||||||
|  | ma1sd comes with a set of builtin templates to easily get started. Those templates can be found | ||||||
|  | [in the repository](https://github.com/ma1uta/ma1sd/tree/master/src/main/resources/threepids). If you want to use | ||||||
|  | customized templates, we recommend using the builtin templates as a starting point. | ||||||
|  |  | ||||||
|  | > **NOTE**: The link above point to the latest version of the built-in templates. Those might be different from your | ||||||
|  | version. Be sure to view the repo at the current tag. | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
|  | All configuration is specific to [3PID mediums](https://matrix.org/docs/spec/appendices.html#pid-types) and happen | ||||||
|  | under the namespace `threepid.medium.<medium>.generators.template`. | ||||||
|  |  | ||||||
|  | Under such namespace, the following keys are available: | ||||||
|  | - `invite`: Path to the 3PID invite notification template | ||||||
|  | - `session.validation`: Path to the 3PID session validation notification template | ||||||
|  | - `session.unbind`: Path to the 3PID session unbind notification template | ||||||
|  | - `generic.matrixId`: Path to the Matrix ID invite notification template | ||||||
|  | - `placeholder`: Map of key/values to set static values for some placeholders. | ||||||
|  |  | ||||||
|  | The `placeholder` map supports the following keys, mapped to their respective template placeholders: | ||||||
|  | - `REGISTER_URL` | ||||||
|  |  | ||||||
|  | ### Example | ||||||
|  | #### Simple | ||||||
|  | ```yaml | ||||||
|  | threepid: | ||||||
|  |   medium: | ||||||
|  |     email: | ||||||
|  |       generators: | ||||||
|  |         template: | ||||||
|  |           placeholder: | ||||||
|  |             REGISTER_URL: 'https://matrix-client.example.org' | ||||||
|  | ``` | ||||||
|  | In this configuration, the builtin templates are used and a static value for the `REGISTER_URL` is set, allowing to point | ||||||
|  | a newly invited user to a webapp allowing the creation of its account on the server. | ||||||
|  |  | ||||||
|  | #### Advanced | ||||||
| To configure paths to the various templates: | To configure paths to the various templates: | ||||||
| ```yaml | ```yaml | ||||||
| threepid.medium.<YOUR 3PID MEDIUM HERE>: | threepid: | ||||||
|   generators: |   medium: | ||||||
|     template: |     email: | ||||||
|       invite: '/path/to/invite-template.eml' |       generators: | ||||||
|       session: |         template: | ||||||
|         validation: |           invite: '/path/to/invite-template.eml' | ||||||
|           local: '/path/to/validate-local-template.eml' |           session: | ||||||
|           remote: 'path/to/validate-remote-template.eml' |             validation: '/path/to/validate-template.eml' | ||||||
|       generic: |             unbind: | ||||||
|         matrixId: '/path/to/mxid-invite-template.eml' |               notification: '/path/to/unbind-notification-template.eml' | ||||||
|  |           generic: | ||||||
|  |             matrixId: '/path/to/mxid-invite-template.eml' | ||||||
|  |           placeholder: | ||||||
|  |             REGISTER_URL: 'https://matrix-client.example.org' | ||||||
| ``` | ``` | ||||||
| The `template` generator is usually the default, so no further configuration is needed. | In this configuration, a custom template is used for each event and a static value for the `REGISTER_URL` is set. | ||||||
|  |  | ||||||
| ##  Global placeholders |  | ||||||
| | Placeholder           | Purpose                                                                      | |  | ||||||
| |-----------------------|------------------------------------------------------------------------------| |  | ||||||
| | `%DOMAIN%`            | Identity server authoritative domain, as configured in `matrix.domain`       | |  | ||||||
| | `%DOMAIN_PRETTY%`     | Same as `%DOMAIN%` with the first letter upper case and all other lower case | |  | ||||||
| | `%FROM_EMAIL%`        | Email address configured in `threepid.medium.<3PID medium>.identity.from`    | |  | ||||||
| | `%FROM_NAME%`         | Name configured in `threepid.medium.<3PID medium>.identity.name`             | |  | ||||||
| | `%RECIPIENT_MEDIUM%`  | The 3PID medium, like `email` or `msisdn`                                    | |  | ||||||
| | `%RECIPIENT_ADDRESS%` | The address to which the notification is sent                                | |  | ||||||
|  |  | ||||||
| ## Events |  | ||||||
| ### Room invitation |  | ||||||
| This template is used when someone is invited into a room using an email address which has no known bind to a Matrix ID. |  | ||||||
| #### Placeholders |  | ||||||
| | Placeholder           | Purpose                                                                                  | |  | ||||||
| |-----------------------|------------------------------------------------------------------------------------------| |  | ||||||
| | `%SENDER_ID%`         | Matrix ID of the user who made the invite                                                | |  | ||||||
| | `%SENDER_NAME%`       | Display name of the user who made the invite, if not available/set, empty                | |  | ||||||
| | `%SENDER_NAME_OR_ID%` | Display name of the user who made the invite. If not available/set, its Matrix ID        | |  | ||||||
| | `%INVITE_MEDIUM%`     | The 3PID medium for the invite.                                                          | |  | ||||||
| | `%INVITE_ADDRESS%`    | The 3PID address for the invite.                                                         | |  | ||||||
| | `%ROOM_ID%`           | The Matrix ID of the Room in which the invite took place                                 | |  | ||||||
| | `%ROOM_NAME%`         | The Name of the room in which the invite took place. If not available/set, empty         | |  | ||||||
| | `%ROOM_NAME_OR_ID%`   | The Name of the room in which the invite took place. If not available/set, its Matrix ID | |  | ||||||
|  |  | ||||||
| ### Local validation of 3PID Session |  | ||||||
| This template is used when to user which added their 3PID address to their profile/settings and the session policy |  | ||||||
| allows at least local sessions.   |  | ||||||
|  |  | ||||||
| #### Placeholders |  | ||||||
| | Placeholder          | Purpose                                                                              | |  | ||||||
| |----------------------|--------------------------------------------------------------------------------------| |  | ||||||
| | `%VALIDATION_LINK%`  | URL, including token, to validate the 3PID session.                                  | |  | ||||||
| | `%VALIDATION_TOKEN%` | The token needed to validate the local session, in case the user cannot use the link | |  | ||||||
|  |  | ||||||
| ### Remote validation of 3PID Session |  | ||||||
| This template is used when to user which added their 3PID address to their profile/settings and the session policy only |  | ||||||
| allows remote sessions. |  | ||||||
|  |  | ||||||
| **NOTE:** 3PID session always require local validation of a token, even if a remote session is enforced.   |  | ||||||
| One cannot bind a Matrix ID to the session until both local and remote sessions have been validated. |  | ||||||
|  |  | ||||||
| #### Placeholders |  | ||||||
| | Placeholder          | Purpose                                                | |  | ||||||
| |----------------------|--------------------------------------------------------| |  | ||||||
| | `%VALIDATION_TOKEN%` | The token needed to validate the session               | |  | ||||||
| | `%NEXT_URL%`         | URL to continue with remote validation of the session. | |  | ||||||
|   | |||||||
| @@ -1,86 +1,42 @@ | |||||||
| # Web pages for the 3PID sessions | # Web pages for the 3PID sessions | ||||||
| You can customize the various pages used during a 3PID validation using [Thymeleaf templates](http://www.thymeleaf.org/). | You can customize the various pages used during a 3PID validation using the options below. | ||||||
|  |  | ||||||
| ## Configuration | ## Configuration | ||||||
| Pseudo-configuration to illustrate the structure: | Pseudo-configuration to illustrate the structure: | ||||||
| ```yaml | ```yaml | ||||||
| # CONFIGURATION EXAMPLE | # CONFIGURATION EXAMPLE | ||||||
| # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION | # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION | ||||||
| view.session.local: | view: | ||||||
|   onTokenSubmit: |   session: | ||||||
|     success: '/path/to/session/local/tokenSubmitSuccess-page.html' |     onTokenSubmit: | ||||||
|     failure: '/path/to/session/local/tokenSubmitFailure-page.html' |       success: '/path/to/session/tokenSubmitSuccess-page.html' | ||||||
| view.session.localRemote: |       failure: '/path/to/session/tokenSubmitFailure-page.html' | ||||||
|   onTokenSubmit: |  | ||||||
|     success: '/path/to/session/localRemote/tokenSubmitSuccess-page.html' |  | ||||||
|     failure: '/path/to/session/local/tokenSubmitFailure-page.html' |  | ||||||
| view.session.remote: |  | ||||||
|   onRequest: |  | ||||||
|     success: '/path/to/session/remote/requestSuccess-page.html' |  | ||||||
|     failure: '/path/to/session/remote/requestFailure-page.html' |  | ||||||
|   onCheck: |  | ||||||
|     success: '/path/to/session/remote/checkSuccess-page.html' |  | ||||||
|     failure: '/path/to/session/remote/checkFailure-page.html' |  | ||||||
| # CONFIGURATION EXAMPLE | # CONFIGURATION EXAMPLE | ||||||
| # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION | # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 3PID session are divided into three config sections: | `view.session`: | ||||||
| - `local` for local-only 3PID sessions |  | ||||||
| - `localRemote` for local 3PID sessions that can also be turned into remote sessions, if the user so desires |  | ||||||
| - `remote` for remote-only 3PID sessions |  | ||||||
|  |  | ||||||
| Each section contains a sub-key per support event. Finally, a `success` and `failure` key is available depending on the |  | ||||||
| outcome of the request. |  | ||||||
|  |  | ||||||
| ## Local |  | ||||||
| ### onTokenSubmit |  | ||||||
| This is triggered when a user submit a validation token for a 3PID session. It is typically visited when clicking the | This is triggered when a user submit a validation token for a 3PID session. It is typically visited when clicking the | ||||||
| link in a validation email. | link in a validation email. | ||||||
|  |  | ||||||
| The template should typically inform the user that the validation was successful and to go back in their Matrix client | The template should typically inform the user that the validation was successful and to go back in their Matrix client | ||||||
| to finish the validation process. | to finish the validation process, or that the validation failed. | ||||||
|  |  | ||||||
| #### Placeholders | Two configuration keys are available that accept paths to HTML templates: | ||||||
|  | - `success` | ||||||
|  | - `failure` | ||||||
|  |  | ||||||
|  | ### Serving static assets | ||||||
|  | ma1sd will not serve any static asset (images, JS, CSS, etc.). If such are needed, you will need to serve them using the | ||||||
|  | reverse proxy sitting in front of ma1sd using a path outside of the `/_matrix/identity/` namespace. We advise using | ||||||
|  | the base path `/static/` for such use cases, allowing to remain under the same hostname/origin. | ||||||
|  |  | ||||||
|  | You can also serve such assets using absolute URL, possibly under other domains, but be aware of Cross-Origin restrictions | ||||||
|  | in browsers which are out of scope of ma1sd. | ||||||
|  |  | ||||||
|  | ## Placeholders | ||||||
|  | ### Success | ||||||
| No object/placeholder are currently available. | No object/placeholder are currently available. | ||||||
|  |  | ||||||
| ## Local & Remote | ### Failure | ||||||
| ### onTokenSubmit |  | ||||||
| This is triggered when a user submit a validation token for a 3PID session. It is typically visited when clicking the |  | ||||||
| link in a validation email. |  | ||||||
|  |  | ||||||
| The template should typically inform the user that their 3PID address will not yet be publicly/globally usable. In case |  | ||||||
| they want to make it, they should start a Remote 3PID session with a given link or that they can go back to their Matrix |  | ||||||
| client if they do not wish to proceed any further. |  | ||||||
|  |  | ||||||
| #### Placeholders |  | ||||||
| ##### Success |  | ||||||
| `<a th:href="${remoteSessionLink}">text</a>` can be used to display the link to start a Remote 3PID session. |  | ||||||
|  |  | ||||||
| ##### Failure |  | ||||||
| No object/placeholder are currently available. |  | ||||||
|  |  | ||||||
| ## Remote |  | ||||||
| ### onRequest |  | ||||||
| This is triggered when a user starts a Remote 3PID session, usually from a link produced in the `local.onTokenSubmit` |  | ||||||
| view or in a remote-only 3PID notification. |  | ||||||
|  |  | ||||||
| The template should typically inform the user that the remote creation was successful, followed the instructions sent by |  | ||||||
| the remote Identity server and, once that is done, click a link to validate the session. |  | ||||||
|  |  | ||||||
| #### Placeholders |  | ||||||
| ##### Success |  | ||||||
| `<a th:href="${checkLink}">text</a>` can be used to display the link to validate the Remote 3PID session. |  | ||||||
|  |  | ||||||
| ##### Failure |  | ||||||
| No object/placeholder are currently available. |  | ||||||
|  |  | ||||||
| ### onCheck |  | ||||||
| This is triggered when a user attempts to inform the Identity server that the Remote 3PID session has been validated |  | ||||||
| with the remote Identity server. |  | ||||||
|  |  | ||||||
| The template should typically inform the user that the validation was successful and to go back in their Matrix client |  | ||||||
| to finish the validation process. |  | ||||||
|  |  | ||||||
| #### Placeholders |  | ||||||
| No object/placeholder are currently available. | No object/placeholder are currently available. | ||||||
|   | |||||||
| @@ -1,9 +1,8 @@ | |||||||
| # 3PID Sessions | # 3PID Sessions | ||||||
| - [Overview](#overview) | - [Overview](#overview) | ||||||
| - [Purpose](#purpose) | - [Restrictions](#restrictions) | ||||||
| - [Federation](#federation) |   - [Bindings](#bindings) | ||||||
|   - [3PID scope](#3pid-scope) |   - [Federation](#federation) | ||||||
|   - [Session scope](#session-scope) |  | ||||||
| - [Notifications](#notifications) | - [Notifications](#notifications) | ||||||
|   - [Email](#email) |   - [Email](#email) | ||||||
|   - [Phone numbers](#msisdn-(phone-numbers)) |   - [Phone numbers](#msisdn-(phone-numbers)) | ||||||
| @@ -11,28 +10,39 @@ | |||||||
|   - [Configuration](#configuration) |   - [Configuration](#configuration) | ||||||
|   - [Web views](#web-views) |   - [Web views](#web-views) | ||||||
|   - [Scenarios](#scenarios) |   - [Scenarios](#scenarios) | ||||||
|     - [Default](#default) |  | ||||||
|     - [Local sessions only](#local-sessions-only) |  | ||||||
|     - [Remote sessions only](#remote-sessions-only) |  | ||||||
|     - [Sessions disabled](#sessions-disabled) |     - [Sessions disabled](#sessions-disabled) | ||||||
|  |  | ||||||
| ## Overview | ## Overview | ||||||
| When adding an email, a phone number or any other kind of 3PID (Third-Party Identifier) in a Matrix client, | When adding an email, a phone number or any other kind of 3PID (Third-Party Identifier) in a Matrix client, | ||||||
| the identity server is contacted to validate the 3PID. | the identity server is contacted to validate the 3PID. | ||||||
|  |  | ||||||
| To validate the 3PID the identity server sends a message to the 3PID (e.g. an | To validate the 3PID, the identity server creates a session associated with a secret token. That token is sent via a message | ||||||
| email) with a hyperlink back to a web-page managed by the identity server to | to the 3PID (e.g. an email) with a the necessary info so the user can submit them to the Identity Server, confirm ownership | ||||||
| confirm ownership of the 3PID. | of the 3PID. | ||||||
|  |  | ||||||
| Once this 3PID is validated, the Homeserver will publish the user Matrix ID on the Identity Server and | Once this 3PID is validated, the Homeserver will request that the Identity Server links the provided user Matrix ID with | ||||||
| add this 3PID to the Matrix account which initiated the request. | the 3PID session and finally add the 3PID to its own data store. | ||||||
|  |  | ||||||
| This serves two purposes: | This serves two purposes: | ||||||
| - Add the 3PID as an administrative/login info for the Homeserver directly | - Add the 3PID as an administrative/login info for the Homeserver directly | ||||||
| - Publish, or *Bind*, the 3PID so it can be queried from Homeservers and clients when inviting someone in a room | - Links, called *Bind*, the 3PID so it can be queried from Homeservers and clients when inviting someone in a room | ||||||
| by a 3PID, allowing it to be resolved to a Matrix ID. | by a 3PID, allowing it to be resolved to a Matrix ID. | ||||||
|  |  | ||||||
| ## Federation | ## Restrictions | ||||||
|  | ### Bindings | ||||||
|  | ma1sd does not store bindings directly. While a user can see its email, phone number or any other 3PID in its | ||||||
|  | settings/profile, it does **NOT** mean it is published/saved anywhere or can be used to invite/search the user. | ||||||
|  |  | ||||||
|  | Identity stores are the ones holding such data, irrelevant if a user added a 3PID to their profile. When queried for | ||||||
|  | bindings, ma1sd will query Identity stores which are responsible to store this kind of information. | ||||||
|  |  | ||||||
|  | Therefore, by default, any 3PID added to a user profile which is NOT within a configured and enabled Identity backend | ||||||
|  | will simply not be usable for search or invites, **even on the same Homeserver!**   | ||||||
|  |  | ||||||
|  | To have such 3PID bindings available for search and invite queries on synapse, use its dedicated | ||||||
|  | [Identity store](../../stores/synapse.md). | ||||||
|  |  | ||||||
|  | ### Federation | ||||||
| In a federated set up, identity servers must cooperate to find the Matrix ID associated with a 3PID. | In a federated set up, identity servers must cooperate to find the Matrix ID associated with a 3PID. | ||||||
|  |  | ||||||
| Federation is based on the principle that each server is responsible for its own (dns) domain. | Federation is based on the principle that each server is responsible for its own (dns) domain. | ||||||
| @@ -43,68 +53,22 @@ Example: a user from Homeserver `example.org` adds an email `john@example.com`. | |||||||
| Federated identity servers would try to find the identity server at `example.com` and ask it for the Matrix ID of associated with `john@example.com`. | Federated identity servers would try to find the identity server at `example.com` and ask it for the Matrix ID of associated with `john@example.com`. | ||||||
|  |  | ||||||
| Nevertheless, Matrix users might add 3PIDs that are not associated to a domain, for example telephone numbers. | Nevertheless, Matrix users might add 3PIDs that are not associated to a domain, for example telephone numbers. | ||||||
| Or they might even add 3PIDs associated to a different domain (such as an email address hosted by gmail). | Or they might even add 3PIDs associated to a different domain (such as an email address hosted by Gmail). | ||||||
| Such 3PIDs cannot be resolved in a federated way. | Such 3PIDs cannot be resolved in a federated way and will not be found from other servers. | ||||||
|  |  | ||||||
| Example: a user from Homeserver `example.org` adds an email `john@gmail.com`.   | Example: a user from Homeserver `example.org` adds an email `john@gmail.com`.   | ||||||
| If a federated lookup was performed, Identity servers would try to find the 3PID bind at the `gmail.com` server, and | If a federated lookup was performed, Identity servers would try to find the 3PID bind at the `gmail.com` server, and | ||||||
| not `example.org`. | not `example.org`. | ||||||
|  |  | ||||||
| In order to resolve such 3PIDs, i.e. 3PIDs that cannot be resolved in a Federated way, an identity server can be configured such that | As ma1sd is built for self-hosted use cases, mainly for orgs/corps, this is usually not a problem for emails.   | ||||||
| - 3PIDs that cannot be resolved locally or using federation, are fowarded to another global identity server. | Sadly, there is currently no mechanism to make this work for phone numbers.  | ||||||
| - registration of new 3PIDs that cannot be looked up in a federated fashion, is forwarded to another global identity server. |  | ||||||
|  |  | ||||||
| By forwarding a 3PIDs registration the identity creates a *Remote session* and *Remote bind*, effectively starting a new 3PID session with another Identity server on |  | ||||||
| behalf of the user.  |  | ||||||
|  |  | ||||||
| To ensure lookup works consistency within the current Matrix network, the central Matrix.org Identity Server should be |  | ||||||
| used to store *remote* sessions and binds. |  | ||||||
|  |  | ||||||
| However, at the time of writing, the Matrix specification and the central Matrix.org servers do not allow to remote a 3PID bind. |  | ||||||
| This means that once a 3PID is published (email, phone number, etc.), it cannot be easily removed |  | ||||||
| and would require contacting the Matrix.org administrators for each bind individually. |  | ||||||
| This poses a privacy, control and security concern, especially for groups/corporations that want to keep a tight control |  | ||||||
| on where such identifiers can be made publicly visible. |  | ||||||
|  |  | ||||||
| To ensure full control, validation management relies on two concepts: |  | ||||||
| - The scope of 3PID being validated |  | ||||||
| - The scope of 3PID sessions that should be possible/offered |  | ||||||
|  |  | ||||||
| ### 3PID scope |  | ||||||
| 3PID can either be scoped as local or remote. |  | ||||||
|  |  | ||||||
| Local means that they can be looked up using federation and that such a federation call would end up on the local |  | ||||||
| Identity Server.   |  | ||||||
| Remote means that they cannot be lookup using federation or that a federation call would not end up on the local |  | ||||||
| Identity Server. |  | ||||||
|  |  | ||||||
| Email addresses can either be local or remote 3PID, depending on the domain. If the address is one from the configured |  | ||||||
| domain in the Identity server, it will be scoped as local. If it is from another domain, it will be as remote. |  | ||||||
|  |  | ||||||
| Phone number can only be scoped as remote, since there is currently no way to perform DNS queries that would lead back |  | ||||||
| to the Identity server who validated the phone number. |  | ||||||
|  |  | ||||||
| ### Session scope |  | ||||||
| Sessions can be scoped as: |  | ||||||
| - Local only - validate 3PIDs directly, do not allow the creation of 3PID sessions on a remote Identity server. |  | ||||||
| - Local and Remote - validate 3PIDs directly, offer users to option to also validate and bind 3PID on another server. |  | ||||||
| - Remote only - validate and bind 3PIDs on another server, no validation or bind done locally. |  | ||||||
|  |  | ||||||
| --- |  | ||||||
|  |  | ||||||
| **IMPORTANT NOTE:** mxisd does not store bindings directly. While a user can see its email, phone number or any other |  | ||||||
| 3PID in its settings/profile, it does **NOT** mean it is published anywhere and can be used to invite/search the user. |  | ||||||
| Identity stores are the ones holding such data.   |  | ||||||
| If you still want added arbitrary 3PIDs to be discoverable on a synapse Homeserver, use the corresponding [Identity store](../../stores/synapse.md). |  | ||||||
|  |  | ||||||
| See the [Scenarios](#scenarios) for more info on how and why. |  | ||||||
|  |  | ||||||
| ## Notifications | ## Notifications | ||||||
| 3PIDs are validated by sending a pre-formatted message containing a token to that 3PID address, which must be given to the | 3PIDs are validated by sending a pre-formatted message containing a token to that 3PID address, which must be given to the | ||||||
| Identity server that received the request. This is usually done by means of a URL to visit for email or a short number | Identity server that received the request. This is usually done by means of a URL to visit for email or a short number | ||||||
| received by SMS for phone numbers. | received by SMS for phone numbers. | ||||||
|  |  | ||||||
| mxisd use two components for this: | ma1sd use two components for this: | ||||||
| - Generator which produces the message to be sent with the necessary information the user needs to validate their session. | - Generator which produces the message to be sent with the necessary information the user needs to validate their session. | ||||||
| - Connector which actually send the notification (e.g. SMTP for email). | - Connector which actually send the notification (e.g. SMTP for email). | ||||||
|  |  | ||||||
| @@ -126,44 +90,32 @@ Connectors: | |||||||
|  |  | ||||||
| ## Usage | ## Usage | ||||||
| ### Configuration | ### Configuration | ||||||
| The following example of configuration (incomplete extract) shows which items are relevant for 3PID sessions. | The following example of configuration shows which items are relevant for 3PID sessions. | ||||||
|  |  | ||||||
| **IMPORTANT:** Most configuration items shown have default values and should not be included in your own configuration | **IMPORTANT:** Most configuration items shown have default values and should not be included in your own configuration | ||||||
| file unless you want to specifically overwrite them. | file unless you want to specifically overwrite them. | ||||||
| ```yaml | ```yaml | ||||||
| # CONFIGURATION EXAMPLE | # CONFIGURATION EXAMPLE | ||||||
| # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION | # DO NOT COPY/PASTE AS-IS IN YOUR CONFIGURATION | ||||||
| session.policy.validation.enabled: true |  | ||||||
| session.policy.validation.forLocal: | session: | ||||||
|   enabled: true |   policy: | ||||||
|   toLocal: true |     validation: | ||||||
|   toRemote: |       enabled: true | ||||||
|     enabled: true |     unbind: | ||||||
|     server: 'configExample'  # Not to be included in config! Already present in default config! |       notification: | ||||||
| session.policy.validation.forRemote: |         enabled: true | ||||||
|   enabled: true |  | ||||||
|   toLocal: true | # DO NOT COPY/PASTE AS-IS IN YOUR CONFIGURATION | ||||||
|   toRemote: |  | ||||||
|     enabled: true |  | ||||||
|     server: 'configExample'  # Not to be included in config! Already present in default config! |  | ||||||
| # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION |  | ||||||
| # CONFIGURATION EXAMPLE | # CONFIGURATION EXAMPLE | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| `session.policy.validation` is the core configuration to control what users configured to use your Identity server | `session.policy.validation` is the core configuration to control what users configured to use your Identity server | ||||||
| are allowed to do in terms of 3PID sessions. | are allowed to do in terms of 3PID sessions. The policy has a global on/off switch for 3PID sessions using `.enabled`   | ||||||
|  |  | ||||||
| The policy has a global on/off switch for 3PID sessions using `.enabled`   | --- | ||||||
| It is also divided into two sections: `forLocal` and `forRemote` which refers to the 3PID scopes.   |  | ||||||
|  |  | ||||||
| Each scope is divided into three parts: | `unbind` controls warning notifications for 3PID removal.   | ||||||
| - global on/off switch for 3PID sessions using `.enabled` |  | ||||||
| - `toLocal` allowing or not local 3PID session validations |  | ||||||
| - `toRemote` allowing or not remote 3PID session validations and to which server such sessions should be sent.    |  | ||||||
|   `.server` takes a Matrix Identity server list label. Only the first server in the list is currently used. |  | ||||||
|  |  | ||||||
| If both `toLocal` and `toRemote` are enabled, the user will be offered to initiate a remote session once their 3PID |  | ||||||
| locally validated. |  | ||||||
|  |  | ||||||
| ### Web views | ### Web views | ||||||
| Once a user click on a validation link, it is taken to the Identity Server validation page where the token is submitted.   | Once a user click on a validation link, it is taken to the Identity Server validation page where the token is submitted.   | ||||||
| @@ -174,103 +126,18 @@ See [the dedicated document](session-views.md) | |||||||
| on how to configure/customize/brand those pages to your liking. | on how to configure/customize/brand those pages to your liking. | ||||||
|  |  | ||||||
| ### Scenarios | ### Scenarios | ||||||
| It is important to keep in mind that mxisd does not create bindings, irrelevant if a user added a 3PID to their profile.   |  | ||||||
| Instead, when queried for bindings, mxisd will query Identity stores which are responsible to store this kind of information. |  | ||||||
|  |  | ||||||
| This has the side effect that any 3PID added to a user profile which is NOT within a configured and enabled Identity backend |  | ||||||
| will simply not be usable for search or invites, **even on the same Homeserver!**   |  | ||||||
| mxisd does not store binds on purpose, as one of its primary goal is to ensure maximum compatibility with federation |  | ||||||
| and the rest of the Matrix ecosystem is preserved. |  | ||||||
|  |  | ||||||
| Nonetheless, because mxisd also aims at offering support for tight control over identity data, it is possible to have |  | ||||||
| such 3PID bindings available for search and invite queries on synapse with the corresponding [Identity store](../../stores/synapse.md). |  | ||||||
|  |  | ||||||
| See the [Local sessions only](#local-sessions-only) use case for more information on how to configure. |  | ||||||
|  |  | ||||||
| #### Default |  | ||||||
| By default, mxisd allows the following: |  | ||||||
|  |  | ||||||
| |                 | Local Session     | Remote Session | |  | ||||||
| |-----------------|-------------------|----------------| |  | ||||||
| | **Local 3PID**  | Yes               | Yes, offered   | |  | ||||||
| | **Remote 3PID** | No, Remote forced | Yes            | |  | ||||||
|  |  | ||||||
| This is usually what people expect and will feel natural to users and does not involve further integration. |  | ||||||
|  |  | ||||||
| This allows to stay in control for e-mail addresses which domain matches your Matrix environment, still making them |  | ||||||
| discoverable with federation but not recorded in a 3rd party Identity server which is not under your control.   |  | ||||||
| Users still get the possibility to publish globally their address if needed. |  | ||||||
|  |  | ||||||
| Other e-mail addresses and phone number will be redirected to remote sessions to ensure full compatibility with the Matrix |  | ||||||
| ecosystem and other federated servers. |  | ||||||
|  |  | ||||||
| #### Local sessions only |  | ||||||
| **NOTE:** This does not affect 3PID lookups (queries to find Matrix IDs). See [Federation](../../features/federation.md) |  | ||||||
| to disable remote lookup for those. |  | ||||||
|  |  | ||||||
| This configuration ensures maximum confidentiality and privacy. |  | ||||||
| Typical use cases: |  | ||||||
| - Private Homeserver, not federated |  | ||||||
| - Internal Homeserver without direct Internet access |  | ||||||
| - Custom product based on Matrix which does not federate |  | ||||||
|  |  | ||||||
| No 3PID will be sent to a remote Identity server and all validation will be performed locally.   |  | ||||||
| On the flip side, people with *Remote* 3PID scopes will not be found from other servers. |  | ||||||
|  |  | ||||||
| Use the following values: |  | ||||||
| ```yaml |  | ||||||
| session.policy.validation.enabled: true |  | ||||||
| session.policy.validation.forLocal: |  | ||||||
|   enabled: true |  | ||||||
|   toLocal: true |  | ||||||
|   toRemote: |  | ||||||
|     enabled: false |  | ||||||
| session.policy.validation.forRemote: |  | ||||||
|   enabled: true |  | ||||||
|   toLocal: true |  | ||||||
|   toRemote: |  | ||||||
|     enabled: false |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| **IMPORTANT**: When using local-only mode and if you are using synapse, you will also need to enable its dedicated Identity |  | ||||||
| store if you want user searches and invites to work. To do so, see the [dedicated document](../../stores/synapse.md). |  | ||||||
|  |  | ||||||
| #### Remote sessions only |  | ||||||
| This configuration ensures all 3PID are made public for maximum compatibility and reach within the Matrix ecosystem, at |  | ||||||
| the cost of confidentiality and privacy.   |  | ||||||
|  |  | ||||||
| Typical use cases: |  | ||||||
| - Public Homeserver |  | ||||||
| - Homeserver with registration enabled |  | ||||||
|  |  | ||||||
| Use the following values: |  | ||||||
| ```yaml |  | ||||||
| session.policy.validation.enabled: true |  | ||||||
| session.policy.validation.forLocal: |  | ||||||
|   enabled: true |  | ||||||
|   toLocal: false |  | ||||||
|   toRemote: |  | ||||||
|     enabled: true |  | ||||||
| session.policy.validation.forRemote: |  | ||||||
|   enabled: true |  | ||||||
|   toLocal: false |  | ||||||
|   toRemote: |  | ||||||
|     enabled: true |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| #### Sessions disabled | #### Sessions disabled | ||||||
| This configuration would disable 3PID session altogether, preventing users from adding emails and/or phone numbers to | This configuration would disable 3PID sessions altogether, preventing users from validating emails and/or phone numbers | ||||||
| their profiles.   | and any subsequent actions that requires them, like adding them to their profiles. | ||||||
| This would be used if mxisd is also performing authentication for the Homeserver, typically with synapse and the |    | ||||||
| [REST password provider](https://github.com/kamax-io/matrix-synapse-rest-auth). | This would be used if ma1sd is also performing authentication for the Homeserver, typically with synapse and the | ||||||
|  | [REST password provider](https://github.com/ma1uta/matrix-synapse-rest-password-provider), where 3PID mappings would be | ||||||
| **This mode comes with several important restrictions:** | auto-populated. | ||||||
| - This does not prevent users from removing 3PID from their profile. They would be unable to add them back! |  | ||||||
| - This prevents users from initiating remote session to make their 3PID binds globally visible |  | ||||||
|  |  | ||||||
| It is therefore recommended to not fully disable sessions but instead restrict specific set of 3PID and Session scopes. |  | ||||||
|  |  | ||||||
| Use the following values to enable this mode: | Use the following values to enable this mode: | ||||||
| ```yaml | ```yaml | ||||||
| session.policy.validation.enabled: false | session: | ||||||
|  |   policy: | ||||||
|  |     validation: | ||||||
|  |       enabled: false | ||||||
| ``` | ``` | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								docs/troubleshooting.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								docs/troubleshooting.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | # Troubleshooting | ||||||
|  | - [Purpose](#purpose) | ||||||
|  | - [Logs](#logs) | ||||||
|  |   - [Locations](#locations) | ||||||
|  |   - [Reading Them](#reading-them) | ||||||
|  |   - [Common issues](#common-issues) | ||||||
|  | - [Submit an issue](#submit-an-issue) | ||||||
|  |  | ||||||
|  | ## Purpose | ||||||
|  | This document describes basic troubleshooting steps for ma1sd. | ||||||
|  |  | ||||||
|  | ## Logs | ||||||
|  | ### Locations | ||||||
|  | ma1sd logs to `STDOUT` (Standard Output) and `STDERR` (Standard Error) only, which gets redirected | ||||||
|  | to log file(s) depending on your system. | ||||||
|  |  | ||||||
|  | If you use the [Debian package](install/debian.md), this goes to `syslog`.   | ||||||
|  | If you use the [Docker image](install/docker.md), this goes to the container logs.   | ||||||
|  |  | ||||||
|  | For any other platform, please refer to your package maintainer. | ||||||
|  |  | ||||||
|  | ### Increase verbosity | ||||||
|  | To increase log verbosity and better track issues, the following means are available: | ||||||
|  | - Add the `-v` command line parameter | ||||||
|  | - Use the environment variable and value `MA1SD_LOG_LEVEL=debug` | ||||||
|  |  | ||||||
|  | ### Reading them | ||||||
|  | Before reporting an issue, it is important to produce clean and complete logs so they can be understood. | ||||||
|  |  | ||||||
|  | It is usually useless to try to troubleshoot an issue based on a single log line. Any action or API request | ||||||
|  | in ma1sd would trigger more than one log lines, and those would be considered necessary context to | ||||||
|  | understand what happened. | ||||||
|  |  | ||||||
|  | You may also find things called *stacktraces*. Those are important to pin-point bugs and the likes and should | ||||||
|  | always be included in any report. They also tend to be very specific about the issue at hand. | ||||||
|  |  | ||||||
|  | Example of a stacktrace: | ||||||
|  | ``` | ||||||
|  | Exception in thread "main" java.lang.NullPointerException | ||||||
|  |         at com.example.myproject.Book.getTitle(Book.java:16) | ||||||
|  |         at com.example.myproject.Author.getBookTitles(Author.java:25) | ||||||
|  |         at com.example.myproject.Bootstrap.main(Bootstrap.java:14) | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Common issues | ||||||
|  | #### Internal Server Error | ||||||
|  | `Contact your administrator with reference Transaction #123456789` | ||||||
|  |  | ||||||
|  | This is a generic message produced in case of an unknown error. The transaction reference allows to easily find | ||||||
|  | the location in the logs to look for an error. | ||||||
|  |  | ||||||
|  | **IMPORTANT:** That line alone does not tell you anything about the error. You'll need the log lines before and after, | ||||||
|  | usually including a stacktrace, to know what happened. Please take the time to read the surround output to get | ||||||
|  | context about the issue at hand. | ||||||
|  |  | ||||||
|  | ## Submit an issue | ||||||
|  | In case the logs do not allow you to understand the issue at hand, please submit clean and complete logs | ||||||
|  | as explained [here](#reading-them) in a new issue on the repository, or [get in touch](../README.md#contact). | ||||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| #Fri Aug 11 17:19:02 CEST 2017 | #Thu Jul 04 22:47:59 MSK 2019 | ||||||
|  | distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip | ||||||
| distributionBase=GRADLE_USER_HOME | distributionBase=GRADLE_USER_HOME | ||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| zipStoreBase=GRADLE_USER_HOME |  | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip | zipStoreBase=GRADLE_USER_HOME | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,21 @@ | |||||||
| #!/usr/bin/env sh | #!/usr/bin/env sh | ||||||
|  |  | ||||||
|  | # | ||||||
|  | # Copyright 2015 the original author or authors. | ||||||
|  | # | ||||||
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | # you may not use this file except in compliance with the License. | ||||||
|  | # You may obtain a copy of the License at | ||||||
|  | # | ||||||
|  | #      http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | # | ||||||
|  | # Unless required by applicable law or agreed to in writing, software | ||||||
|  | # distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | # See the License for the specific language governing permissions and | ||||||
|  | # limitations under the License. | ||||||
|  | # | ||||||
|  |  | ||||||
| ############################################################################## | ############################################################################## | ||||||
| ## | ## | ||||||
| ##  Gradle start up script for UN*X | ##  Gradle start up script for UN*X | ||||||
| @@ -28,7 +44,7 @@ APP_NAME="Gradle" | |||||||
| APP_BASE_NAME=`basename "$0"` | APP_BASE_NAME=`basename "$0"` | ||||||
|  |  | ||||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||||
| DEFAULT_JVM_OPTS="" | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | ||||||
|  |  | ||||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||||
| MAX_FD="maximum" | MAX_FD="maximum" | ||||||
|   | |||||||
							
								
								
									
										184
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										184
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							| @@ -1,84 +1,100 @@ | |||||||
| @if "%DEBUG%" == "" @echo off | @rem | ||||||
| @rem ########################################################################## | @rem Copyright 2015 the original author or authors. | ||||||
| @rem | @rem | ||||||
| @rem  Gradle startup script for Windows | @rem Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
| @rem | @rem you may not use this file except in compliance with the License. | ||||||
| @rem ########################################################################## | @rem You may obtain a copy of the License at | ||||||
|  | @rem | ||||||
| @rem Set local scope for the variables with windows NT shell | @rem      http://www.apache.org/licenses/LICENSE-2.0 | ||||||
| if "%OS%"=="Windows_NT" setlocal | @rem | ||||||
|  | @rem Unless required by applicable law or agreed to in writing, software | ||||||
| set DIRNAME=%~dp0 | @rem distributed under the License is distributed on an "AS IS" BASIS, | ||||||
| if "%DIRNAME%" == "" set DIRNAME=. | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
| set APP_BASE_NAME=%~n0 | @rem See the License for the specific language governing permissions and | ||||||
| set APP_HOME=%DIRNAME% | @rem limitations under the License. | ||||||
|  | @rem | ||||||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |  | ||||||
| set DEFAULT_JVM_OPTS= | @if "%DEBUG%" == "" @echo off | ||||||
|  | @rem ########################################################################## | ||||||
| @rem Find java.exe | @rem | ||||||
| if defined JAVA_HOME goto findJavaFromJavaHome | @rem  Gradle startup script for Windows | ||||||
|  | @rem | ||||||
| set JAVA_EXE=java.exe | @rem ########################################################################## | ||||||
| %JAVA_EXE% -version >NUL 2>&1 |  | ||||||
| if "%ERRORLEVEL%" == "0" goto init | @rem Set local scope for the variables with windows NT shell | ||||||
|  | if "%OS%"=="Windows_NT" setlocal | ||||||
| echo. |  | ||||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | set DIRNAME=%~dp0 | ||||||
| echo. | if "%DIRNAME%" == "" set DIRNAME=. | ||||||
| echo Please set the JAVA_HOME variable in your environment to match the | set APP_BASE_NAME=%~n0 | ||||||
| echo location of your Java installation. | set APP_HOME=%DIRNAME% | ||||||
|  |  | ||||||
| goto fail | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||||
|  | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" | ||||||
| :findJavaFromJavaHome |  | ||||||
| set JAVA_HOME=%JAVA_HOME:"=% | @rem Find java.exe | ||||||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | if defined JAVA_HOME goto findJavaFromJavaHome | ||||||
|  |  | ||||||
| if exist "%JAVA_EXE%" goto init | set JAVA_EXE=java.exe | ||||||
|  | %JAVA_EXE% -version >NUL 2>&1 | ||||||
| echo. | if "%ERRORLEVEL%" == "0" goto init | ||||||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |  | ||||||
| echo. | echo. | ||||||
| echo Please set the JAVA_HOME variable in your environment to match the | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||||
| echo location of your Java installation. | echo. | ||||||
|  | echo Please set the JAVA_HOME variable in your environment to match the | ||||||
| goto fail | echo location of your Java installation. | ||||||
|  |  | ||||||
| :init | goto fail | ||||||
| @rem Get command-line arguments, handling Windows variants |  | ||||||
|  | :findJavaFromJavaHome | ||||||
| if not "%OS%" == "Windows_NT" goto win9xME_args | set JAVA_HOME=%JAVA_HOME:"=% | ||||||
|  | set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||||
| :win9xME_args |  | ||||||
| @rem Slurp the command line arguments. | if exist "%JAVA_EXE%" goto init | ||||||
| set CMD_LINE_ARGS= |  | ||||||
| set _SKIP=2 | echo. | ||||||
|  | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||||
| :win9xME_args_slurp | echo. | ||||||
| if "x%~1" == "x" goto execute | echo Please set the JAVA_HOME variable in your environment to match the | ||||||
|  | echo location of your Java installation. | ||||||
| set CMD_LINE_ARGS=%* |  | ||||||
|  | goto fail | ||||||
| :execute |  | ||||||
| @rem Setup the command line | :init | ||||||
|  | @rem Get command-line arguments, handling Windows variants | ||||||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |  | ||||||
|  | if not "%OS%" == "Windows_NT" goto win9xME_args | ||||||
| @rem Execute Gradle |  | ||||||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | :win9xME_args | ||||||
|  | @rem Slurp the command line arguments. | ||||||
| :end | set CMD_LINE_ARGS= | ||||||
| @rem End local scope for the variables with windows NT shell | set _SKIP=2 | ||||||
| if "%ERRORLEVEL%"=="0" goto mainEnd |  | ||||||
|  | :win9xME_args_slurp | ||||||
| :fail | if "x%~1" == "x" goto execute | ||||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |  | ||||||
| rem the _cmd.exe /c_ return code! | set CMD_LINE_ARGS=%* | ||||||
| if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |  | ||||||
| exit /b 1 | :execute | ||||||
|  | @rem Setup the command line | ||||||
| :mainEnd |  | ||||||
| if "%OS%"=="Windows_NT" endlocal | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||||
|  |  | ||||||
| :omega | @rem Execute Gradle | ||||||
|  | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||||||
|  |  | ||||||
|  | :end | ||||||
|  | @rem End local scope for the variables with windows NT shell | ||||||
|  | if "%ERRORLEVEL%"=="0" goto mainEnd | ||||||
|  |  | ||||||
|  | :fail | ||||||
|  | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||||
|  | rem the _cmd.exe /c_ return code! | ||||||
|  | if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||||
|  | exit /b 1 | ||||||
|  |  | ||||||
|  | :mainEnd | ||||||
|  | if "%OS%"=="Windows_NT" endlocal | ||||||
|  |  | ||||||
|  | :omega | ||||||
|   | |||||||
							
								
								
									
										111
									
								
								ma1sd.example.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								ma1sd.example.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | # Sample configuration file explaining the minimum required keys to be set to run ma1sd | ||||||
|  | # | ||||||
|  | # For a complete list of options, see https://github.com/ma1uta/ma1sd/docs/README.md | ||||||
|  | # | ||||||
|  | # Please follow the Getting Started guide if this is your first time using/configuring ma1sd | ||||||
|  | # | ||||||
|  | #  -- https://github.com/ma1uta/ma1sd/blob/master/docs/getting-started.md#getting-started | ||||||
|  | # | ||||||
|  |  | ||||||
|  | ####################### | ||||||
|  | # Matrix config items # | ||||||
|  | ####################### | ||||||
|  | # Matrix domain, same as the domain configure in your Homeserver configuration. | ||||||
|  | # NOTE: in Synapse Homeserver, the Matrix domain is defined as 'server_name' in configuration file. | ||||||
|  | # | ||||||
|  | # This is used to build the various identifiers in all the features. | ||||||
|  | # | ||||||
|  | # If the hostname of the public URL used to reach your Matrix services is different from your Matrix domain, | ||||||
|  | # per example matrix.domain.tld vs domain.tld, then use the server.name configuration option. | ||||||
|  | # See the "Configure" section of the Getting Started guide for more info. | ||||||
|  | # | ||||||
|  | matrix: | ||||||
|  |   domain: '' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ################ | ||||||
|  | # Signing keys # | ||||||
|  | ################ | ||||||
|  | # Absolute path for the Identity Server signing keys database. | ||||||
|  | # /!\ THIS MUST **NOT** BE YOUR HOMESERVER KEYS FILE /!\ | ||||||
|  | # If this path does not exist, it will be auto-generated. | ||||||
|  | # | ||||||
|  | # During testing, /var/tmp/ma1sd/keys is a possible value | ||||||
|  | # For production, recommended location shall be one of the following: | ||||||
|  | #   - /var/lib/ma1sd/keys | ||||||
|  | #   - /var/opt/ma1sd/keys | ||||||
|  | #   - /var/local/ma1sd/keys | ||||||
|  | # | ||||||
|  | key: | ||||||
|  |   path: '' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Path to the SQLite DB file for ma1sd internal storage | ||||||
|  | # /!\ THIS MUST **NOT** BE YOUR HOMESERVER DATABASE /!\ | ||||||
|  | # | ||||||
|  | # Examples: | ||||||
|  | #  - /var/opt/ma1sd/store.db | ||||||
|  | #  - /var/local/ma1sd/store.db | ||||||
|  | #  - /var/lib/ma1sd/store.db | ||||||
|  | # | ||||||
|  | storage: | ||||||
|  |   provider: | ||||||
|  |     sqlite: | ||||||
|  |       database: '/path/to/ma1sd.db' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ################### | ||||||
|  | # Identity Stores # | ||||||
|  | ################### | ||||||
|  | # If you are using synapse standalone and do not have an Identity store, | ||||||
|  | # see https://github.com/ma1uta/ma1sd/blob/master/docs/stores/synapse.md#synapse-identity-store | ||||||
|  | # | ||||||
|  | # If you would like to integrate with your AD/Samba/LDAP server, | ||||||
|  | # see https://github.com/ma1uta/ma1sd/blob/master/docs/stores/ldap.md | ||||||
|  | # | ||||||
|  | # For any other Identity store, or to simply discover them, | ||||||
|  | # see https://github.com/ma1uta/ma1sd/blob/master/docs/stores/README.md | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ################################################# | ||||||
|  | # Notifications for invites/addition to profile # | ||||||
|  | ################################################# | ||||||
|  | # This is mandatory to deal with anything e-mail related. | ||||||
|  | # | ||||||
|  | # For an introduction to sessions, invites and 3PIDs in general, | ||||||
|  | # see https://github.com/ma1uta/ma1sd/blob/master/docs/threepids/session/session.md#3pid-sessions | ||||||
|  | # | ||||||
|  | # If you would like to change the content of the notifications, | ||||||
|  | # see https://github.com/ma1uta/ma1sd/blob/master/docs/threepids/notification/template-generator.md | ||||||
|  | # | ||||||
|  | #### E-mail connector | ||||||
|  | threepid: | ||||||
|  |   medium: | ||||||
|  |     email: | ||||||
|  |       identity: | ||||||
|  |         # The e-mail to send as. | ||||||
|  |         from: "matrix-identity@example.org" | ||||||
|  |  | ||||||
|  |       connectors: | ||||||
|  |         smtp: | ||||||
|  |           # SMTP host | ||||||
|  |           host: "smtp.example.org" | ||||||
|  |  | ||||||
|  |           # TLS mode for the connection | ||||||
|  |           # Possible values: | ||||||
|  |           #  0    Disable any kind of TLS entirely | ||||||
|  |           #  1    Enable STARTLS if supported by server (default) | ||||||
|  |           #  2    Force STARTLS and fail if not available | ||||||
|  |           #  3    Use full TLS/SSL instead of STARTLS | ||||||
|  |           # | ||||||
|  |           tls: 1 | ||||||
|  |  | ||||||
|  |           # SMTP port | ||||||
|  |           # Be sure to adapt depending on your TLS choice, if changed from default | ||||||
|  |           port: 587 | ||||||
|  |  | ||||||
|  |           # Login for SMTP | ||||||
|  |           login: "matrix-identity@example.org" | ||||||
|  |  | ||||||
|  |           # Password for the account | ||||||
|  |           password: "ThePassword" | ||||||
| @@ -1,7 +1,9 @@ | |||||||
| Package: mxisd | Package: ma1sd | ||||||
| Maintainer: Kamax.io <foss@kamax.io> | Maintainer: ma1uta <sablintolya@gmail.com> | ||||||
| Homepage: https://github.com/kamax-matrix/mxisd | Homepage: https://github.com/ma1uta/ma1sd | ||||||
| Description: Federated Matrix Identity Server | Description: Federated Matrix Identity Server | ||||||
| Architecture: all | Architecture: all | ||||||
| Depends: openjdk-8-jre | openjdk-8-jre-headless | openjdk-8-jdk | openjdk-8-jdk-headless | Section: net | ||||||
|  | Priority: optional | ||||||
|  | Depends: openjdk-8-jre | openjdk-8-jre-headless | openjdk-8-jdk | openjdk-8-jdk-headless | openjdk-11-jre | openjdk-11-jre-headless | openjdk-11-jdk | openjdk-11-jdk-headless | ||||||
| Version: 0 | Version: 0 | ||||||
|   | |||||||
| @@ -1,13 +1,19 @@ | |||||||
| #!/bin/bash -e | #!/bin/bash -e | ||||||
|  |  | ||||||
| # Add service account | # Add service account | ||||||
| useradd -r mxisd || true | useradd -r ma1sd || true | ||||||
|  |  | ||||||
| # Set permissions for data directory | # Set permissions for data directory | ||||||
| chown -R mxisd:mxisd %DEB_DATA_DIR% | chown -R ma1sd:ma1sd %DEB_DATA_DIR% | ||||||
|  |  | ||||||
| # Create symlink to mxusd | # Create symlink to ma1sd run script | ||||||
| ln -sfT /usr/lib/mxisd/mxisd.jar /usr/bin/mxisd | ln -sfT /usr/lib/ma1sd/ma1sd /usr/bin/ma1sd | ||||||
|  |  | ||||||
| # Enable systemd service | # Enable systemd service | ||||||
| systemctl enable mxisd.service | systemctl enable ma1sd.service | ||||||
|  |  | ||||||
|  | # If we already have a config file setup, we attempt to run ma1sd automatically | ||||||
|  | # Specifically targeted at upgrades where the service needs to be restarted | ||||||
|  | if [ -f "%DEB_CONF_FILE%" ]; then | ||||||
|  |     systemctl restart ma1sd.service | ||||||
|  | fi | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| #!/bin/bash | #!/bin/bash | ||||||
|  |  | ||||||
| # Stop running instance if needed | # Stop running instance if needed | ||||||
| systemctl stop mxisd.service | systemctl stop ma1sd.service | ||||||
|  |  | ||||||
| # Disable service if exists | # Disable service if exists | ||||||
| systemctl disable mxisd.service | systemctl disable ma1sd.service | ||||||
|  |  | ||||||
| # remove symlink | # remove symlink | ||||||
| rm /usr/bin/mxisd | rm /usr/bin/ma1sd | ||||||
|   | |||||||
| @@ -1,25 +1,34 @@ | |||||||
| #!/usr/bin/env bash | #!/bin/bash | ||||||
|  |  | ||||||
| if [[ -n "$CONF_FILE_PATH" ]] && [ ! -f "$CONF_FILE_PATH" ]; then | if [[ -n "$CONF_FILE_PATH" ]] && [ ! -f "$CONF_FILE_PATH" ]; then | ||||||
|     echo "Generating config file $CONF_FILE_PATH" |     echo "Generating config file $CONF_FILE_PATH" | ||||||
|     touch "CONF_FILE_PATH" |     touch "CONF_FILE_PATH" | ||||||
|  |  | ||||||
|     if [[ -n "$MATRIX_DOMAIN" ]]; then |     if [[ -n "$MATRIX_DOMAIN" ]]; then | ||||||
|         echo "Setting matrix domain to $MATRIX_DOMAIN" |         echo "Setting matrix domain to $MATRIX_DOMAIN" | ||||||
|         echo "matrix.domain: $MATRIX_DOMAIN" >> "$CONF_FILE_PATH" |         echo "matrix:" >> "$CONF_FILE_PATH" | ||||||
|  |         echo "  domain: '$MATRIX_DOMAIN'" >> "$CONF_FILE_PATH" | ||||||
|  |         echo >> "$CONF_FILE_PATH" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if [[ -n "$SIGN_KEY_PATH" ]]; then |     if [[ -n "$SIGN_KEY_PATH" ]]; then | ||||||
|         echo "Setting signing key path to $SIGN_KEY_PATH" |         echo "Setting signing key path to $SIGN_KEY_PATH" | ||||||
|         echo "key.path: $SIGN_KEY_PATH" >> "$CONF_FILE_PATH" |         echo "key:" >> "$CONF_FILE_PATH" | ||||||
|  |         echo "  path: '$SIGN_KEY_PATH'" >> "$CONF_FILE_PATH" | ||||||
|  |         echo >> "$CONF_FILE_PATH" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     if [[ -n "$SQLITE_DATABASE_PATH" ]]; then |     if [[ -n "$SQLITE_DATABASE_PATH" ]]; then | ||||||
|         echo "Setting SQLite DB path to $SQLITE_DATABASE_PATH" |         echo "Setting SQLite DB path to $SQLITE_DATABASE_PATH" | ||||||
|         echo "storage.provider.sqlite.database: $SQLITE_DATABASE_PATH" >> "$CONF_FILE_PATH" |         echo "storage:" >> "$CONF_FILE_PATH" | ||||||
|  |         echo "  provider:" >> "$CONF_FILE_PATH" | ||||||
|  |         echo "    sqlite:" >> "$CONF_FILE_PATH" | ||||||
|  |         echo "      database: '$SQLITE_DATABASE_PATH'" >> "$CONF_FILE_PATH" | ||||||
|  |         echo >> "$CONF_FILE_PATH" | ||||||
|     fi |     fi | ||||||
|  |  | ||||||
|     echo "Starting mxisd..." |     echo "Starting ma1sd..." | ||||||
|     echo |     echo | ||||||
| fi | fi | ||||||
|  |  | ||||||
| exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.config.location=/etc/mxisd/ -Dspring.config.name=mxisd -jar /mxisd.jar | exec java -jar /app/ma1sd.jar -c /etc/ma1sd/ma1sd.yaml | ||||||
|   | |||||||
| @@ -1,27 +1,26 @@ | |||||||
| /* | /* | ||||||
| * The MIT License |  * The MIT License | ||||||
| * |  * | ||||||
| * Copyright (c) 2013 Edin Dazdarevic (edin.dazdarevic@gmail.com) |  * Copyright (c) 2013 Edin Dazdarevic (edin.dazdarevic@gmail.com) | ||||||
|  |  | ||||||
| * Permission is hereby granted, free of charge, to any person obtaining a copy |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
| * of this software and associated documentation files (the "Software"), to deal |  * of this software and associated documentation files (the "Software"), to deal | ||||||
| * in the Software without restriction, including without limitation the rights |  * in the Software without restriction, including without limitation the rights | ||||||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
| * copies of the Software, and to permit persons to whom the Software is |  * copies of the Software, and to permit persons to whom the Software is | ||||||
| * furnished to do so, subject to the following conditions: |  * furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
| * The above copyright notice and this permission notice shall be included in |  * The above copyright notice and this permission notice shall be included in | ||||||
| * all copies or substantial portions of the Software. |  * all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  * 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 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
| * THE SOFTWARE. |  * THE SOFTWARE. | ||||||
| * |  */ | ||||||
| * */ |  | ||||||
|  |  | ||||||
| package edazdarevic.commons.net; | package edazdarevic.commons.net; | ||||||
|  |  | ||||||
| @@ -37,6 +36,7 @@ import java.util.List; | |||||||
|  * both IPv4 and IPv6. |  * both IPv4 and IPv6. | ||||||
|  */ |  */ | ||||||
| public class CIDRUtils { | public class CIDRUtils { | ||||||
|  |  | ||||||
|     private final String cidr; |     private final String cidr; | ||||||
|  |  | ||||||
|     private InetAddress inetAddress; |     private InetAddress inetAddress; | ||||||
| @@ -44,7 +44,6 @@ public class CIDRUtils { | |||||||
|     private InetAddress endAddress; |     private InetAddress endAddress; | ||||||
|     private final int prefixLength; |     private final int prefixLength; | ||||||
|  |  | ||||||
|  |  | ||||||
|     public CIDRUtils(String cidr) throws UnknownHostException { |     public CIDRUtils(String cidr) throws UnknownHostException { | ||||||
|  |  | ||||||
|         this.cidr = cidr; |         this.cidr = cidr; | ||||||
| @@ -66,7 +65,6 @@ public class CIDRUtils { | |||||||
|  |  | ||||||
|  |  | ||||||
|     private void calculate() throws UnknownHostException { |     private void calculate() throws UnknownHostException { | ||||||
|  |  | ||||||
|         ByteBuffer maskBuffer; |         ByteBuffer maskBuffer; | ||||||
|         int targetSize; |         int targetSize; | ||||||
|         if (inetAddress.getAddress().length == 4) { |         if (inetAddress.getAddress().length == 4) { | ||||||
| @@ -120,14 +118,9 @@ public class CIDRUtils { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String getNetworkAddress() { |     public String getNetworkAddress() { | ||||||
|  |  | ||||||
|         return this.startAddress.getHostAddress(); |         return this.startAddress.getHostAddress(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String getBroadcastAddress() { |  | ||||||
|         return this.endAddress.getHostAddress(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public boolean isInRange(String ipAddress) throws UnknownHostException { |     public boolean isInRange(String ipAddress) throws UnknownHostException { | ||||||
|         InetAddress address = InetAddress.getByName(ipAddress); |         InetAddress address = InetAddress.getByName(ipAddress); | ||||||
|         BigInteger start = new BigInteger(1, this.startAddress.getAddress()); |         BigInteger start = new BigInteger(1, this.startAddress.getAddress()); | ||||||
| @@ -139,4 +132,5 @@ public class CIDRUtils { | |||||||
|  |  | ||||||
|         return (st == -1 || st == 0) && (te == -1 || te == 0); |         return (st == -1 || st == 0) && (te == -1 || te == 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								src/main/java/io/kamax/matrix/MalformedEventException.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/main/java/io/kamax/matrix/MalformedEventException.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public class MalformedEventException extends MatrixException { | ||||||
|  |  | ||||||
|  |     public MalformedEventException(String s) { | ||||||
|  |         super("M_NOT_JSON", s); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MalformedEventException forId(String id) { | ||||||
|  |         return new MalformedEventException("Event " + id + " is malformed"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								src/main/java/io/kamax/matrix/MatrixErrorInfo.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/main/java/io/kamax/matrix/MatrixErrorInfo.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public class MatrixErrorInfo { | ||||||
|  |  | ||||||
|  |     private String errcode; | ||||||
|  |     private String error; | ||||||
|  |  | ||||||
|  |     public MatrixErrorInfo(String errcode) { | ||||||
|  |         this.errcode = errcode; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixErrorInfo(Throwable t) { | ||||||
|  |         this.errcode = "AS_INTERNAL_SERVER_ERROR"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getErrcode() { | ||||||
|  |         return errcode; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getError() { | ||||||
|  |         return error; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								src/main/java/io/kamax/matrix/MatrixException.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/main/java/io/kamax/matrix/MatrixException.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public class MatrixException extends RuntimeException { | ||||||
|  |  | ||||||
|  |     private String errorCode; | ||||||
|  |     private String error; | ||||||
|  |  | ||||||
|  |     public MatrixException(String errorCode, String error) { | ||||||
|  |         super(errorCode + ": " + error); | ||||||
|  |         this.errorCode = errorCode; | ||||||
|  |         this.error = error; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixException(String errorCode, String error, Throwable t) { | ||||||
|  |         super(errorCode + ": " + error, t); | ||||||
|  |         this.errorCode = errorCode; | ||||||
|  |         this.error = error; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getErrorCode() { | ||||||
|  |         return errorCode; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getError() { | ||||||
|  |         return error; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										170
									
								
								src/main/java/io/kamax/matrix/MatrixID.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/main/java/io/kamax/matrix/MatrixID.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  |  | ||||||
|  | public class MatrixID implements _MatrixID { | ||||||
|  |  | ||||||
|  |     public static class Builder { | ||||||
|  |  | ||||||
|  |         private MatrixID mxId; | ||||||
|  |  | ||||||
|  |         public Builder(String id) { | ||||||
|  |             mxId = MatrixID.parse(id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public MatrixID valid() { | ||||||
|  |             if (!mxId.isValid()) { | ||||||
|  |                 throw new IllegalArgumentException(mxId + " is not a valid Matrix ID"); | ||||||
|  |             } | ||||||
|  |             return mxId; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public MatrixID acceptable() { | ||||||
|  |             if (!mxId.isAcceptable()) { | ||||||
|  |                 throw new IllegalArgumentException(mxId + " is not an acceptable Matrix ID"); | ||||||
|  |             } | ||||||
|  |             return mxId; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static final String ALLOWED_CHARS = "0-9a-z-.=_/"; | ||||||
|  |     public static final Pattern LAX_PATTERN = Pattern.compile("@(.*?):(.+)"); | ||||||
|  |     public static final Pattern STRICT_PATTERN = Pattern.compile("@([" + ALLOWED_CHARS + "]+):(.+)"); | ||||||
|  |  | ||||||
|  |     private String id; | ||||||
|  |  | ||||||
|  |     private String localpart; | ||||||
|  |     private String domain; | ||||||
|  |  | ||||||
|  |     private static String buildRaw(String localpart, String domain) { | ||||||
|  |         return "@" + localpart + ":" + domain; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static MatrixID parse(String id) { | ||||||
|  |         Matcher m = LAX_PATTERN.matcher(id); | ||||||
|  |         if (!m.matches()) { | ||||||
|  |             throw new IllegalArgumentException(id + " is not a Matrix ID"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         MatrixID mxId = new MatrixID(); | ||||||
|  |         mxId.id = id; | ||||||
|  |         mxId.localpart = m.group(1); | ||||||
|  |         mxId.domain = m.group(2); | ||||||
|  |         return mxId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static Builder from(String id) { | ||||||
|  |         return new Builder(id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static Builder from(String local, String domain) { | ||||||
|  |         return from(buildRaw(local, domain)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixID asValid(String id) { | ||||||
|  |         return new Builder(id).valid(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixID asAcceptable(String local, String domain) { | ||||||
|  |         return from(local, domain).acceptable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixID asAcceptable(String id) { | ||||||
|  |         return from(id).acceptable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private MatrixID() { | ||||||
|  |         // not for public consumption | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private MatrixID(MatrixID mxId) { | ||||||
|  |         this.id = mxId.id; | ||||||
|  |         this.localpart = mxId.localpart; | ||||||
|  |         this.domain = mxId.domain; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Deprecated | ||||||
|  |     public MatrixID(String mxId) { | ||||||
|  |         this(parse(mxId)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Deprecated | ||||||
|  |     public MatrixID(String localpart, String domain) { | ||||||
|  |         this(parse(buildRaw(localpart, domain))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getLocalPart() { | ||||||
|  |         return localpart; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getDomain() { | ||||||
|  |         return domain; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public MatrixID canonicalize() { | ||||||
|  |         return parse(getId().toLowerCase()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isValid() { | ||||||
|  |         return isAcceptable() && STRICT_PATTERN.matcher(id).matches(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isAcceptable() { | ||||||
|  |         // TODO properly implement | ||||||
|  |  | ||||||
|  |         return id.length() <= 255; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean equals(Object o) { | ||||||
|  |         if (this == o) return true; | ||||||
|  |         if (!(o instanceof MatrixID)) return false; | ||||||
|  |  | ||||||
|  |         MatrixID matrixID = (MatrixID) o; | ||||||
|  |  | ||||||
|  |         return id.equals(matrixID.id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int hashCode() { | ||||||
|  |         return id.hashCode(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |         return getId(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										93
									
								
								src/main/java/io/kamax/matrix/MatrixIdCodec.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/main/java/io/kamax/matrix/MatrixIdCodec.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | import org.apache.commons.codec.DecoderException; | ||||||
|  | import org.apache.commons.codec.binary.Hex; | ||||||
|  |  | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  |  | ||||||
|  | import static io.kamax.matrix.MatrixID.ALLOWED_CHARS; | ||||||
|  |  | ||||||
|  | public class MatrixIdCodec { | ||||||
|  |  | ||||||
|  |     public static final String DELIMITER = "="; | ||||||
|  |     public static final String ENCODE_REGEX = "[^" + ALLOWED_CHARS + "]+"; | ||||||
|  |     public static final Pattern ENCODE_PATTERN = Pattern.compile(ENCODE_REGEX); | ||||||
|  |     public static final Pattern DECODE_PATTERN = Pattern.compile("(=[0-9a-f]{2})+"); | ||||||
|  |  | ||||||
|  |     private MatrixIdCodec() { | ||||||
|  |         // not for public consumption | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static String encode(String decoded) { | ||||||
|  |         decoded = decoded.toLowerCase(); | ||||||
|  |  | ||||||
|  |         StringBuilder builder = new StringBuilder(); | ||||||
|  |         for (Character c : decoded.toCharArray()) { | ||||||
|  |             String s = c.toString(); | ||||||
|  |             Matcher lp = ENCODE_PATTERN.matcher(s); | ||||||
|  |             if (!lp.find()) { | ||||||
|  |                 builder.append(s); | ||||||
|  |             } else { | ||||||
|  |                 for (byte b : c.toString().getBytes(StandardCharsets.UTF_8)) { | ||||||
|  |                     builder.append(DELIMITER); | ||||||
|  |                     builder.append(Hex.encodeHexString(new byte[] { b })); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return builder.toString(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static String decode(String encoded) { | ||||||
|  |         StringBuilder builder = new StringBuilder(); | ||||||
|  |  | ||||||
|  |         Matcher m = DECODE_PATTERN.matcher(encoded); | ||||||
|  |         int prevEnd = 0; | ||||||
|  |         while (m.find()) { | ||||||
|  |             try { | ||||||
|  |                 int start = m.start(); | ||||||
|  |                 int end = m.end(); | ||||||
|  |                 String sub = encoded.substring(start, end).replaceAll(DELIMITER, ""); | ||||||
|  |                 String decoded = new String(Hex.decodeHex(sub.toCharArray()), StandardCharsets.UTF_8); | ||||||
|  |                 builder.append(encoded, prevEnd, start); | ||||||
|  |                 builder.append(decoded); | ||||||
|  |                 prevEnd = end - 1; | ||||||
|  |             } catch (DecoderException e) { | ||||||
|  |                 e.printStackTrace(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         prevEnd++; | ||||||
|  |         if (prevEnd < encoded.length()) { | ||||||
|  |             builder.append(encoded, prevEnd, encoded.length()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (builder.length() == 0) { | ||||||
|  |             return encoded; | ||||||
|  |         } else { | ||||||
|  |             return builder.toString(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								src/main/java/io/kamax/matrix/MatrixPath.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/main/java/io/kamax/matrix/MatrixPath.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sàrl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | import java.io.UnsupportedEncodingException; | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URLEncoder; | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
|  |  | ||||||
|  | public class MatrixPath { | ||||||
|  |  | ||||||
|  |     public static String encode(String element) { | ||||||
|  |         try { | ||||||
|  |             return URLEncoder.encode(element, StandardCharsets.UTF_8.name()); | ||||||
|  |         } catch (UnsupportedEncodingException e) { | ||||||
|  |             // This would be madness if it happened, but we need to handle it still | ||||||
|  |             throw new RuntimeException(e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static MatrixPath with(String base) { | ||||||
|  |         return new MatrixPath().add(base); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixPath root() { | ||||||
|  |         return with(""); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixPath base() { | ||||||
|  |         return root().add("_matrix"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixPath client() { | ||||||
|  |         return base().add("client"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static MatrixPath clientR0() { | ||||||
|  |         return client().add("r0"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private StringBuilder path = new StringBuilder(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add the raw element to this path | ||||||
|  |      *  | ||||||
|  |      * @param element | ||||||
|  |      *            The raw element to be added as is to the path, without encoding or path separator | ||||||
|  |      * @return The MatrixPath | ||||||
|  |      */ | ||||||
|  |     public MatrixPath put(String element) { | ||||||
|  |         path.append(element); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * URL encode and add a new path element | ||||||
|  |      * | ||||||
|  |      * This method handle path separators | ||||||
|  |      *  | ||||||
|  |      * @param element | ||||||
|  |      *            The element to be encoded and added. | ||||||
|  |      * @return The MatrixPath | ||||||
|  |      */ | ||||||
|  |     public MatrixPath add(String element) { | ||||||
|  |         // We add a path separator if this is the first character or if the last character is not a path separator | ||||||
|  |         // already | ||||||
|  |         if (path.length() == 0 || path.lastIndexOf("/", 0) < path.length() - 1) { | ||||||
|  |             put("/"); | ||||||
|  |         } | ||||||
|  |         put(encode(element)); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String get() { | ||||||
|  |         return path.toString(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String toString() { | ||||||
|  |         return get(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public URI toURI() { | ||||||
|  |         return URI.create(toString()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								src/main/java/io/kamax/matrix/ThreePid.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/main/java/io/kamax/matrix/ThreePid.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public class ThreePid implements _ThreePid { | ||||||
|  |  | ||||||
|  |     private String medium; | ||||||
|  |     private String address; | ||||||
|  |  | ||||||
|  |     public ThreePid(String medium, String address) { | ||||||
|  |         this.medium = medium; | ||||||
|  |         this.address = address; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getMedium() { | ||||||
|  |         return medium; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getAddress() { | ||||||
|  |         return address; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean equals(Object o) { | ||||||
|  |         if (this == o) return true; | ||||||
|  |         if (o == null || getClass() != o.getClass()) return false; | ||||||
|  |  | ||||||
|  |         ThreePid threePid = (ThreePid) o; | ||||||
|  |  | ||||||
|  |         if (!medium.equals(threePid.medium)) return false; | ||||||
|  |         return address.equals(threePid.address); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int hashCode() { | ||||||
|  |         int result = medium.hashCode(); | ||||||
|  |         result = 31 * result + address.hashCode(); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								src/main/java/io/kamax/matrix/ThreePidMapping.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/main/java/io/kamax/matrix/ThreePidMapping.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public class ThreePidMapping implements _ThreePidMapping { | ||||||
|  |  | ||||||
|  |     private _ThreePid threePid; | ||||||
|  |     private _MatrixID mxId; | ||||||
|  |  | ||||||
|  |     public ThreePidMapping(_ThreePid threePid, _MatrixID mxId) { | ||||||
|  |         this.threePid = threePid; | ||||||
|  |         this.mxId = mxId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _ThreePid getThreePid() { | ||||||
|  |         return threePid; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixID getMatrixId() { | ||||||
|  |         return mxId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean equals(Object o) { | ||||||
|  |         if (this == o) return true; | ||||||
|  |         if (o == null || getClass() != o.getClass()) return false; | ||||||
|  |  | ||||||
|  |         ThreePidMapping that = (ThreePidMapping) o; | ||||||
|  |  | ||||||
|  |         if (!threePid.equals(that.threePid)) return false; | ||||||
|  |         return mxId.equals(that.mxId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int hashCode() { | ||||||
|  |         int result = threePid.hashCode(); | ||||||
|  |         result = 31 * result + mxId.hashCode(); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								src/main/java/io/kamax/matrix/ThreePidMedium.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/main/java/io/kamax/matrix/ThreePidMedium.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public enum ThreePidMedium { | ||||||
|  |  | ||||||
|  |     Email("email"), | ||||||
|  |     PhoneNumber("msisdn"); | ||||||
|  |  | ||||||
|  |     private String id; | ||||||
|  |  | ||||||
|  |     ThreePidMedium(String id) { | ||||||
|  |         this.id = id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String toString() { | ||||||
|  |         return getId(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean is(String s) { | ||||||
|  |         return getId().contentEquals(s); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								src/main/java/io/kamax/matrix/_MatrixContent.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/main/java/io/kamax/matrix/_MatrixContent.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public interface _MatrixContent { | ||||||
|  |  | ||||||
|  |     URI getAddress(); | ||||||
|  |  | ||||||
|  |     URL getPermaLink(); | ||||||
|  |  | ||||||
|  |     boolean isValid(); | ||||||
|  |  | ||||||
|  |     Optional<String> getType(); | ||||||
|  |  | ||||||
|  |     byte[] getData(); | ||||||
|  |  | ||||||
|  |     Optional<String> getFilename(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								src/main/java/io/kamax/matrix/_MatrixID.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/main/java/io/kamax/matrix/_MatrixID.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public interface _MatrixID { | ||||||
|  |  | ||||||
|  |     String getId(); | ||||||
|  |  | ||||||
|  |     String getLocalPart(); | ||||||
|  |  | ||||||
|  |     String getDomain(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Render this Matrix ID strictly valid. In technical term, transform this ID so | ||||||
|  |      * <code>isValid()</code> returns true. | ||||||
|  |      * | ||||||
|  |      * @return A canonical Matrix ID | ||||||
|  |      */ | ||||||
|  |     _MatrixID canonicalize(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * If the Matrix ID is strictly valid in the protocol as per | ||||||
|  |      * http://matrix.org/docs/spec/intro.html#user-identifiers | ||||||
|  |      * | ||||||
|  |      * @return true if strictly valid, false if not | ||||||
|  |      */ | ||||||
|  |     boolean isValid(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * If the Matrix ID is acceptable in the protocol as per | ||||||
|  |      * http://matrix.org/docs/spec/intro.html#historical-user-ids | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     boolean isAcceptable(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								src/main/java/io/kamax/matrix/_MatrixUser.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/main/java/io/kamax/matrix/_MatrixUser.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.client._Presence; | ||||||
|  |  | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public interface _MatrixUser extends _MatrixUserProfile { | ||||||
|  |  | ||||||
|  |     Optional<_Presence> getPresence(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								src/main/java/io/kamax/matrix/_MatrixUserProfile.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/main/java/io/kamax/matrix/_MatrixUserProfile.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public interface _MatrixUserProfile { | ||||||
|  |  | ||||||
|  |     _MatrixID getId(); | ||||||
|  |  | ||||||
|  |     Optional<String> getName(); | ||||||
|  |  | ||||||
|  |     void setName(String name); | ||||||
|  |  | ||||||
|  |     Optional<String> getAvatarUrl(); | ||||||
|  |  | ||||||
|  |     void setAvatar(String avatarRef); | ||||||
|  |  | ||||||
|  |     void setAvatar(URI avatarUri); | ||||||
|  |  | ||||||
|  |     Optional<_MatrixContent> getAvatar(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/main/java/io/kamax/matrix/_ThreePid.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/main/java/io/kamax/matrix/_ThreePid.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public interface _ThreePid { | ||||||
|  |  | ||||||
|  |     String getMedium(); | ||||||
|  |  | ||||||
|  |     String getAddress(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/main/java/io/kamax/matrix/_ThreePidMapping.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/main/java/io/kamax/matrix/_ThreePidMapping.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix; | ||||||
|  |  | ||||||
|  | public interface _ThreePidMapping { | ||||||
|  |  | ||||||
|  |     _ThreePid getThreePid(); | ||||||
|  |  | ||||||
|  |     _MatrixID getMatrixId(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										409
									
								
								src/main/java/io/kamax/matrix/client/AMatrixHttpClient.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								src/main/java/io/kamax/matrix/client/AMatrixHttpClient.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,409 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.Gson; | ||||||
|  | import com.google.gson.JsonParser; | ||||||
|  | import com.google.gson.JsonSyntaxException; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixErrorInfo; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix.hs._MatrixHomeserver; | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  |  | ||||||
|  | import org.apache.commons.lang3.ArrayUtils; | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.concurrent.TimeUnit; | ||||||
|  | import java.util.Objects; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.*; | ||||||
|  |  | ||||||
|  | public abstract class AMatrixHttpClient implements _MatrixClientRaw { | ||||||
|  |  | ||||||
|  |     private Logger log = LoggerFactory.getLogger(AMatrixHttpClient.class); | ||||||
|  |  | ||||||
|  |     protected MatrixClientContext context; | ||||||
|  |  | ||||||
|  |     protected Gson gson = GsonUtil.get(); | ||||||
|  |     protected JsonParser jsonParser = new JsonParser(); | ||||||
|  |     private OkHttpClient client; | ||||||
|  |  | ||||||
|  |     public AMatrixHttpClient(String domain) { | ||||||
|  |         this(new MatrixClientContext().setDomain(domain)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public AMatrixHttpClient(URL hsBaseUrl) { | ||||||
|  |         this(new MatrixClientContext().setHsBaseUrl(hsBaseUrl)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AMatrixHttpClient(MatrixClientContext context) { | ||||||
|  |         this(context, new OkHttpClient.Builder(), new MatrixClientDefaults()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AMatrixHttpClient(MatrixClientContext context, OkHttpClient.Builder client) { | ||||||
|  |         this(context, client, new MatrixClientDefaults()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AMatrixHttpClient(MatrixClientContext context, OkHttpClient.Builder client, | ||||||
|  |             MatrixClientDefaults defaults) { | ||||||
|  |         this(context, client.connectTimeout(defaults.getConnectTimeout(), TimeUnit.MILLISECONDS) | ||||||
|  |                 .readTimeout(5, TimeUnit.MINUTES).followRedirects(false).build()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected AMatrixHttpClient(MatrixClientContext context, OkHttpClient client) { | ||||||
|  |         this.context = context; | ||||||
|  |         this.client = client; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<_AutoDiscoverySettings> discoverSettings() { | ||||||
|  |         if (StringUtils.isBlank(context.getDomain())) { | ||||||
|  |             throw new IllegalStateException("A non-empty Matrix domain must be set to discover the client settings"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         String hostname = context.getDomain().split(":")[0]; | ||||||
|  |         log.info("Performing .well-known auto-discovery for {}", hostname); | ||||||
|  |  | ||||||
|  |         URL url = new HttpUrl.Builder().scheme("https").host(hostname).addPathSegments(".well-known/matrix/client") | ||||||
|  |                 .build().url(); | ||||||
|  |         String body = execute(new MatrixHttpRequest(new Request.Builder().get().url(url)).addIgnoredErrorCode(404)); | ||||||
|  |         if (StringUtils.isBlank(body)) { | ||||||
|  |             if (Objects.isNull(context.getHsBaseUrl())) { | ||||||
|  |                 throw new IllegalStateException("No valid Homeserver base URL was found"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // No .well-known data found | ||||||
|  |             // FIXME improve SDK so we can differentiate between not found and empty. | ||||||
|  |             // not found = skip | ||||||
|  |             // empty = failure | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         log.info("Found body: {}", body); | ||||||
|  |  | ||||||
|  |         WellKnownAutoDiscoverySettings settings = new WellKnownAutoDiscoverySettings(body); | ||||||
|  |         log.info("Found .well-known data"); | ||||||
|  |  | ||||||
|  |         // TODO reconsider if and where we should check for an already present HS url in the context | ||||||
|  |         if (settings.getHsBaseUrls().isEmpty()) { | ||||||
|  |             throw new IllegalStateException("No valid Homeserver base URL was found"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (URL baseUrlCandidate : settings.getHsBaseUrls()) { | ||||||
|  |             context.setHsBaseUrl(baseUrlCandidate); | ||||||
|  |             try { | ||||||
|  |                 if (!getHomeApiVersions().isEmpty()) { | ||||||
|  |                     log.info("Found a valid HS at {}", getContext().getHsBaseUrl().toString()); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } catch (MatrixClientRequestException e) { | ||||||
|  |                 log.warn("Error when trying to fetch {}: {}", baseUrlCandidate, e.getMessage()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (URL baseUrlCandidate : settings.getIsBaseUrls()) { | ||||||
|  |             context.setIsBaseUrl(baseUrlCandidate); | ||||||
|  |             try { | ||||||
|  |                 if (validateIsBaseUrl()) { | ||||||
|  |                     log.info("Found a valid IS at {}", getContext().getIsBaseUrl().toString()); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } catch (MatrixClientRequestException e) { | ||||||
|  |                 log.warn("Error when trying to fetch {}: {}", baseUrlCandidate, e.getMessage()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return Optional.of(settings); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public MatrixClientContext getContext() { | ||||||
|  |         return context; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixHomeserver getHomeserver() { | ||||||
|  |         return context.getHomeserver(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getAccessToken() { | ||||||
|  |         return Optional.ofNullable(context.getToken()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getAccessTokenOrThrow() { | ||||||
|  |         return getAccessToken() | ||||||
|  |                 .orElseThrow(() -> new IllegalStateException("This method can only be used with a valid token.")); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<String> getHomeApiVersions() { | ||||||
|  |         String body = execute(new Request.Builder().get().url(getPath("client", "", "versions"))); | ||||||
|  |         return GsonUtil.asList(GsonUtil.parseObj(body), "versions", String.class); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean validateIsBaseUrl() { | ||||||
|  |         String body = execute(new Request.Builder().get().url(getIdentityPath("identity", "api", "v1"))); | ||||||
|  |         return "{}".equals(body); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected String getUserId() { | ||||||
|  |         return getUser().orElseThrow(IllegalStateException::new).getId(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<_MatrixID> getUser() { | ||||||
|  |         return context.getUser(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected Request.Builder addAuthHeader(Request.Builder builder, String token) { | ||||||
|  |         builder.addHeader("Authorization", "Bearer " + token); | ||||||
|  |         return builder; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected Request.Builder addAuthHeader(Request.Builder builder) { | ||||||
|  |         return addAuthHeader(builder, getAccessTokenOrThrow()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected String executeAuthenticated(Request.Builder builder, String token) { | ||||||
|  |         return execute(addAuthHeader(builder, token)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected String executeAuthenticated(Request.Builder builder) { | ||||||
|  |         return execute(addAuthHeader(builder)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected String executeAuthenticated(MatrixHttpRequest matrixRequest) { | ||||||
|  |         addAuthHeader(matrixRequest.getHttpRequest()); | ||||||
|  |         return execute(matrixRequest); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected String execute(Request.Builder builder) { | ||||||
|  |         return execute(new MatrixHttpRequest(builder)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected String execute(MatrixHttpRequest matrixRequest) { | ||||||
|  |         log(matrixRequest.getHttpRequest()); | ||||||
|  |         try (Response response = client.newCall(matrixRequest.getHttpRequest().build()).execute()) { | ||||||
|  |             String body = response.body().string(); | ||||||
|  |             int responseStatus = response.code(); | ||||||
|  |  | ||||||
|  |             if (responseStatus == 200) { | ||||||
|  |                 log.debug("Request successfully executed."); | ||||||
|  |             } else if (matrixRequest.getIgnoredErrorCodes().contains(responseStatus)) { | ||||||
|  |                 log.debug("Error code ignored: " + responseStatus); | ||||||
|  |                 return ""; | ||||||
|  |             } else { | ||||||
|  |                 MatrixErrorInfo info = createErrorInfo(body, responseStatus); | ||||||
|  |  | ||||||
|  |                 body = handleError(matrixRequest, responseStatus, info); | ||||||
|  |             } | ||||||
|  |             return body; | ||||||
|  |         } catch (IOException e) { | ||||||
|  |             throw new MatrixClientRequestException(e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected MatrixHttpContentResult executeContentRequest(MatrixHttpRequest matrixRequest) { | ||||||
|  |         log(matrixRequest.getHttpRequest()); | ||||||
|  |         try (Response response = client.newCall(matrixRequest.getHttpRequest().build()).execute()) { | ||||||
|  |             int responseStatus = response.code(); | ||||||
|  |  | ||||||
|  |             MatrixHttpContentResult result; | ||||||
|  |  | ||||||
|  |             if (responseStatus == 200 || matrixRequest.getIgnoredErrorCodes().contains(responseStatus)) { | ||||||
|  |                 log.debug("Request successfully executed."); | ||||||
|  |                 result = new MatrixHttpContentResult(response); | ||||||
|  |             } else { | ||||||
|  |                 String body = response.body().string(); | ||||||
|  |                 MatrixErrorInfo info = createErrorInfo(body, responseStatus); | ||||||
|  |  | ||||||
|  |                 result = handleErrorContentRequest(matrixRequest, responseStatus, info); | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         } catch (IOException e) { | ||||||
|  |             throw new MatrixClientRequestException(e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Default handling of errors. Can be overwritten by a custom implementation in inherited classes. | ||||||
|  |      * | ||||||
|  |      * @param matrixRequest | ||||||
|  |      * @param responseStatus | ||||||
|  |      * @param info | ||||||
|  |      * @return body of the response of a repeated call of the request, else this methods throws a | ||||||
|  |      *         MatrixClientRequestException | ||||||
|  |      */ | ||||||
|  |     protected String handleError(MatrixHttpRequest matrixRequest, int responseStatus, MatrixErrorInfo info) { | ||||||
|  |         String message = String.format("Request failed: %s", responseStatus); | ||||||
|  |  | ||||||
|  |         if (Objects.nonNull(info)) { | ||||||
|  |             message = String.format("%s - %s - %s", message, info.getErrcode(), info.getError()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (responseStatus == 429) { | ||||||
|  |             return handleRateLimited(matrixRequest, info); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new MatrixClientRequestException(info, message); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Default handling of rate limited calls. Can be overwritten by a custom implementation in inherited classes. | ||||||
|  |      * | ||||||
|  |      * @param matrixRequest | ||||||
|  |      * @param info | ||||||
|  |      * @return body of the response of a repeated call of the request, else this methods throws a | ||||||
|  |      *         MatrixClientRequestException | ||||||
|  |      */ | ||||||
|  |     protected String handleRateLimited(MatrixHttpRequest matrixRequest, MatrixErrorInfo info) { | ||||||
|  |         throw new MatrixClientRequestException(info, "Request was rate limited."); | ||||||
|  |         // TODO Add default handling of rate limited call, i.e. repeated call after given time interval. | ||||||
|  |         // 1. Wait for timeout | ||||||
|  |         // 2. return execute(request) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected MatrixHttpContentResult handleErrorContentRequest(MatrixHttpRequest matrixRequest, int responseStatus, | ||||||
|  |             MatrixErrorInfo info) { | ||||||
|  |         String message = String.format("Request failed with status code: %s", responseStatus); | ||||||
|  |  | ||||||
|  |         if (responseStatus == 429) { | ||||||
|  |             return handleRateLimitedContentRequest(matrixRequest, info); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new MatrixClientRequestException(info, message); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected MatrixHttpContentResult handleRateLimitedContentRequest(MatrixHttpRequest matrixRequest, | ||||||
|  |             MatrixErrorInfo info) { | ||||||
|  |         throw new MatrixClientRequestRateLimitedException(info, "Request was rate limited."); | ||||||
|  |         // TODO Add default handling of rate limited call, i.e. repeated call after given time interval. | ||||||
|  |         // 1. Wait for timeout | ||||||
|  |         // 2. return execute(request) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected Optional<String> extractAsStringFromBody(String body, String jsonObjectName) { | ||||||
|  |         if (StringUtils.isEmpty(body)) { | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return GsonUtil.findString(jsonParser.parse(body).getAsJsonObject(), jsonObjectName); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private MatrixErrorInfo createErrorInfo(String body, int responseStatus) { | ||||||
|  |         MatrixErrorInfo info = null; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             info = gson.fromJson(body, MatrixErrorInfo.class); | ||||||
|  |             if (Objects.nonNull(info)) { | ||||||
|  |                 log.debug("Request returned with an error. Status code: {}, errcode: {}, error: {}", responseStatus, | ||||||
|  |                         info.getErrcode(), info.getError()); | ||||||
|  |             } | ||||||
|  |         } catch (JsonSyntaxException e) { | ||||||
|  |             log.debug("Unable to parse Matrix error info. Content was:\n{}", body); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return info; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void log(Request.Builder req) { | ||||||
|  |         log.debug("Doing {} {}", req, req.toString()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getHsBaseUrl() { | ||||||
|  |         return HttpUrl.get(context.getHsBaseUrl()).newBuilder(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getIsBaseUrl() { | ||||||
|  |         return HttpUrl.get(context.getIsBaseUrl()).newBuilder(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getPathBuilder(HttpUrl.Builder base, String... segments) { | ||||||
|  |         base.addPathSegment("_matrix"); | ||||||
|  |         for (String segment : segments) { | ||||||
|  |             base.addPathSegment(segment); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (context.isVirtual()) { | ||||||
|  |             context.getUser().ifPresent(user -> base.addQueryParameter("user_id", user.getId())); | ||||||
|  |         } | ||||||
|  |         return base; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getPathBuilder(String... segments) { | ||||||
|  |         return getPathBuilder(getHsBaseUrl(), segments); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getIdentityPathBuilder(String... segments) { | ||||||
|  |         return getPathBuilder(getIsBaseUrl(), segments); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected URL getPath(String... segments) { | ||||||
|  |         return getPathBuilder(segments).build().url(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected URL getIdentityPath(String... segments) { | ||||||
|  |         return getIdentityPathBuilder(segments).build().url(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getClientPathBuilder(String... segments) { | ||||||
|  |         String[] base = { "client", "r0" }; | ||||||
|  |         segments = ArrayUtils.addAll(base, segments); | ||||||
|  |         return getPathBuilder(segments); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected HttpUrl.Builder getMediaPathBuilder(String... segments) { | ||||||
|  |         String[] base = { "media", "r0" }; | ||||||
|  |         segments = ArrayUtils.addAll(base, segments); | ||||||
|  |         return getPathBuilder(segments); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected URL getClientPath(String... segments) { | ||||||
|  |         return getClientPathBuilder(segments).build().url(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected URL getMediaPath(String... segments) { | ||||||
|  |         return getMediaPathBuilder(segments).build().url(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected RequestBody getJsonBody(Object o) { | ||||||
|  |         return RequestBody.create(MediaType.parse("application/json"), GsonUtil.get().toJson(o)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected Request.Builder request(URL url) { | ||||||
|  |         return new Request.Builder().url(url); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected Request.Builder getRequest(URL url) { | ||||||
|  |         return request(url).get(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										154
									
								
								src/main/java/io/kamax/matrix/client/MatrixClientContext.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/main/java/io/kamax/matrix/client/MatrixClientContext.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix.hs.MatrixHomeserver; | ||||||
|  | import io.kamax.matrix.hs._MatrixHomeserver; | ||||||
|  |  | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.Objects; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public class MatrixClientContext { | ||||||
|  |  | ||||||
|  |     private String domain; | ||||||
|  |     private URL hsBaseUrl; | ||||||
|  |     private URL isBaseUrl; | ||||||
|  |     private _MatrixID user; | ||||||
|  |     private String token; | ||||||
|  |     private boolean isVirtual; | ||||||
|  |     private String deviceId; | ||||||
|  |     private String initialDeviceName; | ||||||
|  |  | ||||||
|  |     public MatrixClientContext() { | ||||||
|  |         // stub | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext(MatrixClientContext other) { | ||||||
|  |         this.domain = other.domain; | ||||||
|  |         this.hsBaseUrl = other.hsBaseUrl; | ||||||
|  |         this.isBaseUrl = other.isBaseUrl; | ||||||
|  |         this.user = other.user; | ||||||
|  |         this.token = other.token; | ||||||
|  |         this.isVirtual = other.isVirtual; | ||||||
|  |         this.deviceId = other.deviceId; | ||||||
|  |         this.initialDeviceName = other.initialDeviceName; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext(_MatrixHomeserver hs) { | ||||||
|  |         setDomain(hs.getDomain()); | ||||||
|  |         setHsBaseUrl(hs.getBaseEndpoint()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext(_MatrixHomeserver hs, _MatrixID user, String token) { | ||||||
|  |         this(hs); | ||||||
|  |         setUser(user); | ||||||
|  |         setToken(token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public _MatrixHomeserver getHomeserver() { | ||||||
|  |         if (Objects.isNull(hsBaseUrl)) { | ||||||
|  |             throw new IllegalStateException("Homeserver Base URL is not set"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new MatrixHomeserver(domain, hsBaseUrl.toString()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getDomain() { | ||||||
|  |         return domain; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setDomain(String domain) { | ||||||
|  |         this.domain = domain; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public URL getHsBaseUrl() { | ||||||
|  |         return hsBaseUrl; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setHsBaseUrl(URL hsBaseUrl) { | ||||||
|  |         this.hsBaseUrl = hsBaseUrl; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public URL getIsBaseUrl() { | ||||||
|  |         return isBaseUrl; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setIsBaseUrl(URL isBaseUrl) { | ||||||
|  |         this.isBaseUrl = isBaseUrl; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Optional<_MatrixID> getUser() { | ||||||
|  |         return Optional.ofNullable(user); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setUser(_MatrixID user) { | ||||||
|  |         this.user = user; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setUserWithLocalpart(String localpart) { | ||||||
|  |         setUser(MatrixID.asAcceptable(localpart, getDomain())); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getToken() { | ||||||
|  |         return token; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setToken(String token) { | ||||||
|  |         this.token = token; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean isVirtual() { | ||||||
|  |         return isVirtual; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setVirtual(boolean virtual) { | ||||||
|  |         isVirtual = virtual; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getDeviceId() { | ||||||
|  |         return deviceId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setDeviceId(String deviceId) { | ||||||
|  |         this.deviceId = deviceId; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getInitialDeviceName() { | ||||||
|  |         return initialDeviceName; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientContext setInitialDeviceName(String initialDeviceName) { | ||||||
|  |         this.initialDeviceName = initialDeviceName; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,59 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | public class MatrixClientDefaults { | ||||||
|  |  | ||||||
|  |     private int connectTimeout = 30 * 1000; // 30 sec | ||||||
|  |     private int requestTimeout = 5 * 60 * 1000; // 5 min | ||||||
|  |     private int socketTimeout = requestTimeout; | ||||||
|  |  | ||||||
|  |     public int getConnectTimeout() { | ||||||
|  |         return connectTimeout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientDefaults setConnectTimeout(int connectTimeout) { | ||||||
|  |         this.connectTimeout = connectTimeout; | ||||||
|  |  | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public int getRequestTimeout() { | ||||||
|  |         return requestTimeout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientDefaults setRequestTimeout(int requestTimeout) { | ||||||
|  |         this.requestTimeout = requestTimeout; | ||||||
|  |  | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public int getSocketTimeout() { | ||||||
|  |         return socketTimeout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientDefaults setSocketTimeout(int socketTimeout) { | ||||||
|  |         this.socketTimeout = socketTimeout; | ||||||
|  |  | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,46 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixErrorInfo; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public class MatrixClientRequestException extends RuntimeException { | ||||||
|  |  | ||||||
|  |     private MatrixErrorInfo errorInfo; | ||||||
|  |  | ||||||
|  |     public MatrixClientRequestException(IOException e) { | ||||||
|  |         super(e); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixClientRequestException(MatrixErrorInfo errorInfo, String message) { | ||||||
|  |         super(message); | ||||||
|  |  | ||||||
|  |         this.errorInfo = errorInfo; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Optional<MatrixErrorInfo> getError() { | ||||||
|  |         return Optional.ofNullable(errorInfo); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixErrorInfo; | ||||||
|  |  | ||||||
|  | public class MatrixClientRequestRateLimitedException extends MatrixClientRequestException { | ||||||
|  |  | ||||||
|  |     public MatrixClientRequestRateLimitedException(MatrixErrorInfo errorInfo, String message) { | ||||||
|  |         super(errorInfo, message); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										133
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpContent.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpContent.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix._MatrixContent; | ||||||
|  |  | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.Request; | ||||||
|  |  | ||||||
|  | public class MatrixHttpContent extends AMatrixHttpClient implements _MatrixContent { | ||||||
|  |  | ||||||
|  |     private Logger log = LoggerFactory.getLogger(MatrixHttpContent.class); | ||||||
|  |     private final Pattern filenamePattern = Pattern.compile("filename=\"?([^\";]+)"); | ||||||
|  |     private URI address; | ||||||
|  |  | ||||||
|  |     private MatrixHttpContentResult result; | ||||||
|  |  | ||||||
|  |     private boolean loaded = false; | ||||||
|  |     private boolean valid = false; | ||||||
|  |  | ||||||
|  |     public MatrixHttpContent(MatrixClientContext context, URI address) { | ||||||
|  |         super(context); | ||||||
|  |         this.address = address; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // TODO switch a HTTP HEAD to fetch initial data, instead of loading in memory directly | ||||||
|  |     private synchronized void load() { | ||||||
|  |         if (loaded) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             if (!StringUtils.equalsIgnoreCase("mxc", address.getScheme())) { | ||||||
|  |                 log.debug("{} is not a supported protocol for avatars, ignoring", address.getScheme()); | ||||||
|  |             } else { | ||||||
|  |                 MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().url(getPermaLink())); | ||||||
|  |                 result = executeContentRequest(request); | ||||||
|  |                 valid = result.isValid(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         } catch (MatrixClientRequestException e) { | ||||||
|  |             valid = false; | ||||||
|  |         } | ||||||
|  |         loaded = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public URI getAddress() { | ||||||
|  |         return address; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public URL getPermaLink() { | ||||||
|  |         return getMediaPathBuilder("download", address.getHost()).addEncodedPathSegments(address.getPath().substring(1)) | ||||||
|  |                 .build().url(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isValid() { | ||||||
|  |         load(); | ||||||
|  |  | ||||||
|  |         return valid; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getType() { | ||||||
|  |         load(); | ||||||
|  |  | ||||||
|  |         if (!isValid()) { | ||||||
|  |             throw new IllegalStateException("This method should only be called, if valid is true."); | ||||||
|  |         } | ||||||
|  |         return result.getContentType(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public byte[] getData() { | ||||||
|  |         load(); | ||||||
|  |  | ||||||
|  |         if (!isValid()) { | ||||||
|  |             throw new IllegalStateException("This method should only be called, if valid is true."); | ||||||
|  |         } | ||||||
|  |         return result.getData(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getFilename() { | ||||||
|  |         load(); | ||||||
|  |  | ||||||
|  |         if (!isValid()) { | ||||||
|  |             throw new IllegalStateException("This method should only be called, if valid is true."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result.getHeader("Content-Disposition").filter(l -> !l.isEmpty()).flatMap(l -> { | ||||||
|  |             for (String v : l) { | ||||||
|  |                 Matcher m = filenamePattern.matcher(v); | ||||||
|  |                 if (m.find()) { | ||||||
|  |                     return Optional.of(m.group(1)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return Optional.empty(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,71 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.MediaType; | ||||||
|  | import okhttp3.Response; | ||||||
|  | import okhttp3.ResponseBody; | ||||||
|  |  | ||||||
|  | public class MatrixHttpContentResult { | ||||||
|  |  | ||||||
|  |     private final boolean valid; | ||||||
|  |     private final Map<String, List<String>> headers; | ||||||
|  |     private final Optional<String> contentType; | ||||||
|  |     private final byte[] data; | ||||||
|  |  | ||||||
|  |     public MatrixHttpContentResult(Response response) throws IOException { | ||||||
|  |         try (ResponseBody body = response.body()) { | ||||||
|  |             boolean hasBody = Objects.nonNull(body); | ||||||
|  |             valid = hasBody && response.code() == 200; | ||||||
|  |             headers = response.headers().toMultimap(); | ||||||
|  |  | ||||||
|  |             if (hasBody) { | ||||||
|  |                 contentType = Optional.ofNullable(body.contentType()).map(MediaType::toString); | ||||||
|  |                 data = body.bytes(); | ||||||
|  |             } else { | ||||||
|  |                 contentType = Optional.empty(); | ||||||
|  |                 data = new byte[0]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean isValid() { | ||||||
|  |         return valid; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Optional<List<String>> getHeader(String name) { | ||||||
|  |         return Optional.ofNullable(headers.get(name)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Optional<String> getContentType() { | ||||||
|  |         return contentType; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public byte[] getData() { | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										93
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpPushRule.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpPushRule.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonArray; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  |  | ||||||
|  | import org.apache.commons.lang3.ArrayUtils; | ||||||
|  |  | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import javax.swing.*; | ||||||
|  |  | ||||||
|  | public class MatrixHttpPushRule extends AMatrixHttpClient implements _PushRule { | ||||||
|  |  | ||||||
|  |     private static final String ActionKey = "actions"; | ||||||
|  |     private static final String EnabledKey = "enabled"; | ||||||
|  |  | ||||||
|  |     private final String[] baseSegments; | ||||||
|  |  | ||||||
|  |     public MatrixHttpPushRule(MatrixClientContext context, String scope, String kind, String id) { | ||||||
|  |         super(context); | ||||||
|  |         baseSegments = new String[] { "pushrules", scope, kind, id }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private URL makeUrl() { | ||||||
|  |         return getClientPath(baseSegments); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private URL makeUrl(String... segments) { | ||||||
|  |         return getClientPath(ArrayUtils.addAll(baseSegments, segments)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public JsonObject getJson() { | ||||||
|  |         return GsonUtil.parseObj(executeAuthenticated(getRequest(makeUrl()))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void set(JsonObject data) { | ||||||
|  |         executeAuthenticated(request(makeUrl()).put(getJsonBody(data))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void delete() { | ||||||
|  |         executeAuthenticated(request(makeUrl()).delete()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public boolean isEnabled() { | ||||||
|  |         JsonObject response = GsonUtil.parseObj(executeAuthenticated(getRequest(makeUrl(EnabledKey)))); | ||||||
|  |         return GsonUtil.getPrimitive(response, EnabledKey).getAsBoolean(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setEnabled(boolean enabled) { | ||||||
|  |         executeAuthenticated(request(makeUrl(EnabledKey)).put(getJsonBody(GsonUtil.makeObj(EnabledKey, enabled)))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<String> getActions() { | ||||||
|  |         JsonObject response = GsonUtil.parseObj(executeAuthenticated(getRequest(makeUrl(ActionKey)))); | ||||||
|  |         return GsonUtil.asList(GsonUtil.findArray(response, ActionKey).orElseGet(JsonArray::new), String.class); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setActions(List<String> data) { | ||||||
|  |         executeAuthenticated( | ||||||
|  |                 request(makeUrl(ActionKey)).put(getJsonBody(GsonUtil.makeObj(ActionKey, GsonUtil.asArray(data))))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										50
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpRequest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpRequest.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.Request; | ||||||
|  |  | ||||||
|  | public class MatrixHttpRequest { | ||||||
|  |     private final Request.Builder httpRequest; | ||||||
|  |     private List<Integer> ignoredErrorCodes = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |     public MatrixHttpRequest(Request.Builder request) { | ||||||
|  |         this.httpRequest = request; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixHttpRequest addIgnoredErrorCode(int errcode) { | ||||||
|  |         ignoredErrorCodes.add(errcode); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Request.Builder getHttpRequest() { | ||||||
|  |         return httpRequest; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public List<Integer> getIgnoredErrorCodes() { | ||||||
|  |         return ignoredErrorCodes; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										440
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpRoom.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										440
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpRoom.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,440 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonElement; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixErrorInfo; | ||||||
|  | import io.kamax.matrix.MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixContent; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixUserProfile; | ||||||
|  | import io.kamax.matrix.hs._MatrixRoom; | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  | import io.kamax.matrix.json.RoomMessageChunkResponseJson; | ||||||
|  | import io.kamax.matrix.json.RoomMessageFormattedTextPutBody; | ||||||
|  | import io.kamax.matrix.json.RoomMessageTextPutBody; | ||||||
|  | import io.kamax.matrix.json.RoomTagSetBody; | ||||||
|  | import io.kamax.matrix.json.event.MatrixJsonPersistentEvent; | ||||||
|  | import io.kamax.matrix.room.*; | ||||||
|  |  | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URISyntaxException; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.HttpUrl; | ||||||
|  | import okhttp3.Request; | ||||||
|  |  | ||||||
|  | public class MatrixHttpRoom extends AMatrixHttpClient implements _MatrixRoom { | ||||||
|  |  | ||||||
|  |     private Logger log = LoggerFactory.getLogger(MatrixHttpRoom.class); | ||||||
|  |  | ||||||
|  |     private String roomId; | ||||||
|  |  | ||||||
|  |     public MatrixHttpRoom(MatrixClientContext context, String roomId) { | ||||||
|  |         super(context); | ||||||
|  |         this.roomId = roomId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getAddress() { | ||||||
|  |         return roomId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getName() { | ||||||
|  |         return getState("m.room.name").flatMap(obj -> GsonUtil.findString(obj, "name")); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getTopic() { | ||||||
|  |         return getState("m.room.topic").flatMap(obj -> GsonUtil.findString(obj, "topic")); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getAvatarUrl() { | ||||||
|  |         return getState("m.room.avatar").flatMap(obj -> GsonUtil.findString(obj, "url")); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<_MatrixContent> getAvatar() { | ||||||
|  |         return getAvatarUrl().flatMap(url -> { | ||||||
|  |             try { | ||||||
|  |                 return Optional.of(new MatrixHttpContent(context, new URI(url))); | ||||||
|  |             } catch (URISyntaxException e) { | ||||||
|  |                 log.debug("{} is not a valid URI for avatar, returning empty", url); | ||||||
|  |                 return Optional.empty(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getId() { | ||||||
|  |         return roomId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<JsonObject> getState(String type) { | ||||||
|  |         URL path = getClientPath("rooms", getAddress(), "state", type); | ||||||
|  |  | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().get().url(path)); | ||||||
|  |         request.addIgnoredErrorCode(404); | ||||||
|  |         String body = executeAuthenticated(request); | ||||||
|  |         if (StringUtils.isBlank(body)) { | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return Optional.of(GsonUtil.parseObj(body)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<JsonObject> getState(String type, String key) { | ||||||
|  |         URL path = getClientPath("rooms", roomId, "state", type, key); | ||||||
|  |  | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().get().url(path)); | ||||||
|  |         request.addIgnoredErrorCode(404); | ||||||
|  |         String body = executeAuthenticated(request); | ||||||
|  |         if (StringUtils.isBlank(body)) { | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return Optional.of(GsonUtil.parseObj(body)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void join() { | ||||||
|  |         join(Collections.emptyList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void join(List<String> servers) { | ||||||
|  |         HttpUrl.Builder b = getClientPathBuilder("rooms", roomId, "join"); | ||||||
|  |         servers.forEach(server -> b.addQueryParameter("server_name", server)); | ||||||
|  |         executeAuthenticated(new Request.Builder().post(getJsonBody(new JsonObject())).url(b.build())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<MatrixErrorInfo> tryJoin() { | ||||||
|  |         return tryJoin(Collections.emptyList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<MatrixErrorInfo> tryJoin(List<String> servers) { | ||||||
|  |         try { | ||||||
|  |             join(servers); | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } catch (MatrixClientRequestException e) { | ||||||
|  |             return e.getError(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void leave() { | ||||||
|  |         URL path = getClientPath("rooms", roomId, "leave"); | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest( | ||||||
|  |                 new Request.Builder().post(getJsonBody(new JsonObject())).url(path)); | ||||||
|  |  | ||||||
|  |         // TODO Find a better way to handle room objects for unknown rooms | ||||||
|  |         // Maybe throw exception? | ||||||
|  |         // TODO implement method to check room existence - isValid() ? | ||||||
|  |         // if (res.getStatusLine().getStatusCode() == 404) { | ||||||
|  |         // log.warn("Room {} is not joined, ignoring call", roomId); | ||||||
|  |         // return; | ||||||
|  |         // } | ||||||
|  |         request.addIgnoredErrorCode(404); | ||||||
|  |         executeAuthenticated(request); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<MatrixErrorInfo> tryLeave() { | ||||||
|  |         try { | ||||||
|  |             leave(); | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } catch (MatrixClientRequestException e) { | ||||||
|  |             return e.getError(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void kick(_MatrixID user) { | ||||||
|  |         kick(user, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void kick(_MatrixID user, String reason) { | ||||||
|  |         JsonObject body = new JsonObject(); | ||||||
|  |         body.addProperty("user_id", user.getId()); | ||||||
|  |         body.addProperty("reason", reason); | ||||||
|  |         URL path = getClientPath("rooms", roomId, "kick"); | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().post(getJsonBody(body)).url(path)); | ||||||
|  |         executeAuthenticated(request); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<MatrixErrorInfo> tryKick(_MatrixID user) { | ||||||
|  |         return tryKick(user, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<MatrixErrorInfo> tryKick(_MatrixID user, String reason) { | ||||||
|  |         try { | ||||||
|  |             kick(user, reason); | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } catch (MatrixClientRequestException e) { | ||||||
|  |             return e.getError(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String sendEvent(String type, JsonObject content) { | ||||||
|  |         // FIXME URL encoding | ||||||
|  |         URL path = getClientPath("rooms", roomId, "send", type, Long.toString(System.currentTimeMillis())); | ||||||
|  |         String body = executeAuthenticated(new Request.Builder().put(getJsonBody(content)).url(path)); | ||||||
|  |         return GsonUtil.getStringOrThrow(GsonUtil.parseObj(body), "event_id"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private String sendMessage(RoomMessageTextPutBody content) { | ||||||
|  |         return sendEvent("m.room.message", GsonUtil.makeObj(content)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String sendText(String message) { | ||||||
|  |         return sendMessage(new RoomMessageTextPutBody(message)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String sendFormattedText(String formatted, String rawFallback) { | ||||||
|  |         // TODO sanitize input | ||||||
|  |         return sendMessage(new RoomMessageFormattedTextPutBody(rawFallback, formatted)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String sendNotice(String message) { | ||||||
|  |         return sendMessage(new RoomMessageTextPutBody("m.notice", message)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String sendNotice(String formatted, String plain) { | ||||||
|  |         // TODO sanitize input | ||||||
|  |         return sendMessage(new RoomMessageFormattedTextPutBody("m.notice", plain, formatted)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void sendReceipt(String type, String eventId) { | ||||||
|  |         URL path = getClientPath("rooms", roomId, "receipt", type, eventId); | ||||||
|  |         executeAuthenticated(new Request.Builder().post(getJsonBody(new JsonObject())).url(path)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void sendReceipt(ReceiptType type, String eventId) { | ||||||
|  |         sendReceipt(type.getId(), eventId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void sendReadReceipt(String eventId) { | ||||||
|  |         sendReceipt(ReceiptType.Read, eventId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void invite(_MatrixID mxId) { | ||||||
|  |         URL path = getClientPath("rooms", roomId, "invite"); | ||||||
|  |         executeAuthenticated( | ||||||
|  |                 new Request.Builder().post(getJsonBody(GsonUtil.makeObj("user_id", mxId.getId()))).url(path)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<_MatrixUserProfile> getJoinedUsers() { | ||||||
|  |         URL path = getClientPath("rooms", roomId, "joined_members"); | ||||||
|  |         String body = executeAuthenticated(new Request.Builder().get().url(path)); | ||||||
|  |  | ||||||
|  |         List<_MatrixUserProfile> ids = new ArrayList<>(); | ||||||
|  |         if (StringUtils.isNotEmpty(body)) { | ||||||
|  |             JsonObject joinedUsers = jsonParser.parse(body).getAsJsonObject().get("joined").getAsJsonObject(); | ||||||
|  |             ids = joinedUsers.entrySet().stream().filter(e -> e.getValue().isJsonObject()).map(entry -> { | ||||||
|  |                 JsonObject obj = entry.getValue().getAsJsonObject(); | ||||||
|  |                 return new MatrixHttpUser(getContext(), MatrixID.asAcceptable(entry.getKey())) { | ||||||
|  |  | ||||||
|  |                     @Override | ||||||
|  |                     public Optional<String> getName() { | ||||||
|  |                         return GsonUtil.findString(obj, "display_name"); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     @Override | ||||||
|  |                     public Optional<_MatrixContent> getAvatar() { | ||||||
|  |                         return GsonUtil.findString(obj, "avatar_url").flatMap(s -> { | ||||||
|  |                             try { | ||||||
|  |                                 return Optional.of(new URI(s)); | ||||||
|  |                             } catch (URISyntaxException e) { | ||||||
|  |                                 return Optional.empty(); | ||||||
|  |                             } | ||||||
|  |                         }).map(uri -> new MatrixHttpContent(getContext(), uri)); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                 }; | ||||||
|  |             }).collect(Collectors.toList()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return ids; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixRoomMessageChunk getMessages(_MatrixRoomMessageChunkOptions options) { | ||||||
|  |         HttpUrl.Builder builder = getClientPathBuilder("rooms", roomId, "messages"); | ||||||
|  |         builder.addQueryParameter("from", options.getFromToken()); | ||||||
|  |         builder.addQueryParameter("dir", options.getDirection()); | ||||||
|  |         options.getToToken().ifPresent(token -> builder.addQueryParameter("to", token)); | ||||||
|  |         options.getLimit().ifPresent(limit -> builder.addQueryParameter("limit", limit.toString())); | ||||||
|  |  | ||||||
|  |         String bodyRaw = executeAuthenticated(new Request.Builder().get().url(builder.build().url())); | ||||||
|  |         RoomMessageChunkResponseJson body = GsonUtil.get().fromJson(bodyRaw, RoomMessageChunkResponseJson.class); | ||||||
|  |         return new MatrixRoomMessageChunk(body.getStart(), body.getEnd(), | ||||||
|  |                 body.getChunk().stream().map(MatrixJsonPersistentEvent::new).collect(Collectors.toList())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<Tag> getUserTags() { | ||||||
|  |         return getAllTags().stream().filter(tag -> "u".equals(tag.getNamespace())) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<Tag> getAllTags() { | ||||||
|  |  | ||||||
|  |         URL path = getClientPath("user", getUserId(), "rooms", getAddress(), "tags"); | ||||||
|  |  | ||||||
|  |         String body = executeAuthenticated(new Request.Builder().get().url(path)); | ||||||
|  |  | ||||||
|  |         JsonObject jsonTags = GsonUtil.parseObj(body).getAsJsonObject("tags").getAsJsonObject(); | ||||||
|  |         List<Tag> tags = jsonTags.entrySet().stream().map(entry -> { | ||||||
|  |             String completeName = entry.getKey(); | ||||||
|  |             String name = ""; | ||||||
|  |             String namespace = ""; | ||||||
|  |             if (completeName.startsWith("m.")) { | ||||||
|  |                 name = completeName.substring(2); | ||||||
|  |                 namespace = "m"; | ||||||
|  |             } else if (completeName.startsWith("u.")) { | ||||||
|  |                 name = completeName.substring(2); | ||||||
|  |                 namespace = "u"; | ||||||
|  |             } else { | ||||||
|  |                 name = completeName; | ||||||
|  |             } | ||||||
|  |             JsonElement jsonOrder = entry.getValue().getAsJsonObject().get("order"); | ||||||
|  |             Double order = null; | ||||||
|  |             if (jsonOrder != null) { | ||||||
|  |                 order = jsonOrder.getAsDouble(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return new Tag(namespace, name, order); | ||||||
|  |         }).collect(Collectors.toList()); | ||||||
|  |  | ||||||
|  |         return tags; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void addUserTag(String tag) { | ||||||
|  |         addTag("u." + tag, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void addUserTag(String tag, double order) { | ||||||
|  |         addTag("u." + tag, order); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void deleteUserTag(String tag) { | ||||||
|  |         deleteTag("u." + tag); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void addFavouriteTag() { | ||||||
|  |         addTag("m.favourite", null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void addFavouriteTag(double order) { | ||||||
|  |         addTag("m.favourite", order); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<Tag> getFavouriteTag() { | ||||||
|  |         return getAllTags().stream() | ||||||
|  |                 .filter(tag -> "m".equals(tag.getNamespace()) && "favourite".equals(tag.getName())).findFirst(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void deleteFavouriteTag() { | ||||||
|  |         deleteTag("m.favourite"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void addLowpriorityTag() { | ||||||
|  |         addTag("m.lowpriority", null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void addLowpriorityTag(double order) { | ||||||
|  |         addTag("m.lowpriority", order); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<Tag> getLowpriorityTag() { | ||||||
|  |         return getAllTags().stream() | ||||||
|  |                 .filter(tag -> "m".equals(tag.getNamespace()) && "lowpriority".equals(tag.getName())).findFirst(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void deleteLowpriorityTag() { | ||||||
|  |         deleteTag("m.lowpriority"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void addTag(String tag, Double order) { | ||||||
|  |         // TODO check name size | ||||||
|  |  | ||||||
|  |         if (order != null && (order < 0 || order > 1)) { | ||||||
|  |             throw new IllegalArgumentException("Order out of range!"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         URL path = getClientPath("user", getUserId(), "rooms", getAddress(), "tags", tag); | ||||||
|  |         Request.Builder request = new Request.Builder().url(path); | ||||||
|  |         if (order != null) { | ||||||
|  |             request.put(getJsonBody(new RoomTagSetBody(order))); | ||||||
|  |         } else { | ||||||
|  |             request.put(getJsonBody(new JsonObject())); | ||||||
|  |         } | ||||||
|  |         executeAuthenticated(request); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void deleteTag(String tag) { | ||||||
|  |         URL path = getClientPath("user", getUserId(), "rooms", getAddress(), "tags", tag); | ||||||
|  |         executeAuthenticated(new Request.Builder().url(path).delete()); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										125
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpUser.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/main/java/io/kamax/matrix/client/MatrixHttpUser.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix._MatrixContent; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixUser; | ||||||
|  | import io.kamax.matrix.client.regular.Presence; | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  |  | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URISyntaxException; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.Request; | ||||||
|  |  | ||||||
|  | public class MatrixHttpUser extends AMatrixHttpClient implements _MatrixUser { | ||||||
|  |  | ||||||
|  |     private Logger log = LoggerFactory.getLogger(MatrixHttpUser.class); | ||||||
|  |  | ||||||
|  |     private _MatrixID mxId; | ||||||
|  |  | ||||||
|  |     public MatrixHttpUser(MatrixClientContext context, _MatrixID mxId) { | ||||||
|  |         super(context); | ||||||
|  |  | ||||||
|  |         this.mxId = mxId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixID getId() { | ||||||
|  |         return mxId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getName() { | ||||||
|  |         URL path = getClientPath("profile", mxId.getId(), "displayname"); | ||||||
|  |  | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().get().url(path)); | ||||||
|  |         request.addIgnoredErrorCode(404); | ||||||
|  |         String body = executeAuthenticated(request); | ||||||
|  |         return extractAsStringFromBody(body, "displayname"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setName(String name) { | ||||||
|  |         URL path = getClientPath("profile", mxId.getId(), "displayname"); | ||||||
|  |         JsonObject body = GsonUtil.makeObj("displayname", name); | ||||||
|  |         executeAuthenticated(new Request.Builder().put(getJsonBody(body)).url(path)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getAvatarUrl() { | ||||||
|  |         URL path = getClientPath("profile", mxId.getId(), "avatar_url"); | ||||||
|  |  | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().get().url(path)); | ||||||
|  |         request.addIgnoredErrorCode(404); | ||||||
|  |         String body = executeAuthenticated(request); | ||||||
|  |         return extractAsStringFromBody(body, "avatar_url"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setAvatar(String avatarRef) { | ||||||
|  |         URL path = getClientPath("profile", mxId.getId(), "avatar_url"); | ||||||
|  |         JsonObject body = GsonUtil.makeObj("avatar_url", avatarRef); | ||||||
|  |         executeAuthenticated(new Request.Builder().put(getJsonBody(body)).url(path)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setAvatar(URI avatarUri) { | ||||||
|  |         setAvatar(avatarUri.toString()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<_MatrixContent> getAvatar() { | ||||||
|  |         return getAvatarUrl().flatMap(uri -> { | ||||||
|  |             try { | ||||||
|  |                 return Optional.of(new MatrixHttpContent(getContext(), new URI(uri))); | ||||||
|  |             } catch (URISyntaxException e) { | ||||||
|  |                 log.debug("{} is not a valid URI for avatar, returning empty", uri); | ||||||
|  |                 return Optional.empty(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<_Presence> getPresence() { | ||||||
|  |         URL path = getClientPath("presence", mxId.getId(), "status"); | ||||||
|  |  | ||||||
|  |         MatrixHttpRequest request = new MatrixHttpRequest(new Request.Builder().get().url(path)); | ||||||
|  |         request.addIgnoredErrorCode(404); | ||||||
|  |         String body = execute(request); | ||||||
|  |         if (StringUtils.isBlank(body)) { | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return Optional.of(new Presence(GsonUtil.parseObj(body))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,39 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | public class MatrixPasswordCredentials { | ||||||
|  |     private final String localPart; | ||||||
|  |     private final String password; | ||||||
|  |  | ||||||
|  |     public MatrixPasswordCredentials(String localPart, String password) { | ||||||
|  |         this.localPart = localPart; | ||||||
|  |         this.password = password; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getLocalPart() { | ||||||
|  |         return localPart; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getPassword() { | ||||||
|  |         return password; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								src/main/java/io/kamax/matrix/client/PresenceStatus.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/main/java/io/kamax/matrix/client/PresenceStatus.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sàrl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  |  | ||||||
|  | public enum PresenceStatus { | ||||||
|  |  | ||||||
|  |     Online("online"), | ||||||
|  |     Offline("offline"), | ||||||
|  |     Unavailable("unavailable"); | ||||||
|  |  | ||||||
|  |     private String id; | ||||||
|  |  | ||||||
|  |     PresenceStatus(String id) { | ||||||
|  |         this.id = id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public boolean is(String status) { | ||||||
|  |         return StringUtils.equals(id, status); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,138 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonArray; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  | import com.google.gson.JsonParseException; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  | import io.kamax.matrix.json.InvalidJsonException; | ||||||
|  |  | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.net.MalformedURLException; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public class WellKnownAutoDiscoverySettings implements _AutoDiscoverySettings { | ||||||
|  |  | ||||||
|  |     private final Logger log = LoggerFactory.getLogger(WellKnownAutoDiscoverySettings.class); | ||||||
|  |  | ||||||
|  |     private JsonObject raw; | ||||||
|  |  | ||||||
|  |     private List<URL> hsBaseUrls = new ArrayList<>(); | ||||||
|  |     private List<URL> isBaseUrls = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Build .well-known auto-discovery settings from a .well-known source. | ||||||
|  |      * | ||||||
|  |      * @param raw | ||||||
|  |      *            The raw JSON data | ||||||
|  |      * @throws IllegalArgumentException | ||||||
|  |      *             if the data is invalid and couldn't be parsed. | ||||||
|  |      */ | ||||||
|  |     public WellKnownAutoDiscoverySettings(String raw) { | ||||||
|  |         try { | ||||||
|  |             setRaw(GsonUtil.parseObj(raw)); | ||||||
|  |         } catch (JsonParseException | InvalidJsonException e) { | ||||||
|  |             throw new IllegalArgumentException("Invalid JSON data for .well-known string"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void setRaw(JsonObject raw) { | ||||||
|  |         this.raw = raw; | ||||||
|  |         process(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Optional<URL> getUrl(String url) { | ||||||
|  |         try { | ||||||
|  |             return Optional.of(new URL(url)); | ||||||
|  |         } catch (MalformedURLException e) { | ||||||
|  |             log.warn("Ignoring invalid Base URL entry in well-known: {} - {}", url, e.getMessage()); | ||||||
|  |             return Optional.empty(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private List<URL> getUrls(JsonArray array) { | ||||||
|  |         List<URL> urls = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         array.forEach(el -> { | ||||||
|  |             if (!el.isJsonPrimitive()) { | ||||||
|  |                 log.warn("Ignoring invalid Base URL entry in well-known: {} - Not a string", GsonUtil.get().toJson(el)); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             getUrl(el.getAsString()).ifPresent(urls::add); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         return urls; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private List<URL> processUrls(JsonObject base, String key) { | ||||||
|  |         List<URL> urls = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         GsonUtil.findObj(base, key).ifPresent(cfg -> { | ||||||
|  |             log.info("Found data"); | ||||||
|  |  | ||||||
|  |             GsonUtil.findArray(cfg, "base_urls").ifPresent(arr -> { | ||||||
|  |                 log.info("Found base URL(s)"); | ||||||
|  |                 urls.addAll(getUrls(arr)); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             if (urls.isEmpty()) { | ||||||
|  |                 GsonUtil.findString(cfg, "base_url").flatMap(this::getUrl).ifPresent(urls::add); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         return urls; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void process() { | ||||||
|  |         log.info("Processing Homeserver Base URLs"); | ||||||
|  |         hsBaseUrls = processUrls(raw, "m.homeserver"); | ||||||
|  |         log.info("Found {} valid URL(s)", hsBaseUrls.size()); | ||||||
|  |  | ||||||
|  |         log.info("Processing Identity server Base URLs"); | ||||||
|  |         isBaseUrls = processUrls(raw, "m.identity_server"); | ||||||
|  |         log.info("Found {} valid URL(s)", isBaseUrls.size()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public JsonObject getRaw() { | ||||||
|  |         return raw; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<URL> getHsBaseUrls() { | ||||||
|  |         return Collections.unmodifiableList(hsBaseUrls); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<URL> getIsBaseUrls() { | ||||||
|  |         return Collections.unmodifiableList(isBaseUrls); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public interface _AutoDiscoverySettings { | ||||||
|  |  | ||||||
|  |     JsonObject getRaw(); | ||||||
|  |  | ||||||
|  |     List<URL> getHsBaseUrls(); | ||||||
|  |  | ||||||
|  |     List<URL> getIsBaseUrls(); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,39 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public interface _GlobalPushRulesSet { | ||||||
|  |  | ||||||
|  |     List<JsonObject> getContent(); | ||||||
|  |  | ||||||
|  |     List<JsonObject> getOverride(); | ||||||
|  |  | ||||||
|  |     List<JsonObject> getRoom(); | ||||||
|  |  | ||||||
|  |     List<JsonObject> getSender(); | ||||||
|  |  | ||||||
|  |     List<JsonObject> getUnderride(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										158
									
								
								src/main/java/io/kamax/matrix/client/_MatrixClient.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/main/java/io/kamax/matrix/client/_MatrixClient.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix._MatrixContent; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixUser; | ||||||
|  | import io.kamax.matrix.hs._MatrixRoom; | ||||||
|  | import io.kamax.matrix.room.RoomAlias; | ||||||
|  | import io.kamax.matrix.room._RoomAliasLookup; | ||||||
|  | import io.kamax.matrix.room._RoomCreationOptions; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.net.URI; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public interface _MatrixClient extends _MatrixClientRaw { | ||||||
|  |  | ||||||
|  |     _MatrixID getWhoAmI(); | ||||||
|  |  | ||||||
|  |     void setDisplayName(String name); | ||||||
|  |  | ||||||
|  |     _RoomAliasLookup lookup(RoomAlias alias); | ||||||
|  |  | ||||||
|  |     _MatrixRoom createRoom(_RoomCreationOptions options); | ||||||
|  |  | ||||||
|  |     _MatrixRoom getRoom(String roomId); | ||||||
|  |  | ||||||
|  |     List<_MatrixRoom> getJoinedRooms(); | ||||||
|  |  | ||||||
|  |     _MatrixRoom joinRoom(String roomIdOrAlias); | ||||||
|  |  | ||||||
|  |     _MatrixUser getUser(_MatrixID mxId); | ||||||
|  |  | ||||||
|  |     Optional<String> getDeviceId(); | ||||||
|  |  | ||||||
|  |     /* Custom endpoint! */ | ||||||
|  |     // TODO refactor into custom synapse class? | ||||||
|  |     void register(MatrixPasswordCredentials credentials, String sharedSecret, boolean admin); | ||||||
|  |  | ||||||
|  |     /*** | ||||||
|  |      * Set the access token to use for any authenticated API calls. | ||||||
|  |      * | ||||||
|  |      * @param accessToken | ||||||
|  |      *            The access token provided by the server which must be valid | ||||||
|  |      * @throws MatrixClientRequestException | ||||||
|  |      *             If an error occurred while checking for the identity behind the access token | ||||||
|  |      */ | ||||||
|  |     void setAccessToken(String accessToken) throws MatrixClientRequestException; | ||||||
|  |  | ||||||
|  |     void login(MatrixPasswordCredentials credentials); | ||||||
|  |  | ||||||
|  |     void logout(); | ||||||
|  |  | ||||||
|  |     _SyncData sync(_SyncOptions options); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Download content from the media repository | ||||||
|  |      * | ||||||
|  |      * @param mxUri | ||||||
|  |      *            The MXC URI for the content to download | ||||||
|  |      * @return The content | ||||||
|  |      * @throws IllegalArgumentException | ||||||
|  |      *             if the parameter is not a valid MXC URI | ||||||
|  |      */ | ||||||
|  |     _MatrixContent getMedia(String mxUri) throws IllegalArgumentException; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Download content from the media repository | ||||||
|  |      * | ||||||
|  |      * @param mxUri | ||||||
|  |      *            The MXC URI for the content to download | ||||||
|  |      * @return The content | ||||||
|  |      * @throws IllegalArgumentException | ||||||
|  |      *             if the parameter is not a valid MXC URI | ||||||
|  |      */ | ||||||
|  |     _MatrixContent getMedia(URI mxUri) throws IllegalArgumentException; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Upload content to the media repository | ||||||
|  |      * | ||||||
|  |      * @param data | ||||||
|  |      *            The data to send | ||||||
|  |      * @param type | ||||||
|  |      *            The mime-type of the content upload | ||||||
|  |      * @return The MXC URI for the uploaded content | ||||||
|  |      */ | ||||||
|  |     String putMedia(byte[] data, String type); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Upload content to the media repository | ||||||
|  |      * | ||||||
|  |      * @param data | ||||||
|  |      *            The data to send | ||||||
|  |      * @param type | ||||||
|  |      *            The mime-type of the content upload | ||||||
|  |      * @param filename | ||||||
|  |      *            A suggested filename for the content | ||||||
|  |      * @return The MXC URI for the uploaded content | ||||||
|  |      */ | ||||||
|  |     String putMedia(byte[] data, String type, String filename); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Upload content to the media repository | ||||||
|  |      * | ||||||
|  |      * @param data | ||||||
|  |      *            The file to read the data from | ||||||
|  |      * @param type | ||||||
|  |      *            The mime-type of the content upload | ||||||
|  |      * @return The MXC URI for the uploaded content | ||||||
|  |      */ | ||||||
|  |     String putMedia(File data, String type); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Upload content to the media repository | ||||||
|  |      * | ||||||
|  |      * @param data | ||||||
|  |      *            The data to send | ||||||
|  |      * @param type | ||||||
|  |      *            The mime-type of the content upload | ||||||
|  |      * @param filename | ||||||
|  |      *            A suggested filename for the content | ||||||
|  |      * @return The MXC URI for the uploaded content | ||||||
|  |      */ | ||||||
|  |     String putMedia(File data, String type, String filename); | ||||||
|  |  | ||||||
|  |     List<JsonObject> getPushers(); | ||||||
|  |  | ||||||
|  |     void setPusher(JsonObject pusher); | ||||||
|  |  | ||||||
|  |     void deletePusher(String pushKey); | ||||||
|  |  | ||||||
|  |     _GlobalPushRulesSet getPushRules(); | ||||||
|  |  | ||||||
|  |     _PushRule getPushRule(String scope, String kind, String id); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								src/main/java/io/kamax/matrix/client/_MatrixClientRaw.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/main/java/io/kamax/matrix/client/_MatrixClientRaw.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix.hs._MatrixHomeserver; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public interface _MatrixClientRaw { | ||||||
|  |  | ||||||
|  |     MatrixClientContext getContext(); | ||||||
|  |  | ||||||
|  |     _MatrixHomeserver getHomeserver(); | ||||||
|  |  | ||||||
|  |     Optional<String> getAccessToken(); | ||||||
|  |  | ||||||
|  |     Optional<_MatrixID> getUser(); | ||||||
|  |  | ||||||
|  |     Optional<_AutoDiscoverySettings> discoverSettings(); | ||||||
|  |  | ||||||
|  |     // FIXME | ||||||
|  |     // we should maybe have a dedicated object for HS related items and be merged into getHomeserver() which is only | ||||||
|  |     // holding state at this point and is not functional | ||||||
|  |     List<String> getHomeApiVersions(); | ||||||
|  |  | ||||||
|  |     // FIXME | ||||||
|  |     // we should maybe have a dedicated object for IS related items. Will reconsider when implementing | ||||||
|  |     // other part of the IS API | ||||||
|  |     boolean validateIsBaseUrl(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/main/java/io/kamax/matrix/client/_Presence.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/main/java/io/kamax/matrix/client/_Presence.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sàrl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | public interface _Presence { | ||||||
|  |  | ||||||
|  |     String getStatus(); | ||||||
|  |  | ||||||
|  |     Long getLastActive(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								src/main/java/io/kamax/matrix/client/_PushRule.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/main/java/io/kamax/matrix/client/_PushRule.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public interface _PushRule { | ||||||
|  |  | ||||||
|  |     JsonObject getJson(); | ||||||
|  |  | ||||||
|  |     void set(JsonObject data); | ||||||
|  |  | ||||||
|  |     void delete(); | ||||||
|  |  | ||||||
|  |     boolean isEnabled(); | ||||||
|  |  | ||||||
|  |     void setEnabled(boolean enabled); | ||||||
|  |  | ||||||
|  |     List<String> getActions(); | ||||||
|  |  | ||||||
|  |     void setActions(List<String> data); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										253
									
								
								src/main/java/io/kamax/matrix/client/_SyncData.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								src/main/java/io/kamax/matrix/client/_SyncData.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,253 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.event._MatrixAccountDataEvent; | ||||||
|  | import io.kamax.matrix.event._MatrixEphemeralEvent; | ||||||
|  | import io.kamax.matrix.event._MatrixPersistentEvent; | ||||||
|  | import io.kamax.matrix.event._MatrixStateEvent; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Representation of the data when performing a sync call on the Matrix Client API. | ||||||
|  |  */ | ||||||
|  | public interface _SyncData { | ||||||
|  |  | ||||||
|  |     interface State { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The state of the room. | ||||||
|  |          *  | ||||||
|  |          * @return a list of state events. | ||||||
|  |          */ | ||||||
|  |         List<_MatrixStateEvent> getEvents(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface Timeline { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Events that happened in the sync window. | ||||||
|  |          *  | ||||||
|  |          * @return List of events. | ||||||
|  |          */ | ||||||
|  |         List<_MatrixPersistentEvent> getEvents(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * If the number of events returned was limited by the sync filter. | ||||||
|  |          *  | ||||||
|  |          * @return true if the number of events was limited, false if not. | ||||||
|  |          */ | ||||||
|  |         boolean isLimited(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Token that can be supplied to fetch previous events for the associated room. | ||||||
|  |          *  | ||||||
|  |          * @return the token. | ||||||
|  |          */ | ||||||
|  |         String getPreviousBatchToken(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface Ephemeral { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Events that happened in the sync window. | ||||||
|  |          * | ||||||
|  |          * @return List of events. | ||||||
|  |          */ | ||||||
|  |         List<_MatrixEphemeralEvent> getEvents(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface AccountData { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Events that happened in the sync window. | ||||||
|  |          * | ||||||
|  |          * @return List of events. | ||||||
|  |          */ | ||||||
|  |         List<_MatrixAccountDataEvent> getEvents(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface InvitedRoom { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The ID of the room the user was invited to. | ||||||
|  |          *  | ||||||
|  |          * @return the room ID. | ||||||
|  |          */ | ||||||
|  |         String getId(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The state of the room at the invite event. | ||||||
|  |          *  | ||||||
|  |          * @return a list of state events. | ||||||
|  |          */ | ||||||
|  |         State getState(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface UnreadNotifications { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The number of unread notifications with the highlight flag set. | ||||||
|  |          *  | ||||||
|  |          * @return the count. | ||||||
|  |          */ | ||||||
|  |         long getHighlightCount(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The total number of unread notifications. | ||||||
|  |          *  | ||||||
|  |          * @return the count. | ||||||
|  |          */ | ||||||
|  |         long getNotificationCount(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface JoinedRoom { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The ID of the room the user is joined to. | ||||||
|  |          *  | ||||||
|  |          * @return the room id. | ||||||
|  |          */ | ||||||
|  |         String getId(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * State changes prior the start of the timeline. | ||||||
|  |          *  | ||||||
|  |          * @return a list of state events. | ||||||
|  |          */ | ||||||
|  |         State getState(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The room timeline for this sync batch. | ||||||
|  |          *  | ||||||
|  |          * @return the timeline. | ||||||
|  |          */ | ||||||
|  |         Timeline getTimeline(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Ephemeral events of the room. | ||||||
|  |          * | ||||||
|  |          * @return a list of ephemeral events. | ||||||
|  |          */ | ||||||
|  |         Ephemeral getEphemeral(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Account events of the room. | ||||||
|  |          * | ||||||
|  |          * @return a list of account data events. | ||||||
|  |          */ | ||||||
|  |         AccountData getAccountData(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The Counts of unread notifications. | ||||||
|  |          *  | ||||||
|  |          * @return unread notifications. | ||||||
|  |          */ | ||||||
|  |         UnreadNotifications getUnreadNotifications(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface LeftRoom { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The ID of the room the user is joined to. | ||||||
|  |          *  | ||||||
|  |          * @return the room id. | ||||||
|  |          */ | ||||||
|  |         String getId(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * State changes prior the start of the timeline. | ||||||
|  |          *  | ||||||
|  |          * @return a list of state events. | ||||||
|  |          */ | ||||||
|  |         State getState(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The room timeline up to the leave event. | ||||||
|  |          *  | ||||||
|  |          * @return the timeline. | ||||||
|  |          */ | ||||||
|  |         Timeline getTimeline(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     interface Rooms { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Rooms the user was invited to within this sync window. | ||||||
|  |          *  | ||||||
|  |          * @return Set of InvitedRoom objects. | ||||||
|  |          */ | ||||||
|  |         Set<InvitedRoom> getInvited(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Rooms the user was joined in within this sync window. | ||||||
|  |          *  | ||||||
|  |          * @return Set of JoinedRoom objects. | ||||||
|  |          */ | ||||||
|  |         Set<JoinedRoom> getJoined(); | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Rooms the user left from within this sync window. | ||||||
|  |          *  | ||||||
|  |          * @return Set of LeftRoom objects. | ||||||
|  |          */ | ||||||
|  |         Set<LeftRoom> getLeft(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The batch token to supply in the next sync call. | ||||||
|  |      *  | ||||||
|  |      * @return the batch token. | ||||||
|  |      */ | ||||||
|  |     String nextBatchToken(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The global private data created by this user. | ||||||
|  |      * | ||||||
|  |      * @return the account data. | ||||||
|  |      */ | ||||||
|  |     AccountData getAccountData(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update to the rooms. | ||||||
|  |      *  | ||||||
|  |      * @return rooms object. | ||||||
|  |      */ | ||||||
|  |     Rooms getRooms(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The raw JSON data for this object. | ||||||
|  |      *  | ||||||
|  |      * @return the JSON data. | ||||||
|  |      */ | ||||||
|  |     JsonObject getJson(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								src/main/java/io/kamax/matrix/client/_SyncOptions.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/main/java/io/kamax/matrix/client/_SyncOptions.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client; | ||||||
|  |  | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Possible options that can be passed to the sync call. | ||||||
|  |  */ | ||||||
|  | public interface _SyncOptions { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The point of time to continue the sync from. | ||||||
|  |      * | ||||||
|  |      * @return A token that was provided in a previous sync call, if set. | ||||||
|  |      */ | ||||||
|  |     Optional<String> getSince(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The filter to use for the sync. | ||||||
|  |      * | ||||||
|  |      * @return The ID or raw JSON filter, if set. | ||||||
|  |      */ | ||||||
|  |     Optional<String> getFilter(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * If the full state should be included in the sync. | ||||||
|  |      * | ||||||
|  |      * @return The full state option, if set. | ||||||
|  |      */ | ||||||
|  |     Optional<Boolean> withFullState(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * If the client should automatically be marked as online. | ||||||
|  |      * | ||||||
|  |      * @return The set presence option, if set. | ||||||
|  |      */ | ||||||
|  |     Optional<String> getSetPresence(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The maximum time to wait, in milliseconds, before ending the sync call. | ||||||
|  |      * | ||||||
|  |      * @return The timeout option, if set. | ||||||
|  |      */ | ||||||
|  |     Optional<Long> getTimeout(); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,87 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.as; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.client.MatrixClientContext; | ||||||
|  | import io.kamax.matrix.client.MatrixClientDefaults; | ||||||
|  | import io.kamax.matrix.client._MatrixClient; | ||||||
|  | import io.kamax.matrix.client.regular.MatrixHttpClient; | ||||||
|  | import io.kamax.matrix.json.VirtualUserRegistrationBody; | ||||||
|  |  | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.net.URL; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.OkHttpClient; | ||||||
|  | import okhttp3.Request; | ||||||
|  |  | ||||||
|  | public class MatrixApplicationServiceClient extends MatrixHttpClient implements _MatrixApplicationServiceClient { | ||||||
|  |  | ||||||
|  |     private Logger log = LoggerFactory.getLogger(MatrixApplicationServiceClient.class); | ||||||
|  |  | ||||||
|  |     public MatrixApplicationServiceClient(String domain) { | ||||||
|  |         super(domain); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixApplicationServiceClient(URL hsBaseUrl) { | ||||||
|  |         super(hsBaseUrl); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixApplicationServiceClient(MatrixClientContext context) { | ||||||
|  |         super(context); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixApplicationServiceClient(MatrixClientContext context, OkHttpClient.Builder client) { | ||||||
|  |         super(context, client); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixApplicationServiceClient(MatrixClientContext context, OkHttpClient.Builder client, | ||||||
|  |             MatrixClientDefaults defaults) { | ||||||
|  |         super(context, client, defaults); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixApplicationServiceClient(MatrixClientContext context, OkHttpClient client) { | ||||||
|  |         super(context, client); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private MatrixHttpClient createClient(String localpart) { | ||||||
|  |         MatrixClientContext context = new MatrixClientContext(getContext()).setUserWithLocalpart(localpart) | ||||||
|  |                 .setVirtual(true); | ||||||
|  |         return new MatrixHttpClient(context); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixClient createUser(String localpart) { | ||||||
|  |         log.debug("Creating new user {}", localpart); | ||||||
|  |         URL path = getClientPath("register"); | ||||||
|  |         executeAuthenticated( | ||||||
|  |                 new Request.Builder().post(getJsonBody(new VirtualUserRegistrationBody(localpart))).url(path)); | ||||||
|  |         return createClient(localpart); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixClient getUser(String localpart) { | ||||||
|  |         return createClient(localpart); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.as; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.client._MatrixClient; | ||||||
|  |  | ||||||
|  | public interface _MatrixApplicationServiceClient extends _MatrixClient { | ||||||
|  |  | ||||||
|  |     _MatrixClient createUser(String localpart); | ||||||
|  |  | ||||||
|  |     _MatrixClient getUser(String localpart); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,68 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.regular; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonArray; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.client._GlobalPushRulesSet; | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | public class GlobalPushRulesSet implements _GlobalPushRulesSet { | ||||||
|  |  | ||||||
|  |     private JsonObject data; | ||||||
|  |  | ||||||
|  |     public GlobalPushRulesSet(JsonObject data) { | ||||||
|  |         this.data = data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private List<JsonObject> getForKey(String key) { | ||||||
|  |         return GsonUtil.asList(GsonUtil.findArray(data, key).orElseGet(JsonArray::new), JsonObject.class); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<JsonObject> getContent() { | ||||||
|  |         return getForKey("content"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<JsonObject> getOverride() { | ||||||
|  |         return getForKey("override"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<JsonObject> getRoom() { | ||||||
|  |         return getForKey("room"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<JsonObject> getSender() { | ||||||
|  |         return getForKey("sender"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<JsonObject> getUnderride() { | ||||||
|  |         return getForKey("underride"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,292 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.regular; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonNull; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixContent; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixUser; | ||||||
|  | import io.kamax.matrix.client.*; | ||||||
|  | import io.kamax.matrix.hs._MatrixRoom; | ||||||
|  | import io.kamax.matrix.json.*; | ||||||
|  | import io.kamax.matrix.room.RoomAlias; | ||||||
|  | import io.kamax.matrix.room.RoomAliasLookup; | ||||||
|  | import io.kamax.matrix.room._RoomAliasLookup; | ||||||
|  | import io.kamax.matrix.room._RoomCreationOptions; | ||||||
|  |  | ||||||
|  | import org.apache.commons.codec.digest.HmacAlgorithms; | ||||||
|  | import org.apache.commons.codec.digest.HmacUtils; | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import okhttp3.*; | ||||||
|  |  | ||||||
|  | public class MatrixHttpClient extends AMatrixHttpClient implements _MatrixClient { | ||||||
|  |  | ||||||
|  |     private Logger log = LoggerFactory.getLogger(MatrixHttpClient.class); | ||||||
|  |  | ||||||
|  |     public MatrixHttpClient(String domain) { | ||||||
|  |         super(domain); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixHttpClient(URL hsBaseUrl) { | ||||||
|  |         super(hsBaseUrl); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixHttpClient(MatrixClientContext context) { | ||||||
|  |         super(context); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixHttpClient(MatrixClientContext context, OkHttpClient.Builder client) { | ||||||
|  |         super(context, client); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixHttpClient(MatrixClientContext context, OkHttpClient.Builder client, MatrixClientDefaults defaults) { | ||||||
|  |         super(context, client, defaults); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public MatrixHttpClient(MatrixClientContext context, OkHttpClient client) { | ||||||
|  |         super(context, client); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected _MatrixID getIdentity(String token) { | ||||||
|  |         URL path = getClientPath("account", "whoami"); | ||||||
|  |         String body = executeAuthenticated(new Request.Builder().get().url(path), token); | ||||||
|  |         return MatrixID.from(GsonUtil.getStringOrThrow(GsonUtil.parseObj(body), "user_id")).acceptable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixID getWhoAmI() { | ||||||
|  |         URL path = getClientPath("account", "whoami"); | ||||||
|  |         String body = executeAuthenticated(new Request.Builder().get().url(path)); | ||||||
|  |         return MatrixID.from(GsonUtil.getStringOrThrow(GsonUtil.parseObj(body), "user_id")).acceptable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setDisplayName(String name) { | ||||||
|  |         URL path = getClientPath("profile", getUserId(), "displayname"); | ||||||
|  |         execute(new Request.Builder().put(getJsonBody(new UserDisplaynameSetBody(name))).url(path)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _RoomAliasLookup lookup(RoomAlias alias) { | ||||||
|  |         URL path = getClientPath("directory", "room", alias.getId()); | ||||||
|  |         String resBody = execute(new Request.Builder().get().url(path)); | ||||||
|  |         RoomAliasLookupJson lookup = GsonUtil.get().fromJson(resBody, RoomAliasLookupJson.class); | ||||||
|  |         return new RoomAliasLookup(lookup.getRoomId(), alias.getId(), lookup.getServers()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixRoom createRoom(_RoomCreationOptions options) { | ||||||
|  |         URL path = getClientPath("createRoom"); | ||||||
|  |         String resBody = executeAuthenticated( | ||||||
|  |                 new Request.Builder().post(getJsonBody(new RoomCreationRequestJson(options))).url(path)); | ||||||
|  |         String roomId = GsonUtil.get().fromJson(resBody, RoomCreationResponseJson.class).getRoomId(); | ||||||
|  |         return getRoom(roomId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixRoom getRoom(String roomId) { | ||||||
|  |         return new MatrixHttpRoom(getContext(), roomId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<_MatrixRoom> getJoinedRooms() { | ||||||
|  |         URL path = getClientPath("joined_rooms"); | ||||||
|  |         JsonObject resBody = GsonUtil.parseObj(executeAuthenticated(new Request.Builder().get().url(path))); | ||||||
|  |         return GsonUtil.asList(resBody, "joined_rooms", String.class).stream().map(this::getRoom) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixRoom joinRoom(String roomIdOrAlias) { | ||||||
|  |         URL path = getClientPath("join", roomIdOrAlias); | ||||||
|  |         String resBody = executeAuthenticated(new Request.Builder().post(getJsonBody(new JsonObject())).url(path)); | ||||||
|  |         String roomId = GsonUtil.get().fromJson(resBody, RoomCreationResponseJson.class).getRoomId(); | ||||||
|  |         return getRoom(roomId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixUser getUser(_MatrixID mxId) { | ||||||
|  |         return new MatrixHttpUser(getContext(), mxId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getDeviceId() { | ||||||
|  |         return Optional.ofNullable(context.getDeviceId()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected void updateContext(String resBody) { | ||||||
|  |         LoginResponse response = gson.fromJson(resBody, LoginResponse.class); | ||||||
|  |         context.setToken(response.getAccessToken()); | ||||||
|  |         context.setDeviceId(response.getDeviceId()); | ||||||
|  |         context.setUser(MatrixID.asAcceptable(response.getUserId())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void register(MatrixPasswordCredentials credentials, String sharedSecret, boolean admin) { | ||||||
|  |         // As per synapse registration script: | ||||||
|  |         // https://github.com/matrix-org/synapse/blob/master/scripts/register_new_matrix_user#L28 | ||||||
|  |  | ||||||
|  |         String value = credentials.getLocalPart() + "\0" + credentials.getPassword() + "\0" | ||||||
|  |                 + (admin ? "admin" : "notadmin"); | ||||||
|  |         String mac = new HmacUtils(HmacAlgorithms.HMAC_SHA_1, sharedSecret).hmacHex(value); | ||||||
|  |         JsonObject body = new JsonObject(); | ||||||
|  |         body.addProperty("user", credentials.getLocalPart()); | ||||||
|  |         body.addProperty("password", credentials.getPassword()); | ||||||
|  |         body.addProperty("mac", mac); | ||||||
|  |         body.addProperty("type", "org.matrix.login.shared_secret"); | ||||||
|  |         body.addProperty("admin", false); | ||||||
|  |         URL url = getPath("client", "api", "v1", "register"); | ||||||
|  |         updateContext(execute(new Request.Builder().post(getJsonBody(body)).url(url))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setAccessToken(String accessToken) { | ||||||
|  |         context.setUser(getIdentity(accessToken)); | ||||||
|  |         context.setToken(accessToken); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void login(MatrixPasswordCredentials credentials) { | ||||||
|  |         URL url = getClientPath("login"); | ||||||
|  |  | ||||||
|  |         LoginPostBody data = new LoginPostBody(credentials.getLocalPart(), credentials.getPassword()); | ||||||
|  |         getDeviceId().ifPresent(data::setDeviceId); | ||||||
|  |         Optional.ofNullable(context.getInitialDeviceName()).ifPresent(data::setInitialDeviceDisplayName); | ||||||
|  |  | ||||||
|  |         updateContext(execute(new Request.Builder().post(getJsonBody(data)).url(url))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void logout() { | ||||||
|  |         URL path = getClientPath("logout"); | ||||||
|  |         executeAuthenticated(new Request.Builder().post(getJsonBody(new JsonObject())).url(path)); | ||||||
|  |         context.setToken(null); | ||||||
|  |         context.setUser(null); | ||||||
|  |         context.setDeviceId(null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _SyncData sync(_SyncOptions options) { | ||||||
|  |         long start = System.currentTimeMillis(); | ||||||
|  |         HttpUrl.Builder path = getClientPathBuilder("sync"); | ||||||
|  |         path.addQueryParameter("timeout", options.getTimeout().map(Long::intValue).orElse(30000).toString()); | ||||||
|  |         options.getSince().ifPresent(since -> path.addQueryParameter("since", since)); | ||||||
|  |         options.getFilter().ifPresent(filter -> path.addQueryParameter("filter", filter)); | ||||||
|  |         options.withFullState().ifPresent(state -> path.addQueryParameter("full_state", state ? "true" : "false")); | ||||||
|  |         options.getSetPresence().ifPresent(presence -> path.addQueryParameter("presence", presence)); | ||||||
|  |  | ||||||
|  |         String body = executeAuthenticated(new Request.Builder().get().url(path.build().url())); | ||||||
|  |         long request = System.currentTimeMillis(); | ||||||
|  |         log.info("Sync: network request took {} ms", (request - start)); | ||||||
|  |         SyncDataJson data = new SyncDataJson(GsonUtil.parseObj(body)); | ||||||
|  |         long parsing = System.currentTimeMillis(); | ||||||
|  |         log.info("Sync: parsing took {} ms", (parsing - request)); | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixContent getMedia(String mxUri) throws IllegalArgumentException { | ||||||
|  |         return getMedia(URI.create(mxUri)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _MatrixContent getMedia(URI mxUri) throws IllegalArgumentException { | ||||||
|  |         return new MatrixHttpContent(context, mxUri); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private String putMedia(Request.Builder builder, String filename) { | ||||||
|  |         HttpUrl.Builder b = getMediaPathBuilder("upload"); | ||||||
|  |         if (StringUtils.isNotEmpty(filename)) b.addQueryParameter("filename", filename); | ||||||
|  |  | ||||||
|  |         String body = executeAuthenticated(builder.url(b.build())); | ||||||
|  |         return GsonUtil.getStringOrThrow(GsonUtil.parseObj(body), "content_uri"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String putMedia(byte[] data, String type) { | ||||||
|  |         return putMedia(data, type, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String putMedia(byte[] data, String type, String filename) { | ||||||
|  |         return putMedia(new Request.Builder().post(RequestBody.create(MediaType.parse(type), data)), filename); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String putMedia(File data, String type) { | ||||||
|  |         return putMedia(data, type, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String putMedia(File data, String type, String filename) { | ||||||
|  |         return putMedia(new Request.Builder().post(RequestBody.create(MediaType.parse(type), data)), filename); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<JsonObject> getPushers() { | ||||||
|  |         URL url = getClientPath("pushers"); | ||||||
|  |         JsonObject response = GsonUtil.parseObj(executeAuthenticated(new Request.Builder().get().url(url))); | ||||||
|  |         return GsonUtil.findArray(response, "pushers").map(array -> GsonUtil.asList(array, JsonObject.class)) | ||||||
|  |                 .orElse(Collections.emptyList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void setPusher(JsonObject pusher) { | ||||||
|  |         URL url = getClientPath("pushers", "set"); | ||||||
|  |         executeAuthenticated(new Request.Builder().url(url).post(getJsonBody(pusher))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void deletePusher(String pushKey) { | ||||||
|  |         JsonObject pusher = new JsonObject(); | ||||||
|  |         pusher.add("kind", JsonNull.INSTANCE); | ||||||
|  |         pusher.addProperty("pushkey", pushKey); | ||||||
|  |         setPusher(pusher); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _GlobalPushRulesSet getPushRules() { | ||||||
|  |         URL url = getClientPath("pushrules", "global", ""); | ||||||
|  |         JsonObject response = GsonUtil.parseObj(executeAuthenticated(new Request.Builder().url(url).get())); | ||||||
|  |         return new GlobalPushRulesSet(response); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public _PushRule getPushRule(String scope, String kind, String id) { | ||||||
|  |         return new MatrixHttpPushRule(context, scope, kind, id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								src/main/java/io/kamax/matrix/client/regular/Presence.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/main/java/io/kamax/matrix/client/regular/Presence.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sàrl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.regular; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.client._Presence; | ||||||
|  | import io.kamax.matrix.json.GsonUtil; | ||||||
|  |  | ||||||
|  | public class Presence implements _Presence { | ||||||
|  |  | ||||||
|  |     private String status; | ||||||
|  |     private Long lastActive; | ||||||
|  |  | ||||||
|  |     public Presence(JsonObject json) { | ||||||
|  |         this.status = GsonUtil.getStringOrThrow(json, "presence"); | ||||||
|  |         this.lastActive = GsonUtil.getLong(json, "last_active_ago"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getStatus() { | ||||||
|  |         return status; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Long getLastActive() { | ||||||
|  |         return lastActive; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										390
									
								
								src/main/java/io/kamax/matrix/client/regular/SyncDataJson.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								src/main/java/io/kamax/matrix/client/regular/SyncDataJson.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,390 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.regular; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonElement; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.MatrixID; | ||||||
|  | import io.kamax.matrix._MatrixID; | ||||||
|  | import io.kamax.matrix.client._SyncData; | ||||||
|  | import io.kamax.matrix.event.EventKey; | ||||||
|  | import io.kamax.matrix.event._MatrixAccountDataEvent; | ||||||
|  | import io.kamax.matrix.event._MatrixEphemeralEvent; | ||||||
|  | import io.kamax.matrix.event._MatrixPersistentEvent; | ||||||
|  | import io.kamax.matrix.event._MatrixStateEvent; | ||||||
|  | import io.kamax.matrix.json.MatrixJsonObject; | ||||||
|  |  | ||||||
|  | import java.util.*; | ||||||
|  |  | ||||||
|  | public class SyncDataJson extends MatrixJsonObject implements _SyncData { | ||||||
|  |  | ||||||
|  |     public class MatrixPersistentEventJson extends MatrixJsonObject implements _MatrixPersistentEvent { | ||||||
|  |  | ||||||
|  |         public MatrixPersistentEventJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getId() { | ||||||
|  |             return findString(EventKey.Id.get()).orElse(""); // FIXME refactor event structure | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getType() { | ||||||
|  |             return getString(EventKey.Type.get()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Long getTime() { | ||||||
|  |             return getLong(EventKey.Timestamp.get()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public _MatrixID getSender() { | ||||||
|  |             return MatrixID.from(getString(EventKey.Sender.get())).acceptable(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class MatrixEphemeralEventJson extends MatrixJsonObject implements _MatrixEphemeralEvent { | ||||||
|  |  | ||||||
|  |         public MatrixEphemeralEventJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getType() { | ||||||
|  |             return getString(EventKey.Type.get()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class MatrixAccountDataEventJson extends MatrixJsonObject implements _MatrixAccountDataEvent { | ||||||
|  |  | ||||||
|  |         public MatrixAccountDataEventJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getType() { | ||||||
|  |             return getString(EventKey.Type.get()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class MatrixStateEventJson extends MatrixPersistentEventJson implements _MatrixStateEvent { | ||||||
|  |  | ||||||
|  |         public MatrixStateEventJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getStateKey() { | ||||||
|  |             return getString(EventKey.StateKey.get()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class StateJson extends MatrixJsonObject implements _SyncData.State { | ||||||
|  |  | ||||||
|  |         private List<_MatrixStateEvent> events = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         public StateJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |  | ||||||
|  |             findArray("events").ifPresent(array -> { | ||||||
|  |                 for (JsonElement el : array) { | ||||||
|  |                     events.add(new MatrixStateEventJson(asObj(el))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public List<_MatrixStateEvent> getEvents() { | ||||||
|  |             return events; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class TimelineJson extends MatrixJsonObject implements _SyncData.Timeline { | ||||||
|  |  | ||||||
|  |         private List<_MatrixPersistentEvent> events = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         public TimelineJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |  | ||||||
|  |             findArray("events").ifPresent(array -> { | ||||||
|  |                 for (JsonElement el : array) { | ||||||
|  |                     events.add(new MatrixPersistentEventJson(asObj(el))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public List<_MatrixPersistentEvent> getEvents() { | ||||||
|  |             return events; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public boolean isLimited() { | ||||||
|  |             return findString("limited").map("true"::equals).orElse(false); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getPreviousBatchToken() { | ||||||
|  |             return getString("prev_batch"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class EphemeralJson extends MatrixJsonObject implements _SyncData.Ephemeral { | ||||||
|  |  | ||||||
|  |         private List<_MatrixEphemeralEvent> events = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         public EphemeralJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |  | ||||||
|  |             findArray("events").ifPresent(array -> { | ||||||
|  |                 for (JsonElement el : array) { | ||||||
|  |                     events.add(new MatrixEphemeralEventJson(asObj(el))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public List<_MatrixEphemeralEvent> getEvents() { | ||||||
|  |             return events; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class AccountDataJson extends MatrixJsonObject implements _SyncData.AccountData { | ||||||
|  |  | ||||||
|  |         private List<_MatrixAccountDataEvent> events = new ArrayList<>(); | ||||||
|  |  | ||||||
|  |         public AccountDataJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |  | ||||||
|  |             findArray("events").ifPresent(array -> { | ||||||
|  |                 for (JsonElement el : array) { | ||||||
|  |                     events.add(new MatrixAccountDataEventJson(asObj(el))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public List<_MatrixAccountDataEvent> getEvents() { | ||||||
|  |             return events; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class InvitedRoomJson extends MatrixJsonObject implements _SyncData.InvitedRoom { | ||||||
|  |  | ||||||
|  |         private String id; | ||||||
|  |         private State state; | ||||||
|  |  | ||||||
|  |         public InvitedRoomJson(String id, JsonObject data) { | ||||||
|  |             super(data); | ||||||
|  |             this.id = id; | ||||||
|  |             this.state = new StateJson(findObj("invite_state").orElseGet(JsonObject::new)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getId() { | ||||||
|  |             return id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public State getState() { | ||||||
|  |             return state; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class UnreadNotificationsJson extends MatrixJsonObject implements _SyncData.UnreadNotifications { | ||||||
|  |  | ||||||
|  |         private long highlights; | ||||||
|  |         private long global; | ||||||
|  |  | ||||||
|  |         public UnreadNotificationsJson(JsonObject data) { | ||||||
|  |             super(data); | ||||||
|  |             this.highlights = findLong("highlight_count").orElse(0L); | ||||||
|  |             this.global = findLong("notification_count").orElse(0L); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public long getHighlightCount() { | ||||||
|  |             return highlights; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public long getNotificationCount() { | ||||||
|  |             return global; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class JoinedRoomJson extends MatrixJsonObject implements _SyncData.JoinedRoom { | ||||||
|  |  | ||||||
|  |         private String id; | ||||||
|  |         private State state; | ||||||
|  |         private Timeline timeline; | ||||||
|  |         private UnreadNotifications unreadNotifications; | ||||||
|  |         private Ephemeral ephemeral; | ||||||
|  |         private AccountData accountData; | ||||||
|  |  | ||||||
|  |         public JoinedRoomJson(String id, JsonObject data) { | ||||||
|  |             super(data); | ||||||
|  |             this.id = id; | ||||||
|  |             this.state = new StateJson(findObj("state").orElseGet(JsonObject::new)); | ||||||
|  |             this.timeline = new TimelineJson(findObj("timeline").orElseGet(JsonObject::new)); | ||||||
|  |             this.unreadNotifications = new UnreadNotificationsJson(computeObj("unread_notifications")); | ||||||
|  |             this.ephemeral = new EphemeralJson(findObj("ephemeral").orElseGet(JsonObject::new)); | ||||||
|  |             this.accountData = new AccountDataJson(findObj("account_data").orElseGet(JsonObject::new)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getId() { | ||||||
|  |             return id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public State getState() { | ||||||
|  |             return state; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Timeline getTimeline() { | ||||||
|  |             return timeline; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Ephemeral getEphemeral() { | ||||||
|  |             return ephemeral; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public AccountData getAccountData() { | ||||||
|  |             return accountData; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public UnreadNotifications getUnreadNotifications() { | ||||||
|  |             return unreadNotifications; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class LeftRoomJson extends MatrixPersistentEventJson implements _SyncData.LeftRoom { | ||||||
|  |  | ||||||
|  |         private String id; | ||||||
|  |         private State state; | ||||||
|  |         private Timeline timeline; | ||||||
|  |  | ||||||
|  |         public LeftRoomJson(String id, JsonObject data) { | ||||||
|  |             super(data); | ||||||
|  |             this.id = id; | ||||||
|  |             this.state = new StateJson(findObj("state").orElseGet(JsonObject::new)); | ||||||
|  |             this.timeline = new TimelineJson(findObj("timeline").orElseGet(JsonObject::new)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public String getId() { | ||||||
|  |             return id; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public State getState() { | ||||||
|  |             return state; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Timeline getTimeline() { | ||||||
|  |             return timeline; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class RoomsJson extends MatrixJsonObject implements _SyncData.Rooms { | ||||||
|  |  | ||||||
|  |         private Set<InvitedRoom> invited = new HashSet<>(); | ||||||
|  |         private Set<JoinedRoom> joined = new HashSet<>(); | ||||||
|  |         private Set<LeftRoom> left = new HashSet<>(); | ||||||
|  |  | ||||||
|  |         public RoomsJson(JsonObject obj) { | ||||||
|  |             super(obj); | ||||||
|  |             findObj("invite").ifPresent(o -> { | ||||||
|  |                 for (Map.Entry<String, JsonElement> entry : o.entrySet()) { | ||||||
|  |                     invited.add(new InvitedRoomJson(entry.getKey(), asObj(entry.getValue()))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             findObj("join").ifPresent(o -> { | ||||||
|  |                 for (Map.Entry<String, JsonElement> entry : o.entrySet()) { | ||||||
|  |                     joined.add(new JoinedRoomJson(entry.getKey(), asObj(entry.getValue()))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             findObj("leave").ifPresent(o -> { | ||||||
|  |                 for (Map.Entry<String, JsonElement> entry : o.entrySet()) { | ||||||
|  |                     left.add(new LeftRoomJson(entry.getKey(), asObj(entry.getValue()))); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Set<InvitedRoom> getInvited() { | ||||||
|  |             return invited; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Set<JoinedRoom> getJoined() { | ||||||
|  |             return joined; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public Set<LeftRoom> getLeft() { | ||||||
|  |             return left; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private String nextBatch; | ||||||
|  |     private AccountDataJson accountData; | ||||||
|  |     private RoomsJson rooms; | ||||||
|  |  | ||||||
|  |     public SyncDataJson(JsonObject data) { | ||||||
|  |         super(data); | ||||||
|  |         nextBatch = getString("next_batch"); | ||||||
|  |         accountData = new AccountDataJson(findObj("account_data").orElseGet(JsonObject::new)); | ||||||
|  |         rooms = new RoomsJson(findObj("rooms").orElseGet(JsonObject::new)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String nextBatchToken() { | ||||||
|  |         return nextBatch; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public AccountData getAccountData() { | ||||||
|  |         return accountData; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Rooms getRooms() { | ||||||
|  |         return rooms; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								src/main/java/io/kamax/matrix/client/regular/SyncOptions.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/main/java/io/kamax/matrix/client/regular/SyncOptions.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2018 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.client.regular; | ||||||
|  |  | ||||||
|  | import io.kamax.matrix.client._SyncOptions; | ||||||
|  |  | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
|  | public class SyncOptions implements _SyncOptions { | ||||||
|  |  | ||||||
|  |     public static class Builder { | ||||||
|  |  | ||||||
|  |         private final SyncOptions obj; | ||||||
|  |  | ||||||
|  |         public Builder() { | ||||||
|  |             this.obj = new SyncOptions(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public SyncOptions get() { | ||||||
|  |             return obj; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public Builder setSince(String since) { | ||||||
|  |             obj.since = since; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public Builder setFilter(String filter) { | ||||||
|  |             obj.filter = filter; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public Builder setWithFullState(boolean withFullState) { | ||||||
|  |             obj.fullState = withFullState; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public Builder setPresence(boolean setPresence) { | ||||||
|  |             obj.setPresence = setPresence ? null : "offline"; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public Builder setTimeout(long timeout) { | ||||||
|  |             obj.timeout = timeout; | ||||||
|  |             return this; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static Builder build() { | ||||||
|  |         return new Builder(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private String since; | ||||||
|  |     private String filter; | ||||||
|  |     private Boolean fullState; | ||||||
|  |     private String setPresence; | ||||||
|  |     private Long timeout; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getSince() { | ||||||
|  |         return Optional.ofNullable(since); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getFilter() { | ||||||
|  |         return Optional.ofNullable(filter); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<Boolean> withFullState() { | ||||||
|  |         return Optional.ofNullable(fullState); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<String> getSetPresence() { | ||||||
|  |         return Optional.ofNullable(setPresence); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Optional<Long> getTimeout() { | ||||||
|  |         return Optional.ofNullable(timeout); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								src/main/java/io/kamax/matrix/codec/MxBase64.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/main/java/io/kamax/matrix/codec/MxBase64.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | /* | ||||||
|  |  * matrix-java-sdk - Matrix Client SDK for Java | ||||||
|  |  * Copyright (C) 2017 Kamax Sarl | ||||||
|  |  * | ||||||
|  |  * https://www.kamax.io/ | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as | ||||||
|  |  * published by the Free Software Foundation, either version 3 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package io.kamax.matrix.codec; | ||||||
|  |  | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.util.Base64; | ||||||
|  |  | ||||||
|  | public class MxBase64 { | ||||||
|  |  | ||||||
|  |     public static String encode(byte[] data) { | ||||||
|  |         return Base64.getEncoder().withoutPadding().encodeToString(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static String encode(String data) { | ||||||
|  |         return encode(data.getBytes(StandardCharsets.UTF_8)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user