User configurable locale (language) (#10204)
* Support for system APP_LOCALE * Start preferences re-write * port 2fa form * Working user preferences * Language user preference * Don't look up locale from the DB every request * Device list working * Deny demo user middleware * Finish password changing * remove used resource methods * remove leftover use * warn that translation is incomplete * fix style
This commit is contained in:
parent
90bb68f026
commit
90a67c2ece
|
@ -55,7 +55,7 @@ class TwoFactor
|
|||
/**
|
||||
* Base32 Decoding dictionary
|
||||
*/
|
||||
private static $base32 = array(
|
||||
private static $base32 = [
|
||||
"A" => 0,
|
||||
"B" => 1,
|
||||
"C" => 2,
|
||||
|
@ -88,7 +88,7 @@ class TwoFactor
|
|||
"5" => 29,
|
||||
"6" => 30,
|
||||
"7" => 31
|
||||
);
|
||||
];
|
||||
|
||||
/**
|
||||
* Base32 Encoding dictionary
|
||||
|
@ -195,4 +195,20 @@ class TwoFactor
|
|||
(ord($hash[$offset + 3]) & 0xff)) % pow(10, self::OTP_SIZE);
|
||||
return str_pad($truncated, self::OTP_SIZE, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate 2fa URI
|
||||
* @param string $username
|
||||
* @param string $key
|
||||
* @param bool $counter if type is counter (false for time based)
|
||||
* @return string
|
||||
*/
|
||||
public static function generateUri($username, $key, $counter = false)
|
||||
{
|
||||
$title = "LibreNMS:" . urlencode($username);
|
||||
|
||||
return $counter ?
|
||||
"otpauth://hotp/$title?issuer=LibreNMS&counter=1&secret=$key" : // counter based
|
||||
"otpauth://totp/$title?issuer=LibreNMS&secret=$key"; // time based
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ class TwoFactorController extends Controller
|
|||
|
||||
return view('auth.2fa')->with([
|
||||
'key' => $twoFactorSettings['key'],
|
||||
'uri' => $this->genUri($request->user(), $twoFactorSettings),
|
||||
'uri' => TwoFactor::generateUri($request->user()->username, $twoFactorSettings['key'], $twoFactorSettings['counter'] !== false),
|
||||
])->withErrors($errors);
|
||||
}
|
||||
|
||||
|
@ -211,18 +211,4 @@ class TwoFactorController extends Controller
|
|||
|
||||
return UserPref::getPref($user, 'twofactor');
|
||||
}
|
||||
|
||||
private function genUri($user, $settings)
|
||||
{
|
||||
$title = "LibreNMS:" . urlencode($user->username);
|
||||
$key = $settings['key'];
|
||||
|
||||
// time based
|
||||
if ($settings['counter'] === false) {
|
||||
return "otpauth://totp/$title?issuer=LibreNMS&secret=$key";
|
||||
}
|
||||
|
||||
// counter based
|
||||
return "otpauth://hotp/$title?issuer=LibreNMS&counter=1&secret=$key";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,15 +30,18 @@ use App\Http\Requests\UpdateUserRequest;
|
|||
use App\Models\Dashboard;
|
||||
use App\Models\User;
|
||||
use App\Models\UserPref;
|
||||
use Hash;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use LibreNMS\Authentication\LegacyAuth;
|
||||
use LibreNMS\Config;
|
||||
use Toastr;
|
||||
use URL;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('deny-demo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
|
@ -159,9 +162,8 @@ class UserController extends Controller
|
|||
}
|
||||
|
||||
$user->fill($request->all());
|
||||
$user->can_modify_passwd = $request->get('can_modify_passwd'); // checkboxes are missing when unchecked
|
||||
|
||||
if ($this->updateDashboard($user, $request->get('dashboard'))) {
|
||||
if ($request->has('dashboard') && $this->updateDashboard($user, $request->get('dashboard'))) {
|
||||
Toastr::success(__('Updated dashboard for :username', ['username' => $user->username]));
|
||||
}
|
||||
|
||||
|
@ -174,7 +176,7 @@ class UserController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
return redirect(route('users.index'));
|
||||
return redirect(route(str_contains(URL::previous(), 'preferences') ? 'preferences.index' : 'users.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/**
|
||||
* UserPreferencesController.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2019 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Dashboard;
|
||||
use App\Models\Device;
|
||||
use App\Models\UserPref;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use LibreNMS\Authentication\LegacyAuth;
|
||||
use LibreNMS\Authentication\TwoFactor;
|
||||
use LibreNMS\Config;
|
||||
use Session;
|
||||
|
||||
class UserPreferencesController extends Controller
|
||||
{
|
||||
private $valid_prefs = [
|
||||
'dashboard' => 'required|integer',
|
||||
'add_schedule_note_to_device' => 'required|integer',
|
||||
'locale' => 'required|in:en,ru',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('deny-demo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = [
|
||||
'user' => $user,
|
||||
'can_change_password' => LegacyAuth::get()->canUpdatePasswords($user->username),
|
||||
'dashboards' => Dashboard::allAvailable($user)->with('user')->get(),
|
||||
'default_dashboard' => UserPref::getPref($user, 'dashboard'),
|
||||
'note_to_device' => UserPref::getPref($user, 'add_schedule_note_to_device'),
|
||||
'locale' => UserPref::getPref($user, 'locale') ?: 'en',
|
||||
'locales' => [
|
||||
'en' => 'English',
|
||||
'ru' => 'русский',
|
||||
],
|
||||
];
|
||||
|
||||
if (Config::get('twofactor')) {
|
||||
$twofactor = UserPref::getPref($user, 'twofactor');
|
||||
if ($twofactor) {
|
||||
$data['twofactor_uri'] = TwoFactor::generateUri($user->username, $twofactor['key'], $twofactor['counter'] !== false);
|
||||
}
|
||||
$data['twofactor'] = $twofactor;
|
||||
}
|
||||
|
||||
if (!$user->hasGlobalRead()) {
|
||||
$data['devices'] = Device::hasAccess($user)->get();
|
||||
}
|
||||
|
||||
return view('user.preferences', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'pref' => ['required', Rule::in(array_keys($this->valid_prefs))],
|
||||
'value' => $this->valid_prefs[$request->pref] ?? 'required|integer',
|
||||
]);
|
||||
|
||||
UserPref::setPref($request->user(), $request->pref, $request->value);
|
||||
|
||||
if ($request->pref == 'locale') {
|
||||
Session::put('locale', $request->value);
|
||||
}
|
||||
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ class Kernel extends HttpKernel
|
|||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\App\Http\Middleware\SetLocale::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\App\Http\Middleware\LegacyExternalAuth::class,
|
||||
|
@ -66,6 +67,7 @@ class Kernel extends HttpKernel
|
|||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'deny-demo' => \App\Http\Middleware\DenyDemoUser::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class DenyDemoUser
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($request->user()->isDemo()) {
|
||||
return response()->view('auth.deny-demo');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App;
|
||||
use App\Models\UserPref;
|
||||
use Closure;
|
||||
use Session;
|
||||
|
||||
class SetLocale
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (Session::has('locale')) {
|
||||
$locale = Session::get('locale');
|
||||
} elseif (!is_null($request->user())) {
|
||||
$locale = UserPref::getPref($request->user(), 'locale');
|
||||
Session::put('locale', $locale);
|
||||
}
|
||||
|
||||
if (!empty($locale)) {
|
||||
App::setLocale($locale);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
|
@ -43,6 +43,7 @@ class UpdateUserRequest extends FormRequest
|
|||
'level' => 'int',
|
||||
'old_password' => 'nullable|string',
|
||||
'new_password' => 'nullable|confirmed|min:' . Config::get('password.min_length', 8),
|
||||
'new_password_confirmation' => 'nullable|same:new_password',
|
||||
'dashboard' => 'int',
|
||||
];
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'locale' => 'en',
|
||||
'locale' => env('APP_LOCALE', 'en'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -1,223 +0,0 @@
|
|||
<?php
|
||||
|
||||
use LibreNMS\Authentication\LegacyAuth;
|
||||
use LibreNMS\Authentication\TwoFactor;
|
||||
|
||||
$no_refresh = true;
|
||||
|
||||
$pagetitle[] = 'Preferences';
|
||||
|
||||
echo '<h2>User Preferences</h2>';
|
||||
echo '<hr>';
|
||||
|
||||
if (LegacyAuth::user()->isDemoUser()) {
|
||||
demo_account();
|
||||
} else {
|
||||
if ($_POST['action'] == 'changepass') {
|
||||
if (LegacyAuth::get()->authenticate(['username' => LegacyAuth::user()->username, 'password' => $_POST['old_pass']])) {
|
||||
if ($_POST['new_pass'] == '' || $_POST['new_pass2'] == '') {
|
||||
$changepass_message = 'Password must not be blank.';
|
||||
} elseif ($_POST['new_pass'] == $_POST['new_pass2']) {
|
||||
LegacyAuth::get()->changePassword(LegacyAuth::user()->username, $_POST['new_pass']);
|
||||
$changepass_message = 'Password Changed.';
|
||||
} else {
|
||||
$changepass_message = "Passwords don't match.";
|
||||
}
|
||||
} else {
|
||||
$changepass_message = 'Incorrect password';
|
||||
}
|
||||
}
|
||||
if ($vars['action'] === 'changedash') {
|
||||
if (!empty($vars['dashboard'])) {
|
||||
set_user_pref('dashboard', (int)$vars['dashboard']);
|
||||
$updatedashboard_message = "User default dashboard updated";
|
||||
}
|
||||
}
|
||||
if ($vars['action'] === 'changenote') {
|
||||
set_user_pref('add_schedule_note_to_device', (bool)$vars['notetodevice']);
|
||||
if ($vars['notetodevice']) {
|
||||
$updatenote_message = "Schedule notes will now be added to device notes";
|
||||
} else {
|
||||
$updatenote_message = "Schedule notes will no longer be added to device notes";
|
||||
}
|
||||
}
|
||||
|
||||
include 'includes/html/update-preferences-password.inc.php';
|
||||
|
||||
if (LegacyAuth::get()->canUpdatePasswords(LegacyAuth::user()->username)) {
|
||||
echo '<h3>Change Password</h3>';
|
||||
echo '<hr>';
|
||||
echo "<div class='well'>";
|
||||
echo $changepass_message;
|
||||
echo "<form method='post' action='preferences/' class='form-horizontal' role='form'>
|
||||
<input type=hidden name='action' value='changepass'>
|
||||
<div class='form-group'>
|
||||
<label for='old_pass' class='col-sm-2 control-label'>Current Password</label>
|
||||
<div class='col-sm-4'>
|
||||
<input type=password name=old_pass autocomplete='off' class='form-control input-sm'>
|
||||
</div>
|
||||
<div class='col-sm-6'>
|
||||
</div>
|
||||
</div>
|
||||
<div class='form-group'>
|
||||
<label for='new_pass' class='col-sm-2 control-label'>New Password</label>
|
||||
<div class='col-sm-4'>
|
||||
<input type=password name=new_pass autocomplete='off' class='form-control input-sm'>
|
||||
</div>
|
||||
<div class='col-sm-6'>
|
||||
</div>
|
||||
</div>
|
||||
<div class='form-group'>
|
||||
<label for='new_pass2' class='col-sm-2 control-label'>New Password</label>
|
||||
<div class='col-sm-4'>
|
||||
<input type=password name=new_pass2 autocomplete='off' class='form-control input-sm'>
|
||||
<br>
|
||||
<center><button type='submit' class='btn btn-default'>Submit</button></center>
|
||||
</div>
|
||||
<div class='col-sm-6'>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>";
|
||||
echo '</div>';
|
||||
}//end if
|
||||
|
||||
if ($config['twofactor'] === true) {
|
||||
$twofactor = get_user_pref('twofactor');
|
||||
echo '<script src="js/jquery.qrcode.min.js"></script>';
|
||||
echo '<h3>Two-Factor Authentication</h3>';
|
||||
echo '<hr>';
|
||||
echo '<div class="well">';
|
||||
if (!empty($twofactor)) {
|
||||
$twofactor['text'] = "<div class='form-group'>
|
||||
<label for='twofactorkey' class='col-sm-2 control-label'>Secret Key</label>
|
||||
<div class='col-sm-4'>
|
||||
<input type='text' name='twofactorkey' autocomplete='off' disabled class='form-control input-sm' value='".$twofactor['key']."' />
|
||||
</div>
|
||||
</div>";
|
||||
if ($twofactor['counter'] !== false) {
|
||||
$twofactor['uri'] = 'otpauth://hotp/'.LegacyAuth::user()->username.'?issuer=LibreNMS&counter='.$twofactor['counter'].'&secret='.$twofactor['key'];
|
||||
$twofactor['text'] .= "<div class='form-group'>
|
||||
<label for='twofactorcounter' class='col-sm-2 control-label'>Counter</label>
|
||||
<div class='col-sm-4'>
|
||||
<input type='text' name='twofactorcounter' autocomplete='off' disabled class='form-control input-sm' value='".$twofactor['counter']."' />
|
||||
</div>
|
||||
</div>";
|
||||
} else {
|
||||
$twofactor['uri'] = 'otpauth://totp/'.LegacyAuth::user()->username.'?issuer=LibreNMS&secret='.$twofactor['key'];
|
||||
}
|
||||
|
||||
echo '<div id="twofactorqrcontainer">
|
||||
<div id="twofactorqr"></div>
|
||||
<button class="btn btn-default" onclick="$(\'#twofactorkeycontainer\').show(); $(\'#twofactorqrcontainer\').hide();">Manual</button>
|
||||
</div>';
|
||||
echo '<div id="twofactorkeycontainer">
|
||||
<form id="twofactorkey" class="form-horizontal" role="form">'.$twofactor['text'].'</form>
|
||||
<button class="btn btn-default" onclick="$(\'#twofactorkeycontainer\').hide(); $(\'#twofactorqrcontainer\').show();">QR</button>
|
||||
</div>';
|
||||
echo '<script>$("#twofactorqr").qrcode({"text": "'.$twofactor['uri'].'"}); $("#twofactorkeycontainer").hide();</script>';
|
||||
echo '<br/><form method="post" class="form-horizontal" role="form" action="2fa/remove">
|
||||
<button class="btn btn-danger" type="submit">Disable TwoFactor</button>
|
||||
</form>';
|
||||
} else {
|
||||
echo '<form method="post" class="form-horizontal" role="form" action="2fa/add">
|
||||
<div class="form-group">
|
||||
<label for="twofactortype" class="col-sm-2 control-label">TwoFactor Type</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="twofactortype" class="select form-control">
|
||||
<option value="time">Time Based (TOTP)</option>
|
||||
<option value="counter">Counter Based (HOTP)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-2">
|
||||
<button class="btn btn-default" type="submit" id="twofactor-generate">Generate TwoFactor Secret Key</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>';
|
||||
}//end if
|
||||
echo '</div>';
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
echo "<h3>Default Dashboard</h3>
|
||||
<hr>
|
||||
<div class='well'>";
|
||||
if (!empty($updatedashboard_message)) {
|
||||
print_message($updatedashboard_message);
|
||||
}
|
||||
echo "
|
||||
<form method='post' action='preferences/' class='form-horizontal' role='form'>
|
||||
<div class='form-group'>
|
||||
<input type=hidden name='action' value='changedash'>
|
||||
<div class='form-group'>
|
||||
<label for='dashboard' class='col-sm-2 control-label'>Dashboard</label>
|
||||
<div class='col-sm-4'>
|
||||
<select class='form-control' name='dashboard'>";
|
||||
foreach (get_dashboards() as $dash) {
|
||||
echo "
|
||||
<option value='".$dash['dashboard_id']."'".($dash['default'] ? ' selected' : '').">".display($dash['username']).':'.display($dash['dashboard_name'])."</option>";
|
||||
}
|
||||
echo '
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-2"><button type="submit" class="btn btn-default">Update Dashboard</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>';
|
||||
|
||||
|
||||
echo "<h3>Add schedule notes to devices notes</h3>
|
||||
<hr>
|
||||
<div class='well'>";
|
||||
if (!empty($updatenote_message)) {
|
||||
print_message($updatenote_message);
|
||||
}
|
||||
echo "
|
||||
<form method='post' action='preferences/' class='form-horizontal' role='form'>
|
||||
<div class='form-group'>
|
||||
<input type=hidden name='action' value='changenote'>
|
||||
<div class='form-group'>
|
||||
<label for='dashboard' class='col-sm-3 control-label'>Add schedule notes to devices notes</label>
|
||||
<div class='col-sm-4'>
|
||||
<input id='notetodevice' type='checkbox' name='notetodevice' data-size='small' " . ((get_user_pref('add_schedule_note_to_device', false)) ? 'checked' : '') . ">
|
||||
</div>
|
||||
</div>
|
||||
<div class='form-group'>
|
||||
<div class='col-sm-4 col-sm-offset-3'>
|
||||
<button type='submit' class='btn btn-default'>Update preferences</button>
|
||||
</div>
|
||||
<div class='col-sm-6'></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>";
|
||||
|
||||
|
||||
|
||||
echo "<h3>Device Permissions</h3>";
|
||||
echo "<hr>";
|
||||
echo '<div class="well">';
|
||||
if (LegacyAuth::user()->hasGlobalAdmin()) {
|
||||
echo "<strong class='blue'>Global Administrative Access</strong>";
|
||||
} elseif (LegacyAuth::user()->hasGlobalRead()) {
|
||||
echo "<strong class='green'>Global Viewing Access</strong>";
|
||||
} else {
|
||||
foreach (dbFetchRows('SELECT * FROM `devices_perms` AS P, `devices` AS D WHERE `user_id` = ? AND P.device_id = D.device_id', array(LegacyAuth::id())) as $perm) {
|
||||
// FIXME generatedevicelink?
|
||||
echo "<a href='device/device=".$perm['device_id']."'>".$perm['hostname'].'</a><br />';
|
||||
$dev_access = 1;
|
||||
}
|
||||
|
||||
if (!$dev_access) {
|
||||
echo 'No access!';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
echo "<script>$(\"[name='notetodevice']\").bootstrapSwitch('offColor','danger');</script>";
|
|
@ -0,0 +1,11 @@
|
|||
@extends('layouts.librenmsv1')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="alert alert-danger col-md-6 col-md-offset-3"><i class="fa fa-fw fa-exclamation-circle" aria-hidden="true"></i>
|
||||
@lang('You are logged in as a demo account, this page is not accessible to you')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
|
@ -108,6 +108,7 @@
|
|||
|
||||
@yield('content')
|
||||
|
||||
@yield('scripts')
|
||||
|
||||
{!! Toastr::render() !!}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
<div class="col-sm-9 col-sm-offset-3">
|
||||
<div class="checkbox">
|
||||
<label class="checkbox-inline">
|
||||
<input type="hidden" value="0" name="can_modify_passwd">
|
||||
<input type="checkbox" id="can_modify_passwd" name="can_modify_passwd" @if(old('can_modify_passwd', $user->can_modify_passwd)) checked @endif> @lang('Can Modify Password')
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
@extends('layouts.librenmsv1')
|
||||
|
||||
@section('title', __('Preferences'))
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<row>
|
||||
<legend>@lang('User Preferences')</legend>
|
||||
</row>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($can_change_password)
|
||||
<div class="panel panel-default panel-condensed">
|
||||
<div class="panel-heading">@lang('Change Password')</div>
|
||||
<div class="panel-body">
|
||||
<form method="POST" action="{{ route('users.update', [$user->user_id]) }}" class="form-horizontal" role="form">
|
||||
<input type="hidden" name="_method" value="PATCH">
|
||||
<div class="form-group">
|
||||
<label for="old_password" class="col-sm-4 control-label">@lang('Current Password')</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="old_password" autocomplete="off" class="form-control input-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password" class="col-sm-4 control-label">@lang('New Password')</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="new_password" autocomplete="off" class="form-control input-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password_confirmation" class="col-sm-4 control-label">@lang('Verify New Password')</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="new_password_confirmation" autocomplete="off" class="form-control input-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-3">
|
||||
<button type="submit" class="btn btn-default">@lang('Change Password')</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="panel panel-default panel-condensed">
|
||||
<div class="panel-heading">@lang('Preferences')</div>
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label for="dashboard" class="col-sm-4 control-label">@lang('Dashboard')</label>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control ajax-select" name="dashboard" data-pref="dashboard" data-previous="{{ $default_dashboard }}">
|
||||
@foreach($dashboards as $dash)
|
||||
<option value="{{ $dash->dashboard_id }}" @if($dash->dashboard_id == $default_dashboard) selected @endif>{{ $dash->user ? $dash->user->username : __('<deleted>') }}:{{ $dash->dashboard_name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="locale" class="col-sm-4 control-label">@lang('Language')</label>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control ajax-select" name="locale" data-pref="locale" data-previous="{{ $locale }}">
|
||||
@foreach($locales as $lang => $descr)
|
||||
<option value="{{ $lang }}" @if($lang == $locale) selected @endif>{{ $descr }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<small>* @lang('Translation not fully supported')</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="notetodevice" class="col-sm-4 control-label">@lang('Add schedule notes to devices notes')</label>
|
||||
<div class="col-sm-4">
|
||||
<input id="notetodevice" type="checkbox" name="notetodevice" @if($note_to_device) checked @endif>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@config('twofactor')
|
||||
<div class="panel panel-default panel-condensed">
|
||||
<div class="panel-heading">@lang('Two-Factor Authentication')</div>
|
||||
<div class="panel-body">
|
||||
@if($twofactor)
|
||||
<div id="twofactorqrcontainer">
|
||||
<div id="twofactorqr"></div>
|
||||
<script>$("#twofactorqr").qrcode({"text": "{{ $twofactor_uri }}"});</script>
|
||||
<button class="btn btn-default" onclick="$('#twofactorkeycontainer').show(); $('#twofactorqrcontainer').hide();">@lang('Manual')</button>
|
||||
</div>
|
||||
<div id="twofactorkeycontainer">
|
||||
<form id="twofactorkey" class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label for="twofactorkey" class="col-sm-4 control-label">@lang('Secret Key')</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="twofactorkey" autocomplete="off" disabled class="form-control input-sm" value="{{ $twofactor['key'] }}" />
|
||||
</div>
|
||||
</div>
|
||||
@if($twofactor['counter'] !== false)
|
||||
<div class="form-group">
|
||||
<label for="twofactorcounter" class="col-sm-4 control-label">@lang('Counter')</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" name="twofactorcounter" autocomplete="off" disabled class="form-control input-sm" value="{{ $twofactor['counter'] }}" />
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
<button class="btn btn-default" onclick="$('#twofactorkeycontainer').hide(); $('#twofactorqrcontainer').show();">@lang('QR')</button>
|
||||
</div>
|
||||
<br/>
|
||||
<form method="post" class="form-horizontal" role="form" action="{{ route('2fa.remove') }}">
|
||||
<button class="btn btn-danger" type="submit">@lang('Disable TwoFactor')</button>
|
||||
</form>
|
||||
@else
|
||||
<form method="post" class="form-horizontal" role="form" action="{{ route('2fa.add') }}">
|
||||
<div class="form-group">
|
||||
<label for="twofactortype" class="col-sm-4 control-label">@lang('TwoFactor Type')</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="twofactortype" class="select form-control">
|
||||
<option value="time">@lang('Time Based (TOTP)')</option>
|
||||
<option value="counter">@lang('Counter Based (HOTP)')</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-3">
|
||||
<button class="btn btn-default" type="submit" id="twofactor-generate">@lang('Generate TwoFactor Secret Key')</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endconfig
|
||||
|
||||
<div class="panel panel-default panel-condensed">
|
||||
<div class="panel-heading">@lang('Device Permissions')</div>
|
||||
<div class="panel-body">
|
||||
@if(auth()->user()->hasGlobalAdmin())
|
||||
<strong class="blue">@lang('Global Administrative Access')</strong>
|
||||
@elseif(auth()->user()->hasGlobalRead())
|
||||
<strong class="green">@lang('Global Viewing Access')</strong>
|
||||
@else
|
||||
@forelse($devices as $device)
|
||||
{!! \LibreNMS\Util\Url::deviceLink($device) !!} <br />
|
||||
@empty
|
||||
<strong class="red">@lang('No access!')</strong>
|
||||
@endforelse
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('javascript')
|
||||
<script src="{{ asset('js/jquery.qrcode.min.js') }}"></script>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
$("[name='notetodevice']")
|
||||
.bootstrapSwitch('offColor', 'danger')
|
||||
.on('switchChange.bootstrapSwitch', function (e, state) {
|
||||
var $this = $(this);
|
||||
$.ajax({
|
||||
url: '{{ route('preferences.store') }}',
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: {
|
||||
pref: 'add_schedule_note_to_device',
|
||||
value: state ? 1 : 0
|
||||
},
|
||||
success: function () {
|
||||
$this.closest('.form-group').addClass('has-success');
|
||||
setTimeout(function () {
|
||||
$this.closest('.form-group').removeClass('has-success');
|
||||
}, 2000);
|
||||
},
|
||||
error: function () {
|
||||
$this.bootstrapSwitch('toggleState', true);
|
||||
$this.closest('.form-group').addClass('has-error');
|
||||
setTimeout(function(){
|
||||
$this.closest('.form-group').removeClass('has-error');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.ajax-select').change(function () {
|
||||
var $this = $(this);
|
||||
var value = $this.val();
|
||||
console.log($this.data('pref'));
|
||||
$.ajax({
|
||||
url: '{{ route('preferences.store') }}',
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: {
|
||||
pref: $this.data('pref'),
|
||||
value: value
|
||||
},
|
||||
success: function () {
|
||||
$this.data('previous', value);
|
||||
$this.closest('.form-group').addClass('has-success');
|
||||
setTimeout(function () {
|
||||
$this.closest('.form-group').removeClass('has-success');
|
||||
}, 2000);
|
||||
},
|
||||
error: function () {
|
||||
$this.val($this.data('previous'));
|
||||
$this.closest('.form-group').addClass('has-error');
|
||||
setTimeout(function(){
|
||||
$this.closest('.form-group').removeClass('has-error');
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@section('css')
|
||||
<style>
|
||||
#twofactorkeycontainer { display: none; }
|
||||
</style>
|
||||
@endsection
|
|
@ -23,6 +23,8 @@ Route::group(['middleware' => ['auth', '2fa'], 'guard' => 'auth'], function () {
|
|||
|
||||
// pages
|
||||
Route::get('locations', 'LocationController@index');
|
||||
Route::resource('preferences', 'UserPreferencesController', ['only' => ['index', 'store']]);
|
||||
Route::resource('users', 'UserController');
|
||||
|
||||
// old route redirects
|
||||
Route::permanentRedirect('poll-log', 'pollers/tab=log/');
|
||||
|
@ -31,7 +33,7 @@ Route::group(['middleware' => ['auth', '2fa'], 'guard' => 'auth'], function () {
|
|||
Route::group(['prefix' => '2fa', 'namespace' => 'Auth'], function () {
|
||||
Route::get('', 'TwoFactorController@showTwoFactorForm')->name('2fa.form');
|
||||
Route::post('', 'TwoFactorController@verifyTwoFactor')->name('2fa.verify');
|
||||
Route::post('add', 'TwoFactorController@create');
|
||||
Route::post('add', 'TwoFactorController@create')->name('2fa.add');
|
||||
Route::post('cancel', 'TwoFactorController@cancelAdd')->name('2fa.cancel');
|
||||
Route::post('remove', 'TwoFactorController@destroy')->name('2fa.remove');
|
||||
|
||||
|
@ -39,8 +41,6 @@ Route::group(['middleware' => ['auth', '2fa'], 'guard' => 'auth'], function () {
|
|||
Route::delete('{user}', 'TwoFactorManagementController@destroy')->name('2fa.delete');
|
||||
});
|
||||
|
||||
Route::resource('users', 'UserController');
|
||||
|
||||
// Ajax routes
|
||||
Route::group(['prefix' => 'ajax'], function () {
|
||||
// page ajax controllers
|
||||
|
|
Loading…
Reference in New Issue