1 Commits

Author SHA1 Message Date
ae83ea1404 further implementing of multilanguage 2018-03-26 23:13:26 +02:00
23 changed files with 1117 additions and 1598 deletions

5
.gitignore vendored
View File

@@ -1,5 +1,2 @@
config.php config.php
db_file.sqlite db_file.sqlite
# do not track sources which will be built by composer
/vendor/

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,177 +13,157 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
class MatrixConnection
{
private $hs;
private $at;
require_once(__DIR__ . "/helpers.php"); function __construct($homeserver, $access_token) {
$this->hs = $homeserver;
$this->at = $access_token;
}
class MatrixConnection { function send($room_id, $message) {
if (!$this->at) {
error_log("No access token defined");
return false;
}
private $hs; $send_message = NULL;
private $at; if (!$message) {
error_log("no message to send");
return false;
} elseif(is_array($message)) {
$send_message = $message;
} elseif ($message instanceof MatrixMessage) {
$send_message = $message->get_object();
} else {
error_log("message is of not valid type\n");
return false;
}
function __construct($homeserver, $access_token) { $url="https://".$this->hs."/_matrix/client/r0/rooms/"
$this->hs = $homeserver; . urlencode($room_id) ."/send/m.room.message?access_token=".$this->at;
$this->at = $access_token; $handle = curl_init($url);
} curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($send_message));
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
function send($room_id, $message) { $response = $this->exec_curl_request($handle);
if (!$this->at) { return isset($response["event_id"]);
error_log("No access token defined"); }
return false;
}
$send_message = NULL; function send_msg($room_id, $message) {
if (!$message) { return $this->send($room_id, array(
error_log("no message to send"); "msgtype" => "m.notice",
return false; "body" => $message
} elseif (is_array($message)) { )
$send_message = $message; );
} elseif ($message instanceof MatrixMessage) { }
$send_message = $message->get_object();
} else {
error_log("message is of not valid type\n");
return false;
}
$url = "https://" . $this->hs . "/_matrix/client/r0/rooms/" function hasUser($username) {
. urlencode($room_id) . "/send/m.room.message?access_token=" . $this->at; if (!$username) {
$handle = getCurlHandle($url); throw new Exception ("no user given to lookup");
curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($send_message)); }
$response = $this->exec_curl_request($handle); $url = "https://".$this->hs."/_matrix/client/r0/profile/@" . $username . ":" . $this->hs;
return isset($response["event_id"]); $handle = curl_init($url);
} curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
function send_msg($room_id, $message) { $res = $this->exec_curl_request($handle);
return $this->send($room_id, array( return !(isset($res["errcode"]) && $res["errcode"] == "M_UNKNOWN");
"msgtype" => "m.notice", }
"body" => $message
)
);
}
function hasUser($username) { function register($username, $password, $shared_secret) {
if (!$username) { if (!$username) {
throw new Exception("no user given to lookup"); error_log("no username provided");
} }
if (!$password) {
error_log("no message to send");
}
$url = "https://" . $this->hs . "/_matrix/client/r0/profile/@" . $username . ":" . $this->hs; $mac = hash_hmac('sha1', $username, $shared_secret);
$handle = getCurlHandle($url);
$res = $this->exec_curl_request($handle); $data = array(
return !(isset($res["errcode"]) && $res["errcode"] == "M_UNKNOWN"); "username" => $username,
} "password" => $password,
"mac" => $mac,
);
$url = "https://".$this->hs."/_matrix/client/v2_alpha/register";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($data));
function getRegisterNonce() { return $this->exec_curl_request($handle);
$url = "https://" . $this->hs . "/_matrix/client/r0/admin/register"; }
$handle = getCurlHandle($url);
try { function exec_curl_request($handle) {
$response = $this->exec_curl_request($handle); $response = curl_exec($handle);
if (is_array($response) && isset($response["nonce"])) {
return $response["nonce"];
}
throw new Exception("INVALID_RESPONSE_FROM_SERVER");
} catch (Exception $e) {
if (strcmp("AUTHENTICATION_FAILED", $e->getMessage()) == 0) {
throw new Exception("WRONG_REGISTRATION_SHARED_SECRET");
} else {
throw $e;
}
}
}
function register($username, $password, $shared_secret) { if ($response === false) {
if (!$username) { $errno = curl_errno($handle);
error_log("no username provided"); $error = curl_error($handle);
} error_log("Curl returned error $errno: $error\n");
if (!$password) { curl_close($handle);
error_log("no password provided"); return false;
} }
$nonce = $this->getRegisterNonce();
//TODO allow registering of admin.
$hmac_content = $nonce . "\x00" . $username . "\x00" . $password . "\x00notadmin";
$mac = hash_hmac('sha1', $hmac_content, $shared_secret);
$data = array( $http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
"nonce" => $nonce, curl_close($handle);
"username" => $username,
"password" => $password,
"mac" => $mac,
);
$url = "https://" . $this->hs . "/_matrix/client/r0/admin/register";
$handle = getCurlHandle($url);
curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($data));
try { if ($http_code >= 500) {
return $this->exec_curl_request($handle); // do not want to DDOS server if something goes wrong
} catch (Exception $e) { sleep(10);
if (strcmp("AUTHENTICATION_FAILED", $e->getMessage()) == 0) { return false;
throw new Exception("WRONG_REGISTRATION_SHARED_SECRET"); } else if ($http_code != 200) {
} else { $response = json_decode($response, true);
throw $e; error_log("Request has failed with error {$response['error']}\n");
} if ($http_code == 401) {
} throw new Exception('Invalid access token provided');
} }
} else {
function exec_curl_request($handle) { $response = json_decode($response, true);
$response = curl_exec($handle); }
if ($response === false) {
$errno = curl_errno($handle);
$error = curl_error($handle);
error_log("Curl returned error $errno: $error\n");
curl_close($handle);
return false;
}
$http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
curl_close($handle);
if ($http_code >= 500) {
// do not want to DDOS server if something goes wrong
sleep(10);
return false;
} else if ($http_code != 200) {
$response = json_decode($response, true);
error_log("Request has failed with error {$response['error']}\n");
if ($http_code == 401) {
throw new Exception("AUTHENTICATION_FAILED");
}
} else {
$response = json_decode($response, true);
}
return $response;
}
return $response;
}
} }
class MatrixMessage { class MatrixMessage
{
private $message;
private $message; function __construct() {
$this->message = ["msgtype" => "m.notice"];
}
function __construct() { function set_type($msgtype) {
$this->message = ["msgtype" => "m.notice"]; $this->message["msgtype"] = $msgtype;
} }
function set_type($msgtype) { function set_format($format) {
$this->message["msgtype"] = $msgtype; $this->message["format"] = $format;
} }
function set_format($format) { function set_body($body) {
$this->message["format"] = $format; $this->message["body"] = $body;
} }
function set_body($body) { function set_formatted_body($fbody, $format="org.matrix.custom.html") {
$this->message["body"] = $body; $this->message["formatted_body"] = $fbody;
} $this->message["format"] = $format;
}
function set_formatted_body($fbody, $format = "org.matrix.custom.html") { function get_object() {
$this->message["formatted_body"] = $fbody; return $this->message;
$this->message["format"] = $format; }
}
function get_object() {
return $this->message;
}
} }
?> ?>

View File

@@ -1,55 +1,27 @@
# matrix-register-bot # matrix-register-bot
![state: alpha](https://img.shields.io/badge/state-alpha-yellowgreen.svg)
[![#matrix-register-bot:msg-net.de](https://img.shields.io/badge/matrix-%23matrix--register--bot%3Amsg--net.de-brightgreen.svg)](https://matrix.to/#/#matrix-register-bot:msg-net.de)
This bot provides a two-step-registration for matrix ([synapse](https://github.com/matrix-org/synapse)). This bot provides a two-step-registration for matrix.
This is done in several steps: This is done in several steps:
- potential new user registers on a bot-provided site - potential new user registers on a bot-provided side
- user has to verify its mail address
- bot sends a message to predefined room with a registration notification. - bot sends a message to predefined room with a registration notification.
- users in that room now can approve or decline the registration. - users in that room now can approve or decline the registration.
- When approved - When approved
- the bot creates short time credentials - the bot creates credentials
- sends them to the user - sends them to the user
- stores them encrypted in own databas or uses that as initial password for registration - stores them encrypted in own database
- provides that credentials to [matrix-synapse-rest-auth](https://github.com/kamax-io/matrix-synapse-rest-auth#integrate) which has to be configured to query login.php
There are two operation modes available: 2nd step: Implement the other apis to integrade [mxisd](https://github.com/kamax-io/mxisd/blob/master/docs/backends/rest.md)
- `operationMode=synapse`
- No adjustments on your running environment are required. This bot uses the the [Shared-Secret Registration of synapse](https://github.com/matrix-org/synapse/blob/master/docs/admin_api/register_api.rst) to register the users.
- `operationMode=local`:
- Bot handles user management. Therefore it stores the user-data and uses [matrix-synapse-rest-auth](https://github.com/kamax-io/matrix-synapse-rest-auth#integrate) to authenticate the users.
- This way it is possible to set the display name of a user on first login (first- and lastname instead of username)
- The email address of the user can be used to implement third party lookup (requires [mxisd](https://github.com/kamax-io/mxisd/blob/master/docs/stores/rest.md))
- search for users you have not seen yet but are available on the server
## Requirements
- Working PHP environment with
- database connection provider \[one of sqlite, mysql, postgres\]
- curl extension
- mail capability to interact with the users (verification, approval (+ initial password), notifications)
- either via sendmail or with credentials
- [composer](https://getcomposer.org) installed
- [matrix-synapse-rest-auth](https://github.com/kamax-io/matrix-synapse-rest-auth) when using `operationMode=local`
## How to install ## How to install
``` - Copy `config.sample.php` to `config.php` and configure the bot as you can find there
git clone https://github.com/krombel/matrix-register-bot - Configure your webserver to publish the folder `public` and configure.
cd matrix-register-bot The folder `internal` contains files that can be accessed by mxisd or matrix-synapse-rest-auth
composer install - To integrate with matrix-synapse-rest-auth:
cp config.sample.php config.php
editor config.php
```
- Configure your webserver to have the folder `public` accessible via web.
When running `operationMode=local`:
- Configure your webserver to provide the folder `internal` internally. This is only meant to be accessible by mxisd and matrix-synapse-rest-auth
- To integrate with [matrix-synapse-rest-auth](https://github.com/kamax-io/matrix-synapse-rest-auth):
- `/_matrix-internal/identity/v1/check_credentials` should map to `internal/login.php` - `/_matrix-internal/identity/v1/check_credentials` should map to `internal/login.php`
- To integrate with [mxisd](https://github.com/kamax-io/mxisd): Have a look at [the docs of mxisd](https://github.com/kamax-io/mxisd/blob/master/docs/stores/rest.md) and apply as follows: - To integrate with mxisd: Have a look at [the docs](https://github.com/kamax-io/mxisd/blob/master/docs/backends/rest.md) and apply as follows:
| Key | file which handles that | Description | | Key | file which handles that | Description |
@@ -58,27 +30,3 @@ When running `operationMode=local`:
| rest.endpoints.directory | internal/directory_search.php | Search for users by arbitrary input | | rest.endpoints.directory | internal/directory_search.php | Search for users by arbitrary input |
| rest.endpoints.identity.single | internal/identity_single.php | Endpoint to query a single 3PID | | rest.endpoints.identity.single | internal/identity_single.php | Endpoint to query a single 3PID |
| rest.endpoints.identity.bulk | internal/identity_bulk.php | Endpoint to query a list of 3PID | | rest.endpoints.identity.bulk | internal/identity_bulk.php | Endpoint to query a list of 3PID |
## Further notes:
### Security: Passwords from registration form are stored in clear text
Currently the passwords which are typed in while capturing the register request are stored in clear text.
The bot needs to access them to trigger a register request with correct credentials.
It is currently strongly recommended to set `"getPasswordOnRegistration" => false` in your config!
This leads to autocreating passwords which will then be send to the users directly without storing it.
### Use the ChangePasswortInterceptor (if `operationMode=local`)
To allow users to change their pasword you need a reverse proxy which maps `/_matrix/client/r0/account/password` to `internal/intercept_change_password.php`.
Here is an example for nginx:
```
location /_matrix/client/r0/account/password {
proxy_pass http://localhost/mxbot/internal/intercept_change_password.php;
proxy_set_header X-Forwarded-For $remote_addr;
}
```
### The bot postpones some actions
There is a cron.php which implements retries and database cleanups (e.g. to remove a username claim)
For this run cron.php regularly with your system of choice.
A suggested interval is once per day

View File

@@ -1,15 +0,0 @@
{
"name": "krombel/matrix-register-bot",
"description": "Register-Bot which implements a 2-factor registration for synapse servers to take part on matrix-communication",
"type": "project",
"require": {
"phpmailer/phpmailer": "^6.0"
},
"license": "Apache-2.0",
"authors": [
{
"name": "Krombel",
"email": "krombel@krombel.de"
}
]
}

84
composer.lock generated
View File

@@ -1,84 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6d67203b6e9fc952ae681c538683a497",
"packages": [
{
"name": "phpmailer/phpmailer",
"version": "v6.0.6",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "8190d73eb5def11a43cfb020b7f36db65330698c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/8190d73eb5def11a43cfb020b7f36db65330698c",
"reference": "8190d73eb5def11a43cfb020b7f36db65330698c",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-filter": "*",
"php": ">=5.5.0"
},
"require-dev": {
"doctrine/annotations": "1.2.*",
"friendsofphp/php-cs-fixer": "^2.2",
"phpdocumentor/phpdocumentor": "2.*",
"phpunit/phpunit": "^4.8 || ^5.7",
"zendframework/zend-eventmanager": "3.0.*",
"zendframework/zend-i18n": "2.7.3",
"zendframework/zend-serializer": "2.7.*"
},
"suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Jim Jagielski",
"email": "jimjag@gmail.com"
},
{
"name": "Marcus Bointon",
"email": "phpmailer@synchromedia.co.uk"
},
{
"name": "Andy Prevost",
"email": "codeworxtech@users.sourceforge.net"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"time": "2018-11-16T00:41:32+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}

View File

@@ -1,51 +1,29 @@
<?php <?php
$config = [ $config = [
"homeserver" => "example.com", "homeserver" => "example.com",
"access_token" => "To be used for sending the registration notification", "access_token" => "To be used for sending the registration notification",
// Which e-mail-adresse shall the bot use to send e-mails? // Which e-mail-adresse shall the bot use to send e-mails?
"register_email" => 'register_bot@example.com', "register_email" => 'register_bot@example.com',
// Where should the bot post registration requests to?
"register_room" => '$registerRoomID:example.com',
// which settings should be used to send via SMTP Gateway? // Where is the public part of the bot located? make sure you have a / at the end
"smtp" => [ "webroot" => "https://myregisterdomain.net/",
"host" => "localhost",
"port" => "25",
// use authentication?
"user" => "register@example.com",
"password" => "SecretEMailPassword",
// Use some encryption to SMTP-Server? [ssl, tls] or unset
"encryption" => False
],
// Where should the bot post registration requests to? // optional: Do you have a place where howTo's are located? If not leave this value out
"register_room" => '$registerRoomID:example.com', "howToURL" => "https://my-url-for-storing-howTos.net",
// Where is the public part of the bot located? make sure you have a / at the end // When you want to collect the password on registration set this to true
"webroot" => "https://myregisterdomain.net/", "getPasswordOnRegistration" => false,
// optional: Do you have a place where howTo's are located? If not leave this value out // to define where the data should be stored:
"howToURL" => "https://my-url-for-storing-howTos.net", "databaseURI" => "sqlite:" . dirname(__FILE__) . "/db_file.sqlite",
// credentials for sqlite not used
"databaseUser" => "dbUser123",
"databasePass" => "secretPassword",
// set the mode of operation. Basically this defines where the data is stored: // default language: one of [ en-gb | de-de ]
// - synapse (using the register endpoint - so no further auth config necessary "defaultLanguage" => "en-gb"
// - local (recommended; using a table in the database to store credentials; ]
// synapse has to be configured to use that)
"operationMode" => "local",
// This setting is only required for operationMode = synapse
"registration_shared_secret" => "SOME_SECRET_KEY_FROM_HOMESERVER_CONFIG",
// When you want to collect the password on registration set this to true
// only evaluated when operationMode = local
"getPasswordOnRegistration" => false,
// default language: one of [ en-gb | de-de ]
"defaultLanguage" => "en-gb",
// to define where the data should be stored:
"databaseURI" => "sqlite:" . dirname(__FILE__) . "/db_file.sqlite",
// credentials for sqlite not used
"databaseUser" => "dbUser123",
"databasePass" => "secretPassword",
]
?> ?>

204
cron.php
View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,133 +13,94 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/config.php"); require_once("config.php");
require_once(__DIR__ . "/language.php"); require_once("mail_templates.php");
require_once(__DIR__ . "/mail_templates.php"); require_once("database.php");
require_once(__DIR__ . "/database.php");
$sql = "SELECT id, first_name, last_name, username, password, email," $sql = "SELECT id, first_name, last_name, username, email, state, note, verify_token, admin_token FROM registrations "
. " state, note, verify_token, admin_token " ."WHERE state = ". RegisterState::PendingEmailSend
. "FROM registrations " . " OR state = " . RegisterState::PendingAdminSend
. "WHERE state = " . RegisterState::PendingEmailSend . " OR state = " . RegisterState::PendingRegistration
. " OR state = " . RegisterState::PendingAdminSend . " OR state = " . RegisterState::PendingSendRegistrationMail
. " OR state = " . RegisterState::PendingRegistration . " OR state = " . RegisterState::RegistrationDeclined
. " OR state = " . RegisterState::PendingSendRegistrationMail . ";"; . " OR state = " . RegisterState::AllDone . ";";
foreach ($mx_db->query($sql) as $row) { foreach ($mx_db->query($sql) as $row) {
$first_name = $row["first_name"]; $first_name = $row["first_name"];
$last_name = $row["last_name"]; $last_name = $row["last_name"];
$username = $row["username"]; $username = $row["username"];
$email = $row["email"]; $email = $row["email"];
$state = $row["state"]; $state = $row["state"];
try { try {
switch ($state) { switch ($state) {
case RegisterState::PendingEmailSend: case RegisterState::PendingEmailSend:
$verify_url = $config["webroot"] . "/verify.php?t=" . $row["verify_token"]; $verify_url = $config["webroot"] . "/verify.php?t=" . $row["verify_token"];
$success = send_mail_pending_verification( $success = send_mail_pending_verification(
$config["homeserver"], $row["first_name"] . " " . $row["last_name"], $row["email"], $verify_url); $config["homeserver"],
$row["first_name"] . " " . $row["last_name"],
$row["email"],
$verify_url);
if ($success) { if ($success) {
$mx_db->setRegistrationStateById(RegisterState::PendingEmailVerify, $row["id"]); $mx_db->setRegistrationStateById(RegisterState::PendingEmailVerify, $row["id"]);
} else { } else {
throw new Exception("Could not send mail to " . $row["first_name"] . " " . $row["last_name"] . "(" . $row["id"] . ")"); throw new Exception("Could not send mail to ".$row["first_name"]." ".$row["last_name"]."(".$row["id"].")");
} }
break; break;
case RegisterState::PendingAdminSend: case RegisterState::PendingAdminSend:
require_once(__DIR__ . "/MatrixConnection.php"); require_once("MatrixConnection.php");
$adminUrl = $config["webroot"] . "/verify_admin.php?t=" . $row["admin_token"]; $adminUrl = $config["webroot"] . "/verify_admin.php?t=" . $row["admin_token"];
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); $mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]);
$mxMsg = new MatrixMessage(); $mxMsg = new MatrixMessage();
$mxMsg->set_body(strtr($language["MSG_USER_WANTS_REGISTER"], [ $mxMsg->set_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:\r\n"
"@name" => (strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username), . $row["note"] . "\r\n"
"@note" => $note, . "Zum Bearbeiten hier klicken:\r\n" . $adminUrl);
"@adminUrl" => $adminUrl $mxMsg->set_formatted_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:<br />"
])); . $row["note"] . "<br />"
if (isset($language["MSG_USER_WANTS_REGISTER_FORMATTED"])) { . "Zum Bearbeiten <a href=\"". $adminUrl . "\">hier</a> klicken");
$mxMsg->set_formatted_body(strtr($language["MSG_USER_WANTS_REGISTER_FORMATTED"], [ $mxMsg->set_type("m.text");
"@name" => (strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username), $response = $mxConn->send($config["register_room"], $mxMsg);
"@note" => $note,
"@adminUrl" => $adminUrl
]));
}
$mxMsg->set_type("m.text");
$response = $mxConn->send($config["register_room"], $mxMsg);
if ($response) { if ($response) {
$mx_db->setRegistrationStateById(RegisterState::PendingAdminVerify, $row["id"]); $mx_db->setRegistrationStateById(RegisterState::PendingAdminVerify, $row["id"]);
send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email); send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email);
} else { } else {
throw new Exception("Could not send notification for " . $row["first_name"] . " " . $row["last_name"] . "(" . $row["id"] . ") to admins."); throw new Exception("Could not send notification for ".$row["first_name"]." ".$row["last_name"]."(".$row["id"].") to admins.");
} }
break; break;
case RegisterState::PendingRegistration: case RegisterState::PendingRegistration:
// Registration got accepted but registration failed // Registration got accepted but registration failed
switch ($config["operationMode"]) {
case "synapse":
// register with registration_shared_secret
// generate a password with 10 characters
$password = bin2hex(openssl_random_pseudo_bytes(5));
$res = $mxConn->register($row["username"], $password, $config["registration_shared_secret"]);
if (!$res) {
// something went wrong while registering
$password = NULL;
}
break;
case "local":
// register by adding a user to the local database
$password = $mx_db->addUser($row["first_name"], $row["last_name"], $row["username"], $row["password"], $row["email"]);
break;
default:
throw new Exception("Unknown operationMode");
}
if ($password != NULL) {
// send registration_success
$res = send_mail_registration_success(
$config["homeserver"], strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username, $email, $username, $password, $config["howToURL"]
);
if ($res) {
$mx_db->setRegistrationStateById(RegisterState::AllDone, $row["id"]);
} else {
$mx_db->setRegistrationStateById(RegisterState::PendingSendRegistrationMail, $row["id"]);
}
} else {
send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email);
$mxMsg = new MatrixMessage();
$mxMsg->set_type("m.text");
$mxMsg->set_body(strtr($language["REGISTRATION_FAILED_FOR"], [
"@name" => strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username,
]));
$mxConn->send($config["register_room"], $mxMsg);
throw new Exception($language["REGISTRATION_FAILED"]);
}
break;
case RegisterState::PendingSendRegistrationMail:
print ("Error: Unhandled state: PendingSendRegistrationMail for " . $first_name . " " . $last_name . " (" . $username . ")\n");
break;
}
} catch (Exception $e) {
print("Error while handling cron for " . $first_name . " " . $last_name . " (" . $username . ")\n");
print($e->getMessage());
}
}
try { $password = $mx_db->addUser($row["first_name"], $row["last_name"], $row["username"], $row["email"]);
//cleanup: all finished entries older than one month if ($password != NULL) {
$timestamp = date('Y-m-d H:m:s', strtotime("-1 month")); // send registration_success
$mx_db->query("DELETE FROM registrations " $res = send_mail_registration_success($config["homeserver"], $first_name . " " . $last_name, $email, $username, $password, $config["howToURL"]);
. "WHERE request_date < '$timestamp'" if ($res) {
. " AND (state = " . RegisterState::RegistrationDeclined $mx_db->setRegistrationStateById(RegisterState::AllDone, $row["id"]);
. " OR state = " . RegisterState::AllDone . " );" } else {
); $mx_db->setRegistrationStateById(RegisterState::PendingSendRegistrationMail, $row["id"]);
//cleanup: all entries which are pending email registration older than two days }
$timestamp = date('Y-m-d H:m:s', strtotime("-2 days")); } else {
$mx_db->query("DELETE FROM registrations " send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email);
. "WHERE request_date < '$timestamp'" $mxMsg = new MatrixMessage();
. " AND state = " . RegisterState::PendingEmailVerify . ";" $mxMsg->set_type("m.text");
); $mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . ".");
} catch (Exception $e) { $mxConn->send($config["register_room"], $mxMsg);
print("Error while database cleanup\n"); throw new Exception($language["REGISTRATION_FAILED"]);
print($e->getMessage()); }
break;
case RegisterState::PendingSendRegistrationMail:
print ("Error: Unhandled state: PendingSendRegistrationMail for " . $first_name . " " . $last_name . " (" . $username . ")\n");
break;
case RegisterState::RegistrationDeclined:
case RegisterState::AllDone:
// do reqular cleanup
break;
}
} catch (Exception $e) {
print("Error while handling cron for " . $first_name . " " . $last_name . " (" . $username . ")\n");
print($e->getMessage());
}
} }
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,78 +13,80 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/config.php"); require_once("config.php");
if (!isset($config["databaseURI"])) { if (!isset($config["databaseURI"])) {
throw new Exception("malformed configuration: databaseURI not defined"); throw new Exception ("malformed configuration: databaseURI not defined");
} }
abstract class RegisterState { abstract class RegisterState
{
// Sending an E-Mail failed in the first attempt. Will retry later
const PendingEmailSend = 0;
// User got a mail. We wait for it to verfiy
const PendingEmailVerify = 1;
// Sending a message to the register room failed on first attempt
const PendingAdminSend = 5;
// No admin has verified the registration yet
const PendingAdminVerify = 6;
// Registration failed on first attempt. Will retry
const PendingRegistration = 7;
// Sending an E-Mail failed in the first attempt. Will retry later // in this case we have to reset the password of the user (or should we store it for this case?)
const PendingEmailSend = 0; const PendingSendRegistrationMail = 8;
// User got a mail. We wait for it to verfiy
const PendingEmailVerify = 1;
// Sending a message to the register room failed on first attempt
const PendingAdminSend = 5;
// No admin has verified the registration yet
const PendingAdminVerify = 6;
// Registration failed on first attempt. Will retry
const PendingRegistration = 7;
// in this case we have to reset the password of the user (or should we store it for this case?)
const PendingSendRegistrationMail = 8;
// State to allow persisting in the database although an admin declined it.
// Will be removed regularly
const RegistrationAccepted = 7;
const RegistrationDeclined = 13;
// User got successfully registered. Will be cleaned up later
const AllDone = 100;
// State to allow persisting in the database although an admin declined it.
// Will be removed regularly
const RegistrationAccepted = 7;
const RegistrationDeclined = 13;
// User got successfully registered. Will be cleaned up later
const AllDone = 100;
} }
class mxDatabase { class mxDatabase
{
private $db = NULL;
private $db = NULL; /**
* Creates mxDatabase object
/** * @param config object which has following members:
* Creates mxDatabase object * databaseURI: path to the sqlite file where the credentials should be stored
* @param config object which has following members: * or a param which can be used to connect to a database with PDO
* databaseURI: path to the sqlite file where the credentials should be stored * databaseUser and databasePass when authentication is required
* or a param which can be used to connect to a database with PDO * register_email which email does the register bot have (here used for providing lookup)
* databaseUser and databasePass when authentication is required */
* register_email which email does the register bot have (here used for providing lookup) function __construct($config) {
*/ if (empty($config)) {
function __construct($config) { throw new Exception("config is empty");
if (empty($config)) { }
throw new Exception("config is empty"); if (!isset($config["databaseURI"])) {
} throw new Exception("'databaseURI' not defined");
if (!isset($config["databaseURI"])) { }
throw new Exception("'databaseURI' not defined"); $db_input = $config["databaseURI"];
} $user = '';
$db_input = $config["databaseURI"]; $password = '';
$user = ''; if (isset($config["databaseUser"]) && isset($config["databasePass"])) {
$password = ''; // only use it when both are defined
if (isset($config["databaseUser"]) && isset($config["databasePass"])) { $user = $config["databaseUser"];
// only use it when both are defined $password = $config["databasePass"];
$user = $config["databaseUser"]; }
$password = $config["databasePass"]; // create database file when not existent yet
} $this->db = new PDO($db_input, $user, $password);
// create database file when not existent yet $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db = new PDO($db_input, $user, $password); $this->db->exec("CREATE TABLE IF NOT EXISTS registrations(
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->exec("CREATE TABLE IF NOT EXISTS registrations(
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
state INT DEFAULT 0, state INT DEFAULT 0,
first_name TEXT, first_name TEXT,
last_name TEXT, last_name TEXT,
username TEXT, username TEXT,
password TEXT DEFAULT '', password_hash TEXT DEFAULT '',
note TEXT, note TEXT,
email TEXT, email TEXT,
verify_token TEXT, verify_token TEXT,
admin_token TEXT, admin_token TEXT,
request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)"); )");
$this->db->exec("CREATE TABLE IF NOT EXISTS logins ( $this->db->exec("CREATE TABLE IF NOT EXISTS logins (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
active INT DEFAULT 1, active INT DEFAULT 1,
first_name TEXT, first_name TEXT,
@@ -96,276 +97,273 @@ class mxDatabase {
create_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, create_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)"); )");
// make sure the bot is allowed to login // make sure the bot is allowed to login
if (!$this->userRegistered("register_bot")) { if (!$this->userRegistered("register_bot")) {
$password = $this->addUser("Register", "Bot", "register_bot", NULL, $config["register_email"]); $password = $this->addUser("Register", "Bot", "register_bot", $config["register_email"]);
$config["register_password"] = $password; $config["register_password"] = $password;
$myfile = fopen(dirname(__FILE__) . "/config.json", "w"); $myfile = fopen(dirname(__FILE__) . "/config.json", "w");
fwrite($myfile, json_encode($config, JSON_PRETTY_PRINT)); fwrite($myfile, json_encode($config, JSON_PRETTY_PRINT));
fclose($myfile); fclose($myfile);
} }
// set writeable when not set already // set writeable when not set already
if (strpos($db_input, "sqlite") === 0) { if (strpos($db_input, "sqlite") === 0) {
$sqlite_file = substr($db_input, strlen("sqlite:")); $sqlite_file = substr($db_input, strlen("sqlite:"));
if (!is_writable($sqlite_file)) { if (!is_writable($sqlite_file)) {
chmod($sqlite_file, 0660); chmod($sqlite_file, 0660);
} }
unset($sqlite_file); unset($sqlite_file);
} }
} }
/** /**
* WARNING: This allows accessing the database directly. * WARNING: This allows accessing the database directly.
* This was only be added for convenience. You are advised to not use this function extensively * This was only be added for convenience. You are advised to not use this function extensively
* *
* @param sql String wich will be passed directly to the database * @param sql String wich will be passed directly to the database
* @return Response of PDO::query() * @return Response of PDO::query()
*/ */
function query($sql) { function query($sql) {
return $this->db->query($sql); return $this->db->query($sql);
} }
function setRegistrationStateVerify($state, $token) { function setRegistrationStateVerify($state, $token) {
$sql = "UPDATE registrations SET state = " . $state $sql = "UPDATE registrations SET state = " . $state
. " WHERE verify_token = '" . $token . "';"; . " WHERE verify_token = '" . $token . "';";
return $this->db->exec($sql); return $this->db->exec($sql);
} }
function setRegistrationStateById($state, $id) { function setRegistrationStateById($state, $id) {
$sql = "UPDATE registrations SET state = " . $state $sql = "UPDATE registrations SET state = " . $state
. " WHERE id = '" . $id . "';"; . " WHERE id = '" . $id . "';";
return $this->db->exec($sql); return $this->db->exec($sql);
} }
function setRegistrationStateAdmin($state, $token) { function setRegistrationStateAdmin($state, $token) {
$sql = "UPDATE registrations SET state = " . $state $sql = "UPDATE registrations SET state = " . $state
. " WHERE admin_token = '" . $token . "';"; . " WHERE admin_token = '" . $token . "';";
return $this->db->exec($sql); return $this->db->exec($sql);
} }
function setRegistrationState($state, $token) { function setRegistrationState($state, $token) {
$sql = "UPDATE registrations SET state = " . $state $sql = "UPDATE registrations SET state = " . $state
. " WHERE verify_token = '" . $token . "' OR admin_token = '" . $token . "';"; . " WHERE verify_token = '" . $token . "' OR admin_token = '" . $token . "';";
return $this->db->exec($sql); return $this->db->exec($sql);
} }
function userPendingRegistrations($username) { function userPendingRegistrations($username) {
$sql = "SELECT COUNT(*) FROM registrations WHERE username = '" . $username . "' AND NOT state = " $sql = "SELECT COUNT(*) FROM registrations WHERE username = '" . $username . "' AND NOT state = "
. RegisterState::RegistrationDeclined . " LIMIT 1;"; . RegisterState::RegistrationDeclined . " LIMIT 1;";
$res = $this->db->query($sql); $res = $this->db->query($sql);
if ($res->fetchColumn() > 0) { if ($res->fetchColumn() > 0) {
return true; return true;
} }
return false; return false;
} }
function userRegistered($username) {
$sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $username . "' LIMIT 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
return true;
}
return false;
}
function userRegistered($username) { /**
$sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $username . "' LIMIT 1;"; * Adds user to the database. Next steps should be sending a verify-mail to the user
$res = $this->db->query($sql); * @param first_name First name of the user
if ($res->fetchColumn() > 0) { * @param last_name Sirname of the user
return true; * @param username the future localpart of that user
} * @param note Note the user typed in to give a hint
return false; * @param email E-Mail-Adress which will be stored into the database.
} * This will be send to the server on first login
*
* @return ["verify_token"]
*/
function addRegistration($first_name, $last_name, $username, $note, $email) {
if ($this->userPendingRegistrations($username)) {
throw new Exception("USERNAME_PENDING_REGISTRATION");
}
if ($this->userRegistered($username)) {
throw new Exception("USERNAME_REGISTERED");
}
/** $verify_token = bin2hex(random_bytes(16));
* Adds user to the database. Next steps should be sending a verify-mail to the user $admin_token = bin2hex(random_bytes(16));
* @param first_name First name of the user
* @param last_name Sirname of the user
* @param username the future localpart of that user
* @param note Note the user typed in to give a hint
* @param email E-Mail-Adress which will be stored into the database.
* This will be send to the server on first login
*
* @return ["verify_token"]
*/
function addRegistration($first_name, $last_name, $username, $password, $note, $email) {
if ($this->userPendingRegistrations($username)) {
throw new Exception("USERNAME_PENDING_REGISTRATION");
}
if ($this->userRegistered($username)) {
throw new Exception("USERNAME_REGISTERED");
}
$verify_token = bin2hex(random_bytes(16)); $this->db->exec("INSERT INTO registrations
$admin_token = bin2hex(random_bytes(16)); (first_name, last_name, username, note, email, verify_token, admin_token)
VALUES ('" . $first_name."','" . $last_name . "','" . $username . "','" . $note . "','"
. $email."','" .$verify_token."','" .$admin_token."')");
$this->db->exec("INSERT INTO registrations return [
(first_name, last_name, username, password, note, email, verify_token, admin_token) "verify_token"=> $verify_token,
VALUES ('" . $first_name . "','" . $last_name . "','" ];
. $username . "','" . $password . "','" . $note . "','" }
. $email . "','" . $verify_token . "','" . $admin_token . "')");
return [ /**
"verify_token" => $verify_token, * Gets the user for the verify_admin page.
]; *
} * @return ArrayOfUser|NULL Array with "first_name, last_name, username, note and email"
* as members
*/
function getUserForApproval($admin_token) {
$sql = "SELECT COUNT(*) FROM registrations WHERE admin_token = '" . $admin_token . "'"
. " AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;";
$res = $this->db->query($sql);
$first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
/** if ($res->fetchColumn() > 0) {
* Gets the user for the verify_admin page. $sql = "SELECT first_name, last_name, username, note, email FROM registrations"
* . " WHERE admin_token = '" . $admin_token . "'"
* @return ArrayOfUser|NULL Array with "first_name, last_name, username, note and email" . " AND state = " . RegisterState::PendingAdminVerify
* as members . " LIMIT 1;";
*/ foreach ($this->db->query($sql) as $row) {
function getUserForApproval($admin_token) { // will only be executed once
$sql = "SELECT COUNT(*) FROM registrations WHERE admin_token = '" . $admin_token . "'" return $row;
. " AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;"; }
$res = $this->db->query($sql); }
return NULL;
}
if ($res->fetchColumn() > 0) { /**
$sql = "SELECT first_name, last_name, username, password, note, email FROM registrations" * Gets the user when it opens the page to verify its mail
. " WHERE admin_token = '" . $admin_token . "'" *
. " AND state = " . RegisterState::PendingAdminVerify * @return ArrayOfUser|NULL Array with "first_name, last_name, note, email and admin_token"
. " LIMIT 1;"; * as members
foreach ($this->db->query($sql) as $row) { */
// will only be executed once function getUserForVerify($verify_token) {
return $row; $sql = "SELECT COUNT(*) FROM registrations WHERE verify_token = '" . $verify_token . "'"
} . " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
} $res = $this->db->query($sql);
return NULL; $first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
}
/** if ($res->fetchColumn() > 0) {
* Gets the user when it opens the page to verify its mail $sql = "SELECT first_name, last_name, note, email, admin_token FROM registrations "
* . " WHERE verify_token = '" . $verify_token . "'"
* @return ArrayOfUser|NULL Array with "first_name, last_name, note, email and admin_token" . " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
* as members foreach ($this->db->query($sql) as $row) {
*/ // will only be executed once
function getUserForVerify($verify_token) { return $row;
$sql = "SELECT COUNT(*) FROM registrations WHERE verify_token = '" . $verify_token . "'" }
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;"; }
$res = $this->db->query($sql); return NULL;
}
if ($res->fetchColumn() > 0) { function getUserForLogin($localpart, $password) {
$sql = "SELECT first_name, last_name, note, email, username, admin_token FROM registrations " $sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $localpart
. " WHERE verify_token = '" . $verify_token . "'" . "' AND active = 1 LIMIT 1;";
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;"; $res = $this->db->query($sql);
foreach ($this->db->query($sql) as $row) {
// will only be executed once
return $row;
}
}
return NULL;
}
function getUserForLogin($localpart, $password) { if ($res->fetchColumn() > 0) {
$sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $localpart $sql = "SELECT first_name, last_name, email, password_hash FROM logins "
. "' AND active = 1 LIMIT 1;"; . " WHERE localpart = '" . $localpart . "' AND active = 1 LIMIT 1;";
$res = $this->db->query($sql); foreach ($this->db->query($sql) as $row) {
if (password_verify($password, $row["password_hash"])) {
return $row;
}
}
}
return NULL;
}
if ($res->fetchColumn() > 0) { /**
$sql = "SELECT first_name, last_name, email, password_hash FROM logins " * adds User to be able to login afterwards.
. " WHERE localpart = '" . $localpart . "' AND active = 1 LIMIT 1;"; * @param first_name First name of the user
foreach ($this->db->query($sql) as $row) { * @param last_name Sirname of the user
if (password_verify($password, $row["password_hash"])) { * @param username the future localpart of that user
return $row; * @param email E-Mail-Adress which will be stored into the database.
} * This will be send to the server on first login
} *
} * @return password|NULL with member password as this method generates a
return NULL; * password and saves that into the database
} * NULL when failed
*
*/
function addUser($first_name, $last_name, $username, $email) {
// check if user already exists and abort in that case
if ($this->userRegistered($username)) {
return NULL;
}
/** // generate a password with 10 characters
* adds User to be able to login afterwards. $password = bin2hex(openssl_random_pseudo_bytes(5));
* @param first_name First name of the user $password_hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>12]);
* @param last_name Sirname of the user
* @param username the future localpart of that user
* @param email E-Mail-Adress which will be stored into the database.
* This will be send to the server on first login
*
* @return password|NULL with member password as this method generates a
* password and saves that into the database
* NULL when failed
*
*/
function addUser($first_name, $last_name, $username, $password, $email) {
// check if user already exists and abort in that case
if ($this->userRegistered($username)) {
return NULL;
}
if ($password == NULL) { $sql = "INSERT INTO logins (first_name, last_name, localpart, password_hash, email) VALUES "
// generate a password with 10 characters . "('" . $first_name."','" . $last_name . "','" . $username . "','"
$password = bin2hex(openssl_random_pseudo_bytes(5)); . $password_hash . "','" . $email . "');";
}
$password_hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 12]);
$sql = "INSERT INTO logins (first_name, last_name, localpart, password_hash, email) VALUES " if ($this->db->exec($sql)) {
. "('" . $first_name . "','" . $last_name . "','" . $username . "','" return $password;
. $password_hash . "','" . $email . "');"; }
return NULL;
}
if ($this->db->exec($sql)) { function updatePassword($localpart, $old_password, $new_password) {
return $password; $user = $this->getUserForLogin($localpart, $old_password);
} if ($user == NULL) {
return NULL; throw new Exception ("user with that credentials not found");
} }
function updatePassword($localpart, $old_password, $new_password) { // The credentials were fine. So now set the new password
$user = $this->getUserForLogin($localpart, $old_password); $password_hash = password_hash($new_password, PASSWORD_BCRYPT, ["cost"=>12]);
if ($user == NULL) {
throw new Exception("user with that credentials not found");
}
// The credentials were fine. So now set the new password $sql = "UPDATE logins SET password_hash = '" . $password_hash . "'"
$password_hash = password_hash($new_password, PASSWORD_BCRYPT, ["cost" => 12]); . "WHERE localpart = '" . $localpart . "'";
$sql = "UPDATE logins SET password_hash = '" . $password_hash . "'" if ($this->db->exec($sql)) {
. "WHERE localpart = '" . $localpart . "'"; return true;
}
return false;
}
if ($this->db->exec($sql)) { function searchUserByName($search_term) {
return true; $term = filter_var($search_term, FILTER_SANITIZE_STRING);
} $result = array();
return false; $sql = "SELECT COUNT(*) FROM logins WHERE"
} . " localpart LIKE '" . $term . "%' AND active = 1;";
$res = $this->db->query($sql);
function searchUserByName($search_term) { if ($res->fetchColumn() > 0) {
$term = filter_var($search_term, FILTER_SANITIZE_STRING); $sql = "SELECT first_name, last_name, localpart FROM logins WHERE"
$result = array(); . " localpart LIKE '" . $term . "%' AND active = 1;";
$sql = "SELECT COUNT(*) FROM logins WHERE" foreach ($this->db->query($sql) as $row) {
. " localpart LIKE '" . $term . "%' AND active = 1;"; array_push($result, [
$res = $this->db->query($sql); "display_name" => $row["first_name"] . " " . $row["last_name"],
"user_id" => $row["localpart"],
]);
}
}
return $result;
}
if ($res->fetchColumn() > 0) { function searchUserByEmail($search_term) {
$sql = "SELECT first_name, last_name, localpart FROM logins WHERE" $term = filter_var($search_term, FILTER_SANITIZE_STRING);
. " localpart LIKE '" . $term . "%' AND active = 1;"; $result = array();
foreach ($this->db->query($sql) as $row) { $sql = "SELECT COUNT(*) FROM logins WHERE"
array_push($result, [ . " email = '" . $term . "' AND active = 1;";
"display_name" => $row["first_name"] . " " . $row["last_name"], $res = $this->db->query($sql);
"user_id" => $row["localpart"],
]);
}
}
return $result;
}
function searchUserByEmail($search_term) {
$term = filter_var($search_term, FILTER_SANITIZE_STRING);
$result = array();
$sql = "SELECT COUNT(*) FROM logins WHERE"
. " email = '" . $term . "' AND active = 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, localpart FROM logins WHERE"
. " email = '" . $term . "' AND active = 1;";
foreach ($this->db->query($sql) as $row) {
array_push($result, [
"display_name" => $row["first_name"] . " " . $row["last_name"],
"user_id" => $row["localpart"],
]);
}
}
return $result;
}
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, localpart FROM logins WHERE"
. " email = '" . $term . "' AND active = 1;";
foreach ($this->db->query($sql) as $row) {
array_push($result, [
"display_name" => $row["first_name"] . " " . $row["last_name"],
"user_id" => $row["localpart"],
]);
}
}
return $result;
}
} }
if (!isset($mx_db)) { if (!isset($mx_db)) {
$mx_db = new mxDatabase($config); $mx_db = new mxDatabase($config);
} }
?> ?>

View File

@@ -1,42 +1,18 @@
<?php <?php
/**
* Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function stripLocalpart($mxid) { function stripLocalpart($mxid) {
$localpart = NULL; $localpart = NULL;
if (!empty($mxid)) { if (!empty($mxid)) {
// A mxid would start with an @ so we start at the 2. position // A mxid would start with an @ so we start at the 2. position
$sepPos = strpos($mxid, ':', 1); $sepPos = strpos($mxid,':', 1);
if ($sepPos === false) { if ($sepPos === false) {
// : not found. Assume mxid is localpart // : not found. Assume mxid is localpart
// TODO: further checks // TODO: further checks
$localpart = $mxid; $localpart = $mxid;
} else { } else {
$localpart = substr($mxid, 1, strpos($mxid, ':') - 1); $localpart = substr($mxid, 1, strpos($mxid,':') - 1 );
} }
} }
return $localpart; return $localpart;
} }
function getCurlHandle($url) { ?>
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
return $handle;
}
?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
$response = [ $response=[
"limited" => false, "limited" => false,
"result" => [], "result" => [],
]; ];
@@ -24,7 +23,7 @@ try {
$inputJSON = file_get_contents('php://input'); $inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); $input = json_decode($inputJSON, TRUE);
if (empty($input)) { if (empty($input)) {
throw new Exception('no valid json as input present'); throw new Exception('no valid json as input present');
} }
if (!isset($input["by"])) { if (!isset($input["by"])) {
throw new Exception('"by" is not defined'); throw new Exception('"by" is not defined');
@@ -40,11 +39,12 @@ try {
$response["result"] = $mx_db->searchUserByEmail($input["search_term"]); $response["result"] = $mx_db->searchUserByEmail($input["search_term"]);
break; break;
default: default:
throw new Exception('unknown type for "by" param'); throw new Exception("unknown type for \"by\" param");
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log("failed with error: " . $e->getMessage()); error_log("failed with error: " . $e->getMessage());
$response["error"] = $e->getMessage(); $response["error"] = $e->getMessage();
} }
print (json_encode($response, JSON_PRETTY_PRINT)); print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
$response = [ $response = [
"lookup" => [] "lookup" => []
]; ];
@@ -22,7 +21,7 @@ try {
$inputJSON = file_get_contents('php://input'); $inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); $input = json_decode($inputJSON, TRUE);
if (!isset($input)) { if (!isset($input)) {
throw new Exception('request body is no valid json'); throw new Exception('request body is no valid json');
} }
if (!isset($input["lookup"])) { if (!isset($input["lookup"])) {
@@ -38,33 +37,31 @@ try {
if (!isset($lookup["address"])) { if (!isset($lookup["address"])) {
throw new Exception('"lookup.address" is not defined'); throw new Exception('"lookup.address" is not defined');
} }
$res2 = NULL; $res2 = array();
switch ($lookup["medium"]) { switch ($lookup["medium"]) {
case "email": case "email":
$res2 = $mx_db->searchUserByEmail($lookup["address"]); $res2 = $mx_db->searchUserByEmail($lookup["address"]);
if (!empty($res2)) { if (!empty($res2)) {
array_push($response["lookup"], [ array_push($response["lookup"], [
"medium" => $lookup["medium"], "medium" => $lookup["medium"],
"address" => $lookup["address"], "address" => $lookup["address"],
"id" => [ "id" => [
"type" => "localpart", "type" => "localpart",
"value" => $res2[0]["user_id"], "value" => $res2[0]["user_id"],
]
] ]
]
); );
} }
break; break;
case "msisdn": case "msisdn":
// This is reserved for number lookups
throw new Exception("unimplemented lookup medium");
break; break;
default: default:
throw new Exception("unknown lookup medium"); throw new Exception("unknown type for \"by\" param");
} }
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log("ídentity_bulk failed with error: " . $e->getMessage()); error_log("ídentity_bulk failed with error: " . $e->getMessage());
$response["error"] = $e->getMessage(); $response["error"] = $e->getMessage();
} }
print (json_encode($response, JSON_PRETTY_PRINT)); print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,13 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
$response = new stdClass; $response = new stdClass;
try { try {
$inputJSON = file_get_contents('php://input'); $inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); $input = json_decode($inputJSON, TRUE);
if (empty($input)) { if (empty($input)) {
throw new Exception('no valid json as input present'); throw new Exception('no valid json as input present');
} }
if (!isset($input["lookup"])) { if (!isset($input["lookup"])) {
throw new Exception('"lookup" is not defined'); throw new Exception('"lookup" is not defined');
@@ -31,7 +30,7 @@ try {
if (!isset($input["lookup"]["address"])) { if (!isset($input["lookup"]["address"])) {
throw new Exception('"lookup.address" is not defined'); throw new Exception('"lookup.address" is not defined');
} }
$res2 = NULL; $res2 = array();
switch ($input["lookup"]["medium"]) { switch ($input["lookup"]["medium"]) {
case "email": case "email":
$res2 = $mx_db->searchUserByEmail($input["lookup"]["address"]); $res2 = $mx_db->searchUserByEmail($input["lookup"]["address"]);
@@ -47,19 +46,15 @@ try {
] ]
]; ];
} }
break;
case "msisdn":
// This is reserved for number lookups
throw new Exception("unimplemented lookup medium");
break; break;
default: default:
throw new Exception("unknown lookup medium"); throw new Exception("unknown type for \"by\" param");
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log("ídentity_single failed with error: " . $e->getMessage()); error_log("ídentity_bulk failed with error: " . $e->getMessage());
$response = [ $response["error"] = $e->getMessage();
"error" => $e->getMessage()
];
} }
print (json_encode($response, JSON_PRETTY_PRINT)); print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,56 +13,60 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// URL for this: /_matrix/client/r0/account/password?access_token=$ACCESS_TOKEN // URL for this: /_matrix/client/r0/account/password?access_token=$ACCESS_TOKEN
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS'); header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization'); header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
print ("{}"); print ("{}");
// return with success // return with success
exit(); exit();
} }
$response = new stdClass; $response= new stdClass;
try { try {
$inputJSON = file_get_contents('php://input'); $inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); $input = json_decode($inputJSON, TRUE);
if (empty($input)) { if (empty($input)) {
throw new Exception('no valid json as input present'); throw new Exception('no valid json as input present');
} }
if (!isset($input["auth"])) { if (!isset($input["auth"])) {
throw new Exception('"auth" is not defined'); throw new Exception('"auth" is not defined');
} }
if (!isset($input["auth"]["user"]) || !isset($input["auth"]["password"])) { if (!isset($input["auth"]["user"]) || !isset($input["auth"]["password"])) {
throw new Exception('"auth.user" or "auth.password" is not defined'); throw new Exception('"auth.user" or "auth.password" is not defined');
} }
if (!isset($input["auth"]["type"]) || $input["auth"]["type"] !== "m.login.password") { if (!isset($input["auth"]["type"]) || $input["auth"]["type"] !== "m.login.password") {
throw new Exception('no or unknown auth.type'); throw new Exception('no or unknown auth.type');
} }
if (!isset($input["new_password"])) { if (!isset($input["new_password"])) {
throw new Exception('"new_password" is not defined'); throw new Exception('"new_password" is not defined');
} }
require_once(__DIR__ . "/../helpers.php"); require_once("../helpers.php");
$localpart = stripLocalpart($input["auth"]["user"]); $localpart = stripLocalpart($input["auth"]["user"]);
if (empty($localpart)) { if (empty($localpart)) {
throw new Exception("localpart cannot be identified"); throw new Exception ("localpart cannot be identified");
} }
require_once("../database.php");
if (!$mx_db->updatePassword(
$localpart,
$input["auth"]["password"],
$input["new_password"]
)) {
throw new Exception("invalid credentials or another error while updating");
}
require_once(__DIR__ . "/../database.php");
if (!$mx_db->updatePassword(
$localpart, $input["auth"]["password"], $input["new_password"]
)) {
throw new Exception("invalid credentials or another error while updating");
}
} catch (Exception $e) { } catch (Exception $e) {
header("HTTP/1.0 500 Internal Error"); header("HTTP/1.0 500 Internal Error");
error_log("failed with error: " . $e->getMessage()); error_log("failed with error: " . $e->getMessage());
$response = [ $response = [
"errorcode" => "M_UNKNOWN", "errorcode" => "M_UNKNOWN",
"error" => $e->getMessage(), "error" => $e->getMessage(),
]; ];
} }
print (json_encode($response, JSON_PRETTY_PRINT)); print (json_encode($response, JSON_PRETTY_PRINT));
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,22 +19,19 @@ $response = [
] ]
]; ];
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
abstract class LoginRequester { abstract class LoginRequester {
const UNDEFINED = 0; const UNDEFINED = 0;
const MXISD = 1; const MXISD = 1;
const RestAuth = 2; const RestAuth = 2;
} }
$loginRequester = LoginRequester::UNDEFINED; $loginRequester = LoginRequester::UNDEFINED;
try { try {
$inputJSON = file_get_contents('php://input'); $inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); $input = json_decode($inputJSON, TRUE);
$mxid = $localpart = NULL; $mxid = NULL;
$localpart = NULL;
if (isset($input["user"])) { if (isset($input["user"])) {
if (isset($input["user"]["localpart"])) { if (isset($input["user"]["localpart"])) {
$localpart = $input["user"]["localpart"]; $localpart = $input["user"]["localpart"];
@@ -49,27 +45,25 @@ try {
$mxid = $input["user"]["mxid"]; $mxid = $input["user"]["mxid"];
$loginRequester = LoginRequester::MXISD; $loginRequester = LoginRequester::MXISD;
} }
} else {
throw new Exception('"user" not in request body');
} }
// prefer the localpart attribute of mxisd. But in case of matrix-synapse-rest-auth // prefer the localpart attribute of mxisd. But in case of matrix-synapse-rest-auth
// we have to parse it on our own // we have to parse it on our own
if (empty($localpart)) { if (empty($localpart)) {
require_once(__DIR__ . "/../helpers.php"); require_once("../helpers.php");
$localpart = stripLocalpart($mxid); $localpart = stripLocalpart($mxid);
} }
if (empty($localpart)) { if (empty($localpart)) {
throw new Exception("localpart cannot be identified"); throw new Exception ("localpart cannot be identified");
} }
$password = NULL; $password = NULL;
if (isset($input["user"]["password"])) { if (isset($input["user"]) && isset($input["user"]["password"])) {
$password = $input["user"]["password"]; $password = $input["user"]["password"];
} }
if (empty($password)) { if (empty($password)) {
throw new Exception("password is not present"); throw new Exception ("password is not present");
} }
$user = $mx_db->getUserForLogin($localpart, $password); $user = $mx_db->getUserForLogin($localpart, $password);
@@ -101,12 +95,11 @@ try {
// only return that it was successful. // only return that it was successful.
// we do not know how the data shall be transmitted so we do nothing with it // we do not know how the data shall be transmitted so we do nothing with it
$response["auth"]["success"] = false; $response["auth"]["success"] = false;
$response["auth"]["error"] = "unidentified requester";
break; break;
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log("Auth failed with error: " . $e->getMessage()); error_log("Auth failed with error: " . $e->getMessage());
$response["auth"]["error"] = $e->getMessage(); $response["auth"]["error"] = $e->getMessage();
} }
print (json_encode($response, JSON_PRETTY_PRINT)); print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,60 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
$language = array( $language = array(
"ACCEPT" => "Akzeptieren",
"DECLINE" => "Ablehnen",
"DECLINE_REASON" => "Grund für die Ablehnung",
"SUBMIT" => "Abschicken",
"MAKE_A_SELECTION" => "Treffe eine Auswahl",
"SUCCESS" => "Erfolgreich",
"FIRST_NAME" => "Vorname",
"LAST_NAME" => "Nachname",
"USERNAME" => "Nutzername (für den Login)",
"PASSWORD" => "Passwort",
"PASSWORD_CONFIRM" => "Passwort bestätigen",
"EMAIL_ADDRESS" => "E-Mail-Adresse",
"REGISTER" => "Registrieren",
"NOTE" => "Hinweis",
"NO_CONFIGURATION" => "Es konnte keine Konfiguration gefunden werden.", "NO_CONFIGURATION" => "Es konnte keine Konfiguration gefunden werden.",
"UNKNOWN_ERROR" => "Unbekannter Fehler",
"UNKNOWN_SESSION" => "Sitzungstoken nicht vorhanden oder ungültig.", "UNKNOWN_SESSION" => "Sitzungstoken nicht vorhanden oder ungültig.",
"UNKNOWN_USERNAME" => "Nutzername fehlt", "UNKNOWN_USERNAME" => "Nutzername fehlt",
"UNKNOWN_TOKEN" => "Token ist unbekannt", "UNKNOWN_TOKEN" => "Token ist unbekannt",
"AUTHENTICATION_FAILED" => "Authentifizierung fehlgeschlagen", "USERNAME_LENGTH_INVALID" => "Entweder mehr als 20 oder weniger als 3 Zeichen für den Nutzernamen verwendet",
"WRONG_REGISTRATION_SHARED_SECRET" => "registration_shared_secret fehlerhaft",
"USERNAME_INVALID" => "Nutzername muss aus 3 bis 20 Kleinbuchstaben und Zahlen bestehen",
"USERNAME_NOT_ALNUM" => "Nutzername ist nicht alphanumerisch", "USERNAME_NOT_ALNUM" => "Nutzername ist nicht alphanumerisch",
"USERNAME_PENDING_REGISTRATION" => "Dieser Nutzername wurde bereits zur Registrierung vorgemerkt. Versuche es später noch einmal oder wähle einen anderen Nutzernamen", "USERNAME_PENDING_REGISTRATION" => "Dieser Nutzername wurde bereits zur Registrierung vorgemerkt. Versuche es später noch einmal oder wähle einen anderen Nutzernamen",
"USERNAME_REGISTERED" => "Dieser Nutzername wurde bereits registriert. Bitte wähle einen anderen Nutzernamen", "USERNAME_REGISTERED" => "Dieser Nutzername wurde bereits registriert. Bitte wähle einen anderen Nutzernamen",
"PASSWORD_NOT_PROVIDED" => "Ein oder beide Passwörter wurden nicht gesetzt",
"PASSWORD_NOT_MATCH" => "Passwörter stimmen nicht überein", "PASSWORD_NOT_MATCH" => "Passwörter stimmen nicht überein",
"NOTE_LENGTH_EXEEDED" => "Notiz ist länger als die erlaubten 50 Zeichen", "NOTE_LENGTH_EXEEDED" => "Notiz ist länger als die erlaubten 50 Zeichen",
"PLACEHOLDER_NOTE_ABOUT_YOURSELF" => "Notiz zu dir (max. 50 Zeichen)",
"EMAIL_INVALID_FORMAT" => "Keine valide E-Mail-Adresse angegeben", "EMAIL_INVALID_FORMAT" => "Keine valide E-Mail-Adresse angegeben",
"FIRSTNAME_INVALID_FORMAT" => "Vorname muss das Format <Großbuchstabe><Kleinbuchstaben> haben", "FIRSTNAME_INVALID_FORMAT" => "Vorname hat ungültiges Format",
"SIRNAME_INVALID_FORMAT" => "Nachname muss das Format <Großbuchstabe><Kleinbuchstaben> haben", "SIRNAME_INVALID_FORMAT" => "Nachname hat ungültiges Format",
"SEND_MAIL_FAIL" => "Senden der E-Mail fehlgeschlagen", "SEND_MAIL_FAIL" => "Senden der E-Mail fehlgeschlagen",
"SEND_MATRIX_FAIL" => "Senden einer Nachricht an die Administratoren fehlgeschlagen", "SEND_MATRIX_FAIL" => "Senden einer Nachricht an die Administratoren fehlgeschlagen",
"TASK_CHECK_YOUR_EMAIL_VERIFY" => "Bitte prüfe deine E-Mails um deine Adresse zu bestätigen",
"REGISTRATION_REQUEST_FAILED" => "Registrierungsanfrage ist fehlgeschlagen", "REGISTRATION_REQUEST_FAILED" => "Registrierungsanfrage ist fehlgeschlagen",
"REGISTRATION_FAILED" => "Registrierung ist fehlgeschlagen", "REGISTRATION_FAILED" => "Registrierung ist fehlgeschlagen",
"REGISTRATION_FAILED_FOR" => "Registrierung für @user ist fehlgeschlagen",
"VERIFICATION_SUCEEDED" => "Verifizierung erfolgreich", "VERIFICATION_SUCEEDED" => "Verifizierung erfolgreich",
"VERIFICATION_FAILED" => "Verifizierung fehlgeschlagen", "VERIFICATION_FAILED" => "Verifizierung fehlgeschlagen",
"VERIFICATION_SUCCESS_BODY" => "Vielen Dank. Die Administratoren wurden informiert", "VERIFICATION_SUCCESS_BODY" => "Vielen Dank. Die Administratoren wurden informiert",
"ADMIN_VERIFY_SITE_TITLE" => "Registrierungsanfrage bearbeiten", "ADMIN_VERIFY_SITE_TITLE" => "Registrierungsanfrage bearbeiten",
"ADMIN_REGISTER_ACCEPTED_BODY" => "Die Registrierungsanfrage wurde akzeptiert. Der Nutzer wurde per Mail informiert.", "ADMIN_REGISTER_ACCEPTED_BODY" => "Die Registrierungsanfrage wurde akzeptiert. Der Nutzer wurde per Mail informiert.",
"ADMIN_REGISTER_DECLINED_BODY" => "Die Registrierungsanfrage wurde angelehnt. Der Nutzer wurde per Mail informiert.", "ADMIN_REGISTER_DECLINED_BODY" => "Die Registrierungsanfrage wurde angelehnt. Der Nutzer wurde per Mail informiert.",
"JUMP_TO_HOMEPAGE" => "Zur Startseite",
"TOPIC_PLEASE_REGISTER" => "Bitte für @homeserver registrieren",
"TOPIC_PLEASE_REGISTER_NOTE" => "2-Schritt-Registrierung",
"NOTE_FOR_REGISTRATION" => "@homeserver ist ein geschlossenes Chat-Netzwerk in dem jeder Nutzer bestätigt werden muss.<br />
Du bekommst eine E-Mail wenn jemand deine Mitgliedschaft bestätigt hat. An diese wird auch dein initiales Passwort gesendet.
Hinterlasse also bitte einen Hinweis zu dir (den nur die Administratoren sehen werden).<br />
Liebe Grüße vom Team von @homeserver",
"MSG_USER_WANTS_REGISTER" => "@name möchte sich registrieren und hat folgende Notiz hinterlassen:
@note \r\nZum Bearbeiten hier klicken:\r\n @adminUrl",
"MSG_USER_WANTS_REGISTER_FORMATTED" => "@name möchte sich registrieren und hat folgende Notiz hinterlassen:<br />
@note <br />Zum Bearbeiten <a href=\"@adminUrl\">hier</a> klicken",
); );
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,60 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
$language = array( $language = array(
"ACCEPT" => "Accept",
"DECLINE" => "Decline",
"DECLINE_REASON" => "Reason for declining",
"SUBMIT" => "Submit",
"MAKE_A_SELECTION" => "Make a selection",
"SUCCESS" => "Success",
"FIRST_NAME" => "First name",
"LAST_NAME" => "Last name",
"USERNAME" => "username (for login)",
"PASSWORD" => "Password",
"PASSWORD_CONFIRM" => "Confirm password",
"EMAIL_ADDRESS" => "EMail Address",
"REGISTER" => "Register",
"NOTE" => "Note",
"NO_CONFIGURATION" => "No configuration found", "NO_CONFIGURATION" => "No configuration found",
"UNKNOWN_ERROR" => "Unknown Error",
"UNKNOWN_SESSION" => "Session token not found of invalid.", "UNKNOWN_SESSION" => "Session token not found of invalid.",
"UNKNOWN_USERNAME" => "username unknown", "UNKNOWN_USERNAME" => "username unknown",
"UNKNOWN_TOKEN" => "Token is unknown", "UNKNOWN_TOKEN" => "Token is unknown",
"AUTHENTICATION_FAILED" => "Authentication failed", "USERNAME_LENGTH_INVALID" => "Username cpnsists pf more than 20 or less than 3 characters",
"WRONG_REGISTRATION_SHARED_SECRET" => "wrong registration_shared_secret",
"USERNAME_INVALID" => "Username has to consist of 3 to 20 small letters and numbers",
"USERNAME_NOT_ALNUM" => "Username is not alphanumeric", "USERNAME_NOT_ALNUM" => "Username is not alphanumeric",
"USERNAME_PENDING_REGISTRATION" => "This username is locked for registration. Try again later or try again with a different username", "USERNAME_PENDING_REGISTRATION" => "This username is locked for registration. Try again later or try again with a different username",
"USERNAME_REGISTERED" => "This username is already registered. Please try again with another username", "USERNAME_REGISTERED" => "This username is already registered. Please try again with another username",
"PASSWORD_NOT_PROVIDED" => "One or both passwords are not provided",
"PASSWORD_NOT_MATCH" => "passwords do not match", "PASSWORD_NOT_MATCH" => "passwords do not match",
"NOTE_LENGTH_EXEEDED" => "Note consists of more than 50 characters", "NOTE_LENGTH_EXEEDED" => "Note consists of more than 50 characters",
"PLACEHOLDER_NOTE_ABOUT_YOURSELF" => "Note about yourself (max. 50 characters)",
"EMAIL_INVALID_FORMAT" => "no valid email address", "EMAIL_INVALID_FORMAT" => "no valid email address",
"FIRSTNAME_INVALID_FORMAT" => "First name with invalid formatting", "FIRSTNAME_INVALID_FORMAT" => "First name with invalid formatting",
"SIRNAME_INVALID_FORMAT" => "Sirname with invalid formatting", "SIRNAME_INVALID_FORMAT" => "Sirname with invalid formatting",
"SEND_MAIL_FAIL" => "Email could not be sent", "SEND_MAIL_FAIL" => "Email could not be sent",
"SEND_MATRIX_FAIL" => "Sending a message to the admins failed", "SEND_MATRIX_FAIL" => "Sending a message to the admins failed",
"TASK_CHECK_YOUR_EMAIL_VERIFY" => "Please check your emails to verify your email address",
"REGISTRATION_REQUEST_FAILED" => "Registration request failed", "REGISTRATION_REQUEST_FAILED" => "Registration request failed",
"REGISTRATION_FAILED" => "Registration failed", "REGISTRATION_FAILED" => "Registration failed",
"REGISTRATION_FAILED_FOR" => "Registrierung für @user ist fehlgeschlagen",
"VERIFICATION_SUCEEDED" => "Verification suceeded", "VERIFICATION_SUCEEDED" => "Verification suceeded",
"VERIFICATION_FAILED" => "Verification failed", "VERIFICATION_FAILED" => "Verification failed",
"VERIFICATION_SUCCESS_BODY" => "Thank you. The admins got informed", "VERIFICATION_SUCCESS_BODY" => "Thank you. The admins got informed",
"ADMIN_VERIFY_SITE_TITLE" => "Handle registration request", "ADMIN_VERIFY_SITE_TITLE" => "Handle registration request",
"ADMIN_REGISTER_ACCEPTED_BODY" => "The registration request got accepted. The user got notified per email.", "ADMIN_REGISTER_ACCEPTED_BODY" => "The registration request got accepted. The user got notified per email.",
"ADMIN_REGISTER_DECLINED_BODY" => "The registration request got declined. The user got notified per email.", "ADMIN_REGISTER_DECLINED_BODY" => "The registration request got declined. The user got notified per email.",
"JUMP_TO_HOMEPAGE" => "To homepage",
"TOPIC_PLEASE_REGISTER" => "Please register for @homeserver",
"TOPIC_PLEASE_REGISTER_NOTE" => "2-Step-Registration",
"NOTE_FOR_REGISTRATION" => "@homeserver is a closed chat network where every user has to be confirmed.<br />
You will get an email once sb. approved your registration. An initial password will be send to you afterwards.
Please leave a note about yourself (that will only be shown to the admins).<br />
Greetings from the team of @homeserver",
"MSG_USER_WANTS_REGISTER" => "@name wants to register and left the following note:
@note \r\nTo handle that request:\r\n @adminUrl",
"MSG_USER_WANTS_REGISTER_FORMATTED" => "@name wants to register and left the following note:<br />
@note <br />To handle that request click <a href=\"@adminUrl\">here</a>",
); );
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
function send_mail($receiver, $subject, $body) {
include("config.php");
$headers = "From: " . $config["register_email"] . "\r\n"
. "Content-Type: text/plain;charset=utf-8";
return mail($receiver, $subject, $body, $headers);
}
function send_mail_pending_verification($homeserver, $user, $receiver, $verify_url) { function send_mail_pending_verification($homeserver, $user, $receiver, $verify_url) {
$subject = "Bitte bestätige Registrierung auf $homeserver"; $subject = "Bitte bestätige Registrierung auf $homeserver";
$body = "Guten Tag " . $user . ", $body = "Guten Tag " . $user . ",
Du hast anscheinend versucht dich auf $homeserver zu registrieren. Du hast anscheinend versucht dich auf $homeserver zu registrieren.
Hier gibt es eine zweistufige Registrierung. Hier gibt es eine zweistufige Registrierung.
@@ -33,12 +39,12 @@ Danach ist eine Re-Registrierung mit deinem gewünschten Nutzernamen für andere
Vielen Dank für dein Verständnis. Vielen Dank für dein Verständnis.
Das Administratoren-Team von " . $homeserver; Das Administratoren-Team von " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body );
} }
function send_mail_pending_approval($homeserver, $user, $receiver) { function send_mail_pending_approval($homeserver, $user, $receiver) {
$subject = "Registrierung wartet auf Bestätigung durch Administratoren"; $subject = "Registrierung wartet auf Bestätigung durch Administratoren";
$body = "Guten Tag " . $user . ", $body = "Guten Tag " . $user . ",
Deine Registrierungsanfrage wurde verifiziert und wird nun durch die Administratoren überprüft. Deine Registrierungsanfrage wurde verifiziert und wird nun durch die Administratoren überprüft.
@@ -47,12 +53,12 @@ Du bekommst eine weitere E-Mail, sobald deine Registrierung bestätigt oder able
Vielen Dank für dein Verständnis. Vielen Dank für dein Verständnis.
Das Administratoren-Team von " . $homeserver; Das Administratoren-Team von " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body );
} }
function send_mail_registration_allowed_but_failed($homeserver, $user, $receiver) { function send_mail_registration_allowed_but_failed($homeserver, $user, $receiver) {
$subject = "Registrierung auf $homeserver genehmigt"; $subject = "Registrierung auf $homeserver genehmigt";
$body = "Guten Tag " . $user . ", $body = "Guten Tag " . $user . ",
Deine Registrierungsanfrage wurde durch die Administratoren bestätigt. Deine Registrierungsanfrage wurde durch die Administratoren bestätigt.
@@ -61,58 +67,58 @@ Wir hoffen, das Problem ist bald behoben.
Wir melden uns, wenn die Registrierung erfolgreich war. Wir melden uns, wenn die Registrierung erfolgreich war.
Das Administratoren-Team von " . $homeserver; Das Administratoren-Team von " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body);
} }
function send_mail_registration_success($homeserver, $user, $receiver, $username, $password, $howToURL) { function send_mail_registration_success($homeserver, $user, $receiver, $username, $password, $howToURL) {
$subject = "Registrierung auf $homeserver erfolgreich"; $subject = "Registrierung auf $homeserver erfolgreich";
$body = "Guten Tag " . $user . ", $body = "Guten Tag " . $user . ",
Deine Registrierungsanfrage wurde durch die Administratoren bestätigt. Deine Registrierungsanfrage wurde durch die Administratoren bestätigt.
Zum Anmelden kannst du folgende Zugangsdaten verwenden: Zum Anmelden kannst du folgende Zugangsdaten verwenden:
Nutzername: $username Nutzername: $username
Passwort: " . (empty($password) ? "wie selbst gesetzt": $password) . " Passwort: $password
Hinweis: Das Passwort kannst du aktuell über die App selbst ändern. Auch wenn das Passwort nirgends Hinweis: Das Passwort kannst du aktuell über die App selbst ändern. Auch wenn das Passwort nirgends
im Klartext gespeichert wird, kann jemand Zugriff auf diese Mail erlangen und so den Zugriff bekommen. im Klartext gespeichert wird, kann jemand Zugriff auf diese Mail erlangen und so den Zugriff bekommen.
"; ";
/* /*
Wichtig: Bitte ändere das Passwort direkt nach der Anmeldung. Wichtig: Bitte ändere das Passwort direkt nach der Anmeldung.
Es wird zwar von unserer Seite nicht gespeichert, doch fremde könnten Zugriff auf diese E-Mail Es wird zwar von unserer Seite nicht gespeichert, doch fremde könnten Zugriff auf diese E-Mail
erhalten und so deinen Account kompromittieren. erhalten und so deinen Account kompromittieren.
*/ */
if (!empty($howToURL)) { if (!empty($howToURL)) {
$body .= " $body .= "
Zu weiteren Hilfestellungen findest du hier eine Auflistung von verschiedenen Zu weiteren Hilfestellungen findest du hier eine Auflistung von verschiedenen
Anleitungen zu verschiedenen Clients: Anleitungen zu verschiedenen Clients:
$howToURL\n"; $howToURL\n";
} }
$body .= " $body .= "
Viel Spaß bei der Verwendung von $homeserver. Viel Spaß bei der Verwendung von $homeserver.
Bei Fragen findest du nach der Anmeldung ein paar Räume in denen du sie stellen kannst. Bei Fragen findest du nach der Anmeldung ein paar Räume in denen du sie stellen kannst.
Das Administratoren-Team von " . $homeserver; Das Administratoren-Team von " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body);
}
}
function send_mail_registration_decline($homeserver, $user, $receiver, $reason) { function send_mail_registration_decline($homeserver, $user, $receiver, $reason) {
$subject = "Registrierung auf $homeserver abgelehnt"; $subject = "Registrierung auf $homeserver abgelehnt";
$body = "Guten Tag " . $user . ", $body = "Guten Tag " . $user . ",
Deine Registrierungsanfrage wurde durch die Administratoren abgelehnt.\n"; Deine Registrierungsanfrage wurde durch die Administratoren abgelehnt.\n";
if (empty($reason)) { if (empty($reason)) {
$body .= "\nEs wurde kein Grund angegeben\n"; $body .= "\nEs wurde kein Grund angegeben\n";
} else { } else {
$body .= "\nAls Grund wurde folgendes angegeben:\n$reason\n"; $body .= "\nAls Grund wurde folgendes angegeben:\n$reason\n";
} }
$body .= " $body .= "
Wir hoffen, dass du dies akzeptieren kannst. Wir hoffen, dass du dies akzeptieren kannst.
Das Administratoren-Team von " . $homeserver; Das Administratoren-Team von " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body );
} }
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
function send_mail($receiver, $subject, $body) {
include("config.php");
$headers = "From: " . $config["register_email"] . "\r\n"
. "Content-Type: text/plain;charset=utf-8";
return mail($receiver, $subject, $body, $headers);
}
function send_mail_pending_verification($homeserver, $user, $receiver, $verify_url) { function send_mail_pending_verification($homeserver, $user, $receiver, $verify_url) {
$subject = "Pleast approve your registration request on $homeserver"; $subject = "Pleast approve your registration request on $homeserver";
$body = "Dear " . $user . ", $body = "Dear " . $user . ",
It seems that you tried to register on $homeserver. It seems that you tried to register on $homeserver.
This homeserver requires a two step registration. This homeserver requires a two step registration.
@@ -32,12 +38,12 @@ Others might take your username afterwards.
Thanks for your patience. Thanks for your patience.
The admin team of " . $homeserver; The admin team of " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body );
} }
function send_mail_pending_approval($homeserver, $user, $receiver) { function send_mail_pending_approval($homeserver, $user, $receiver) {
$subject = "Registration is pending verification from an admin"; $subject = "Registration is pending verification from an admin";
$body = "Dear " . $user . ", $body = "Dear " . $user . ",
You have verified your registration request. The admins are now checking your request. You have verified your registration request. The admins are now checking your request.
@@ -46,12 +52,12 @@ You will get an email once they approve or decline your request.
Sincerely, Sincerely,
The admin team of " . $homeserver; The admin team of " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body );
} }
function send_mail_registration_allowed_but_failed($homeserver, $user, $receiver) { function send_mail_registration_allowed_but_failed($homeserver, $user, $receiver) {
$subject = "Registration on $homeserver got approved"; $subject = "Registration on $homeserver got approved";
$body = "Dear " . $user . ", $body = "Dear " . $user . ",
Your registration request got approved by the admin team. Your registration request got approved by the admin team.
@@ -60,53 +66,53 @@ We hope that the issue will be fixed soon.
You will get another email with initial credentials once the registration got handled completely. You will get another email with initial credentials once the registration got handled completely.
The admin team of " . $homeserver; The admin team of " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body);
} }
function send_mail_registration_success($homeserver, $user, $receiver, $username, $password, $howToURL) { function send_mail_registration_success($homeserver, $user, $receiver, $username, $password, $howToURL) {
$subject = "Registration on $homeserver got approved"; $subject = "Registration on $homeserver got approved";
$body = "Dear " . $user . ", $body = "Dear " . $user . ",
Your registration request got verified by the admin team. Your registration request got verified by the admin team.
To log in you can use the following credentials:: To log in you can use the following credentials::
Username: $username Username: $username
Passwort: " . (empty($password) ? "as self-set": $password) . " Password: $password
Important: Please change your password as soon as possible after your first login. Important: Please change your password as soon as possible after your first login.
The password is not stored in clear text on the server but people could get access to this mail The password is not stored in clear text on the server but people could get access to this mail
and compromise your account. and compromise your account.
"; ";
if (!empty($howToURL)) { if (!empty($howToURL)) {
$body .= " $body .= "
You can find further help here:: You can find further help here::
$howToURL\n"; $howToURL\n";
} }
$body .= " $body .= "
Enjoy your usage of $homeserver. Enjoy your usage of $homeserver.
You can ask further questions inside of the chat system. You can ask further questions inside of the chat system.
The admin team of " . $homeserver; The admin team of " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body);
}
}
function send_mail_registration_decline($homeserver, $user, $receiver, $reason) { function send_mail_registration_decline($homeserver, $user, $receiver, $reason) {
$subject = "Registration on $homeserver declined."; $subject = "Registration on $homeserver declined.";
$body = "Guten Tag " . $user . ", $body = "Guten Tag " . $user . ",
Your registration request got declined by the admin team.\n"; Your registration request got declined by the admin team.\n";
if (empty($reason)) { if (empty($reason)) {
$body .= "\nThey did not provide any reason for this\n"; $body .= "\nThey did not provide any reason for this\n";
} else { } else {
$body .= "\nThey provide following hint for you:\n$reason\n"; $body .= "\nThey provide following hint for you:\n$reason\n";
} }
$body .= " $body .= "
We hope that you can understand this reason. We hope that you can understand this reason.
The admin team of " . $homeserver; The admin team of " . $homeserver;
return send_mail($receiver, $subject, $body); return send_mail($receiver, $subject, $body );
} }
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,18 +13,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/config.php"); require_once("config.php");
$lang = $config["defaultLanguage"]; $lang=$config["defaultLanguage"];
if (isset($_GET['lang'])) { if(isset($_GET['lang'])){
$lang = filter_var($_GET['lang'], FILTER_SANITIZE_STRING); $lang = filter_var($_GET['lang'], FILTER_SANITIZE_STRING);
} }
$lang_file = dirname(__FILE__) . "/lang/lang." . $lang . ".php"; $lang_file = dirname(__FILE__) . "/lang/lang.".$lang.".php";
if (!file_exists($lang_file)) { if (!file_exists($lang_file)) {
error_log("Translation for " . $lang . " not found. Fallback to 'de-de'"); error_log("Translation for '" . $lang . "' not found. Fallback to 'de-de'");
$lang = "de-de"; $lang = "de-de";
} }
$lang_file = __DIR__ . "/lang/lang." . $lang . ".php";
require_once($lang_file); require_once($lang_file);
unset($lang_file); unset($lang_file);
?> ?>

View File

@@ -1,5 +1,4 @@
<?php <?php
/** /**
* Copyright 2018 Matthias Kesler * Copyright 2018 Matthias Kesler
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,65 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/config.php"); require_once("config.php");
$lang=$config["defaultLanguage"];
use PHPMailer\PHPMailer\PHPMailer; if(isset($_GET['lang'])){
use PHPMailer\PHPMailer\Exception; $lang = filter_var($_GET['lang'], FILTER_SANITIZE_STRING);
require_once(__DIR__ . "/vendor/autoload.php");
// standard mail implementation
function send_mail($receiver, $subject, $body) {
// somehow $config is not available when called again => reinit here
include(__DIR__ . "/config.php");
$mail = new PHPMailer(true);
try {
$mail->CharSet = 'utf-8'; // Enable utf-8 support for umlauts
if (is_array($config["smtp"])) {
$smtp_conf = $config["smtp"];
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = $smtp_conf["host"]; // Specify main and backup SMTP servers
$mail->Port = $smtp_conf["port"]; // TCP port to connect to
if (!empty($smtp_conf["user"])) {
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = $smtp_conf["user"]; // SMTP username
if (!empty($smtp_conf["password"])) {
$mail->Password = $smtp_conf["password"]; // SMTP password
}
}
if (!empty($smtp_conf["encryption"])) {
$mail->SMTPSecure = $smtp_conf["encryption"]; // Enable TLS encryption, `ssl` also accepted
}
} else {
// fallback to sendmail functionality (as before)
$mail->isSendmail();
}
//Recipients
$mail->setFrom($config["register_email"], 'Register Service');
$mail->addAddress($receiver);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->send();
return True;
} catch (Exception $e) {
error_log('Message could not be sent. Mailer Error: ' . $mail->ErrorInfo);
return False;
}
} }
$lang_file = dirname(__FILE__) . "/lang/mail.".$lang.".php";
$lang = $config["defaultLanguage"];
if (isset($_GET['lang'])) {
$lang = filter_var($_GET['lang'], FILTER_SANITIZE_STRING);
}
$lang_file = __DIR__ . "/lang/mail." . $lang . ".php";
if (!file_exists($lang_file)) { if (!file_exists($lang_file)) {
error_log("Mail templates for '" . $lang . "' not found. Fallback to 'de-de'"); error_log("Mail templates for '" . $lang . "' not found. Fallback to 'de-de'");
$lang = "de-de"; $lang = "de-de";
} }
$lang_file = __DIR__ . "/lang/mail." . $lang . ".php";
require_once($lang_file); require_once($lang_file);
unset($lang_file); unset($lang_file);
?> ?>

View File

@@ -13,247 +13,222 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once "../language.php";
if (!file_exists("../config.php")) {
print($language["NO_CONFIGURATION"]);
exit();
}
require_once "../config.php";
// enforce admin via https // enforce admin via https
if (!isset($_SERVER['HTTPS'])) { if (!isset($_SERVER['HTTPS'])) {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301); header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
exit(); exit();
} }
require_once(__DIR__ . "/../language.php");
if (!file_exists(__DIR__ . "/../config.php")) {
print($language["NO_CONFIGURATION"]);
exit();
}
require_once(__DIR__ . "/../config.php");
// this values will not be used when using the register operation type
$storeFirstLastName = false;
if (isset($config["operationMode"]) && $config["operationMode"] === "local") {
$storeFirstLastName = true;
}
// currently the case to store the password on our own is the only supported one
$storePassword = false;
if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"] &&
isset($config["operationMode"]) && $config["operationMode"] === "synapse") {
$storePassword = true;
}
session_start(); session_start();
if ($_SERVER["REQUEST_METHOD"] == "POST") { if ($_SERVER["REQUEST_METHOD"] == "POST") {
try { try {
if (!isset($_SESSION["token"]) || !isset($_POST["token"]) || $_SESSION["token"] != $_POST["token"]) { if (!isset($_SESSION["token"]) || !isset($_POST["token"]) || $_SESSION["token"] != $_POST["token"]) {
// token not present or invalid // token not present or invalid
throw new Exception("UNKNOWN_SESSION"); throw new Exception("UNKNOWN_SESSION");
} }
$username = filter_input(INPUT_POST, "username", FILTER_SANITIZE_STRING); if (!isset($_POST["username"])) {
if (empty($username)) { throw new Exception("UNKNOWN_USERNAME");
throw new Exception("UNKNOWN_USERNAME"); }
} if (strlen($_POST["username"] > 20 || strlen($_POST["username"]) < 3)) {
if (strlen($username) > 20 || strlen($username) < 3) { throw new Exception("USERNAME_LENGTH_INVALID");
throw new Exception("USERNAME_INVALID"); }
} if (ctype_alnum($_POST['username']) != true) {
if (!ctype_alnum($username)) { throw new Exception("USERNAME_NOT_ALNUM");
throw new Exception("USERNAME_NOT_ALNUM"); }
} if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"] &&
if (strcmp($username, strtolower($username)) !== 0) { $_POST["password"] != $_POST["password_confirm"]) {
throw new Exception("USERNAME_INVALID"); throw new Exception("PASSWORD_NOT_MATCH");
} }
if ($storePassword && (!isset($_POST["password"]) || !isset($_POST["password_confirm"]))) { if (isset($_POST["note"]) && strlen($_POST["note"]) > 50) {
throw new Exception("PASSWORD_NOT_PROVIDED"); throw new Exception("NOTE_LENGTH_EXEEDED");
} }
if ($storePassword && $_POST["password"] != $_POST["password_confirm"]) { if (!isset($_POST["email"]) || !filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) {
throw new Exception("PASSWORD_NOT_MATCH"); throw new Exception("EMAIL_INVALID_FORMAT");
} }
if (isset($_POST["note"]) && strlen($_POST["note"]) > 50) { if (isset($_POST["first_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["first_name"])) {
throw new Exception("NOTE_LENGTH_EXEEDED"); throw new Exception("FIRSTNAME_INVALID_FORMAT");
} }
if (!isset($_POST["email"]) || !filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) { if (isset($_POST["last_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["last_name"])) {
throw new Exception("EMAIL_INVALID_FORMAT"); throw new Exception("SIRNAME_INVALID_FORMAT");
} }
if ($storeFirstLastName) {
// only require first_name and last_name when we will evaluate them
if (!isset($_POST["first_name"]) || !preg_match("/[A-Z][a-z]+/", $_POST["first_name"])) {
throw new Exception("FIRSTNAME_INVALID_FORMAT");
}
if (!isset($_POST["last_name"]) || !preg_match("/[A-Z][a-z]+/", $_POST["last_name"])) {
throw new Exception("SIRNAME_INVALID_FORMAT");
}
$first_name = filter_var($_POST["first_name"], FILTER_SANITIZE_STRING);
$last_name = filter_var($_POST["last_name"], FILTER_SANITIZE_STRING);
} else {
$first_name = $last_name = "";
}
$password = ""; $first_name = filter_var($_POST["first_name"], FILTER_SANITIZE_STRING);
if ($storePassword && isset($_POST["password"])) { $last_name = filter_var($_POST["last_name"], FILTER_SANITIZE_STRING);
$password = filter_var($_POST["password"], FILTER_SANITIZE_STRING); $username = filter_var($_POST["username"], FILTER_SANITIZE_STRING);
} if (isset($_POST["password"])) {
$note = filter_var($_POST["note"], FILTER_SANITIZE_STRING); $password = filter_var($_POST["password"], FILTER_SANITIZE_STRING);
$email = filter_var($_POST["email"], FILTER_VALIDATE_EMAIL); }
$note = filter_var($_POST["note"], FILTER_SANITIZE_STRING);
$email = filter_var($_POST["email"], FILTER_VALIDATE_EMAIL);
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
$res = $mx_db->addRegistration($first_name, $last_name, $username, $password, $note, $email); $res = $mx_db->addRegistration($first_name, $last_name, $username, $note, $email);
if (!isset($res["verify_token"])) { if (!isset($res["verify_token"])) {
error_log("sth. went wrong. registration did not throw but admin_token not set"); error_log("sth. went wrong. registration did not throw but admin_token not set");
throw Exception("UNKNOWN_ERROR"); throw Exception ("Unknown Error");
} }
$verify_token = $res["verify_token"]; $verify_token = $res["verify_token"];
$verify_url = $config["webroot"] . "/verify.php?t=" . $verify_token; $verify_url = $config["webroot"] . "/verify.php?t=" . $verify_token;
require_once(__DIR__ . "/../mail_templates.php"); require_once "../mail_templates.php";
$success = send_mail_pending_verification( $success = send_mail_pending_verification(
$config["homeserver"], $storeFirstLastName ? $first_name . " " . $last_name : $username, $email, $verify_url); $config["homeserver"],
$first_name . " " . $last_name,
$email,
$verify_url);
$mx_db->setRegistrationStateVerify( $mx_db->setRegistrationStateVerify(
($success ? RegisterState::PendingEmailVerify : RegisterState::PendingEmailSend), $verify_token); ($success ? RegisterState::PendingEmailVerify : RegisterState::PendingEmailSend),
$verify_token);
print("<title>" . $language["SUCCESS"] . "</title>"); print("<title>Erfolgreich</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["SUCCESS"] . "</h1>"); print("<h1>Erfolgreich</h1>");
print("<p>" . $language["TASK_CHECK_YOUR_EMAIL_VERIFY"] . "</p>"); print("<p>Bitte überprüfe deine E-Mails um deine E-Mail-Adresse zu bestätigen.</p>");
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
} catch (Exception $e) { } catch (Exception $e) {
print("<title>" . $language["REGISTRATION_REQUEST_FAILED"] . "</title>"); print("<title>" . $language["REGISTRATION_REQUEST_FAILED"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["REGISTRATION_REQUEST_FAILED"] . "</h1>"); print("<h1>" . $language["REGISTRATION_REQUEST_FAILED"] . "</h1>");
if (isset($language[$e->getMessage()])) { if (isset($language[$e->getMessage()])) {
print("<p>" . $language[$e->getMessage()] . "</p>"); print("<p>" . $language[$e->getMessage()] . "</p>");
} else { } else {
print("<p>" . $e->getMessage() . "</p>"); print("<p>" . $e->getMessage() . "</p>");
} }
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
} }
} else { } else {
$_SESSION["token"] = bin2hex(random_bytes(16)); $_SESSION["token"] = bin2hex(random_bytes(16));
?> ?>
<title><?php echo strtr($language["TOPIC_PLEASE_REGISTER"], ["@homeserver" => $config["homeserver"]]); ?></title> <title>Registriere dich für <?php echo $config["homeserver"]; ?></title>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet"> <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
<style> <style>
body{ body{
background-color: #525252; background-color: #525252;
} }
.centered-form{ .centered-form{
margin-top: 60px; margin-top: 60px;
} }
.centered-form .panel{ .centered-form .panel{
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
box-shadow: rgba(0, 0, 0, 0.3) 20px 20px 20px; box-shadow: rgba(0, 0, 0, 0.3) 20px 20px 20px;
} }
</style> </style>
<script type="text/javascript" src="//code.jquery.com/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script> <script type="text/javascript" src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<div class="row centered-form"> <div class="row centered-form">
<div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4"> <div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"><?php <h3 class="panel-title">Bitte für <?php echo $config["homeserver"]; ?> registrieren<small>2-Schritt-Registrierung</small></h3>
echo strtr($language["TOPIC_PLEASE_REGISTER"], ["@homeserver" => $config["homeserver"]]) </div>
. "<small>" . $language["TOPIC_PLEASE_REGISTER_NOTE"] . "</small>"; <div class="panel-body">
?></h3> <form name="regForm" role="form" action="index.php" method="post">
</div> <div class="row">
<div class="panel-body"> <div class="col-xs-6 col-sm-6 col-md-6">
<form name="regForm" role="form" action="index.php" method="post"> <div class="form-group">
<?php if ($storeFirstLastName) { ?> <input type="text" name="first_name" id="first_name" class="form-control input-sm"
<div class="row"> placeholder="Vorname" pattern="[A-Z][a-z]+">
<div class="col-xs-6 col-sm-6 col-md-6"> </div>
<div class="form-group"> </div>
<input type="text" name="first_name" id="first_name" class="form-control input-sm" <div class="col-xs-6 col-sm-6 col-md-6">
placeholder="<?php echo $language["FIRST_NAME"]; ?>" pattern="[A-Z][a-z]+"> <div class="form-group">
</div> <input type="text" name="last_name" id="last_name" class="form-control input-sm"
</div> placeholder="Nachname" pattern="[A-Z][a-z]+">
<div class="col-xs-6 col-sm-6 col-md-6"> </div>
<div class="form-group"> </div>
<input type="text" name="last_name" id="last_name" class="form-control input-sm" </div>
placeholder="<?php echo $language["LAST_NAME"]; ?>" pattern="[A-Z][a-z]+">
</div>
</div>
</div>
<?php } ?>
<div class="form-group"> <div class="form-group">
<input type="email" name="email" id="email" class="form-control input-sm" placeholder="<?php echo $language["EMAIL_ADDRESS"]; ?>" required> <input type="email" name="email" id="email" class="form-control input-sm" placeholder="E-Mail-Adresse" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="text" name="note" id="note" class="form-control input-sm" placeholder="<?php echo $language["PLACEHOLDER_NOTE_ABOUT_YOURSELF"]; ?>"> <input type="text" name="note" id="note" class="form-control input-sm" placeholder="Notiz zu dir (max. 50 Zeichen)">
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="text" name="username" id="username" class="form-control input-sm" <input type="text" name="username" id="username" class="form-control input-sm"
placeholder="<?php echo $language["USERNAME"]; ?>" pattern="[a-z1-9]{3,20}" required> placeholder="Nutzername (für den Login)" pattern="[a-z1-9]{3,20}" required>
</div> </div>
<?php if ($storePassword) { ?> <?php if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]) { ?>
<div class="row"> <div class="row">
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="password" name="password" id="password" class="form-control input-sm" placeholder="<?php echo $language["PASSWORD"]; ?>" required> <input type="password" name="password" id="password" class="form-control input-sm" placeholder="Passwort" required>
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="password" name="password_confirm" id="password_confirm" class="form-control input-sm" placeholder="<?php echo $language["PASSWORD_CONFIRM"]; ?>" required> <input type="password" name="password_confirm" id="password_confirm" class="form-control input-sm" placeholder="Passwort bestätigen" required>
</div> </div>
</div> </div>
</div> </div>
<?php } ?>
<input type="hidden" name="token" id="token" value="<?php echo $_SESSION["token"]; ?>">
<input type="submit" value="<?php echo $language["REGISTER"]; ?>" class="btn btn-info btn-block">
</form>
<?php
if (isset($language["NOTE_FOR_REGISTRATION"])) {
echo "<p>" . $language["NOTE"] . ": <br />";
echo strtr($language["NOTE_FOR_REGISTRATION"], ["@homeserver" => $config["homeserver"]]);
echo "</p>";
}
?>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var user_name = document.getElementById("username");
user_name.oninvalid = function (event) {
event.target.setCustomValidity("<?php echo $language["USERNAME_INVALID"]; ?>");
}
user_name.onkeyup = function (event) {
event.target.setCustomValidity("");
}
<?php if ($storeFirstLastName) { ?>
var first_name = document.getElementById("first_name");
first_name.oninvalid = function (event) {
event.target.setCustomValidity("<?php echo $language["FIRSTNAME_INVALID_FORMAT"]; ?>");
}
first_name.onkeyup = function (event) {
event.target.setCustomValidity("");
}
var last_name = document.getElementById("last_name");
last_name.oninvalid = function (event) {
event.target.setCustomValidity("<?php echo $language["SIRNAME_INVALID_FORMAT"]; ?>");
}
last_name.onkeyup = function (event) {
event.target.setCustomValidity("");
}
<?php } if ($storePassword) { ?>
var password = document.getElementById("password")
, confirm_password = document.getElementById("password_confirm");
function validatePassword() {
if (password.value != confirm_password.value) {
confirm_password.setCustomValidity("<?php echo $language["PASSWORD_NOT_MATCH"]; ?>");
} else {
confirm_password.setCustomValidity('');
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
<?php } ?> <?php } ?>
</script> <input type="hidden" name="token" id="token" value="<?php echo $_SESSION["token"]; ?>">
<?php } ?> <input type="submit" value="Registrieren" class="btn btn-info btn-block">
</body></html>
</form>
<p>Hinweis: <br />
<?php echo $config["homeserver"]; ?> ist ein geschlossenes Chat-Netzwerk in dem jeder Nutzer bestätigt werden muss.<br />
Du bekommst eine E-Mail wenn jemand deine Mitgliedschaft bestätigt hat. An diese wird auch dein initiales Passwort gesendet.
Hinterlasse also bitte einen Hinweis zu dir (der nur den entsprechenden Personen gezeigt wird).<br />
Liebe Grüße vom Team von <?php echo $config["homeserver"]; ?>
</p>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var first_name = document.getElementById("first_name");
first_name.oninvalid = function(event) {
event.target.setCustomValidity("Vorname muss das Format <Großbuchstabe><Kleinbuchstaben> haben");
}
first_name.onkeyup = function(event) {
event.target.setCustomValidity("");
}
var last_name = document.getElementById("last_name");
last_name.oninvalid = function(event) {
event.target.setCustomValidity("Nachname muss das Format <Großbuchstabe><Kleinbuchstaben> haben");
}
last_name.onkeyup = function(event) {
event.target.setCustomValidity("");
}
var user_name = document.getElementById("username");
user_name.oninvalid = function(event) {
event.target.setCustomValidity("Nutzername darf zwischen 3 und 20 kleine Buchstaben und Zahlen enthalten");
}
user_name.onkeyup = function (event) {
event.target.setCustomValidity("");
}
<?php if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]) { ?>
var password = document.getElementById("password")
, confirm_password = document.getElementById("password_confirm");
function validatePassword(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwörter stimmen nicht überein");
} else {
confirm_password.setCustomValidity('');
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
<?php } ?>
</script>
<?php } ?>
</body>
</html>

View File

@@ -13,90 +13,81 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/../language.php"); require_once "../language.php";
if (!file_exists("../config.php")) { if (!file_exists("../config.php")) {
print($language["NO_CONFIGURATION"]); print($language["NO_CONFIGURATION"]);
exit(); exit();
} }
require_once(__DIR__ . "/../config.php"); require_once "../config.php";
require_once(__DIR__ . "/../mail_templates.php"); require_once "../mail_templates.php";
// enforce admin via https // enforce admin via https
if (!isset($_SERVER['HTTPS'])) { if (!isset($_SERVER['HTTPS'])) {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301); header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
exit(); exit();
} }
session_start(); session_start();
try { try {
if ($_SERVER["REQUEST_METHOD"] != "GET") { if ($_SERVER["REQUEST_METHOD"] != "GET") {
throw new Exception("Method not allowed"); throw new Exception("Method not allowed");
} }
if (!isset($_GET["t"])) { if (!isset($_GET["t"])) {
throw new Exception("UNKNOWN_TOKEN"); throw new Exception("UNKNOWN_TOKEN");
} }
$token = filter_var($_GET["t"], FILTER_SANITIZE_STRING); $token = filter_var($_GET["t"], FILTER_SANITIZE_STRING);
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
$user = $mx_db->getUserForVerify($token); $user = $mx_db->getUserForVerify($token);
if ($user == NULL) { if ($user == NULL) {
throw new Exception("UNKNOWN_TOKEN"); throw new Exception("UNKNOWN_TOKEN");
} }
$first_name = $user["first_name"]; $first_name = $user["first_name"];
$last_name = $user["last_name"]; $last_name = $user["last_name"];
$username = $user["username"]; $note = $user["note"];
$note = $user["note"]; $email = $user["email"];
$email = $user["email"]; $admin_token = $user["admin_token"];
$admin_token = $user["admin_token"];
// we have 2 cases: first and last name or just the username require_once("../MatrixConnection.php");
$call_name = strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username; $adminUrl = $config["webroot"] . "/verify_admin.php?t=" . $admin_token;
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]);
$mxMsg = new MatrixMessage();
$mxMsg->set_body($first_name . ' ' . $last_name . "möchte sich registrieren und hat folgende Notiz hinterlassen:\r\n"
. $note . "\r\n"
. "Zum Bearbeiten hier klicken:\r\n" . $adminUrl);
$mxMsg->set_formatted_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:<br />"
. $note . "<br />"
. "Zum Bearbeiten <a href=\"". $adminUrl . "\">hier</a> klicken");
$mxMsg->set_type("m.text");
$response = $mxConn->send($config["register_room"], $mxMsg);
require_once(__DIR__ . "/../MatrixConnection.php"); if ($response) {
$adminUrl = $config["webroot"] . "/verify_admin.php?t=" . $admin_token; $message = $language["SEND_MATRIX_FAIL"];
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); }
$mxMsg = new MatrixMessage(); $mx_db->setRegistrationStateVerify(
$mxMsg->set_body(strtr($language["MSG_USER_WANTS_REGISTER"], [ ($response ? RegisterState::PendingAdminVerify : RegisterState::PendingAdminSend),
"@name" => $call_name, $token);
"@note" => $note,
"@adminUrl" => $adminUrl
]));
if (isset($language["MSG_USER_WANTS_REGISTER_FORMATTED"])) {
$mxMsg->set_formatted_body(strtr($language["MSG_USER_WANTS_REGISTER_FORMATTED"], [
"@name" => $call_name,
"@note" => $note,
"@adminUrl" => $adminUrl
]));
}
$mxMsg->set_type("m.text");
$response = $mxConn->send($config["register_room"], $mxMsg);
if ($response) { send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email);
$message = $language["SEND_MATRIX_FAIL"];
}
$mx_db->setRegistrationStateVerify(
($response ? RegisterState::PendingAdminVerify : RegisterState::PendingAdminSend), $token);
send_mail_pending_approval($config["homeserver"], $call_name, $email); print("<title>" . $language["VERIFICATION_SUCEEDED"] . "</title>");
print("</head><body>");
print("<title>" . $language["VERIFICATION_SUCEEDED"] . "</title>"); print("<h1>" . $language["VERIFICATION_SUCEEDED"] . "</h1>");
print("</head><body>"); print("<p>" . $language["VERIFICATION_SUCCESS_BODY"] . "</p>");
print("<h1>" . $language["VERIFICATION_SUCEEDED"] . "</h1>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
print("<p>" . $language["VERIFICATION_SUCCESS_BODY"] . "</p>");
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>");
} catch (Exception $e) { } catch (Exception $e) {
print("<title>" . $language["VERIFICATION_FAILED"] . "</title>"); print("<title>" . $language["VERIFICATION_FAILED"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["VERIFICATION_FAILED"] . "</h1>"); print("<h1>" . $language["VERIFICATION_FAILED"] . "</h1>");
if (isset($language[$e->getMessage()])) { if (isset($language[$e->getMessage()])) {
print("<p>" . $language[$e->getMessage()] . "</p>"); print("<p>" . $language[$e->getMessage()] . "</p>");
} else { } else {
print("<p>" . $e->getMessage() . "</p>"); print("<p>" . $e->getMessage() . "</p>");
} }
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
} }
?> ?>
</body> </body>
</html> </html>

View File

@@ -13,238 +13,172 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
require_once(__DIR__ . "/../language.php"); require_once "../language.php";
if (!file_exists("../config.php")) { if (!file_exists("../config.php")) {
print($language["NO_CONFIGURATION"]); print($language["NO_CONFIGURATION"]);
exit(); exit();
} }
require_once(__DIR__ . "/../config.php"); require_once "../config.php";
require_once(__DIR__ . "/../mail_templates.php"); require_once "../mail_templates.php";
// enforce admin via https // enforce admin via https
if (!isset($_SERVER['HTTPS'])) { if (!isset($_SERVER['HTTPS'])) {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301); header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
exit(); exit();
} }
session_start(); session_start();
try { try {
if ($_SERVER["REQUEST_METHOD"] != "GET") { if ($_SERVER["REQUEST_METHOD"] != "GET") {
throw new Exception("Method not allowed"); throw new Exception("Method not allowed");
} }
$token = filter_input(INPUT_GET, "t", FILTER_SANITIZE_STRING); if (!isset($_GET["t"])) {
if (empty($token)) { throw new Exception("UNKNOWN_TOKEN");
throw new Exception("UNKNOWN_TOKEN"); }
} $token = filter_var($_GET["t"], FILTER_SANITIZE_STRING);
require_once(__DIR__ . "/../database.php"); require_once("../database.php");
$param_action = filter_input(INPUT_GET, "d", FILTER_SANITIZE_STRING); $action = NULL;
if ($param_action == "allow") { if (isset($_GET["allow"])) {
$action = RegisterState::RegistrationAccepted; $action = RegisterState::RegistrationAccepted;
} elseif ($param_action == "deny") { }
$action = RegisterState::RegistrationDeclined; $decline_reason = NULL;
$decline_reason = filter_input(INPUT_GET, "decline_reason", FILTER_SANITIZE_STRING); if (isset($_GET["deny"])) {
} $action = RegisterState::RegistrationDeclined;
if (isset($_GET["reason"])) {
$decline_reason = filter_var($_GET["reason"], FILTER_SANITIZE_STRING);
}
}
$user = $mx_db->getUserForApproval($token); $user = $mx_db->getUserForApproval($token);
if ($user == NULL) { if ($user == NULL) {
throw new Exception("UNKNOWN_TOKEN"); throw new Exception("UNKNOWN_TOKEN");
} }
$first_name = $user["first_name"]; $first_name = $user["first_name"];
$last_name = $user["last_name"]; $last_name = $user["last_name"];
$username = $user["username"]; $username = $user["username"];
// we have 2 cases: first and last name or just the username $note = $user["note"];
$call_name = strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username; $email = $user["email"];
$note = $user["note"]; if ($action == RegisterState::RegistrationAccepted) {
$email = $user["email"]; $mx_db->setRegistrationStateAdmin(RegisterState::PendingRegistration, $token);
if ($action == RegisterState::RegistrationAccepted) { // register user
$mx_db->setRegistrationStateAdmin(RegisterState::PendingRegistration, $token); require_once("../MatrixConnection.php");
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]);
// register user // generate a password with 8 characters
require_once(__DIR__ . "/../MatrixConnection.php"); $password = $mx_db->addUser($first_name, $last_name, $username, $email);
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); if ($password != NULL) {
// send registration_success
$res = send_mail_registration_success($config["homeserver"], $first_name . " " . $last_name, $email, $username, $password, $config["howToURL"]);
if ($res) {
$mx_db->setRegistrationStateAdmin(RegisterState::AllDone, $token);
} else {
$mx_db->setRegistrationStateAdmin(RegisterState::PendingSendRegistrationMail, $token);
}
} else {
send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email);
$mxMsg = new MatrixMessage();
$mxMsg->set_type("m.text");
$mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . ".");
$mxConn->send($config["register_room"], $mxMsg);
throw new Exception("REGISTRATION_FAILED");
}
$password = NULL; print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
$use_db_password = (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]); print("</head><body>");
if ($use_db_password && isset($user["password"]) && strlen($user["password"]) > 0) { print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>");
$password = $user["password"]; print("<p>" . $language["ADMIN_REGISTER_ACCEPTED_BODY"] . "</p>");
} else { } elseif ($action == RegisterState::RegistrationDeclined) {
$use_db_password = false; $mx_db->setRegistrationStateAdmin(RegisterState::RegistrationDeclined, $token);
// generate a password with 10 characters send_mail_registration_decline($config["homeserver"], $first_name . " " . $last_name, $email, $decline_reason);
$password = bin2hex(openssl_random_pseudo_bytes(5)); print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
} print("</head><body>");
switch ($config["operationMode"]) { print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>");
case "synapse": print("<p>" . $language["ADMIN_REGISTER_DECLINED_BODY"] . "</p>");
// register with registration_shared_secret } else {
$res = $mxConn->register($username, $password, $config["registration_shared_secret"]);
if (!$res) {
// something went wrong while registering
$password = NULL;
}
break;
case "local":
// register by adding a user to the local database
$password = $mx_db->addUser($first_name, $last_name, $username, $password, $email);
break;
default:
throw new Exception("Unknown operationMode");
}
if ($password != NULL) {
// send registration_success
$res = send_mail_registration_success(
$config["homeserver"],
$call_name,
$email,
$username,
// only send password when auto-created
($use_db_password ? NULL : $password),
$config["howToURL"]
);
if ($res) {
$mx_db->setRegistrationStateAdmin(RegisterState::AllDone, $token);
} else {
$mx_db->setRegistrationStateAdmin(RegisterState::PendingSendRegistrationMail, $token);
}
} else {
send_mail_registration_allowed_but_failed($config["homeserver"], $call_name, $email);
$mxMsg = new MatrixMessage();
$mxMsg->set_type("m.text");
$mxMsg->set_body(strtr($language["REGISTRATION_FAILED_FOR"], [
"@name" => $call_name,
]));
$mxConn->send($config["register_room"], $mxMsg);
throw new Exception("REGISTRATION_FAILED");
}
print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>"); print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
print("</head><body>"); ?>
print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>"); <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
print("<p>" . $language["ADMIN_REGISTER_ACCEPTED_BODY"] . "</p>"); <style>
} elseif ($action == RegisterState::RegistrationDeclined) { body{
$mx_db->setRegistrationStateAdmin(RegisterState::RegistrationDeclined, $token); background-color: #525252;
send_mail_registration_decline( }
$config["homeserver"], $call_name, $email, $decline_reason .centered-form{
); margin-top: 60px;
print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>"); }
print("</head><body>");
print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>");
print("<p>" . $language["ADMIN_REGISTER_DECLINED_BODY"] . "</p>");
} else {
print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
?>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
<style>
body{
background-color: #525252;
}
.centered-form{
margin-top: 60px;
}
.centered-form .panel{ .centered-form .panel{
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
box-shadow: rgba(0, 0, 0, 0.3) 20px 20px 20px; box-shadow: rgba(0, 0, 0, 0.3) 20px 20px 20px;
} }
</style> </style>
<script type="text/javascript" src="//code.jquery.com/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script> <script type="text/javascript" src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<div class="row centered-form"> <div class="row centered-form">
<div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4"> <div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"><?php echo $language["ADMIN_VERIFY_SITE_TITLE"]; ?></h3> <h3 class="panel-title"><?php echo $language["ADMIN_VERIFY_SITE_TITLE"] ; ?></h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form name="appForm" role="form" onsubmit="return submitForm()" action="verify_admin.php" method="GET"> <form name="appForm" role="form" action="verify_admin.php" method="GET">
<?php <div class="row">
if (isset($config["operationMode"]) && $config["operationMode"] === "local") { <div class="col-xs-6 col-sm-6 col-md-6">
// this values will not be used when using the register operation type <div class="form-group">
?> <input type="text" id="first_name" class="form-control input-sm"
<div class="row"> value="<?php echo $first_name; ?>" disabled=true>
<div class="col-xs-6 col-sm-6 col-md-6"> </div>
<div class="form-group"> </div>
<input type="text" id="first_name" class="form-control input-sm" <div class="col-xs-6 col-sm-6 col-md-6">
value="<?php echo $first_name; ?>" disabled=true> <div class="form-group">
</div> <input type="text" id="last_name" class="form-control input-sm"
</div> value="<?php echo $last_name; ?>" disabled=true>
<div class="col-xs-6 col-sm-6 col-md-6"> </div>
<div class="form-group"> </div>
<input type="text" id="last_name" class="form-control input-sm" </div>
value="<?php echo $last_name; ?>" disabled=true>
</div>
</div>
</div>
<?php } ?>
<div class="form-group">
<input type="text" id="note" class="form-control input-sm" value="<?php echo $note; ?>" disabled=true>
</div>
<div class="form-group"> <div class="form-group">
<input type="text" id="username" class="form-control input-sm" <input type="text" id="note" class="form-control input-sm" value="<?php echo $note; ?>" disabled=true>
value="<?php echo $username; ?>" disabled=true> </div>
</div>
<div class="form-group"> <div class="form-group">
<input type="hidden" name="decline_reason" class="form-control input-sm" <input type="text" id="username" class="form-control input-sm"
placeholder="<?php echo $language["DECLINE_REASON"]; ?>"> value="<?php echo $username; ?>" disabled=true>
</div> </div>
<input type="hidden" name="t" id="token" value="<?php echo $token; ?>"> <input type="hidden" name="t" id="token" value="<?php echo $token; ?>">
<div class="form-group"> <input type="submit" name="allow" value="Bestätigen" class="btn btn-info btn-block">
<input type="radio" name="d" value="allow"><?php echo $language["ACCEPT"]; ?> <input type="submit" name="deny" value="Ablehnen" class="btn btn-info btn-block">
<input type="radio" name="d" value="deny"><?php echo $language["DECLINE"]; ?>
</div> </form>
<input type="submit" value="<?php echo $language["SUBMIT"]; ?>" class="btn btn-info btn-block"> </div>
</form> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <script type="text/javascript">
</div>
<script type="text/javascript"> <?php
var rad = document.appForm.d; } // else - no action provided
function isSelected() { } catch (Exception $e) {
for (var i=0; i<rad.length; i++) print("<title>" . $language["REGISTRATION_FAILED"] . "</title>");
if (rad[i].checked) print("</head><body>");
return true; print("<h1>" . $language["REGISTRATION_FAILED"] . "</h1>");
return false; if (isset($language[$e->getMessage()])) {
} print("<p>" . $language[$e->getMessage()] . "</p>");
function submitForm() { } else {
if (isSelected()) { print("<p>" . $e->getMessage() . "</p>");
return true; }
} print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
alert("<?php echo $language["MAKE_A_SELECTION"];?>"); }
return false; ?>
} </body>
for(var i = 0; i < rad.length; i++) {
rad[i].onclick = function() {
if (this.value === "deny") {
document.appForm.decline_reason.type = "text";
} else {
document.appForm.decline_reason.type = "hidden";
}
};
}
</script>
<?php
} // else - no action provided
} catch (Exception $e) {
print("<title>" . $language["REGISTRATION_FAILED"] . "</title>");
print("</head><body>");
print("<h1>" . $language["REGISTRATION_FAILED"] . "</h1>");
if (isset($language[$e->getMessage()])) {
print("<p>" . $language[$e->getMessage()] . "</p>");
} else {
print("<p>" . $e->getMessage() . "</p>");
}
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>");
}
?>
</body>
</html> </html>