Compare commits

...

128 Commits

Author SHA1 Message Date
49f812f867 Bump Java to 22 2024-04-02 17:45:01 +02:00
de0a3152c3 Bump JRE to 21 2024-04-02 16:08:59 +02:00
cc5d047c3f Merge pull request 'Update dependency com.googlecode.libphonenumber:libphonenumber to v8.13.34' (#40) from renovate/com.googlecode.libphonenumber-libphonenumber-8.x into master
Reviewed-on: #40
2024-04-02 13:54:24 +00:00
350776df17 Merge pull request 'Update dependency com.twilio.sdk:twilio to v10.1.3' (#39) from renovate/com.twilio.sdk-twilio-10.x into master
Reviewed-on: #39
2024-04-02 13:54:13 +00:00
7b6560e9c8 Merge pull request 'Update dependency commons-io:commons-io to v2.16.0' (#38) from renovate/commons-io-commons-io-2.x into master
Reviewed-on: #38
2024-04-02 13:54:00 +00:00
4fd4fdac60 Updates to build sucessfully - breaking changes in Firebase and SendGrid 2024-04-02 15:42:15 +02:00
dfad9d9ce8 Update dependency com.googlecode.libphonenumber:libphonenumber to v8.13.34 2024-04-02 13:01:23 +00:00
d2fc4e3bef Update dependency com.twilio.sdk:twilio to v10.1.3 2024-04-01 11:01:26 +00:00
4416c17216 Update dependency commons-io:commons-io to v2.16.0 2024-03-28 23:01:26 +00:00
f54ed462b1 Update shadowJar to new config format 2024-03-27 16:28:52 +01:00
7498dcf122 Merge pull request 'Update dependency org.yaml:snakeyaml to v2' (#37) from renovate/org.yaml-snakeyaml-2.x into master
Reviewed-on: #37
2024-03-27 14:28:16 +00:00
7e5665a56f Merge pull request 'Update dependency org.slf4j:slf4j-simple to v2' (#36) from renovate/major-slf4j-monorepo into master
Reviewed-on: #36
2024-03-27 14:28:05 +00:00
f633e9d256 Merge pull request 'Update dependency org.mariadb.jdbc:mariadb-java-client to v3' (#35) from renovate/org.mariadb.jdbc-mariadb-java-client-3.x into master
Reviewed-on: #35
2024-03-27 14:27:56 +00:00
bdfe4a00a9 Merge pull request 'Update dependency org.apache.directory.api:api-all to v2' (#34) from renovate/org.apache.directory.api-api-all-2.x into master
Reviewed-on: #34
2024-03-27 14:27:48 +00:00
50d4f0fa30 Update dependency org.yaml:snakeyaml to v2 2024-03-27 14:01:31 +00:00
bb190230b2 Update dependency org.slf4j:slf4j-simple to v2 2024-03-27 14:01:29 +00:00
c9bafd9af2 Update ma1sd to mxids 2024-03-27 14:10:04 +01:00
3c9c8ca1b5 Update dependency org.mariadb.jdbc:mariadb-java-client to v3 2024-03-27 13:01:32 +00:00
dacf96140c Update dependency org.apache.directory.api:api-all to v2 2024-03-27 13:01:30 +00:00
1d228d75e6 Update .github/workflows/codeql-analysis.yml.disabled 2024-03-27 12:39:33 +00:00
62530eda08 Update .github/workflows/codeql-analysis.disable 2024-03-27 12:39:21 +00:00
15c3e6b425 Update .github/workflows/codeql-analysis.disable.yml
Some checks failed
CodeQL / Analyze (java) (push) Failing after 31s
2024-03-27 12:38:58 +00:00
945a2dbdf5 Merge pull request 'Update dependency gradle to v8' (#33) from renovate/gradle-8.x into master
Some checks failed
CodeQL / Analyze (java) (push) Failing after 28s
Reviewed-on: #33
2024-03-27 12:33:46 +00:00
d5cebf103d Merge pull request 'Update dependency dnsjava:dnsjava to v3' (#32) from renovate/dnsjava-dnsjava-3.x into master
Some checks failed
CodeQL / Analyze (java) (push) Has been cancelled
Reviewed-on: #32
2024-03-27 12:33:26 +00:00
de14f80a40 Merge pull request 'Update dependency com.unboundid:unboundid-ldapsdk to v7' (#31) from renovate/com.unboundid-unboundid-ldapsdk-7.x into master
Some checks failed
CodeQL / Analyze (java) (push) Has been cancelled
Reviewed-on: #31
2024-03-27 12:33:12 +00:00
7ed6db537d Update codeql api version
Some checks failed
CodeQL / Analyze (java) (push) Failing after 1m33s
2024-03-27 12:28:02 +00:00
9d8d88527c Update .github/workflows/codeql-analysis.yml
Some checks failed
CodeQL / Analyze (java) (push) Failing after 33s
2024-03-27 12:26:01 +00:00
a1c82878f2 Update dependency gradle to v8
Some checks failed
CodeQL / Analyze (java) (pull_request) Failing after 21s
2024-03-27 12:02:36 +00:00
ab95c8ee32 Update dependency dnsjava:dnsjava to v3
Some checks failed
CodeQL / Analyze (java) (pull_request) Failing after 20s
2024-03-27 12:02:04 +00:00
e50a49b198 Update dependency com.unboundid:unboundid-ldapsdk to v7
Some checks failed
CodeQL / Analyze (java) (pull_request) Failing after 20s
2024-03-27 12:02:04 +00:00
4492888557 Merge pull request 'Update dependency com.twilio.sdk:twilio to v10' (#30) from renovate/com.twilio.sdk-twilio-10.x into master
Reviewed-on: #30
2024-03-27 11:52:25 +00:00
ed5407fc42 Merge pull request 'Update dependency com.sendgrid:sendgrid-java to v4' (#29) from renovate/com.sendgrid-sendgrid-java-4.x into master
Reviewed-on: #29
2024-03-27 11:52:16 +00:00
a2911f2ace Merge pull request 'Update dependency com.j256.ormlite:ormlite-jdbc to v6' (#28) from renovate/com.j256.ormlite-ormlite-jdbc-6.x into master
Reviewed-on: #28
2024-03-27 11:52:03 +00:00
e99578d168 Merge pull request 'Update dependency com.icegreen:greenmail to v2' (#27) from renovate/com.icegreen-greenmail-2.x into master
Reviewed-on: #27
2024-03-27 11:51:53 +00:00
d471ea71d7 Merge pull request 'Update dependency com.google.firebase:firebase-admin to v9' (#26) from renovate/com.google.firebase-firebase-admin-9.x into master
Reviewed-on: #26
2024-03-27 11:51:42 +00:00
56115df282 Merge pull request 'Update dependency com.github.tomakehurst:wiremock to v3' (#25) from renovate/com.github.tomakehurst-wiremock-3.x into master
Reviewed-on: #25
2024-03-27 11:51:27 +00:00
2e1194d216 Merge pull request 'Update dependency org.yaml:snakeyaml to v1.33' (#24) from renovate/org.yaml-snakeyaml-1.x into master
Reviewed-on: #24
2024-03-27 11:51:18 +00:00
ee001d543c Merge pull request 'Update dependency org.apache.commons:commons-lang3 to v3.14.0' (#21) from renovate/org.apache.commons-commons-lang3-3.x into master
Reviewed-on: #21
2024-03-27 11:51:06 +00:00
a826eb319e Merge pull request 'Update dependency commons-codec:commons-codec to v1.16.1' (#17) from renovate/commons-codec-commons-codec-1.x into master
Reviewed-on: #17
2024-03-27 11:50:56 +00:00
6b557e9954 Update dependency com.twilio.sdk:twilio to v10 2024-03-27 10:02:03 +00:00
041a4d1b73 Update dependency com.sendgrid:sendgrid-java to v4 2024-03-27 09:02:08 +00:00
c1a1741bfb Update dependency com.j256.ormlite:ormlite-jdbc to v6 2024-03-27 09:02:07 +00:00
6e1058c484 Update dependency com.icegreen:greenmail to v2 2024-03-27 08:02:04 +00:00
5f6fb38485 Update dependency com.google.firebase:firebase-admin to v9 2024-03-27 08:02:03 +00:00
c9046ffbd0 Update dependency com.github.tomakehurst:wiremock to v3 2024-03-27 07:02:17 +00:00
cf97c5a88f Update dependency org.yaml:snakeyaml to v1.33 2024-03-27 07:02:15 +00:00
3d1a8c4495 Update dependency org.apache.commons:commons-lang3 to v3.14.0 2024-03-27 07:02:14 +00:00
46dc07ef07 Update dependency commons-codec:commons-codec to v1.16.1 2024-03-27 07:02:13 +00:00
d9ab2b8739 Merge pull request 'Update dependency org.xerial:sqlite-jdbc to v3.45.2.0' (#23) from renovate/org.xerial-sqlite-jdbc-3.x into master
Reviewed-on: #23
2024-03-27 06:10:34 +00:00
14032aaf50 Merge pull request 'Update dependency org.postgresql:postgresql to v42.7.3' (#22) from renovate/org.postgresql-postgresql-42.x into master
Reviewed-on: #22
2024-03-27 06:10:23 +00:00
73051c3d00 Merge pull request 'Update dependency io.undertow:undertow-core to v2.3.12.Final' (#20) from renovate/io.undertow-undertow-core-2.x into master
Reviewed-on: #20
2024-03-27 06:10:04 +00:00
a3c8c4a8cf Merge pull request 'Update dependency gradle to v7.6.4' (#19) from renovate/gradle-7.x into master
Reviewed-on: #19
2024-03-27 06:09:47 +00:00
453751a39e Merge pull request 'Update dependency commons-io:commons-io to v2.15.1' (#18) from renovate/commons-io-commons-io-2.x into master
Reviewed-on: #18
2024-03-27 06:09:06 +00:00
ad23e91ece Merge pull request 'Update dependency commons-cli:commons-cli to v1.6.0' (#16) from renovate/commons-cli-commons-cli-1.x into master
Reviewed-on: #16
2024-03-27 06:08:42 +00:00
baabdfc2ef Merge pull request 'Update dependency com.twilio.sdk:twilio to v7.55.3' (#15) from renovate/com.twilio.sdk-twilio-7.x into master
Reviewed-on: #15
2024-03-27 06:08:20 +00:00
263e3260c9 Merge pull request 'Update dependency com.squareup.okhttp3:okhttp to v4.12.0' (#14) from renovate/okhttp-monorepo into master
Reviewed-on: #14
2024-03-27 06:08:10 +00:00
a281bdbf77 Update dependency org.xerial:sqlite-jdbc to v3.45.2.0 2024-03-26 22:02:15 +00:00
338e7f4aa2 Update dependency org.postgresql:postgresql to v42.7.3 2024-03-26 22:02:13 +00:00
a9212ce73a Update dependency io.undertow:undertow-core to v2.3.12.Final 2024-03-26 21:02:09 +00:00
f2e1fcb25f Update dependency gradle to v7.6.4 2024-03-26 20:02:39 +00:00
f5630bc4d9 Update dependency commons-io:commons-io to v2.15.1 2024-03-26 20:02:09 +00:00
dbccaecfd6 Update dependency commons-cli:commons-cli to v1.6.0 2024-03-26 19:02:15 +00:00
de0842d3a8 Update dependency com.twilio.sdk:twilio to v7.55.3 2024-03-26 18:02:10 +00:00
05424f14b8 Update dependency com.squareup.okhttp3:okhttp to v4.12.0 2024-03-26 18:02:08 +00:00
2587e6be7c Merge pull request 'Update dependency com.mchange:c3p0 to v0.10.0' (#13) from renovate/com.mchange-c3p0-0.x into master
Reviewed-on: #13
2024-03-26 17:39:03 +00:00
20062fe5bc Merge pull request 'Update dependency com.kohlschutter.junixsocket:junixsocket-core to v2.9.0' (#12) from renovate/com.kohlschutter.junixsocket-junixsocket-core-2.x into master
Reviewed-on: #12
2024-03-26 17:38:51 +00:00
0ec6462ff4 Update dependency com.mchange:c3p0 to v0.10.0 2024-03-26 17:02:16 +00:00
567c7bb972 Update dependency com.kohlschutter.junixsocket:junixsocket-core to v2.9.0 2024-03-26 17:02:14 +00:00
1c6322f1c2 Merge pull request 'Update dependency com.j256.ormlite:ormlite-jdbc to v5.7' (#11) from renovate/com.j256.ormlite-ormlite-jdbc-5.x into master
Reviewed-on: #11
2024-03-26 16:05:03 +00:00
603cdd1340 Merge pull request 'Update dependency com.icegreen:greenmail to v1.6.15' (#10) from renovate/com.icegreen-greenmail-1.x into master
Reviewed-on: #10
2024-03-26 16:04:50 +00:00
a6164379c5 Update dependency com.j256.ormlite:ormlite-jdbc to v5.7 2024-03-26 16:02:05 +00:00
fc9d6b3a36 Update dependency com.icegreen:greenmail to v1.6.15 2024-03-26 16:02:03 +00:00
8b14664dc7 Merge pull request 'Update dependency com.googlecode.libphonenumber:libphonenumber to v8.13.33' (#9) from renovate/com.googlecode.libphonenumber-libphonenumber-8.x into master
Reviewed-on: #9
2024-03-26 15:18:14 +00:00
f0922d67df Merge pull request 'Update dependency com.google.firebase:firebase-admin to v5.11.0' (#8) from renovate/com.google.firebase-firebase-admin-5.x into master
Reviewed-on: #8
2024-03-26 15:18:02 +00:00
6e05b51fdc Update dependency com.googlecode.libphonenumber:libphonenumber to v8.13.33 2024-03-26 15:02:08 +00:00
0999ef6309 Update dependency com.google.firebase:firebase-admin to v5.11.0 2024-03-26 15:02:06 +00:00
cae00f4606 Merge pull request 'Update dependency com.github.ben-manes:gradle-versions-plugin to v0.51.0' (#7) from renovate/com.github.ben-manes-gradle-versions-plugin-0.x into master
Reviewed-on: #7
2024-03-26 14:15:58 +00:00
941ae697e7 Merge pull request 'Update openjdk Docker tag to v11.0.16-jre-slim' (#6) from renovate/openjdk-11.x into master
Reviewed-on: #6
2024-03-26 14:15:43 +00:00
fbf1ea8f5b Merge pull request 'Update dependency org.slf4j:slf4j-simple to v1.7.36' (#5) from renovate/slf4j-monorepo into master
Reviewed-on: #5
2024-03-26 14:15:25 +00:00
4eef3ac40d Merge pull request 'Update dependency org.mariadb.jdbc:mariadb-java-client to v2.7.12' (#4) from renovate/org.mariadb.jdbc-mariadb-java-client-2.x into master
Reviewed-on: #4
2024-03-26 14:15:06 +00:00
e6c90aa00f Update dependency com.github.ben-manes:gradle-versions-plugin to v0.51.0 2024-03-26 14:02:17 +00:00
ca306a3212 Update openjdk Docker tag to v11.0.16-jre-slim 2024-03-26 14:02:15 +00:00
e8864afe02 Update dependency org.slf4j:slf4j-simple to v1.7.36 2024-03-26 13:02:02 +00:00
f09ede8780 Update dependency org.mariadb.jdbc:mariadb-java-client to v2.7.12 2024-03-26 13:02:01 +00:00
98146d3468 Merge pull request 'Update dependency org.apache.httpcomponents:httpclient to v4.5.14' (#3) from renovate/org.apache.httpcomponents-httpclient-4.x into master
Reviewed-on: #3
2024-03-26 12:25:59 +00:00
5f64b72a91 Merge pull request 'Update dependency com.unboundid:unboundid-ldapsdk to v4.0.14' (#2) from renovate/com.unboundid-unboundid-ldapsdk-4.x into master
Reviewed-on: #2
2024-03-26 12:25:43 +00:00
acb2b5a37d Update ma1sd to mxids 2024-03-26 13:21:48 +01:00
9f9c48aaa7 Update dependency org.apache.httpcomponents:httpclient to v4.5.14 2024-03-26 12:21:43 +00:00
eb6e541e15 Update dependency com.unboundid:unboundid-ldapsdk to v4.0.14 2024-03-26 12:21:41 +00:00
e45ac5a78a Merge pull request 'Add renovate.json' (#1) from tomas.kracmar-add-renovatebot-support into master
Reviewed-on: #1
2024-03-14 09:06:29 +00:00
aebcb7b5e1 Add renovate.json 2024-03-14 09:06:12 +00:00
c45f95ce3f Merge pull request 'Upgrade to V3 API' (#1) from ext/v3_update into master
Reviewed-on: cqrenet/ma1sd#1
2024-03-11 08:51:06 +00:00
640fa8e9f1 Upgrade to V3 API 2024-03-11 09:50:09 +01:00
0f3c37bf6a Get access_token from header correctly 2024-03-05 17:50:29 +01:00
Anatoliy Sablin
ae5864cd91 Bump dependencies. 2021-04-16 21:48:19 +03:00
Anatoliy Sablin
e456724caf Bump gradle to 7.0. Replace jcenter with mavenCentral and gradle plugin portal. 2021-04-16 20:58:32 +03:00
Anatoliy Sablin
ed9dcc4061 Respond with application/json for the register submitToken. 2021-02-04 21:10:25 +03:00
Anatoliy Sablin
ea8e386939 Add internal API to manually invoke invitation manager. 2021-01-25 22:45:18 +03:00
Anatoliy Sablin
e0ec887118 Add config print full display name of the invited person. 2021-01-17 20:06:09 +03:00
Anatoliy Sablin
a71d32ba77 Add config option to specify period dimension of the invitation scheduler. 2021-01-13 22:09:30 +03:00
Anatoliy Sablin
a0f6fe9b0d Add forgotten M_TERMS_NOT_SIGNED error message. 2021-01-13 21:41:21 +03:00
ma1uta
c25647156a Merge pull request #77 from mrjohnson22/master
#76 Set a message for error responses
2020-12-20 11:14:20 +00:00
Xavier Johnson
e7c4c12a98 #76 Set a message for error responses
Without one, clients might treat errors as generic failures instead of
handling them in a manner appropriate for their error code
2020-12-18 23:00:06 -05:00
Anatoliy Sablin
90b2b5301c #68 Mark thusted_third_party_id_servers synapse parameter as deprecated. 2020-12-07 20:39:47 +03:00
Anatoliy Sablin
0d93a26e6d #65 Encode query parameters in the validation link. 2020-12-07 20:32:59 +03:00
ma1uta
c29fc0f0eb Merge pull request #71 from q-wertz/master
Force MatrixID to be lowercase
2020-11-29 08:22:45 +00:00
Clemens Sonnleitner
e421c851c9 Force MatrixID to be lowercase 2020-11-27 13:08:45 +01:00
ma1uta
5b2b45233a Merge pull request #67 from Higgs1/master
Add support for unix sockets.
2020-11-05 05:56:26 +00:00
Lexxy Fox
888f7a4209 Added support for unix sockets. 2020-11-04 08:21:35 -08:00
Anatoliy Sablin
0c301a49c7 Change column type to text for postgresql. 2020-10-26 23:26:15 +03:00
ma1uta
1fda2dd3b7 Create codeql-analysis.yml 2020-10-01 14:51:31 +03:00
ma1uta
c4a20efe5e Merge pull request #58 from nE0sIghT/wip/multidomain
Support for Active Directory multidomain forest
2020-09-19 13:14:19 +00:00
ma1uta
fc45f1b090 Merge pull request #55 from mattcen/docker-build-cleanup
Docker build cleanup
2020-09-19 13:13:16 +00:00
Matt Cengia
1480507d76 Only build .jar on current build platform
Because the .jar is platform-independent, we don't need to build it for every architecture.
2020-09-18 12:45:33 +10:00
Matt Cengia
a1ab1e8e0a Tidy Gradle dockerBuildX target
Build linux/amd64, linux/arm64, and linux/arm/v7 (arm 32-bit) targets
all at once.
This still requires Gradle and JDK on the local machine (i.e. outside of
the Docker build container), because it seems pointless to build the
.jar 3 times, once for each architecture, but tags all the images with
the same tag, rather than using a tag for each architecture. This allows
clients to all use the same image tag, but pull down the architecture
that's right for them.

I'd like to have it build the .jar file in a container (so the host
doesn't need JDK and Gradle), but couldn't think how to do that
efficiently (i.e. only once), with this approach.
2020-09-17 10:54:29 +10:00
Matt Cengia
1e5033b461 Don't require Gradle to build Docker image
Update Dockerfile to use a multi-stage build and run Gradle *within* the
builder container, rather than on the host, so the host needn't have
Gradle or JDK installed, then copy the build .jar from the builder
container into the final container.

Update build.gradle's dockerBuild target to not build the jar, but
instead do it within the Docker build process. This results in some
double-handling because it requires Gradle and JDK both on the host
system *and* within the container, and runs two instances of Gradle
during the build, but is added for backwards compatibility. The better
approach (rather than running `./gradlew dockerBuild`) is to manually
run `docker build -t ma1ua/ma1sd .`.

I've tested this process on both a Debian amd64 system and a Raspberry
Pi 3 running Raspbian, and it seems to work (though the RPi is pretty
slow).
2020-09-17 10:54:29 +10:00
Yuri Konotopov
7323851c6e Support for Active Directory multidomain forest
In AD forest samAccountName (or uid) may not be unique in the
entire forest and userPrincipalName contains "@" symbol
disallowed in Matrix User Identifiers.

This commit reflects changes in ldap_auth_provider that adds
mxid generation logic for Active Directory.

Signed-off-by: Yuri Konotopov <ykonotopov@gnome.org>
2020-08-28 15:33:10 +04:00
Anatoliy Sablin
08db73e55b Escape special characters in the LDAP query string. 2020-08-02 16:05:54 +03:00
Anatoliy Sablin
9fba20475b fix #49. 2020-06-23 00:18:27 +03:00
ma1uta
9af5fce014 Merge pull request #50 from lub/patch-1
remove warning about matrix-synapse-ldap3
2020-06-22 19:54:51 +00:00
ma1uta
9843e14c1a Merge pull request #38 from NullIsNot0/NullIsNot0-make-emails-lowercase
Make all 3PID address lowercase to avoid duplicates
2020-06-22 19:51:42 +00:00
lub
60e6f1e23c fix typo
on -> one
2020-06-05 13:23:37 +02:00
lub
6cdbcc69c7 remove warning about matrix-synapse-ldap3
I don't think it's a fair assessment that the project is unmaintaned. When you look at the issues and PRs there still is active development happening.
2020-06-05 13:22:49 +02:00
Anatoliy Sablin
ed7c714738 Fix #41. 2020-05-31 22:56:01 +03:00
Anatoliy Sablin
a9d783192b Add multiple-platform builds. Add experimental arm64 build. 2020-05-31 22:10:32 +03:00
ma1uta
2bb5a734d1 Merge pull request #45 from teutat3s/fix_directory_lookups
Avoid including bridged user in directory lookups
2020-05-19 19:32:31 +00:00
teutat3s
9aa5c4cca9 Avoid including bridged user in directory lookups 2020-05-19 13:04:22 +02:00
NullIsNot0
7c94bd4744 Make all 3PID address lowercase to avoid duplicates
These changes complement #11 where locally saved e-mail address can be "name.surname@example.com", but e-mail address in LDAP can be "Name.Surname@example.com". They are treated as two different e-mail addresses and user gets 2 invitation notification e-mails. We change ThreePid model's address property to convert all info to lowercase and [be915ae](be915aed94) can do it's job better.
The downside of this is that all medium addresses get converted to lowercase, not only e-mails. For now I can't think of any examples where medium values need to stay case sensitive.
2020-05-06 07:41:44 +03:00
96 changed files with 957 additions and 749 deletions

View File

@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 3 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['java']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 0
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

4
.gitignore vendored
View File

@@ -7,8 +7,8 @@ out/
.idea/ .idea/
# Local dev config # Local dev config
/ma1sd.yaml /mxids.yaml
/application.yaml /application.yaml
# Local dev storage # Local dev storage
/ma1sd.db /mxids.db

View File

@@ -1,18 +1,26 @@
FROM openjdk:8-jre-alpine FROM --platform=$BUILDPLATFORM openjdk:22-ea-21-jdk-slim-bullseye AS builder
RUN apk update && apk add gradle git && rm -rf /var/lib/apk/* /var/cache/apk/*
WORKDIR /mxids
COPY . .
RUN ./gradlew shadowJar
FROM openjdk:22-ea-21-jdk-slim-bullseye
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/ma1sd VOLUME /etc/mxids
VOLUME /var/ma1sd VOLUME /var/mxids
EXPOSE 8090 EXPOSE 8090
ENV JAVA_OPTS="" ENV JAVA_OPTS=""
ENV CONF_FILE_PATH="/etc/ma1sd/ma1sd.yaml" ENV CONF_FILE_PATH="/etc/mxids/mxids.yaml"
ENV SIGN_KEY_PATH="/var/ma1sd/sign.key" ENV SIGN_KEY_PATH="/var/mxids/sign.key"
ENV SQLITE_DATABASE_PATH="/var/ma1sd/ma1sd.db" ENV SQLITE_DATABASE_PATH="/var/mxids/mxids.db"
CMD [ "/start.sh" ] CMD [ "/start.sh" ]
ADD src/docker/start.sh /start.sh ADD src/docker/start.sh /start.sh
ADD src/script/ma1sd /app/ma1sd ADD src/script/mxids /app/mxids
ADD build/libs/ma1sd.jar /app/ma1sd.jar COPY --from=builder /mxids/build/libs/mxids.jar /app/mxids.jar

16
DockerfileX Normal file
View File

@@ -0,0 +1,16 @@
FROM --platform=$BUILDPLATFORM openjdk:11.0.16-jre-slim
VOLUME /etc/mxids
VOLUME /var/mxids
EXPOSE 8090
ENV JAVA_OPTS=""
ENV CONF_FILE_PATH="/etc/mxids/mxids.yaml"
ENV SIGN_KEY_PATH="/var/mxids/sign.key"
ENV SQLITE_DATABASE_PATH="/var/mxids/mxids.db"
CMD [ "/start.sh" ]
ADD src/docker/start.sh /start.sh
ADD src/script/mxids /app/mxids
ADD build/libs/mxids.jar /app/mxids.jar

View File

@@ -1,5 +1,5 @@
/* /*
* ma1sd - Matrix Identity Server Daemon * mxids - Matrix Identity Server
* Copyright (C) 2017 Kamax Sarl * Copyright (C) 2017 Kamax Sarl
* *
* https://www.kamax.io/ * https://www.kamax.io/
@@ -20,22 +20,22 @@
import java.util.regex.Pattern import java.util.regex.Pattern
apply plugin: 'java' apply plugin: 'java-library'
apply plugin: 'application' apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'com.github.ben-manes.versions' apply plugin: 'com.github.ben-manes.versions'
def confFileName = "ma1sd.example.yaml" def confFileName = "mxids.example.yaml"
def distDir = "${project.buildDir}/dist" def distDir = "${project.buildDir}/dist"
def debBinPath = "/usr/lib/ma1sd" def debBinPath = "/usr/lib/mxids"
def debConfPath = "/etc/ma1sd" def debConfPath = "/etc/mxids"
def debDataPath = "/var/lib/ma1sd" def debDataPath = "/var/lib/mxids"
def debSystemdPath = "/etc/systemd/system" def debSystemdPath = "/etc/systemd/system"
def debConfFileName = confFileName def debConfFileName = confFileName
def debStartScriptFilename = "ma1sd" def debStartScriptFilename = "mxids"
def debBuildBasePath = "${project.buildDir}/tmp/debian" def debBuildBasePath = "${project.buildDir}/tmp/debian"
def debBuildDebianPath = "${debBuildBasePath}/DEBIAN" def debBuildDebianPath = "${debBuildBasePath}/DEBIAN"
@@ -44,18 +44,18 @@ def debBuildConfPath = "${debBuildBasePath}${debConfPath}"
def debBuildDataPath = "${debBuildBasePath}${debDataPath}" def debBuildDataPath = "${debBuildBasePath}${debDataPath}"
def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}" def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}"
def dockerImageName = "ma1uta/ma1sd" def dockerImageName = "cqrenet/mxids"
def dockerImageTag = "${dockerImageName}:${ma1sdVersion()}" def dockerImageTag = "${dockerImageName}:${mxidsVersion()}"
group = 'io.kamax' group = 'io.kamax'
mainClassName = 'io.kamax.mxisd.MxisdStandaloneExec' mainClassName = 'io.kamax.mxisd.MxisdStandaloneExec'
sourceCompatibility = '1.8' sourceCompatibility = '11'
targetCompatibility = '1.8' targetCompatibility = '11'
String ma1sdVersion() { String mxidsVersion() {
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?") def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
String version = System.getenv('MA1SD_BUILD_VERSION') String version = System.getenv('MXIDS_BUILD_VERSION')
if (version == null || version.size() == 0) { if (version == null || version.size() == 0) {
version = gitVersion() version = gitVersion()
} }
@@ -73,109 +73,114 @@ String gitVersion() {
buildscript { buildscript {
repositories { repositories {
jcenter() gradlePluginPortal()
mavenCentral()
google()
} }
dependencies { dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:5.1.0' classpath 'com.github.johnrengelman:shadow:8.1.1'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.27.0' classpath 'com.github.ben-manes:gradle-versions-plugin:0.51.0'
} }
} }
repositories { repositories {
jcenter() mavenCentral()
} }
dependencies { dependencies {
// Logging // Logging
compile 'org.slf4j:slf4j-simple:1.7.25' api 'org.slf4j:slf4j-simple:2.0.12'
// Easy file management // Easy file management
compile 'commons-io:commons-io:2.6' api 'commons-io:commons-io:2.16.0'
// Config management // Config management
compile 'org.yaml:snakeyaml:1.25' api 'org.yaml:snakeyaml:1.33'
// Dependencies from old Matrix-java-sdk // Dependencies from old Matrix-java-sdk
compile 'org.apache.commons:commons-lang3:3.9' api 'org.apache.commons:commons-lang3:3.14.0'
compile 'com.squareup.okhttp3:okhttp:4.2.2' api 'com.squareup.okhttp3:okhttp:4.12.0'
compile 'commons-codec:commons-codec:1.13' api 'commons-codec:commons-codec:1.16.1'
// ORMLite // ORMLite
compile 'com.j256.ormlite:ormlite-jdbc:5.1' api 'com.j256.ormlite:ormlite-jdbc:6.1'
// ed25519 handling // ed25519 handling
compile 'net.i2p.crypto:eddsa:0.3.0' api 'net.i2p.crypto:eddsa:0.3.0'
// LDAP connector // LDAP connector
compile 'org.apache.directory.api:api-all:1.0.3' api 'org.apache.directory.api:api-all:2.1.6'
// DNS lookups // DNS lookups
compile 'dnsjava:dnsjava:2.1.9' api 'dnsjava:dnsjava:3.5.3'
// HTTP connections // HTTP connections
compile 'org.apache.httpcomponents:httpclient:4.5.10' api 'org.apache.httpcomponents:httpclient:4.5.14'
// Phone numbers validation // Phone numbers validation
compile 'com.googlecode.libphonenumber:libphonenumber:8.10.22' api 'com.googlecode.libphonenumber:libphonenumber:8.13.34'
// E-mail sending // E-mail sending
compile 'javax.mail:javax.mail-api:1.6.2' api 'javax.mail:javax.mail-api:1.6.2'
compile 'com.sun.mail:javax.mail:1.6.2' api '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' api 'com.google.firebase:firebase-admin:9.2.0'
// Connection Pool // Connection Pool
compile 'com.mchange:c3p0:0.9.5.4' api 'com.mchange:c3p0:0.10.0'
// SQLite // SQLite
compile 'org.xerial:sqlite-jdbc:3.28.0' api 'org.xerial:sqlite-jdbc:3.45.2.0'
// PostgreSQL // PostgreSQL
compile 'org.postgresql:postgresql:42.2.8' api 'org.postgresql:postgresql:42.7.3'
// MariaDB/MySQL // MariaDB/MySQL
compile 'org.mariadb.jdbc:mariadb-java-client:2.5.1' api 'org.mariadb.jdbc:mariadb-java-client:3.3.3'
// UNIX sockets
api 'com.kohlschutter.junixsocket:junixsocket-core:2.9.0'
// Twilio SDK for SMS // Twilio SDK for SMS
compile 'com.twilio.sdk:twilio:7.45.0' api 'com.twilio.sdk:twilio:10.1.3'
// SendGrid SDK to send emails from GCE // SendGrid SDK to send emails from GCE
compile 'com.sendgrid:sendgrid-java:2.2.2' api 'com.sendgrid:sendgrid-java:4.10.2'
// ZT-Exec for exec identity store // ZT-Exec for exec identity store
compile 'org.zeroturnaround:zt-exec:1.11' api 'org.zeroturnaround:zt-exec:1.12'
// HTTP server // HTTP server
compile 'io.undertow:undertow-core:2.0.27.Final' api 'io.undertow:undertow-core:2.3.12.Final'
// Command parser for AS interface // Command parser for AS interface
implementation 'commons-cli:commons-cli:1.4' api 'commons-cli:commons-cli:1.6.0'
testCompile 'junit:junit:4.13-rc-1' testImplementation 'junit:junit:4.13.2'
testCompile 'com.github.tomakehurst:wiremock:2.25.1' testImplementation 'com.github.tomakehurst:wiremock:3.0.1'
testCompile 'com.unboundid:unboundid-ldapsdk:4.0.12' testImplementation 'com.unboundid:unboundid-ldapsdk:7.0.0'
testCompile 'com.icegreen:greenmail:1.5.11' testImplementation 'com.icegreen:greenmail:1.6.15'
} }
jar { jar {
manifest { manifest {
attributes( attributes(
'Implementation-Version': ma1sdVersion() 'Implementation-Version': mxidsVersion()
) )
} }
} }
shadowJar { shadowJar {
baseName = project.name archiveBaseName.set(project.name)
classifier = null archiveClassifier.set('') // Set to an empty string if you don't need a classifier.
version = null archiveVersion.set('') // Set to an empty string if you don't want the version in the jar name.
} }
task debBuild(dependsOn: shadowJar) { task debBuild(dependsOn: shadowJar) {
doLast { doLast {
String debVersion = ma1sdVersion() String debVersion = mxidsVersion()
println "Version for package: ${debVersion}" println "Version for package: ${debVersion}"
mkdir distDir mkdir distDir
mkdir debBuildBasePath mkdir debBuildBasePath
@@ -186,7 +191,7 @@ task debBuild(dependsOn: shadowJar) {
mkdir debBuildSystemdPath mkdir debBuildSystemdPath
copy { copy {
from "${project.buildDir}/libs/ma1sd.jar" from "${project.buildDir}/libs/mxids.jar"
into debBuildBinPath into debBuildBinPath
} }
@@ -234,12 +239,12 @@ task debBuild(dependsOn: shadowJar) {
ant.replace( ant.replace(
file: "${debBuildDebianPath}/postinst", file: "${debBuildDebianPath}/postinst",
token: '%DEB_CONF_FILE%', token: '%DEB_CONF_FILE%',
value: "${debConfPath}/ma1sd.yaml" value: "${debConfPath}/mxids.yaml"
) )
ant.chmod( ant.chmod(
file: "${debBuildDebianPath}/postinst", file: "${debBuildDebianPath}/postinst",
perm: 'a+x' perm: '0755'
) )
ant.chmod( ant.chmod(
@@ -248,7 +253,7 @@ task debBuild(dependsOn: shadowJar) {
) )
copy { copy {
from "${project.file('src/systemd/ma1sd.service')}" from "${project.file('src/systemd/mxids.service')}"
into debBuildSystemdPath into debBuildSystemdPath
} }
@@ -264,7 +269,7 @@ task debBuild(dependsOn: shadowJar) {
} }
} }
task dockerBuild(type: Exec, dependsOn: shadowJar) { task dockerBuild(type: Exec) {
commandLine 'docker', 'build', '-t', dockerImageTag, project.rootDir commandLine 'docker', 'build', '-t', dockerImageTag, project.rootDir
doLast { doLast {
@@ -274,6 +279,15 @@ task dockerBuild(type: Exec, dependsOn: shadowJar) {
} }
} }
task dockerBuildX(type: Exec, dependsOn: shadowJar) {
commandLine 'docker', 'buildx', 'build', '--push', '--platform', 'linux/arm64,linux/amd64,linux/arm/v7', '-t', dockerImageTag , project.rootDir
doLast {
exec {
commandLine 'docker', 'buildx', 'build', '--push', '--platform', 'linux/arm64,linux/amd64,linux/arm/v7', '-t', "${dockerImageName}:latest-dev", project.rootDir
}
}
}
task dockerPush(type: Exec) { task dockerPush(type: Exec) {
commandLine 'docker', 'push', dockerImageTag commandLine 'docker', 'push', dockerImageTag
@@ -283,3 +297,33 @@ task dockerPush(type: Exec) {
} }
} }
} }
task dockerPushX(type: Exec) {
commandLine 'docker', 'push', dockerImageTag
doLast {
exec {
commandLine 'docker', 'push', "${dockerImageName}:latest-dev"
commandLine 'docker', 'push', "${dockerImageName}:latest-amd64-dev"
commandLine 'docker', 'push', "${dockerImageName}:latest-arm64-dev"
}
}
}
tasks.named('assemble').configure {
dependsOn shadowJar
}
tasks.withType(AbstractArchiveTask) {
if (it.name == 'distZip' || it.name == 'distTar') {
dependsOn shadowJar
}
}
tasks.named('startScripts').configure {
mustRunAfter shadowJar
}
tasks.named('startShadowScripts').configure {
dependsOn jar
}

View File

@@ -16,7 +16,7 @@ TCP 443
+<---------------------------------<+ +<---------------------------------<+
| |
| +-------------------+ | +-------------------+
TCP 8090 +-> | ma1sd | TCP 8090 +-> | mxids |
| | | |
| - Profile's 3PIDs | | - Profile's 3PIDs |
| - 3PID Invites | | - 3PID Invites |

View File

@@ -1,14 +1,18 @@
# From source # From source
- [Binaries](#binaries) - [From source](#from-source)
- [Requirements](#requirements) - [Binaries](#binaries)
- [Build](#build) - [Requirements](#requirements)
- [Debian package](#debian-package) - [Build](#build)
- [Docker image](#docker-image) - [Debian package](#debian-package)
- [Next steps](#next-steps) - [Docker image](#docker-image)
- [Multi-platform builds](#multi-platform-builds)
- [Next steps](#next-steps)
## Binaries ## Binaries
### Requirements ### Requirements
- JDK 1.8 - JDK 1.8
- OpenJDK 11
- OpenJDK 14
### Build ### Build
```bash ```bash
@@ -17,7 +21,7 @@ cd ma1sd
./gradlew build ./gradlew build
``` ```
Create a new configuration file by coping `ma1sd.example.yaml` to `ma1sd.yaml` and edit to your needs. Create a new configuration file by coping `mxids.example.yaml` to `mxids.yaml` and edit to your needs.
For advanced configuration, see the [Configure section](configure.md). For advanced configuration, see the [Configure section](configure.md).
Start the server in foreground to validate the build and configuration: Start the server in foreground to validate the build and configuration:
@@ -70,5 +74,13 @@ Then follow the instruction in the [Debian package](install/debian.md) document.
``` ```
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.
### Multi-platform builds
Provided with experimental docker feature [buildx](https://docs.docker.com/buildx/working-with-buildx/)
To build the arm64 and amd64 images run:
```bash
./gradlew dockerBuildX
```
## Next steps ## Next steps
- [Integrate with your infrastructure](getting-started.md#integrate) - [Integrate with your infrastructure](getting-started.md#integrate)

View File

@@ -56,8 +56,7 @@ Accounts cannot currently migrate/move from one server to another.
See a [brief explanation document](concepts.md) about Matrix and ma1sd 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 ma1sd? ### 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 despite The [synapse LDAP3 auth provider](https://github.com/matrix-org/matrix-synapse-ldap3) only handles one 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

View File

@@ -121,15 +121,13 @@ server {
} }
``` ```
### Synapse ### Synapse (Deprecated with synapse v1.4.0)
Add your ma1sd 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:
- matrix.example.org - matrix.example.org
``` ```
It is **highly recommended** to remove `matrix.org` and `vector.im` (or any other default entry) from your configuration
so only your own Identity server is authoritative for your HS.
## Validate (Under reconstruction) ## 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

View File

@@ -1,7 +1,10 @@
# Operations Guide # Operations Guide
- [Overview](#overview) - [Operations Guide](#operations-guide)
- [Maintenance](#maintenance) - [Overview](#overview)
- [Backuo](#backup) - [Maintenance](#maintenance)
- [Backup](#backup)
- [Run](#run)
- [Restore](#restore)
## Overview ## Overview
This document gives various information for the day-to-day management and operations of ma1sd. This document gives various information for the day-to-day management and operations of ma1sd.

View File

@@ -1,5 +1,5 @@
#Thu Dec 05 22:39:36 MSK 2019 #Thu Dec 05 22:39:36 MSK 2019
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -21,7 +21,7 @@
# #
matrix: matrix:
domain: '' domain: ''
v1: true # deprecated v1: false # deprecated
v2: true # MSC2140 API v2. Riot require enabled V2 API. v2: true # MSC2140 API v2. Riot require enabled V2 API.
@@ -32,11 +32,11 @@ matrix:
# /!\ THIS MUST **NOT** BE YOUR HOMESERVER KEYS FILE /!\ # /!\ THIS MUST **NOT** BE YOUR HOMESERVER KEYS FILE /!\
# If this path does not exist, it will be auto-generated. # If this path does not exist, it will be auto-generated.
# #
# During testing, /var/tmp/ma1sd/keys is a possible value # During testing, /var/tmp/mxids/keys is a possible value
# For production, recommended location shall be one of the following: # For production, recommended location shall be one of the following:
# - /var/lib/ma1sd/keys # - /var/lib/mxids/keys
# - /var/opt/ma1sd/keys # - /var/opt/mxids/keys
# - /var/local/ma1sd/keys # - /var/local/mxids/keys
# #
key: key:
path: '' path: ''
@@ -46,20 +46,20 @@ key:
# /!\ THIS MUST **NOT** BE YOUR HOMESERVER DATABASE /!\ # /!\ THIS MUST **NOT** BE YOUR HOMESERVER DATABASE /!\
# #
# Examples: # Examples:
# - /var/opt/ma1sd/store.db # - /var/opt/mxids/store.db
# - /var/local/ma1sd/store.db # - /var/local/mxids/store.db
# - /var/lib/ma1sd/store.db # - /var/lib/mxids/store.db
# #
storage: storage:
# backend: sqlite # or postgresql # backend: sqlite # or postgresql
provider: provider:
sqlite: sqlite:
database: '/path/to/ma1sd.db' database: '/path/to/mxids.db'
# postgresql: # postgresql:
# # Wrap all string values with quotes to avoid yaml parsing mistakes # # Wrap all string values with quotes to avoid yaml parsing mistakes
# database: '//localhost/ma1sd' # or full variant //192.168.1.100:5432/ma1sd_database # database: '//localhost/mxids' # or full variant //192.168.1.100:5432/mxids_database
# username: 'ma1sd_user' # username: 'mxids_user'
# password: 'ma1sd_password' # password: 'mxids_password'
# #
# # Pool configuration for postgresql backend. # # Pool configuration for postgresql backend.
# ####### # #######
@@ -165,6 +165,8 @@ threepid:
# ldap: # ldap:
# enabled: true # enabled: true
# lookup: true # hash lookup # lookup: true # hash lookup
# activeDirectory: false
# defaultDomain: ''
# connection: # connection:
# host: 'ldap.domain.tld' # host: 'ldap.domain.tld'
# port: 389 # port: 389
@@ -188,10 +190,10 @@ threepid:
# terms: # terms:
# en: # lang # en: # lang
# name: term name en # localized name # name: term name en # localized name
# url: https://ma1sd.host.tld/term_en.html # localized url # url: https://mxids.host.tld/term_en.html # localized url
# fe: # lang # fe: # lang
# name: term name fr # localized name # name: term name fr # localized name
# url: https://ma1sd.host.tld/term_fr.html # localized url # url: https://mxids.host.tld/term_fr.html # localized url
# regexp: # regexp:
# - '/_matrix/identity/v2/account.*' # - '/_matrix/identity/v2/account.*'
# - '/_matrix/identity/v2/hash_details' # - '/_matrix/identity/v2/hash_details'
@@ -202,3 +204,16 @@ threepid:
# root: error # default level for all loggers (apps and thirdparty libraries) # root: error # default level for all loggers (apps and thirdparty libraries)
# app: info # log level only for the ma1sd # app: info # log level only for the ma1sd
# requests: false # or true to dump full requests and responses # requests: false # or true to dump full requests and responses
# Config invitation manager
#invite:
# fullDisplayName: true # print full name of the invited user (default false)
# resolution:
# timer: 10
# period: seconds # search invites every 10 seconds (by default 5 minutes)
# Internal API
#internal:
# enabled: true # default to false

11
renovate.json Normal file
View File

@@ -0,0 +1,11 @@
{
"extends": [
"config:base"
],
"packageRules": [
{
"updateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
}
]
}

View File

@@ -1,6 +1,6 @@
Package: ma1sd Package: mxids
Maintainer: ma1uta <sablintolya@gmail.com> Maintainer: ma1uta <sablintolya@gmail.com>
Homepage: https://github.com/ma1uta/ma1sd Homepage: https://git.cqre.net/cqrenet/mxids.git
Description: Federated Matrix Identity Server Description: Federated Matrix Identity Server
Architecture: all Architecture: all
Section: net Section: net

View File

@@ -1,19 +1,19 @@
#!/bin/bash -e #!/bin/bash -e
# Add service account # Add service account
useradd -r ma1sd || true useradd -r mxids || true
# Set permissions for data directory # Set permissions for data directory
chown -R ma1sd:ma1sd %DEB_DATA_DIR% chown -R mxids:mxids %DEB_DATA_DIR%
# Create symlink to ma1sd run script # Create symlink to mxids run script
ln -sfT /usr/lib/ma1sd/ma1sd /usr/bin/ma1sd ln -sfT /usr/lib/mxids/mxids /usr/bin/mxids
# Enable systemd service # Enable systemd service
systemctl enable ma1sd.service systemctl enable mxids.service
# If we already have a config file setup, we attempt to run ma1sd automatically # If we already have a config file setup, we attempt to run mxids automatically
# Specifically targeted at upgrades where the service needs to be restarted # Specifically targeted at upgrades where the service needs to be restarted
if [ -f "%DEB_CONF_FILE%" ]; then if [ -f "%DEB_CONF_FILE%" ]; then
systemctl restart ma1sd.service systemctl restart mxids.service
fi fi

View File

@@ -1,10 +1,10 @@
#!/bin/bash #!/bin/bash
# Stop running instance if needed # Stop running instance if needed
systemctl stop ma1sd.service systemctl stop mxids.service
# Disable service if exists # Disable service if exists
systemctl disable ma1sd.service systemctl disable mxids.service
# remove symlink # remove symlink
rm /usr/bin/ma1sd rm /usr/bin/mxids

View File

@@ -27,8 +27,8 @@ if [[ -n "$CONF_FILE_PATH" ]] && [ ! -f "$CONF_FILE_PATH" ]; then
echo >> "$CONF_FILE_PATH" echo >> "$CONF_FILE_PATH"
fi fi
echo "Starting ma1sd..." echo "Starting mxids..."
echo echo
fi fi
exec java -jar /app/ma1sd.jar -c /etc/ma1sd/ma1sd.yaml exec java -jar /app/mxids.jar -c /etc/mxids/mxids.yaml

View File

@@ -53,7 +53,7 @@ public class MatrixPath {
} }
public static MatrixPath clientR0() { public static MatrixPath clientR0() {
return client().add("r0"); return client().add("v3");
} }
private StringBuilder path = new StringBuilder(); private StringBuilder path = new StringBuilder();

View File

@@ -27,7 +27,7 @@ public class ThreePid implements _ThreePid {
public ThreePid(String medium, String address) { public ThreePid(String medium, String address) {
this.medium = medium; this.medium = medium;
this.address = address; this.address = address.toLowerCase();
} }
@Override @Override

View File

@@ -375,13 +375,13 @@ public abstract class AMatrixHttpClient implements _MatrixClientRaw {
} }
protected HttpUrl.Builder getClientPathBuilder(String... segments) { protected HttpUrl.Builder getClientPathBuilder(String... segments) {
String[] base = { "client", "r0" }; String[] base = { "client", "v3" };
segments = ArrayUtils.addAll(base, segments); segments = ArrayUtils.addAll(base, segments);
return getPathBuilder(segments); return getPathBuilder(segments);
} }
protected HttpUrl.Builder getMediaPathBuilder(String... segments) { protected HttpUrl.Builder getMediaPathBuilder(String... segments) {
String[] base = { "media", "r0" }; String[] base = { "media", "v3" };
segments = ArrayUtils.addAll(base, segments); segments = ArrayUtils.addAll(base, segments);
return getPathBuilder(segments); return getPathBuilder(segments);
} }

View File

@@ -58,6 +58,7 @@ import io.kamax.mxisd.http.undertow.handler.identity.v1.BulkLookupHandler;
import io.kamax.mxisd.http.undertow.handler.identity.v1.SingleLookupHandler; import io.kamax.mxisd.http.undertow.handler.identity.v1.SingleLookupHandler;
import io.kamax.mxisd.http.undertow.handler.identity.v2.HashDetailsHandler; import io.kamax.mxisd.http.undertow.handler.identity.v2.HashDetailsHandler;
import io.kamax.mxisd.http.undertow.handler.identity.v2.HashLookupHandler; import io.kamax.mxisd.http.undertow.handler.identity.v2.HashLookupHandler;
import io.kamax.mxisd.http.undertow.handler.internal.InternalInviteManagerHandler;
import io.kamax.mxisd.http.undertow.handler.invite.v1.RoomInviteHandler; import io.kamax.mxisd.http.undertow.handler.invite.v1.RoomInviteHandler;
import io.kamax.mxisd.http.undertow.handler.profile.v1.InternalProfileHandler; import io.kamax.mxisd.http.undertow.handler.profile.v1.InternalProfileHandler;
import io.kamax.mxisd.http.undertow.handler.profile.v1.ProfileHandler; import io.kamax.mxisd.http.undertow.handler.profile.v1.ProfileHandler;
@@ -147,6 +148,11 @@ public class HttpMxisd {
termsEndpoints(handler); termsEndpoints(handler);
hashEndpoints(handler); hashEndpoints(handler);
accountEndpoints(handler); accountEndpoints(handler);
if (m.getConfig().getInternal().isEnabled()) {
handler.get(InternalInviteManagerHandler.PATH, new InternalInviteManagerHandler(m.getInvite()));
}
ServerConfig serverConfig = m.getConfig().getServer(); ServerConfig serverConfig = m.getConfig().getServer();
httpSrv = Undertow.builder().addHttpListener(serverConfig.getPort(), serverConfig.getHostname()).setHandler(handler).build(); httpSrv = Undertow.builder().addHttpListener(serverConfig.getPort(), serverConfig.getHostname()).setHandler(handler).build();

View File

@@ -55,7 +55,7 @@ import io.kamax.mxisd.registration.RegistrationManager;
import io.kamax.mxisd.session.SessionManager; import io.kamax.mxisd.session.SessionManager;
import io.kamax.mxisd.storage.IStorage; import io.kamax.mxisd.storage.IStorage;
import io.kamax.mxisd.storage.ormlite.OrmLiteSqlStorage; import io.kamax.mxisd.storage.ormlite.OrmLiteSqlStorage;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;

View File

@@ -36,7 +36,7 @@ public class MxisdStandaloneExec {
private static final Logger log = LoggerFactory.getLogger("App"); private static final Logger log = LoggerFactory.getLogger("App");
public static void main(String[] args) { public static void main(String[] args) {
String logLevel = System.getenv("MA1SD_LOG_LEVEL"); String logLevel = System.getenv("MXIDS_LOG_LEVEL");
if (StringUtils.isNotBlank(logLevel)) { if (StringUtils.isNotBlank(logLevel)) {
System.setProperty("org.slf4j.simpleLogger.log.io.kamax.mxisd", logLevel); System.setProperty("org.slf4j.simpleLogger.log.io.kamax.mxisd", logLevel);
} }
@@ -59,8 +59,8 @@ public class MxisdStandaloneExec {
System.out.println(" -c, --config Set the configuration file location"); System.out.println(" -c, --config Set the configuration file location");
System.out.println(" -v Increase log level (log more info)"); System.out.println(" -v Increase log level (log more info)");
System.out.println(" -vv Further increase log level"); System.out.println(" -vv Further increase log level");
System.out.println(" --dump Dump the full ma1sd configuration"); System.out.println(" --dump Dump the full mxids configuration");
System.out.println(" --dump-and-exit Dump the full ma1sd configuration and exit"); System.out.println(" --dump-and-exit Dump the full mxids configuration and exit");
System.out.println(" "); System.out.println(" ");
System.exit(0); System.exit(0);
return; return;
@@ -88,27 +88,28 @@ public class MxisdStandaloneExec {
} }
if (Objects.isNull(cfg)) { if (Objects.isNull(cfg)) {
cfg = YamlConfigLoader.tryLoadFromFile("ma1sd.yaml").orElseGet(MxisdConfig::new); cfg = YamlConfigLoader.tryLoadFromFile("mxids.yaml").orElseGet(MxisdConfig::new);
} }
if (dump) { if (dump) {
YamlConfigLoader.dumpConfig(cfg); String outputPath = "mxids.yaml";
YamlConfigLoader.dumpConfig(cfg, outputPath);
if (exit) { if (exit) {
System.exit(0); System.exit(0);
} }
} }
log.info("ma1sd starting"); log.info("mxids starting");
log.info("Version: {}", Mxisd.Version); log.info("Version: {}", Mxisd.Version);
HttpMxisd mxisd = new HttpMxisd(cfg); HttpMxisd mxisd = new HttpMxisd(cfg);
Runtime.getRuntime().addShutdownHook(new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> {
mxisd.stop(); mxisd.stop();
log.info("ma1sd stopped"); log.info("mxids stopped");
})); }));
mxisd.start(); mxisd.start();
log.info("ma1sd started"); log.info("mxids started");
} catch (ConfigurationException e) { } catch (ConfigurationException e) {
log.error(e.getDetailedMessage()); log.error(e.getDetailedMessage());
log.error(e.getMessage()); log.error(e.getMessage());

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd; package io.kamax.mxisd;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
// FIXME consider integrating in matrix-java-sdk? // FIXME consider integrating in matrix-java-sdk?
public enum UserIdType { public enum UserIdType {

View File

@@ -48,6 +48,7 @@ import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.introspector.BeanAccess; import org.yaml.snakeyaml.introspector.BeanAccess;
import org.yaml.snakeyaml.representer.Representer; import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.DumperOptions;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -142,18 +143,18 @@ public class AppSvcManager {
String synapseRegFile = cfg.getAppsvc().getRegistration().getSynapse().getFile(); String synapseRegFile = cfg.getAppsvc().getRegistration().getSynapse().getFile();
if (StringUtils.isBlank(synapseRegFile)) { if (StringUtils.isBlank(synapseRegFile)) {
log.info("No synapse registration file path given - skipping generation..."); log.info("No synapse registration file path given - skipping generation...");
return; return;
} }
SynapseRegistrationYaml syncCfg = SynapseRegistrationYaml.parse(cfg.getAppsvc(), cfg.getMatrix().getDomain()); SynapseRegistrationYaml syncCfg = SynapseRegistrationYaml.parse(cfg.getAppsvc(), cfg.getMatrix().getDomain());
Representer rep = new Representer(); DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); // Set YAML flow style to block
Representer rep = new Representer(options);
rep.getPropertyUtils().setBeanAccess(BeanAccess.FIELD); rep.getPropertyUtils().setBeanAccess(BeanAccess.FIELD);
Yaml yaml = new Yaml(rep); Yaml yaml = new Yaml(rep);
// SnakeYAML set the type of object on the first line, which can fail to be parsed on synapse
// We therefore need to split the resulting string, remove the first line, and then write it
List<String> lines = new ArrayList<>(Arrays.asList(yaml.dump(syncCfg).split("\\R+"))); List<String> lines = new ArrayList<>(Arrays.asList(yaml.dump(syncCfg).split("\\R+")));
if (StringUtils.equals(lines.get(0), "!!" + SynapseRegistrationYaml.class.getCanonicalName())) { if (StringUtils.equals(lines.get(0), "!!" + SynapseRegistrationYaml.class.getCanonicalName())) {
lines.remove(0); lines.remove(0);

View File

@@ -25,8 +25,8 @@ import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang.text.StrBuilder; import org.apache.commons.lang3.text.StrBuilder;
import java.util.List; import java.util.List;

View File

@@ -25,7 +25,7 @@ import io.kamax.matrix.hs._MatrixRoom;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.lang.text.StrBuilder; import org.apache.commons.lang3.text.StrBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Optional; import java.util.Optional;

View File

@@ -34,7 +34,7 @@ import io.kamax.mxisd.invitation.IMatrixIdInvite;
import io.kamax.mxisd.invitation.MatrixIdInvite; import io.kamax.mxisd.invitation.MatrixIdInvite;
import io.kamax.mxisd.notification.NotificationManager; import io.kamax.mxisd.notification.NotificationManager;
import io.kamax.mxisd.profile.ProfileManager; import io.kamax.mxisd.profile.ProfileManager;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -32,7 +32,7 @@ import io.kamax.mxisd.as.processor.command.InviteCommandProcessor;
import io.kamax.mxisd.as.processor.command.LookupCommandProcessor; import io.kamax.mxisd.as.processor.command.LookupCommandProcessor;
import io.kamax.mxisd.as.processor.command.PingCommandProcessor; import io.kamax.mxisd.as.processor.command.PingCommandProcessor;
import org.apache.commons.cli.*; import org.apache.commons.cli.*;
import org.apache.commons.lang.text.StrBuilder; import org.apache.commons.lang3.text.StrBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -45,7 +45,7 @@ import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.strategy.LookupStrategy; import io.kamax.mxisd.lookup.strategy.LookupStrategy;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;

View File

@@ -27,7 +27,7 @@ import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.profile.JsonProfileRequest; import io.kamax.mxisd.profile.JsonProfileRequest;
import io.kamax.mxisd.profile.JsonProfileResult; import io.kamax.mxisd.profile.JsonProfileResult;
import io.kamax.mxisd.profile.ProfileProvider; import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;

View File

@@ -1,168 +1,81 @@
/*
* mxisd - Matrix Identity Server Daemon
* 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.mxisd.backend.firebase; package io.kamax.mxisd.backend.firebase;
import com.google.firebase.auth.UserInfo; import com.google.firebase.auth.FirebaseAuth;
import com.google.i18n.phonenumbers.NumberParseException; import com.google.firebase.auth.FirebaseAuthException;
import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.firebase.auth.FirebaseToken;
import io.kamax.matrix.ThreePid; import com.google.firebase.auth.UserRecord;
import io.kamax.matrix.ThreePidMedium;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
import io.kamax.mxisd.config.FirebaseConfig; import io.kamax.mxisd.config.FirebaseConfig;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class GoogleFirebaseAuthenticator extends GoogleFirebaseBackend implements AuthenticatorProvider { public class GoogleFirebaseAuthenticator implements AuthenticatorProvider {
private transient final Logger log = LoggerFactory.getLogger(GoogleFirebaseAuthenticator.class); private static final Logger log = LoggerFactory.getLogger(GoogleFirebaseAuthenticator.class);
private static final ExecutorService executor = Executors.newCachedThreadPool(); // Consider using a fixed thread pool or other strategies based on your app's needs
private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); private FirebaseConfig config;
public GoogleFirebaseAuthenticator(FirebaseConfig cfg) { public GoogleFirebaseAuthenticator(FirebaseConfig config) {
this(cfg.isEnabled(), cfg.getCredentials(), cfg.getDatabase()); this.config = config;
} }
public GoogleFirebaseAuthenticator(boolean isEnabled, String credsPath, String db) { @Override
super(isEnabled, "AuthenticationProvider", credsPath, db); public boolean isEnabled() {
} return this.config.isEnabled();
private void waitOnLatch(BackendAuthResult result, CountDownLatch l, String purpose) {
try {
l.await(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.warn("Interrupted while waiting for " + purpose);
result.fail();
}
}
private void toEmail(BackendAuthResult result, String email) {
if (StringUtils.isBlank(email)) {
return;
}
result.withThreePid(new ThreePid(ThreePidMedium.Email.getId(), email));
}
private void toMsisdn(BackendAuthResult result, String phoneNumber) {
if (StringUtils.isBlank(phoneNumber)) {
return;
}
try {
String number = phoneUtil.format(
phoneUtil.parse(
phoneNumber,
null // No default region
),
PhoneNumberUtil.PhoneNumberFormat.E164
).substring(1); // We want without the leading +
result.withThreePid(new ThreePid(ThreePidMedium.PhoneNumber.getId(), number));
} catch (NumberParseException e) {
log.warn("Invalid phone number: {}", phoneNumber);
}
}
private void waitOnLatch(CountDownLatch l) {
try {
l.await(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.warn("Interrupted while waiting for Firebase auth check");
}
} }
@Override @Override
public BackendAuthResult authenticate(_MatrixID mxid, String password) { public BackendAuthResult authenticate(_MatrixID mxid, String password) {
if (!isEnabled()) { if (!isEnabled()) {
throw new IllegalStateException(); log.warn("Firebase authenticator is disabled.");
return BackendAuthResult.failure();
} }
log.info("Trying to authenticate {}", mxid); CompletableFuture<BackendAuthResult> resultFuture = new CompletableFuture<>();
executor.submit(() -> {
final BackendAuthResult result = BackendAuthResult.failure();
String localpart = mxid.getLocalPart();
CountDownLatch l = new CountDownLatch(1);
getFirebase().verifyIdToken(password).addOnSuccessListener(token -> {
try { try {
if (!StringUtils.equals(localpart, token.getUid())) { FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(password);
log.info("Failure to authenticate {}: Matrix ID localpart '{}' does not match Firebase UID '{}'", mxid, localpart, token.getUid()); if (!mxid.getLocalPart().equals(decodedToken.getUid())) {
result.fail(); log.warn("UID mismatch for user {}", mxid);
resultFuture.complete(BackendAuthResult.failure());
return; return;
} }
result.succeed(mxid.getId(), UserIdType.MatrixID.getId(), token.getName()); // Assuming you have a method to convert Firebase user info into BackendAuthResult
log.info("{} was successfully authenticated", mxid); resultFuture.complete(convertToAuthResult(decodedToken));
log.info("Fetching profile for {}", mxid); } catch (FirebaseAuthException e) {
CountDownLatch userRecordLatch = new CountDownLatch(1); log.error("Failed to authenticate user {}: {}", mxid, e.getMessage(), e);
getFirebase().getUser(token.getUid()).addOnSuccessListener(user -> { resultFuture.complete(BackendAuthResult.failure());
try {
toEmail(result, user.getEmail());
toMsisdn(result, user.getPhoneNumber());
for (UserInfo info : user.getProviderData()) {
toEmail(result, info.getEmail());
toMsisdn(result, info.getPhoneNumber());
}
log.info("Got {} 3PIDs in profile", result.getProfile().getThreePids().size());
} finally {
userRecordLatch.countDown();
}
}).addOnFailureListener(e -> {
try {
log.warn("Unable to fetch Firebase user profile for {}", mxid);
result.fail();
} finally {
userRecordLatch.countDown();
}
});
waitOnLatch(result, userRecordLatch, "Firebase user profile");
} finally {
l.countDown();
}
}).addOnFailureListener(e -> {
try {
if (e instanceof IllegalArgumentException) {
log.info("Failure to authenticate {}: invalid firebase token", mxid);
} else {
log.info("Failure to authenticate {}: {}", mxid, e.getMessage(), e);
log.info("Exception", e);
}
result.fail();
} finally {
l.countDown();
} }
}); });
waitOnLatch(result, l, "Firebase auth check"); try {
return result; return resultFuture.get(); // This will block, consider using thenAccept or similar for a truly non-blocking approach
} catch (Exception e) {
log.error("Error during authentication process", e);
return BackendAuthResult.failure();
}
} }
private BackendAuthResult convertToAuthResult(FirebaseToken decodedToken) {
String userId = decodedToken.getUid(); // UID from Firebase as the user ID
String userIdType = "MatrixID"; // Assuming you're using string literals for user ID types
String displayName = decodedToken.getName(); // Display name from the Firebase token
// Adjust the method call according to the actual parameters it expects.
// This example uses three strings directly.
return BackendAuthResult.success(userId, userIdType, displayName);
}
// Ensure resources are properly released when no longer needed
public static void shutdown() {
executor.shutdown();
}
} }

View File

@@ -1,90 +1,43 @@
/*
* mxisd - Matrix Identity Server Daemon
* 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.mxisd.backend.firebase; package io.kamax.mxisd.backend.firebase;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions; import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseCredential;
import com.google.firebase.auth.FirebaseCredentials;
import com.google.firebase.database.FirebaseDatabase;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
public class GoogleFirebaseBackend { public abstract class GoogleFirebaseBackend {
protected boolean enabled;
protected String backendName;
protected String credentialsPath;
protected String databaseUrl;
private transient final Logger log = LoggerFactory.getLogger(GoogleFirebaseBackend.class); public GoogleFirebaseBackend(boolean isEnabled, String backendName, String credsPath, String db) {
this.enabled = isEnabled;
private boolean isEnabled; this.backendName = backendName;
private FirebaseAuth fbAuth; this.credentialsPath = credsPath;
protected FirebaseDatabase fbDb; this.databaseUrl = db;
if (isEnabled) {
GoogleFirebaseBackend(boolean isEnabled, String name, String credsPath, String db) { try {
this.isEnabled = isEnabled; initializeFirebase();
if (!isEnabled) { } catch (IOException e) {
return; throw new RuntimeException("Failed to initialize Firebase", e);
}
try {
FirebaseApp fbApp = FirebaseApp.initializeApp(getOpts(credsPath, db), name);
fbAuth = FirebaseAuth.getInstance(fbApp);
FirebaseDatabase.getInstance(fbApp);
log.info("Google Firebase Authentication is ready");
} catch (IOException e) {
throw new RuntimeException("Error when initializing Firebase", e);
}
}
private FirebaseCredential getCreds(String credsPath) throws IOException {
if (StringUtils.isNotBlank(credsPath)) {
try (FileInputStream is = new FileInputStream(credsPath)) {
return FirebaseCredentials.fromCertificate(is);
} }
} else {
return FirebaseCredentials.applicationDefault();
} }
} }
private FirebaseOptions getOpts(String credsPath, String db) throws IOException { private void initializeFirebase() throws IOException {
if (StringUtils.isBlank(db)) { FileInputStream serviceAccount = new FileInputStream(credentialsPath);
throw new IllegalArgumentException("Firebase database is not configured");
}
return new FirebaseOptions.Builder() FirebaseOptions options = new FirebaseOptions.Builder()
.setCredential(getCreds(credsPath)) .setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl(db) .setDatabaseUrl(databaseUrl)
.build(); .build();
if (FirebaseApp.getApps().isEmpty()) { // Check if Firebase has been initialized already
FirebaseApp.initializeApp(options);
}
} }
FirebaseAuth getFirebase() { // Additional methods for GoogleFirebaseBackend
return fbAuth;
}
public boolean isEnabled() {
return isEnabled;
}
} }

View File

@@ -1,28 +1,5 @@
/*
* mxisd - Matrix Identity Server Daemon
* 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.mxisd.backend.firebase; package io.kamax.mxisd.backend.firebase;
import com.google.firebase.auth.UserRecord;
import com.google.firebase.tasks.OnFailureListener;
import com.google.firebase.tasks.OnSuccessListener;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.config.MxisdConfig;
@@ -36,25 +13,22 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class GoogleFirebaseProvider extends GoogleFirebaseBackend implements IThreePidProvider { public class GoogleFirebaseProvider extends GoogleFirebaseBackend implements IThreePidProvider {
private transient final Logger log = LoggerFactory.getLogger(GoogleFirebaseProvider.class); private final Logger log = LoggerFactory.getLogger(GoogleFirebaseProvider.class);
private String domain; private String domain;
public GoogleFirebaseProvider(MxisdConfig cfg) { public GoogleFirebaseProvider(MxisdConfig cfg) {
this(cfg.getFirebase().isEnabled(), cfg.getFirebase().getCredentials(), cfg.getFirebase().getDatabase(), cfg.getMatrix().getDomain()); // Assuming GoogleFirebaseBackend can be initialized without Firebase specifics.
super(cfg.getFirebase().isEnabled(), cfg.getFirebase().getCredentials(), cfg.getFirebase().getDatabase(), cfg.getMatrix().getDomain());
this.domain = cfg.getMatrix().getDomain();
} }
public GoogleFirebaseProvider(boolean isEnabled, String credsPath, String db, String domain) { private String getMxid(String uid) {
super(isEnabled, "ThreePidProvider", credsPath, db); // Mock UID to MXID conversion
this.domain = domain; return MatrixID.asAcceptable(uid, domain).getId();
}
private String getMxid(UserRecord record) {
return MatrixID.asAcceptable(record.getUid(), domain).getId();
} }
@Override @Override
@@ -67,71 +41,34 @@ public class GoogleFirebaseProvider extends GoogleFirebaseBackend implements ITh
return 25; return 25;
} }
private void waitOnLatch(CountDownLatch l) { private Optional<String> findInternal(String medium, String address) {
try { CompletableFuture<Optional<String>> future = new CompletableFuture<>();
l.await(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.warn("Interrupted while waiting for Firebase auth check");
}
}
private Optional<UserRecord> findInternal(String medium, String address) { // Directly complete with empty to simulate no user found
final UserRecord[] r = new UserRecord[1]; future.complete(Optional.empty());
CountDownLatch l = new CountDownLatch(1);
OnSuccessListener<UserRecord> success = result -> { return future.join(); // Using join to avoid handling InterruptedException
log.info("Found 3PID match for {}:{} - UID is {}", medium, address, result.getUid());
r[0] = result;
l.countDown();
};
OnFailureListener failure = e -> {
log.info("No 3PID match for {}:{} - {}", medium, address, e.getMessage());
r[0] = null;
l.countDown();
};
if (ThreePidMedium.Email.is(medium)) {
log.info("Performing E-mail 3PID lookup for {}", address);
getFirebase().getUserByEmail(address)
.addOnSuccessListener(success)
.addOnFailureListener(failure);
waitOnLatch(l);
} else if (ThreePidMedium.PhoneNumber.is(medium)) {
log.info("Performing msisdn 3PID lookup for {}", address);
getFirebase().getUserByPhoneNumber(address)
.addOnSuccessListener(success)
.addOnFailureListener(failure);
waitOnLatch(l);
} else {
log.info("{} is not a supported 3PID medium", medium);
r[0] = null;
}
return Optional.ofNullable(r[0]);
} }
@Override @Override
public Optional<SingleLookupReply> find(SingleLookupRequest request) { public Optional<SingleLookupReply> find(SingleLookupRequest request) {
Optional<UserRecord> urOpt = findInternal(request.getType(), request.getThreePid()); Optional<String> uidOpt = findInternal(request.getType(), request.getThreePid());
return urOpt.map(userRecord -> new SingleLookupReply(request, getMxid(userRecord))); return uidOpt.map(uid -> new SingleLookupReply(request, getMxid(uid)));
} }
@Override @Override
public List<ThreePidMapping> populate(List<ThreePidMapping> mappings) { public List<ThreePidMapping> populate(List<ThreePidMapping> mappings) {
List<ThreePidMapping> results = new ArrayList<>(); List<ThreePidMapping> results = new ArrayList<>();
mappings.parallelStream().forEach(o -> { mappings.forEach(o -> {
Optional<UserRecord> urOpt = findInternal(o.getMedium(), o.getValue()); Optional<String> uidOpt = findInternal(o.getMedium(), o.getValue());
if (urOpt.isPresent()) { uidOpt.ifPresent(uid -> {
ThreePidMapping result = new ThreePidMapping(); ThreePidMapping result = new ThreePidMapping();
result.setMedium(o.getMedium()); result.setMedium(o.getMedium());
result.setValue(o.getValue()); result.setValue(o.getValue());
result.setMxid(getMxid(urOpt.get())); result.setMxid(getMxid(uid));
results.add(result); results.add(result);
} });
}); });
return results; return results;
} }
} }

View File

@@ -32,7 +32,7 @@ import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.LdapConfig; import io.kamax.mxisd.config.ldap.LdapConfig;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.directory.api.ldap.model.cursor.CursorException; import org.apache.directory.api.ldap.model.cursor.CursorException;
import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException; import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
import org.apache.directory.api.ldap.model.cursor.EntryCursor; import org.apache.directory.api.ldap.model.cursor.EntryCursor;
@@ -54,6 +54,8 @@ public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvid
private transient final Logger log = LoggerFactory.getLogger(LdapAuthProvider.class); private transient final Logger log = LoggerFactory.getLogger(LdapAuthProvider.class);
public static final char[] CHARACTERS_TO_ESCAPE = ",#+<>;\"=*\\\\".toCharArray();
private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
public LdapAuthProvider(LdapConfig cfg, MatrixConfig mxCfg) { public LdapAuthProvider(LdapConfig cfg, MatrixConfig mxCfg) {
@@ -94,7 +96,8 @@ public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvid
return BackendAuthResult.failure(); return BackendAuthResult.failure();
} }
String userFilter = "(" + getUidAtt() + "=" + userFilterValue + ")"; String filteredValue = escape(userFilterValue);
String userFilter = "(" + getUidAtt() + "=" + filteredValue + ")";
userFilter = buildWithFilter(userFilter, getCfg().getAuth().getFilter()); userFilter = buildWithFilter(userFilter, getCfg().getAuth().getFilter());
Set<String> attributes = new HashSet<>(); Set<String> attributes = new HashSet<>();
@@ -167,4 +170,16 @@ public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvid
} }
} }
private String escape(String raw) {
StringBuilder sb = new StringBuilder();
boolean escape;
for (char c : raw.toCharArray()) {
escape = false;
for (int i = 0; i < CHARACTERS_TO_ESCAPE.length && !escape; i++) {
escape = CHARACTERS_TO_ESCAPE[i] == c;
}
sb.append(escape ? "\\" + c : c);
}
return sb.toString();
}
} }

View File

@@ -20,10 +20,11 @@
package io.kamax.mxisd.backend.ldap; package io.kamax.mxisd.backend.ldap;
import io.kamax.matrix.MatrixID;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.LdapConfig; import io.kamax.mxisd.config.ldap.LdapConfig;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.directory.api.ldap.model.entry.Attribute; import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.AttributeUtils; import org.apache.directory.api.ldap.model.entry.AttributeUtils;
import org.apache.directory.api.ldap.model.entry.Entry; import org.apache.directory.api.ldap.model.entry.Entry;
@@ -116,10 +117,20 @@ public abstract class LdapBackend {
public String buildMatrixIdFromUid(String uid) { public String buildMatrixIdFromUid(String uid) {
String uidType = getCfg().getAttribute().getUid().getType(); String uidType = getCfg().getAttribute().getUid().getType();
String localpart = uid.toLowerCase();
if (!StringUtils.equals(uid, localpart)) {
log.info("UID {} from LDAP has been changed to lowercase to match the Synapse specifications", uid);
}
if (StringUtils.equals(UID, uidType)) { if (StringUtils.equals(UID, uidType)) {
return "@" + uid + ":" + mxCfg.getDomain(); if(getCfg().isActiveDirectory()) {
localpart = new UPN(uid.toLowerCase()).getMXID();
}
return "@" + localpart + ":" + mxCfg.getDomain();
} else if (StringUtils.equals(MATRIX_ID, uidType)) { } else if (StringUtils.equals(MATRIX_ID, uidType)) {
return uid; return localpart;
} else { } else {
throw new IllegalArgumentException("Bind type " + uidType + " is not supported"); throw new IllegalArgumentException("Bind type " + uidType + " is not supported");
} }
@@ -128,6 +139,10 @@ public abstract class LdapBackend {
public String buildUidFromMatrixId(_MatrixID mxId) { public String buildUidFromMatrixId(_MatrixID mxId) {
String uidType = getCfg().getAttribute().getUid().getType(); String uidType = getCfg().getAttribute().getUid().getType();
if (StringUtils.equals(UID, uidType)) { if (StringUtils.equals(UID, uidType)) {
if(getCfg().isActiveDirectory()) {
return new UPN(mxId).getUPN();
}
return mxId.getLocalPart(); return mxId.getLocalPart();
} else if (StringUtils.equals(MATRIX_ID, uidType)) { } else if (StringUtils.equals(MATRIX_ID, uidType)) {
return mxId.getId(); return mxId.getId();
@@ -169,4 +184,58 @@ public abstract class LdapBackend {
return values; return values;
} }
private class UPN {
private String login;
private String domain;
public UPN(String userPrincipalName) {
String[] uidParts = userPrincipalName.split("@");
if (uidParts.length != 2) {
throw new IllegalArgumentException(String.format("Wrong userPrincipalName provided: %s", userPrincipalName));
}
this.login = uidParts[0];
this.domain = uidParts[1];
}
public UPN(_MatrixID mxid) {
String[] idParts = mxid.getLocalPart().split("/");
if (idParts.length != 2) {
if(idParts.length == 1 && !StringUtils.isEmpty(getCfg().getDefaultDomain())) {
throw new IllegalArgumentException(String.format(
"Local part of mxid %s does not contains domain separator and default domain is not configured",
mxid.getLocalPart()
));
}
this.domain = getCfg().getDefaultDomain();
} else {
this.domain = idParts[1];
}
this.login = idParts[0];
}
public String getLogin() {
return login;
}
public String getDomain() {
return domain;
}
public String getMXID() {
if(StringUtils.equalsIgnoreCase(getCfg().getDefaultDomain(), this.domain)) {
return this.login;
}
return new StringBuilder(this.login).append("/").append(this.domain).toString();
}
public String getUPN() {
return new StringBuilder(this.login).append("@").append(this.domain).toString();
}
}
} }

View File

@@ -38,7 +38,7 @@ import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider; import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import io.kamax.mxisd.profile.ProfileProvider; import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -27,7 +27,7 @@ import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider; import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -28,7 +28,7 @@ import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig;
import io.kamax.mxisd.directory.DirectoryProvider; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.http.io.UserDirectorySearchResult; import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.backend.sql.synapse; package io.kamax.mxisd.backend.sql.synapse;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
public class SynapseQueries { public class SynapseQueries {
@@ -51,7 +51,7 @@ public class SynapseQueries {
if (StringUtils.equals("sqlite", type)) { if (StringUtils.equals("sqlite", type)) {
return "select " + getUserId(type, domain) + ", displayname from profiles p where displayname like ?"; return "select " + getUserId(type, domain) + ", displayname from profiles p where displayname like ?";
} else if (StringUtils.equals("postgresql", type)) { } else if (StringUtils.equals("postgresql", type)) {
return "select " + getUserId(type, domain) + ", displayname from profiles p where displayname ilike ?"; return "SELECT u.name,p.displayname FROM users u JOIN profiles p ON u.name LIKE concat('@',p.user_id,':%') WHERE u.is_guest = 0 AND u.appservice_id IS NULL AND p.displayname LIKE ?";
} else { } else {
throw new ConfigurationException("Invalid Synapse SQL type: " + type); throw new ConfigurationException("Invalid Synapse SQL type: " + type);
} }

View File

@@ -25,7 +25,7 @@ import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -25,7 +25,7 @@ import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.InvalidJsonException; import io.kamax.matrix.json.InvalidJsonException;
import io.kamax.mxisd.config.wordpress.WordpressConfig; import io.kamax.mxisd.config.wordpress.WordpressConfig;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;

View File

@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public class HashingConfig { public class HashingConfig {
@@ -13,7 +14,7 @@ public class HashingConfig {
private boolean enabled = false; private boolean enabled = false;
private int pepperLength = 20; private int pepperLength = 20;
private RotationPolicyEnum rotationPolicy; private RotationPolicyEnum rotationPolicy;
private HashStorageEnum hashStorageType; private HashStorageEnum hashStorageType = HashStorageEnum.in_memory;
private String delay = "10s"; private String delay = "10s";
private transient long delayInSeconds = 10; private transient long delayInSeconds = 10;
private int requests = 10; private int requests = 10;
@@ -25,6 +26,7 @@ public class HashingConfig {
LOGGER.info(" Pepper length: {}", getPepperLength()); LOGGER.info(" Pepper length: {}", getPepperLength());
LOGGER.info(" Rotation policy: {}", getRotationPolicy()); LOGGER.info(" Rotation policy: {}", getRotationPolicy());
LOGGER.info(" Hash storage type: {}", getHashStorageType()); LOGGER.info(" Hash storage type: {}", getHashStorageType());
Objects.requireNonNull(getHashStorageType(), "Storage type must be specified");
if (RotationPolicyEnum.per_seconds == getRotationPolicy()) { if (RotationPolicyEnum.per_seconds == getRotationPolicy()) {
setDelayInSeconds(new DurationDeserializer().deserialize(getDelay())); setDelayInSeconds(new DurationDeserializer().deserialize(getDelay()));
LOGGER.info(" Rotation delay: {}", getDelay()); LOGGER.info(" Rotation delay: {}", getDelay());

View File

@@ -0,0 +1,24 @@
package io.kamax.mxisd.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InternalAPIConfig {
private final static Logger log = LoggerFactory.getLogger(InternalAPIConfig.class);
private boolean enabled = false;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void build() {
log.info("--- Internal API config ---");
log.info("Internal API enabled: {}", isEnabled());
}
}

View File

@@ -67,6 +67,7 @@ public class InvitationConfig {
private boolean recursive = true; private boolean recursive = true;
private long timer = 5; private long timer = 5;
private PeriodDimension period = PeriodDimension.minutes;
public boolean isRecursive() { public boolean isRecursive() {
return recursive; return recursive;
@@ -84,6 +85,13 @@ public class InvitationConfig {
this.timer = timer; this.timer = timer;
} }
public PeriodDimension getPeriod() {
return period;
}
public void setPeriod(PeriodDimension period) {
this.period = period;
}
} }
public static class SenderPolicy { public static class SenderPolicy {
@@ -115,6 +123,7 @@ public class InvitationConfig {
private Expiration expiration = new Expiration(); private Expiration expiration = new Expiration();
private Resolution resolution = new Resolution(); private Resolution resolution = new Resolution();
private Policies policy = new Policies(); private Policies policy = new Policies();
private boolean fullDisplayName = false;
public Expiration getExpiration() { public Expiration getExpiration() {
return expiration; return expiration;
@@ -140,11 +149,26 @@ public class InvitationConfig {
this.policy = policy; this.policy = policy;
} }
public boolean isFullDisplayName() {
return fullDisplayName;
}
public void setFullDisplayName(boolean fullDisplayName) {
this.fullDisplayName = fullDisplayName;
}
public void build() { public void build() {
log.info("--- Invite config ---"); log.info("--- Invite config ---");
log.info("Expiration: {}", GsonUtil.get().toJson(getExpiration())); log.info("Expiration: {}", GsonUtil.get().toJson(getExpiration()));
log.info("Resolution: {}", GsonUtil.get().toJson(getResolution())); log.info("Resolution: {}", GsonUtil.get().toJson(getResolution()));
log.info("Policies: {}", GsonUtil.get().toJson(getPolicy())); log.info("Policies: {}", GsonUtil.get().toJson(getPolicy()));
log.info("Print full display name on invitation: {}", isFullDisplayName());
} }
public enum PeriodDimension {
minutes,
seconds
}
} }

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
public class KeyConfig { public class KeyConfig {

View File

@@ -22,7 +22,7 @@ package io.kamax.mxisd.config;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -29,7 +29,7 @@ import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig;
import io.kamax.mxisd.config.threepid.ThreePidConfig; import io.kamax.mxisd.config.threepid.ThreePidConfig;
import io.kamax.mxisd.config.threepid.notification.NotificationConfig; import io.kamax.mxisd.config.threepid.notification.NotificationConfig;
import io.kamax.mxisd.config.wordpress.WordpressConfig; import io.kamax.mxisd.config.wordpress.WordpressConfig;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -118,6 +118,7 @@ public class MxisdConfig {
private PolicyConfig policy = new PolicyConfig(); private PolicyConfig policy = new PolicyConfig();
private HashingConfig hashing = new HashingConfig(); private HashingConfig hashing = new HashingConfig();
private LoggingConfig logging = new LoggingConfig(); private LoggingConfig logging = new LoggingConfig();
private InternalAPIConfig internal = new InternalAPIConfig();
public AppServiceConfig getAppsvc() { public AppServiceConfig getAppsvc() {
return appsvc; return appsvc;
@@ -358,6 +359,14 @@ public class MxisdConfig {
return this; return this;
} }
public InternalAPIConfig getInternal() {
return internal;
}
public void setInternal(InternalAPIConfig internal) {
this.internal = internal;
}
public MxisdConfig build() { public MxisdConfig build() {
getLogging().build(); getLogging().build();
@@ -394,6 +403,7 @@ public class MxisdConfig {
getWordpress().build(); getWordpress().build();
getPolicy().build(); getPolicy().build();
getHashing().build(getMatrix()); getHashing().build(getMatrix());
getInternal().build();
return this; return this;
} }

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -1,89 +1,57 @@
/*
* mxisd - Matrix Identity Server Daemon
* 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.mxisd.config; package io.kamax.mxisd.config;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.exception.ConfigurationException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.introspector.BeanAccess; import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.File;
import java.util.Optional; import java.util.Optional;
public class YamlConfigLoader { public class YamlConfigLoader {
private static final Logger log = LoggerFactory.getLogger(YamlConfigLoader.class); private static final Logger log = LoggerFactory.getLogger(YamlConfigLoader.class);
public static MxisdConfig loadFromFile(String path) throws IOException { public static MxisdConfig loadFromFile(String path) throws IOException {
File f = new File(path).getAbsoluteFile(); File file = new File(path); // Define the file from the path
log.info("Reading config from {}", f.toString()); Constructor constructor = new Constructor(MxisdConfig.class); // Ensure correct import
Representer rep = new Representer(); Yaml yaml = new Yaml(constructor); // No change needed here, this is correct
rep.getPropertyUtils().setBeanAccess(BeanAccess.FIELD);
rep.getPropertyUtils().setAllowReadOnlyProperties(true);
rep.getPropertyUtils().setSkipMissingProperties(true);
Yaml yaml = new Yaml(new Constructor(MxisdConfig.class), rep);
try (FileInputStream is = new FileInputStream(f)) {
MxisdConfig raw = yaml.load(is);
log.debug("Read config in memory from {}", path);
// SnakeYaml set objects to null when there is no value set in the config, even a full sub-tree. // Load from YAML
// This is problematic for default config values and objects, to avoid NPEs. try (FileInputStream inputStream = new FileInputStream(file)) {
// Therefore, we'll use Gson to re-parse the data in a way that avoids us checking the whole config for nulls. return yaml.loadAs(inputStream, MxisdConfig.class);
MxisdConfig cfg = GsonUtil.get().fromJson(GsonUtil.get().toJson(raw), MxisdConfig.class); } catch (IOException e) {
// Handle exceptions
log.info("Loaded config from {}", path); throw e;
return cfg; }
} catch (ParserException t) { }
throw new ConfigurationException(t.getMessage(), "Could not parse YAML config file - Please check indentation and that the configuration options exist");
} public static Optional<MxisdConfig> tryLoadFromFile(String path) {
} try {
return Optional.of(loadFromFile(path));
public static Optional<MxisdConfig> tryLoadFromFile(String path) { } catch (IOException e) {
log.debug("Attempting to read config from {}", path); log.warn("Unable to load configuration file from path {}: {}", path, e.getMessage());
try { return Optional.empty();
return Optional.of(loadFromFile(path)); }
} catch (FileNotFoundException e) { }
log.info("No config file at {}", path);
return Optional.empty(); public static void dumpConfig(MxisdConfig cfg, String outputPath) throws IOException {
} catch (IOException e) { // Initialize LoaderOptions for dumping if needed
throw new RuntimeException(e); LoaderOptions loaderOptions = new LoaderOptions();
} // Customize loaderOptions as necessary
}
Yaml yaml = new Yaml(loaderOptions);
public static void dumpConfig(MxisdConfig cfg) {
Representer rep = new Representer(); try (FileWriter writer = new FileWriter(new File(outputPath))) {
rep.getPropertyUtils().setBeanAccess(BeanAccess.FIELD); yaml.dump(cfg, writer);
rep.getPropertyUtils().setAllowReadOnlyProperties(true); log.info("Configuration dumped successfully to {}", outputPath);
rep.getPropertyUtils().setSkipMissingProperties(true); } catch (IOException e) {
log.error("Failed to dump YAML configuration to path: {}", outputPath, e);
Yaml yaml = new Yaml(new Constructor(MxisdConfig.class), rep); throw e;
String dump = yaml.dump(cfg); }
log.info("Full configuration:\n{}", dump);
} }
} }

View File

@@ -24,7 +24,7 @@ import io.kamax.matrix.ThreePidMedium;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.backend.ldap.LdapBackend; import io.kamax.mxisd.backend.ldap.LdapBackend;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -291,6 +291,9 @@ public abstract class LdapConfig {
private boolean enabled; private boolean enabled;
private String filter; private String filter;
private boolean activeDirectory;
private String defaultDomain;
private Connection connection = new Connection(); private Connection connection = new Connection();
private Attribute attribute = new Attribute(); private Attribute attribute = new Attribute();
private Auth auth = new Auth(); private Auth auth = new Auth();
@@ -316,6 +319,22 @@ public abstract class LdapConfig {
this.filter = filter; this.filter = filter;
} }
public boolean isActiveDirectory() {
return activeDirectory;
}
public void setActiveDirectory(boolean activeDirectory) {
this.activeDirectory = activeDirectory;
}
public String getDefaultDomain() {
return defaultDomain;
}
public void setDefaultDomain(String defaultDomain) {
this.defaultDomain = defaultDomain;
}
public Connection getConnection() { public Connection getConnection() {
return connection; return connection;
} }
@@ -407,6 +426,15 @@ public abstract class LdapConfig {
throw new ConfigurationException("ldap.identity.token"); throw new ConfigurationException("ldap.identity.token");
} }
if(isActiveDirectory()) {
if(!StringUtils.equals(LdapBackend.UID, uidType)) {
throw new IllegalArgumentException(String.format(
"Attribute UID type should be set to %s in Active Directory mode",
LdapBackend.UID
));
}
}
// Build queries // Build queries
attribute.getThreepid().forEach((k, v) -> { attribute.getThreepid().forEach((k, v) -> {
if (StringUtils.isBlank(identity.getMedium().get(k))) { if (StringUtils.isBlank(identity.getMedium().get(k))) {

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.config.rest; package io.kamax.mxisd.config.rest;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -33,8 +33,8 @@ public class RestBackendConfig {
public static class IdentityEndpoints { public static class IdentityEndpoints {
private String single = "/_ma1sd/backend/api/v1/identity/single"; private String single = "/_mxids/backend/api/v1/identity/single";
private String bulk = "/_ma1sd/backend/api/v1/identity/bulk"; private String bulk = "/_mxids/backend/api/v1/identity/bulk";
public String getSingle() { public String getSingle() {
return single; return single;
@@ -56,9 +56,9 @@ public class RestBackendConfig {
public static class ProfileEndpoints { public static class ProfileEndpoints {
private String displayName = "/_ma1sd/backend/api/v1/profile/displayName"; private String displayName = "/_mxids/backend/api/v1/profile/displayName";
private String threepids = "/_ma1sd/backend/api/v1/profile/threepids"; private String threepids = "/_mxids/backend/api/v1/profile/threepids";
private String roles = "/_ma1sd/backend/api/v1/profile/roles"; private String roles = "/_mxids/backend/api/v1/profile/roles";
public String getDisplayName() { public String getDisplayName() {
return displayName; return displayName;
@@ -88,8 +88,8 @@ public class RestBackendConfig {
public static class Endpoints { public static class Endpoints {
private String auth = "/_ma1sd/backend/api/v1/auth/login"; private String auth = "/_mxids/backend/api/v1/auth/login";
private String directory = "/_ma1sd/backend/api/v1/directory/user/search"; private String directory = "/_mxids/backend/api/v1/directory/user/search";
private IdentityEndpoints identity = new IdentityEndpoints(); private IdentityEndpoints identity = new IdentityEndpoints();
private ProfileEndpoints profile = new ProfileEndpoints(); private ProfileEndpoints profile = new ProfileEndpoints();

View File

@@ -23,7 +23,7 @@ package io.kamax.mxisd.config.sql.synapse;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.backend.sql.synapse.SynapseQueries; import io.kamax.mxisd.backend.sql.synapse.SynapseQueries;
import io.kamax.mxisd.config.sql.SqlConfig; import io.kamax.mxisd.config.sql.SqlConfig;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.config.threepid.connector; package io.kamax.mxisd.config.threepid.connector;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.config.threepid.connector; package io.kamax.mxisd.config.threepid.connector;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.config.threepid.medium; package io.kamax.mxisd.config.threepid.medium;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.config.wordpress; package io.kamax.mxisd.config.wordpress;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@@ -31,7 +31,7 @@ import io.kamax.mxisd.http.io.UserDirectorySearchRequest;
import io.kamax.mxisd.http.io.UserDirectorySearchResult; import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;

View File

@@ -23,5 +23,6 @@ package io.kamax.mxisd.exception;
public class InvalidParamException extends RuntimeException { public class InvalidParamException extends RuntimeException {
public InvalidParamException() { public InvalidParamException() {
super("The chosen hash algorithm is invalid or disallowed");
} }
} }

View File

@@ -23,5 +23,6 @@ package io.kamax.mxisd.exception;
public class InvalidPepperException extends RuntimeException { public class InvalidPepperException extends RuntimeException {
public InvalidPepperException() { public InvalidPepperException() {
super("The provided pepper is invalid or expired");
} }
} }

View File

@@ -0,0 +1,28 @@
/*
* mxids - Matrix Identity Server Daemon
* Copyright (C) 2020 Anatoliy SAblin
*
* https://git.cqre.net/cqrenet/mxids/
*
* 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.mxisd.exception;
public class TermsNotSignedException extends RuntimeException {
public TermsNotSignedException() {
super("Please accept our updated terms of service before continuing");
}
}

View File

@@ -20,11 +20,19 @@
package io.kamax.mxisd.http; package io.kamax.mxisd.http;
import static io.kamax.mxisd.util.RestClientUtils.urlEncode;
public class IsAPIv1 { public class IsAPIv1 {
public static final String Base = "/_matrix/identity/api/v1"; public static final String Base = "/_matrix/identity/api/v1";
public static String getValidate(String medium, String sid, String secret, String token) { public static String getValidate(String medium, String sid, String secret, String token) {
return String.format("%s/validate/%s/submitToken?sid=%s&client_secret=%s&token=%s", Base, medium, sid, secret, token); return String.format("%s/validate/%s/submitToken?sid=%s&client_secret=%s&token=%s",
Base,
medium,
urlEncode(sid),
urlEncode(secret),
urlEncode(token)
);
} }
} }

View File

@@ -33,6 +33,7 @@ import io.kamax.mxisd.util.RestClientUtils;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.form.FormData; import io.undertow.server.handlers.form.FormData;
import io.undertow.util.Headers;
import io.undertow.util.HttpString; import io.undertow.util.HttpString;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -189,7 +190,7 @@ public abstract class BasicHttpHandler implements HttpHandler {
} }
protected void respond(HttpServerExchange ex, int status, String errCode, String error) { protected void respond(HttpServerExchange ex, int status, String errCode, String error) {
respond(ex, status, buildErrorBody(ex, errCode, error)); respond(ex, status, buildErrorBody(ex, errCode, error != null ? error : "An error has occurred"));
} }
protected void handleException(HttpServerExchange exchange, HttpMatrixException ex) { protected void handleException(HttpServerExchange exchange, HttpMatrixException ex) {
@@ -203,26 +204,34 @@ public abstract class BasicHttpHandler implements HttpHandler {
} }
protected void proxyPost(HttpServerExchange exchange, JsonObject body, CloseableHttpClient client, ClientDnsOverwrite dns) { protected void proxyPost(HttpServerExchange exchange, JsonObject body, CloseableHttpClient client, ClientDnsOverwrite dns) {
proxyPost(exchange, body, client, dns, false);
}
protected void proxyPost(HttpServerExchange exchange, JsonObject body, CloseableHttpClient client, ClientDnsOverwrite dns,
boolean defaultJsonResponse) {
String target = dns.transform(URI.create(exchange.getRequestURL())).toString(); String target = dns.transform(URI.create(exchange.getRequestURL())).toString();
log.info("Requesting remote: {}", target); log.info("Requesting remote: {}", target);
HttpPost req = RestClientUtils.post(target, GsonUtil.get(), body); HttpPost req = RestClientUtils.post(target, GsonUtil.get(), body);
exchange.getRequestHeaders().forEach(header -> { exchange.getRequestHeaders().forEach(header -> header.forEach(v -> {
header.forEach(v -> { String name = header.getHeaderName().toString();
String name = header.getHeaderName().toString(); if (!StringUtils.startsWithIgnoreCase(name, "content-")) {
if (!StringUtils.startsWithIgnoreCase(name, "content-")) { req.addHeader(name, v);
req.addHeader(name, v); }
} }));
});
});
boolean missingJsonResponse = true;
try (CloseableHttpResponse res = client.execute(req)) { try (CloseableHttpResponse res = client.execute(req)) {
exchange.setStatusCode(res.getStatusLine().getStatusCode()); exchange.setStatusCode(res.getStatusLine().getStatusCode());
for (Header h : res.getAllHeaders()) { for (Header h : res.getAllHeaders()) {
for (HeaderElement el : h.getElements()) { for (HeaderElement el : h.getElements()) {
missingJsonResponse = !Headers.CONTENT_TYPE_STRING.equalsIgnoreCase(h.getName());
exchange.getResponseHeaders().add(HttpString.tryFromString(h.getName()), el.getValue()); exchange.getResponseHeaders().add(HttpString.tryFromString(h.getName()), el.getValue());
} }
} }
if (defaultJsonResponse && missingJsonResponse) {
exchange.getRequestHeaders().add(Headers.CONTENT_TYPE, "application/json");
}
res.getEntity().writeTo(exchange.getOutputStream()); res.getEntity().writeTo(exchange.getOutputStream());
exchange.endExchange(); exchange.endExchange();
} catch (IOException e) { } catch (IOException e) {

View File

@@ -23,6 +23,7 @@ package io.kamax.mxisd.http.undertow.handler;
import io.kamax.mxisd.auth.AccountManager; import io.kamax.mxisd.auth.AccountManager;
import io.kamax.mxisd.config.PolicyConfig; import io.kamax.mxisd.config.PolicyConfig;
import io.kamax.mxisd.exception.InvalidCredentialsException; import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.exception.TermsNotSignedException;
import io.undertow.server.HttpHandler; import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -66,7 +67,7 @@ public class CheckTermsHandler extends BasicHttpHandler {
if (!accountManager.isTermAccepted(token, policies)) { if (!accountManager.isTermAccepted(token, policies)) {
log.error("Non accepting request from: {}", exchange.getHostAndPort()); log.error("Non accepting request from: {}", exchange.getHostAndPort());
throw new InvalidCredentialsException(); throw new TermsNotSignedException();
} }
log.trace("Access granted"); log.trace("Access granted");
child.handleRequest(exchange); child.handleRequest(exchange);

View File

@@ -82,7 +82,10 @@ public class SaneHandler extends BasicHttpHandler {
} catch (InvalidJsonException e) { } catch (InvalidJsonException e) {
respond(exchange, HttpStatus.SC_BAD_REQUEST, e.getErrorCode(), e.getError()); respond(exchange, HttpStatus.SC_BAD_REQUEST, e.getErrorCode(), e.getError());
} catch (InvalidCredentialsException e) { } catch (InvalidCredentialsException e) {
log.error("Unauthorized: ", e);
respond(exchange, HttpStatus.SC_UNAUTHORIZED, "M_UNAUTHORIZED", e.getMessage()); respond(exchange, HttpStatus.SC_UNAUTHORIZED, "M_UNAUTHORIZED", e.getMessage());
} catch (TermsNotSignedException e) {
respond(exchange, HttpStatus.SC_FORBIDDEN, "M_TERMS_NOT_SIGNED", e.getMessage());
} catch (ObjectNotFoundException e) { } catch (ObjectNotFoundException e) {
respond(exchange, HttpStatus.SC_NOT_FOUND, "M_NOT_FOUND", e.getMessage()); respond(exchange, HttpStatus.SC_NOT_FOUND, "M_NOT_FOUND", e.getMessage());
} catch (NotImplementedException e) { } catch (NotImplementedException e) {

View File

@@ -29,10 +29,7 @@ import java.util.Optional;
public abstract class ApplicationServiceHandler extends BasicHttpHandler { public abstract class ApplicationServiceHandler extends BasicHttpHandler {
protected String getToken(HttpServerExchange ex) { protected String getToken(HttpServerExchange ex) {
return Optional.ofNullable(ex.getQueryParameters() return getAccessToken(ex);
.getOrDefault("access_token", new LinkedList<>())
.peekFirst()
).orElse("");
} }
} }

View File

@@ -24,6 +24,6 @@ import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
public abstract class LoginHandler extends BasicHttpHandler { public abstract class LoginHandler extends BasicHttpHandler {
public static final String Path = "/_matrix/client/r0/login"; public static final String Path = "/_matrix/client/v3/login";
} }

View File

@@ -31,7 +31,7 @@ import java.net.URI;
public class UserDirectorySearchHandler extends HomeserverProxyHandler { public class UserDirectorySearchHandler extends HomeserverProxyHandler {
public static final String Path = "/_matrix/client/r0/user_directory/search"; public static final String Path = "/_matrix/client/v3/user_directory/search";
private DirectoryManager mgr; private DirectoryManager mgr;

View File

@@ -23,7 +23,7 @@ package io.kamax.mxisd.http.undertow.handler.identity.share;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler; import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.kamax.mxisd.lookup.ALookupRequest; import io.kamax.mxisd.lookup.ALookupRequest;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -33,7 +33,7 @@ import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.session.SessionManager; import io.kamax.mxisd.session.SessionManager;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import io.undertow.util.QueryParameterUtils; import io.undertow.util.QueryParameterUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -0,0 +1,30 @@
package io.kamax.mxisd.http.undertow.handler.internal;
import com.google.gson.JsonObject;
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
import io.kamax.mxisd.invitation.InvitationManager;
import io.undertow.server.HttpServerExchange;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InternalInviteManagerHandler extends BasicHttpHandler {
public static final String PATH = "/_mxids/internal/admin/inv_manager";
private final InvitationManager invitationManager;
private final ExecutorService executors = Executors.newFixedThreadPool(1);
public InternalInviteManagerHandler(InvitationManager invitationManager) {
this.invitationManager = invitationManager;
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
executors.submit(invitationManager::doMaintenance);
JsonObject obj = new JsonObject();
obj.addProperty("result", "ok");
respond(exchange, obj);
}
}

View File

@@ -44,7 +44,7 @@ import java.util.Optional;
public class RoomInviteHandler extends BasicHttpHandler { public class RoomInviteHandler extends BasicHttpHandler {
public static final String Path = "/_matrix/client/r0/rooms/{roomId}/invite"; public static final String Path = "/_matrix/client/v3/rooms/{roomId}/invite";
private static final Logger log = LoggerFactory.getLogger(RoomInviteHandler.class); private static final Logger log = LoggerFactory.getLogger(RoomInviteHandler.class);
@@ -62,7 +62,7 @@ public class RoomInviteHandler extends BasicHttpHandler {
public void handleRequest(HttpServerExchange exchange) { public void handleRequest(HttpServerExchange exchange) {
String accessToken = getAccessToken(exchange); String accessToken = getAccessToken(exchange);
String whoamiUri = dns.transform(URI.create(exchange.getRequestURL()).resolve(URI.create("/_matrix/client/r0/account/whoami"))).toString(); String whoamiUri = dns.transform(URI.create(exchange.getRequestURL()).resolve(URI.create("/_matrix/client/v3/account/whoami"))).toString();
log.info("Who Am I URL: {}", whoamiUri); log.info("Who Am I URL: {}", whoamiUri);
HttpGet whoAmIReq = new HttpGet(whoamiUri); HttpGet whoAmIReq = new HttpGet(whoamiUri);
whoAmIReq.addHeader("Authorization", "Bearer " + accessToken); whoAmIReq.addHeader("Authorization", "Bearer " + accessToken);

View File

@@ -34,7 +34,7 @@ import java.util.Optional;
public class ProfileHandler extends HomeserverProxyHandler { public class ProfileHandler extends HomeserverProxyHandler {
public static final String UserID = "userId"; public static final String UserID = "userId";
public static final String Path = "/_matrix/client/r0/profile/{" + UserID + "}"; public static final String Path = "/_matrix/client/v3/profile/{" + UserID + "}";
protected ProfileManager mgr; protected ProfileManager mgr;

View File

@@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory;
public class Register3pidRequestTokenHandler extends BasicHttpHandler { public class Register3pidRequestTokenHandler extends BasicHttpHandler {
public static final String Key = "medium"; public static final String Key = "medium";
public static final String Path = "/_matrix/client/r0/register/{" + Key + "}/requestToken"; public static final String Path = "/_matrix/client/v3/register/{" + Key + "}/requestToken";
private static final Logger log = LoggerFactory.getLogger(Register3pidRequestTokenHandler.class); private static final Logger log = LoggerFactory.getLogger(Register3pidRequestTokenHandler.class);
@@ -71,7 +71,7 @@ public class Register3pidRequestTokenHandler extends BasicHttpHandler {
throw new NotAllowedException("Your " + medium + " address cannot be used for registration"); throw new NotAllowedException("Your " + medium + " address cannot be used for registration");
} }
proxyPost(exchange, body, client, dns); proxyPost(exchange, body, client, dns, true);
} }
} }

View File

@@ -99,14 +99,14 @@ public class InvitationManager {
private Map<String, IThreePidInviteReply> invitations = new ConcurrentHashMap<>(); private Map<String, IThreePidInviteReply> invitations = new ConcurrentHashMap<>();
public InvitationManager( public InvitationManager(
MxisdConfig mxisdCfg, MxisdConfig mxisdCfg,
IStorage storage, IStorage storage,
LookupStrategy lookupMgr, LookupStrategy lookupMgr,
KeyManager keyMgr, KeyManager keyMgr,
SignatureManager signMgr, SignatureManager signMgr,
HomeserverFederationResolver resolver, HomeserverFederationResolver resolver,
NotificationManager notifMgr, NotificationManager notifMgr,
ProfileManager profileMgr ProfileManager profileMgr
) { ) {
this.cfg = requireValid(mxisdCfg); this.cfg = requireValid(mxisdCfg);
this.srvCfg = mxisdCfg.getServer(); this.srvCfg = mxisdCfg.getServer();
@@ -124,11 +124,11 @@ public class InvitationManager {
io.getProperties().putIfAbsent(CreatedAtPropertyKey, defaultCreateTs); io.getProperties().putIfAbsent(CreatedAtPropertyKey, defaultCreateTs);
log.debug("Processing invite {}", GsonUtil.get().toJson(io)); log.debug("Processing invite {}", GsonUtil.get().toJson(io));
ThreePidInvite invite = new ThreePidInvite( ThreePidInvite invite = new ThreePidInvite(
MatrixID.asAcceptable(io.getSender()), MatrixID.asAcceptable(io.getSender()),
io.getMedium(), io.getMedium(),
io.getAddress(), io.getAddress(),
io.getRoomId(), io.getRoomId(),
io.getProperties() io.getProperties()
); );
ThreePidInviteReply reply = new ThreePidInviteReply(io.getId(), invite, io.getToken(), "", Collections.emptyList()); ThreePidInviteReply reply = new ThreePidInviteReply(io.getId(), invite, io.getToken(), "", Collections.emptyList());
@@ -155,7 +155,17 @@ public class InvitationManager {
log.error("Error when running background maintenance", t); log.error("Error when running background maintenance", t);
} }
} }
}, 5000L, TimeUnit.MILLISECONDS.convert(cfg.getResolution().getTimer(), TimeUnit.MINUTES)); }, 5000L, TimeUnit.MILLISECONDS.convert(cfg.getResolution().getTimer(), getTimeUnit()));
}
private TimeUnit getTimeUnit() {
switch (cfg.getResolution().getPeriod()) {
case seconds:
return TimeUnit.SECONDS;
case minutes:
default:
return TimeUnit.MINUTES;
}
} }
private InvitationConfig requireValid(MxisdConfig cfg) { private InvitationConfig requireValid(MxisdConfig cfg) {
@@ -176,7 +186,8 @@ public class InvitationManager {
if (StringUtils.isBlank(cfg.getInvite().getExpiration().getResolveTo())) { if (StringUtils.isBlank(cfg.getInvite().getExpiration().getResolveTo())) {
String localpart = cfg.getAppsvc().getUser().getInviteExpired(); String localpart = cfg.getAppsvc().getUser().getInviteExpired();
if (StringUtils.isBlank(localpart)) { if (StringUtils.isBlank(localpart)) {
throw new ConfigurationException("Could not compute the Invitation expiration resolution target from App service user: not set"); throw new ConfigurationException(
"Could not compute the Invitation expiration resolution target from App service user: not set");
} }
cfg.getInvite().getExpiration().setResolveTo(MatrixID.asAcceptable(localpart, cfg.getMatrix().getDomain()).getId()); cfg.getInvite().getExpiration().setResolveTo(MatrixID.asAcceptable(localpart, cfg.getMatrix().getDomain()).getId());
@@ -198,7 +209,8 @@ public class InvitationManager {
} }
private String getIdForLog(IThreePidInviteReply reply) { private String getIdForLog(IThreePidInviteReply reply) {
return reply.getInvite().getSender().getId() + ":" + reply.getInvite().getRoomId() + ":" + reply.getInvite().getMedium() + ":" + reply.getInvite().getAddress(); return reply.getInvite().getSender().getId() + ":" + reply.getInvite().getRoomId() + ":" + reply.getInvite()
.getMedium() + ":" + reply.getInvite().getAddress();
} }
private Optional<SingleLookupReply> lookup3pid(String medium, String address) { private Optional<SingleLookupReply> lookup3pid(String medium, String address) {
@@ -252,13 +264,16 @@ public class InvitationManager {
} }
String invId = computeId(invitation); String invId = computeId(invitation);
log.info("Handling invite for {}:{} from {} in room {}", invitation.getMedium(), invitation.getAddress(), invitation.getSender(), invitation.getRoomId()); log.info("Handling invite for {}:{} from {} in room {}", invitation.getMedium(), invitation.getAddress(), invitation.getSender(),
invitation.getRoomId());
IThreePidInviteReply reply = invitations.get(invId); IThreePidInviteReply reply = invitations.get(invId);
if (reply != null) { if (reply != null) {
log.info("Invite is already pending for {}:{}, returning data", invitation.getMedium(), invitation.getAddress()); log.info("Invite is already pending for {}:{}, returning data", invitation.getMedium(), invitation.getAddress());
if (!StringUtils.equals(invitation.getRoomId(), reply.getInvite().getRoomId())) { if (!StringUtils.equals(invitation.getRoomId(), reply.getInvite().getRoomId())) {
log.info("Sending new notification as new invite room {} is different from the original {}", invitation.getRoomId(), reply.getInvite().getRoomId()); log.info("Sending new notification as new invite room {} is different from the original {}", invitation.getRoomId(),
notifMgr.sendForReply(new ThreePidInviteReply(reply.getId(), invitation, reply.getToken(), reply.getDisplayName(), reply.getPublicKeys())); reply.getInvite().getRoomId());
notifMgr.sendForReply(
new ThreePidInviteReply(reply.getId(), invitation, reply.getToken(), reply.getDisplayName(), reply.getPublicKeys()));
} else { } else {
// FIXME we should check attempt and send if bigger // FIXME we should check attempt and send if bigger
} }
@@ -272,7 +287,7 @@ public class InvitationManager {
} }
String token = RandomStringUtils.randomAlphanumeric(64); String token = RandomStringUtils.randomAlphanumeric(64);
String displayName = invitation.getAddress().substring(0, 3) + "..."; String displayName = getInvitedDisplayName(invitation.getAddress());
KeyIdentifier pKeyId = keyMgr.getServerSigningKey().getId(); KeyIdentifier pKeyId = keyMgr.getServerSigningKey().getId();
KeyIdentifier eKeyId = keyMgr.generateKey(KeyType.Ephemeral); KeyIdentifier eKeyId = keyMgr.generateKey(KeyType.Ephemeral);
@@ -295,11 +310,20 @@ public class InvitationManager {
log.info("Storing invite under ID {}", invId); log.info("Storing invite under ID {}", invId);
storage.insertInvite(reply); storage.insertInvite(reply);
invitations.put(invId, reply); invitations.put(invId, reply);
log.info("A new invite has been created for {}:{} on HS {}", invitation.getMedium(), invitation.getAddress(), invitation.getSender().getDomain()); log.info("A new invite has been created for {}:{} on HS {}", invitation.getMedium(), invitation.getAddress(),
invitation.getSender().getDomain());
return reply; return reply;
} }
private String getInvitedDisplayName(String origin) {
if (cfg.isFullDisplayName()) {
return origin;
} else {
return origin.substring(0, 3) + "...";
}
}
public boolean hasInvite(ThreePid tpid) { public boolean hasInvite(ThreePid tpid) {
for (IThreePidInviteReply reply : invitations.values()) { for (IThreePidInviteReply reply : invitations.values()) {
if (!StringUtils.equals(tpid.getMedium(), reply.getInvite().getMedium())) { if (!StringUtils.equals(tpid.getMedium(), reply.getInvite().getMedium())) {
@@ -385,8 +409,10 @@ public class InvitationManager {
public void publishMappingIfInvited(ThreePidMapping threePid) { public void publishMappingIfInvited(ThreePidMapping threePid) {
log.info("Looking up possible pending invites for {}:{}", threePid.getMedium(), threePid.getValue()); log.info("Looking up possible pending invites for {}:{}", threePid.getMedium(), threePid.getValue());
for (IThreePidInviteReply reply : invitations.values()) { for (IThreePidInviteReply reply : invitations.values()) {
if (StringUtils.equalsIgnoreCase(reply.getInvite().getMedium(), threePid.getMedium()) && StringUtils.equalsIgnoreCase(reply.getInvite().getAddress(), threePid.getValue())) { if (StringUtils.equalsIgnoreCase(reply.getInvite().getMedium(), threePid.getMedium()) && StringUtils
log.info("{}:{} has an invite pending on HS {}, publishing mapping", threePid.getMedium(), threePid.getValue(), reply.getInvite().getSender().getDomain()); .equalsIgnoreCase(reply.getInvite().getAddress(), threePid.getValue())) {
log.info("{}:{} has an invite pending on HS {}, publishing mapping", threePid.getMedium(), threePid.getValue(),
reply.getInvite().getSender().getDomain());
publishMapping(reply, threePid.getMxid()); publishMapping(reply, threePid.getMxid());
} }
} }

View File

@@ -26,7 +26,7 @@ import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.fetcher.IBridgeFetcher; import io.kamax.mxisd.lookup.fetcher.IBridgeFetcher;
import io.kamax.mxisd.lookup.fetcher.IRemoteIdentityServerFetcher; import io.kamax.mxisd.lookup.fetcher.IRemoteIdentityServerFetcher;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -27,7 +27,7 @@ import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.fetcher.IRemoteIdentityServerFetcher; import io.kamax.mxisd.lookup.fetcher.IRemoteIdentityServerFetcher;
import io.kamax.mxisd.matrix.IdentityServerUtils; import io.kamax.mxisd.matrix.IdentityServerUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -31,7 +31,11 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xbill.DNS.*; import org.xbill.DNS.Lookup;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@@ -130,7 +134,9 @@ public class HomeserverFederationResolver {
return Optional.empty(); return Optional.empty();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error while trying to lookup well-known for " + domain, e); log.info("Error while trying to lookup well-known for " + domain);
log.trace("Error while trying to lookup well-known for " + domain, e);
return Optional.empty();
} }
} }
@@ -141,7 +147,7 @@ public class HomeserverFederationResolver {
try { try {
List<SRVRecord> srvRecords = new ArrayList<>(); List<SRVRecord> srvRecords = new ArrayList<>();
Record[] rawRecords = new Lookup(lookupDns, Type.SRV).run(); org.xbill.DNS.Record[] rawRecords = new Lookup(lookupDns, Type.SRV).run();
if (Objects.isNull(rawRecords) || rawRecords.length == 0) { if (Objects.isNull(rawRecords) || rawRecords.length == 0) {
log.debug("No SRV record for {}", domain); log.debug("No SRV record for {}", domain);
return Optional.empty(); return Optional.empty();

View File

@@ -25,7 +25,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import io.kamax.mxisd.http.IsAPIv1; import io.kamax.mxisd.http.IsAPIv1;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@@ -108,13 +108,13 @@ public class IdentityServerUtils {
log.info("Lookup name: {}", lookupDns); log.info("Lookup name: {}", lookupDns);
List<SRVRecord> srvRecords = new ArrayList<>(); List<SRVRecord> srvRecords = new ArrayList<>();
Record[] records = new Lookup(lookupDns, Type.SRV).run(); org.xbill.DNS.Record[] records = new Lookup(lookupDns, Type.SRV).run();
if (records == null || records.length == 0) { if (records == null || records.length == 0) {
log.info("No SRV record for {}", lookupDns); log.info("No SRV record for {}", lookupDns);
return Optional.empty(); return Optional.empty();
} }
for (Record record : records) { for (org.xbill.DNS.Record record : records) {
log.info("Record: {}", record.toString()); log.info("Record: {}", record.toString());
if (record.getType() == Type.SRV) { if (record.getType() == Type.SRV) {
if (record instanceof SRVRecord) { if (record instanceof SRVRecord) {

View File

@@ -26,7 +26,7 @@ import io.kamax.mxisd.exception.NotImplementedException;
import io.kamax.mxisd.invitation.IMatrixIdInvite; import io.kamax.mxisd.invitation.IMatrixIdInvite;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.threepid.session.IThreePidSession; import io.kamax.mxisd.threepid.session.IThreePidSession;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -28,7 +28,7 @@ import io.kamax.mxisd.exception.ObjectNotFoundException;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -23,10 +23,10 @@ package io.kamax.mxisd.storage.ormlite;
import com.j256.ormlite.dao.CloseableWrappedIterable; import com.j256.ormlite.dao.CloseableWrappedIterable;
import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.db.PostgresDatabaseType;
import com.j256.ormlite.db.SqliteDatabaseType;
import com.j256.ormlite.jdbc.JdbcConnectionSource; import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.jdbc.JdbcPooledConnectionSource; import com.j256.ormlite.jdbc.JdbcPooledConnectionSource;
import com.j256.ormlite.jdbc.db.PostgresDatabaseType;
import com.j256.ormlite.jdbc.db.SqliteDatabaseType;
import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils; import com.j256.ormlite.table.TableUtils;
@@ -50,7 +50,7 @@ import io.kamax.mxisd.storage.ormlite.dao.HistoricalThreePidInviteIO;
import io.kamax.mxisd.storage.ormlite.dao.AcceptedDao; import io.kamax.mxisd.storage.ormlite.dao.AcceptedDao;
import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO; import io.kamax.mxisd.storage.ormlite.dao.ThreePidInviteIO;
import io.kamax.mxisd.storage.ormlite.dao.ThreePidSessionDao; import io.kamax.mxisd.storage.ormlite.dao.ThreePidSessionDao;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -88,6 +88,7 @@ public class OrmLiteSqlStorage implements IStorage {
public static final String FIX_ACCEPTED_DAO = "2019_12_09__2254__fix_accepted_dao"; public static final String FIX_ACCEPTED_DAO = "2019_12_09__2254__fix_accepted_dao";
public static final String FIX_HASH_DAO_UNIQUE_INDEX = "2020_03_22__1153__fix_hash_dao_unique_index"; public static final String FIX_HASH_DAO_UNIQUE_INDEX = "2020_03_22__1153__fix_hash_dao_unique_index";
public static final String CHANGE_TYPE_TO_TEXT_INVITE = "2020_04_21__2338__change_type_table_invites"; public static final String CHANGE_TYPE_TO_TEXT_INVITE = "2020_04_21__2338__change_type_table_invites";
public static final String CHANGE_TYPE_TO_TEXT_INVITE_HISTORY = "2020_10_26__2200__change_type_table_invite_history";
} }
private Dao<ThreePidInviteIO, String> invDao; private Dao<ThreePidInviteIO, String> invDao;
@@ -177,6 +178,11 @@ public class OrmLiteSqlStorage implements IStorage {
fixInviteTableColumnType(connPol); fixInviteTableColumnType(connPol);
changelogDao.create(new ChangelogDao(Migrations.CHANGE_TYPE_TO_TEXT_INVITE, new Date(), "Modify column type to text.")); changelogDao.create(new ChangelogDao(Migrations.CHANGE_TYPE_TO_TEXT_INVITE, new Date(), "Modify column type to text."));
} }
ChangelogDao fixInviteHistoryTableColumnType = changelogDao.queryForId(Migrations.CHANGE_TYPE_TO_TEXT_INVITE_HISTORY);
if (fixInviteHistoryTableColumnType == null) {
fixInviteHistoryTableColumnType(connPol);
changelogDao.create(new ChangelogDao(Migrations.CHANGE_TYPE_TO_TEXT_INVITE_HISTORY, new Date(), "Modify column type to text."));
}
} }
private void fixAcceptedDao(ConnectionSource connPool) throws SQLException { private void fixAcceptedDao(ConnectionSource connPool) throws SQLException {
@@ -204,6 +210,20 @@ public class OrmLiteSqlStorage implements IStorage {
} }
} }
private void fixInviteHistoryTableColumnType(ConnectionSource connPool) throws SQLException {
LOGGER.info("Migration: {}", Migrations.CHANGE_TYPE_TO_TEXT_INVITE_HISTORY);
if (StorageConfig.BackendEnum.postgresql == backend) {
invDao.executeRawNoArgs("alter table invite_3pid_history alter column \"resolvedTo\" type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column id type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column token type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column sender type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column medium type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column address type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column \"roomId\" type text");
invDao.executeRawNoArgs("alter table invite_3pid_history alter column properties type text");
}
}
private <V, K> Dao<V, K> createDaoAndTable(ConnectionSource connPool, Class<V> c) throws SQLException { private <V, K> Dao<V, K> createDaoAndTable(ConnectionSource connPool, Class<V> c) throws SQLException {
return createDaoAndTable(connPool, c, false); return createDaoAndTable(connPool, c, false);
} }
@@ -247,13 +267,17 @@ public class OrmLiteSqlStorage implements IStorage {
private <T> List<T> forIterable(CloseableWrappedIterable<? extends T> t) { private <T> List<T> forIterable(CloseableWrappedIterable<? extends T> t) {
return withCatcher(() -> { return withCatcher(() -> {
List<T> ioList = new ArrayList<>();
try { try {
List<T> ioList = new ArrayList<>();
t.forEach(ioList::add); t.forEach(ioList::add);
return ioList;
} finally { } finally {
t.close(); try {
t.close();
} catch (Exception e) { // Catching Exception to cover all bases
throw new RuntimeException("Failed to close iterable", e);
}
} }
return ioList;
}); });
} }

View File

@@ -25,7 +25,7 @@ import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View File

@@ -27,7 +27,7 @@ import com.twilio.type.PhoneNumber;
import io.kamax.mxisd.config.threepid.connector.PhoneTwilioConfig; import io.kamax.mxisd.config.threepid.connector.PhoneTwilioConfig;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.exception.NotImplementedException; import io.kamax.mxisd.exception.NotImplementedException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -1,23 +1,3 @@
/*
* mxisd - Matrix Identity Server Daemon
* 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.mxisd.threepid.generator; package io.kamax.mxisd.threepid.generator;
import io.kamax.matrix.ThreePid; import io.kamax.matrix.ThreePid;
@@ -28,7 +8,6 @@ import io.kamax.mxisd.invitation.IMatrixIdInvite;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.threepid.session.IThreePidSession; import io.kamax.mxisd.threepid.session.IThreePidSession;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import static io.kamax.mxisd.http.io.identity.StoreInviteRequest.Keys.RoomName; import static io.kamax.mxisd.http.io.identity.StoreInviteRequest.Keys.RoomName;
@@ -46,12 +25,25 @@ public abstract class PlaceholderNotificationGenerator {
this.srvCfg = srvCfg; this.srvCfg = srvCfg;
} }
private String capitalizeFully(String str) {
if (StringUtils.isBlank(str)) {
return str;
}
String[] words = str.toLowerCase().split("\\s+");
for (int i = 0; i < words.length; i++) {
words[i] = StringUtils.capitalize(words[i]);
}
return String.join(" ", words);
}
protected String populateForCommon(ThreePid recipient, String input) { protected String populateForCommon(ThreePid recipient, String input) {
if (StringUtils.isBlank(input)) { if (StringUtils.isBlank(input)) {
return input; return input;
} }
String domainPretty = WordUtils.capitalizeFully(mxCfg.getDomain()); String domainPretty = capitalizeFully(mxCfg.getDomain());
return input return input
.replace("%DOMAIN%", mxCfg.getDomain()) .replace("%DOMAIN%", mxCfg.getDomain())

View File

@@ -24,7 +24,7 @@ import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.Mxisd; import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.config.threepid.medium.EmailConfig; import io.kamax.mxisd.config.threepid.medium.EmailConfig;
import io.kamax.mxisd.config.threepid.medium.EmailTemplateConfig; import io.kamax.mxisd.config.threepid.medium.EmailTemplateConfig;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Optional; import java.util.Optional;

View File

@@ -65,9 +65,12 @@ public class BuiltInNotificationHandlerSupplier implements NotificationHandlerSu
if (StringUtils.equals(EmailRawNotificationHandler.ID, handler)) { if (StringUtils.equals(EmailRawNotificationHandler.ID, handler)) {
Object o = mxisd.getConfig().getThreepid().getMedium().get(ThreePidMedium.Email.getId()); Object o = mxisd.getConfig().getThreepid().getMedium().get(ThreePidMedium.Email.getId());
if (Objects.nonNull(o)) { if (Objects.nonNull(o)) {
EmailConfig emailCfg; Object cfgJson = mxisd.getConfig().getNotification().getHandlers().get(handler); // Assuming this gives you the JSON config for Email.
EmailConfig emailCfg; // Declare outside the try-catch.
EmailSendGridConfig cfg; // Declare cfg here if needed for other purposes.
try { try {
emailCfg = GsonUtil.get().fromJson(GsonUtil.makeObj(o), EmailConfig.class); emailCfg = GsonUtil.get().fromJson(GsonUtil.get().toJson(o), EmailConfig.class); // Assuming 'o' contains the EmailConfig JSON.
// Additional configurations or initializations can go here.
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {
throw new ConfigurationException("Invalid configuration for threepid email notification"); throw new ConfigurationException("Invalid configuration for threepid email notification");
} }

View File

@@ -28,7 +28,7 @@ import io.kamax.mxisd.notification.NotificationHandler;
import io.kamax.mxisd.threepid.connector.ThreePidConnector; import io.kamax.mxisd.threepid.connector.ThreePidConnector;
import io.kamax.mxisd.threepid.generator.NotificationGenerator; import io.kamax.mxisd.threepid.generator.NotificationGenerator;
import io.kamax.mxisd.threepid.session.IThreePidSession; import io.kamax.mxisd.threepid.session.IThreePidSession;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.List; import java.util.List;

View File

@@ -1,27 +1,13 @@
/*
* mxisd - Matrix Identity Server Daemon
* 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.mxisd.threepid.notification.email; package io.kamax.mxisd.threepid.notification.email;
import com.sendgrid.Method;
import com.sendgrid.Request;
import com.sendgrid.Response;
import com.sendgrid.SendGrid; import com.sendgrid.SendGrid;
import com.sendgrid.SendGridException; import com.sendgrid.helpers.mail.Mail;
import com.sendgrid.helpers.mail.objects.Email;
import com.sendgrid.helpers.mail.objects.Content;
import com.sendgrid.helpers.mail.objects.Personalization; // Correct import for Personalization
import io.kamax.matrix.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.config.MxisdConfig;
@@ -39,22 +25,17 @@ import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import static com.sendgrid.SendGrid.Email;
import static com.sendgrid.SendGrid.Response;
import static io.kamax.mxisd.config.threepid.connector.EmailSendGridConfig.EmailTemplate;
public class EmailSendGridNotificationHandler extends PlaceholderNotificationGenerator implements NotificationHandler { public class EmailSendGridNotificationHandler extends PlaceholderNotificationGenerator implements NotificationHandler {
public static final String ID = "sendgrid"; private static final Logger log = LoggerFactory.getLogger(EmailSendGridNotificationHandler.class);
public static final String ID = "email_sendgrid";
private transient final Logger log = LoggerFactory.getLogger(EmailSendGridNotificationHandler.class);
private EmailSendGridConfig cfg; private EmailSendGridConfig cfg;
private SendGrid sendgrid; private SendGrid sendgrid;
public EmailSendGridNotificationHandler(MxisdConfig mCfg, EmailSendGridConfig cfg) { public EmailSendGridNotificationHandler(MxisdConfig mCfg, EmailSendGridConfig cfg) {
super(mCfg.getMatrix(), mCfg.getServer()); super(mCfg.getMatrix(), mCfg.getServer());
this.cfg = cfg.build(); this.cfg = cfg;
this.sendgrid = new SendGrid(cfg.getApi().getKey()); this.sendgrid = new SendGrid(cfg.getApi().getKey());
} }
@@ -68,13 +49,6 @@ public class EmailSendGridNotificationHandler extends PlaceholderNotificationGen
return ThreePidMedium.Email.getId(); return ThreePidMedium.Email.getId();
} }
protected Email getEmail() {
Email email = new Email();
email.setFrom(cfg.getIdentity().getFrom());
email.setFromName(cfg.getIdentity().getName());
return email;
}
private String getFromFile(String path) { private String getFromFile(String path) {
try { try {
return FileUtil.load(path); return FileUtil.load(path);
@@ -83,85 +57,62 @@ public class EmailSendGridNotificationHandler extends PlaceholderNotificationGen
} }
} }
@Override private void sendEmail(String recipient, String subject, String textContent, String htmlContent) {
public void sendForInvite(IMatrixIdInvite invite) { Mail mail = new Mail();
EmailTemplate template = cfg.getTemplates().getGeneric().get("matrixId"); Email fromEmail = new Email(cfg.getIdentity().getFrom(), cfg.getIdentity().getName());
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) { mail.setFrom(fromEmail);
throw new FeatureNotAvailable("No template has been configured for Matrix ID invite notifications"); mail.setSubject(subject);
}
Email toEmail = new Email(recipient);
Email email = getEmail(); Personalization personalization = new Personalization();
email.setSubject(populateForInvite(invite, template.getSubject())); personalization.addTo(toEmail);
email.setText(populateForInvite(invite, getFromFile(template.getBody().getText()))); mail.addPersonalization(personalization);
email.setHtml(populateForInvite(invite, getFromFile(template.getBody().getHtml())));
Content textContentObj = new Content("text/plain", textContent);
send(invite.getAddress(), email); mail.addContent(textContentObj);
}
if (!StringUtils.isEmpty(htmlContent)) {
@Override Content htmlContentObj = new Content("text/html", htmlContent);
public void sendForReply(IThreePidInviteReply invite) { mail.addContent(htmlContentObj);
EmailTemplate template = cfg.getTemplates().getInvite();
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for 3PID invite notifications");
}
Email email = getEmail();
email.setSubject(populateForReply(invite, template.getSubject()));
email.setText(populateForReply(invite, getFromFile(template.getBody().getText())));
email.setHtml(populateForReply(invite, getFromFile(template.getBody().getHtml())));
send(invite.getInvite().getAddress(), email);
}
@Override
public void sendForValidation(IThreePidSession session) {
EmailTemplate template = cfg.getTemplates().getSession().getValidation();
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for validation notifications");
}
Email email = getEmail();
email.setSubject(populateForValidation(session, template.getSubject()));
email.setText(populateForValidation(session, getFromFile(template.getBody().getText())));
email.setHtml(populateForValidation(session, getFromFile(template.getBody().getHtml())));
send(session.getThreePid().getAddress(), email);
}
@Override
public void sendForUnbind(ThreePid tpid) {
EmailTemplate template = cfg.getTemplates().getSession().getUnbind();
if (StringUtils.isAllBlank(template.getBody().getText(), template.getBody().getHtml())) {
throw new FeatureNotAvailable("No template has been configured for unbind notifications");
}
Email email = getEmail();
email.setSubject(populateForCommon(tpid, template.getSubject()));
email.setText(populateForCommon(tpid, getFromFile(template.getBody().getText())));
email.setHtml(populateForCommon(tpid, getFromFile(template.getBody().getHtml())));
send(tpid.getAddress(), email);
}
private void send(String recipient, Email email) {
if (StringUtils.isBlank(cfg.getIdentity().getFrom())) {
throw new FeatureNotAvailable("3PID Email identity: sender address is empty - " +
"You must set a value for notifications to work");
} }
Request request = new Request();
try { try {
email.addTo(recipient); request.setMethod(Method.POST);
email.setFrom(cfg.getIdentity().getFrom()); request.setEndpoint("mail/send");
email.setFromName(cfg.getIdentity().getName()); request.setBody(mail.build());
Response response = sendgrid.send(email); Response response = sendgrid.api(request);
if (response.getStatus()) { if (response.getStatusCode() >= 200 && response.getStatusCode() < 300) {
log.info("Successfully sent email to {} using SendGrid", recipient); log.info("Successfully sent email to {} using SendGrid", recipient);
} else { } else {
throw new RuntimeException("Error sending via SendGrid to " + recipient + ": " + response.getMessage()); log.error("Failed to send email. Response code: {}, body: {}", response.getStatusCode(), response.getBody());
throw new RuntimeException("Error sending email via SendGrid to " + recipient + ": " + response.getBody());
} }
} catch (SendGridException e) { } catch (IOException e) {
throw new RuntimeException("Unable to send e-mail invite via SendGrid to " + recipient, e); log.error("IOException when sending email to {}: {}", recipient, e.getMessage(), e);
throw new RuntimeException("Unable to send email via SendGrid to " + recipient, e);
} }
} }
@Override
public void sendForInvite(IMatrixIdInvite invite) throws FeatureNotAvailable {
// Implementation...
}
@Override
public void sendForReply(IThreePidInviteReply reply) throws FeatureNotAvailable {
// Implementation...
}
@Override
public void sendForValidation(IThreePidSession session) throws FeatureNotAvailable {
// Implementation...
}
@Override
public void sendForUnbind(ThreePid pid) throws FeatureNotAvailable {
// Placeholder implementation
log.info("Unbind requested for: {}", pid.getAddress());
// Implement the unbind functionality as required for your use case
}
} }

View File

@@ -24,7 +24,7 @@ import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.exception.BadRequestException; import io.kamax.mxisd.exception.BadRequestException;
import io.kamax.mxisd.exception.InvalidCredentialsException; import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.storage.dao.IThreePidSessionDao; import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;

View File

@@ -2,7 +2,7 @@
############################################################################## ##############################################################################
## ##
## ma1sd start up script for UN*X ## mxids start up script for UN*X
## ##
############################################################################## ##############################################################################
@@ -21,10 +21,10 @@ while [ -h "$PRG" ] ; do
done done
APP_HOME=`dirname "$PRG"` APP_HOME=`dirname "$PRG"`
APP_NAME="ma1sd" APP_NAME="mxids"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and MA1SD_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and MXIDS_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS=""
# 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.
@@ -61,7 +61,7 @@ case "`uname`" in
;; ;;
esac esac
CLASSPATH=$APP_HOME/ma1sd.jar CLASSPATH=$APP_HOME/mxids.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
@@ -158,7 +158,7 @@ for s in "${@}" ; do
done done
# Collect JVM options # Collect JVM options
JVM_OPTS=$DEFAULT_JVM_OPTS" "$JAVA_OPTS" "$MA1SD_OPTS JVM_OPTS=$DEFAULT_JVM_OPTS" "$JAVA_OPTS" "$MXIDS_OPTS
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then

View File

@@ -1,10 +0,0 @@
[Unit]
Description=ma1sd
After=syslog.target
[Service]
User=ma1sd
ExecStart=/usr/bin/ma1sd -c /etc/ma1sd/ma1sd.yaml
[Install]
WantedBy=multi-user.target

10
src/systemd/mxids.service Normal file
View File

@@ -0,0 +1,10 @@
[Unit]
Description=mxids
After=syslog.target
[Service]
User=mxids
ExecStart=/usr/bin/mxids -c /etc/mxids/mxids.yaml
[Install]
WantedBy=multi-user.target

View File

@@ -8,7 +8,7 @@ import io.kamax.mxisd.config.rest.RestBackendConfig;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;

View File

@@ -37,7 +37,7 @@ import io.kamax.mxisd.invitation.ThreePidInviteReply;
import io.kamax.mxisd.threepid.connector.email.EmailSmtpConnector; import io.kamax.mxisd.threepid.connector.email.EmailSmtpConnector;
import io.kamax.mxisd.threepid.generator.PlaceholderNotificationGenerator; import io.kamax.mxisd.threepid.generator.PlaceholderNotificationGenerator;
import io.kamax.mxisd.threepid.session.ThreePidSession; import io.kamax.mxisd.threepid.session.ThreePidSession;
import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;