11 Commits

Author SHA1 Message Date
5eeaa11c0c fix in config.sample 2018-04-16 15:17:58 +02:00
f74a2f74e0 fix path to config.php in mail.l.php 2018-04-16 15:15:32 +02:00
53ccd1c2b3 hopefully complete operationMode=synapse 2018-04-16 15:06:44 +02:00
6d19d869c8 Merge branch 'master' into feature_multimodeOperation 2018-04-16 14:52:09 +02:00
6143a23dd8 autoformat to reduce merge conflicts 2018-04-16 14:29:40 +02:00
Matthias
31bacaeb36 Implement multilanguage
This completes the multilanguage support

For this a new setting in the config got added "defaultLanguage"
2018-04-16 14:18:26 +02:00
79341b4c88 run some autoformat 2018-04-15 22:01:22 +02:00
f808615f22 start implementing multiple modes for operation
- synapse: Only trigger register calls and do not store anything for longterm
- local: Provide an identity store and register to the own backend
2018-04-15 21:36:24 +02:00
ffce2fc28b run some autoformat 2018-04-04 20:43:24 +02:00
eb5b76c5c8 smaller optimizations 2018-04-04 20:29:00 +02:00
Matthias
b343c6f862 Update readme to have howTo for ChangePasswordInterceptor 2018-03-26 23:27:04 +02:00
20 changed files with 1167 additions and 1015 deletions

View File

@@ -1,4 +1,5 @@
<?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");
@@ -13,157 +14,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 class MatrixConnection {
{
private $hs;
private $at;
function __construct($homeserver, $access_token) { private $hs;
$this->hs = $homeserver; private $at;
$this->at = $access_token;
}
function send($room_id, $message) { function __construct($homeserver, $access_token) {
if (!$this->at) { $this->hs = $homeserver;
error_log("No access token defined"); $this->at = $access_token;
return false; }
}
$send_message = NULL; function send($room_id, $message) {
if (!$message) { if (!$this->at) {
error_log("no message to send"); error_log("No access token defined");
return false; 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;
}
$url="https://".$this->hs."/_matrix/client/r0/rooms/" $send_message = NULL;
. urlencode($room_id) ."/send/m.room.message?access_token=".$this->at; if (!$message) {
$handle = curl_init($url); error_log("no message to send");
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); return false;
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); } elseif (is_array($message)) {
curl_setopt($handle, CURLOPT_TIMEOUT, 60); $send_message = $message;
curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($send_message)); } elseif ($message instanceof MatrixMessage) {
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json")); $send_message = $message->get_object();
} else {
error_log("message is of not valid type\n");
return false;
}
$response = $this->exec_curl_request($handle); $url = "https://" . $this->hs . "/_matrix/client/r0/rooms/"
return isset($response["event_id"]); . urlencode($room_id) . "/send/m.room.message?access_token=" . $this->at;
} $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_msg($room_id, $message) { $response = $this->exec_curl_request($handle);
return $this->send($room_id, array( return isset($response["event_id"]);
"msgtype" => "m.notice", }
"body" => $message
)
);
}
function hasUser($username) { function send_msg($room_id, $message) {
if (!$username) { return $this->send($room_id, array(
throw new Exception ("no user given to lookup"); "msgtype" => "m.notice",
} "body" => $message
)
);
}
$url = "https://".$this->hs."/_matrix/client/r0/profile/@" . $username . ":" . $this->hs; function hasUser($username) {
$handle = curl_init($url); if (!$username) {
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); throw new Exception("no user given to lookup");
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); }
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
$res = $this->exec_curl_request($handle); $url = "https://" . $this->hs . "/_matrix/client/r0/profile/@" . $username . ":" . $this->hs;
return !(isset($res["errcode"]) && $res["errcode"] == "M_UNKNOWN"); $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 register($username, $password, $shared_secret) { $res = $this->exec_curl_request($handle);
if (!$username) { return !(isset($res["errcode"]) && $res["errcode"] == "M_UNKNOWN");
error_log("no username provided"); }
}
if (!$password) {
error_log("no message to send");
}
$mac = hash_hmac('sha1', $username, $shared_secret); function register($username, $password, $shared_secret) {
if (!$username) {
error_log("no username provided");
}
if (!$password) {
error_log("no message to send");
}
$data = array( $mac = hash_hmac('sha1', $username, $shared_secret);
"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));
return $this->exec_curl_request($handle); $data = array(
} "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 exec_curl_request($handle) { return $this->exec_curl_request($handle);
$response = curl_exec($handle); }
if ($response === false) { function exec_curl_request($handle) {
$errno = curl_errno($handle); $response = curl_exec($handle);
$error = curl_error($handle); if ($response === false) {
error_log("Curl returned error $errno: $error\n"); $errno = curl_errno($handle);
curl_close($handle); $error = curl_error($handle);
return false; 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);
$http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE)); if ($http_code >= 500) {
curl_close($handle); // 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('Invalid access token provided');
}
} else {
$response = json_decode($response, true);
}
return $response;
}
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('Invalid access token provided');
}
} else {
$response = json_decode($response, true);
}
return $response;
}
} }
class MatrixMessage class MatrixMessage {
{
private $message;
function __construct() { private $message;
$this->message = ["msgtype" => "m.notice"];
}
function set_type($msgtype) { function __construct() {
$this->message["msgtype"] = $msgtype; $this->message = ["msgtype" => "m.notice"];
} }
function set_format($format) { function set_type($msgtype) {
$this->message["format"] = $format; $this->message["msgtype"] = $msgtype;
} }
function set_body($body) { function set_format($format) {
$this->message["body"] = $body; $this->message["format"] = $format;
} }
function set_formatted_body($fbody, $format="org.matrix.custom.html") { function set_body($body) {
$this->message["formatted_body"] = $fbody; $this->message["body"] = $body;
$this->message["format"] = $format; }
}
function set_formatted_body($fbody, $format = "org.matrix.custom.html") {
$this->message["formatted_body"] = $fbody;
$this->message["format"] = $format;
}
function get_object() {
return $this->message;
}
function get_object() {
return $this->message;
}
} }
?> ?>

View File

@@ -14,14 +14,15 @@ This is done in several steps:
2nd step: Implement the other apis to integrade [mxisd](https://github.com/kamax-io/mxisd/blob/master/docs/backends/rest.md) 2nd step: Implement the other apis to integrade [mxisd](https://github.com/kamax-io/mxisd/blob/master/docs/backends/rest.md)
This bot takes care for user accounts. So it stores the credentials itself and provides ways to access them via matrix-synapse-rest-auth or mxisd.
## How to install ## How to install
- Copy `config.sample.php` to `config.php` and configure the bot as you can find there - Copy `config.sample.php` to `config.php` and configure the bot as you can find there
- Configure your webserver to publish the folder `public` and configure. - Configure your webserver to publish the folder `public`.
The folder `internal` contains files that can be accessed by mxisd or matrix-synapse-rest-auth The folder `internal` contains files that can be accessed by mxisd or matrix-synapse-rest-auth or else via a reverse proxy
- To integrate with 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: Have a look at [the docs](https://github.com/kamax-io/mxisd/blob/master/docs/backends/rest.md) and apply as follows: - To integrate with [mxisd](https://github.com/kamax-io/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 |
@@ -30,3 +31,17 @@ This is done in several steps:
| 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 |
## Implement usage of additional features:
### Use the ChangePasswortInterceptor:
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;
}
```

View File

@@ -1,29 +1,39 @@
<?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? // Where should the bot post registration requests to?
"register_room" => '$registerRoomID:example.com', "register_room" => '$registerRoomID:example.com',
// Where is the public part of the bot located? make sure you have a / at the end // Where is the public part of the bot located? make sure you have a / at the end
"webroot" => "https://myregisterdomain.net/", "webroot" => "https://myregisterdomain.net/",
// optional: Do you have a place where howTo's are located? If not leave this value out // optional: Do you have a place where howTo's are located? If not leave this value out
"howToURL" => "https://my-url-for-storing-howTos.net", "howToURL" => "https://my-url-for-storing-howTos.net",
// When you want to collect the password on registration set this to true // set the mode of operation. Basically this defines where the data is stored:
"getPasswordOnRegistration" => false, // - synapse (using the register endpoint - so no further auth config necessary
// - local (recommended; using a table in the database to store credentials;
// synapse has to be configured to use that)
"operationMode" => "local",
// to define where the data should be stored: // This setting is only required for operationMode = synapse
"databaseURI" => "sqlite:" . dirname(__FILE__) . "/db_file.sqlite", "registration_shared_secret" => "SOME_SECRET_KEY_FROM_HOMESERVER_CONFIG",
// credentials for sqlite not used
"databaseUser" => "dbUser123",
"databasePass" => "secretPassword",
// default language: one of [ en-gb | de-de ] // When you want to collect the password on registration set this to true
"defaultLanguage" => "en-gb" // 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",
]
?> ?>

154
cron.php
View File

@@ -1,4 +1,5 @@
<?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");
@@ -18,89 +19,86 @@ require_once("mail_templates.php");
require_once("database.php"); require_once("database.php");
$sql = "SELECT id, first_name, last_name, username, email, state, note, verify_token, admin_token FROM registrations " $sql = "SELECT id, first_name, last_name, username, email, state, note, verify_token, admin_token FROM registrations "
."WHERE state = ". RegisterState::PendingEmailSend . "WHERE state = " . RegisterState::PendingEmailSend
. " OR state = " . RegisterState::PendingAdminSend . " OR state = " . RegisterState::PendingAdminSend
. " OR state = " . RegisterState::PendingRegistration . " OR state = " . RegisterState::PendingRegistration
. " OR state = " . RegisterState::PendingSendRegistrationMail . " OR state = " . RegisterState::PendingSendRegistrationMail
. " OR state = " . RegisterState::RegistrationDeclined . " OR state = " . RegisterState::RegistrationDeclined
. " OR state = " . RegisterState::AllDone . ";"; . " 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"], $config["homeserver"], $row["first_name"] . " " . $row["last_name"], $row["email"], $verify_url);
$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("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($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:\r\n" $mxMsg->set_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:\r\n"
. $row["note"] . "\r\n" . $row["note"] . "\r\n"
. "Zum Bearbeiten hier klicken:\r\n" . $adminUrl); . "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 />" $mxMsg->set_formatted_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:<br />"
. $row["note"] . "<br />" . $row["note"] . "<br />"
. "Zum Bearbeiten <a href=\"". $adminUrl . "\">hier</a> klicken"); . "Zum Bearbeiten <a href=\"" . $adminUrl . "\">hier</a> klicken");
$mxMsg->set_type("m.text"); $mxMsg->set_type("m.text");
$response = $mxConn->send($config["register_room"], $mxMsg); $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
$password = $mx_db->addUser($row["first_name"], $row["last_name"], $row["username"], $row["email"]); $password = $mx_db->addUser($row["first_name"], $row["last_name"], $row["username"], $row["email"]);
if ($password != NULL) { if ($password != NULL) {
// send registration_success // send registration_success
$res = send_mail_registration_success($config["homeserver"], $first_name . " " . $last_name, $email, $username, $password, $config["howToURL"]); $res = send_mail_registration_success($config["homeserver"], $first_name . " " . $last_name, $email, $username, $password, $config["howToURL"]);
if ($res) { if ($res) {
$mx_db->setRegistrationStateById(RegisterState::AllDone, $row["id"]); $mx_db->setRegistrationStateById(RegisterState::AllDone, $row["id"]);
} else { } else {
$mx_db->setRegistrationStateById(RegisterState::PendingSendRegistrationMail, $row["id"]); $mx_db->setRegistrationStateById(RegisterState::PendingSendRegistrationMail, $row["id"]);
} }
} else { } else {
send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email); send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email);
$mxMsg = new MatrixMessage(); $mxMsg = new MatrixMessage();
$mxMsg->set_type("m.text"); $mxMsg->set_type("m.text");
$mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . "."); $mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . ".");
$mxConn->send($config["register_room"], $mxMsg); $mxConn->send($config["register_room"], $mxMsg);
throw new Exception($language["REGISTRATION_FAILED"]); throw new Exception($language["REGISTRATION_FAILED"]);
} }
break; break;
case RegisterState::PendingSendRegistrationMail: case RegisterState::PendingSendRegistrationMail:
print ("Error: Unhandled state: PendingSendRegistrationMail for " . $first_name . " " . $last_name . " (" . $username . ")\n"); print ("Error: Unhandled state: PendingSendRegistrationMail for " . $first_name . " " . $last_name . " (" . $username . ")\n");
break; break;
case RegisterState::RegistrationDeclined: case RegisterState::RegistrationDeclined:
case RegisterState::AllDone: case RegisterState::AllDone:
// do reqular cleanup // do reqular cleanup
break; break;
} }
} catch (Exception $e) { } catch (Exception $e) {
print("Error while handling cron for " . $first_name . " " . $last_name . " (" . $username . ")\n"); print("Error while handling cron for " . $first_name . " " . $last_name . " (" . $username . ")\n");
print($e->getMessage()); print($e->getMessage());
} }
} }
?> ?>

View File

@@ -1,4 +1,5 @@
<?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,65 +16,63 @@
*/ */
require_once("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;
// in this case we have to reset the password of the user (or should we store it for this case?) // Sending an E-Mail failed in the first attempt. Will retry later
const PendingSendRegistrationMail = 8; 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;
// 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: /**
* databaseURI: path to the sqlite file where the credentials should be stored * Creates mxDatabase object
* or a param which can be used to connect to a database with PDO * @param config object which has following members:
* databaseUser and databasePass when authentication is required * databaseURI: path to the sqlite file where the credentials should be stored
* register_email which email does the register bot have (here used for providing lookup) * or a param which can be used to connect to a database with PDO
*/ * databaseUser and databasePass when authentication is required
function __construct($config) { * register_email which email does the register bot have (here used for providing lookup)
if (empty($config)) { */
throw new Exception("config is empty"); function __construct($config) {
} if (empty($config)) {
if (!isset($config["databaseURI"])) { throw new Exception("config is empty");
throw new Exception("'databaseURI' not defined"); }
} if (!isset($config["databaseURI"])) {
$db_input = $config["databaseURI"]; throw new Exception("'databaseURI' not defined");
$user = ''; }
$password = ''; $db_input = $config["databaseURI"];
if (isset($config["databaseUser"]) && isset($config["databasePass"])) { $user = '';
// only use it when both are defined $password = '';
$user = $config["databaseUser"]; if (isset($config["databaseUser"]) && isset($config["databasePass"])) {
$password = $config["databasePass"]; // only use it when both are defined
} $user = $config["databaseUser"];
// create database file when not existent yet $password = $config["databasePass"];
$this->db = new PDO($db_input, $user, $password); }
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // create database file when not existent yet
$this->db->exec("CREATE TABLE IF NOT EXISTS registrations( $this->db = new PDO($db_input, $user, $password);
$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,
@@ -86,7 +85,7 @@ class mxDatabase
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,
@@ -97,273 +96,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", $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) {
* Adds user to the database. Next steps should be sending a verify-mail to the user $sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $username . "' LIMIT 1;";
* @param first_name First name of the user $res = $this->db->query($sql);
* @param last_name Sirname of the user if ($res->fetchColumn() > 0) {
* @param username the future localpart of that user return true;
* @param note Note the user typed in to give a hint }
* @param email E-Mail-Adress which will be stored into the database. return false;
* 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)); /**
$admin_token = bin2hex(random_bytes(16)); * Adds user to the database. Next steps should be sending a verify-mail to the user
* @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, $note, $email) {
if ($this->userPendingRegistrations($username)) {
throw new Exception("USERNAME_PENDING_REGISTRATION");
}
if ($this->userRegistered($username)) {
throw new Exception("USERNAME_REGISTERED");
}
$this->db->exec("INSERT INTO registrations $verify_token = bin2hex(random_bytes(16));
$admin_token = bin2hex(random_bytes(16));
$this->db->exec("INSERT INTO registrations
(first_name, last_name, username, note, email, verify_token, admin_token) (first_name, last_name, username, note, email, verify_token, admin_token)
VALUES ('" . $first_name."','" . $last_name . "','" . $username . "','" . $note . "','" VALUES ('" . $first_name . "','" . $last_name . "','" . $username . "','" . $note . "','"
. $email."','" .$verify_token."','" .$admin_token."')"); . $email . "','" . $verify_token . "','" . $admin_token . "')");
return [ return [
"verify_token"=> $verify_token, "verify_token" => $verify_token,
]; ];
} }
/** /**
* Gets the user for the verify_admin page. * Gets the user for the verify_admin page.
* *
* @return ArrayOfUser|NULL Array with "first_name, last_name, username, note and email" * @return ArrayOfUser|NULL Array with "first_name, last_name, username, note and email"
* as members * as members
*/ */
function getUserForApproval($admin_token) { function getUserForApproval($admin_token) {
$sql = "SELECT COUNT(*) FROM registrations WHERE admin_token = '" . $admin_token . "'" $sql = "SELECT COUNT(*) FROM registrations WHERE admin_token = '" . $admin_token . "'"
. " AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;"; . " AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;";
$res = $this->db->query($sql); $res = $this->db->query($sql);
$first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
if ($res->fetchColumn() > 0) { if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, username, note, email FROM registrations" $sql = "SELECT first_name, last_name, username, note, email FROM registrations"
. " WHERE admin_token = '" . $admin_token . "'" . " WHERE admin_token = '" . $admin_token . "'"
. " AND state = " . RegisterState::PendingAdminVerify . " AND state = " . RegisterState::PendingAdminVerify
. " LIMIT 1;"; . " LIMIT 1;";
foreach ($this->db->query($sql) as $row) { foreach ($this->db->query($sql) as $row) {
// will only be executed once // will only be executed once
return $row; return $row;
} }
} }
return NULL; return NULL;
} }
/** /**
* Gets the user when it opens the page to verify its mail * Gets the user when it opens the page to verify its mail
* *
* @return ArrayOfUser|NULL Array with "first_name, last_name, note, email and admin_token" * @return ArrayOfUser|NULL Array with "first_name, last_name, note, email and admin_token"
* as members * as members
*/ */
function getUserForVerify($verify_token) { function getUserForVerify($verify_token) {
$sql = "SELECT COUNT(*) FROM registrations WHERE verify_token = '" . $verify_token . "'" $sql = "SELECT COUNT(*) FROM registrations WHERE verify_token = '" . $verify_token . "'"
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;"; . " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
$res = $this->db->query($sql); $res = $this->db->query($sql);
$first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
if ($res->fetchColumn() > 0) { if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, note, email, admin_token FROM registrations " $sql = "SELECT first_name, last_name, note, email, username, admin_token FROM registrations "
. " WHERE verify_token = '" . $verify_token . "'" . " WHERE verify_token = '" . $verify_token . "'"
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;"; . " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
foreach ($this->db->query($sql) as $row) { foreach ($this->db->query($sql) as $row) {
// will only be executed once // will only be executed once
return $row; return $row;
} }
} }
return NULL; return NULL;
} }
function getUserForLogin($localpart, $password) { function getUserForLogin($localpart, $password) {
$sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $localpart $sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $localpart
. "' AND active = 1 LIMIT 1;"; . "' AND active = 1 LIMIT 1;";
$res = $this->db->query($sql); $res = $this->db->query($sql);
if ($res->fetchColumn() > 0) { if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, email, password_hash FROM logins " $sql = "SELECT first_name, last_name, email, password_hash FROM logins "
. " WHERE localpart = '" . $localpart . "' AND active = 1 LIMIT 1;"; . " WHERE localpart = '" . $localpart . "' AND active = 1 LIMIT 1;";
foreach ($this->db->query($sql) as $row) { foreach ($this->db->query($sql) as $row) {
if (password_verify($password, $row["password_hash"])) { if (password_verify($password, $row["password_hash"])) {
return $row; return $row;
} }
} }
} }
return NULL; return NULL;
} }
/** /**
* adds User to be able to login afterwards. * adds User to be able to login afterwards.
* @param first_name First name of the user * @param first_name First name of the user
* @param last_name Sirname of the user * @param last_name Sirname of the user
* @param username the future localpart of that user * @param username the future localpart of that user
* @param email E-Mail-Adress which will be stored into the database. * @param email E-Mail-Adress which will be stored into the database.
* This will be send to the server on first login * This will be send to the server on first login
* *
* @return password|NULL with member password as this method generates a * @return password|NULL with member password as this method generates a
* password and saves that into the database * password and saves that into the database
* NULL when failed * NULL when failed
* *
*/ */
function addUser($first_name, $last_name, $username, $email) { function addUser($first_name, $last_name, $username, $email) {
// check if user already exists and abort in that case // check if user already exists and abort in that case
if ($this->userRegistered($username)) { if ($this->userRegistered($username)) {
return NULL; return NULL;
} }
// generate a password with 10 characters // generate a password with 10 characters
$password = bin2hex(openssl_random_pseudo_bytes(5)); $password = bin2hex(openssl_random_pseudo_bytes(5));
$password_hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>12]); $password_hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 12]);
$sql = "INSERT INTO logins (first_name, last_name, localpart, password_hash, email) VALUES " $sql = "INSERT INTO logins (first_name, last_name, localpart, password_hash, email) VALUES "
. "('" . $first_name."','" . $last_name . "','" . $username . "','" . "('" . $first_name . "','" . $last_name . "','" . $username . "','"
. $password_hash . "','" . $email . "');"; . $password_hash . "','" . $email . "');";
if ($this->db->exec($sql)) { if ($this->db->exec($sql)) {
return $password; return $password;
} }
return NULL; return NULL;
} }
function updatePassword($localpart, $old_password, $new_password) { function updatePassword($localpart, $old_password, $new_password) {
$user = $this->getUserForLogin($localpart, $old_password); $user = $this->getUserForLogin($localpart, $old_password);
if ($user == NULL) { if ($user == NULL) {
throw new Exception ("user with that credentials not found"); throw new Exception("user with that credentials not found");
} }
// The credentials were fine. So now set the new password // The credentials were fine. So now set the new password
$password_hash = password_hash($new_password, PASSWORD_BCRYPT, ["cost"=>12]); $password_hash = password_hash($new_password, PASSWORD_BCRYPT, ["cost" => 12]);
$sql = "UPDATE logins SET password_hash = '" . $password_hash . "'" $sql = "UPDATE logins SET password_hash = '" . $password_hash . "'"
. "WHERE localpart = '" . $localpart . "'"; . "WHERE localpart = '" . $localpart . "'";
if ($this->db->exec($sql)) { if ($this->db->exec($sql)) {
return true; return true;
} }
return false; return false;
} }
function searchUserByName($search_term) { function searchUserByName($search_term) {
$term = filter_var($search_term, FILTER_SANITIZE_STRING); $term = filter_var($search_term, FILTER_SANITIZE_STRING);
$result = array(); $result = array();
$sql = "SELECT COUNT(*) FROM logins WHERE" $sql = "SELECT COUNT(*) FROM logins WHERE"
. " localpart LIKE '" . $term . "%' AND active = 1;"; . " localpart LIKE '" . $term . "%' AND active = 1;";
$res = $this->db->query($sql); $res = $this->db->query($sql);
if ($res->fetchColumn() > 0) { if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, localpart FROM logins WHERE" $sql = "SELECT first_name, last_name, localpart FROM logins WHERE"
. " localpart LIKE '" . $term . "%' AND active = 1;"; . " localpart LIKE '" . $term . "%' AND active = 1;";
foreach ($this->db->query($sql) as $row) { foreach ($this->db->query($sql) as $row) {
array_push($result, [ array_push($result, [
"display_name" => $row["first_name"] . " " . $row["last_name"], "display_name" => $row["first_name"] . " " . $row["last_name"],
"user_id" => $row["localpart"], "user_id" => $row["localpart"],
]); ]);
} }
} }
return $result; return $result;
} }
function searchUserByEmail($search_term) { function searchUserByEmail($search_term) {
$term = filter_var($search_term, FILTER_SANITIZE_STRING); $term = filter_var($search_term, FILTER_SANITIZE_STRING);
$result = array(); $result = array();
$sql = "SELECT COUNT(*) FROM logins WHERE" $sql = "SELECT COUNT(*) FROM logins WHERE"
. " email = '" . $term . "' AND active = 1;"; . " email = '" . $term . "' AND active = 1;";
$res = $this->db->query($sql); $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,18 +1,33 @@
<?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;
} }
?> ?>

View File

@@ -1,4 +1,5 @@
<?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 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
require_once("../database.php"); require_once("../database.php");
$response=[ $response = [
"limited" => false, "limited" => false,
"result" => [], "result" => [],
]; ];
@@ -23,7 +24,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');
@@ -39,12 +40,11 @@ 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) . "\n"); print (json_encode($response, JSON_PRETTY_PRINT));
?> ?>

View File

@@ -1,4 +1,5 @@
<?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");
@@ -21,7 +22,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"])) {
@@ -37,31 +38,33 @@ 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 = array(); $res2 = NULL;
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 type for \"by\" param"); throw new Exception("unknown lookup medium");
} }
} }
} 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) . "\n"); print (json_encode($response, JSON_PRETTY_PRINT));
?> ?>

View File

@@ -1,4 +1,5 @@
<?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");
@@ -19,7 +20,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["lookup"])) { if (!isset($input["lookup"])) {
throw new Exception('"lookup" is not defined'); throw new Exception('"lookup" is not defined');
@@ -30,7 +31,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 = array(); $res2 = NULL;
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"]);
@@ -46,15 +47,19 @@ try {
] ]
]; ];
} }
break;
case "msisdn":
// This is reserved for number lookups
throw new Exception("unimplemented lookup medium");
break; break;
default: default:
throw new Exception("unknown type for \"by\" param"); throw new Exception("unknown lookup medium");
} }
} catch (Exception $e) { } catch (Exception $e) {
error_log("ídentity_bulk failed with error: " . $e->getMessage()); error_log("ídentity_single failed with error: " . $e->getMessage());
$response["error"] = $e->getMessage(); $response = [
"error" => $e->getMessage()
];
} }
print (json_encode($response, JSON_PRETTY_PRINT) . "\n"); print (json_encode($response, JSON_PRETTY_PRINT));
?> ?>

View File

@@ -1,4 +1,5 @@
<?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");
@@ -13,60 +14,56 @@
* 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("../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("../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,4 +1,5 @@
<?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,18 +21,21 @@ $response = [
]; ];
require_once("../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 = NULL; $mxid = $localpart = 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"];
@@ -45,25 +49,27 @@ 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("../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"]) && isset($input["user"]["password"])) { if (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);
@@ -95,11 +101,12 @@ 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) . "\n"); print (json_encode($response, JSON_PRETTY_PRINT));
?> ?>

View File

@@ -1,4 +1,5 @@
<?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 +15,19 @@
* limitations under the License. * limitations under the License.
*/ */
$language = array( $language = array(
"ACCEPT" => "Akzeptieren",
"DECLINE" => "Ablehnen",
"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",
@@ -24,18 +37,32 @@ $language = array(
"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_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 hat ungültiges Format", "FIRSTNAME_INVALID_FORMAT" => "Vorname muss das Format <Großbuchstabe><Kleinbuchstaben> haben",
"SIRNAME_INVALID_FORMAT" => "Nachname hat ungültiges Format", "SIRNAME_INVALID_FORMAT" => "Nachname muss das Format <Großbuchstabe><Kleinbuchstaben> haben",
"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

@@ -14,7 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
$language = array( $language = array(
"ACCEPT" => "Accept",
"DECLINE" => "Decline",
"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",
@@ -24,18 +36,31 @@ $language = array(
"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_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<small>2-Step-Registration</small>",
"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

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
function send_mail($receiver, $subject, $body) { function send_mail($receiver, $subject, $body) {
include("config.php"); include("../config.php");
$headers = "From: " . $config["register_email"] . "\r\n" $headers = "From: " . $config["register_email"] . "\r\n"
. "Content-Type: text/plain;charset=utf-8"; . "Content-Type: text/plain;charset=utf-8";
return mail($receiver, $subject, $body, $headers); return mail($receiver, $subject, $body, $headers);

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
function send_mail($receiver, $subject, $body) { function send_mail($receiver, $subject, $body) {
include("config.php"); include("../config.php");
$headers = "From: " . $config["register_email"] . "\r\n" $headers = "From: " . $config["register_email"] . "\r\n"
. "Content-Type: text/plain;charset=utf-8"; . "Content-Type: text/plain;charset=utf-8";
return mail($receiver, $subject, $body, $headers); return mail($receiver, $subject, $body, $headers);

View File

@@ -1,4 +1,5 @@
<?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,16 +15,17 @@
* limitations under the License. * limitations under the License.
*/ */
require_once("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 = dirname(__FILE__) . "/lang/lang." . $lang . ".php";
require_once($lang_file); require_once($lang_file);
unset($lang_file); unset($lang_file);
?> ?>

View File

@@ -1,4 +1,5 @@
<?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,15 +15,16 @@
* limitations under the License. * limitations under the License.
*/ */
require_once("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/mail.".$lang.".php"; $lang_file = dirname(__FILE__) . "/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 = dirname(__FILE__) . "/lang/mail." . $lang . ".php";
require_once($lang_file); require_once($lang_file);
unset($lang_file); unset($lang_file);
?> ?>

View File

@@ -13,222 +13,237 @@
* 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.
*/ */
// enforce admin via https
if (!isset($_SERVER['HTTPS'])) {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
exit();
}
require_once "../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 "../config.php"; require_once "../config.php";
// enforce admin via https // this values will not be used when using the register operation type
if (!isset($_SERVER['HTTPS'])) { $storeFirstLastName = false;
header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301); if (isset($config["operationMode"]) && $config["operationMode"] === "local") {
exit(); $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");
} }
if (!isset($_POST["username"])) { if (!isset($_POST["username"])) {
throw new Exception("UNKNOWN_USERNAME"); throw new Exception("UNKNOWN_USERNAME");
} }
if (strlen($_POST["username"] > 20 || strlen($_POST["username"]) < 3)) { if (strlen($_POST["username"] > 20 || strlen($_POST["username"]) < 3)) {
throw new Exception("USERNAME_LENGTH_INVALID"); throw new Exception("USERNAME_LENGTH_INVALID");
} }
if (ctype_alnum($_POST['username']) != true) { if (ctype_alnum($_POST['username']) != true) {
throw new Exception("USERNAME_NOT_ALNUM"); throw new Exception("USERNAME_NOT_ALNUM");
} }
if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"] && if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"] &&
$_POST["password"] != $_POST["password_confirm"]) { $_POST["password"] != $_POST["password_confirm"]) {
throw new Exception("PASSWORD_NOT_MATCH"); throw new Exception("PASSWORD_NOT_MATCH");
} }
if (isset($_POST["note"]) && strlen($_POST["note"]) > 50) { if (isset($_POST["note"]) && strlen($_POST["note"]) > 50) {
throw new Exception("NOTE_LENGTH_EXEEDED"); throw new Exception("NOTE_LENGTH_EXEEDED");
} }
if (!isset($_POST["email"]) || !filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) { if (!isset($_POST["email"]) || !filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) {
throw new Exception("EMAIL_INVALID_FORMAT"); throw new Exception("EMAIL_INVALID_FORMAT");
} }
if (isset($_POST["first_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["first_name"])) { if ($storeFirstLastName) {
throw new Exception("FIRSTNAME_INVALID_FORMAT"); // 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"])) {
if (isset($_POST["last_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["last_name"])) { throw new Exception("FIRSTNAME_INVALID_FORMAT");
throw new Exception("SIRNAME_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 = "";
}
$first_name = filter_var($_POST["first_name"], FILTER_SANITIZE_STRING); $username = filter_var($_POST["username"], FILTER_SANITIZE_STRING);
$last_name = filter_var($_POST["last_name"], FILTER_SANITIZE_STRING); if ($storePassword && isset($_POST["password"])) {
$username = filter_var($_POST["username"], FILTER_SANITIZE_STRING); $password = filter_var($_POST["password"], FILTER_SANITIZE_STRING);
if (isset($_POST["password"])) { }
$password = filter_var($_POST["password"], FILTER_SANITIZE_STRING); $note = filter_var($_POST["note"], 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("../database.php"); require_once("../database.php");
$res = $mx_db->addRegistration($first_name, $last_name, $username, $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 "../mail_templates.php"; require_once "../mail_templates.php";
$success = send_mail_pending_verification( $success = send_mail_pending_verification(
$config["homeserver"], $config["homeserver"], $storeFirstLastName ? $first_name . " " . $last_name : $username, $email, $verify_url);
$first_name . " " . $last_name,
$email,
$verify_url);
$mx_db->setRegistrationStateVerify( $mx_db->setRegistrationStateVerify(
($success ? RegisterState::PendingEmailVerify : RegisterState::PendingEmailSend), ($success ? RegisterState::PendingEmailVerify : RegisterState::PendingEmailSend), $verify_token);
$verify_token);
print("<title>Erfolgreich</title>"); print("<title>" . $language["SUCCESS"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>Erfolgreich</h1>"); print("<h1>" . $language["SUCCESS"] . "</h1>");
print("<p>Bitte überprüfe deine E-Mails um deine E-Mail-Adresse zu bestätigen.</p>"); print("<p>" . $language["TASK_CHECK_YOUR_EMAIL_VERIFY"] . "</p>");
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</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" . "\">Zur Registrierungsseite</a>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>");
} }
} else { } else {
$_SESSION["token"] = bin2hex(random_bytes(16)); $_SESSION["token"] = bin2hex(random_bytes(16));
?> ?>
<title>Registriere dich für <?php echo $config["homeserver"]; ?></title> <title><?php echo strtr($language["TOPIC_PLEASE_REGISTER"], [ "@homeserver" => $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">Bitte für <?php echo $config["homeserver"]; ?> registrieren<small>2-Schritt-Registrierung</small></h3> <h3 class="panel-title"><?php echo strtr($language["TOPIC_PLEASE_REGISTER"], [ "@homeserver" => $config["homeserver"] ])
</div> . "<small>" . $language["TOPIC_PLEASE_REGISTER_NOTE"] . "</small>"; ?></h3>
<div class="panel-body"> </div>
<form name="regForm" role="form" action="index.php" method="post"> <div class="panel-body">
<div class="row"> <form name="regForm" role="form" action="index.php" method="post">
<div class="col-xs-6 col-sm-6 col-md-6"> <?php if ($storeFirstLastName) { ?>
<div class="form-group"> <div class="row">
<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="Vorname" pattern="[A-Z][a-z]+"> <div class="form-group">
</div> <input type="text" name="first_name" id="first_name" class="form-control input-sm"
</div> placeholder="<?php echo $language["FIRST_NAME"]; ?>" 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 class="col-xs-6 col-sm-6 col-md-6">
placeholder="Nachname" 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="<?php echo $language["LAST_NAME"]; ?>" pattern="[A-Z][a-z]+">
</div> </div>
</div>
<div class="form-group"> </div>
<input type="email" name="email" id="email" class="form-control input-sm" placeholder="E-Mail-Adresse" required>
</div>
<div class="form-group">
<input type="text" name="note" id="note" class="form-control input-sm" placeholder="Notiz zu dir (max. 50 Zeichen)">
</div>
<div class="form-group">
<input type="text" name="username" id="username" class="form-control input-sm"
placeholder="Nutzername (für den Login)" pattern="[a-z1-9]{3,20}" required>
</div>
<?php if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]) { ?>
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group">
<input type="password" name="password" id="password" class="form-control input-sm" placeholder="Passwort" required>
</div>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group">
<input type="password" name="password_confirm" id="password_confirm" class="form-control input-sm" placeholder="Passwort bestätigen" required>
</div>
</div>
</div>
<?php } ?> <?php } ?>
<input type="hidden" name="token" id="token" value="<?php echo $_SESSION["token"]; ?>">
<input type="submit" value="Registrieren" class="btn btn-info btn-block">
</form> <div class="form-group">
<p>Hinweis: <br /> <input type="email" name="email" id="email" class="form-control input-sm" placeholder="<?php echo $language["EMAIL_ADDRESS"]; ?>" required>
<?php echo $config["homeserver"]; ?> ist ein geschlossenes Chat-Netzwerk in dem jeder Nutzer bestätigt werden muss.<br /> </div>
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 /> <div class="form-group">
Liebe Grüße vom Team von <?php echo $config["homeserver"]; ?> <input type="text" name="note" id="note" class="form-control input-sm" placeholder="<?php echo $language["PLACEHOLDER_NOTE_ABOUT_YOURSELF"]; ?>">
</p> </div>
</div>
</div> <div class="form-group">
</div> <input type="text" name="username" id="username" class="form-control input-sm"
</div> placeholder="<?php echo $language["USERNAME"]; ?>" pattern="[a-z1-9]{3,20}" required>
</div> </div>
<script type="text/javascript"> <?php if ($storePassword) { ?>
var first_name = document.getElementById("first_name"); <div class="row">
first_name.oninvalid = function(event) { <div class="col-xs-6 col-sm-6 col-md-6">
event.target.setCustomValidity("Vorname muss das Format <Großbuchstabe><Kleinbuchstaben> haben"); <div class="form-group">
} <input type="password" name="password" id="password" class="form-control input-sm" placeholder="<?php echo $language["PASSWORD"]; ?>" required>
first_name.onkeyup = function(event) { </div>
event.target.setCustomValidity(""); </div>
} <div class="col-xs-6 col-sm-6 col-md-6">
var last_name = document.getElementById("last_name"); <div class="form-group">
last_name.oninvalid = function(event) { <input type="password" name="password_confirm" id="password_confirm" class="form-control input-sm" placeholder="<?php echo $language["PASSWORD_CONFIRM"]; ?>" required>
event.target.setCustomValidity("Nachname muss das Format <Großbuchstabe><Kleinbuchstaben> haben"); </div>
} </div>
last_name.onkeyup = function(event) { </div>
event.target.setCustomValidity(""); <?php } ?>
} <input type="hidden" name="token" id="token" value="<?php echo $_SESSION["token"]; ?>">
var user_name = document.getElementById("username"); <input type="submit" value="<?php echo $language["REGISTER"]; ?>" class="btn btn-info btn-block">
user_name.oninvalid = function(event) {
event.target.setCustomValidity("Nutzername darf zwischen 3 und 20 kleine Buchstaben und Zahlen enthalten"); </form>
} <?php if (isset($language["NOTE_FOR_REGISTRATION"])) {
user_name.onkeyup = function (event) { echo "<p>" . $language["NOTE"] . ": <br />";
event.target.setCustomValidity(""); echo strtr($language["NOTE_FOR_REGISTRATION"], [ "@homeserver" => $config["homeserver"] ]);
} echo "</p>";
<?php if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]) { ?> } ?>
var password = document.getElementById("password") </div>
, confirm_password = document.getElementById("password_confirm"); </div>
function validatePassword(){ </div>
if(password.value != confirm_password.value) { </div>
confirm_password.setCustomValidity("Passwörter stimmen nicht überein"); </div>
} else { <script type="text/javascript">
confirm_password.setCustomValidity(''); var user_name = document.getElementById("username");
} user_name.oninvalid = function (event) {
} event.target.setCustomValidity("<?php echo $language["USERNAME_LENGTH_INVALID"]; ?>");
password.onchange = validatePassword; }
confirm_password.onkeyup = validatePassword; user_name.onkeyup = function (event) {
<?php } ?> event.target.setCustomValidity("");
</script> }
<?php } ?> <?php if ($storeFirstLastName) { ?>
</body> var first_name = document.getElementById("first_name");
</html> 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 } ?>
</script>
<?php } ?>
</body></html>

View File

@@ -15,79 +15,85 @@
*/ */
require_once "../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 "../config.php"; require_once "../config.php";
require_once "../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("../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"];
$note = $user["note"]; $username = $user["username"];
$email = $user["email"]; $note = $user["note"];
$admin_token = $user["admin_token"]; $email = $user["email"];
$admin_token = $user["admin_token"];
require_once("../MatrixConnection.php"); require_once("../MatrixConnection.php");
$adminUrl = $config["webroot"] . "/verify_admin.php?t=" . $admin_token; $adminUrl = $config["webroot"] . "/verify_admin.php?t=" . $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($first_name . ' ' . $last_name . "möchte sich registrieren und hat folgende Notiz hinterlassen:\r\n" $mxMsg->set_body(strtr($language["MSG_USER_WANTS_REGISTER"], [
. $note . "\r\n" "@name" => (strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username),
. "Zum Bearbeiten hier klicken:\r\n" . $adminUrl); "@note" => $note,
$mxMsg->set_formatted_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:<br />" "@adminUrl" => $adminUrl
. $note . "<br />" ]));
. "Zum Bearbeiten <a href=\"". $adminUrl . "\">hier</a> klicken"); if (isset($language["MSG_USER_WANTS_REGISTER_FORMATTED"])) {
$mxMsg->set_type("m.text"); $mxMsg->set_formatted_body(strtr($language["MSG_USER_WANTS_REGISTER_FORMATTED"], [
$response = $mxConn->send($config["register_room"], $mxMsg); "@name" => (strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username),
"@note" => $note,
"@adminUrl" => $adminUrl
]));
}
$mxMsg->set_type("m.text");
$response = $mxConn->send($config["register_room"], $mxMsg);
if ($response) { if ($response) {
$message = $language["SEND_MATRIX_FAIL"]; $message = $language["SEND_MATRIX_FAIL"];
} }
$mx_db->setRegistrationStateVerify( $mx_db->setRegistrationStateVerify(
($response ? RegisterState::PendingAdminVerify : RegisterState::PendingAdminSend), ($response ? RegisterState::PendingAdminVerify : RegisterState::PendingAdminSend), $token);
$token);
send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email); send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email);
print("<title>" . $language["VERIFICATION_SUCEEDED"] . "</title>"); print("<title>" . $language["VERIFICATION_SUCEEDED"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["VERIFICATION_SUCEEDED"] . "</h1>"); print("<h1>" . $language["VERIFICATION_SUCEEDED"] . "</h1>");
print("<p>" . $language["VERIFICATION_SUCCESS_BODY"] . "</p>"); print("<p>" . $language["VERIFICATION_SUCCESS_BODY"] . "</p>");
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>"); 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" . "\">Zur Registrierungsseite</a>"); print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>");
} }
?> ?>
</body> </body>
</html> </html>

View File

@@ -15,170 +15,195 @@
*/ */
require_once "../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 "../config.php"; require_once "../config.php";
require_once "../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("../database.php"); require_once("../database.php");
$action = NULL; $action = NULL;
if (isset($_GET["allow"])) { if (isset($_GET["allow"])) {
$action = RegisterState::RegistrationAccepted; $action = RegisterState::RegistrationAccepted;
} }
$decline_reason = NULL; $decline_reason = NULL;
if (isset($_GET["deny"])) { if (isset($_GET["deny"])) {
$action = RegisterState::RegistrationDeclined; $action = RegisterState::RegistrationDeclined;
if (isset($_GET["reason"])) { if (isset($_GET["reason"])) {
$decline_reason = filter_var($_GET["reason"], FILTER_SANITIZE_STRING); $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"];
$note = $user["note"]; $note = $user["note"];
$email = $user["email"]; $email = $user["email"];
if ($action == RegisterState::RegistrationAccepted) { if ($action == RegisterState::RegistrationAccepted) {
$mx_db->setRegistrationStateAdmin(RegisterState::PendingRegistration, $token); $mx_db->setRegistrationStateAdmin(RegisterState::PendingRegistration, $token);
// register user // register user
require_once("../MatrixConnection.php"); require_once("../MatrixConnection.php");
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); $mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]);
// generate a password with 8 characters $password = NULL;
$password = $mx_db->addUser($first_name, $last_name, $username, $email); switch ($config["operationMode"]) {
if ($password != NULL) { case "synapse":
// send registration_success // register with registration_shared_secret
$res = send_mail_registration_success($config["homeserver"], $first_name . " " . $last_name, $email, $username, $password, $config["howToURL"]); // generate a password with 10 characters
if ($res) { $password = bin2hex(openssl_random_pseudo_bytes(5));
$mx_db->setRegistrationStateAdmin(RegisterState::AllDone, $token); $res = $mxConn->register($username, $password, $config["registration_shared_secret"]);
} else { if (!$res) {
$mx_db->setRegistrationStateAdmin(RegisterState::PendingSendRegistrationMail, $token); // something went wrong while registering
} $password = NULL;
} else { }
send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email); break;
$mxMsg = new MatrixMessage(); case "local":
$mxMsg->set_type("m.text"); // register by adding a user to the local database
$mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . "."); $password = $mx_db->addUser($first_name, $last_name, $username, $email);
$mxConn->send($config["register_room"], $mxMsg); break;
throw new Exception("REGISTRATION_FAILED"); default:
} throw new Exception("Unknown operationMode");
}
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(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("REGISTRATION_FAILED");
}
print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>"); print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>"); print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>");
print("<p>" . $language["ADMIN_REGISTER_ACCEPTED_BODY"] . "</p>"); print("<p>" . $language["ADMIN_REGISTER_ACCEPTED_BODY"] . "</p>");
} elseif ($action == RegisterState::RegistrationDeclined) { } elseif ($action == RegisterState::RegistrationDeclined) {
$mx_db->setRegistrationStateAdmin(RegisterState::RegistrationDeclined, $token); $mx_db->setRegistrationStateAdmin(RegisterState::RegistrationDeclined, $token);
send_mail_registration_decline($config["homeserver"], $first_name . " " . $last_name, $email, $decline_reason); send_mail_registration_decline(
print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>"); $config["homeserver"], strlen($first_name . $last_name) > 0 ? $first_name . " " . $last_name : $username, $email, $decline_reason
print("</head><body>"); );
print("<h1>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</h1>"); print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
print("<p>" . $language["ADMIN_REGISTER_DECLINED_BODY"] . "</p>"); print("</head><body>");
} else { 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>"); print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</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 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" action="verify_admin.php" method="GET"> <form name="appForm" role="form" action="verify_admin.php" method="GET">
<div class="row"> <?php 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="note" class="form-control input-sm" value="<?php echo $note; ?>" disabled=true> <input type="text" id="username" class="form-control input-sm"
</div> value="<?php echo $username; ?>" disabled=true>
</div>
<input type="hidden" name="t" id="token" value="<?php echo $token; ?>">
<input type="submit" name="allow" value="<?php echo $language["ACCEPT"]; ?>" class="btn btn-info btn-block">
<input type="submit" name="deny" value="<?php echo $language["DECLINE"]; ?>" class="btn btn-info btn-block">
</form>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
<div class="form-group"> <?php
<input type="text" id="username" class="form-control input-sm" } // else - no action provided
value="<?php echo $username; ?>" disabled=true> } catch (Exception $e) {
</div> print("<title>" . $language["REGISTRATION_FAILED"] . "</title>");
<input type="hidden" name="t" id="token" value="<?php echo $token; ?>"> print("</head><body>");
<input type="submit" name="allow" value="Bestätigen" class="btn btn-info btn-block"> print("<h1>" . $language["REGISTRATION_FAILED"] . "</h1>");
<input type="submit" name="deny" value="Ablehnen" class="btn btn-info btn-block"> if (isset($language[$e->getMessage()])) {
print("<p>" . $language[$e->getMessage()] . "</p>");
</form> } else {
</div> print("<p>" . $e->getMessage() . "</p>");
</div> }
</div> print("<a href=\"" . $config["webroot"] . "/index.php" . "\">" . $language["JUMP_TO_HOMEPAGE"] . "</a>");
</div> }
</div> ?>
<script type="text/javascript"> < /body>
</html>
<?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" . "\">Zur Registrierungsseite</a>");
}
?>
</body>
</html>