22 Commits

Author SHA1 Message Date
9fe28604c2 abort when e-mail got verified already; remove duplicate / in path 2018-03-02 15:48:11 +01:00
45a4a38935 fix 'Translation not found' 2018-03-02 15:31:52 +01:00
f595c445f2 changed wording for mail_templates to allow unset values 2018-02-28 23:37:02 +01:00
9b1a9f9a79 fix sending error message to room; add \n for cron-output 2018-02-28 23:20:58 +01:00
b736721a1c fix: const RegistrationAccepted is equal to another internal number 2018-02-28 23:08:05 +01:00
b2842308b3 Merge branch 'first_implementation' of gitea.krombel.de:krombel/matrix-register-bot into first_implementation 2018-02-28 20:00:29 +01:00
b68f6afa97 fix cron.php 2018-02-28 20:00:17 +01:00
40b6970c1c remove abort(); change lang-def de => de-de; cleanup 2018-02-27 10:31:51 +01:00
83cf11149b fix for cron.php 2018-02-23 19:25:30 +01:00
4e33985cfc further implement cron.php; autoformat
- set Register_Accept to 6 internally as it reflects the same state as PendingSendRequest
- cleanups
2018-02-23 19:22:14 +01:00
ff9969b04e restore reference to exec_curl_request 2018-02-23 18:32:41 +01:00
076138a0a4 move exec_curl_request from functions to MatrixConnection 2018-02-23 18:28:29 +01:00
a51f44c01b add mail_templates and prepare cron.php 2018-02-23 17:50:02 +01:00
e38d201ec1 only allow actions (admin) when in right state; prepare decline reason
- fixes on path's and varnames
2018-02-23 17:43:08 +01:00
e88eb13d91 implement hasUser(localpart), RegisterState add verify{_admin}.php
- fixes
2018-02-23 15:28:50 +01:00
8fff520b28 first try for a database for pending registrations 2018-02-20 20:37:15 +01:00
c62bd21646 add MatrixConnection->register(username,passwort,registration_secret); 2018-02-20 20:10:44 +01:00
b8f8fc1f69 fix compilation errors; add public folder 2018-02-11 21:31:01 +01:00
bd06342ccf add saving registrations to sqlite 2018-02-11 20:22:40 +01:00
f306dda4f9 do not request password on register request
the aim is that the initial password is
generated and send on register approval
2018-02-11 19:48:42 +01:00
b56798dc35 move language to lang-directory 2018-02-11 19:47:35 +01:00
c1f5f4d451 first WIP implementation 2018-02-10 18:01:42 +01:00
16 changed files with 217 additions and 926 deletions

1
.gitignore vendored
View File

@@ -1,2 +1 @@
config.php config.php
db_file.sqlite

View File

@@ -1,18 +1,4 @@
<?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.
*/
class MatrixConnection class MatrixConnection
{ {
private $hs; private $hs;
@@ -32,7 +18,6 @@ class MatrixConnection
$send_message = NULL; $send_message = NULL;
if (!$message) { if (!$message) {
error_log("no message to send"); error_log("no message to send");
return false;
} elseif(is_array($message)) { } elseif(is_array($message)) {
$send_message = $message; $send_message = $message;
} elseif ($message instanceof MatrixMessage) { } elseif ($message instanceof MatrixMessage) {
@@ -142,7 +127,9 @@ class MatrixMessage
private $message; private $message;
function __construct() { function __construct() {
$this->message = ["msgtype" => "m.notice"]; $this->message = array(
"msgtype" => "m.notice",
);
} }
function set_type($msgtype) { function set_type($msgtype) {

View File

@@ -4,27 +4,6 @@ This bot provides a two-step-registration for matrix.
This is done in several steps: This is done in several steps:
- potential new user registers on a bot-provided side - potential new user registers on a bot-provided side
- bot sends a message to predefined room with a registration notification. - bot sends a message to prefined room with a registration notification.
- users in that room now can approve or decline the registration. - users in that room now can approve or decline the registration.
- When approved - The bot then uses the registration token to register the user or just drops the registration request.
- the bot creates credentials
- sends them to the user
- stores them encrypted in own database
- provides that credentials to [matrix-synapse-rest-auth](https://github.com/kamax-io/matrix-synapse-rest-auth#integrate) which has to be configured to query login.php
2nd step: Implement the other apis to integrade [mxisd](https://github.com/kamax-io/mxisd/blob/master/docs/backends/rest.md)
## How to install
- 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.
The folder `internal` contains files that can be accessed by mxisd or matrix-synapse-rest-auth
- To integrate with matrix-synapse-rest-auth:
- `/_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:
| Key | file which handles that | Description |
|--------------------------------|-------------------------------|------------------------------------------------------|
| rest.endpoints.auth | internal/login.php | Validate credentials and get user profile |
| 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.bulk | internal/identity_bulk.php | Endpoint to query a list of 3PID |

View File

@@ -1,26 +1,9 @@
<?php <?php
$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", $register_room = '$registerRoomID:example.com';
$registration_shared_secret = "To be used for actually register the user";
// Which e-mail-adresse shall the bot use to send e-mails? $webroot="https://myregisterdomain.net/";
"register_email" => 'register_bot@example.com', $howToURL = "https://my-url-for-storing-howTos.net";
// Where should the bot post registration requests to?
"register_room" => '$registerRoomID:example.com',
// Where is the public part of the bot located? make sure you have a / at the end
"webroot" => "https://myregisterdomain.net/",
// 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",
// When you want to collect the password on registration set this to true
"getPasswordOnRegistration" => false,
// to define where the data should be stored:
"databaseURI" => "sqlite:" . dirname(__FILE__) . "/db_file.sqlite",
// credentials for sqlite not used
"databaseUser" => "dbUser123",
"databasePass" => "secretPassword",
]
?> ?>

View File

@@ -1,18 +1,4 @@
<?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.
*/
require_once("config.php"); require_once("config.php");
require_once("mail_templates.php"); require_once("mail_templates.php");
require_once("database.php"); require_once("database.php");
@@ -24,7 +10,7 @@ $sql = "SELECT id, first_name, last_name, username, email, state, note, verify_t
. " 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 ($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"];
@@ -34,37 +20,39 @@ foreach ($mx_db->query($sql) as $row) {
try { try {
switch ($state) { switch ($state) {
case RegisterState::PendingEmailSend: case RegisterState::PendingEmailSend:
$verify_url = $config["webroot"] . "/verify.php?t=" . $row["verify_token"]; $verify_url = $webroot . "/verify.php?t=" . $row["verify_token"];
$success = send_mail_pending_verification( $success = send_mail_pending_verification(
$config["homeserver"], $homeserver,
$row["first_name"] . " " . $row["last_name"], $row["first_name"] . " " . $row["last_name"],
$row["email"], $row["email"],
$verify_url); $row["verify_url"]);
if ($success) { if ($success) {
$mx_db->setRegistrationStateById(RegisterState::PendingEmailVerify, $row["id"]); $db->exec("UPDATE registrations SET state = " . RegisterState::PendingEmailVerify
. " WHERE id = " . $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 = $webroot . "/verify_admin.php?t=" . $row["admin_token"];
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); $mxConn = new MatrixConnection($homeserver, $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($register_room, $mxMsg);
if ($response) { if ($response) {
$mx_db->setRegistrationStateById(RegisterState::PendingAdminVerify, $row["id"]); $db->exec("UPDATE registrations SET state = " . RegisterState::PendingAdminVerify
. " WHERE id = " . $row["id"] . ";");
send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email); send_mail_pending_approval($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.");
} }
@@ -72,21 +60,23 @@ foreach ($mx_db->query($sql) as $row) {
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"]); // register user
if ($password != NULL) { require_once("MatrixConnection.php");
$mxConn = new MatrixConnection($homeserver, $access_token);
// generate a password with 8 characters
$password = bin2hex(openssl_random_pseudo_bytes(4));
$res = $mxConn->register($username, $password, $shared_secret);
if ($res) {
// send registration_success // send registration_success
$res = send_mail_registration_success($config["homeserver"], $first_name . " " . $last_name, $email, $username, $password, $config["howToURL"]); send_mail_registration_success($homeserver, $first_name . " " . $last_name, $email, $username, $password, $howToURL);
if ($res) {
$mx_db->setRegistrationStateById(RegisterState::AllDone, $row["id"]);
} else {
$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($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($register_room, $mxMsg);
throw new Exception($language["REGISTRATION_FAILED"]); throw new Exception($language["REGISTRATION_FAILED"]);
} }
break; break;

View File

@@ -1,22 +1,5 @@
<?php <?php
/** $db_file = dirname(__DIR__)."/db_file.sqlite";
* 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.
*/
require_once("config.php");
if (!isset($config["databaseURI"])) {
throw new Exception ("malformed configuration: databaseURI not defined");
}
abstract class RegisterState abstract class RegisterState
{ {
@@ -43,309 +26,30 @@ abstract class RegisterState
const AllDone = 100; const AllDone = 100;
} }
class mxDatabase // create database file when not existent yet
{ if (!file_exists($db_file)) {
private $db = NULL; $db = new PDO('sqlite:' . $db_file);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/** $db->exec("CREATE TABLE registrations(
* Creates mxDatabase object id INTEGER PRIMARY KEY AUTOINCREMENT,
* @param config object which has following members: state INT DEFAULT 0,
* databaseURI: path to the sqlite file where the credentials should be stored first_name TEXT,
* or a param which can be used to connect to a database with PDO last_name TEXT,
* databaseUser and databasePass when authentication is required username TEXT,
* register_email which email does the register bot have (here used for providing lookup) note TEXT,
*/ email TEXT,
function __construct($config) { verify_token TEXT,
if (empty($config)) { admin_token TEXT,
throw new Exception("config is empty"); request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
} }
if (!isset($config["databaseURI"])) { else {
throw new Exception("'databaseURI' not defined"); // establish connection
} $db = new PDO('sqlite:' . $db_file);
$db_input = $config["databaseURI"]; $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = '';
$password = '';
if (isset($config["databaseUser"]) && isset($config["databasePass"])) {
// only use it when both are defined
$user = $config["databaseUser"];
$password = $config["databasePass"];
}
// create database file when not existent yet
$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,
state INT DEFAULT 0,
first_name TEXT,
last_name TEXT,
username TEXT,
password_hash TEXT DEFAULT '',
note TEXT,
email TEXT,
verify_token TEXT,
admin_token TEXT,
request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$this->db->exec("CREATE TABLE IF NOT EXISTS logins (
id SERIAL PRIMARY KEY,
active INT DEFAULT 1,
first_name TEXT,
last_name TEXT,
localpart TEXT,
password_hash TEXT,
email TEXT,
create_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
// make sure the bot is allowed to login
if (!$this->userRegistered("register_bot")) {
$password = $this->addUser("Register", "Bot", "register_bot", $config["register_email"]);
$config["register_password"] = $password;
$myfile = fopen(dirname(__FILE__) . "/config.json", "w");
fwrite($myfile, json_encode($config, JSON_PRETTY_PRINT));
fclose($myfile);
}
// set writeable when not set already
if (strpos($db_input, "sqlite") === 0) {
$sqlite_file = substr($db_input, strlen("sqlite:"));
if (!is_writable($sqlite_file)) {
chmod($sqlite_file, 0660);
}
unset($sqlite_file);
}
}
/**
* WARNING: This allows accessing the database directly.
* 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
* @return Response of PDO::query()
*/
function query($sql) {
return $this->db->query($sql);
}
function setRegistrationStateVerify($state, $token) {
$sql = "UPDATE registrations SET state = " . $state
. " WHERE verify_token = '" . $token . "';";
return $this->db->exec($sql);
}
function setRegistrationStateById($state, $id) {
$sql = "UPDATE registrations SET state = " . $state
. " WHERE id = '" . $id . "';";
return $this->db->exec($sql);
}
function setRegistrationStateAdmin($state, $token) {
$sql = "UPDATE registrations SET state = " . $state
. " WHERE admin_token = '" . $token . "';";
return $this->db->exec($sql);
}
function setRegistrationState($state, $token) {
$sql = "UPDATE registrations SET state = " . $state
. " WHERE verify_token = '" . $token . "' OR admin_token = '" . $token . "';";
return $this->db->exec($sql);
}
function userPendingRegistrations($username) {
$sql = "SELECT COUNT(*) FROM registrations WHERE username = '" . $username . "' AND NOT state = "
. RegisterState::RegistrationDeclined . " LIMIT 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
return true;
}
return false;
}
function userRegistered($username) {
$sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $username . "' LIMIT 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
return true;
}
return false;
}
/**
* 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");
}
$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)
VALUES ('" . $first_name."','" . $last_name . "','" . $username . "','" . $note . "','"
. $email."','" .$verify_token."','" .$admin_token."')");
return [
"verify_token"=> $verify_token,
];
}
/**
* Gets the user for the verify_admin page.
*
* @return ArrayOfUser|NULL Array with "first_name, last_name, username, note and email"
* as members
*/
function getUserForApproval($admin_token) {
$sql = "SELECT COUNT(*) FROM registrations WHERE admin_token = '" . $admin_token . "'"
. " AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;";
$res = $this->db->query($sql);
$first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, username, note, email FROM registrations"
. " WHERE admin_token = '" . $admin_token . "'"
. " AND state = " . RegisterState::PendingAdminVerify
. " LIMIT 1;";
foreach ($this->db->query($sql) as $row) {
// will only be executed once
return $row;
}
}
return NULL;
}
/**
* 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"
* as members
*/
function getUserForVerify($verify_token) {
$sql = "SELECT COUNT(*) FROM registrations WHERE verify_token = '" . $verify_token . "'"
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
$res = $this->db->query($sql);
$first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, note, email, admin_token FROM registrations "
. " WHERE verify_token = '" . $verify_token . "'"
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
foreach ($this->db->query($sql) as $row) {
// will only be executed once
return $row;
}
}
return NULL;
}
function getUserForLogin($localpart, $password) {
$sql = "SELECT COUNT(*) FROM logins WHERE localpart = '" . $localpart
. "' AND active = 1 LIMIT 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, email, password_hash FROM logins "
. " WHERE localpart = '" . $localpart . "' AND active = 1 LIMIT 1;";
foreach ($this->db->query($sql) as $row) {
if (password_verify($password, $row["password_hash"])) {
return $row;
}
}
}
return NULL;
}
/**
* adds User to be able to login afterwards.
* @param first_name First name of the user
* @param last_name Sirname of the user
* @param username the future localpart of that user
* @param email E-Mail-Adress which will be stored into the database.
* This will be send to the server on first login
*
* @return password|NULL with member password as this method generates a
* password and saves that into the database
* NULL when failed
*
*/
function addUser($first_name, $last_name, $username, $email) {
// check if user already exists and abort in that case
if ($this->userRegistered($username)) {
return NULL;
}
// generate a password with 10 characters
$password = bin2hex(openssl_random_pseudo_bytes(5));
$password_hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>12]);
$sql = "INSERT INTO logins (first_name, last_name, localpart, password_hash, email) VALUES "
. "('" . $first_name."','" . $last_name . "','" . $username . "','"
. $password_hash . "','" . $email . "');";
if ($this->db->exec($sql)) {
return $password;
}
return NULL;
}
function searchUserByName($search_term) {
$term = filter_var($search_term, FILTER_SANITIZE_STRING);
$result = array();
$sql = "SELECT COUNT(*) FROM logins WHERE"
. " localpart LIKE '" . $term . "%' AND active = 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, localpart FROM logins WHERE"
. " localpart LIKE '" . $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;
}
function searchUserByEmail($search_term) {
$term = filter_var($search_term, FILTER_SANITIZE_STRING);
$result = array();
$sql = "SELECT COUNT(*) FROM logins WHERE"
. " email = '" . $term . "' AND active = 1;";
$res = $this->db->query($sql);
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, localpart FROM logins WHERE"
. " email = '" . $term . "' AND active = 1;";
foreach ($this->db->query($sql) as $row) {
array_push($result, [
"display_name" => $row["first_name"] . " " . $row["last_name"],
"user_id" => $row["localpart"],
]);
}
}
return $result;
}
} }
if (!isset($mx_db)) { // set writeable when not set already
$mx_db = new mxDatabase($config); if (!is_writable($db_file)) {
chmod($db_file, 0777);
} }
?> ?>

View File

@@ -1,50 +0,0 @@
<?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.
*/
require_once("../database.php");
$response=[
"limited" => false,
"result" => [],
];
try {
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE);
if (empty($input)) {
throw new Exception('no valid json as input present');
}
if (!isset($input["by"])) {
throw new Exception('"by" is not defined');
}
if (!isset($input["search_term"])) {
throw new Exception('"search_term" is not defined');
}
switch ($input["by"]) {
case "name":
$response["result"] = $mx_db->searchUserByName($input["search_term"]);
break;
case "threepid":
$response["result"] = $mx_db->searchUserByEmail($input["search_term"]);
break;
default:
throw new Exception("unknown type for \"by\" param");
}
} catch (Exception $e) {
error_log("failed with error: " . $e->getMessage());
$response["error"] = $e->getMessage();
}
print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?>

View File

@@ -1,67 +0,0 @@
<?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.
*/
require_once("../database.php");
$response = [
"lookup" => []
];
try {
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE);
if (!isset($input)) {
throw new Exception('request body is no valid json');
}
if (!isset($input["lookup"])) {
throw new Exception('"lookup" is not defined');
}
if (!is_array($input["lookup"])) {
throw new Exception('"lookup" is not an array');
}
foreach ($input["lookup"] as $lookup) {
if (!isset($lookup["medium"])) {
throw new Exception('"lookup.medium" is not defined');
}
if (!isset($lookup["address"])) {
throw new Exception('"lookup.address" is not defined');
}
$res2 = array();
switch ($lookup["medium"]) {
case "email":
$res2 = $mx_db->searchUserByEmail($lookup["address"]);
if (!empty($res2)) {
array_push($response["lookup"], [
"medium" => $lookup["medium"],
"address" => $lookup["address"],
"id" => [
"type" => "localpart",
"value" => $res2[0]["user_id"],
]
]
);
}
break;
case "msisdn":
break;
default:
throw new Exception("unknown type for \"by\" param");
}
}
} catch (Exception $e) {
error_log("ídentity_bulk failed with error: " . $e->getMessage());
$response["error"] = $e->getMessage();
}
print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?>

View File

@@ -1,60 +0,0 @@
<?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.
*/
require_once("../database.php");
$response = new stdClass;
try {
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE);
if (empty($input)) {
throw new Exception('no valid json as input present');
}
if (!isset($input["lookup"])) {
throw new Exception('"lookup" is not defined');
}
if (!isset($input["lookup"]["medium"])) {
throw new Exception('"lookup.medium" is not defined');
}
if (!isset($input["lookup"]["address"])) {
throw new Exception('"lookup.address" is not defined');
}
$res2 = array();
switch ($input["lookup"]["medium"]) {
case "email":
$res2 = $mx_db->searchUserByEmail($input["lookup"]["address"]);
if (!empty($res2)) {
$response = [
"lookup" => [
"medium" => $input["lookup"]["medium"],
"address" => $input["lookup"]["address"],
"id" => [
"type" => "localpart",
"value" => $res2[0]["user_id"],
]
]
];
}
break;
default:
throw new Exception("unknown type for \"by\" param");
}
} catch (Exception $e) {
error_log("ídentity_bulk failed with error: " . $e->getMessage());
$response["error"] = $e->getMessage();
}
print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?>

View File

@@ -1,112 +0,0 @@
<?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.
*/
$response = [
"auth" => [
"success" => false,
]
];
require_once("../database.php");
abstract class LoginRequester {
const UNDEFINED = 0;
const MXISD = 1;
const RestAuth = 2;
}
$loginRequester = LoginRequester::UNDEFINED;
try {
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE);
$mxid = NULL;
$localpart = NULL;
if (isset($input["user"])) {
if (isset($input["user"]["localpart"])) {
$localpart = $input["user"]["localpart"];
$loginRequester = LoginRequester::MXISD;
} elseif (isset($input["user"]["id"])) {
// compatibility for matrix-synapse-rest-auth
$mxid = $input["user"]["id"];
$loginRequester = LoginRequester::RestAuth;
} elseif (isset($input["user"]["mxid"])) {
// compatibility for mxisd
$mxid = $input["user"]["mxid"];
$loginRequester = LoginRequester::MXISD;
}
}
// prefer the localpart attribute of mxisd. But in case of matrix-synapse-rest-auth
// we have to parse it on our own
if (empty($localpart) && !empty($mxid)) {
// A mxid would start with an @ so we start at the 2. position
$sepPos = strpos($mxid,':', 1);
if ($sepPos === false) {
// : not found. Assume mxid is localpart
// TODO: further checks
$localpart = $mxid;
} else {
$localpart = substr($mxid, 1, strpos($mxid,':') - 1 );
}
}
if (empty($localpart)) {
throw new Exception ("localpart cannot be identified");
}
$password = NULL;
if (isset($input["user"]) && isset($input["user"]["password"])) {
$password = $input["user"]["password"];
}
if (empty($password)) {
throw new Exception ("password is not present");
}
$user = $mx_db->getUserForLogin($localpart, $password);
if (!$user) {
throw new Exception("user not found or password did not match");
}
$response["auth"]["success"] = true;
$response["auth"]["profile"] = [
"display_name" => $user["first_name"] . " " . $user["last_name"],
"three_pids" => [
[
"medium" => "email",
"address" => $user["email"],
],
],
];
switch ($loginRequester) {
case LoginRequester::RestAuth:
$response["auth"]["mxid"] = $mxid;
break;
case LoginRequester::MXISD;
$response["auth"]["id"] = [
"type" => "localpart",
"value" => $localpart,
];
break;
default:
// only return that it was successful.
// we do not know how the data shall be transmitted so we do nothing with it
$response["auth"]["success"] = false;
break;
}
} catch (Exception $e) {
error_log("Auth failed with error: " . $e->getMessage());
$response["auth"]["error"] = $e->getMessage();
}
print (json_encode($response, JSON_PRETTY_PRINT) . "\n");
?>

View File

@@ -1,18 +1,4 @@
<?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.
*/
$language = array( $language = array(
"NO_CONFIGURATION" => "Es konnte keine Konfiguration gefunden werden.", "NO_CONFIGURATION" => "Es konnte keine Konfiguration gefunden werden.",
"UNKNOWN_SESSION" => "Sitzungstoken nicht vorhanden oder ungültig.", "UNKNOWN_SESSION" => "Sitzungstoken nicht vorhanden oder ungültig.",

View File

@@ -1,26 +1,11 @@
<?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.
*/
$lang = "de-de"; $lang = "de-de";
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'"); throw new Exception("Translation for " . $lang . " not found");
$lang = "de-de";
} }
require_once($lang_file); require_once($lang_file);
unset($lang_file); unset($lang_file);

View File

@@ -1,21 +1,7 @@
<?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 send_mail($receiver, $subject, $body) { function send_mail($receiver, $subject, $body) {
include("config.php"); $headers = "From: registration@cg-s.tk\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);
} }
@@ -81,14 +67,10 @@ Zum Anmelden kannst du folgende Zugangsdaten verwenden:
Nutzername: $username Nutzername: $username
Passwort: $password Passwort: $password
Hinweis: Aktuell ist es nicht möglich, das Passwort selbst zu ändern. Sobald die Funktionalität zur
Verfügung steht, gibt es aber einen Hinweis.
";
/*
Wichtig: Bitte ändere das Passwort direkt nach der Anmeldung. Wichtig: Bitte ändere das Passwort direkt nach der Anmeldung.
Es wird zwar von unserer Seite nicht gespeichert, doch fremde könnten Zugriff auf diese E-Mail Es wird zwar von unserer Seite nicht gespeichert, doch fremde könnten Zugriff auf diese E-Mail
erhalten und so deinen Account kompromittieren. erhalten und so deinen Account kompromittieren.
*/ ";
if (!empty($howToURL)) { if (!empty($howToURL)) {
$body .= " $body .= "
Zu weiteren Hilfestellungen findest du hier eine Auflistung von verschiedenen Zu weiteren Hilfestellungen findest du hier eine Auflistung von verschiedenen

View File

@@ -1,24 +1,13 @@
<html><head><?php <html>
/** <head>
* Copyright 2018 Matthias Kesler <?php
* 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.
*/
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";
// enforce admin via https // enforce admin via https
if (!isset($_SERVER['HTTPS'])) { if (!isset($_SERVER['HTTPS'])) {
@@ -28,88 +17,101 @@ if (!isset($_SERVER['HTTPS'])) {
session_start(); session_start();
require_once("../database.php");
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($language["UNKNOWN_SESSION"]);
} }
if (!isset($_POST["username"])) { if (!isset($_POST["username"])) {
throw new Exception("UNKNOWN_USERNAME"); throw new Exception($language["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($language["USERNAME_LENGTH_INVALID"]);
} }
if (ctype_alnum($_POST['username']) != true) { if (ctype_alnum($_POST['username']) != true) {
throw new Exception("USERNAME_NOT_ALNUM"); throw new Exception($language["USERNAME_NOT_ALNUM"]);
}
if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"] &&
$_POST["password"] != $_POST["password_confirm"]) {
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($language["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($language["EMAIL_INVALID_FORMAT"]);
} }
if (isset($_POST["first_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["first_name"])) { if (isset($_POST["first_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["first_name"])) {
throw new Exception("FIRSTNAME_INVALID_FORMAT"); throw new Exception($language["FIRSTNAME_INVALID_FORMAT"]);
} }
if (isset($_POST["last_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["last_name"])) { if (isset($_POST["last_name"]) && ! preg_match("/[A-Z][a-z]+/", $_POST["last_name"])) {
throw new Exception("SIRNAME_INVALID_FORMAT"); throw new Exception($language["SIRNAME_INVALID_FORMAT"]);
} }
// check valid password
$first_name = filter_var($_POST["first_name"], FILTER_SANITIZE_STRING); $first_name = filter_var($_POST["first_name"], FILTER_SANITIZE_STRING);
$last_name = filter_var($_POST["last_name"], FILTER_SANITIZE_STRING); $last_name = filter_var($_POST["last_name"], FILTER_SANITIZE_STRING);
$username = filter_var($_POST["username"], FILTER_SANITIZE_STRING); $username = filter_var($_POST["username"], FILTER_SANITIZE_STRING);
if (isset($_POST["password"])) {
$password = filter_var($_POST["password"], FILTER_SANITIZE_STRING);
}
$note = filter_var($_POST["note"], FILTER_SANITIZE_STRING); $note = filter_var($_POST["note"], FILTER_SANITIZE_STRING);
$email = filter_var($_POST["email"], FILTER_VALIDATE_EMAIL); $email = filter_var($_POST["email"], FILTER_VALIDATE_EMAIL);
$verify_token = bin2hex(random_bytes(16));
$admin_token = bin2hex(random_bytes(16));
require_once("../database.php"); # $first="test"; $last="test2"; $user="test3"; $note="empty"; $email="mail+test1@matthias-kesler.de";
$res = $mx_db->addRegistration($first_name, $last_name, $username, $note, $email);
if (!isset($res["verify_token"])) { $sql = "SELECT COUNT(*) FROM registrations WHERE username = '" . $username . "' AND NOT state = "
error_log("sth. went wrong. registration did not throw but admin_token not set"); . RegisterState::RegistrationDeclined . " LIMIT 1;";
throw Exception ("Unknown Error"); $res = $db->query($sql);
if ($res->fetchColumn() > 0) {
throw new Exception($language["USERNAME_PENDING_REGISTRATION"]);
}
require_once("../MatrixConnection.php");
$mxConn = new MatrixConnection($homeserver, $access_token);
if ($mxConn->hasUser($username)) {
throw new Exception($language["USERNAME_REGISTERED"]);
} }
$verify_token = $res["verify_token"];
$verify_url = $config["webroot"] . "/verify.php?t=" . $verify_token; $db->exec('INSERT INTO registrations
require_once "../mail_templates.php"; (first_name, last_name, username, note, email, verify_token, admin_token)
VALUES ("' . $first_name.'","' . $last_name . '","' . $username . '","' . $note . '","'
. $email.'","' .$verify_token.'","' .$admin_token.'")');
# $ins_stmt->bindValue(':first_name', $first);
# $ins_stmt->bindValue(':last_lame', $last);
# $ins_stmt->bindValue(':username', $user);
# $ins_stmt->bindValue(':note', $note);
# $ins_stmt->bindValue(':email', $email);
# $ins_stmt->bindValue(':verify_token', $vToken);
# $ins_stmt->bindValue(':admin_token', $adminToken);
# $ins_stmt->bindValue(':now', date('Y-m-d H:i:s'));
#
# $ins_stmt->execute();
$verify_url = $webroot . "/verify.php?t=" . $verify_token;
$success = send_mail_pending_verification( $success = send_mail_pending_verification(
$config["homeserver"], $homeserver,
$first_name . " " . $last_name, $first_name . " " . $last_name,
$email, $email,
$verify_url); $verify_url);
$mx_db->setRegistrationStateVerify( $db->exec("UPDATE registrations SET state = " .
($success ? RegisterState::PendingEmailVerify : RegisterState::PendingEmailSend), ($success ? RegisterState::PendingEmailVerify : RegisterState::PendingEmailSend)
$verify_token); . " WHERE verify_token = \"" . $verify_token. "\";");
print("<title>Erfolgreich</title>"); print("<title>Erfolgreich</title>");
print("</head><body>"); print("</head><body>");
print("<h1>Erfolgreich</h1>"); print("<h1>Erfolgreich</h1>");
print("<p>Bitte überprüfe deine E-Mails um deine E-Mail-Adresse zu bestätigen.</p>"); print("<p>Bitte überprüfe deine E-Mails um deine E-Mail-Adresse zu bestätigen.</p>");
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>"); print("<a href=\"" . "/register.php" . "\">Zur Registrierungsseite</a>");
} catch (Exception $e) { } catch (Exception $e) {
print("<title>" . $language["REGISTRATION_REQUEST_FAILED"] . "</title>"); print("<title>" . $language["REGISTRATION_REQUEST_FAILED"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["REGISTRATION_REQUEST_FAILED"] . "</h1>"); print("<h1>" . $language["REGISTRATION_REQUEST_FAILED"] . "</h1>");
if (isset($language[$e->getMessage()])) { print("<p>" . $e->getMessage() . "</p>");
print("<p>" . $language[$e->getMessage()] . "</p>"); print("<a href=\"" . $webroot . "/register.php" . "\">Zur Registrierungsseite</a>");
} else {
print("<p>" . $e->getMessage() . "</p>");
}
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
} }
} else { } else {
$_SESSION["token"] = bin2hex(random_bytes(16)); $_SESSION["token"] = bin2hex(random_bytes(16));
?> ?>
<title>Registriere dich für <?php echo $config["homeserver"]; ?></title> <title>Registriere dich für <?php echo $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{
@@ -133,21 +135,21 @@ body{
<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">Bitte für <?php echo $homeserver; ?> registrieren<small>2-Schritt-Registrierung</small></h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form name="regForm" role="form" action="index.php" method="post"> <form name="regForm" role="form" action="register.php" method="post">
<div class="row"> <div class="row">
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="text" name="first_name" id="first_name" class="form-control input-sm" <input type="text" name="first_name" id="first_name" class="form-control input-sm"
placeholder="Vorname" pattern="[A-Z][a-z]+"> placeholder="Vorname" pattern="[A-Z][a-z]+">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="text" name="last_name" id="last_name" class="form-control input-sm" <input type="text" name="last_name" id="last_name" class="form-control input-sm"
placeholder="Nachname" pattern="[A-Z][a-z]+"> placeholder="Nachname" pattern="[A-Z][a-z]+">
</div> </div>
</div> </div>
</div> </div>
@@ -162,31 +164,33 @@ body{
<div class="form-group"> <div class="form-group">
<input type="text" name="username" id="username" class="form-control input-sm" <input type="text" name="username" id="username" class="form-control input-sm"
placeholder="Nutzername (für den Login)" pattern="[a-z1-9]{3,20}" required> placeholder="Nutzername (für den Login)"
pattern="[a-z1-9]{3,20}"
required>
</div> </div>
<?php if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]) { ?> <?php /**
<div class="row"> <div class="row">
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="password" name="password" id="password" class="form-control input-sm" placeholder="Passwort" required> <input type="password" name="password" id="password" class="form-control input-sm" placeholder="Passwort" required>
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6"> <div class="col-xs-6 col-sm-6 col-md-6">
<div class="form-group"> <div class="form-group">
<input type="password" name="password_confirm" id="password_confirm" class="form-control input-sm" placeholder="Passwort bestätigen" required> <input type="password" name="password_confirm" id="password_confirm" class="form-control input-sm" placeholder="Passwort bestätigen" required>
</div> </div>
</div> </div>
</div> </div>
<?php } ?> */ ?>
<input type="hidden" name="token" id="token" value="<?php echo $_SESSION["token"]; ?>"> <input type="hidden" name="token" id="token" value="<?php echo $_SESSION["token"]; ?>">
<input type="submit" value="Registrieren" class="btn btn-info btn-block"> <input type="submit" value="Registrieren" class="btn btn-info btn-block">
</form> </form>
<p>Hinweis: <br /> <p>Hinweis: <br />
<?php echo $config["homeserver"]; ?> ist ein geschlossenes Chat-Netzwerk in dem jeder Nutzer bestätigt werden muss.<br /> cg-s.tk is 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. 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 /> Hinterlasse also bitte einen Hinweis zu dir (der nur den entsprechenden Personen gezeigt wird).<br />
Liebe Grüße vom Team von <?php echo $config["homeserver"]; ?> Liebe Grüße vom Team von cg-s.tk
</p> </p>
</div> </div>
</div> </div>
@@ -215,20 +219,7 @@ body{
user_name.onkeyup = function (event) { user_name.onkeyup = function (event) {
event.target.setCustomValidity(""); event.target.setCustomValidity("");
} }
<?php if (isset($config["getPasswordOnRegistration"]) && $config["getPasswordOnRegistration"]) { ?> </script>
var password = document.getElementById("password")
, confirm_password = document.getElementById("password_confirm");
function validatePassword(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwörter stimmen nicht überein");
} else {
confirm_password.setCustomValidity('');
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
<?php } ?>
</script>
<?php } ?> <?php } ?>
</body> </body>
</html> </html>

View File

@@ -1,18 +1,6 @@
<html><head><?php <html>
/** <head>
* Copyright 2018 Matthias Kesler <?php
* 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.
*/
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"]);
@@ -34,25 +22,36 @@ try {
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($language["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); $sql = "SELECT COUNT(*) FROM registrations WHERE verify_token = '" . $token . "'"
if ($user == NULL) { . " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
throw new Exception("UNKNOWN_TOKEN"); $res = $db->query($sql);
$first_name = NULL; $last_name = NULL; $note = NULL; $email = NULL; $admin_token = NULL;
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, note, email, admin_token FROM registrations WHERE verify_token = '" . $token . "'"
. " AND state = " . RegisterState::PendingEmailVerify . " LIMIT 1;";
foreach ($db->query($sql) as $row) {
// will only be executed once
$first_name = $row["first_name"];
$last_name = $row["last_name"];
$note = $row["note"];
$email = $row["email"];
$admin_token = $row["admin_token"];
}
} else {
throw new Exception($language["UNKNOWN_TOKEN"]);
} }
$first_name = $user["first_name"];
$last_name = $user["last_name"];
$note = $user["note"];
$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 = $webroot . "verify_admin.php?t=" . $admin_token;
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); $mxConn = new MatrixConnection($homeserver, $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"
. $note . "\r\n" . $note . "\r\n"
@@ -61,32 +60,28 @@ try {
. $note . "<br />" . $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($register_room, $mxMsg);
if ($response) { if ($response) {
$message = $language["SEND_MATRIX_FAIL"]; $message = $language["SEND_MATRIX_FAIL"];
} }
$mx_db->setRegistrationStateVerify( $db->exec("UPDATE registrations SET state = " .
($response ? RegisterState::PendingAdminVerify : RegisterState::PendingAdminSend), ($response ? RegisterState::PendingAdminVerify : RegisterState::PendingAdminSend)
$token); . " WHERE verify_token = \"" . $token. "\";");
send_mail_pending_approval($config["homeserver"], $first_name . " " . $last_name, $email); send_mail_pending_approval($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=\"" . $webroot . "register.php" . "\">Zur Registrierungsseite</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()])) { print("<p>" . $e->getMessage() . "</p>");
print("<p>" . $language[$e->getMessage()] . "</p>"); print("<a href=\"" . $webroot . "register.php" . "\">Zur Registrierungsseite</a>");
} else {
print("<p>" . $e->getMessage() . "</p>");
}
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
} }
?> ?>
</body> </body>

View File

@@ -1,18 +1,6 @@
<html><head><?php <html>
/** <head>
* Copyright 2018 Matthias Kesler <?php
* 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.
*/
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"]);
@@ -34,7 +22,7 @@ try {
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($language["UNKNOWN_TOKEN"]);
} }
$token = filter_var($_GET["t"], FILTER_SANITIZE_STRING); $token = filter_var($_GET["t"], FILTER_SANITIZE_STRING);
@@ -44,7 +32,7 @@ try {
if (isset($_GET["allow"])) { if (isset($_GET["allow"])) {
$action = RegisterState::RegistrationAccepted; $action = RegisterState::RegistrationAccepted;
} }
$decline_reason = NULL; $decline_reason = "Noch nicht implementiert";
if (isset($_GET["deny"])) { if (isset($_GET["deny"])) {
$action = RegisterState::RegistrationDeclined; $action = RegisterState::RegistrationDeclined;
if (isset($_GET["reason"])) { if (isset($_GET["reason"])) {
@@ -52,41 +40,55 @@ try {
} }
} }
$user = $mx_db->getUserForApproval($token); $sql = "SELECT COUNT(*) FROM registrations WHERE admin_token = '" . $token
if ($user == NULL) { . "' AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;";
throw new Exception("UNKNOWN_TOKEN"); $res = $db->query($sql);
$first_name = NULL; $last_name = NULL; $username = NULL; $note = NULL; $email = NULL;
if ($res->fetchColumn() > 0) {
$sql = "SELECT first_name, last_name, username, note, email FROM registrations WHERE admin_token = '" . $token
. "' AND state = " . RegisterState::PendingAdminVerify . " LIMIT 1;";
foreach ($db->query($sql) as $row) {
// will only be executed once
$first_name = $row["first_name"];
$last_name = $row["last_name"];
$username = $row["username"];
$note = $row["note"];
$email = $row["email"];
}
} else {
throw new Exception($language["UNKNOWN_TOKEN"]);
} }
$first_name = $user["first_name"];
$last_name = $user["last_name"];
$username = $user["username"];
$note = $user["note"];
$email = $user["email"];
if ($action == RegisterState::RegistrationAccepted) { if ($action == RegisterState::RegistrationAccepted) {
$mx_db->setRegistrationStateAdmin(RegisterState::PendingRegistration, $token); $db->exec("UPDATE registrations SET state = " . RegisterState::PendingRegistration
. " WHERE admin_token = '" . $token. "';");
// register user // register user
require_once("../MatrixConnection.php"); require_once("../MatrixConnection.php");
$mxConn = new MatrixConnection($config["homeserver"], $config["access_token"]); $mxConn = new MatrixConnection($homeserver, $access_token);
// generate a password with 8 characters // generate a password with 8 characters
$password = $mx_db->addUser($first_name, $last_name, $username, $email); $password = bin2hex(openssl_random_pseudo_bytes(4));
if ($password != NULL) {
$res = $mxConn->register($username, $password, $registration_shared_secret);
if ($res) {
// 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($homeserver, $first_name . " " . $last_name, $email, $username, $password, $howToURL);
if ($res) { if ($res) {
$mx_db->setRegistrationStateAdmin(RegisterState::AllDone, $token); $db->exec("UPDATE registrations SET state = " . RegisterState::AllDone
. " WHERE admin_token = '" . $token. "';");
} else { } else {
$mx_db->setRegistrationStateAdmin(RegisterState::PendingSendRegistrationMail, $token); $db->exec("UPDATE registrations SET state = " . RegisterState::PendingSendRegistrationMail
. " WHERE admin_token = '" . $token. "';");
} }
} else { } else {
send_mail_registration_allowed_but_failed($config["homeserver"], $first_name . " " . $last_name, $email); send_mail_registration_allowed_but_failed($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($register_room, $mxMsg);
throw new Exception("REGISTRATION_FAILED"); throw new Exception($language["REGISTRATION_FAILED"]);
} }
print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>"); print("<title>" . $language["ADMIN_VERIFY_SITE_TITLE"] . "</title>");
@@ -94,8 +96,9 @@ try {
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); $db->exec("UPDATE registrations SET state = " . RegisterState::RegistrationDeclined
send_mail_registration_decline($config["homeserver"], $first_name . " " . $last_name, $email, $decline_reason); . " WHERE admin_token = '" . $token. "';");
send_mail_registration_decline($homeserver, $first_name . " " . $last_name, $email, $decline_reason);
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>");
@@ -172,12 +175,8 @@ background: rgba(255, 255, 255, 0.8);
print("<title>" . $language["REGISTRATION_FAILED"] . "</title>"); print("<title>" . $language["REGISTRATION_FAILED"] . "</title>");
print("</head><body>"); print("</head><body>");
print("<h1>" . $language["REGISTRATION_FAILED"] . "</h1>"); print("<h1>" . $language["REGISTRATION_FAILED"] . "</h1>");
if (isset($language[$e->getMessage()])) { print("<p>" . $e->getMessage() . "</p>");
print("<p>" . $language[$e->getMessage()] . "</p>"); print("<a href=\"" . $webroot . "/register.php" . "\">Zur Registrierungsseite</a>");
} else {
print("<p>" . $e->getMessage() . "</p>");
}
print("<a href=\"" . $config["webroot"] . "/index.php" . "\">Zur Registrierungsseite</a>");
} }
?> ?>
</body> </body>