diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4f4773f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+config.php
diff --git a/MatrixConnection.php b/MatrixConnection.php
new file mode 100644
index 0000000..e97a39e
--- /dev/null
+++ b/MatrixConnection.php
@@ -0,0 +1,156 @@
+hs = $homeserver;
+ $this->at = $access_token;
+ }
+
+ function send($room_id, $message) {
+ if (!$this->at) {
+ error_log("No access token defined");
+ return false;
+ }
+
+ $send_message = NULL;
+ if (!$message) {
+ error_log("no message to send");
+ } 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/"
+ . 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"));
+
+ $response = $this->exec_curl_request($handle);
+ return isset($response["event_id"]);
+ }
+
+ function send_msg($room_id, $message) {
+ return $this->send($room_id, array(
+ "msgtype" => "m.notice",
+ "body" => $message
+ )
+ );
+ }
+
+ function hasUser($username) {
+ if (!$username) {
+ throw new Exception ("no user given to lookup");
+ }
+
+ $url = "https://".$this->hs."/_matrix/client/r0/profile/@" . $username . ":" . $this->hs;
+ $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"));
+
+ $res = $this->exec_curl_request($handle);
+ return !(isset($res["errcode"]) && $res["errcode"] == "M_UNKNOWN");
+ }
+
+ function register($username, $password, $shared_secret) {
+ if (!$username) {
+ error_log("no username provided");
+ }
+ if (!$password) {
+ error_log("no message to send");
+ }
+
+ $mac = hash_hmac('sha1', $username, $shared_secret);
+
+ $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));
+
+ return $this->exec_curl_request($handle);
+ }
+
+ function exec_curl_request($handle) {
+ $response = curl_exec($handle);
+
+ if ($response === false) {
+ $errno = curl_errno($handle);
+ $error = curl_error($handle);
+ error_log("Curl returned error $errno: $error\n");
+ curl_close($handle);
+ return false;
+ }
+
+ $http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
+ curl_close($handle);
+
+ if ($http_code >= 500) {
+ // do not want to DDOS server if something goes wrong
+ sleep(10);
+ return false;
+ } else if ($http_code != 200) {
+ $response = json_decode($response, true);
+ error_log("Request has failed with error {$response['error']}\n");
+ if ($http_code == 401) {
+ throw new Exception('Invalid access token provided');
+ }
+ } else {
+ $response = json_decode($response, true);
+ }
+
+ return $response;
+ }
+}
+
+class MatrixMessage
+{
+ private $message;
+
+ function __construct() {
+ $this->message = array(
+ "msgtype" => "m.notice",
+ );
+ }
+
+ function set_type($msgtype) {
+ $this->message["msgtype"] = $msgtype;
+ }
+
+ function set_format($format) {
+ $this->message["format"] = $format;
+ }
+
+ function set_body($body) {
+ $this->message["body"] = $body;
+ }
+
+ 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;
+ }
+}
+?>
diff --git a/config.sample.php b/config.sample.php
new file mode 100644
index 0000000..419a682
--- /dev/null
+++ b/config.sample.php
@@ -0,0 +1,9 @@
+
diff --git a/cron.php b/cron.php
new file mode 100644
index 0000000..861137e
--- /dev/null
+++ b/cron.php
@@ -0,0 +1,96 @@
+query($sql) as $row) {
+ $first_name = $row["first_name"];
+ $last_name = $row["last_name"];
+ $username = $row["username"];
+ $email = $row["email"];
+ $state = $row["state"];
+
+ try {
+ switch ($state) {
+ case RegisterState::PendingEmailSend:
+ $verify_url = $webroot . "/verify.php?t=" . $row["verify_token"];
+ $success = send_mail_pending_verification(
+ $homeserver,
+ $row["first_name"] . " " . $row["last_name"],
+ $row["email"],
+ $row["verify_url"]);
+
+ if ($success) {
+ $db->exec("UPDATE registrations SET state = " . RegisterState::PendingEmailVerify
+ . " WHERE id = " . $row["id"] . ";");
+ } else {
+ throw new Exception("Could not send mail to ".$row["first_name"]." ".$row["last_name"]."(".$row["id"].")");
+ }
+ break;
+ case RegisterState::PendingAdminSend:
+ require_once("MatrixConnection.php");
+ $adminUrl = $webroot . "/verify_admin.php?t=" . $row["admin_token"];
+ $mxConn = new MatrixConnection($homeserver, $access_token);
+ $mxMsg = new MatrixMessage();
+ $mxMsg->set_body($first_name . ' ' . $last_name . "möchte sich registrieren und hat folgende Notiz hinterlassen:\r\n"
+ . $row["note"] . "\r\n"
+ . "Zum Bearbeiten hier klicken:\r\n" . $adminUrl);
+ $mxMsg->set_formatted_body($first_name . ' ' . $last_name . " möchte sich registrieren und hat folgende Notiz hinterlassen:
"
+ . $row["note"] . "
"
+ . "Zum Bearbeiten hier klicken");
+ $mxMsg->set_type("m.text");
+ $response = $mxConn->send($register_room, $mxMsg);
+
+ if ($response) {
+ $db->exec("UPDATE registrations SET state = " . RegisterState::PendingAdminVerify
+ . " WHERE id = " . $row["id"] . ";");
+
+ send_mail_pending_approval($homeserver, $first_name . " " . $last_name, $email);
+ } else {
+ throw new Exception("Could not send notification for ".$row["first_name"]." ".$row["last_name"]."(".$row["id"].") to admins.");
+ }
+ break;
+ case RegisterState::PendingRegistration:
+ // Registration got accepted but registration failed
+
+ // register user
+ 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_mail_registration_success($homeserver, $first_name . " " . $last_name, $email, $username, $password, $howToURL);
+ } else {
+ send_mail_registration_allowed_but_failed($homeserver, $first_name . " " . $last_name, $email);
+ $mxMsg = new MatrixMessage();
+ $mxMsg->set_type("m.text");
+ $mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . ".");
+ $mxConn->send($register_room, $mxMsg);
+ throw new Exception($language["REGISTRATION_FAILED"]);
+ }
+ break;
+ case RegisterState::PendingSendRegistrationMail:
+ print ("Error: Unhandled state: PendingSendRegistrationMail for " . $first_name . " " . $last_name . " (" . $username . ")\n");
+ break;
+ case RegisterState::RegistrationDeclined:
+ case RegisterState::AllDone:
+ // do reqular cleanup
+ break;
+ }
+ } catch (Exception $e) {
+ print("Error while handling cron for " . $first_name . " " . $last_name . " (" . $username . ")\n");
+ print($e->getMessage());
+ }
+}
+?>
diff --git a/database.php b/database.php
new file mode 100644
index 0000000..abfeae3
--- /dev/null
+++ b/database.php
@@ -0,0 +1,55 @@
+setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $db->exec("CREATE TABLE registrations(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ state INT DEFAULT 0,
+ first_name TEXT,
+ last_name TEXT,
+ username TEXT,
+ note TEXT,
+ email TEXT,
+ verify_token TEXT,
+ admin_token TEXT,
+ request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP)");
+}
+else {
+ // establish connection
+ $db = new PDO('sqlite:' . $db_file);
+ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+}
+
+// set writeable when not set already
+if (!is_writable($db_file)) {
+ chmod($db_file, 0777);
+}
+?>
diff --git a/lang/lang.de-de.php b/lang/lang.de-de.php
new file mode 100644
index 0000000..84dafb0
--- /dev/null
+++ b/lang/lang.de-de.php
@@ -0,0 +1,27 @@
+ "Es konnte keine Konfiguration gefunden werden.",
+ "UNKNOWN_SESSION" => "Sitzungstoken nicht vorhanden oder ungültig.",
+ "UNKNOWN_USERNAME" => "Nutzername fehlt",
+ "UNKNOWN_TOKEN" => "Token ist unbekannt",
+ "USERNAME_LENGTH_INVALID" => "Entweder mehr als 20 oder weniger als 3 Zeichen für den Nutzernamen verwendet",
+ "USERNAME_NOT_ALNUM" => "Nutzername ist nicht alphanumerisch",
+ "USERNAME_PENDING_REGISTRATION" => "Dieser Nutzername wurde bereits zur Registrierung vorgemerkt. Versuche es später noch einmal oder wähle einen anderen Nutzernamen",
+ "USERNAME_REGISTERED" => "Dieser Nutzername wurde bereits registriert. Bitte wähle einen anderen Nutzernamen",
+ "PASSWORD_NOT_MATCH" => "Passwörter stimmen nicht überein",
+ "NOTE_LENGTH_EXEEDED" => "Notiz ist länger als die erlaubten 50 Zeichen",
+ "EMAIL_INVALID_FORMAT" => "Keine valide E-Mail-Adresse angegeben",
+ "FIRSTNAME_INVALID_FORMAT" => "Vorname hat ungültiges Format",
+ "SIRNAME_INVALID_FORMAT" => "Nachname hat ungültiges Format",
+ "SEND_MAIL_FAIL" => "Senden der E-Mail fehlgeschlagen",
+ "SEND_MATRIX_FAIL" => "Senden einer Nachricht an die Administratoren fehlgeschlagen",
+ "REGISTRATION_REQUEST_FAILED" => "Registrierungsanfrage ist fehlgeschlagen",
+ "REGISTRATION_FAILED" => "Registrierung ist fehlgeschlagen",
+ "VERIFICATION_SUCEEDED" => "Verifizierung erfolgreich",
+ "VERIFICATION_FAILED" => "Verifizierung fehlgeschlagen",
+ "VERIFICATION_SUCCESS_BODY" => "Vielen Dank. Die Administratoren wurden informiert",
+ "ADMIN_VERIFY_SITE_TITLE" => "Registrierungsanfrage bearbeiten",
+ "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.",
+);
+?>
diff --git a/language.php b/language.php
new file mode 100644
index 0000000..bd50c04
--- /dev/null
+++ b/language.php
@@ -0,0 +1,12 @@
+
diff --git a/mail_templates.php b/mail_templates.php
new file mode 100644
index 0000000..5db7b81
--- /dev/null
+++ b/mail_templates.php
@@ -0,0 +1,103 @@
+
diff --git a/public/register.php b/public/register.php
new file mode 100644
index 0000000..d52a2c7
--- /dev/null
+++ b/public/register.php
@@ -0,0 +1,225 @@
+
+
Bitte überprüfe deine E-Mails um deine E-Mail-Adresse zu bestätigen.
"); + print("Zur Registrierungsseite"); + } catch (Exception $e) { + print("" . $e->getMessage() . "
"); + print("Zur Registrierungsseite"); + } +} else { + $_SESSION["token"] = bin2hex(random_bytes(16)); +?> +Hinweis:
+ cg-s.tk is ein geschlossenes Chat-Netzwerk in dem jeder Nutzer bestätigt werden muss.
+ 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).
+ Liebe Grüße vom Team von cg-s.tk
+
" . $language["VERIFICATION_SUCCESS_BODY"] . "
"); + print("Zur Registrierungsseite"); +} catch (Exception $e) { + print("" . $e->getMessage() . "
"); + print("Zur Registrierungsseite"); +} +?> + + diff --git a/public/verify_admin.php b/public/verify_admin.php new file mode 100644 index 0000000..7ba51fd --- /dev/null +++ b/public/verify_admin.php @@ -0,0 +1,183 @@ + + +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"]); + } + + if ($action == RegisterState::RegistrationAccepted) { + $db->exec("UPDATE registrations SET state = " . RegisterState::PendingRegistration + . " WHERE admin_token = '" . $token. "';"); + + // register user + 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, $registration_shared_secret); + if ($res) { + // send registration_success + $res = send_mail_registration_success($homeserver, $first_name . " " . $last_name, $email, $username, $password, $howToURL); + if ($res) { + $db->exec("UPDATE registrations SET state = " . RegisterState::AllDone + . " WHERE admin_token = '" . $token. "';"); + } else { + $db->exec("UPDATE registrations SET state = " . RegisterState::PendingSendRegistrationMail + . " WHERE admin_token = '" . $token. "';"); + } + } else { + send_mail_registration_allowed_but_failed($homeserver, $first_name . " " . $last_name, $email); + $mxMsg = new MatrixMessage(); + $mxMsg->set_type("m.text"); + $mxMsg->set_body("Fehler beim Registrieren von " . $first_name . " " . $last_name . "."); + $mxConn->send($register_room, $mxMsg); + throw new Exception($language["REGISTRATION_FAILED"]); + } + + print("" . $language["ADMIN_REGISTER_ACCEPTED_BODY"] . "
"); + } elseif ($action == RegisterState::RegistrationDeclined) { + $db->exec("UPDATE registrations SET state = " . RegisterState::RegistrationDeclined + . " WHERE admin_token = '" . $token. "';"); + send_mail_registration_decline($homeserver, $first_name . " " . $last_name, $email, $decline_reason); + print("" . $language["ADMIN_REGISTER_DECLINED_BODY"] . "
"); + } else { + + print("