Compare commits

...

17 Commits

Author SHA1 Message Date
Max Dor
f13748abeb Fix #101
The default value was never initialized due to a missing annotation
2018-11-30 02:53:30 +01:00
Max Dor
7208c7e456 Fix #100 2018-11-30 00:18:05 +01:00
Max Dor
8857f636d6 Fix deprecated method calls 2018-11-28 13:18:22 +01:00
Max Dor
d9fc41e8c7 Merge pull request #88 from stygianguest/patch-1 2018-11-28 12:55:21 +01:00
Max Dor
da08e0b4ad Add more debug statements for experimental AS-mode for Matrix ID invites 2018-11-27 23:39:37 +01:00
Max Dor
11fc8f08b0 Add reference to the new community NixOS package 2018-11-25 20:11:19 +01:00
Max Dor
af4d734105 Merge pull request #96 from abeluck/patch-1
Fix broken links in example configuration
2018-11-22 13:12:38 +01:00
Abel Luck
0f4f5ac81b Fix broken links in example configuration 2018-11-22 11:42:13 +00:00
Max Dor
8c4ddd2e65 Make Exec ID Store test scripts compatible with more *nix systems 2018-11-16 16:06:59 +01:00
Max Dor
cb8049b54a Set appropriate copyright owner and website 2018-11-14 03:56:47 +01:00
Max Dor
99b7d9f27d Complete the documentation and polish the code 2018-11-01 05:09:47 +01:00
Max Dor
ded5e3db5e Add support for all features for Exec Identity Store 2018-11-01 02:15:56 +01:00
Max Dor
b892d19023 Add skeleton support for Directory and Identity in Exec IdStore 2018-10-31 03:49:06 +01:00
Max Dor
026a2e82d9 Further progress on Exec Identity Store 2018-10-29 07:00:07 +01:00
Max Dor
b881f73798 Add support for setting build version using env variable 2018-10-28 20:20:30 +01:00
Gideon Smeding
29017fbe1e Reworking the introduction of the session documentation 2018-10-13 16:43:06 +02:00
Gideon Smeding
20a4d8dd91 Minor corrections for session.md 2018-09-23 23:20:27 +02:00
170 changed files with 2467 additions and 496 deletions

View File

@@ -64,28 +64,28 @@ storage.provider.sqlite.database: '/path/to/mxisd.db'
# LDAP Backend #
################
# If you would like to integrate with your AD/Samba/LDAP server,
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/backends/ldap.md
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/stores/ldap.md
###############
# SQL Backend #
###############
# If you would like to integrate with a MySQL/MariaDB/PostgreQL/SQLite DB,
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/backends/sql.md
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/stores/sql.md
################
# REST Backend #
################
# If you would like to integrate with an existing web service/webapp,
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/backends/rest.md
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/stores/rest.md
#################################################
# Notifications for invites/addition to profile #
#################################################
# If you would like to change the content,
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/notifications/template-generator.md
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/notification/template-generator.md
#
#### E-mail invite sender
#

View File

@@ -41,17 +41,25 @@ def debBuildDataPath = "${debBuildBasePath}${debDataPath}"
def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}"
def dockerImageName = "kamax/mxisd"
def dockerImageTag = "${dockerImageName}:${gitVersion()}"
def dockerImageTag = "${dockerImageName}:${mxisdVersion()}"
String mxisdVersion() {
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
String version = System.getenv('MXISD_BUILD_VERSION')
if (version == null || version.size() == 0) {
version = gitVersion()
}
return versionPattern.matcher(version).matches() ? version.substring(1) : version
}
String gitVersion() {
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
ByteArrayOutputStream out = new ByteArrayOutputStream()
exec {
commandLine = ['git', 'describe', '--tags', '--always', '--dirty']
standardOutput = out
}
def v = out.toString().replace(System.lineSeparator(), '')
return versionPattern.matcher(v).matches() ? v.substring(1) : v
return out.toString().replace(System.lineSeparator(), '');
}
buildscript {
@@ -99,8 +107,8 @@ dependencies {
compile 'com.googlecode.libphonenumber:libphonenumber:8.7.1'
// E-mail sending
compile 'com.sun.mail:javax.mail:1.5.6'
compile 'javax.mail:javax.mail-api:1.5.6'
compile 'com.sun.mail:javax.mail:1.6.2'
compile 'javax.mail:javax.mail-api:1.6.2'
// Google Firebase Authentication backend
compile 'com.google.firebase:firebase-admin:5.3.0'
@@ -154,7 +162,7 @@ processResources {
task buildDeb(dependsOn: build) {
doLast {
def v = gitVersion()
def v = mxisdVersion()
println "Version for package: ${v}"
mkdir distDir
mkdir debBuildBasePath

View File

@@ -29,9 +29,10 @@ If you would like a high-level view of the infrastructure and how each feature i
## Install
Install via:
- [Docker image](install/docker.md)
- [Debian package](install/debian.md)
- [ArchLinux](install/archlinux.md)
- [Docker image](install/docker.md)
- [NixOS](install/nixos.md)
- [Sources](build.md)
See the [Latest release](https://github.com/kamax-matrix/mxisd/releases/latest) for links to each.

8
docs/install/nixos.md Normal file
View File

@@ -0,0 +1,8 @@
# NixOS package
mxisd is available as a NixOS package in the official repos.
It is maintained by [maximilian](https://matrix.to/#/@maximilian:transformierende-gesellschaft.org), a community member.
Related resources:
- [NixOS](https://nixos.org/)
- [The module definition](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/mxisd.nix)

View File

@@ -1,60 +1,470 @@
# Exec Identity Store
This Identity Store lets you run arbitrary commands to handle the various requests in each support feature.
- [Features](#features)
- [Overview](#overview)
- [Configuration](#configuration)
- [Global](#global)
- [Tokens](#tokens)
- [Executable](#executable)
- [Input](#input)
- [Output](#output)
- [Examples](#examples)
- [Per-Feature](#per-feature)
- [Authentication](#authentication)
- [Tokens](#tokens-1)
- [Input](#input-1)
- [Output](#output-1)
- [Directory](#directory)
- [Tokens](#tokens-2)
- [Input](#input-2)
- [Output](#output-2)
- [Identity](#identity)
- [Single Lookup](#single-lookup)
- [Tokens](#tokens-3)
- [Input](#input-3)
- [Output](#output-3)
- [Bulk Lookup](#bulk-lookup)
- [Tokens](#tokens-4)
- [Input](#input-4)
- [Output](#output-4)
- [Profile](#profile)
- [Tokens](#tokens-5)
- [Input](#input-5)
- [Output](#output-5)
This is the most versatile Identity store of mxisd, allowing you to connect any kind of logic in any language/scripting.
---
## Features
| Name | Supported? |
|----------------|---------------|
| Authentication | Yes |
| Directory | *In Progress* |
| Identity | *In Progress* |
| Profile | *In Progress* |
| Name | Supported |
|-------------------------------------------------|-----------|
| [Authentication](../features/authentication.md) | Yes |
| [Directory](../features/directory.md) | Yes |
| [Identity](../features/identity.md) | Yes |
| [Profile](#profile) | Yes |
This Identity Store lets you run arbitrary commands to handle the various requests in each support feature.
It is the most versatile Identity store of mxisd, allowing you to connect any kind of logic with any executable/script.
## Overview
Each request can be mapping to a fully customizable command configuration.
The various parameters can be provided via any combination of:
- Standard Input
- Command line arguments
- Environment variables
- [Standard Input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin))
- [Command-line arguments](https://en.wikipedia.org/wiki/Command-line_interface#Arguments)
- [Environment variables](https://en.wikipedia.org/wiki/Environment_variable)
Each of those supports a set of customizable token which will be replaced prior to running the command, allowing to
provide the input values in any number of ways.
Success and data will be provided via [Exit status](https://en.wikipedia.org/wiki/Exit_status) and Standard Output, both
supporting a set of options.
Success and data will be provided via any combination of:
- [Exit status](https://en.wikipedia.org/wiki/Exit_status)
- [Standard Output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout))
Each of those supports a set of configuration item to decide how to process the value and/or in which format.
All values, inputs and outputs are UTF-8 encoded.
## Configuration
Each feature comes with a set of possible lookup/action which is mapped to a generic configuration item block.
We will use the term `Executable` for each lookup/action and `Processor` for each configuration block.
### Global
```yaml
exec.enabled: <boolean>
```
Enable/disable the Identity store at a global/default level. Each feature can still be enabled/disabled specifically.
Enable/disable the Identity store at a global/default level. Each feature can still be individually enabled/disabled.
*TBC*
#### Tokens
The following options allow to globally set tokens for value replacement across all features and processors config.
Not all features use all tokens, and each feature might also have its own specific tokens. See each feature documentation.
## Use-case examples
They can be set within the following scope:
```yaml
exec.token.<token>: '<value>'
```
---
The following tokens and default values are available:
```yaml
localpart: '{localpart}'
```
Localpart of Matrix User IDs
```yaml
domain: '{domain}'
```
Domain of Matrix User IDs
```yaml
mxid: '{mxid}'
```
Full representation of Matrix User IDs
```yaml
medium: '{medium}'
```
Medium of 3PIDs
```yaml
address: '{address}'
```
Address of 3PIDs
```yaml
type: '{type}'
```
Type of query
```yaml
query: '{query}'
```
Query value
### Executable
*Executable*s have the following options:
```yaml
command: '/path/to/executableOrScript'
```
Set the executable (relative or absolute) path to be executed. If no command is given, the action will return a "neutral"
result if possible or be skipped altogether.
---
Command line arguments can be given via a list via both YAML formats:
```yaml
args:
- '-t'
- '{token}'
- '-v'
- 'value'
```
or
```yaml
args: ['-t', '{token}', '-v', 'value]
```
Each argument will be processed for token replacement.
---
Environment variables can be given as key/value pairs:
```yaml
env:
ENV_VAR_1: 'value'
ENV_VAR_2: '{token}'
```
Each variable value will be processed for token replacement.
#### Input
Standard input can be configured in the namespaces `input` with:
- `type`: The format to use
- `template`: The full or partial template with tokens to be used when generating the input
Not all features and *Executable*s allow for a template to be provided.
Templates for listed-based input are not supported at this time.
Default templates may be provided per *Executable*.
The following types are available:
- `json`: Use JSON format, shared with the [REST Identity Store](rest.md)
- `plain`: Use a custom multi-lines, optionally tab-separated input
#### Output
Standard output can be configured in the namespaces `output` with:
- `type`: The format to use
- `template`: The full or partial template with tokens to be used when processing the output
Not all features and *Executable*s allow for a template to be provided.
Templates for listed-based output are not supported at this time.
Default templates may be provided per *Executable*.
The following types are available:
- `json`: Use JSON format, shared with the [REST Identity Store](rest.md)
- `plain`: Use a custom multi-lines, optionally tab-separated output
### Examples
#### Basic
```yaml
exec.auth.enabled: true
exec.auth.command: '/opt/mxisd-exec/auth.sh'
exec.auth.args: ['{localpart}']
exec.auth.input.type: 'plain'
exec.auth.input.template: '{password}'
exec.auth.env:
DOMAIN: '{domain}'
```
With Authentication enabled, run `/opt/mxisd-exec/auth.sh` when validating credentials, providing:
- A single command-line argument to provide the `localoart` as username
- A plain text string with the password token for standard input, which will be replaced by the password to check
- A single environment variable `DOMAIN` containing Matrix ID domain, if given
The command will use the default values for:
- Success exit status of `0`
- Failure exit status of `1`
- Any other exit status considered as error
- The standard output processing as not processed
#### Advanced
Given the fictional `placeholder` feature:
```yaml
exec.enabled: true
exec.token.mxid: '{matrixId}'
exec.auth.command: '/path/to/auth/executable'
exec.auth.args: ['-u', '{localpart}']
exec.auth.env:
PASSWORD: '{password}'
exec.placeholder.token.localpart: '{username}'
exec.placeholder.command: '/path/to/executable'
exec.placeholder.args:
- '-u'
- '{username}'
exec.placeholder.env:
MATRIX_DOMAIN: '{domain}'
MATRIX_USER_ID: '{mxid}'
```
This will run `/path/to/auth/executable` with:
- The extracted Matrix User ID `localpart` provided as the second command line argument, the first one being `-u`
- The password, the extract Matrix `domain` and the full User ID as arbitrary environment variables, respectively `PASSWORD`, `MATRIX_DOMAIN` and `MATRIX_USER_ID`
MATRIX_USER_ID: '{matrixId}'
```yaml
## Few more available config items
#
# exec.token.domain: '{matrixDomain}' # This sets the default replacement token for the Matrix Domain of the User ID, across all features.
# exec.auth.token.domain: '{matrixDomainForAuth}' # We can also set another token specific to a feature.
# exec.auth.input: 'json' # This is not supported yet.
# exec.auth.exit.success: [0] # Exit status that will consider the request successful. This is already the default.
# exec.auth.exit.failure: [1,2,3] # Exist status that will consider the request failed. Anything else than success or failure statuses will throw an exception.
# exec.auth.output: 'json' # Required if stdout should be read on success. This uses the same output as the REST Identity store for Auth.
exec.placeholder.output.type: 'json'
exec.placeholder.exit.success: [0, 128]
exec.placeholder.exit.failure: [1, 129]
```
*TBC*
With:
- The Identity store enabled for all features
- A global specific token `{matrixId}` for Matrix User IDs, replacing the default `{mxid}`
Running `/path/to/executable` providing:
- A custom token for localpart, `{username}`, used as a 2nd command-line argument
- An extracted Matrix User ID `localpart` provided as the second command line argument, the first one being `-u`
- A password, the extracted Matrix `domain` and the full User ID as arbitrary environment variables, respectively
`PASSWORD`, `MATRIX_DOMAIN` and `MATRIX_USER_ID`
After execution:
- Process stdout as [JSON](https://en.wikipedia.org/wiki/JSON)
- Consider exit status `0` and `128` as success and try to process the stdout for data
- Consider exit status `1` and `129` as failure and try to process the stdout for error code and message
### Per Feature
See each dedicated [Feature](#features) section.
## Authentication
The Authentication feature can be enabled/disabled using:
```yaml
exec.auth.enabled: <true/false>
```
---
This feature provides a single *Executable* under the namespace:
```yaml
exec.auth:
...
```
### Tokens
The following tokens/default values are specific to this feature:
```yaml
password: '{password}'
```
The provided password
### Input
Supported input types and default templates:
#### JSON (`json`)
Same as the [REST Identity Store](rest.md);
#### Plain (`plain`)
Default template:
```
{localpart}
{domain}
{mxid}
{password}
```
### Output
Supported output types and default templates:
#### JSON (`json`)
Same as the [REST Identity Store](rest.md);
#### Plain (`plain`)
**NOTE:** This has limited support. Use the JSON type for full support.
Default template:
```
[success status, true or 1 are interpreted as success]
[display name of the user]
```
## Directory
The Directory feature can be enabled/disabled using:
```yaml
exec.directory.enabled: <true/false>
```
---
Two search types configuration namespace are available, using the same input/output formats and templates:
By name:
```yaml
exec.directory.search.byName:
...
```
By 3PID:
```yaml
exec.directory.search.byThreepid:
...
```
#### Tokens
No specific tokens are available.
#### Input
Supported input types and default templates:
##### JSON (`json`)
Same as the [REST Identity Store](rest.md);
##### Plain (`plain`)
Default template:
```
[type of search, following the REST Identity store format]
[query string]
```
#### Output
Supported output types and default templates:
##### JSON (`json`)
Same as the [REST Identity Store](rest.md);
##### Plain (`plain`)
**Not supported at this time.** Use the JSON type.
## Identity
The Identity feature can be enabled/disabled using:
```yaml
exec.identity.enabled: <true/false>
```
### Single lookup
Configuration namespace:
```yaml
exec.identity.lookup.single:
...
```
#### Tokens
No specific tokens are available.
#### Input
Supported input types and default templates:
##### JSON (`json`)
Same as the [REST Identity Store](rest.md);
##### Plain (`plain`)
Default template:
```
{medium}
{address}
```
#### Output
Supported output types and default templates:
##### JSON (`json`)
Same as the [REST Identity Store](rest.md);
##### Plain (`plain`)
Default template:
```
[User ID type, as documented in the REST Identity Store]
[User ID value]
```
The User ID type will default to `localpart` if:
- Only one line is returned
- The first line is empty
### Bulk lookup
Configuration namespace:
```yaml
exec.identity.lookup.bulk:
...
```
#### Tokens
No specific tokens are available.
#### Input
Supported input types and default templates:
##### JSON (`json`)
**NOTE:** Custom Templates are not supported.
Same as the [REST Identity Store](rest.md).
##### Plain (`plain`)
**Not supported at this time.** Use the JSON type.
#### Output
Supported output types and default templates:
##### JSON (`json`)
**NOTE:** Custom Templates are not supported.
Same as the [REST Identity Store](rest.md).
##### Plain (`plain`)
**Not supported at this time.** Use the JSON type.
## Profile
The Profile feature can be enabled/disabled using:
```yaml
exec.profile.enabled: <true/false>
```
---
The following *Executable*s namespace are available, share the same input/output formats and templates:
Get Display name:
```yaml
exec.profile.displayName:
...
```
Get 3PIDs:
```yaml
exec.profile.threePid:
...
```
Get Roles:
```yaml
exec.profile.role:
...
```
### Tokens
No specific tokens are available.
### Input
Supported input types and default templates:
#### JSON (`json`)
Same as the [REST Identity Store](rest.md);
#### Plain (`plain`)
Default template:
```
{localpart}
{domain}
{mxid}
```
### Output
Supported output types and default templates:
#### JSON (`json`)
Same as the [REST Identity Store](rest.md);
#### Plain (`plain`)
**Not supported at this time.** Use the JSON type.

View File

@@ -18,48 +18,62 @@
## Overview
When adding an email, a phone number or any other kind of 3PID (Third-Party Identifier) in a Matrix client,
the identity server is called to validate the 3PID.
the identity server is contacted to validate the 3PID.
To validate the 3PID the identity server sends a message to the 3PID (e.g. an
email) with a hyperlink back to a web-page managed by the identity server to
confirm ownership of the 3PID.
Once this 3PID is validated, the Homeserver will publish the user Matrix ID on the Identity Server and
add this 3PID to the Matrix account which initiated the request.
## Purpose
This serves two purposes:
- Add the 3PID as an administrative/login info for the Homeserver directly
- Publish, or *Bind*, the 3PID so it can be queried from Homeservers and clients when inviting someone in a room
by a 3PID, allowing it to be resolved to a Matrix ID.
## Federation
Federation is based on the principle that one can get a domain name and serve services and information within that
domain namespace in a way which can be discovered following a specific protocol or specification.
In a federated set up, identity servers must cooperate to find the Matrix ID associated with a 3PID.
In the Matrix eco-system, some 3PID can be federated (e.g. emails) while some others cannot (phone numbers).
Also, Matrix users might add 3PIDs that would not point to the Identity server that actually holds the 3PID binding.
Federation is based on the principle that each server is responsible for its own (dns) domain.
Therefore only those 3PID can be federated that can be distinguished by their
domain such as email addresses.
Example: a user from Homeserver `example.org` adds an email `john@example.com`.
Federated identity servers would try to find the identity server at `example.com` and ask it for the Matrix ID of associated with `john@example.com`.
Nevertheless, Matrix users might add 3PIDs that are not associated to a domain, for example telephone numbers.
Or they might even add 3PIDs associated to a different domain (such as an email address hosted by gmail).
Such 3PIDs cannot be resolved in a federated way.
Example: a user from Homeserver `example.org` adds an email `john@gmail.com`.
If a federated lookup was performed, Identity servers would try to find the 3PID bind at the `gmail.com` server, and
not `example.org`.
To allow global publishing of 3PID bindings to be found anywhere within the current protocol specification, one would
perform a *Remote session* and *Remote bind*, effectively starting a new 3PID session with another Identity server on
In order to resolve such 3PIDs, i.e. 3PIDs that cannot be resolved in a Federated way, an identity server can be configured such that
- 3PIDs that cannot be resolved locally or using federation, are fowarded to another global identity server.
- registration of new 3PIDs that cannot be looked up in a federated fashion, is forwarded to another global identity server.
By forwarding a 3PIDs registration the identity creates a *Remote session* and *Remote bind*, effectively starting a new 3PID session with another Identity server on
behalf of the user.
To ensure lookup works consistency within the current Matrix network, the central Matrix.org Identity Server should be
used to store *remote* sessions and binds.
On the flip side, at the time of writing, the Matrix specification and the central Matrix.org servers do not allow to
remote a 3PID bind. This means that once a 3PID is published (email, phone number, etc.), it cannot be easily removed
However, at the time of writing, the Matrix specification and the central Matrix.org servers do not allow to remote a 3PID bind.
This means that once a 3PID is published (email, phone number, etc.), it cannot be easily removed
and would require contacting the Matrix.org administrators for each bind individually.
This poses a privacy, control and security concern, especially for groups/corporations that want to keep a tight control
on where such identifiers can be made publicly visible.
To ensure full control, validation management rely on two concepts:
To ensure full control, validation management relies on two concepts:
- The scope of 3PID being validated
- The scope of 3PID sessions that should be possible/offered
### 3PID scope
3PID can either be scoped as local or remote.
Local means that they can looked up using federation and that such federation call would end up on the local
Local means that they can be looked up using federation and that such a federation call would end up on the local
Identity Server.
Remote means that they cannot be lookup using federation or that a federation call would not end up on the local
Identity Server.
@@ -139,7 +153,7 @@ session.policy.validation.forRemote:
`session.policy.validation` is the core configuration to control what users configured to use your Identity server
are allowed to do in terms of 3PID sessions.
The policy is divided contains a global on/off switch for 3PID sessions using `.enabled`
The policy has a global on/off switch for 3PID sessions using `.enabled`
It is also divided into two sections: `forLocal` and `forRemote` which refers to the 3PID scopes.
Each scope is divided into three parts:

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -22,6 +22,7 @@ package io.kamax.mxisd.as;
import com.google.gson.JsonObject;
import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePidMedium;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import io.kamax.matrix.event.EventKey;
@@ -39,6 +40,7 @@ import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class AppServiceHandler {
@@ -60,52 +62,77 @@ public class AppServiceHandler {
public void processTransaction(List<JsonObject> eventsJson) {
eventsJson.forEach(ev -> {
String evId = EventKey.Id.getStringOrNull(ev);
if (StringUtils.isBlank(evId)) {
log.warn("Event has no ID, skipping");
log.debug("Event:\n{}", GsonUtil.getPrettyForLog(ev));
return;
}
log.debug("Event {}: processing start", evId);
String roomId = EventKey.RoomId.getStringOrNull(ev);
if (StringUtils.isBlank(roomId)) {
log.debug("Event has no room ID, skipping");
return;
}
String senderId = EventKey.Sender.getStringOrNull(ev);
if (StringUtils.isBlank(senderId)) {
log.debug("Event has no room ID, skipping");
return;
}
_MatrixID sender = MatrixID.asAcceptable(senderId);
if (!StringUtils.equals("m.room.member", GsonUtil.getStringOrNull(ev, "type"))) {
log.debug("This is not a room membership event, skipping");
return;
}
if (!StringUtils.equals("invite", GsonUtil.getStringOrNull(ev, "membership"))) {
log.debug("This is not an invite event, skipping");
return;
}
String roomId = GsonUtil.getStringOrNull(ev, "room_id");
_MatrixID sender = MatrixID.asAcceptable(GsonUtil.getStringOrNull(ev, "sender"));
EventKey.StateKey.findString(ev).ifPresent(id -> {
_MatrixID mxid = MatrixID.asAcceptable(id);
if (!StringUtils.equals(mxid.getDomain(), cfg.getDomain())) {
log.debug("Ignoring invite for {}: not a local user");
return;
}
log.info("Got invite for {}", id);
String inviteeId = EventKey.StateKey.getStringOrNull(ev);
if (StringUtils.isBlank(inviteeId)) {
log.warn("Invalid event: No invitee ID, skipping");
return;
}
boolean wasSent = false;
List<_ThreePid> tpids = profiler.getThreepids(mxid);
if (tpids.isEmpty()) {
log.info("No email found in identity stores for {}", id);
_MatrixID invitee = MatrixID.asAcceptable(inviteeId);
if (!StringUtils.equals(invitee.getDomain(), cfg.getDomain())) {
log.debug("Ignoring invite for {}: not a local user");
return;
}
log.info("Got invite for {}", inviteeId);
boolean wasSent = false;
List<_ThreePid> tpids = profiler.getThreepids(invitee).stream()
.filter(tpid -> ThreePidMedium.Email.is(tpid.getMedium()))
.collect(Collectors.toList());
log.info("Found {} email(s) in identity store for {}", tpids.size(), inviteeId);
for (_ThreePid tpid : tpids) {
log.info("Found Email to notify about room invitation: {}", tpid.getAddress());
Map<String, String> properties = new HashMap<>();
profiler.getDisplayName(sender).ifPresent(name -> properties.put("sender_display_name", name));
try {
synapse.getRoomName(roomId).ifPresent(name -> properties.put("room_name", name));
} catch (RuntimeException e) {
log.warn("Could not fetch room name", e);
log.warn("Unable to fetch room name: Did you integrate your Homeserver as documented?");
}
for (_ThreePid tpid : tpids) {
if (!StringUtils.equals("email", tpid.getMedium())) {
continue;
}
IMatrixIdInvite inv = new MatrixIdInvite(roomId, sender, invitee, tpid.getMedium(), tpid.getAddress(), properties);
notif.sendForInvite(inv);
log.info("Notification for invite of {} sent to {}", inviteeId, tpid.getAddress());
wasSent = true;
}
log.info("Found an email address to notify about room invitation: {}", tpid.getAddress());
Map<String, String> properties = new HashMap<>();
profiler.getDisplayName(sender).ifPresent(name -> properties.put("sender_display_name", name));
try {
synapse.getRoomName(roomId).ifPresent(name -> properties.put("room_name", name));
} catch (RuntimeException e) {
log.warn("Unable to fetch room name - Did you provide synapse DB information as documented?");
log.warn("Underlying error:", e);
}
log.info("Was notification sent? {}", wasSent);
IMatrixIdInvite inv = new MatrixIdInvite(roomId, sender, mxid, tpid.getMedium(), tpid.getAddress(), properties);
notif.sendForInvite(inv);
wasSent = true;
}
log.info("Was notification sent? {}", wasSent);
});
log.debug("Event {}: processing end", evId);
});
}

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -27,27 +27,22 @@ import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.UserID;
import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.backend.rest.RestAuthRequestJson;
import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.exception.InternalServerError;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.ProcessResult;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.Objects;
import java.util.Optional;
@Component
public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
private final transient Logger log = LoggerFactory.getLogger(ExecAuthStore.class);
private final Logger log = LoggerFactory.getLogger(ExecAuthStore.class);
private ExecConfig.Auth cfg;
@@ -71,71 +66,64 @@ public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
ExecAuthResult result = new ExecAuthResult();
result.setId(new UserID(UserIdType.Localpart, uId.getLocalPart()));
ProcessExecutor psExec = new ProcessExecutor().readOutput(true);
Processor<ExecAuthResult> p = new Processor<>(cfg);
List<String> args = new ArrayList<>();
args.add(cfg.getCommand());
args.addAll(cfg.getArgs().stream().map(arg -> arg
.replace(cfg.getToken().getLocalpart(), uId.getLocalPart())
.replace(cfg.getToken().getDomain(), uId.getDomain())
.replace(cfg.getToken().getMxid(), uId.getId())
.replace(cfg.getToken().getPassword(), password)
).collect(Collectors.toList()));
psExec.command(args);
p.addTokenMapper(cfg.getToken().getLocalpart(), uId::getLocalPart);
p.addTokenMapper(cfg.getToken().getDomain(), uId::getDomain);
p.addTokenMapper(cfg.getToken().getMxid(), uId::getId);
p.addTokenMapper(cfg.getToken().getPassword(), () -> password);
psExec.environment(new HashMap<>(cfg.getEnv()).entrySet().stream().peek(e -> {
e.setValue(e.getValue().replace(cfg.getToken().getLocalpart(), uId.getLocalPart()));
e.setValue(e.getValue().replace(cfg.getToken().getDomain(), uId.getDomain()));
e.setValue(e.getValue().replace(cfg.getToken().getMxid(), uId.getId()));
e.setValue(e.getValue().replace(cfg.getToken().getPassword(), password));
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
p.addJsonInputTemplate(tokens -> {
RestAuthRequestJson json = new RestAuthRequestJson();
json.setLocalpart(tokens.getLocalpart());
json.setDomain(tokens.getDomain());
json.setMxid(tokens.getMxid());
json.setPassword(tokens.getPassword());
return json;
});
p.addInputTemplate(PlainType, tokens -> tokens.getLocalpart() + System.lineSeparator() +
tokens.getDomain() + System.lineSeparator() +
tokens.getMxid() + System.lineSeparator() +
tokens.getPassword() + System.lineSeparator()
);
if (StringUtils.isNotBlank(cfg.getInput())) {
if (StringUtils.equals("json", cfg.getInput())) {
JsonObject input = new JsonObject();
input.addProperty("localpart", uId.getLocalPart());
input.addProperty("mxid", uId.getId());
input.addProperty("password", password);
psExec.redirectInput(IOUtils.toInputStream(GsonUtil.get().toJson(input), StandardCharsets.UTF_8));
} else {
throw new InternalServerError(cfg.getInput() + " is not a valid executable input format");
p.withExitHandler(pr -> result.setExitStatus(pr.getExitValue()));
p.withSuccessHandler(pr -> result.setSuccess(true));
p.withSuccessDefault(o -> result);
p.addSuccessMapper(JsonType, output -> {
JsonObject data = GsonUtil.getObj(GsonUtil.parseObj(output), "auth");
GsonUtil.findPrimitive(data, "success")
.map(JsonPrimitive::getAsBoolean)
.ifPresent(result::setSuccess);
GsonUtil.findObj(data, "profile")
.flatMap(profile -> GsonUtil.findString(profile, "display_name"))
.ifPresent(v -> result.getProfile().setDisplayName(v));
return result;
});
p.addSuccessMapper(PlainType, output -> {
String[] lines = output.split("\\R");
if (lines.length > 2) {
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
}
}
try {
log.info("Executing {}", cfg.getCommand());
ProcessResult psResult = psExec.execute();
result.setExitStatus(psResult.getExitValue());
String output = psResult.outputUTF8();
result.setSuccess(Optional.ofNullable(StringUtils.isEmpty(lines[0]) ? null : lines[0])
.map(v -> StringUtils.equalsAnyIgnoreCase(v, "true", "1"))
.orElse(result.isSuccess()));
log.info("Exit status: {}", result.getExitStatus());
if (cfg.getExit().getSuccess().contains(result.getExitStatus())) {
result.setSuccess(true);
if (result.isSuccess()) {
if (StringUtils.equals("json", cfg.getOutput())) {
JsonObject data = GsonUtil.parseObj(output);
GsonUtil.findPrimitive(data, "success")
.map(JsonPrimitive::getAsBoolean)
.ifPresent(result::setSuccess);
GsonUtil.findObj(data, "profile")
.flatMap(p -> GsonUtil.findString(p, "display_name"))
.ifPresent(v -> result.getProfile().setDisplayName(v));
} else {
log.debug("Command output:{}{}", "\n", output);
}
}
} else if (cfg.getExit().getFailure().contains(result.getExitStatus())) {
log.debug("{} stdout:{}{}", cfg.getCommand(), "\n", output);
result.setSuccess(false);
} else {
log.error("{} stdout:{}{}", cfg.getCommand(), "\n", output);
throw new InternalServerError("Exec auth command returned with unexpected exit status");
if (lines.length == 2) {
Optional.ofNullable(StringUtils.isEmpty(lines[1]) ? null : lines[1])
.ifPresent(v -> result.getProfile().setDisplayName(v));
}
return result;
} catch (IOException | InterruptedException | TimeoutException e) {
throw new InternalServerError(e);
}
});
p.withFailureHandler(pr -> result.setSuccess(false));
p.withFailureDefault(o -> result);
return p.execute();
}
}

View File

@@ -20,27 +20,75 @@
package io.kamax.mxisd.backend.exec;
import io.kamax.matrix.MatrixID;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
import io.kamax.mxisd.directory.IDirectoryProvider;
import io.kamax.mxisd.exception.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ExecDirectoryStore extends ExecStore implements IDirectoryProvider {
private ExecConfig.Directory cfg;
private MatrixConfig mxCfg;
@Autowired
public ExecDirectoryStore(ExecConfig cfg, MatrixConfig mxCfg) {
this(cfg.getDirectory(), mxCfg);
}
public ExecDirectoryStore(ExecConfig.Directory cfg, MatrixConfig mxCfg) {
this.cfg = cfg;
this.mxCfg = mxCfg;
}
@Override
public boolean isEnabled() {
return false;
return cfg.isEnabled();
}
private UserDirectorySearchResult search(ExecConfig.Process cfg, UserDirectorySearchRequest request) {
if (StringUtils.isEmpty(cfg.getCommand())) {
return UserDirectorySearchResult.empty();
}
Processor<UserDirectorySearchResult> p = new Processor<>(cfg);
p.addJsonInputTemplate(tokens -> new UserDirectorySearchRequest(tokens.getType(), tokens.getQuery()));
p.addInputTemplate(PlainType, tokens -> tokens.getType() + System.lineSeparator() + tokens.getQuery());
p.addTokenMapper(cfg.getToken().getType(), request::getBy);
p.addTokenMapper(cfg.getToken().getQuery(), request::getSearchTerm);
p.addSuccessMapper(JsonType, output -> {
if (StringUtils.isBlank(output)) {
return UserDirectorySearchResult.empty();
}
UserDirectorySearchResult response = GsonUtil.get().fromJson(output, UserDirectorySearchResult.class);
for (UserDirectorySearchResult.Result result : response.getResults()) {
result.setUserId(MatrixID.asAcceptable(result.getUserId(), mxCfg.getDomain()).getId());
}
return response;
});
p.withFailureDefault(output -> new UserDirectorySearchResult());
return p.execute();
}
@Override
public UserDirectorySearchResult searchByDisplayName(String query) {
throw new NotImplementedException(this.getClass().getName());
return search(cfg.getSearch().getByName(), new UserDirectorySearchRequest("name", query));
}
@Override
public UserDirectorySearchResult searchBy3pid(String query) {
throw new NotImplementedException(this.getClass().getName());
return search(cfg.getSearch().getByName(), new UserDirectorySearchRequest("threepid", query));
}
}

View File

@@ -20,22 +20,56 @@
package io.kamax.mxisd.backend.exec;
import io.kamax.mxisd.exception.NotImplementedException;
import com.google.gson.JsonArray;
import com.google.gson.JsonParseException;
import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.UserID;
import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.backend.rest.LookupBulkResponseJson;
import io.kamax.mxisd.backend.rest.LookupSingleResponseJson;
import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
private final Logger log = LoggerFactory.getLogger(ExecIdentityStore.class);
private final ExecConfig.Identity cfg;
private final MatrixConfig mxCfg;
@Autowired
public ExecIdentityStore(ExecConfig cfg, MatrixConfig mxCfg) {
this(cfg.getIdentity(), mxCfg);
}
public ExecIdentityStore(ExecConfig.Identity cfg, MatrixConfig mxCfg) {
this.cfg = cfg;
this.mxCfg = mxCfg;
}
@Override
public boolean isEnabled() {
return false;
return cfg.isEnabled();
}
@Override
@@ -45,17 +79,131 @@ public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
@Override
public int getPriority() {
return 0;
return cfg.getPriority();
}
private ExecConfig.Process getSingleCfg() {
return cfg.getLookup().getSingle();
}
private _MatrixID getUserId(UserID id) {
if (Objects.isNull(id)) {
throw new JsonParseException("User id key is not present");
}
if (UserIdType.Localpart.is(id.getType())) {
return MatrixID.asAcceptable(id.getValue(), mxCfg.getDomain());
}
if (UserIdType.MatrixID.is(id.getType())) {
return MatrixID.asAcceptable(id.getValue());
}
throw new InternalServerError("Unknown user type: " + id.getType());
}
@Override
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
throw new NotImplementedException(this.getClass().getName());
Processor<Optional<SingleLookupReply>> p = new Processor<>();
p.withConfig(cfg.getLookup().getSingle());
p.addTokenMapper(getSingleCfg().getToken().getMedium(), request::getType);
p.addTokenMapper(getSingleCfg().getToken().getAddress(), request::getThreePid);
p.addJsonInputTemplate(tokens -> new ThreePid(tokens.getMedium(), tokens.getAddress()));
p.addInputTemplate(PlainType, tokens -> tokens.getMedium()
+ System.lineSeparator()
+ tokens.getAddress()
);
p.addSuccessMapper(JsonType, output -> {
if (StringUtils.isBlank(output)) {
return Optional.empty();
}
return GsonUtil.findObj(GsonUtil.parseObj(output), "lookup")
.filter(obj -> !obj.entrySet().isEmpty())
.map(json -> GsonUtil.get().fromJson(json, LookupSingleResponseJson.class))
.map(lookup -> getUserId(lookup.getId()))
.map(mxId -> new SingleLookupReply(request, mxId));
});
p.addSuccessMapper(PlainType, output -> {
String[] lines = output.split("\\R");
if (lines.length > 2) {
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
}
if (lines.length == 1 && StringUtils.isBlank(lines[0])) {
return Optional.empty();
}
String type = StringUtils.trimToEmpty(lines.length == 1 ? UserIdType.Localpart.getId() : lines[0]);
String value = StringUtils.trimToEmpty(lines.length == 2 ? lines[1] : lines[0]);
if (UserIdType.Localpart.is(type)) {
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(value, mxCfg.getDomain())));
}
if (UserIdType.MatrixID.is(type)) {
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(value)));
}
throw new InternalServerError("Invalid user type: " + type);
});
p.withFailureDefault(o -> Optional.empty());
return p.execute();
}
@Override
public List<ThreePidMapping> populate(List<ThreePidMapping> mappings) {
throw new NotImplementedException(this.getClass().getName());
Processor<List<ThreePidMapping>> p = new Processor<>();
p.withConfig(cfg.getLookup().getBulk());
p.addInput(JsonType, () -> {
JsonArray tpids = GsonUtil.asArray(mappings.stream()
.map(mapping -> GsonUtil.get().toJsonTree(new ThreePid(mapping.getMedium(), mapping.getValue())))
.collect(Collectors.toList()));
return GsonUtil.get().toJson(GsonUtil.makeObj("lookup", tpids));
});
p.addInput(PlainType, () -> {
StringBuilder input = new StringBuilder();
for (ThreePidMapping mapping : mappings) {
input.append(mapping.getMedium()).append("\t").append(mapping.getValue()).append(System.lineSeparator());
}
return input.toString();
});
p.addSuccessMapper(JsonType, output -> {
if (StringUtils.isBlank(output)) {
return Collections.emptyList();
}
LookupBulkResponseJson response = GsonUtil.get().fromJson(output, LookupBulkResponseJson.class);
return response.getLookup().stream().map(item -> {
ThreePidMapping mapping = new ThreePidMapping();
mapping.setMedium(item.getMedium());
mapping.setValue(item.getAddress());
if (UserIdType.Localpart.is(item.getId().getType())) {
mapping.setValue(MatrixID.asAcceptable(item.getId().getValue(), mxCfg.getDomain()).getId());
return mapping;
}
if (UserIdType.MatrixID.is(item.getId().getType())) {
mapping.setValue(MatrixID.asAcceptable(item.getId().getValue()).getId());
return mapping;
}
throw new InternalServerError("Invalid user type: " + item.getId().getType());
}).collect(Collectors.toList());
});
p.withFailureDefault(output -> Collections.emptyList());
return p.execute();
}
}

View File

@@ -22,34 +22,82 @@ package io.kamax.mxisd.backend.exec;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import io.kamax.mxisd.exception.NotImplementedException;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.profile.JsonProfileRequest;
import io.kamax.mxisd.profile.JsonProfileResult;
import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@Component
public class ExecProfileStore extends ExecStore implements ProfileProvider {
private ExecConfig.Profile cfg;
@Autowired
public ExecProfileStore(ExecConfig cfg) {
this(cfg.getProfile());
}
public ExecProfileStore(ExecConfig.Profile cfg) {
this.cfg = cfg;
}
@Override
public boolean isEnabled() {
return false;
return cfg.isEnabled();
}
private Optional<JsonProfileResult> getFull(_MatrixID userId, ExecConfig.Process cfg) {
Processor<Optional<JsonProfileResult>> p = new Processor<>(cfg);
p.addJsonInputTemplate(tokens -> new JsonProfileRequest(tokens.getLocalpart(), tokens.getDomain(), tokens.getMxid()));
p.addInputTemplate(PlainType, tokens -> tokens.getLocalpart() + System.lineSeparator()
+ tokens.getDomain() + System.lineSeparator()
+ tokens.getMxid() + System.lineSeparator()
);
p.addTokenMapper(cfg.getToken().getLocalpart(), userId::getLocalPart);
p.addTokenMapper(cfg.getToken().getDomain(), userId::getDomain);
p.addTokenMapper(cfg.getToken().getMxid(), userId::getId);
p.withFailureDefault(v -> Optional.empty());
p.addSuccessMapper(JsonType, output -> {
if (StringUtils.isBlank(output)) {
return Optional.empty();
}
return GsonUtil.findObj(GsonUtil.parseObj(output), "profile")
.map(obj -> GsonUtil.get().fromJson(obj, JsonProfileResult.class));
});
return p.execute();
}
@Override
public Optional<String> getDisplayName(_MatrixID userId) {
throw new NotImplementedException(this.getClass().getName());
return getFull(userId, cfg.getDisplayName()).map(JsonProfileResult::getDisplayName);
}
@Override
public List<_ThreePid> getThreepids(_MatrixID userId) {
throw new NotImplementedException(this.getClass().getName());
return getFull(userId, cfg.getThreePid())
.map(p -> Collections.<_ThreePid>unmodifiableList(p.getThreepids()))
.orElseGet(Collections::emptyList);
}
@Override
public List<String> getRoles(_MatrixID userId) {
throw new NotImplementedException(this.getClass().getName());
return getFull(userId, cfg.getRole())
.map(JsonProfileResult::getRoles)
.orElseGet(Collections::emptyList);
}
}

View File

@@ -20,8 +20,233 @@
package io.kamax.mxisd.backend.exec;
public abstract class ExecStore {
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.exception.InternalServerError;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.ProcessResult;
// no-op
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class ExecStore {
public static final String JsonType = "json";
public static final String PlainType = "plain";
protected static String toJson(Object o) {
return GsonUtil.get().toJson(o);
}
private final Logger log = LoggerFactory.getLogger(ExecStore.class);
private Supplier<ProcessExecutor> executorSupplier = () -> new ProcessExecutor().readOutput(true);
public void setExecutorSupplier(Supplier<ProcessExecutor> supplier) {
executorSupplier = supplier;
}
public class Processor<V> {
private ExecConfig.Process cfg;
private Supplier<Optional<String>> inputSupplier;
private Function<String, String> inputTypeMapper;
private Function<String, String> inputUnknownTypeMapper;
private Map<String, Supplier<String>> inputTypeSuppliers;
private Map<String, Function<ExecConfig.TokenOverride, String>> inputTypeTemplates;
private Supplier<String> inputTypeNoTemplateHandler;
private Map<String, Supplier<String>> tokenMappers;
private Function<String, String> tokenHandler;
private Consumer<ProcessResult> onExitHandler;
private Consumer<ProcessResult> successHandler;
private Map<String, Function<String, V>> successMappers;
private Function<String, V> successDefault;
private Consumer<ProcessResult> failureHandler;
private Map<String, Function<String, V>> failureMappers;
private Function<String, V> failureDefault;
private Consumer<ProcessResult> unknownHandler;
private Map<String, Function<String, V>> unknownMappers;
private Function<String, V> unknownDefault;
public Processor(ExecConfig.Process cfg) {
this();
withConfig(cfg);
}
public Processor() {
tokenMappers = new HashMap<>();
inputTypeSuppliers = new HashMap<>();
inputTypeTemplates = new HashMap<>();
withTokenHandler(tokenHandler = input -> {
for (Map.Entry<String, Supplier<String>> entry : tokenMappers.entrySet()) {
input = input.replace(entry.getKey(), entry.getValue().get());
}
return input;
});
inputTypeNoTemplateHandler = () -> cfg.getInput().getType()
.map(type -> inputTypeTemplates.get(type).apply(cfg.getToken()))
.orElse("");
inputUnknownTypeMapper = type -> tokenHandler.apply(cfg.getInput().getTemplate().orElseGet(inputTypeNoTemplateHandler));
inputTypeMapper = type -> {
if (!inputTypeSuppliers.containsKey(type)) {
return inputUnknownTypeMapper.apply(type);
}
return inputTypeSuppliers.get(type).get();
};
inputSupplier = () -> cfg.getInput().getType().map(type -> inputTypeMapper.apply(type));
withExitHandler(pr -> {
});
successHandler = pr -> {
};
successMappers = new HashMap<>();
successDefault = output -> {
log.info("{} stdout: {}{}", cfg.getCommand(), System.lineSeparator(), output);
throw new InternalServerError("Exec command has no success handler configured. This is a bug. Please report.");
};
failureHandler = pr -> {
};
failureMappers = new HashMap<>();
failureDefault = output -> {
log.info("{} stdout: {}{}", cfg.getCommand(), System.lineSeparator(), output);
throw new InternalServerError("Exec command has no failure handler configured. This is a bug. Please report.");
};
unknownHandler = pr -> log.warn("Unexpected exit status: {}", pr.getExitValue());
unknownMappers = new HashMap<>();
withUnknownDefault(output -> {
log.error("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
throw new InternalServerError("Exec command returned with unexpected exit status");
});
}
public void withConfig(ExecConfig.Process cfg) {
this.cfg = cfg;
}
public void addTokenMapper(String token, Supplier<String> data) {
tokenMappers.put(token, data);
}
public void withTokenHandler(Function<String, String> handler) {
tokenHandler = handler;
}
public void addInput(String type, Supplier<String> handler) {
inputTypeSuppliers.put(type, handler);
}
protected void addInputTemplate(String type, Function<ExecConfig.TokenOverride, String> template) {
inputTypeTemplates.put(type, template);
}
public void addJsonInputTemplate(Function<ExecConfig.TokenOverride, Object> template) {
inputTypeTemplates.put(JsonType, token -> GsonUtil.get().toJson(template.apply(token)));
}
public void withExitHandler(Consumer<ProcessResult> handler) {
onExitHandler = handler;
}
public void withSuccessHandler(Consumer<ProcessResult> handler) {
successHandler = handler;
}
public void addSuccessMapper(String type, Function<String, V> mapper) {
successMappers.put(type, mapper);
}
public void withSuccessDefault(Function<String, V> mapper) {
successDefault = mapper;
}
public void withFailureHandler(Consumer<ProcessResult> handler) {
failureHandler = handler;
}
public void addFailureMapper(String type, Function<String, V> mapper) {
failureMappers.put(type, mapper);
}
public void withFailureDefault(Function<String, V> mapper) {
failureDefault = mapper;
}
public void addUnknownMapper(String type, Function<String, V> mapper) {
unknownMappers.put(type, mapper);
}
public void withUnknownDefault(Function<String, V> mapper) {
unknownDefault = mapper;
}
public V execute() {
log.info("Executing {}", cfg.getCommand());
try {
ProcessExecutor psExec = executorSupplier.get();
List<String> args = new ArrayList<>();
args.add(tokenHandler.apply(cfg.getCommand()));
args.addAll(cfg.getArgs().stream().map(arg -> tokenHandler.apply(arg)).collect(Collectors.toList()));
psExec.command(args);
psExec.environment(new HashMap<>(cfg.getEnv()).entrySet().stream()
.peek(e -> e.setValue(tokenHandler.apply(e.getValue())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
inputSupplier.get().ifPresent(input -> psExec.redirectInput(IOUtils.toInputStream(input, StandardCharsets.UTF_8)));
ProcessResult psResult = psExec.execute();
String output = psResult.outputUTF8();
onExitHandler.accept(psResult);
if (cfg.getExit().getSuccess().contains(psResult.getExitValue())) {
successHandler.accept(psResult);
return cfg.getOutput().getType()
.map(type -> successMappers.getOrDefault(type, successDefault).apply(output))
.orElseGet(() -> successDefault.apply(output));
} else if (cfg.getExit().getFailure().contains(psResult.getExitValue())) {
failureHandler.accept(psResult);
return cfg.getOutput().getType()
.map(type -> failureMappers.getOrDefault(type, failureDefault).apply(output))
.orElseGet(() -> failureDefault.apply(output));
} else {
unknownHandler.accept(psResult);
return cfg.getOutput().getType()
.map(type -> unknownMappers.getOrDefault(type, unknownDefault).apply(output))
.orElseGet(() -> unknownDefault.apply(output));
}
} catch (RuntimeException | IOException | InterruptedException | TimeoutException e) {
log.error("Failed to execute {}", cfg.getCommand());
log.debug("Internal exception:", e);
throw new InternalServerError(e);
}
}
}
}

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -49,7 +49,7 @@ public class GoogleFirebaseProvider extends GoogleFirebaseBackend implements ITh
}
private String getMxid(UserRecord record) {
return new MatrixID(record.getUid(), domain).getId();
return MatrixID.asAcceptable(record.getUid(), domain).getId();
}
@Override

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -148,7 +148,7 @@ public class MemoryIdentityStore implements AuthenticatorProvider, IDirectoryPro
for (MemoryIdentityConfig id : cfg.getIdentities()) {
for (MemoryThreePid threepid : id.getThreepids()) {
if (req.equals(new ThreePid(threepid.getMedium(), threepid.getAddress()))) {
return Optional.of(new SingleLookupReply(request, new MatrixID(id.getUsername(), mxCfg.getDomain())));
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(id.getUsername(), mxCfg.getDomain())));
}
}
}

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -20,6 +20,7 @@
package io.kamax.mxisd.backend.rest;
import io.kamax.matrix.ThreePidMedium;
import io.kamax.mxisd.UserID;
public class LookupSingleResponseJson {
@@ -32,12 +33,28 @@ public class LookupSingleResponseJson {
return medium;
}
public void setMedium(String medium) {
this.medium = medium;
}
public void setMedium(ThreePidMedium medium) {
setMedium(medium.getId());
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public UserID getId() {
return id;
}
public void setId(UserID id) {
this.id = id;
}
}

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -62,7 +62,7 @@ public class RestDirectoryProvider extends RestProvider implements IDirectoryPro
UserDirectorySearchResult response = parser.parse(httpResponse, UserDirectorySearchResult.class);
for (UserDirectorySearchResult.Result result : response.getResults()) {
result.setUserId(new MatrixID(result.getUserId(), mxCfg.getDomain()).getId());
result.setUserId(MatrixID.asAcceptable(result.getUserId(), mxCfg.getDomain()).getId());
}
return response;

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -60,9 +60,9 @@ public class RestThreePidProvider extends RestProvider implements IThreePidProvi
// TODO refactor in lookup manager with above FIXME
private _MatrixID getMxId(UserID id) {
if (UserIdType.Localpart.is(id.getType())) {
return new MatrixID(id.getValue(), mxCfg.getDomain());
return MatrixID.asAcceptable(id.getValue(), mxCfg.getDomain());
} else {
return new MatrixID(id.getValue());
return MatrixID.asAcceptable(id.getValue());
}
}

View File

@@ -85,11 +85,11 @@ public abstract class SqlThreePidProvider implements IThreePidProvider {
log.info("Found match: {}", uid);
if (StringUtils.equals("uid", cfg.getIdentity().getType())) {
log.info("Resolving as localpart");
return Optional.of(new SingleLookupReply(request, new MatrixID(uid, mxCfg.getDomain())));
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(uid, mxCfg.getDomain())));
}
if (StringUtils.equals("mxid", cfg.getIdentity().getType())) {
log.info("Resolving as MXID");
return Optional.of(new SingleLookupReply(request, new MatrixID(uid)));
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(uid)));
}
log.info("Identity type is unknown, skipping");

View File

@@ -86,7 +86,7 @@ public abstract class GenericSqlDirectoryProvider implements IDirectoryProvider
while (rSet.next()) {
processRow(rSet).ifPresent(e -> {
if (StringUtils.equalsIgnoreCase("localpart", query.getType())) {
e.setUserId(new MatrixID(e.getUserId(), mxCfg.getDomain()).getId());
e.setUserId(MatrixID.asAcceptable(e.getUserId(), mxCfg.getDomain()).getId());
}
result.addResult(e);
});

View File

@@ -23,6 +23,7 @@ package io.kamax.mxisd.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.Objects;
@Configuration
@@ -39,6 +40,7 @@ public class BulkLookupConfig {
this.enabled = enabled;
}
@PostConstruct
public void build() {
if (Objects.isNull(enabled)) {
enabled = true;

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -31,6 +31,29 @@ import java.util.*;
@ConfigurationProperties("exec")
public class ExecConfig {
public class IO {
private String type;
private String template;
public Optional<String> getType() {
return Optional.ofNullable(type);
}
public void setType(String type) {
this.type = type;
}
public Optional<String> getTemplate() {
return Optional.ofNullable(template);
}
public void setTemplate(String template) {
this.template = template;
}
}
public class Exit {
private List<Integer> success = Collections.singletonList(0);
@@ -60,6 +83,10 @@ public class ExecConfig {
private String domain;
private String mxid;
private String password;
private String medium;
private String address;
private String type;
private String query;
public String getLocalpart() {
return StringUtils.defaultIfEmpty(localpart, getToken().getLocalpart());
@@ -93,6 +120,38 @@ public class ExecConfig {
this.password = password;
}
public String getMedium() {
return StringUtils.defaultIfEmpty(medium, getToken().getMedium());
}
public void setMedium(String medium) {
this.medium = medium;
}
public String getAddress() {
return StringUtils.defaultIfEmpty(address, getToken().getAddress());
}
public void setAddress(String address) {
this.address = address;
}
public String getType() {
return StringUtils.defaultIfEmpty(type, getToken().getType());
}
public void setType(String type) {
this.type = type;
}
public String getQuery() {
return StringUtils.defaultIfEmpty(query, getToken().getQuery());
}
public void setQuery(String query) {
this.query = query;
}
}
public class Token {
@@ -101,6 +160,10 @@ public class ExecConfig {
private String domain = "{domain}";
private String mxid = "{mxid}";
private String password = "{password}";
private String medium = "{medium}";
private String address = "{address}";
private String type = "{type}";
private String query = "{query}";
public String getLocalpart() {
return localpart;
@@ -134,6 +197,38 @@ public class ExecConfig {
this.password = password;
}
public String getMedium() {
return medium;
}
public void setMedium(String medium) {
this.medium = medium;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
public class Process {
@@ -143,10 +238,10 @@ public class ExecConfig {
private List<String> args = new ArrayList<>();
private Map<String, String> env = new HashMap<>();
private String input;
private IO input = new IO();
private Exit exit = new Exit();
private String output;
private IO output = new IO();
public TokenOverride getToken() {
return token;
@@ -184,11 +279,11 @@ public class ExecConfig {
this.env.put(key, value);
}
public String getInput() {
public IO getInput() {
return input;
}
public void setInput(String input) {
public void setInput(IO input) {
this.input = input;
}
@@ -200,11 +295,11 @@ public class ExecConfig {
this.exit = exit;
}
public String getOutput() {
public IO getOutput() {
return output;
}
public void setOutput(String output) {
public void setOutput(IO output) {
this.output = output;
}
@@ -224,9 +319,33 @@ public class ExecConfig {
}
public class Directory extends Process {
public class Directory {
public class Search {
private Process byName = new Process();
private Process byThreepid = new Process();
public Process getByName() {
return byName;
}
public void setByName(Process byName) {
this.byName = byName;
}
public Process getByThreepid() {
return byThreepid;
}
public void setByThreepid(Process byThreepid) {
this.byThreepid = byThreepid;
}
}
private Boolean enabled;
private Search search = new Search();
public Boolean isEnabled() {
return enabled;
@@ -236,25 +355,44 @@ public class ExecConfig {
this.enabled = enabled;
}
public Search getSearch() {
return search;
}
public void setSearch(Search search) {
this.search = search;
}
}
public class Identity extends Process {
public class Lookup {
private Boolean enabled;
private Process single = new Process();
private Process bulk = new Process();
public Boolean isEnabled() {
return enabled;
public Process getSingle() {
return single;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
public void setSingle(Process single) {
this.single = single;
}
public Process getBulk() {
return bulk;
}
public void setBulk(Process bulk) {
this.bulk = bulk;
}
}
public class Profile extends Process {
public class Identity {
private Boolean enabled;
private int priority;
private Lookup lookup = new Lookup();
public Boolean isEnabled() {
return enabled;
@@ -264,6 +402,63 @@ public class ExecConfig {
this.enabled = enabled;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public Lookup getLookup() {
return lookup;
}
public void setLookup(Lookup lookup) {
this.lookup = lookup;
}
}
public class Profile {
private Boolean enabled;
private Process displayName = new Process();
private Process threePid = new Process();
private Process role = new Process();
public Boolean isEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Process getDisplayName() {
return displayName;
}
public void setDisplayName(Process displayName) {
this.displayName = displayName;
}
public Process getThreePid() {
return threePid;
}
public void setThreePid(Process threePid) {
this.threePid = threePid;
}
public Process getRole() {
return role;
}
public void setRoles(Process role) {
this.role = role;
}
}
private boolean enabled;
@@ -322,7 +517,7 @@ public class ExecConfig {
}
@PostConstruct
public void build() {
public ExecConfig compute() {
if (Objects.isNull(getAuth().isEnabled())) {
getAuth().setEnabled(isEnabled());
}
@@ -338,6 +533,8 @@ public class ExecConfig {
if (Objects.isNull(getProfile().isEnabled())) {
getProfile().setEnabled(isEnabled());
}
return this;
}
}

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,6 +1,6 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Maxime Dor
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*

View File

@@ -1,6 +1,6 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Maxime Dor
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*

View File

@@ -1,6 +1,6 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Maxime Dor
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,6 +1,6 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Maxime Dor
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*

View File

@@ -89,19 +89,20 @@ public class AppServiceController {
}
@RequestMapping(value = "/transactions/{txnId:.+}", method = PUT)
public Object getTransaction(
public String getTransaction(
HttpServletRequest request,
@RequestParam(name = "access_token", required = false) String token,
@PathVariable String txnId) {
try {
validateToken(token);
log.info("Processing transaction {}", txnId);
log.info("Transaction {}: Processing start", txnId);
List<JsonObject> events = GsonUtil.asList(GsonUtil.getArray(parser.parse(request.getInputStream()), "events"), JsonObject.class);
log.debug("Transaction {}: {} events to process", txnId, events.size());
handler.processTransaction(events);
return "{}";
log.info("Transaction {}: Processing end", txnId);
} catch (Throwable e) {
log.warn("Unable to properly process transaction", e);
log.error("Unable to properly process transaction {}", txnId, e);
}
return "{}";

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -29,6 +29,11 @@ public class UserDirectorySearchRequest {
setSearchTerm(searchTerm);
}
public UserDirectorySearchRequest(String type, String searchTerm) {
setBy(type);
setSearchTerm(searchTerm);
}
public String getBy() {
return by;
}

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -25,6 +25,10 @@ import java.util.Set;
public class UserDirectorySearchResult {
public static UserDirectorySearchResult empty() {
return new UserDirectorySearchResult();
}
public static class Result {
private String displayName;

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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
@@ -73,7 +73,7 @@ class InvitationController {
for (String key : request.getParameterMap().keySet()) {
parameters.put(key, request.getParameter(key));
}
IThreePidInvite invite = new ThreePidInvite(new MatrixID(sender), medium, address, roomId, parameters);
IThreePidInvite invite = new ThreePidInvite(MatrixID.asAcceptable(sender), medium, address, roomId, parameters);
IThreePidInviteReply reply = mgr.storeInvite(invite);
return gson.toJson(new ThreePidInviteReplyIO(reply, keyMgr.getPublicKeyBase64(keyMgr.getCurrentIndex()), srvCfg.getPublicUrl()));

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

View File

@@ -1,8 +1,8 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
* Copyright (C) 2017 Kamax Sarl
*
* https://max.kamax.io/
* 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

Some files were not shown because too many files have changed in this diff Show More