Files
pathfinder/app/main/controller/api/user.php
2015-10-11 14:37:21 +02:00

686 lines
22 KiB
PHP

<?php
/**
* Created by PhpStorm.
* User: exodus4d
* Date: 29.03.15
* Time: 20:50
*/
namespace Controller\Api;
use Controller;
use controller\MailController;
use Model;
use Exception;
use DB;
class User extends Controller\Controller{
/**
* valid reasons for captcha images
* @var array
*/
private static $captchaReason = ['createAccount', 'deleteAccount'];
/**
* login function
* @param $f3
*/
public function logIn($f3){
$data = $data = $f3->get('POST');
$return = (object) [];
$user = null;
if($data['loginData']){
$loginData = $data['loginData'];
$user = $this->logUserIn( $loginData['userName'], $loginData['userPassword'] );
}
// set "vague" error
if(is_null($user)){
$return->error = [];
$loginError = (object) [];
$loginError->type = 'login';
$return->error[] = $loginError;
}else{
// update/check api data
$user->updateApiData();
// route user to map app
$return->reroute = self::getEnvironmentData('URL') . $f3->alias('map');
}
echo json_encode($return);
}
/**
* core function for user login
* @param $userName
* @param $password
* @return Model\UserModel|null
*/
private function logUserIn($userName, $password){
// try to verify user
$user = $this->_verifyUser($userName, $password);
if( !is_null($user)){
// user is verified -> ready for login
// set Session login
$dateTime = new \DateTime();
$this->f3->set('SESSION.user', [
'time' => $dateTime->getTimestamp(),
'name' => $user->name,
'id' => $user->id
]);
// save user login information
$user->touch('lastLogin');
$user->save();
// save log
$logText = "id: %s, name: %s, ip: %s";
self::getLogger( $this->f3->get('PATHFINDER.LOGFILES.LOGIN') )->write(
sprintf($logText, $user->id, $user->name, $this->f3->get('IP'))
);
}
return $user;
}
/**
* get captcha image and store key to session
* @param $f3
*/
public function getCaptcha($f3){
$data = $f3->get('POST');
$return = (object) [];
$return->error = [];
// check if reason for captcha generation is valid
if(
isset($data['reason']) &&
in_array( $data['reason'], self::$captchaReason)
){
$reason = $data['reason'];
$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);
}
/**
* delete the character log entry for the current active (main) character
* @param $f3
*/
public function deleteLog($f3){
$user = $this->_getUser();
if($user){
$activeUserCharacter = $user->getActiveUserCharacter();
if($activeUserCharacter){
$character = $activeUserCharacter->getCharacter();
if($characterLog = $character->getLog()){
$characterLog->erase();
}
}
}
}
/**
* log the current user out + clear character system log data
* @param $f3
*/
public function logOut($f3){
$this->deleteLog($f3);
return parent::logOut($f3);
}
/**
* save/update "map sharing" configurations for all map types
* the user has access to
* @param $f3
*/
public function saveSharingConfig($f3){
$data = $f3->get('POST');
$return = (object) [];
$privateSharing = 0;
$corporationSharing = 0;
$allianceSharing = 0;
$user = $this->_getUser();
if($user){
// form values
if(isset($data['formData'])){
$formData = $data['formData'];
if(isset($formData['privateSharing'])){
$privateSharing = 1;
}
if(isset($formData['corporationSharing'])){
$corporationSharing = 1;
}
if(isset($formData['allianceSharing'])){
$allianceSharing = 1;
}
}
$user->sharing = $privateSharing;
$user->save();
// update corp/ally ---------------------------------------------------------------
$activeUserCharacter = $user->getActiveUserCharacter();
if(is_object($activeUserCharacter)){
$corporation = $activeUserCharacter->getCharacter()->getCorporation();
$alliance = $activeUserCharacter->getCharacter()->getAlliance();
if(is_object($corporation)){
$corporation->sharing = $corporationSharing;
$corporation->save();
}
if(is_object($alliance)){
$alliance->sharing = $allianceSharing;
$alliance->save();
}
}
$return->userData = $user->getData();
}
echo json_encode($return);
}
/**
* search for a registration key model
* e.g. for new user registration with "invite" feature enabled
* @param $email
* @param $registrationKey
* @return bool|Model\RegistrationKeyModel
* @throws Exception
*/
protected function getRegistrationKey($email, $registrationKey){
$registrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
$registrationKeyModel->load([
'registrationKey = :registrationKey AND
email = :email AND
used = 0 AND
active = 1',
':registrationKey' => $registrationKey,
':email' => $email
]);
if( $registrationKeyModel->dry() ){
return false;
}else{
return $registrationKeyModel;
}
}
/**
* check if there is already an active Key for a mail
* @param $email
* @param bool|false $used
* @return bool|null
* @throws Exception
*/
protected function findRegistrationKey($email, $used = false){
$queryPart = 'email = :email AND active = 1';
if(is_int($used)){
$queryPart .= ' AND used = ' . $used;
}
$registrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
$registrationKeyModels = $registrationKeyModel->find([
$queryPart,
':email' => $email
]);
if( is_object($registrationKeyModels) ){
return $registrationKeyModels;
}else{
return false;
}
}
/**
* save/update user data
* @param $f3
*/
public function saveConfig($f3){
$data = $f3->get('POST');
$return = (object) [];
$return->error = [];
$captcha = $f3->get('SESSION.createAccount');
// reset captcha -> forces user to enter new one
$f3->clear('SESSION.createAccount');
$newUserData = null;
// check for new user
$loginAfterSave = false;
// send registration mail
$sendRegistrationMail = false;
// valid registration key Model is required for new registration
// if "invite" feature is enabled
$registrationKeyModel = false;
if( isset($data['settingsData']) ){
$settingsData = $data['settingsData'];
try{
$user = $this->_getUser();
// captcha is send -> check captcha
if(
isset($settingsData['captcha']) &&
!empty($settingsData['captcha'])
){
if($settingsData['captcha'] === $captcha){
// change/set sensitive user data requires captcha!
if($user === false){
// check if registration key invite function is enabled
if($f3->get('PATHFINDER.REGISTRATION.INVITE') === 1 ){
$registrationKeyModel = $this->getRegistrationKey( $settingsData['email'], $settingsData['registrationKey'] );
if($registrationKeyModel === false){
throw new Exception\RegistrationException('Registration key invalid', 'registrationKey');
}
}
// new user registration
$user = $mapType = Model\BasicModel::getNew('UserModel');
$loginAfterSave = true;
$sendRegistrationMail = true;
// set username
if(
isset($settingsData['name']) &&
!empty($settingsData['name'])
){
$user->name = $settingsData['name'];
}
}
// change/set email
if(
isset($settingsData['email']) &&
isset($settingsData['email_confirm']) &&
!empty($settingsData['email']) &&
!empty($settingsData['email_confirm']) &&
$settingsData['email'] == $settingsData['email_confirm']
){
$user->email = $settingsData['email'];
}
// change/set password
if(
isset($settingsData['password']) &&
isset($settingsData['password_confirm']) &&
!empty($settingsData['password']) &&
!empty($settingsData['password_confirm']) &&
$settingsData['password'] == $settingsData['password_confirm']
){
$user->password = $settingsData['password'];
// pw changed -> send mail
$sendRegistrationMail = true;
}
}else{
// captcha was send but not valid -> return error
$captchaError = (object) [];
$captchaError->type = 'error';
$captchaError->message = 'Captcha does not match';
$return->error[] = $captchaError;
}
}
// saving additional user info requires valid user object (no captcha required)
if($user){
// save API data
if(
isset($settingsData['keyId']) &&
isset($settingsData['vCode']) &&
is_array($settingsData['keyId']) &&
is_array($settingsData['vCode'])
){
// get all existing API models for this user
$apiModels = $user->getAPIs();
foreach($settingsData['keyId'] as $i => $keyId){
$api = null;
// search for existing API model
foreach($apiModels as $key => $apiModel){
if($apiModel->keyId == $keyId){
$api = $apiModel;
// make sure model is up2data -> cast()
$api->cast();
unset($apiModels[$key]);
break;
}
}
if(is_null($api)){
// new API Key
$api = Model\BasicModel::getNew('UserApiModel');
$api->userId = $user;
}
$api->keyId = $keyId;
$api->vCode = $settingsData['vCode'][$i];
$api->save();
$characterCount = $api->updateCharacters();
if($characterCount == 0){
// no characters found -> return warning
$characterError = (object) [];
$characterError->type = 'warning';
$characterError->message = 'API verification failed. No Characters found for KeyId ' . $api->keyId;
$return->error[] = $characterError;
}
}
// delete API models that no longer exists
foreach($apiModels as $apiModel){
$apiModel->delete();
}
}
// set main character
if( isset($settingsData['mainCharacterId']) ){
$user->setMainCharacterId((int)$settingsData['mainCharacterId']);
}
// check if the user already has a main character
// if not -> save the next best character as main
$mainUserCharacter = $user->getMainUserCharacter();
// set main character if no main character exists
if(is_null($mainUserCharacter)){
$user->setMainCharacterId();
}
// save/update user model
// this will fail if model validation fails!
$user->save();
if(is_object($registrationKeyModel)){
$registrationKeyModel->used = 1;
$registrationKeyModel->save();
}
// log user in (in case he is new
if($loginAfterSave){
$this->logUserIn( $user->name, $settingsData['password'] );
// return reroute path
$return->reroute = self::getEnvironmentData('URL') . $this->f3->alias('map');
}
// get fresh updated user object
$user = $this->_getUser(0);
$newUserData = $user->getData();
// send registration mail with account information
if($sendRegistrationMail){
$this->sendRegistration($user, $settingsData['password']);
}
}
}catch(Exception\ValidationException $e){
$validationError = (object) [];
$validationError->type = 'error';
$validationError->field = $e->getField();
$validationError->message = $e->getMessage();
$return->error[] = $validationError;
}catch(Exception\RegistrationException $e){
$registrationError = (object) [];
$registrationError->type = 'error';
$registrationError->field = $e->getField();
$registrationError->message = $e->getMessage();
$return->error[] = $registrationError;
}
// return new/updated user data
$return->userData = $newUserData;
}
echo json_encode($return);
}
/**
* send registration mail to user
* @param $user
* @param $password
* @return mixed
*/
protected function sendRegistration($user, $password){
$msg = 'Username: ' . $user->name . '<br>';
$msg .= 'Password: ' . $password . '<br>';
$mailController = new MailController();
$status = $mailController->sendRegistration($user->email, $msg);
return $status;
}
/**
* send mail with registration key
* -> check INVITE in pathfinder.ini
* @param $f3
* @throws Exception
*/
public function sendInvite($f3){
$data = $f3->get('POST.settingsData');
$return = (object) [];
// check invite limit
// get handed out key count
$tempRegistrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
$tempRegistrationKeyModels = $tempRegistrationKeyModel->find([ '
email != "" AND
active = 1'
]);
$totalKeys = 0;
if(is_object($tempRegistrationKeyModels)){
$totalKeys = $tempRegistrationKeyModels->count();
}
if(
$f3->get('PATHFINDER.REGISTRATION.INVITE') == 1 &&
$totalKeys < $f3->get('PATHFINDER.REGISTRATION.INVITE_LIMIT')
){
// key limit not reached
if(
isset($data['email']) &&
!empty($data['email'])
){
$email = trim($data['email']);
// check if mail is valid
if( \Audit::instance()->email($email) ){
// new key for this mail is allowed
$registrationKeyModel = $this->findRegistrationKey($email, 0);
if($registrationKeyModel === false){
// check for total number of invites (active and inactive) -> prevent spamming
$allRegistrationKeysByMail = $this->findRegistrationKey($email);
if(
$allRegistrationKeysByMail == false ||
$allRegistrationKeysByMail->count() < 3
){
// get a fresh key
$registrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
$registrationKeyModel->load(['
used = 0 AND
active = 1 AND
email = "" ',
':email' => $email
], ['limit' => 1]);
}else{
$validationError = (object) [];
$validationError->type = 'warning';
$validationError->message = 'The number of keys is limited by Email. You can not get more keys';
$return->error[] = $validationError;
}
}else{
$registrationKeyModel = $registrationKeyModel[0];
}
// send "old" key again or send a new key
if( is_object($registrationKeyModel) ){
$msg = 'Your personal Registration Key: ' . $registrationKeyModel->registrationKey;
$mailController = new MailController();
$status = $mailController->sendInviteKey($email, $msg);
if( $status ){
$registrationKeyModel->email = $email;
$registrationKeyModel->ip = $this->f3->get('IP');
$registrationKeyModel->save();
}
}
}else{
$validationError = (object) [];
$validationError->type = 'error';
$validationError->field = 'email';
$validationError->message = 'Email is not valid';
$return->error[] = $validationError;
}
}
}else{
$validationError = (object) [];
$validationError->type = 'warning';
$validationError->message = 'The pool of beta keys has been exhausted, please try again in a few days/weeks';
$return->error[] = $validationError;
}
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 . ',<br><br>';
$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);
}
}