diff --git a/app/main/controller/api/user.php b/app/main/controller/api/user.php index fd3c4012..6b940bfa 100644 --- a/app/main/controller/api/user.php +++ b/app/main/controller/api/user.php @@ -14,6 +14,13 @@ use Exception; class User extends Controller\Controller{ + /** + * valid reasons for captcha images + * @var array + */ + private static $captchaReason = ['createAccount', 'deleteAccount']; + + /** * login function * @param $f3 @@ -87,20 +94,39 @@ class User extends Controller\Controller{ * @param $f3 */ public function getCaptcha($f3){ + $data = $f3->get('POST'); - $img = new \Image(); + $return = (object) []; + $return->error = []; - $imgDump = $img->captcha( - 'fonts/oxygen-bold-webfont.ttf', - 14, - 6, - 'SESSION.captcha_code', - '', - '0x66C84F', - '0x313335' - )->dump(); + // check if reason for captcha generation is valid + if( + isset($data['reason']) && + in_array( $data['reason'], self::$captchaReason) + ){ + $reason = $data['reason']; - echo $f3->base64( $imgDump, 'image/png'); + $img = new \Image(); + + $imgDump = $img->captcha( + 'fonts/oxygen-bold-webfont.ttf', + 14, + 6, + 'SESSION.' . $reason, + '', + '0x66C84F', + '0x313335' + )->dump(); + + $return->img = $f3->base64( $imgDump, 'image/png'); + }else{ + $captchaError = (object) []; + $captchaError->type = 'error'; + $captchaError->message = 'Could not create captcha image'; + $return->error[] = $captchaError; + } + + echo json_encode($return); } /** @@ -270,10 +296,10 @@ class User extends Controller\Controller{ $return = (object) []; $return->error = []; - $captcha = $f3->get('SESSION.captcha_code'); + $captcha = $f3->get('SESSION.createAccount'); // reset captcha -> forces user to enter new one - $f3->clear('SESSION.captcha_code'); + $f3->clear('SESSION.createAccount'); $newUserData = null; @@ -598,4 +624,71 @@ class User extends Controller\Controller{ echo json_encode($return); } + + /** + * delete current user account from DB + * @param $f3 + */ + public function deleteAccount($f3){ + $data = $f3->get('POST.formData'); + $return = (object) []; + + $captcha = $f3->get('SESSION.deleteAccount'); + + // reset captcha -> forces user to enter new one + $f3->clear('SESSION.deleteAccount'); + + if( + isset($data['captcha']) && + !empty($data['captcha']) && + $data['captcha'] === $captcha + ){ + $user = $this->_getUser(0); + + $validUser = $this->_verifyUser( $user->name, $data['password']); + + if( + is_object($validUser) && + is_object($user) && + $user->id === $validUser->id + ){ + // send delete account mail + $msg = 'Hello ' . $user->name . ',

'; + $msg .= 'your account data has been successfully deleted.'; + + $mailController = new MailController(); + $status = $mailController->sendDeleteAccount($user->email, $msg); + + if($status){ + // save log + $logText = "id: %s, name: %s, ip: %s"; + self::getLogger( $this->f3->get('PATHFINDER.LOGFILES.DELETE_ACCOUNT') )->write( + sprintf($logText, $user->id, $user->name, $f3->get('IP')) + ); + + // remove user + $user->erase(); + + $this->logOut($f3); + die(); + } + }else{ + // password does not match current user pw + $passwordError = (object) []; + $passwordError->type = 'error'; + $passwordError->message = 'Invalid password'; + $return->error[] = $passwordError; + } + }else{ + // captcha not valid -> return error + $captchaError = (object) []; + $captchaError->type = 'error'; + $captchaError->message = 'Captcha does not match'; + $return->error[] = $captchaError; + } + + echo json_encode($return); + } + + } \ No newline at end of file diff --git a/app/main/controller/controller.php b/app/main/controller/controller.php index 28d8fe8a..e9df401c 100644 --- a/app/main/controller/controller.php +++ b/app/main/controller/controller.php @@ -183,7 +183,8 @@ class Controller { public function logOut($f3){ // destroy session - $f3->clear('SESSION'); + $f3->clear('SESSION.user'); + $f3->sync('SESSION'); if( !$f3->get('AJAX') ){ // redirect to landing page diff --git a/app/main/controller/mailcontroller.php b/app/main/controller/mailcontroller.php index 69aad51c..1f401155 100644 --- a/app/main/controller/mailcontroller.php +++ b/app/main/controller/mailcontroller.php @@ -49,7 +49,6 @@ class MailController extends \SMTP{ * @return bool */ public function sendInviteKey($to, $msg){ - $this->set('To', '<' . $to . '>'); $this->set('From', 'Pathfinder <' . Controller::getEnvironmentData('SMTP_FROM') . '>'); $this->set('Subject', 'Registration Key'); @@ -57,4 +56,19 @@ class MailController extends \SMTP{ return $status; } + + /** + * send mail to removed user account + * @param $to + * @param $msg + * @return bool + */ + public function sendDeleteAccount($to, $msg){ + $this->set('To', '<' . $to . '>'); + $this->set('From', 'Pathfinder <' . Controller::getEnvironmentData('SMTP_FROM') . '>'); + $this->set('Subject', 'Account deleted'); + $status = $this->send($msg); + + return $status; + } } \ No newline at end of file diff --git a/build_js/app/landingpage.js b/build_js/app/landingpage.js index d47beb6c..2a3981c1 100644 --- a/build_js/app/landingpage.js +++ b/build_js/app/landingpage.js @@ -1,15 +1,15 @@ -!function(t,e){"object"==typeof module&&"object"==typeof module.exports?module.exports=t.document?e(t,!0):function(t){if(!t.document)throw new Error("jQuery requires a window with a document");return e(t)}:e(t)}("undefined"!=typeof window?window:this,function(t,e){function i(t){var e="length"in t&&t.length,i=at.type(t);return"function"===i||at.isWindow(t)?!1:1===t.nodeType&&e?!0:"array"===i||0===e||"number"==typeof e&&e>0&&e-1 in t}function n(t,e,i){if(at.isFunction(e))return at.grep(t,function(t,n){return!!e.call(t,n,t)!==i});if(e.nodeType)return at.grep(t,function(t){return t===e!==i});if("string"==typeof e){if(ht.test(e))return at.filter(e,t,i);e=at.filter(e,t)}return at.grep(t,function(t){return at.inArray(t,e)>=0!==i})}function a(t,e){do t=t[e];while(t&&1!==t.nodeType);return t}function o(t){var e=wt[t]={};return at.each(t.match(bt)||[],function(t,i){e[i]=!0}),e}function s(){ft.addEventListener?(ft.removeEventListener("DOMContentLoaded",r,!1),t.removeEventListener("load",r,!1)):(ft.detachEvent("onreadystatechange",r),t.detachEvent("onload",r))}function r(){(ft.addEventListener||"load"===event.type||"complete"===ft.readyState)&&(s(),at.ready())}function l(t,e,i){if(void 0===i&&1===t.nodeType){var n="data-"+e.replace(_t,"-$1").toLowerCase();if(i=t.getAttribute(n),"string"==typeof i){try{i="true"===i?!0:"false"===i?!1:"null"===i?null:+i+""===i?+i:Tt.test(i)?at.parseJSON(i):i}catch(a){}at.data(t,e,i)}else i=void 0}return i}function c(t){var e;for(e in t)if(("data"!==e||!at.isEmptyObject(t[e]))&&"toJSON"!==e)return!1;return!0}function u(t,e,i,n){if(at.acceptData(t)){var a,o,s=at.expando,r=t.nodeType,l=r?at.cache:t,c=r?t[s]:t[s]&&s;if(c&&l[c]&&(n||l[c].data)||void 0!==i||"string"!=typeof e)return c||(c=r?t[s]=X.pop()||at.guid++:s),l[c]||(l[c]=r?{}:{toJSON:at.noop}),("object"==typeof e||"function"==typeof e)&&(n?l[c]=at.extend(l[c],e):l[c].data=at.extend(l[c].data,e)),o=l[c],n||(o.data||(o.data={}),o=o.data),void 0!==i&&(o[at.camelCase(e)]=i),"string"==typeof e?(a=o[e],null==a&&(a=o[at.camelCase(e)])):a=o,a}}function d(t,e,i){if(at.acceptData(t)){var n,a,o=t.nodeType,s=o?at.cache:t,r=o?t[at.expando]:at.expando;if(s[r]){if(e&&(n=i?s[r]:s[r].data)){at.isArray(e)?e=e.concat(at.map(e,at.camelCase)):e in n?e=[e]:(e=at.camelCase(e),e=e in n?[e]:e.split(" ")),a=e.length;for(;a--;)delete n[e[a]];if(i?!c(n):!at.isEmptyObject(n))return}(i||(delete s[r].data,c(s[r])))&&(o?at.cleanData([t],!0):it.deleteExpando||s!=s.window?delete s[r]:s[r]=null)}}}function h(){return!0}function p(){return!1}function f(){try{return ft.activeElement}catch(t){}}function m(t){var e=Rt.split("|"),i=t.createDocumentFragment();if(i.createElement)for(;e.length;)i.createElement(e.pop());return i}function g(t,e){var i,n,a=0,o=typeof t.getElementsByTagName!==St?t.getElementsByTagName(e||"*"):typeof t.querySelectorAll!==St?t.querySelectorAll(e||"*"):void 0;if(!o)for(o=[],i=t.childNodes||t;null!=(n=i[a]);a++)!e||at.nodeName(n,e)?o.push(n):at.merge(o,g(n,e));return void 0===e||e&&at.nodeName(t,e)?at.merge([t],o):o}function v(t){Pt.test(t.type)&&(t.defaultChecked=t.checked)}function y(t,e){return at.nodeName(t,"table")&&at.nodeName(11!==e.nodeType?e:e.firstChild,"tr")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}function b(t){return t.type=(null!==at.find.attr(t,"type"))+"/"+t.type,t}function w(t){var e=Yt.exec(t.type);return e?t.type=e[1]:t.removeAttribute("type"),t}function C(t,e){for(var i,n=0;null!=(i=t[n]);n++)at._data(i,"globalEval",!e||at._data(e[n],"globalEval"))}function x(t,e){if(1===e.nodeType&&at.hasData(t)){var i,n,a,o=at._data(t),s=at._data(e,o),r=o.events;if(r){delete s.handle,s.events={};for(i in r)for(n=0,a=r[i].length;a>n;n++)at.event.add(e,i,r[i][n])}s.data&&(s.data=at.extend({},s.data))}}function S(t,e){var i,n,a;if(1===e.nodeType){if(i=e.nodeName.toLowerCase(),!it.noCloneEvent&&e[at.expando]){a=at._data(e);for(n in a.events)at.removeEvent(e,n,a.handle);e.removeAttribute(at.expando)}"script"===i&&e.text!==t.text?(b(e).text=t.text,w(e)):"object"===i?(e.parentNode&&(e.outerHTML=t.outerHTML),it.html5Clone&&t.innerHTML&&!at.trim(e.innerHTML)&&(e.innerHTML=t.innerHTML)):"input"===i&&Pt.test(t.type)?(e.defaultChecked=e.checked=t.checked,e.value!==t.value&&(e.value=t.value)):"option"===i?e.defaultSelected=e.selected=t.defaultSelected:("input"===i||"textarea"===i)&&(e.defaultValue=t.defaultValue)}}function T(e,i){var n,a=at(i.createElement(e)).appendTo(i.body),o=t.getDefaultComputedStyle&&(n=t.getDefaultComputedStyle(a[0]))?n.display:at.css(a[0],"display");return a.detach(),o}function _(t){var e=ft,i=Jt[t];return i||(i=T(t,e),"none"!==i&&i||(Zt=(Zt||at("