diff --git a/.all-contributorsrc b/.all-contributorsrc index d8a5df3d4..a47bf5b0c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -2514,6 +2514,15 @@ "code" ] }, + { + "login": "Haxatron", + "name": "Haxatron", + "avatar_url": "https://avatars.githubusercontent.com/u/76475453?v=4", + "profile": "https://github.com/Haxatron", + "contributions": [ + "code" + ] + }, { "login": "PlaneNuts", "name": "PlaneNuts", @@ -2532,6 +2541,15 @@ "code" ] }, + { + "login": "UniversalSuperBox", + "name": "Dalton Durst", + "avatar_url": "https://avatars.githubusercontent.com/u/21966173?v=4", + "profile": "https://daltondur.st", + "contributions": [ + "code" + ] + }, { "login": "adagioajanes", "name": "Alex Janes", diff --git a/README.md b/README.md index 4812fb522..837fdfcc7 100644 --- a/README.md +++ b/README.md @@ -128,9 +128,9 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
Mark Stenglein](https://markstenglein.com)
[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [
ajsy](https://github.com/ajsy)
[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [
Jan Kiesewetter](https://github.com/t3easy)
[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [
Tetrachloromethane250](https://github.com/Tetrachloromethane250)
[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [
Lars Kajes](https://www.kajes.se/)
[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [
Joly0](https://github.com/Joly0)
[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [
theburger](https://github.com/limeless)
[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") | | [
David Valin Alonso](https://github.com/deivishome)
[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [
andreaci](https://github.com/andreaci)
[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [
Jelle Sebreghts](http://www.jellesebreghts.be)
[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [
Michael Pietsch](https://github.com/Skywalker-11)
| [
Masudul Haque Shihab](https://github.com/sh1hab)
[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [
Supapong Areeprasertkul](http://www.freedomdive.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [
Peter Sarossy](https://github.com/psarossy)
[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") | | [
Renee Margaret McConahy](https://github.com/nepella)
[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [
JohnnyPicnic](https://github.com/JohnnyPicnic)
[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [
markbrule](https://github.com/markbrule)
[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [
Mike Campbell](https://github.com/mikecmpbll)
[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | [
tbrconnect](https://github.com/tbrconnect)
[💻](https://github.com/snipe/snipe-it/commits?author=tbrconnect "Code") | [
kcoyo](https://github.com/kcoyo)
[💻](https://github.com/snipe/snipe-it/commits?author=kcoyo "Code") | [
Travis Miller](https://travismiller.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=travismiller "Code") | -| [
Evan Taylor](https://github.com/Delta5)
[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [
Petri Asikainen](https://github.com/PetriAsi)
[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [
derdeagle](https://github.com/derdeagle)
[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [
Mike Frysinger](https://wh0rd.org/)
[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [
ALPHA](https://github.com/AL4AL)
[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [
FliegenKLATSCH](https://www.ifern.de)
[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [
Jeremy Price](https://github.com/jerm)
[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") | -| [
Toreg87](https://github.com/Toreg87)
[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [
Matthew Nickson](https://github.com/Computroniks)
[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [
Jethro Nederhof](https://jethron.id.au)
[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [
Oskar Stenberg](https://github.com/01ste02)
[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [
Robert-Azelis](https://github.com/Robert-Azelis)
[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [
Alexander William Smith](https://github.com/alwism)
[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [
LEITWERK AG](https://www.leitwerk.de/)
[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") | -| [
Adam](http://www.aboutcher.co.uk)
[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [
Ian](https://snksrv.com)
[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [
Shao Yu-Lung (Allen)](http://blog.bestlong.idv.tw/)
[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [
PlaneNuts](https://github.com/PlaneNuts)
[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [
Bradley Coudriet](http://bjcpgd.cias.rit.edu)
[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [
Alex Janes](https://adagiohealth.org)
[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [
Nuraeil](https://github.com/nuraeil)
[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | +| [
Petri Asikainen](https://github.com/PetriAsi)
[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [
derdeagle](https://github.com/derdeagle)
[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [
Mike Frysinger](https://wh0rd.org/)
[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [
ALPHA](https://github.com/AL4AL)
[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [
FliegenKLATSCH](https://www.ifern.de)
[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [
Jeremy Price](https://github.com/jerm)
[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") | [
Toreg87](https://github.com/Toreg87)
[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | +| [
Matthew Nickson](https://github.com/Computroniks)
[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [
Jethro Nederhof](https://jethron.id.au)
[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [
Oskar Stenberg](https://github.com/01ste02)
[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [
Robert-Azelis](https://github.com/Robert-Azelis)
[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [
Alexander William Smith](https://github.com/alwism)
[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [
LEITWERK AG](https://www.leitwerk.de/)
[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") | [
Adam](http://www.aboutcher.co.uk)
[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | +| [
Ian](https://snksrv.com)
[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [
Shao Yu-Lung (Allen)](http://blog.bestlong.idv.tw/)
[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [
Haxatron](https://github.com/Haxatron)
[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [
Bradley Coudriet](http://bjcpgd.cias.rit.edu)
[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [
Dalton Durst](https://daltondur.st)
[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") | [
TenOfTens](https://github.com/TenOfTens)
[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [
Simona Avornicesei](http://www.avornicesei.com)
[⚠️](https://github.com/snipe/snipe-it/commits?author=savornicesei "Tests") | | [
TenOfTens](https://github.com/TenOfTens)
[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [
waffle](https://ditisjens.be/)
[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index fbd120fe6..2bb8cc9f5 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -18,7 +18,15 @@ class Handler extends ExceptionHandler * @var array */ protected $dontReport = [ - JsonException::class + \Illuminate\Auth\AuthenticationException::class, + \Illuminate\Auth\Access\AuthorizationException::class, + \Symfony\Component\HttpKernel\Exception\HttpException::class, + \Illuminate\Database\Eloquent\ModelNotFoundException::class, + \Illuminate\Session\TokenMismatchException::class, + \Illuminate\Validation\ValidationException::class, + \Intervention\Image\Exception\NotSupportedException::class, + \League\OAuth2\Server\Exception\OAuthServerException::class, + JsonException::class, ]; /** @@ -40,7 +48,6 @@ class Handler extends ExceptionHandler /** * Render an exception into an HTTP response. * - * * @param \Illuminate\Http\Request $request * @param \Exception $e * @return \Illuminate\Http\Response @@ -96,6 +103,23 @@ class Handler extends ExceptionHandler } + /** + * Convert an authentication exception into an unauthenticated response. + * + * @param \Illuminate\Http\Request $request + * @param \Illuminate\Auth\AuthenticationException $exception + * @return \Illuminate\Http\Response + */ + protected function unauthenticated($request, AuthenticationException $exception) + { + if ($request->expectsJson()) { + return response()->json(['error' => 'Unauthorized or unauthenticated.'], 401); + } + + return redirect()->guest('login'); + } + + /** * A list of the inputs that are never flashed for validation exceptions. * diff --git a/app/Http/Controllers/Api/AssetMaintenancesController.php b/app/Http/Controllers/Api/AssetMaintenancesController.php index 6dcc009fc..18c205be5 100644 --- a/app/Http/Controllers/Api/AssetMaintenancesController.php +++ b/app/Http/Controllers/Api/AssetMaintenancesController.php @@ -34,6 +34,7 @@ class AssetMaintenancesController extends Controller */ public function index(Request $request) { + $this->authorize('view', Asset::class); $maintenances = AssetMaintenance::with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin'); if ($request->filled('search')) { @@ -101,6 +102,7 @@ class AssetMaintenancesController extends Controller */ public function store(Request $request) { + $this->authorize('edit', Asset::class); // create a new model instance $assetMaintenance = new AssetMaintenance(); $assetMaintenance->supplier_id = $request->input('supplier_id'); @@ -152,6 +154,7 @@ class AssetMaintenancesController extends Controller */ public function update(Request $request, $assetMaintenanceId = null) { + $this->authorize('edit', Asset::class); // Check if the asset maintenance exists $assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId); @@ -215,6 +218,7 @@ class AssetMaintenancesController extends Controller */ public function destroy($assetMaintenanceId) { + $this->authorize('edit', Asset::class); // Check if the asset maintenance exists $assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId); @@ -240,6 +244,7 @@ class AssetMaintenancesController extends Controller */ public function show($assetMaintenanceId) { + $this->authorize('view', Asset::class); $assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId); if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) { return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot view a maintenance for that asset')); diff --git a/app/Http/Controllers/Api/AssetModelsController.php b/app/Http/Controllers/Api/AssetModelsController.php index e4385032d..b788bc167 100644 --- a/app/Http/Controllers/Api/AssetModelsController.php +++ b/app/Http/Controllers/Api/AssetModelsController.php @@ -235,6 +235,8 @@ class AssetModelsController extends Controller */ public function selectlist(Request $request) { + + $this->authorize('view.selectlists'); $assetmodels = AssetModel::select([ 'models.id', 'models.name', diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index b8de5e8f5..2b6a7e2b5 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -368,8 +368,8 @@ class AssetsController extends Controller return (new AssetsTransformer)->transformAsset($asset, $request); } - return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200); + } /** @@ -858,8 +858,13 @@ class AssetsController extends Controller $asset->status_id = $request->input('status_id'); } + $checkin_at = null; + if ($request->filled('checkin_at')) { + $checkin_at = $request->input('checkin_at'); + } + if ($asset->save()) { - event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'))); + event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at)); return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.success'))); } @@ -898,6 +903,7 @@ class AssetsController extends Controller * @return JsonResponse */ public function audit(Request $request) + { $this->authorize('audit', Asset::class); $rules = [ diff --git a/app/Http/Controllers/Api/CategoriesController.php b/app/Http/Controllers/Api/CategoriesController.php index b1e36b29e..931056286 100644 --- a/app/Http/Controllers/Api/CategoriesController.php +++ b/app/Http/Controllers/Api/CategoriesController.php @@ -50,6 +50,7 @@ class CategoriesController extends Controller } + /** * Store a newly created resource in storage. * @@ -69,8 +70,8 @@ class CategoriesController extends Controller if ($category->save()) { return response()->json(Helper::formatStandardApiResponse('success', $category, trans('admin/categories/message.create.success'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, $category->getErrors())); + } /** @@ -85,10 +86,11 @@ class CategoriesController extends Controller { $this->authorize('view', Category::class); $category = Category::findOrFail($id); - return (new CategoriesTransformer)->transformCategory($category); + } + /** * Update the specified resource in storage. * @@ -136,6 +138,7 @@ class CategoriesController extends Controller return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/categories/message.delete.success'))); } + /** * Gets a paginated collection for the select2 menus * @@ -145,6 +148,7 @@ class CategoriesController extends Controller */ public function selectlist(Request $request, $category_type = 'asset') { + $this->authorize('view.selectlists'); $categories = Category::select([ 'id', 'name', diff --git a/app/Http/Controllers/Api/CompaniesController.php b/app/Http/Controllers/Api/CompaniesController.php index 6e53ad068..8efe9f1c7 100644 --- a/app/Http/Controllers/Api/CompaniesController.php +++ b/app/Http/Controllers/Api/CompaniesController.php @@ -56,10 +56,11 @@ class CompaniesController extends Controller $total = $companies->count(); $companies = $companies->skip($offset)->take($limit)->get(); - return (new CompaniesTransformer)->transformCompanies($companies, $total); + } + /** * Store a newly created resource in storage. * @@ -95,10 +96,11 @@ class CompaniesController extends Controller { $this->authorize('view', Company::class); $company = Company::findOrFail($id); - return (new CompaniesTransformer)->transformCompany($company); + } + /** * Update the specified resource in storage. * @@ -157,6 +159,7 @@ class CompaniesController extends Controller */ public function selectlist(Request $request) { + $this->authorize('view.selectlists'); $companies = Company::select([ 'companies.id', 'companies.name', diff --git a/app/Http/Controllers/Api/DepartmentsController.php b/app/Http/Controllers/Api/DepartmentsController.php index 9c648e635..314de2aa5 100644 --- a/app/Http/Controllers/Api/DepartmentsController.php +++ b/app/Http/Controllers/Api/DepartmentsController.php @@ -66,8 +66,8 @@ class DepartmentsController extends Controller $total = $departments->count(); $departments = $departments->skip($offset)->take($limit)->get(); - return (new DepartmentsTransformer)->transformDepartments($departments, $total); + } /** @@ -91,8 +91,8 @@ class DepartmentsController extends Controller if ($department->save()) { return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.create.success'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors())); + } /** @@ -134,6 +134,7 @@ class DepartmentsController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors())); } + /** * Validates and deletes selected department. * @@ -153,8 +154,8 @@ class DepartmentsController extends Controller } $department->delete(); - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/departments/message.delete.success'))); + } /** @@ -166,6 +167,8 @@ class DepartmentsController extends Controller */ public function selectlist(Request $request) { + + $this->authorize('view.selectlists'); $departments = Department::select([ 'id', 'name', diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index d03a45f02..5a4c7d90d 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -92,6 +92,10 @@ class LicensesController extends Controller $licenses = $licenses->TextSearch($request->input('search')); } + if ($request->input('deleted')=='true') { + $licenses->onlyTrashed(); + } + // Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which // case we override with the actual count, so we should return 0 items. $offset = (($licenses) && ($request->get('offset') > $licenses->count())) ? $licenses->count() : $request->get('offset', 0); diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index 43be34a27..fa16f8dbb 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -73,6 +73,7 @@ class LocationsController extends Controller break; } + $total = $locations->count(); $locations = $locations->skip($offset)->take($limit)->get(); @@ -137,6 +138,7 @@ class LocationsController extends Controller return (new LocationsTransformer)->transformLocation($location); } + /** * Update the specified resource in storage. * @@ -155,8 +157,8 @@ class LocationsController extends Controller $location = $request->handleImages($location); if ($location->isValid()) { - $location->save(); + $location->save(); return response()->json( Helper::formatStandardApiResponse( 'success', @@ -221,6 +223,9 @@ class LocationsController extends Controller */ public function selectlist(Request $request) { + + $this->authorize('view.selectlists'); + $locations = Location::select([ 'locations.id', 'locations.name', diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php index 5392c1d21..b1a411fc5 100644 --- a/app/Http/Controllers/Api/ManufacturersController.php +++ b/app/Http/Controllers/Api/ManufacturersController.php @@ -72,8 +72,8 @@ class ManufacturersController extends Controller if ($manufacturer->save()) { return response()->json(Helper::formatStandardApiResponse('success', $manufacturer, trans('admin/manufacturers/message.create.success'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, $manufacturer->getErrors())); + } /** @@ -131,11 +131,11 @@ class ManufacturersController extends Controller if ($manufacturer->isDeletable()) { $manufacturer->delete(); - - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success'))); + return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/manufacturers/message.delete.success'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.assoc_users'))); + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.assoc_users'))); + } /** @@ -147,6 +147,8 @@ class ManufacturersController extends Controller */ public function selectlist(Request $request) { + + $this->authorize('view.selectlists'); $manufacturers = Manufacturer::select([ 'id', 'name', diff --git a/app/Http/Controllers/Api/SuppliersController.php b/app/Http/Controllers/Api/SuppliersController.php index e5668b6ba..40ff9e8bd 100644 --- a/app/Http/Controllers/Api/SuppliersController.php +++ b/app/Http/Controllers/Api/SuppliersController.php @@ -70,8 +70,8 @@ class SuppliersController extends Controller if ($supplier->save()) { return response()->json(Helper::formatStandardApiResponse('success', $supplier, trans('admin/suppliers/message.create.success'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, $supplier->getErrors())); + } /** @@ -90,6 +90,7 @@ class SuppliersController extends Controller return (new SuppliersTransformer)->transformSupplier($supplier); } + /** * Update the specified resource in storage. * @@ -127,6 +128,7 @@ class SuppliersController extends Controller $supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id); $this->authorize('delete', $supplier); + if ($supplier->assets_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count]))); } @@ -153,6 +155,9 @@ class SuppliersController extends Controller */ public function selectlist(Request $request) { + + $this->authorize('view.selectlists'); + $suppliers = Supplier::select([ 'id', 'name', diff --git a/app/Http/Controllers/AssetMaintenancesController.php b/app/Http/Controllers/AssetMaintenancesController.php index 1ab24b768..333c4a6b2 100644 --- a/app/Http/Controllers/AssetMaintenancesController.php +++ b/app/Http/Controllers/AssetMaintenancesController.php @@ -50,6 +50,7 @@ class AssetMaintenancesController extends Controller */ public function index() { + $this->authorize('view', Asset::class); return view('asset_maintenances/index'); } @@ -64,6 +65,7 @@ class AssetMaintenancesController extends Controller */ public function create() { + $this->authorize('edit', Asset::class); $asset = null; if ($asset = Asset::find(request('asset_id'))) { @@ -94,6 +96,7 @@ class AssetMaintenancesController extends Controller */ public function store(Request $request) { + $this->authorize('edit', Asset::class); // create a new model instance $assetMaintenance = new AssetMaintenance(); $assetMaintenance->supplier_id = $request->input('supplier_id'); @@ -145,6 +148,7 @@ class AssetMaintenancesController extends Controller */ public function edit($assetMaintenanceId = null) { + $this->authorize('edit', Asset::class); // Check if the asset maintenance exists if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) { // Redirect to the improvement management page @@ -195,6 +199,7 @@ class AssetMaintenancesController extends Controller */ public function update(Request $request, $assetMaintenanceId = null) { + $this->authorize('edit', Asset::class); // Check if the asset maintenance exists if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) { // Redirect to the asset maintenance management page @@ -262,6 +267,7 @@ class AssetMaintenancesController extends Controller */ public function destroy($assetMaintenanceId) { + $this->authorize('edit', Asset::class); // Check if the asset maintenance exists if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) { // Redirect to the asset maintenance management page @@ -290,6 +296,8 @@ class AssetMaintenancesController extends Controller */ public function show($assetMaintenanceId) { + $this->authorize('view', Asset::class); + // Check if the asset maintenance exists if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) { // Redirect to the asset maintenance management page diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index f431a1736..9a7c1407b 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -123,6 +123,7 @@ class AssetModelsController extends Controller return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist')); } + /** * Validates and processes form data from the edit * Asset Model form based on the model ID passed. @@ -231,10 +232,11 @@ class AssetModelsController extends Controller return redirect()->route('models.index')->with('success', trans('admin/models/message.restore.success')); } - return redirect()->back()->with('error', trans('admin/models/message.not_found')); + } + /** * Get the model information to present to the model view page * @@ -282,6 +284,7 @@ class AssetModelsController extends Controller ->with('clone_model', $model_to_clone); } + /** * Get the custom fields form * @@ -295,6 +298,8 @@ class AssetModelsController extends Controller return view('models.custom_fields_form')->with('model', AssetModel::find($modelId)); } + + /** * Returns a view that allows the user to bulk edit model attrbutes * @@ -337,6 +342,8 @@ class AssetModelsController extends Controller ->with('error', 'You must select at least one model to edit.'); } + + /** * Returns a view that allows the user to bulk edit model attrbutes * @@ -349,6 +356,7 @@ class AssetModelsController extends Controller $models_raw_array = $request->input('ids'); $update_array = []; + if (($request->filled('manufacturer_id') && ($request->input('manufacturer_id') != 'NC'))) { $update_array['manufacturer_id'] = $request->input('manufacturer_id'); } @@ -362,6 +370,7 @@ class AssetModelsController extends Controller $update_array['depreciation_id'] = $request->input('depreciation_id'); } + if (count($update_array) > 0) { AssetModel::whereIn('id', $models_raw_array)->update($update_array); @@ -443,7 +452,9 @@ class AssetModelsController extends Controller private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues) { foreach ($defaultValues as $customFieldId => $defaultValue) { - if ($defaultValue) { + if(is_array($defaultValue)){ + $model->defaultValues()->attach($customFieldId, ['default_value' => implode(', ', $defaultValue)]); + }elseif ($defaultValue) { $model->defaultValues()->attach($customFieldId, ['default_value' => $defaultValue]); } } diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 8912da442..cb661eabd 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -82,6 +82,8 @@ class ForgotPasswordController extends Controller \Log::info('Password reset attempt: User '.$request->input('username').'failed with exception: '.$e ); } + // Prevent timing attack to enumerate users. + usleep(500000 + random_int(0, 1500000)); if ($response === \Password::RESET_LINK_SENT) { \Log::info('Password reset attempt: User '.$request->input('username').' WAS found, password reset sent'); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 3e256c564..7b55539cc 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -302,6 +302,7 @@ class LoginController extends Controller return redirect()->intended()->with('success', trans('auth/message.signin.success')); } + /** * Two factor enrollment page * @@ -402,7 +403,7 @@ class LoginController extends Controller if (Google2FA::verifyKey($user->two_factor_secret, $secret)) { $user->two_factor_enrolled = 1; $user->save(); - $request->session()->put('2fa_authed', 'true'); + $request->session()->put('2fa_authed', $user->id); return redirect()->route('home')->with('success', 'You are logged in!'); } @@ -410,6 +411,7 @@ class LoginController extends Controller return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code')); } + /** * Logout page. * @@ -456,6 +458,7 @@ class LoginController extends Controller return redirect()->route('login')->with(['success' => trans('auth/message.logout.success'), 'loggedout' => true]); } + /** * Get a validator for an incoming registration request. * diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index 8e29cba74..da4bd0855 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -53,6 +53,7 @@ class CustomFieldsController extends Controller return redirect()->route('fields.index'); } + /** * Returns a view with a form to create a new custom field. * @@ -96,6 +97,7 @@ class CustomFieldsController extends Controller "user_id" => Auth::id() ]); + if ($request->filled('custom_format')) { $field->format = e($request->get('custom_format')); } else { @@ -125,12 +127,23 @@ class CustomFieldsController extends Controller $this->authorize('update', $field); + // Check that the field exists - this is mostly related to the demo, where we + // rewrite the data every x minutes, so it's possible someone might be disassociating + // a field from a fieldset just as we're wiping the database + if (($field) && ($fieldset_id)) { + if ($field->fieldset()->detach($fieldset_id)) { return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id]) ->with('success', trans('admin/custom_fields/message.field.delete.success')); + } else { + return redirect()->back()->withErrors(['message' => "Field is in use and cannot be deleted."]); + } + } - return redirect()->back()->withErrors(['message' => 'Field is in-use']); + return redirect()->back()->withErrors(['message' => "Error deleting field from fieldset"]); + + } /** @@ -157,6 +170,7 @@ class CustomFieldsController extends Controller return redirect()->back()->withErrors(['message' => 'Field does not exist']); } + /** * Return a view to edit a custom field * @@ -189,6 +203,7 @@ class CustomFieldsController extends Controller } + /** * Store the updated field * diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 27fd8236a..852212ef3 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -8,6 +8,7 @@ use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\SettingsSamlRequest; use App\Http\Requests\SetupUserRequest; use App\Models\Setting; +use App\Models\Asset; use App\Models\User; use App\Notifications\FirstAdminNotification; use App\Notifications\MailTest; @@ -419,6 +420,7 @@ class SettingsController extends Controller $setting->brand = 1; } + $setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo'); @@ -476,6 +478,7 @@ class SettingsController extends Controller return redirect()->back()->withInput()->withErrors($setting->getErrors()); } + /** * Return a form to allow a super admin to update settings. * @@ -615,6 +618,26 @@ class SettingsController extends Controller return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } + // Check if the audit interval has changed - if it has, we want to update ALL of the assets audit dates + if ($request->input('audit_interval') != $setting->audit_interval) { + + // Be careful - this could be a negative number + $audit_diff_months = ((int)$request->input('audit_interval') - (int)($setting->audit_interval)); + + // Grab all of the assets that have an existing next_audit_date + $assets = Asset::whereNotNull('next_audit_date')->get(); + + // Update all of the assets' next_audit_date values + foreach ($assets as $asset) { + + if ($asset->next_audit_date != '') { + $old_next_audit = new \DateTime($asset->next_audit_date); + $asset->next_audit_date = $old_next_audit->modify($audit_diff_months.' month')->format('Y-m-d'); + $asset->forceSave(); + } + } + } + $alert_email = rtrim($request->input('alert_email'), ','); $alert_email = trim($alert_email); $admin_cc_email = rtrim($request->input('admin_cc_email'), ','); @@ -1027,7 +1050,6 @@ class SettingsController extends Controller //$lastmodified = Carbon::parse(Storage::lastModified($backup_files[$f]))->toDatetimeString(); $file_timestamp = Storage::lastModified($backup_files[$f]); - $files_raw[] = [ 'filename' => basename($backup_files[$f]), 'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])), diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php index 1bbb419b3..ebf8df5d6 100755 --- a/app/Http/Controllers/Users/UsersController.php +++ b/app/Http/Controllers/Users/UsersController.php @@ -479,7 +479,6 @@ class UsersController extends Controller $user->first_name = ''; $user->last_name = ''; $user->email = substr($user->email, ($pos = strpos($user->email, '@')) !== false ? $pos : 0); - $user->id = null; // Get this user groups diff --git a/app/Http/Middleware/CheckForTwoFactor.php b/app/Http/Middleware/CheckForTwoFactor.php index 4cf7e265c..51ad9c750 100644 --- a/app/Http/Middleware/CheckForTwoFactor.php +++ b/app/Http/Middleware/CheckForTwoFactor.php @@ -32,7 +32,7 @@ class CheckForTwoFactor if ($settings = Setting::getSettings()) { if (Auth::check() && ($settings->two_factor_enabled != '')) { // This user is already 2fa-authed - if ($request->session()->get('2fa_authed')) { + if ($request->session()->get('2fa_authed')==Auth::user()->id) { return $next($request); } diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 8e32ac705..795915710 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -36,7 +36,11 @@ class ActionlogsTransformer foreach ($value as $meta_key => $meta_value) { if (is_array($meta_value)) { foreach ($meta_value as $meta_value_key => $meta_value_value) { - $clean_meta[$key][$meta_value_key] = e($meta_value_value); + if (is_scalar($meta_value_value)) { + $clean_meta[$key][$meta_value_key] = e($meta_value_value); + } else { + $clean_meta[$key][$meta_value_key] = 'invalid scalar: '.print_r($meta_value_value, true); + } } } else { diff --git a/app/Http/Transformers/LicensesTransformer.php b/app/Http/Transformers/LicensesTransformer.php index 56492ba45..3fb2a8943 100644 --- a/app/Http/Transformers/LicensesTransformer.php +++ b/app/Http/Transformers/LicensesTransformer.php @@ -46,7 +46,9 @@ class LicensesTransformer 'category' => ($license->category) ? ['id' => (int) $license->category->id, 'name'=> e($license->category->name)] : null, 'created_at' => Helper::getFormattedDateObject($license->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'), + 'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'), 'user_can_checkout' => (bool) ($license->free_seats_count > 0), + ]; $permissions_array['available_actions'] = [ diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php index 988eda3aa..3609298ac 100644 --- a/app/Models/Loggable.php +++ b/app/Models/Loggable.php @@ -110,9 +110,10 @@ trait Loggable } } + $log->location_id = null; $log->note = $note; - $log->action_date= $action_date; + $log->action_date = $action_date; if (Auth::user()) { $log->user_id = Auth::user()->id; diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 31a328abf..7148e03f4 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -151,6 +151,8 @@ class AuthServiceProvider extends ServiceProvider return $user->hasAccess('self.checkout_assets'); }); + // This is largely used to determine whether to display the gear icon sidenav + // in the left-side navigation Gate::define('backend.interact', function ($user) { return $user->can('view', Statuslabel::class) || $user->can('view', AssetModel::class) @@ -165,5 +167,19 @@ class AuthServiceProvider extends ServiceProvider || $user->can('view', CustomFieldset::class) || $user->can('view', Depreciation::class); }); + + + // This determines whether or not an API user should be able to get the selectlists. + // This can seem a little confusing, since view properties may not have been granted + // to the logged in API user, but creating assets, licenses, etc won't work + // if the user can't view and interact with the select lists. + Gate::define('view.selectlists', function ($user) { + return $user->can(['create','update'], Asset::class) + || $user->can(['create','update'], License::class) + || $user->can(['create','update'], Component::class) + || $user->can(['create','update'], Consumable::class) + || $user->can(['create','update'], Accessory::class) + || $user->can(['create','update'], User::class); + }); } } diff --git a/database/migrations/2015_11_08_222305_add_ldap_fields_to_settings.php b/database/migrations/2015_11_08_222305_add_ldap_fields_to_settings.php index d52191f3d..171258f27 100644 --- a/database/migrations/2015_11_08_222305_add_ldap_fields_to_settings.php +++ b/database/migrations/2015_11_08_222305_add_ldap_fields_to_settings.php @@ -22,7 +22,7 @@ class AddLdapFieldsToSettings extends Migration $table->string('ldap_username_field')->nullable()->default('samaccountname'); $table->string('ldap_lname_field')->nullable()->default('sn'); $table->string('ldap_fname_field')->nullable()->default('givenname'); - $table->string('ldap_auth_filter_query')->nullable()->default('uid=samaccountname'); + $table->string('ldap_auth_filter_query')->nullable()->default('uid='); $table->integer('ldap_version')->nullable()->default(3); $table->string('ldap_active_flag')->nullable()->default(null); $table->string('ldap_emp_num')->nullable()->default(null); diff --git a/database/migrations/2022_02_03_214958_blank_out_ldap_active_flag.php b/database/migrations/2022_02_03_214958_blank_out_ldap_active_flag.php new file mode 100644 index 000000000..e183788f0 --- /dev/null +++ b/database/migrations/2022_02_03_214958_blank_out_ldap_active_flag.php @@ -0,0 +1,32 @@ +ldap_active_flag = ''; + $s->save(); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/resources/lang/en/admin/settings/general.php b/resources/lang/en/admin/settings/general.php index f4e8cc57b..1905392ba 100644 --- a/resources/lang/en/admin/settings/general.php +++ b/resources/lang/en/admin/settings/general.php @@ -21,7 +21,7 @@ return [ 'allow_user_skin_help_text' => 'Checking this box will allow a user to override the UI skin with a different one.', 'asset_ids' => 'Asset IDs', 'audit_interval' => 'Audit Interval', - 'audit_interval_help' => 'If you are required to regularly physically audit your assets, enter the interval in months.', + 'audit_interval_help' => 'If you are required to regularly physically audit your assets, enter the interval in months that you use. If you update this value, all of the "next audit dates" for assets with an upcoming audit date.', 'audit_warning_days' => 'Audit Warning Threshold', 'audit_warning_days_help' => 'How many days in advance should we warn you when assets are due for auditing?', 'auto_increment_assets' => 'Generate auto-incrementing asset tags', diff --git a/resources/lang/en/passwords.php b/resources/lang/en/passwords.php index 6205ef774..477294001 100644 --- a/resources/lang/en/passwords.php +++ b/resources/lang/en/passwords.php @@ -1,6 +1,6 @@ 'Your password link has been sent!', + 'sent' => 'Success: If that email address exists in our system, a password recovery email has been sent.', 'user' => 'No matching active user found with that email.', ]; diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 428a5389c..3a2dab4c1 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -285,7 +285,11 @@
- {{ Helper::getFormattedDateObject($audit_log->created_at, 'date', false) }} (by {{ link_to_route('users.show', $audit_log->user->present()->fullname(), [$audit_log->user->id]) }}) + {{ \App\Helpers\Helper::getFormattedDateObject($audit_log->created_at, 'date', false) }} + @if ($audit_log->user) + (by {{ link_to_route('users.show', $audit_log->user->present()->fullname(), [$audit_log->user->id]) }}) + @endif +
@endif diff --git a/resources/views/models/custom_fields_form.blade.php b/resources/views/models/custom_fields_form.blade.php index 8548caef6..2ee656d35 100644 --- a/resources/views/models/custom_fields_form.blade.php +++ b/resources/views/models/custom_fields_form.blade.php @@ -18,10 +18,9 @@ @elseif ($field->element=='checkbox') @foreach ($field->formatFieldValuesAsArray() as $key => $value) -
@@ -32,7 +31,7 @@