diff --git a/Dockerfile b/Dockerfile index 46ad8682d1..35680b161c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,7 @@ vim \ git \ cron \ mysql-client \ +supervisor \ cron \ gcc \ make \ @@ -92,7 +93,9 @@ RUN \ && rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \ && mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \ && ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \ - && chown docker "/var/lib/snipeit/keys/" + && chown docker "/var/lib/snipeit/keys/" \ + && chmod +x /var/www/html/artisan \ + && echo "Finished setting up application in /var/www/html" ############## DEPENDENCIES via COMPOSER ################### @@ -119,16 +122,11 @@ VOLUME ["/var/lib/snipeit"] ##### START SERVER -COPY docker/entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh +COPY docker/startup.sh docker/supervisord.conf / +COPY docker/supervisor-exit-event-listener /usr/bin/supervisor-exit-event-listener +RUN chmod +x /startup.sh /usr/bin/supervisor-exit-event-listener -# Add Tini -ENV TINI_VERSION v0.14.0 -ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini -RUN chmod +x /tini -ENTRYPOINT ["/tini", "--"] - -CMD ["/entrypoint.sh"] +CMD ["/startup.sh"] EXPOSE 80 EXPOSE 443 diff --git a/README.md b/README.md index 9b7f81ad44..bbb1d2a3bc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=master)](https://travis-ci.org/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) -[![All Contributors](https://img.shields.io/badge/all_contributors-201-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) +[![All Contributors](https://img.shields.io/badge/all_contributors-180-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) ## Snipe-IT - Open Source Asset Management System diff --git a/app/Http/Controllers/Api/AssetModelsController.php b/app/Http/Controllers/Api/AssetModelsController.php index 2a739b1681..6190100817 100644 --- a/app/Http/Controllers/Api/AssetModelsController.php +++ b/app/Http/Controllers/Api/AssetModelsController.php @@ -179,7 +179,7 @@ class AssetModelsController extends Controller try { Storage::disk('public')->delete('assetmodels/'.$assetmodel->image); } catch (\Exception $e) { - \Log::error($e); + \Log::info($e); } } diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index 7504daf633..1ea456c4e9 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -25,7 +25,7 @@ class ImportController extends Controller */ public function index() { - // + $this->authorize('import'); $imports = Import::latest()->get(); return (new ImportsTransformer)->transformImports($imports); @@ -39,10 +39,8 @@ class ImportController extends Controller */ public function store() { - // - if (!Company::isCurrentUserAuthorized()) { - return redirect()->route('hardware.index')->with('error', trans('general.insufficient_permissions')); - } elseif (!config('app.lock_passwords')) { + $this->authorize('import'); + if (!config('app.lock_passwords')) { $files = Input::file('files'); $path = config('app.private_uploads').'/imports'; $results = []; @@ -119,7 +117,7 @@ class ImportController extends Controller */ public function process(ItemImportRequest $request, $import_id) { - $this->authorize('create', Asset::class); + $this->authorize('import'); // Run a backup immediately before processing Artisan::call('backup:run'); $errors = $request->import(Import::find($import_id)); diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index ec1ae80ed9..ea01ec9c2e 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -54,6 +54,7 @@ class UsersController extends Controller 'users.phone', 'users.state', 'users.two_factor_enrolled', + 'users.two_factor_optin', 'users.updated_at', 'users.username', 'users.zip', diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index 0375fe456f..491de8325d 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -195,7 +195,7 @@ class AssetModelsController extends Controller try { Storage::disk('public')->delete('models/'.$model->image); } catch (\Exception $e) { - \Log::error($e); + \Log::info($e); } } diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 520156bd4a..331ba912ca 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -308,7 +308,7 @@ class AssetsController extends Controller unlink(public_path().'/uploads/assets/'.$asset->image); $asset->image = ''; } catch (\Exception $e) { - \Log::error($e); + \Log::info($e); } } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 5f3bd91bae..71fa69c898 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -15,6 +15,11 @@ use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Validator; use Redirect; +use Log; +use View; +use Otp\Otp; +use Otp\GoogleAuthenticator; +use ParagonIE\ConstantTime\Encoding; /** * This controller handles authentication for the user, including local @@ -198,22 +203,24 @@ class LoginController extends Controller return redirect()->route('login')->with('error', 'You must be logged in.'); } - $user = Auth::user(); - $google2fa = app()->make('pragmarx.google2fa'); - if ($user->two_factor_secret=='') { - $user->two_factor_secret = $google2fa->generateSecretKey(32); - $user->save(); + $settings = Setting::getSettings(); + $user = Auth::user(); + + if (($user->two_factor_secret!='') && ($user->two_factor_enrolled==1)) { + return redirect()->route('two-factor')->with('error', 'Your device is already enrolled.'); } - $google2fa_url = $google2fa->getQRCodeInline( - urlencode(Setting::getSettings()->site_name), - urlencode($user->username), - $user->two_factor_secret - ); - return view('auth.two_factor_enroll')->with('google2fa_url', $google2fa_url); + new Otp(); + $secret = GoogleAuthenticator::generateRandom(); + $user->two_factor_secret = $secret; + $user->save(); + + $barcode = new \Com\Tecnick\Barcode\Barcode(); + $barcode_obj = $barcode->getBarcodeObj('QRCODE', 'otpauth://totp/'.urlencode($settings->site_name).':'.urlencode($user->username).'?secret='.urlencode($secret).'&issuer=Snipe-IT&period=30', 300, 300, 'black', array(-2, -2, -2, -2)); + return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj); } @@ -242,18 +249,23 @@ class LoginController extends Controller return redirect()->route('login')->with('error', 'You must be logged in.'); } - $user = Auth::user(); - $secret = $request->get('two_factor_secret'); - $google2fa = app()->make('pragmarx.google2fa'); - $valid = $google2fa->verifyKey($user->two_factor_secret, $secret); + if (!$request->has('two_factor_secret')) { + return redirect()->route('two-factor')->with('error', 'Two-factor code is required.'); + } - if ($valid) { + $user = Auth::user(); + $otp = new Otp(); + + + + if ($otp->checkTotp(Encoding::base32DecodeUpper($user->two_factor_secret), $request->get('two_factor_secret'))) { $user->two_factor_enrolled = 1; $user->save(); $request->session()->put('2fa_authed', 'true'); return redirect()->route('home')->with('success', 'You are logged in!'); } + \Log::debug('Did not match'); return redirect()->route('two-factor')->with('error', 'Invalid two-factor code'); diff --git a/app/Http/Controllers/ImportsController.php b/app/Http/Controllers/ImportsController.php index 7c4c8430f3..46954303c5 100644 --- a/app/Http/Controllers/ImportsController.php +++ b/app/Http/Controllers/ImportsController.php @@ -14,7 +14,7 @@ class ImportsController extends Controller */ public function index() { - $this->authorize('create', Asset::class); + $this->authorize('import'); $imports = (new ImportsTransformer)->transformImports(Import::latest()->get()); return view('importer/import')->with('imports', $imports); } diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php index 06162924cb..52a479fdd1 100755 --- a/app/Http/Controllers/ManufacturersController.php +++ b/app/Http/Controllers/ManufacturersController.php @@ -164,7 +164,7 @@ class ManufacturersController extends Controller try { Storage::disk('public')->delete('manufacturers/'.$manufacturer->image); } catch (\Exception $e) { - \Log::error($e); + \Log::info($e); } } diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index e299575cd4..3a690704b4 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -52,6 +52,8 @@ class UsersTransformer 'permissions' => $user->decodePermissions(), 'activated' => ($user->activated =='1') ? true : false, 'two_factor_activated' => ($user->two_factor_active()) ? true : false, + 'two_factor_enrolled' => ($user->two_factor_active_and_enrolled()) ? true : false, + 'assets_count' => (int) $user->assets_count, 'licenses_count' => (int) $user->licenses_count, 'accessories_count' => (int) $user->accessories_count, diff --git a/app/Models/User.php b/app/Models/User.php index 36d57cfd08..a3f217285b 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -525,7 +525,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Check whether two-factor authorization is required and the user has activated it + * Check whether two-factor authorization is requiredfor this user + * + * 0 = 2FA disabled + * 1 = 2FA optional + * 2 = 2FA universally required * * @author [A. Gianotto] [] * @since [v4.0] @@ -534,10 +538,45 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo */ public function two_factor_active () { - if (Setting::getSettings()->two_factor_enabled !='0') { - if (($this->two_factor_optin =='1') && ($this->two_factor_enrolled)) { - return true; - } + // If the 2FA is optional and the user has opted in + if ((Setting::getSettings()->two_factor_enabled =='1') && ($this->two_factor_optin =='1')) + { + return true; + } + // If the 2FA is required for everyone so is implicitly active + elseif (Setting::getSettings()->two_factor_enabled =='2') + { + return true; + } + + return false; + + } + + /** + * Check whether two-factor authorization is required and the user has activated it + * and enrolled a device + * + * 0 = 2FA disabled + * 1 = 2FA optional + * 2 = 2FA universally required + * + * @author [A. Gianotto] [] + * @since [v4.6.14] + * + * @return bool + */ + public function two_factor_active_and_enrolled () { + + // If the 2FA is optional and the user has opted in and is enrolled + if ((Setting::getSettings()->two_factor_enabled =='1') && ($this->two_factor_optin =='1') && ($this->two_factor_enrolled =='1')) + { + return true; + } + // If the 2FA is required for everyone and the user has enrolled + elseif ((Setting::getSettings()->two_factor_enabled =='2') && ($this->two_factor_enrolled)) + { + return true; } return false; diff --git a/app/Policies/SnipePermissionsPolicy.php b/app/Policies/SnipePermissionsPolicy.php index b8d4501bdf..e17f4f68e5 100644 --- a/app/Policies/SnipePermissionsPolicy.php +++ b/app/Policies/SnipePermissionsPolicy.php @@ -53,7 +53,7 @@ abstract class SnipePermissionsPolicy /** * Determine whether the user can view the accessory. * - * @param \App\User $user + * @param \App\Models\User $user * @return mixed */ public function view(User $user, $item = null) @@ -64,7 +64,7 @@ abstract class SnipePermissionsPolicy /** * Determine whether the user can create accessories. * - * @param \App\User $user + * @param \App\Models\User $user * @return mixed */ public function create(User $user) @@ -75,7 +75,7 @@ abstract class SnipePermissionsPolicy /** * Determine whether the user can update the accessory. * - * @param \App\User $user + * @param \App\Models\User $user * @return mixed */ public function update(User $user, $item = null) @@ -86,7 +86,7 @@ abstract class SnipePermissionsPolicy /** * Determine whether the user can delete the accessory. * - * @param \App\User $user + * @param \App\Models\User $user * @return mixed */ public function delete(User $user, $item = null) @@ -97,11 +97,13 @@ abstract class SnipePermissionsPolicy /** * Determine whether the user can manage the accessory. * - * @param \App\User $user + * @param \App\Models\User $user * @return mixed */ public function manage(User $user, $item = null) { return $user->hasAccess($this->columnName().'.edit'); } + + } diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index 5d24fa974c..5d3f6b6bed 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -223,14 +223,14 @@ class UserPresenter extends Presenter [ "field" => "two_factor_enrolled", "searchable" => false, - "sortable" => false, + "sortable" => true, "switchable" => true, "title" => trans('admin/users/general.two_factor_enrolled'), "visible" => false, 'formatter' => 'trueFalseFormatter' ], [ - "field" => "two_factor_active", + "field" => "two_factor_activated", "searchable" => false, "sortable" => false, "switchable" => true, @@ -243,7 +243,7 @@ class UserPresenter extends Presenter "searchable" => false, "sortable" => true, "switchable" => true, - "title" => trans('general.activated'), + "title" => trans('general.login_enabled'), "visible" => true, 'formatter' => 'trueFalseFormatter' ], diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 6674645715..050adb5907 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -113,6 +113,14 @@ class AuthServiceProvider extends ServiceProvider }); + // Can the user import CSVs? + Gate::define('import', function ($user) { + if ($user->hasAccess('import') ) { + return true; + } + }); + + # ----------------------------------------- # Reports # ----------------------------------------- diff --git a/composer.json b/composer.json index ab2faf85ca..3c6db1e7fc 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "league/flysystem-sftp": "~1.0", "maknz/slack": "^1.7", "neitanod/forceutf8": "^2.0", + "paragonie/constant_time_encoding": "^1.0", "patchwork/utf8": "~1.2", "phpdocumentor/reflection-docblock": "3.2.2", "phpspec/prophecy": "1.7.5", diff --git a/config/permissions.php b/config/permissions.php index 7692477548..a17857161e 100644 --- a/config/permissions.php +++ b/config/permissions.php @@ -27,6 +27,15 @@ return array( ) ), + 'CSV Import' => array( + array( + 'permission' => 'import', + 'label' => '', + 'note' => 'This will allow users to import even if access to users, assets, etc is denied elsewhere.', + 'display' => true, + ) + ), + 'Reports' => array( array( 'permission' => 'reports.view', diff --git a/docker/entrypoint.sh b/docker/startup.sh similarity index 94% rename from docker/entrypoint.sh rename to docker/startup.sh index 9459701efa..3fecb47c21 100644 --- a/docker/entrypoint.sh +++ b/docker/startup.sh @@ -5,7 +5,7 @@ if [ -z "$APP_KEY" ] then echo "Please re-run this container with an environment variable \$APP_KEY" echo "An example APP_KEY you could use is: " - php artisan key:generate --show + /var/www/html/artisan key:generate --show exit fi @@ -47,6 +47,8 @@ then cp -ax /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/ fi +exec supervisord -c /supervisord.conf + php artisan migrate --force php artisan config:clear php artisan config:cache diff --git a/docker/supervisor-exit-event-listener b/docker/supervisor-exit-event-listener new file mode 100644 index 0000000000..84201634e1 --- /dev/null +++ b/docker/supervisor-exit-event-listener @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# A supervisor event listener which terminates supervisord if any of its child +# processes enter the FATAL state. +# https://stackoverflow.com/a/37527488/119527 +import os +import signal + +from supervisor import childutils + +def main(): + while True: + headers, payload = childutils.listener.wait() + childutils.listener.ok() + if headers['eventname'] != 'PROCESS_STATE_FATAL': + continue + os.kill(os.getppid(), signal.SIGTERM) + +if __name__ == "__main__": + main() diff --git a/docker/supervisord.conf b/docker/supervisord.conf new file mode 100644 index 0000000000..9820147310 --- /dev/null +++ b/docker/supervisord.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true + +[program:apache] +; https://advancedweb.hu/2018/07/03/supervisor_docker/ +command=apache2ctl -DFOREGROUND +killasgroup=true +stopasgroup=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:run_schedule] +; Simply run the Laravel command scheduler every minute +command=/bin/bash -c "while true; do /var/www/html/artisan schedule:run; sleep 1m; done" +user=docker +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + + +; https://stackoverflow.com/a/37527488/119527 +[eventlistener:exit_on_any_fatal] +command=supervisor-exit-event-listener +events=PROCESS_STATE_FATAL diff --git a/public/css/build/all.css b/public/css/build/all.css new file mode 100644 index 0000000000..4bfc2811b5 Binary files /dev/null and b/public/css/build/all.css differ diff --git a/public/css/dist/all.css b/public/css/dist/all.css new file mode 100644 index 0000000000..0613103f1f Binary files /dev/null and b/public/css/dist/all.css differ diff --git a/public/js/build/all.js b/public/js/build/all.js index b1e269197d..116840800b 100644 Binary files a/public/js/build/all.js and b/public/js/build/all.js differ diff --git a/public/js/build/vue.js b/public/js/build/vue.js index fabec21b5b..a35ff4af16 100644 Binary files a/public/js/build/vue.js and b/public/js/build/vue.js differ diff --git a/public/js/build/vue.js.map b/public/js/build/vue.js.map index 779f53b315..68a5b50a28 100644 Binary files a/public/js/build/vue.js.map and b/public/js/build/vue.js.map differ diff --git a/public/js/dist/all.js b/public/js/dist/all.js index f3e9beaf7a..cb8780018e 100644 Binary files a/public/js/dist/all.js and b/public/js/dist/all.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index bf12640cc7..61daa83a74 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,4 +1,5 @@ { +<<<<<<< HEAD "/js/app.js": "/js/app.js?id=be43e3109667a86c9a02", "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=f7a5d783fef321018f4c", "/css/build/app.css": "/css/build/app.css?id=0dfc05b0fe1dcc9b6e3d", @@ -14,4 +15,18 @@ "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=bc5e33610f678021cc48", "/js/dist/bootstrap-table-simple-view.js": "/js/dist/bootstrap-table-simple-view.js?id=3926b8f4aaad6ca20d31", "/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=6b4ccfd094c065f065ae" +======= + "/js/build/vue.js": "/js/build/vue.js?id=96f90510b797ac27a94b", + "/css/AdminLTE.css": "/css/AdminLTE.css?id=5e72463a66acbcc740d5", + "/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405", + "/css/overrides.css": "/css/overrides.css?id=2d81c3704393bac77011", + "/js/build/vue.js.map": "/js/build/vue.js.map?id=423f16f63b86abd6b196", + "/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=0be7790b84909dca6a0a", + "/css/app.css.map": "/css/app.css.map?id=96b5c985e860716e6a16", + "/css/overrides.css.map": "/css/overrides.css.map?id=f7ce9ca49027594ac402", + "/css/dist/all.css": "/css/dist/all.css?id=98db4e9b7650453c8b00", + "/js/dist/all.js": "/js/dist/all.js?id=114f1025a1b3e8975476", + "/css/build/all.css": "/css/build/all.css?id=98db4e9b7650453c8b00", + "/js/build/all.js": "/js/build/all.js?id=114f1025a1b3e8975476" +>>>>>>> hotfixes/2fa_qr } diff --git a/resources/assets/js/components/importer/importer-file.vue b/resources/assets/js/components/importer/importer-file.vue index afcd151ee5..21deb263a8 100644 --- a/resources/assets/js/components/importer/importer-file.vue +++ b/resources/assets/js/components/importer/importer-file.vue @@ -40,9 +40,8 @@ -
{{ this.statusText }}
diff --git a/resources/assets/js/snipeit.js b/resources/assets/js/snipeit.js index 1fb74cfc82..ae22d560d9 100755 --- a/resources/assets/js/snipeit.js +++ b/resources/assets/js/snipeit.js @@ -346,7 +346,18 @@ $(document).ready(function () { } function formatDataSelection (datalist) { - return datalist.text; + // This a heinous workaround for a known bug in Select2. + // Without this, the rich selectlists are vulnerable to XSS. + // Many thanks to @uberbrady for this fix. It ain't pretty, + // but it resolves the issue until Select2 addresses it on their end. + // + // Bug was reported in 2016 :{ + // https://github.com/select2/select2/issues/4587 + + return datalist.text.replace(/>/g, '>') + .replace(/ 'Zip', 'noimage' => 'No image uploaded or image not found.', 'token_expired' => 'Your form session has expired. Please try again.', + 'login_enabled' => 'Login Enabled', ]; diff --git a/resources/views/auth/two_factor_enroll.blade.php b/resources/views/auth/two_factor_enroll.blade.php index 1fe9c89c9b..18003a5d73 100644 --- a/resources/views/auth/two_factor_enroll.blade.php +++ b/resources/views/auth/two_factor_enroll.blade.php @@ -28,7 +28,7 @@
- + {!! $barcode_obj->getHtmlDiv() !!}
diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 2d84259449..c28e56a51a 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -509,7 +509,7 @@ @endcan - @can('create', \App\Models\Asset::class) + @can('import') diff --git a/resources/views/settings/general.blade.php b/resources/views/settings/general.blade.php index f5fab70906..7ebb312a71 100644 --- a/resources/views/settings/general.blade.php +++ b/resources/views/settings/general.blade.php @@ -61,7 +61,7 @@
- {{ Form::label('full_multiple_companies_support', + {{ Form::label('require_accept_signature', trans('admin/settings/general.require_accept_signature')) }}
@@ -166,7 +166,7 @@
- {{ Form::label('per_page', trans('admin/settings/general.default_eula_text')) }} + {{ Form::label('default_eula_text', trans('admin/settings/general.default_eula_text')) }}
{{ Form::textarea('default_eula_text', Input::old('default_eula_text', $setting->default_eula_text), array('class' => 'form-control','placeholder' => 'Add your default EULA text')) }} diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index 05a5f8629c..c805c70ac7 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -123,22 +123,22 @@ @if (!is_null($user->company)) - + @endif - + - + - + - + @endif @if ($user->employee_num) - + @endif @if ($user->manager) - + - + @endif @if ($user->phone) - + @endif @if ($user->userloc) - + @@ -206,14 +206,14 @@ @endif @if ($user->last_login) - + @endif @if (!is_null($user->department)) - + @endif @@ -223,6 +223,45 @@ @endif + + + + + + @if ($user->activated=='1') + + + + + + + + + + @endif + +
{{ trans('general.company') }}{{ trans('general.company') }} {{ $user->company->name }}
{{ trans('admin/users/table.name') }}{{ trans('admin/users/table.name') }} {{ $user->present()->fullName() }}
{{ trans('admin/users/table.username') }}{{ trans('admin/users/table.username') }} {{ $user->username }}
{{ trans('general.groups') }}{{ trans('general.groups') }} @if ($user->groups->count() > 0) @foreach ($user->groups as $group) @@ -160,21 +160,21 @@ @if ($user->jobtitle)
{{ trans('admin/users/table.job') }}{{ trans('admin/users/table.job') }} {{ $user->jobtitle }}
{{ trans('admin/users/table.employee_num') }}{{ trans('admin/users/table.employee_num') }} {{ $user->employee_num }}
{{ trans('admin/users/table.manager') }}{{ trans('admin/users/table.manager') }} {{ $user->manager->getFullNameAttribute() }} @@ -184,21 +184,21 @@ @if ($user->email)
{{ trans('admin/users/table.email') }}{{ trans('admin/users/table.email') }} {{ $user->email }}
{{ trans('admin/users/table.phone') }}{{ trans('admin/users/table.phone') }} {{ $user->phone }}
{{ trans('admin/users/table.location') }}{{ trans('admin/users/table.location') }} {{ link_to_route('locations.show', $user->userloc->name, [$user->userloc->id]) }}
{{ trans('general.last_login') }}{{ trans('general.last_login') }} {{ \App\Helpers\Helper::getFormattedDateObject($user->last_login, 'datetime', false) }}
{{ trans('general.department') }}{{ trans('general.department') }} {{ $user->department->name }}
{{ $user->created_at->format('F j, Y h:iA') }}
{{ trans('general.login_enabled') }}{{ ($user->activated=='1') ? trans('general.yes') : trans('general.no') }}
{{ trans('admin/users/general.two_factor_active') }}{{ ($user->two_factor_active()) ? trans('general.yes') : trans('general.no') }}
{{ trans('admin/users/general.two_factor_enrolled') }} +
+
+ {{ ($user->two_factor_active_and_enrolled()) ? trans('general.yes') : trans('general.no') }} +
+ + @if ((Auth::user()->isSuperUser()) && ($snipeSettings->two_factor_enabled!='0')) +
+ {{ trans('admin/settings/general.two_factor_reset') }} + + + + + + + +

{{ trans('admin/settings/general.two_factor_reset_help') }}

+
+
+ @endif + +
@@ -532,6 +571,40 @@ @include ('partials.bootstrap-table', ['simple_view' => true])