+ ';
+} elseif ($requesttype == "falselogin") {
+ $error = '
';
+} else {
+ $userInput = '';
+ $pwdInput = '';
+ $twoFactorInput = '';
+ $error = '';
+}
+?>
-
-
-
-
-
-
Bitte einloggen
-
-
-
+
+
+
+
+
Bitte einloggen
+
+
+
+
+
-
-
diff --git a/Layout/default/topbar.php b/Layout/default/topbar.php
index e8dd609c6..3cbd55d21 100644
--- a/Layout/default/topbar.php
+++ b/Layout/default/topbar.php
@@ -23,11 +23,12 @@
-
+ =self::getUrl("UserProfile")?> ">
-
+
+
- =$me->username?>
+ =$me->username?>
diff --git a/application/SmsNotification/SmsNotification.php b/application/SmsNotification/SmsNotification.php
index 3da3d54e5..052d38cd0 100644
--- a/application/SmsNotification/SmsNotification.php
+++ b/application/SmsNotification/SmsNotification.php
@@ -48,8 +48,16 @@ class SmsNotification
),
));
$response = curl_exec($curl);
+ $exploderesponse = explode("&", $response);
+ foreach ($exploderesponse as $value) {
+ $explode = explode("=", $value);
+ if (count($explode) == 2) {
+ $responsedata['data'][$explode[0]] = $explode[1];
+ }
+ }
+
curl_close($curl);
- echo $response;
+ return $responsedata;
}
}
diff --git a/application/User/User.php b/application/User/User.php
index 62aa16132..a20c89a74 100644
--- a/application/User/User.php
+++ b/application/User/User.php
@@ -9,7 +9,8 @@ class User extends mfBaseModel {
public $permissions;
public $flags;
public $address;
-
+ protected $forcestr = ['mobile','twofactorcode'];
+
private $my_networks;
public function init() {
diff --git a/application/User/UserController.php b/application/User/UserController.php
index d8c29048c..167ab3337 100644
--- a/application/User/UserController.php
+++ b/application/User/UserController.php
@@ -5,260 +5,278 @@
*
* @author fronk
*/
-class UserController extends mfBaseController {
- private $me;
-
- protected function init($request = null) {
- $this->needlogin=true;
- $me = new User();
- $me->loadMe();
- $this->me = $me;
- $this->layout()->set("me",$me);
-
- if(!$me->isAdmin()) {
- // all users can call non-action methods
- if($this->action != "" || $request != null) {
- $this->redirect("Dashboard");
- }
- }
- }
-
- protected function indexAction($request) {
- if(!$this->isAdmin()) {
- throw new Exception("Forbidden", 403);
- }
- $this->layout()->setTemplate('User/Index');
-
- if($this->request->filter) {
- $users = UserModel::search($this->request->filter);
- } else {
- $users = UserModel::getAll();
- }
- $this->layout()->set('users',$users);
-
- $addresses = AddressModel::getAll();
- $this->layout()->set("addresses", $addresses);
- $this->layout()->set("filter", $this->request->filter);
- }
-
- protected function addAction($request) {
- if(!$this->isAdmin()) {
- throw new Exception("Forbidden", 403);
- }
- $this->layout()->setTemplate('User/Form');
-
- $addresses = AddressModel::getAll();
- $this->layout()->set("addresses", $addresses);
-
- if($this->request->address_id) {
- $this->layout()->set("address_id", $this->request->address_id);
- }
- }
-
- protected function editAction($request) {
- if(!$this->isAdmin()) {
- throw new Exception("Forbidden", 403);
- }
- $this->layout()->setTemplate('User/Form');
-
- $id=$request['id'];
- if(!is_numeric($id) || $id <= 0) {
- throw new Exception("User $id not found",604);
- }
-
- $user=new User($id);
- $this->layout()->set('user',$user);
-
- $addresses = AddressModel::getAll();
- $this->layout()->set("addresses", $addresses);
- }
-
- protected function generateApikey($request) {
- if(!$this->isAdmin()) {
- $this->redirect("Dashboard");
- }
- $id = $request['id'];
- if(!is_numeric($id) || $id < 1) {
- $this->layout()->setFlash("User nicht gefunden.", "error");
- $this->redirect("User");
- }
-
- $user = new User($id);
- if(!$user->id) {
- $this->layout()->setFlash("User nicht gefunden.", "error");
- $this->redirect("User");
- }
-
- $user->apikey = $user->createApiKey();
- $user->save();
-
- $this->layout()->setFlash("API Key erfolgreich generiert.", "success");
- $this->redirect("User", "edit", ['id' => $id]);
-
- }
-
- protected function profileAction($request) {
-
- }
+class UserController extends mfBaseController
+{
+ private $me;
+ protected function init($request = null)
+ {
+ $this->needlogin = true;
+ $me = new User();
+ $me->loadMe();
+ $this->me = $me;
+ $this->layout()->set("me", $me);
- protected function saveAction() {
- $r = $this->request;
- $id = $r->id;
- if(!$this->isAdmin()) {
- $id = $this->me->id;
- $request['username'] = $this->me->username;
- unset($r->address_id);
- }
-
- if(!$id && !$r->username) {
- self::redirect('User');
- }
-
- $user = new User($id);
-
- // check if new user already exits
- if($this->isAdmin() && !$r->id) {
- $tu = new User();
- $tu->loadByUsername($r->username);
- if($tu->id) {
- $this->layout()->setFlash("Benutzer mit diesem Benutzername bereits vorhanden!", "error");
- $this->redirect("User");
- }
- }
-
- if(!$user->permissions) {
- $user->permissions = new WorkerPermission();
- }
- if($r->username) {
- $user->username = $r->username;
- }
- if($r->name) {
- $user->name = $r->name;
- }
- if($r->email) {
- $user->email = $r->email;
- }
- if($r->address_id) {
- if($this->isAdmin()) {
- $user->address_id = intval($r->address_id);
- //var_dump($user);exit;
- $address = new Address($user->address_id);
- if(!$address->id) {
- throw new Exception("Unbekannte Firma/Person");
+ if (!$me->isAdmin()) {
+ // all users can call non-action methods
+ if ($this->action != "" || $request != null) {
+ $this->redirect("Dashboard");
+ }
}
- }
}
-
- if($r->password) {
- if($r->password === $r->password2) {
- $user->password=mfLoginController::generatePasswordHash($r->password);
- } else {
- $this->layout()->setFlash("Passwörter stimmen nicht überein!", "error");
- }
+
+ protected function indexAction($request)
+ {
+ if (!$this->isAdmin()) {
+ throw new Exception("Forbidden", 403);
+ }
+ $this->layout()->setTemplate('User/Index');
+
+ if ($this->request->filter) {
+ $users = UserModel::search($this->request->filter);
+ } else {
+ $users = UserModel::getAll();
+ }
+ $this->layout()->set('users', $users);
+
+ $addresses = AddressModel::getAll();
+ $this->layout()->set("addresses", $addresses);
+ $this->layout()->set("filter", $this->request->filter);
}
-
- $user->edit_by = $this->me->id;
- if(!$id) {
- $user->create_by = $this->me->id;
+
+ protected function addAction($request)
+ {
+ if (!$this->isAdmin()) {
+ throw new Exception("Forbidden", 403);
+ }
+ $this->layout()->setTemplate('User/Form');
+
+ $addresses = AddressModel::getAll();
+ $this->layout()->set("addresses", $addresses);
+
+ if ($this->request->address_id) {
+ $this->layout()->set("address_id", $this->request->address_id);
+ }
}
-
- $id = $user->save();
-
- if($this->isAdmin()) {
- if($r->admin == "true" || $user->id == 1) {
- $user->permissions->admin = "true";
- } else {
- $user->permissions->admin = "false";
- }
-
- if($r->technician == "true") {
- $user->permissions->technician = "true";
- } else {
- $user->permissions->technician = "false";
- }
-
- if($r->preorderfront == "true") {
- $user->permissions->preorderfront = "true";
- } else {
- $user->permissions->preorderfront = "false";
- }
-
- $user->permissions->save();
-
- // save networks
- $pn = $user->getFlag("preorder_networks");
- if($r->preorderfront == "true" && is_array($r->preorder_networks) && count($r->preorder_networks)) {
- $pn->value(json_encode($r->preorder_networks));
- $pn->save();
- } else {
- $pn->delete();
- }
+
+ protected function editAction($request)
+ {
+ if (!$this->isAdmin()) {
+ throw new Exception("Forbidden", 403);
+ }
+ $this->layout()->setTemplate('User/Form');
+
+ $id = $request['id'];
+ if (!is_numeric($id) || $id <= 0) {
+ throw new Exception("User $id not found", 604);
+ }
+
+ $user = new User($id);
+ $this->layout()->set('user', $user);
+
+ $addresses = AddressModel::getAll();
+ $this->layout()->set("addresses", $addresses);
}
-
- $this->layout()->setFlash("Benutzer gespeichert.", "success");
- self::redirect('User');
- }
-
- protected function deleteAction($request) {
- if(!$this->isAdmin()) {
- $this->redirect("Bridge");
+
+ protected function generateApikey($request)
+ {
+ if (!$this->isAdmin()) {
+ $this->redirect("Dashboard");
+ }
+ $id = $request['id'];
+ if (!is_numeric($id) || $id < 1) {
+ $this->layout()->setFlash("User nicht gefunden.", "error");
+ $this->redirect("User");
+ }
+
+ $user = new User($id);
+ if (!$user->id) {
+ $this->layout()->setFlash("User nicht gefunden.", "error");
+ $this->redirect("User");
+ }
+
+ $user->apikey = $user->createApiKey();
+ $user->save();
+
+ $this->layout()->setFlash("API Key erfolgreich generiert.", "success");
+ $this->redirect("User", "edit", ['id' => $id]);
+
}
- $id = $request['id'];
-
- if(!is_numeric($id) || $id <= 0) {
- throw new Exception("User $id not found",604);
+
+ protected function profileAction($request)
+ {
+
}
-
- $user = new User($id);
- if($user->id == $id) {
- $user->delete();
- }
-
- self::redirect("User");
- }
-
- protected function pwchangeAction($request) {
- $me = new User();
- $me->loadMe();
-
- $pw1 = $request['password'];
- $pw2 = $request['password2'];
-
- if(!$pw1 == $pw2) {
- throw new Exception("Passwords don't match! Password change aborted.");
- }
-
- if(strlen($pw1) < 8) {
- throw new Exception("Passwords must be 8 characters minimum!");
- }
-
- if($pw1 == "12345678" || $pw1 == "123456789" || $pw1 == "password" || $pw1 == "passwort") {
- throw new Exception("Be a little more creative with your password please...");
- }
-
- $me->password = mfLoginController::generatePasswordHash($pw1);
- $me->save();
- $this->redirect("Dashboard");
- }
- public function getUsers() {
- $users=array();
- $res=$this->db()->select(MFUSERTABLE,'*','1=1 ORDER BY username');
- if($this->db()->num_rows($res)) {
- while($data=$this->db()->fetch_object($res)) {
- $users[$data->id]=new User($data);
- }
+ protected function saveAction()
+ {
+ $r = $this->request;
+ $id = $r->id;
+ if (!$this->isAdmin()) {
+ $id = $this->me->id;
+ $request['username'] = $this->me->username;
+ unset($r->address_id);
+ }
+
+ if (!$id && !$r->username) {
+ self::redirect('User');
+ }
+
+ $user = new User($id);
+
+ // check if new user already exits
+ if ($this->isAdmin() && !$r->id) {
+ $tu = new User();
+ $tu->loadByUsername($r->username);
+ if ($tu->id) {
+ $this->layout()->setFlash("Benutzer mit diesem Benutzername bereits vorhanden!", "error");
+ $this->redirect("User");
+ }
+ }
+
+ if (!$user->permissions) {
+ $user->permissions = new WorkerPermission();
+ }
+ if ($r->username) {
+ $user->username = $r->username;
+ }
+ if ($r->name) {
+ $user->name = $r->name;
+ }
+ if ($r->email) {
+ $user->email = $r->email;
+ }
+ if ($r->mobile) {
+ $user->mobile = $r->mobile;
+ } else {
+ $user->mobile = NULL;
+ }
+
+ if ($r->address_id) {
+ if ($this->isAdmin()) {
+ $user->address_id = intval($r->address_id);
+ //var_dump($user);exit;
+ $address = new Address($user->address_id);
+ if (!$address->id) {
+ throw new Exception("Unbekannte Firma/Person");
+ }
+ }
+ }
+
+ if ($r->password) {
+ if ($r->password === $r->password2) {
+ $user->password = mfLoginController::generatePasswordHash($r->password);
+ } else {
+ $this->layout()->setFlash("Passwörter stimmen nicht überein!", "error");
+ }
+ }
+
+ $user->edit_by = $this->me->id;
+ if (!$id) {
+ $user->create_by = $this->me->id;
+ }
+
+ $id = $user->save();
+
+ if ($this->isAdmin()) {
+ if ($r->admin == "true" || $user->id == 1) {
+ $user->permissions->admin = "true";
+ } else {
+ $user->permissions->admin = "false";
+ }
+
+ if ($r->technician == "true") {
+ $user->permissions->technician = "true";
+ } else {
+ $user->permissions->technician = "false";
+ }
+
+ if ($r->preorderfront == "true") {
+ $user->permissions->preorderfront = "true";
+ } else {
+ $user->permissions->preorderfront = "false";
+ }
+
+ $user->permissions->save();
+
+ // save networks
+ $pn = $user->getFlag("preorder_networks");
+ if ($r->preorderfront == "true" && is_array($r->preorder_networks) && count($r->preorder_networks)) {
+ $pn->value(json_encode($r->preorder_networks));
+ $pn->save();
+ } else {
+ $pn->delete();
+ }
+ }
+
+ $this->layout()->setFlash("Benutzer gespeichert.", "success");
+ self::redirect('User');
+ }
+
+ protected function deleteAction($request)
+ {
+ if (!$this->isAdmin()) {
+ $this->redirect("Bridge");
+ }
+ $id = $request['id'];
+
+ if (!is_numeric($id) || $id <= 0) {
+ throw new Exception("User $id not found", 604);
+ }
+
+ $user = new User($id);
+ if ($user->id == $id) {
+ $user->delete();
+ }
+
+ self::redirect("User");
+ }
+
+ protected function pwchangeAction($request)
+ {
+ $me = new User();
+ $me->loadMe();
+
+ $pw1 = $request['password'];
+ $pw2 = $request['password2'];
+
+ if (!$pw1 == $pw2) {
+ throw new Exception("Passwords don't match! Password change aborted.");
+ }
+
+ if (strlen($pw1) < 8) {
+ throw new Exception("Passwords must be 8 characters minimum!");
+ }
+
+ if ($pw1 == "12345678" || $pw1 == "123456789" || $pw1 == "password" || $pw1 == "passwort") {
+ throw new Exception("Be a little more creative with your password please...");
+ }
+
+ $me->password = mfLoginController::generatePasswordHash($pw1);
+ $me->save();
+ $this->redirect("Dashboard");
+ }
+
+
+ public function getUsers()
+ {
+ $users = array();
+ $res = $this->db()->select(MFUSERTABLE, '*', '1=1 ORDER BY username');
+ if ($this->db()->num_rows($res)) {
+ while ($data = $this->db()->fetch_object($res)) {
+ $users[$data->id] = new User($data);
+ }
+ }
+ return $users;
+ }
+
+ private function isAdmin()
+ {
+ $me = new User();
+ $this->layout->set("me", $me);
+ $me->loadMe();
+
+ return $me->isAdmin();
}
- return $users;
- }
-
- private function isAdmin() {
- $me = new User();
- $this->layout->set("me", $me);
- $me->loadMe();
-
- return $me->isAdmin();
- }
}
diff --git a/application/UserProfile/UserProfile.php b/application/UserProfile/UserProfile.php
new file mode 100644
index 000000000..91912d0e9
--- /dev/null
+++ b/application/UserProfile/UserProfile.php
@@ -0,0 +1,40 @@
+$name == null) {
+
+ if (!$this->id) {
+ return null;
+ }
+
+ if ($name == "creator") {
+ $this->creator = new User($this->create_by);
+ return $this->creator;
+ }
+
+ if ($name == "editor") {
+ $this->editor = new User($this->edit_by);
+ return $this->editor;
+ }
+
+ $classname = ucfirst($name);
+ $idfield = $name . "_id";
+ $this->$name = new $classname($this->$idfield);
+
+ if ($this->$name->id) {
+ return $this->$name;
+ } else {
+ return null;
+ }
+ }
+
+ return $this->$name;
+ }
+
+}
\ No newline at end of file
diff --git a/application/UserProfile/UserProfileController.php b/application/UserProfile/UserProfileController.php
new file mode 100644
index 000000000..e6aa66338
--- /dev/null
+++ b/application/UserProfile/UserProfileController.php
@@ -0,0 +1,279 @@
+needlogin = true;
+ $me = new User();
+ $me->loadMe();
+ $this->me = $me;
+ $this->layout()->set("me", $me);
+
+
+ }
+
+ protected function indexAction()
+ {
+
+ $this->layout()->setTemplate("UserProfile/Index");
+ $this->layout()->set("userprofile", $this->me);
+// $email = new Emailnotification();
+// $email->setSubject('testemail');
+// $email->setBody('Testemail');
+// $email->setTo('daniel.spitzer@inode.at');
+// $email->send();
+ }
+
+ protected function addAction()
+ {
+
+ }
+
+ protected function apiAction()
+ {
+ $do = $this->request->do;
+ $codetype = $this->request->twofactor;
+ switch ($do) {
+ case "sendcode":
+ $return = $this->sendCode($codetype);
+ break;
+ case "checkverfication":
+ $return = $this->checkverfication();
+ break;
+ default:
+ $return = false;
+ }
+
+
+ }
+
+ private function checkverfication()
+ {
+ $id = $this->me->id;
+ $User = new User($id);
+ if ($User) {
+ $response['data']['verficationtype'] = $User->twofactor;
+ $response['success'] = "true";
+ } else {
+ $response['success'] = "false";
+ }
+ echo json_encode($response);
+ exit;
+ }
+
+ private function sendCode($codetype)
+ {
+
+ $r = $this->request;
+ $code = rand(0, 99999);
+ $code = str_pad($code, 5, 0, STR_PAD_LEFT);
+ $id = $this->me->id;
+ $emailaddress = $this->me->email;
+ $mobile = str_replace('+', '', $this->me->mobile);
+ $verification = $r->twofactor;
+
+ $User = new User($id);
+ $data = [];
+ $data['twofactorcode'] = $code;
+ $data['twofactortimestamp'] = time();
+ $User->update($data);
+ $User->save();
+ if ($verification == 1) {
+ $email = new Emailnotification();
+ $email->setSubject('Authentifizierungscode');
+ $email->setFrom('noreply@xinon.at', 'noreply@xinon.at');
+ $email->setBody($code);
+ $email->setTo($emailaddress);
+ $response = $email->send();
+ } else if ($verification == 2) {
+ if (!$this->me->mobile) {
+ $this->layout()->setFlash("Keine Mobilnummer hinterlegt", "error");
+ $this->redirect("UserProfile");
+ }
+ $sms = new SmsNotification();
+ $sms->setBody('Xinon 2FA Code: ' . $code);
+ $sms->setRecipient($mobile);
+ $response = $sms->send();
+ }
+ $response['success'] = "true";
+ echo json_encode($response);
+ exit;
+ }
+
+ protected function editAction()
+ {
+ $this->layout()->setTemplate("UserProfile/Form");
+ $this->layout()->set("userprofile", $this->me);
+ }
+
+ protected function saveAction()
+ {
+ $r = $this->request;
+ $id = $this->me->id;
+ $User = new User($id);
+ if ($User->twofactor != 0) {
+ $requestcode2fa = $r->code;
+ $userCode2fa = $User->twofactorcode;
+ if (!trim($requestcode2fa)) {
+ $this->layout()->setFlash("Verifizierungscode ", "error");
+ $this->redirect("UserProfile/edit");
+ } else if ($requestcode2fa != $userCode2fa) {
+ $this->layout()->setFlash("Verifizierungscode ungültig", "error");
+ $this->redirect("UserProfile/edit");
+ }
+
+ }
+
+ $data = [];
+ $data['name'] = trim($r->name);
+ if ($User->twofactor != 1) {
+ $data['email'] = trim($r->email);
+ if (!$data['email']) {
+ $this->layout()->setFlash("Email darf nicht leer sein", "error");
+ $this->redirect("UserProfile/edit");
+ }
+ }
+ if ($User->twofactor != 2) {
+ $data['mobile'] = trim($r->mobile);
+ }
+ if (!$data['name']) {
+ $this->layout()->setFlash("Name darf nicht leer sein", "error");
+ $this->redirect("UserProfile/edit");
+ }
+
+ if ($data['mobile'] && substr($data['mobile'], 0, 1) != "+") {
+ $this->layout()->setFlash("Telefonnummer im Format +436641122334455 eingeben", "error");
+ $this->redirect("UserProfile/edit");
+ }
+
+ $User->update($data);
+ $User->save();
+ $this->layout()->setFlash("Benutzerprofil erfolgreich geändert", "success");
+
+ $this->redirect("UserProfile");
+ }
+
+ protected function changepwdAction()
+ {
+ $r = $this->request;
+ $id = $this->me->id;
+ $pwd = $this->me->password;
+ $oldpwd = trim($r->oldpwd);
+ $newpwd = trim($r->newpwd);
+ $checkpwd = trim($r->checkpwd);
+ $User = new User($id);
+ $data = [];
+
+
+ $salt = substr($pwd, 0, 16);
+ $passhash = mfLoginController::generatePasswordHash($oldpwd, $salt);
+ if (!$oldpwd) {
+ $this->layout()->setFlash("altes Passwort darf nicht leer sein", "error");
+ $this->redirect("UserProfile");
+ }
+ if (!$newpwd) {
+ $this->layout()->setFlash("neues Passwort darf nicht leer sein", "error");
+ $this->redirect("UserProfile");
+ }
+
+ if ($pwd != $passhash) {
+ $this->layout()->setFlash("altes Passwort falsch", "error");
+ $this->redirect("UserProfile");
+ }
+ if (strlen($newpwd < 8)) {
+ $this->layout()->setFlash("neues Passwort muss min. 8 Zeichen haben", "error");
+ $this->redirect("UserProfile");
+ }
+ if ($newpwd != $checkpwd) {
+ $this->layout()->setFlash("Passwörter stimmen nicht überein", "error");
+ $this->redirect("UserProfile");
+ }
+
+ $newpasshash = mfLoginController::generatePasswordHash($newpwd);
+ $data['password'] = $newpasshash;
+ $User->update($data);
+ $User->save();
+ $this->layout()->setFlash("Passwort erfolgreich geändert", "success");
+ $this->redirect("UserProfile");
+
+
+ }
+
+ protected function code2faaction()
+ {
+ $r = $this->request;
+ $code = rand(0, 99999);
+ $code = str_pad($code, 5, 0, STR_PAD_LEFT);
+ $id = $this->me->id;
+ $emailaddress = $this->me->email;
+ $mobile = str_replace('+', '', $this->me->mobile);
+ $verification = $r->twofactor;
+
+ $User = new User($id);
+ $data = [];
+ $data['twofactorcode'] = $code;
+ $data['twofactortimestamp'] = time();
+ $User->update($data);
+ $User->save();
+ if ($verification == 1) {
+ $email = new Emailnotification();
+ $email->setSubject('Authentifizierungscode');
+ $email->setFrom('noreply@xinon.at', 'noreply@xinon.at');
+ $email->setBody($code);
+ $email->setTo($emailaddress);
+ $email->send();
+ } else if ($verification == 2) {
+ if (!$this->me->mobile) {
+ $this->layout()->setFlash("Keine Mobilnummer hinterlegt", "error");
+ $this->redirect("UserProfile");
+ }
+ $sms = new SmsNotification();
+ $sms->setBody('Xinon 2FA Code: ' . $code);
+ $sms->setRecipient($mobile);
+ $sms->send();
+ }
+ $this->layout()->setTemplate("UserProfile/Index");
+ $this->layout()->set("verification", $verification);
+ $this->layout()->set("userprofile", $this->me);
+ }
+
+ protected function activate2faaction()
+ {
+ $r = $this->request;
+ $reqCode = $r->code;
+ $twofactorcode = $this->me->twofactorcode;
+ $twofactortimestamp = $this->me->twofactortimestamp;
+ $timeSecond = time() - $twofactortimestamp;
+
+ if ($timeSecond <= 300 && $reqCode == $twofactorcode) {
+ $id = $this->me->id;
+ $User = new User($id);
+ $data['twofactor'] = $r->twofactor;
+ $User->update($data);
+ $User->save();
+ $this->layout()->setFlash("Zwei-Faktor-Authentifizierung aktiv", "success");
+ $this->redirect("UserProfile");
+ } else {
+ $verification = $r->twofactor;
+ $this->layout()->setFlash("Verifizierungscode falsch oder abgelaufen", "error");
+ $this->layout()->setTemplate("UserProfile/Index");
+ $this->layout()->set("verification", $verification);
+ $this->layout()->set("userprofile", $this->me);
+ }
+ }
+
+ protected function change2faaction()
+ {
+ if ($this->request->twofactor == 2) {
+ if (!$this->me->mobile) {
+ $this->layout()->setFlash("Keine Mobilnummer hinterlegt", "error");
+ $this->redirect("UserProfile");
+ }
+ }
+ $this->code2faaction();
+ }
+}
diff --git a/application/UserToken/UserToken.php b/application/UserToken/UserToken.php
new file mode 100644
index 000000000..96ba02713
--- /dev/null
+++ b/application/UserToken/UserToken.php
@@ -0,0 +1,68 @@
+escape($selector);
+ $now = time();
+ $res = $db->select(MFUSERTOKENTABLE, "worker_id,token", "selector='$selector' AND token_expire > '$now'");
+ if ($db->num_rows($res)) {
+ $Token = $db->fetch_object($res);
+ if ($Token->token == $token) {
+ $res = $db->select(MFUSERTABLE, "username", "id='$Token->worker_id'");
+ if ($db->num_rows($res)) {
+ $User = $db->fetch_object($res);
+ if (!isset($_SESSION[MFAPPNAME . '_username'])) {
+ $refresh = true;
+ }
+ $_SESSION[MFAPPNAME . '_username'] = $User->username;
+ $_SESSION[MFAPPNAME . '_ip'] = $_SERVER['REMOTE_ADDR'];;
+ $db->update(MFUSERTABLE, array('ip' => $_SERVER['REMOTE_ADDR'], 'sessionid' => session_id()), "id='$Token->worker_id'");
+ if ($refresh) {
+ header("Refresh:0");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public function generateToken($userId)
+ {
+ $db = new FronkDB();
+ $tokenExpireTime = time() + 2592000;
+ $selector = bin2hex(random_bytes(16));
+ $token = bin2hex(random_bytes(32));
+ $values['worker_id'] = $userId;
+ $values['selector'] = $selector;
+ $values['token'] = $token;
+ $values['token_expire'] = $tokenExpireTime;
+ $values['create_by'] = $userId;
+ $values['create'] = date('U');
+ $db->insert("WorkerToken", $values);
+ setcookie(MFAPPNAME . '_remembertoken', $selector . ':' . $token, $tokenExpireTime, "/");
+ }
+
+ public function deleteToken()
+ {
+ $db = new FronkDB();
+ $cookie = explode(':', $_COOKIE[MFAPPNAME . '_remembertoken']);
+ $selector = $cookie[0];
+ if (count($cookie) === 2) {
+
+ $db->delete("WorkerToken", "selector='" . $selector . "'", 1);
+ }
+ setcookie(MFAPPNAME . '_remembertoken', '', time() - 3600, '/');
+
+ }
+
+}
\ No newline at end of file
diff --git a/application/UserTwofactor/UserTwofactor.php b/application/UserTwofactor/UserTwofactor.php
new file mode 100644
index 000000000..97a95b95e
--- /dev/null
+++ b/application/UserTwofactor/UserTwofactor.php
@@ -0,0 +1,88 @@
+UserId = $UserId;
+ $this->getVerification();
+ }
+
+ public function setVerification($verification)
+ {
+ $this->Verification = $verification;
+ }
+
+ protected function apiAction()
+ {
+ $do = $this->request->do;
+ $codetype = $this->request->twofactor;
+ switch ($do) {
+ case "sendcode":
+ $return = $this->sendCode();
+ break;
+ case "checkverfication":
+ $return = $this->checkVerfication();
+ break;
+ default:
+ $return = false;
+ }
+
+
+ }
+
+ private function getVerification()
+ {
+ $id = $this->UserId;
+ $User = new User($id);
+ $this->Verification = $User->twofactor;
+ }
+
+ private function checkVerfication()
+ {
+ $this->getVerification();
+ $response['data']['verficationtype'] = $this->Verification;
+ $response['success'] = "true";
+
+ echo json_encode($response);
+ exit;
+ }
+
+ public function sendCode()
+ {
+ $code = rand(0, 99999);
+ $code = str_pad($code, 5, 0, STR_PAD_LEFT);
+ $verification = $this->Verification;
+ $id = $this->UserId;
+ $User = new User($id);
+ $emailaddress = $User->email;
+ $mobile = str_replace('+', '', $User->mobile);
+
+ $data = [];
+ $data['twofactorcode'] = $code;
+ $data['twofactortimestamp'] = time();
+ $User->update($data);
+ $User->save();
+ if ($verification == 1) {
+ $fromMail = TT_OUTGOING_EMAIL_2FA;
+ $fromName = TT_OUTGOING_EMAIL_2FA_NAME;
+
+ $email = new Emailnotification();
+ $email->setSubject('Authentifizierungscode');
+ $email->setFrom($fromMail, $fromName);
+ $email->setBody($code);
+ $email->setTo($emailaddress);
+ $email->send();
+ } else if ($verification == 2) {
+ $sms = new SmsNotification();
+ $sms->setBody('Xinon 2FA Code: ' . $code);
+ $sms->setRecipient($mobile);
+ $sms->send();
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/lib/mvcfronk/mfLogin/mfLoginController.php b/lib/mvcfronk/mfLogin/mfLoginController.php
index 1bac659ed..254b9b93a 100644
--- a/lib/mvcfronk/mfLogin/mfLoginController.php
+++ b/lib/mvcfronk/mfLogin/mfLoginController.php
@@ -1,162 +1,236 @@
layout()->setTemplate("mfLogin/Index");
- if($request['mfLoginTemplate']) {
- $this->layout()->setTemplate($request['mfLoginTemplate']);
- }
- /*if($request['mfLoginGet']) {
- $_SESSION['mfLoginGet']=$request['mfLoginGet'];
- }*/
- if($request['mfLoginUrl']) {
- $_SESSION['mfLoginUrl']=$request['mfLoginUrl'];
- }
-
-
- $this->logout();
- }
-
-
- protected function indexAction() {
- if($_SESSION[MFAPPNAME."_loginfailed"]) {
- $this->layout()->set("LayoutError","Login fehlgeschlagen.");
- }
- unset($_SESSION[MFAPPNAME."_loginfailed"]);
-
- }
-
- protected function loginAction($request) {
- if(!$this->performLogin($request['Username'],$request['Password'])) {
- $_SESSION[MFAPPNAME."_loginfailed"]=true;
- }
- //$get=$_SESSION['mfLoginGet'];
- $url=$_SESSION['mfLoginUrl'];
- //unset($_SESSION['mfLoginGet']);
- unset($_SESSION['mfLoginUrl']);
- /*
- $mod=$get['action'];
- if(preg_match('/([^_]+)_(.+)/',$action,$m)) {
- $mod=$m[1];
- $action=$m[2];
- }
- unset($get['action']);
-
- self::redirect($mod,$action,$get);
- */
-
- header("Location: $url");
- }
-
+class mfLoginController extends mfBaseController
+{
+ protected function init($request)
+ {
+ $this->layout()->setTemplate("mfLogin/Index");
+ if ($request['mfLoginTemplate']) {
+ $this->layout()->setTemplate($request['mfLoginTemplate']);
+ }
+ /*if($request['mfLoginGet']) {
+ $_SESSION['mfLoginGet']=$request['mfLoginGet'];
+ }*/
+ if ($request['mfLoginUrl']) {
+ $_SESSION['mfLoginUrl'] = $request['mfLoginUrl'];
+ }
-
- /*
- * Internal functions
- */
- public function logout() {
- if(!defined("MFAPPNAME")) define("MFAPPNAME","mvcfronk");
- if(!defined("MFUSERTABLE")) define("MFUSERTABLE","mfWorker");
- //session_name(MFAPPNAME."_session");
- //session_start();
- unset($_SESSION[MFAPPNAME.'_username']);
- unset($_SESSION[MFAPPNAME.'_ip']);
- }
-
- public static function staticLogout() {
- if(!defined("MFAPPNAME")) define("MFAPPNAME","mvcfronk");
- if(!defined("MFUSERTABLE")) define("MFUSERTABLE","mfWorker");
- //session_name(MFAPPNAME."_session");
- //session_start();
- unset($_SESSION[MFAPPNAME.'_username']);
- unset($_SESSION[MFAPPNAME.'_ip']);
- }
-
- public static function isLoggedIn() {
- $db=new FronkDB();
- if(!defined("MFAPPNAME")) define("MFAPPNAME","mvcfronk");
- if(!defined("MFUSERTABLE")) define("MFUSERTABLE","mfWorker");
-
- //session_name(MFAPPNAME."_session");
- //session_start();
- if($_SESSION[MFAPPNAME.'_username'] && $_SESSION[MFAPPNAME.'_ip']) {
- $username=$_SESSION[MFAPPNAME.'_username'];
- $ip=$_SERVER['REMOTE_ADDR'];
- $sid=session_id();
-
- if($_SESSION[MFAPPNAME.'_ip']==$ip) {
- // session seems legit, check if user exists and additionally check IP saved in database
- $res=$db->select(MFUSERTABLE,"*","username='$username' AND ip='$ip' AND sessionid='$sid'");
- if($db->num_rows($res)) {
- $user=$db->fetch_object($res);
- self::initSession($user);
- return true;
- }
- return false;
- }
- } else {
-
- return false;
- }
- }
-
- protected static function initSession($user) {
- $_SESSION[MFAPPNAME.'_username']=$user->username;
- $_SESSION[MFAPPNAME.'_ip']=$_SERVER['REMOTE_ADDR'];
- unset($_SESSION[MFAPPNAME."_loginfailed"]);
-
- $user=mfUser::singleton($user);
-
- return true;
- }
-
-
- protected function performLogin($username,$password) {
- if(!defined("MFAPPNAME")) define("MFAPPNAME","mvcfronk");
- if(!defined("MFUSERTABLE")) define("MFUSERTABLE","mfWorker");
-
- //session_set_cookie_params(0);
- //session_name(MFAPPNAME."_session");
- //session_start();
-
- if(!is_scalar($username) || !is_scalar($password)) {
- return false;
+
+ $this->logout();
+ }
+
+
+ protected function indexAction()
+ {
+ if ($_SESSION[MFAPPNAME . "_loginfailed"]) {
+ $this->layout()->set("LayoutError", "Login fehlgeschlagen.");
+ }
+ unset($_SESSION[MFAPPNAME . "_loginfailed"]);
+ }
+
+ protected function loginAction($request)
+ {
+ #Check if 2FA Code existiert
+ if (!$request['TwofactorCode'] || !is_int((int)$request['TwofactorCode'])) {
+ $code2fa = "unset";
+
+ } else {
+ $code2fa = $request['TwofactorCode'];
+ }
+
+ #Check ob Angemeldet bleiben aktiv ist
+ if (isset($request['Remember']) && $request['Remember'] === "true") {
+ $remember = true;
+ } else {
+ $remember = false;
+ }
+
+
+ #performLogin um 2FA Code und Remember erweitert
+ $performLogin = $this->performLogin($request['Username'], $request['Password'], $code2fa, $remember);
+
+ #performLogin um mehrere Stati erweitert
+ if ($performLogin === true) {
+
+ } elseif ($performLogin == "2fa") {
+ $this->layout()->setTemplate("mfLogin/Index");
+ $this->layout()->set("request", $request);
+ $this->layout()->set("requesttype", $performLogin);
+ return;
+ } elseif ($performLogin == "false2fa") {
+ $this->layout()->setTemplate("mfLogin/Index");
+ $this->layout()->setFlash("Verifizierungscode falsch oder abgelaufen", "error");
+ $this->layout()->set("request", $request);
+ $this->layout()->set("requesttype", $performLogin);
+ return;
+ } else {
+ $_SESSION[MFAPPNAME . "_loginfailed"] = true;
+ $this->layout()->setTemplate("mfLogin/Index");
+ $this->layout()->set("requesttype", "falselogin");
+ return;
+ }
+ //$get=$_SESSION['mfLoginGet'];
+ $url = $_SESSION['mfLoginUrl'];
+ //unset($_SESSION['mfLoginGet']);
+ unset($_SESSION['mfLoginUrl']);
+ /*
+ $mod=$get['action'];
+ if(preg_match('/([^_]+)_(.+)/',$action,$m)) {
+ $mod=$m[1];
+ $action=$m[2];
+ }
+ unset($get['action']);
+
+ self::redirect($mod,$action,$get);
+ */
+
+ #Header wird nur neu geladen wenn Login true ist
+ header("Location: $url");
+ }
+
+
+ /*
+ * Internal functions
+ */
+ public function logout()
+ {
+ if (!defined("MFAPPNAME")) define("MFAPPNAME", "mvcfronk");
+ if (!defined("MFUSERTABLE")) define("MFUSERTABLE", "mfWorker");
+ //session_name(MFAPPNAME."_session");
+ //session_start();
+ #Delete Token (DB und Cookie)
+ UserToken::deleteToken();
+ unset($_SESSION[MFAPPNAME . '_username']);
+ unset($_SESSION[MFAPPNAME . '_ip']);
+ }
+
+ public static function staticLogout()
+ {
+ if (!defined("MFAPPNAME")) define("MFAPPNAME", "mvcfronk");
+ if (!defined("MFUSERTABLE")) define("MFUSERTABLE", "mfWorker");
+ //session_name(MFAPPNAME."_session");
+ //session_start();
+ #Delete Token (DB und Cookie)
+ UserToken::deleteToken();
+ unset($_SESSION[MFAPPNAME . '_username']);
+ unset($_SESSION[MFAPPNAME . '_ip']);
+ }
+
+ public static function isLoggedIn()
+ {
+ $db = new FronkDB();
+ if (!defined("MFAPPNAME")) define("MFAPPNAME", "mvcfronk");
+ if (!defined("MFUSERTABLE")) define("MFUSERTABLE", "mfWorker");
+
+ //session_name(MFAPPNAME."_session");
+ //session_start();
+ #Check if Token Cookie und DB Eintrag existiert
+ UserToken::checkToken();
+
+
+ if ($_SESSION[MFAPPNAME . '_username'] && $_SESSION[MFAPPNAME . '_ip']) {
+ $username = $_SESSION[MFAPPNAME . '_username'];
+ $ip = $_SERVER['REMOTE_ADDR'];
+ $sid = session_id();
+
+ if ($_SESSION[MFAPPNAME . '_ip'] == $ip) {
+ // session seems legit, check if user exists and additionally check IP saved in database
+ $res = $db->select(MFUSERTABLE, "*", "username='$username' AND ip='$ip' AND sessionid='$sid'");
+ if ($db->num_rows($res)) {
+ $user = $db->fetch_object($res);
+ self::initSession($user);
+ return true;
+ }
+ return false;
+ }
+ } else {
+
+ return false;
+ }
+ }
+
+ protected static function initSession($user)
+ {
+ $_SESSION[MFAPPNAME . '_username'] = $user->username;
+ $_SESSION[MFAPPNAME . '_ip'] = $_SERVER['REMOTE_ADDR'];
+ unset($_SESSION[MFAPPNAME . "_loginfailed"]);
+
+ $user = mfUser::singleton($user);
+
+ return true;
+ }
+
+
+ protected function performLogin($username, $password, $code2fa, $remember)
+ {
+ if (!defined("MFAPPNAME")) define("MFAPPNAME", "mvcfronk");
+ if (!defined("MFUSERTABLE")) define("MFUSERTABLE", "mfWorker");
+
+ //session_set_cookie_params(0);
+ //session_name(MFAPPNAME."_session");
+ //session_start();
+
+ if (!is_scalar($username) || !is_scalar($password)) {
+ return false;
+ }
+
+ $username = $this->db()->escape($username);
+
+ $res = $this->db()->select(MFUSERTABLE, "*", "username='$username'");
+ if (!$this->db()->num_rows($res)) {
+ sleep(1);
+ return false;
+ }
+ $user = $this->db()->fetch_object($res);
+ $hash = $user->password;
+
+ #2FA Variablen
+ $twofactor = $user->twofactor;
+ $twofactorcode = $user->twofactorcode;
+ $twofactortimestamp = $user->twofactortimestamp;
+
+ #Zeitdifferenz des 2FA Codes
+ $timeSecond = time() - $twofactortimestamp;
+
+ $userid = $user->id;
+
+ $salt = substr($hash, 0, 16);
+ $passhash = $this->generatePasswordHash($password, $salt);
+ if ($passhash === $hash) {
+ if ($twofactor !== "0") {
+ if ($code2fa == "unset") {
+ #2FA Code wird generiert
+ $twoFactor = new UserTwofactor($userid);
+ $twoFactor->sendCode();
+ return "2fa"; #Return für das Einblenden der Verifizierungsmaske
+ } elseif ($twofactorcode != $code2fa || $timeSecond > 300) {
+ return "false2fa"; #Return für falscher/abgelaufener 2FA Code
+ } elseif ($remember) {
+ #Token generieren in DB und Cookie schreiben
+ UserToken::generateToken($userid);
+ }
+ }
+ //session_name(MFAPPNAME."_session");
+ //session_start();
+ $this->db()->update(MFUSERTABLE, array('ip' => $_SERVER['REMOTE_ADDR'], 'sessionid' => session_id()), "username='$username'");
+ $this->log->debug("$username logged in");
+ self::initSession($user);
+ return true;
+ }
+
+ sleep(1);
+
+ return false;
+ }
+
+ public static function generatePasswordHash($pass, $salt = NULL)
+ {
+ if (!$salt) {
+ $salt = substr(md5(uniqid(rand(), true)), 0, 16);
+ } else {
+ $salt = substr($salt, 0, 16);
+ }
+
+ return $salt . sha1($salt . $pass);
}
-
- $username = $this->db()->escape($username);
-
- $res = $this->db()->select(MFUSERTABLE,"*","username='$username'");
- if(!$this->db()->num_rows($res)) {
- sleep(1);
- return false;
- }
- $user = $this->db()->fetch_object($res);
- $hash = $user->password;
-
- $salt = substr($hash,0,16);
- $passhash = $this->generatePasswordHash($password,$salt);
-
- if($passhash === $hash) {
- //session_name(MFAPPNAME."_session");
- //session_start();
- $this->db()->update(MFUSERTABLE,array('ip' => $_SERVER['REMOTE_ADDR'],'sessionid' => session_id()),"username='$username'");
- $this->log->debug("$username logged in");
- self::initSession($user);
- return true;
- }
-
- sleep(1);
-
- return false;
- }
-
- public static function generatePasswordHash($pass,$salt=NULL) {
- if(!$salt) {
- $salt = substr(md5(uniqid(rand(), true)), 0, 16);
- } else {
- $salt = substr($salt,0,16);
- }
-
- return $salt.sha1($salt.$pass);
- }
}
diff --git a/public/assets/css/datatables-std.css b/public/assets/css/datatables-std.css
index a76801f22..fd8c02a2a 100644
--- a/public/assets/css/datatables-std.css
+++ b/public/assets/css/datatables-std.css
@@ -102,3 +102,6 @@
color: #f1556c;
font-size: 15px;
}
+table.dataTable.table-sm>thead>tr>th:not(.sorting_disabled) {
+ padding-right:.85rem ;
+}
diff --git a/public/assets/js/datatables-std.js b/public/assets/js/datatables-std.js
index e29cca7de..c883afb79 100644
--- a/public/assets/js/datatables-std.js
+++ b/public/assets/js/datatables-std.js
@@ -20,6 +20,10 @@ if (typeof columnfilter === "undefined") {
var columnfilter;
columnfilter = "";
}
+if (typeof columnoptions === "undefined") {
+ var columnoptions;
+ columnoptions = "";
+}
$('#filterrow th').each(function (i) {
let title = $('#datatable thead th').eq($(this).index()).text();
@@ -27,7 +31,7 @@ $('#filterrow th').each(function (i) {
if (hidesearch.includes($(this).index())) {
} else if (columnfilter.includes($(this).index())) {
- $(this).html('
');
+ $(this).html('
');
} else {
$(this).html('
');