diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 68a748ef92..58b3119474 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -12,6 +12,7 @@ // use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Validation\ValidationException; +use Illuminate\Session\TokenMismatchException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Handler extends ExceptionHandler @@ -171,6 +172,8 @@ public function common($request, $e) // } else { // return parent::render($request, $e); // } + case $e instanceof TokenMismatchException: + return redirect()->back()->with('fails', \Lang::get('lang.session-expired')); default: return $this->render500($request, $e); } diff --git a/app/FaveoStorage/Controllers/StorageController.php b/app/FaveoStorage/Controllers/StorageController.php index 7c61783776..7cd9d064eb 100644 --- a/app/FaveoStorage/Controllers/StorageController.php +++ b/app/FaveoStorage/Controllers/StorageController.php @@ -9,8 +9,8 @@ use Config; use Storage; -class StorageController extends Controller -{ +class StorageController extends Controller { + protected $default; protected $driver; protected $root; @@ -25,8 +25,7 @@ class StorageController extends Controller protected $rackspace_endpoint; protected $rackspace_url_type; - public function __construct() - { + public function __construct() { $this->default = $this->defaults(); $this->driver = $this->driver(); $this->root = $this->root(); @@ -41,8 +40,7 @@ public function __construct() $this->rackspace_username = $this->rackspaceUsername(); } - protected function settings($option) - { + protected function settings($option) { $settings = new CommonSettings(); $setting = $settings->getOptionValue('storage', $option); $value = ''; @@ -53,8 +51,7 @@ protected function settings($option) return $value; } - public function defaults() - { + public function defaults() { $default = 'local'; if ($this->settings('default')) { $default = $this->settings('default'); @@ -63,13 +60,11 @@ public function defaults() return $default; } - public function driver() - { + public function driver() { return $this->settings('default'); } - public function root() - { + public function root() { $root = storage_path('app'); if ($this->settings('root')) { $root = $this->settings('root'); @@ -78,58 +73,47 @@ public function root() return $root; } - public function s3Key() - { + public function s3Key() { return $this->settings('s3_key'); } - public function s3Region() - { + public function s3Region() { return $this->settings('s3_region'); } - public function s3Secret() - { + public function s3Secret() { return $this->settings('s3_secret'); } - public function s3Bucket() - { + public function s3Bucket() { return $this->settings('s3_bucket'); } - public function rackspaceKey() - { + public function rackspaceKey() { return $this->settings('root'); } - public function rackspaceRegion() - { + public function rackspaceRegion() { return $this->settings('rackspace_region'); } - public function rackspaceUsername() - { + public function rackspaceUsername() { return $this->settings('rackspace_username'); } - public function rackspaceContainer() - { + public function rackspaceContainer() { return $this->settings('rackspace_container'); } - public function rackspaceEndpoint() - { + public function rackspaceEndpoint() { return $this->settings('rackspace_endpoint'); } - public function rackspaceUrlType() - { + public function rackspaceUrlType() { return $this->settings('rackspace_url_type'); } - protected function setFileSystem() - { + protected function setFileSystem() { $config = $this->config(); //dd($config); foreach ($config as $key => $con) { @@ -144,43 +128,40 @@ protected function setFileSystem() return Config::get('filesystem'); } - protected function config() - { + protected function config() { return [ 'default' => $this->default, - 'cloud' => 's3', - 'disks' => $this->disks(), + 'cloud' => 's3', + 'disks' => $this->disks(), ]; } - protected function disks() - { + protected function disks() { return [ 'local' => [ 'driver' => 'local', - 'root' => $this->root.'/attachments', + 'root' => $this->root . '/attachments', ], 's3' => [ 'driver' => 's3', - 'key' => $this->s3_key, + 'key' => $this->s3_key, 'secret' => $this->s3_secret, 'region' => $this->s3_region, 'bucket' => $this->s3_bucket, ], 'rackspace' => [ - 'driver' => 'rackspace', - 'username' => $this->rackspace_username, - 'key' => $this->rackspace_key, + 'driver' => 'rackspace', + 'username' => $this->rackspace_username, + 'key' => $this->rackspace_key, 'container' => $this->rackspace_container, - 'endpoint' => $this->rackspace_endpoint, - 'region' => $this->rackspace_region, - 'url_type' => $this->rackspace_url_type, + 'endpoint' => $this->rackspace_endpoint, + 'region' => $this->rackspace_region, + 'url_type' => $this->rackspace_url_type, ], ]; } - public function upload($data, $filename, $type, $size, $disposition, $thread_id) - { + public function upload($data, $filename, $type, $size, $disposition, $thread_id) { $upload = new Ticket_attachments(); $upload->thread_id = $thread_id; $upload->name = $filename; @@ -188,10 +169,14 @@ public function upload($data, $filename, $type, $size, $disposition, $thread_id) $upload->size = $size; $upload->poster = $disposition; $upload->driver = $this->default; - $upload->path = $this->root; + $upload->path = $this->root. DIRECTORY_SEPARATOR.'attachments'; if ($this->default !== 'database') { $this->setFileSystem(); Storage::disk($this->default)->put($filename, $data); + $storagePath = Storage::disk($this->default)->getDriver()->getAdapter()->getPathPrefix() . $filename; + if (mime(\File::mimeType($storagePath)) != 'image' || mime(\File::extension($storagePath)) != 'image') { + chmod($storagePath, 1204); + } } else { $upload->file = $data; } @@ -200,51 +185,67 @@ public function upload($data, $filename, $type, $size, $disposition, $thread_id) } } - public function saveAttachments($thread_id, $attachments = []) - { - if (is_array($attachments) && count($attachments) > 0) { - foreach ($attachments as $attachment) { - $structure = $attachment->getStructure(); - $disposition = 'ATTACHMENT'; - if (isset($structure->disposition)) { - $disposition = $structure->disposition; + public function saveAttachments($thread_id, $attachments = []) { + $disposition = 'ATTACHMENT'; + $thread = ''; + foreach ($attachments as $attachment) { + if (is_object($attachment)) { + if (method_exists($attachment, 'getStructure')) { + + $structure = $attachment->getStructure(); + if (isset($structure->disposition)) { + $disposition = $structure->disposition; + } + $filename = rand(1111, 9999) . "_" . $attachment->getFileName(); + $type = $attachment->getMimeType(); + $size = $attachment->getSize(); + $data = $attachment->getData(); + } else { + $filename = rand(1111, 9999) . "_" . $attachment->getClientOriginalName(); + $type = $attachment->getMimeType(); + $size = $attachment->getSize(); + $data = file_get_contents($attachment->getRealPath()); } - $filename = str_random(16).'-'.$attachment->getFileName(); - $type = $attachment->getMimeType(); - $size = $attachment->getSize(); - $data = $attachment->getData(); $this->upload($data, $filename, $type, $size, $disposition, $thread_id); - $this->updateBody($attachment, $thread_id, $filename); + $thread = $this->updateBody($attachment, $thread_id, $filename); } } + return $thread; } - public function updateBody($attachment, $thread_id, $filename) - { - $structure = $attachment->getStructure(); + public function updateBody($attachment, $thread_id, $filename) { + $threads = new Ticket_Thread(); + $thread = $threads->find($thread_id); $disposition = 'ATTACHMENT'; - if (isset($structure->disposition)) { - $disposition = $structure->disposition; + if (is_object($attachment)) { + if (method_exists($attachment, 'getStructure')) { + $structure = $attachment->getStructure(); + if (isset($structure->disposition)) { + $disposition = $structure->disposition; + } + } } + if ($disposition == 'INLINE' || $disposition == 'inline') { $id = str_replace('>', '', str_replace('<', '', $structure->id)); - $threads = new Ticket_Thread(); - $thread = $threads->find($thread_id); $body = $thread->body; - $body = str_replace('cid:'.$id, $filename, $body); + // dd($id,$filename,$body); + $body = str_replace('cid:' . $id, $filename, $body); + // dd($body); $thread->body = $body; $thread->save(); } + return $thread; } - public function getFile($drive, $name) - { - //dd($drive,$name); - if ($drive != 'database') { - $this->setFileSystem(); - if (Storage::disk($this->default)->exists($name)) { - return Storage::disk($this->default)->get($name); + public function getFile($drive, $name, $root) { + if ($drive != "database") { + $root = $root . DIRECTORY_SEPARATOR . $name; + if (\File::exists($root)) { + chmod($root, 0755); + return \File::get($root); } } } + } diff --git a/app/Http/Controllers/Agent/helpdesk/UserController.php b/app/Http/Controllers/Agent/helpdesk/UserController.php index ccc0a68967..b6fb024c66 100644 --- a/app/Http/Controllers/Agent/helpdesk/UserController.php +++ b/app/Http/Controllers/Agent/helpdesk/UserController.php @@ -764,10 +764,12 @@ public function postProfileedit(ProfileRequest $request) if (Input::file('profile_pic')) { // fetching picture name $name = Input::file('profile_pic')->getClientOriginalName(); + // dd($name); + // dd(str_replace(" ", "_", $name)); // fetching upload destination path $destinationPath = 'uploads/profilepic'; // adding a random value to profile picture filename - $fileName = rand(0000, 9999).'.'.$name; + $fileName = rand(0000, 9999).'.'.str_replace(" ", "_", $name); // moving the picture to a destination folder Input::file('profile_pic')->move($destinationPath, $fileName); // saving filename to database diff --git a/app/Http/Controllers/Client/helpdesk/FormController.php b/app/Http/Controllers/Client/helpdesk/FormController.php index 2f95ee9862..15afebc94c 100644 --- a/app/Http/Controllers/Client/helpdesk/FormController.php +++ b/app/Http/Controllers/Client/helpdesk/FormController.php @@ -229,16 +229,18 @@ public function postedForm(User $user, ClientRequest $request, Ticket $ticket_se $ticketId = Tickets::where('ticket_number', '=', $result[0])->first(); $thread = Ticket_Thread::where('ticket_id', '=', $ticketId->id)->first(); if ($attachments != null) { - foreach ($attachments as $attachment) { - if ($attachment != null) { - $name = $attachment->getClientOriginalName(); - $type = $attachment->getClientOriginalExtension(); - $size = $attachment->getSize(); - $data = file_get_contents($attachment->getRealPath()); - $attachPath = $attachment->getRealPath(); - $ta->create(['thread_id' => $thread->id, 'name' => $name, 'size' => $size, 'type' => $type, 'file' => $data, 'poster' => 'ATTACHMENT']); - } - } + $storage = new \App\FaveoStorage\Controllers\StorageController(); + $storage->saveAttachments($thread->id, $attachments); +// foreach ($attachments as $attachment) { +// if ($attachment != null) { +// $name = $attachment->getClientOriginalName(); +// $type = $attachment->getClientOriginalExtension(); +// $size = $attachment->getSize(); +// $data = file_get_contents($attachment->getRealPath()); +// $attachPath = $attachment->getRealPath(); +// $ta->create(['thread_id' => $thread->id, 'name' => $name, 'size' => $size, 'type' => $type, 'file' => $data, 'poster' => 'ATTACHMENT']); +// } +// } } // dd($result); return Redirect::back()->with('success', Lang::get('lang.Ticket-has-been-created-successfully-your-ticket-number-is').' '.$result[0].'. '.Lang::get('lang.Please-save-this-for-future-reference')); @@ -246,6 +248,7 @@ public function postedForm(User $user, ClientRequest $request, Ticket $ticket_se return Redirect::back()->withInput($request->except('password'))->with('fails', Lang::get('lang.failed-to-create-user-tcket-as-mobile-has-been-taken')); } } catch (\Exception $ex) { + dd($ex); return redirect()->back()->with('fails', $ex->getMessage()); } // dd($result); diff --git a/app/Http/Controllers/Client/helpdesk/GuestController.php b/app/Http/Controllers/Client/helpdesk/GuestController.php index 0b1281d8d9..d1a0afd740 100644 --- a/app/Http/Controllers/Client/helpdesk/GuestController.php +++ b/app/Http/Controllers/Client/helpdesk/GuestController.php @@ -101,7 +101,7 @@ public function postProfile(ProfileRequest $request) // fetching upload destination path $destinationPath = 'uploads/profilepic'; // adding a random value to profile picture filename - $fileName = rand(0000, 9999).'.'.$name; + $fileName = rand(0000, 9999).'.'.str_replace(" ", "_", $name); // moving the picture to a destination folder Input::file('profile_pic')->move($destinationPath, $fileName); // saving filename to database diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 53b5e19925..e4bcc1e655 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -4,9 +4,21 @@ use Closure; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier; +use Lang; class VerifyCsrfToken extends BaseVerifier { + + /** + * The URIs that should be excluded from CSRF verification. + * + * @var array + */ + protected $except = [ + 'CheckSerial', + 'api/v1/*' + ]; + /** * Handle an incoming request. * diff --git a/app/Model/helpdesk/Ticket/Ticket_attachments.php b/app/Model/helpdesk/Ticket/Ticket_attachments.php index 1172eac023..163e864c7a 100644 --- a/app/Model/helpdesk/Ticket/Ticket_attachments.php +++ b/app/Model/helpdesk/Ticket/Ticket_attachments.php @@ -25,13 +25,20 @@ public function getFileAttribute($value) $drive = $this->driver; $name = $this->name; $root = $this->path; + if (($drive == 'database' || !$drive) && $value && base64_decode($value, true) === false) { $value = base64_encode($value); } if ($drive && $drive !== 'database') { $storage = new \App\FaveoStorage\Controllers\StorageController(); - $content = $storage->getFile($drive, $name); - $value = base64_encode($content); + $content = $storage->getFile($drive, $name, $root); + if ($content) { + $value = base64_encode($content); + if (mime($this->type) != 'image') { + $root = $root . "/" . $name; + chmod($root, 1204); + } + } } return $value; @@ -52,7 +59,6 @@ public function getFile() return '
  • '.$var.'
    '.$this->name.'

    '.$value.'

  • '; } else { - //$var = ''; $var = ''.strtoupper(str_limit($this->type, 15)).'
    '.$this->name.'

    '.$value.'

    '; return '
  • '.$var.'
  • '; diff --git a/app/User.php b/app/User.php index a746bd1c7a..1ce1abfa83 100644 --- a/app/User.php +++ b/app/User.php @@ -44,13 +44,18 @@ public function getProfilePicAttribute($value) if ($info) { $pic = $this->checkArray('avatar', $info); } - if (!$pic) { - $pic = asset('uploads/profilepic/'.$value); + if (!$pic && $value) { + $pic = ""; + $file = asset('uploads/profilepic/' . $value); + if ($file) { + $type = pathinfo($file, PATHINFO_EXTENSION); + $data = file_get_contents($file); + $pic = 'data:image/' . $type . ';base64,' . base64_encode($data); + } } if (!$value) { $pic = \Gravatar::src($this->attributes['email']); } - return $pic; } diff --git a/config/app.php b/config/app.php index bce581ae47..a8a5e27f6a 100644 --- a/config/app.php +++ b/config/app.php @@ -33,7 +33,7 @@ | This tells about aplication current version. | */ - 'version' => 'Community 1.9.4', + 'version' => 'Community 1.9.5', /* |-------------------------------------------------------------------------- | Application Name diff --git a/release-notes.txt b/release-notes.txt index 89340d06ed..34cdbeac15 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -21,6 +21,13 @@ | | | || | | || | | || | | || | | || | | || | | || | | | | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +|===================================================== +| v1.9.5 (security hot fixt patch2) +|===================================================== +## Bug Fixed + Prevents execution of backdoor scripts + Prevents users from uploading PHP files into user's profile picture + Handling token mismatch error when the page is opened for too long and session gets expired |===================================================== | v1.9.4 (security hot fixt patch) diff --git a/resources/lang/de/lang.php b/resources/lang/de/lang.php index f7f6107653..dba6d08496 100644 --- a/resources/lang/de/lang.php +++ b/resources/lang/de/lang.php @@ -1157,5 +1157,6 @@ 'search' => 'Search...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'Selected user is already the owner of this ticket.', - + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ]; diff --git a/resources/lang/en/lang.php b/resources/lang/en/lang.php index 2cefeee50f..e576f82650 100644 --- a/resources/lang/en/lang.php +++ b/resources/lang/en/lang.php @@ -1594,4 +1594,6 @@ 'search' => 'Search...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'Selected user is already the owner of this ticket.', + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ]; diff --git a/resources/lang/fr/lang.php b/resources/lang/fr/lang.php index 71d8663ee7..e8656a327a 100644 --- a/resources/lang/fr/lang.php +++ b/resources/lang/fr/lang.php @@ -1565,5 +1565,7 @@ 'search' => 'Rechercher...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'L\'utilisateur sélectionné est déjà le propriétaire du ticket.', + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ]; diff --git a/resources/lang/it/lang.php b/resources/lang/it/lang.php index aa4fc7cc3c..087f45769f 100644 --- a/resources/lang/it/lang.php +++ b/resources/lang/it/lang.php @@ -1117,4 +1117,6 @@ 'search' => 'Search...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'Selected user is already the owner of this ticket.', + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ]; diff --git a/resources/lang/nl/lang.php b/resources/lang/nl/lang.php index 4ab5bce4ce..fbf5463fba 100644 --- a/resources/lang/nl/lang.php +++ b/resources/lang/nl/lang.php @@ -1611,4 +1611,6 @@ 'search' => 'Search...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'Selected user is already the owner of this ticket.', + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ]; diff --git a/resources/lang/pt/lang.php b/resources/lang/pt/lang.php index 79a0ec5202..35727ce309 100644 --- a/resources/lang/pt/lang.php +++ b/resources/lang/pt/lang.php @@ -1556,5 +1556,7 @@ 'search' => 'Search...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'Selected user is already the owner of this ticket.', + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ]; diff --git a/resources/lang/ru/lang.php b/resources/lang/ru/lang.php index e6a4ae6510..0fc6c253df 100644 --- a/resources/lang/ru/lang.php +++ b/resources/lang/ru/lang.php @@ -1065,4 +1065,6 @@ 'search' => 'Search...', //update 21-12-2016 'selected-user-is-already-the-owner' => 'Selected user is already the owner of this ticket.', + //updated 15-5-2017 + 'session-expired' => 'Session expired or invalid, please try again.', ];