add contents

This commit is contained in:
Trevor Batley
2025-10-09 15:04:29 +11:00
parent 170362eec1
commit bce7dd054a
2537 changed files with 301282 additions and 0 deletions

25
lib/plugins/loglog/README Normal file
View File

@@ -0,0 +1,25 @@
loglog Plugin for DokuWiki
All documentation for this plugin can be found at
http://www.dokuwiki.org/plugin:loglog
If you install this plugin manually, make sure it is installed in
lib/plugins/loglog/ - if the folder is called different it
will not work!
Please refer to http://www.dokuwiki.org/plugins for additional info
on how to install plugins in DokuWiki.
----
Copyright (C) Andreas Gohr <andi@splitbrain.org>
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; version 2 of the License
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.
See the COPYING file in your DokuWiki folder for details

View File

@@ -0,0 +1,60 @@
<?php
namespace dokuwiki\plugin\loglog\test;
/**
* Tests for the loglog plugin
*
* @group plugin_loglog
* @group plugins
*
*/
class Logging_loglog_test extends \DokuWikiTest
{
/**
* @var \helper_plugin_loglog_logging
*/
protected $logHelper;
public function setUp()
{
$this->pluginsEnabled[] = 'loglog';
parent::setUp();
$this->logHelper = plugin_load('helper', 'loglog_logging');
}
public function test_readLinesInRange()
{
$min = strtotime('2020-10-01');
$max = strtotime('2020-10-31');
$expected = 4;
$actual = count($this->logHelper->readLines($min, $max));
$this->assertEquals($expected, $actual);
}
public function test_reportStats()
{
$min = strtotime('2020-11-01');
$max = strtotime('2020-11-30');
$lines = $this->logHelper->readLines($min, $max);
/** @var \helper_plugin_loglog_report $reportHelper */
$reportHelper = plugin_load('helper', 'loglog_report');
$actual = $reportHelper->getStats($lines);
$expected = [
\helper_plugin_loglog_main::LOGTYPE_AUTH_OK => 1,
\helper_plugin_loglog_main::LOGTYPE_AUTH_FAIL => 2,
'users' => 1,
'admin' => [
'start' => 1,
'usermanager' => 1,
]
];
$this->assertEquals($expected, $actual);
}
}

View File

@@ -0,0 +1,12 @@
1598914860 2020/09/01 01:01 127.0.0.1 admin failed login attempt
1599004920 2020/09/02 02:02 127.0.0.1 admin logged in temporarily
1599094980 2020/09/03 03:03 127.0.0.1 admin logged off
1601506860 2020/10/01 01:01 127.0.0.1 testuser logged in temporarily
1601596920 2020/10/02 02:02 127.0.0.1 admin logged in temporarily
1601686980 2020/10/03 03:03 127.0.0.1 admin admin
1601777040 2020/10/04 04:04 127.0.0.1 admin admin - usermanager ["delete user","user1"]
1604188860 2020/11/01 01:01 127.0.0.1 testuser logged in temporarily
1604278920 2020/11/02 02:02 127.0.0.1 admin admin
1604368980 2020/11/03 03:03 127.0.0.1 admin admin - usermanager
1604459040 2020/11/04 04:04 127.0.0.1 fakeuser failed login attempt
1604549100 2020/11/05 05:05 127.0.0.1 fakeuser failed login attempt

View File

@@ -0,0 +1,300 @@
<?php
/**
* Login/Logout logging plugin
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <gohr@cosmocode.de>
*/
class action_plugin_loglog extends DokuWiki_Action_Plugin
{
/**
* @var \helper_plugin_loglog_logging
*/
protected $logHelper;
/**
* @var \helper_plugin_loglog_main
*/
protected $mainHelper;
/**
* @var \helper_plugin_loglog_alert
*/
protected $alertHelper;
public function __construct()
{
$this->mainHelper = $this->loadHelper('loglog_main');
$this->logHelper = $this->loadHelper('loglog_logging');
$this->alertHelper = $this->loadHelper('loglog_alert');
}
/** @inheritDoc */
function register(Doku_Event_Handler $controller)
{
// tasks to perform on login/logoff
$controller->register_hook(
'ACTION_ACT_PREPROCESS',
'BEFORE',
$this,
'handleAuth'
);
// allow other plugins to emit logging events
$controller->register_hook(
'PLUGIN_LOGLOG_LOG',
'BEFORE',
$this,
'handleCustom'
);
// autologout plugin
$controller->register_hook(
'ACTION_AUTH_AUTOLOGOUT',
'BEFORE',
$this,
'handleAutologout'
);
// log admin access
$controller->register_hook(
'ACTION_ACT_PREPROCESS',
'BEFORE',
$this,
'handleAdminAccess'
);
// log user modifications
$controller->register_hook(
'AUTH_USER_CHANGE',
'BEFORE',
$this,
'handleUsermod'
);
// log admin actions triggered via Ajax
$controller->register_hook(
'AJAX_CALL_UNKNOWN',
'AFTER',
$this,
'handleAjax'
);
// log other admin actions
$controller->register_hook(
'DOKUWIKI_STARTED',
'AFTER',
$this,
'handleOther'
);
// log other admin actions
$controller->register_hook(
'INDEXER_TASKS_RUN',
'AFTER',
$this,
'handleReport'
);
}
/**
* Log login/logoff actions and optionally trigger alerts
* if configured thresholds have just been exceeded
*
* @param $msg
* @param null|string $user
*/
protected function logAuth($msg, $user = null)
{
$this->logHelper->writeLine($msg, $user);
// trigger alert notifications if necessary
$this->alertHelper->checkAlertThresholds();
}
/**
* Log usage of admin tools
*
* @param array $data
* @param string $more
*/
protected function logAdmin(array $data = [], $more = '')
{
global $INPUT;
$msg = 'admin';
$page = $INPUT->str('page');
if ($page) $msg .= " - $page";
if ($more && $more !== $page) $msg .= " - $more";
$this->logHelper->writeLine($msg,null, $data);
}
/**
* Handle custom logging events
*
* @param Doku_Event $event
* @param mixed $param data passed to the event handler
*/
public function handleCustom(Doku_Event $event, $param)
{
if (isset($event->data['message'])) {
$log = $event->data['message'];
} else {
return;
}
if (isset($event->data['user'])) {
$user = $event->data['user'];
} else {
$user = null;
}
$this->logHelper->writeLine($log, $user);
}
/**
* Handle autologoffs by the autologout plugin
*
* @param Doku_Event $event
* @param mixed $param data passed to the event handler
*/
public function handleAutologout(Doku_Event $event, $param)
{
$this->logAuth('has been automatically logged off');
}
/**
* catch standard logins/logouts, check if any alert notifications should be sent
*
* @param Doku_Event $event
* @param mixed $param data passed to the event handler
*/
public function handleAuth(Doku_Event $event, $param)
{
// log authentication events
$act = act_clean($event->data);
if ($act == 'logout') {
$this->logAuth('logged off');
} elseif (!empty($_SERVER['REMOTE_USER']) && $act == 'login') {
if (isset($_REQUEST['r'])) {
$this->logAuth('logged in permanently');
} else {
$this->logAuth('logged in temporarily');
}
} elseif ($_REQUEST['u'] && empty($_REQUEST['http_credentials']) && empty($_SERVER['REMOTE_USER'])) {
$this->logAuth('failed login attempt');
}
}
/**
* Log access to admin pages
*
* @param Doku_Event $event
*/
public function handleAdminAccess(Doku_Event $event)
{
global $ACT;
if ($ACT === 'admin') {
$this->logAdmin();
}
}
/**
* Log user modifications
*
* @param Doku_Event $event
*/
public function handleUsermod(Doku_Event $event)
{
$modType = $event->data['type'];
$modUser = $event->data['params'][0];
if (is_array($modUser)) $modUser = implode(', ', $modUser);
// check if admin or user are modifying the data
global $ACT;
if ($ACT === 'profile') {
$this->logHelper->writeLine('user profile',null, [$modType . ' user', $modUser]);
} else {
$this->logAdmin([$modType . ' user', $modUser]);
}
}
/**
* Catch admin actions performed via Ajax
*
* @param Doku_Event $event
*/
public function handleAjax(Doku_Event $event)
{
global $INPUT;
// extension manager
if ($event->data === 'plugin_extension') {
$this->logAdmin([$INPUT->str('act') . ' ' . $INPUT->str('ext')], 'extension');
}
}
/**
* Log activity in select core admin modules
*
* @param \Doku_Event $event
*/
public function handleOther(\Doku_Event $event)
{
global $INPUT;
// configuration manager
if ($INPUT->str('page') === 'config'
&& $INPUT->bool('save') === true
&& !empty($INPUT->arr('config'))
) {
$this->logAdmin(['save config']);
}
// extension manager
if ($INPUT->str('page') === 'extension') {
if ($INPUT->post->has('fn')) {
$actions = $INPUT->post->arr('fn');
foreach ($actions as $action => $extensions) {
foreach ($extensions as $extname => $label) {
$this->logAdmin([$action, $extname]);
}
}
} elseif ($INPUT->post->str('installurl')) {
$this->logAdmin(['installurl', $INPUT->post->str('installurl')]);
} elseif (isset($_FILES['installfile'])) {
$this->logAdmin(['installfile', $_FILES['installfile']['name']]);
}
}
// ACL manager
if ($INPUT->str('page') === 'acl' && $INPUT->has('cmd')) {
$cmd = $INPUT->extract('cmd')->str('cmd');
$del = $INPUT->arr('del');
if ($cmd === 'update' && !empty($del)) {
$cmd = 'delete';
$rule = $del;
} else {
$rule = [
'ns' => $INPUT->str('ns'),
'acl_t' => $INPUT->str('acl_t'),
'acl_w' => $INPUT->str('acl_w'),
'acl' => $INPUT->str('acl')
];
}
$this->logAdmin([$cmd, $rule]);
}
}
/**
* Handle monthly usage reports
*
* @param Doku_Event $event
*/
public function handleReport(Doku_Event $event)
{
$reportHelper = new helper_plugin_loglog_report();
$reportHelper->handleReport();
}
}

View File

@@ -0,0 +1,174 @@
<?php
class admin_plugin_loglog extends DokuWiki_Admin_Plugin
{
/**
* @var \helper_plugin_loglog_logging
*/
protected $logHelper;
/**
* @var \helper_plugin_loglog_main
*/
protected $mainHelper;
/**
* @var string
*/
protected $filter = '';
/** @inheritDoc */
public function forAdminOnly()
{
return false;
}
/** @inheritDoc */
public function getMenuSort()
{
return 141;
}
public function __construct()
{
$this->logHelper = $this->loadHelper('loglog_logging');
$this->mainHelper = $this->loadHelper('loglog_main');
global $INPUT;
$this->filter = $INPUT->str('filter');
}
/** @inheritDoc */
public function html()
{
global $ID, $INPUT, $conf, $lang;
$now = time();
$go = isset($_REQUEST['time']) ? intval($_REQUEST['time']) : $now;
$min = $go - (7 * 24 * 60 * 60);
$max = $go;
$past = $now - $go > 60 * 60 * 5;
if ($past) {
$next = $max + (7 * 24 * 60 * 60);
if ($now - $next < 60 * 60 * 5) {
$next = $now;
}
}
$time = $INPUT->str('time') ?: $now;
// alternative date format?
$dateFormat = $this->getConf('admin_date_format') ?: $conf['dformat'];
echo $this->locale_xhtml('intro');
$form = new dokuwiki\Form\Form(['method'=>'GET']);
$form->setHiddenField('do', 'admin');
$form->setHiddenField('page', 'loglog');
$form->setHiddenField('time', $time);
$form->addDropdown(
'filter',
[
'' => '',
'auth_ok' => $this->getLang('filter_auth_ok'),
'auth_error' => $this->getLang('filter_auth_error'),
'admin' => $this->getLang('filter_admin'),
'other' => $this->getLang('filter_other')
]
);
$form->addButton('submit', $this->getLang('submit'))->attr('type','submit');
echo $form->toHTML();
echo '<p>' . $this->getLang('range') . ' ' . strftime($dateFormat, $min) .
' - ' . strftime($dateFormat, $max) . '</p>';
echo '<table class="inline loglog">';
echo '<tr>';
echo '<th>' . $this->getLang('date') . '</th>';
echo '<th>' . $this->getLang('ip') . '</th>';
echo '<th>' . $lang['user'] . '</th>';
echo '<th>' . $this->getLang('action') . '</th>';
echo '<th>'. $this->getLang('data') . '</th>';
echo '</tr>';
$lines = $this->logHelper->readLines($min, $max);
$lines = array_reverse($lines);
foreach ($lines as $line) {
if (!$line['user']) continue;
$logType = $this->mainHelper->getLogTypeFromMsg($line['msg']);
if ($this->filter && $this->filter !== '' && $this->filter!== $logType) {
continue;
}
if ($line['msg'] == 'logged off') {
$line['msg'] = $this->getLang('off');
$class = 'off';
} elseif ($line['msg'] == 'logged in permanently') {
$line['msg'] = $this->getLang('in');
$class = 'perm';
} elseif ($line['msg'] == 'logged in temporarily') {
$line['msg'] = $this->getLang('tin');
$class = 'temp';
} elseif ($line['msg'] == 'failed login attempt') {
$line['msg'] = $this->getLang('fail');
$class = 'fail';
} elseif ($line['msg'] == 'has been automatically logged off') {
$line['msg'] = $this->getLang('autologoff');
$class = 'off';
} else {
$line['msg'] = hsc($line['msg']);
if (strpos($line['msg'], 'logged off') !== false) {
$class = 'off';
} elseif (strpos($line['msg'], 'logged in permanently') !== false) {
$class = 'perm';
} elseif (strpos($line['msg'], 'logged in') !== false) {
$class = 'temp';
} elseif (strpos($line['msg'], 'failed') !== false) {
$class = 'fail';
} else {
$class = 'unknown';
}
}
echo '<tr>';
echo '<td>' . strftime($dateFormat, $line['dt']) . '</td>';
echo '<td>' . hsc($line['ip']) . '</td>';
echo '<td>' . hsc($line['user']) . '</td>';
echo '<td><span class="loglog_' . $class . '">' . $line['msg'] . '</span></td>';
echo '<td>';
if ($line['data']) {
// logs contain single-line JSON data, so we have to decode and encode it again for pretty print
echo '<pre>' . json_encode(json_decode($line['data']), JSON_PRETTY_PRINT) . '</pre>';
}
echo '</td>';
echo '</tr>';
}
echo '</table>';
echo '<div class="pagenav">';
if ($past) {
echo '<div class="pagenav-prev">';
echo html_btn('newer',
$ID,
"p",
['do' => 'admin', 'page' => 'loglog', 'time' => $next, 'filter' => $this->filter]
);
echo '</div>';
}
echo '<div class="pagenav-next">';
echo html_btn('older',
$ID,
"n",
['do' => 'admin', 'page' => 'loglog', 'time' => $min, 'filter' => $this->filter]
);
echo '</div>';
echo '</div>';
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 9c2.33 0 7 1.17 7 3.5V15h-6v-2.5c0-1.5-.81-2.61-1.96-3.45L16 9M8 9c2.33 0 7 1.17 7 3.5V15H1v-2.5C1 10.17 5.67 9 8 9m0-2a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3m8 0a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3m-7 9.75V19h6v-2.25L18.25 20 15 23.25V21H9v2.25L5.75 20 9 16.75z"/></svg>

After

Width:  |  Height:  |  Size: 404 B

View File

@@ -0,0 +1,10 @@
<?php
$conf['login_success_max'] = '50';
$conf['login_success_interval'] = '1';
$conf['login_success_email'] = '';
$conf['login_failed_max'] = '10';
$conf['login_failed_interval'] = '1';
$conf['login_failed_email'] = '';
$conf['report_email'] = '';
$conf['admin_date_format'] = '';

View File

@@ -0,0 +1,10 @@
<?php
$meta['login_success_max'] = ['numeric'];
$meta['login_success_interval'] = ['string'];
$meta['login_success_email'] = ['string'];
$meta['login_failed_max'] = ['numeric'];
$meta['login_failed_interval'] = ['string'];
$meta['login_failed_email'] = ['string'];
$meta['report_email'] = ['string'];
$meta['admin_date_format'] = ['string'];

View File

@@ -0,0 +1,190 @@
<?php
/**
* Class helper_plugin_loglog_alert
*/
class helper_plugin_loglog_alert extends DokuWiki_Plugin
{
/**
* @var \helper_plugin_loglog_main
*/
protected $mainHelper;
/**
* @var \helper_plugin_loglog_logging
*/
protected $logHelper;
/** @var int */
protected $interval;
/** @var int */
protected $threshold;
/** @var int */
protected $now;
/** @var int */
protected $multiplier;
/** @var string */
protected $statfile;
public function __construct()
{
$this->mainHelper = $this->loadHelper('loglog_main');
$this->logHelper = $this->loadHelper('loglog_logging');
}
/**
* Check if any configured thresholds have been exceeded and trigger
* alert notifications accordingly.
*
* @return void
*/
public function checkAlertThresholds()
{
$this->handleThreshold(
\helper_plugin_loglog_main::LOGTYPE_AUTH_FAIL,
$this->getConf('login_failed_max'),
$this->getConf('login_failed_interval'),
$this->getConf('login_failed_email')
);
$this->handleThreshold(
\helper_plugin_loglog_main::LOGTYPE_AUTH_OK,
$this->getConf('login_success_max'),
$this->getConf('login_success_interval'),
$this->getConf('login_success_email')
);
}
/**
* Evaluates threshold configuration for given type of logged event
* and triggers email alerts.
*
* @param string $logType
* @param int $threshold
* @param int $minuteInterval
* @param string $email
*/
protected function handleThreshold($logType, $threshold, $minuteInterval, $email)
{
// proceed only if we have sufficient configuration
if (! $email || ! $threshold || ! $minuteInterval) {
return;
}
$this->resetMultiplier();
$this->threshold = $threshold;
$this->interval = $minuteInterval * 60;
$this->now = time();
$max = $this->now;
$min = $this->now - ($this->interval);
$msgNeedle = $this->mainHelper->getNotificationString($logType, 'msgNeedle');
$lines = $this->logHelper->readLines($min, $max);
$cnt = $this->logHelper->countMatchingLines($lines, $msgNeedle);
if ($cnt < $threshold) {
return;
}
global $conf;
$this->statfile = $conf['cachedir'] . '/loglog.' . $logType . '.stat';
if ($this->actNow()) {
io_saveFile($this->statfile, $this->multiplier);
$this->sendAlert($logType, $email);
}
}
/**
* Send alert email
*
* @param string $logType
* @param string $email
*/
protected function sendAlert($logType, $email)
{
$template = $this->localFN($logType);
$text = file_get_contents($template);
$this->mainHelper->sendEmail(
$email,
$this->getLang($this->mainHelper->getNotificationString($logType, 'emailSubjectLang')),
$text,
[
'threshold' => $this->threshold,
'interval' => $this->interval / 60, // falling back to minutes for the view
'now' => date('Y-m-d H:i', $this->now),
'sequence' => $this->getSequencePhase(),
'next_alert' => date('Y-m-d H:i', $this->getNextAlert()),
]
);
}
/**
* Check if it is time to act or wait this interval out
*
* @return bool
*/
protected function actNow()
{
$act = true;
if (!is_file($this->statfile)) {
return $act;
}
$lastAlert = filemtime($this->statfile);
$this->multiplier = (int)file_get_contents($this->statfile);
$intervalsAfterLastAlert = (int)floor(($this->now - $lastAlert) / $this->interval);
if ($intervalsAfterLastAlert === $this->multiplier) {
$this->increaseMultiplier();
} elseif ($intervalsAfterLastAlert < $this->multiplier) {
$act = false;
} elseif ($intervalsAfterLastAlert > $this->multiplier) {
$this->resetMultiplier(); // no longer part of series, reset multiplier
}
return $act;
}
/**
* Calculate which phase of sequential events we are in (possible attacks),
* based on the interval multiplier. 1 indicates the first incident,
* otherwise evaluate the exponent (because we multiply the interval by 2 on each alert).
*
* @return int
*/
protected function getSequencePhase()
{
return $this->multiplier === 1 ? $this->multiplier : log($this->multiplier, 2) + 1;
}
/**
* Calculate when the next alert is due based on the current multiplier
*
* @return int
*/
protected function getNextAlert()
{
return $this->now + $this->interval * $this->multiplier * 2;
}
/**
* Reset multiplier. Called when the triggering event is not part of a sequence.
*/
protected function resetMultiplier()
{
$this->multiplier = 1;
}
/**
* Increase multiplier. Called when the triggering event belongs to a sequence.
*/
protected function increaseMultiplier()
{
$this->multiplier *= 2;
}
}

View File

@@ -0,0 +1,166 @@
<?php
/**
* Class helper_plugin_loglog_logging
*/
class helper_plugin_loglog_logging extends DokuWiki_Plugin
{
protected $file = '';
public function __construct()
{
global $conf;
if(defined('DOKU_UNITTEST')) {
$this->file = DOKU_PLUGIN . 'loglog/_test/loglog.log';
} else {
$this->file = $conf['cachedir'] . '/loglog.log';
}
}
/**
* Build a log entry from passed data and write a single line to log file
*
* @param string $msg
* @param null $user
* @param array $data
*/
public function writeLine($msg, $user = null, $data = [])
{
global $conf, $INPUT;
if (is_null($user)) $user = $INPUT->server->str('REMOTE_USER');
if (!$user) $user = $_REQUEST['u'];
if (!$user) return;
$t = time();
$ip = clientIP(true);
$data = !empty($data) ? json_encode($data) : '';
$line = join("\t", [$t, strftime($conf['dformat'], $t), $ip, $user, $msg, $data]);
io_saveFile($this->file, "$line\n", true);
}
/**
* Return logfile lines limited to specified $min - $max range
*
* @param int $min
* @param int $max
* @return array
*/
public function readLines($min, $max)
{
$lines = [];
$candidateLines = $this->readChunks($min, $max);
foreach ($candidateLines as $line) {
if (empty($line)) continue; // Filter empty lines
$parsedLine = $this->loglineToArray($line);
if ($parsedLine['dt'] >= $min && $parsedLine['dt'] <= $max) {
$lines[] = $parsedLine;
}
}
return $lines;
}
/**
* Read log lines backwards. Start and end timestamps are used to evaluate
* only the chunks being read, NOT single lines. This method will return
* too many lines, the dates have to be checked by the caller again.
*
* @param int $min start time (in seconds)
* @param int $max end time (in seconds)
* @return array
*/
protected function readChunks($min, $max)
{
$data = array();
$lines = array();
$chunk_size = 8192;
if (!@file_exists($this->file)) return $data;
$fp = fopen($this->file, 'rb');
if ($fp === false) return $data;
//seek to end
fseek($fp, 0, SEEK_END);
$pos = ftell($fp);
$chunk = '';
while ($pos) {
// how much to read? Set pointer
if ($pos > $chunk_size) {
$pos -= $chunk_size;
$read = $chunk_size;
} else {
$read = $pos;
$pos = 0;
}
fseek($fp, $pos);
$tmp = fread($fp, $read);
if ($tmp === false) break;
$chunk = $tmp . $chunk;
// now split the chunk
$cparts = explode("\n", $chunk);
// keep the first part in chunk (may be incomplete)
if ($pos) $chunk = array_shift($cparts);
// no more parts available, read on
if (!count($cparts)) continue;
// get date of first line:
list($cdate) = explode("\t", $cparts[0]);
if ($cdate > $max) continue; // haven't reached wanted area, yet
// put all the lines from the chunk on the stack
$lines = array_merge($cparts, $lines);
if ($cdate < $min) break; // we have enough
}
fclose($fp);
return $lines;
}
/**
* Convert log line to array
*
* @param string $line
* @return array
*/
protected function loglineToArray($line)
{
list($dt, $junk, $ip, $user, $msg, $data) = explode("\t", $line, 6);
return [
'dt' => $dt, // timestamp
'ip' => $ip,
'user' => $user,
'msg' => $msg,
'data' => $data, // JSON encoded additional data
];
}
/**
* Returns the number of lines where the given needle has been found in message
*
* @param array $lines
* @param string $msgNeedle
* @return mixed
*/
public function countMatchingLines(array $lines, string $msgNeedle)
{
return array_reduce(
$lines,
function ($carry, $line) use ($msgNeedle) {
$carry = $carry + (int)(strpos($line['msg'], $msgNeedle) !== false);
return $carry;
},
0
);
}
}

View File

@@ -0,0 +1,97 @@
<?php
/**
* Class helper_plugin_loglog_main
*/
class helper_plugin_loglog_main extends DokuWiki_Plugin
{
const LOGTYPE_AUTH_OK = 'auth_success';
const LOGTYPE_AUTH_FAIL = 'auth_failed';
/**
* @var helper_plugin_loglog_logging
*/
protected $logHelper;
public function __construct()
{
$this->logHelper = $this->loadHelper('loglog_logging');
}
/**
* Deduce the type of logged event from message field. Those types are used in a dropdown filter
* in admin listing of activities, as well as when generating reports to send per email.
*
* @param string $msg
* @return string
*/
public function getLogTypeFromMsg($msg)
{
$filter = 'other';
if (in_array(
$msg,
[
'logged in temporarily',
'logged in permanently',
'logged off',
'has been automatically logged off'
]
)) {
$filter = 'auth_ok';
} elseif (in_array(
$msg,
[
'failed login attempt',
]
)) {
$filter = 'auth_error';
} elseif (strpos($msg, 'admin') === 0) {
$filter = 'admin';
}
return $filter;
}
/**
* Sends emails
*
* @param string $email
* @param string $subject
* @param string $text
* @return bool
*/
public function sendEmail($email, $subject, $text, $textrep = [])
{
$html = p_render('xhtml', p_get_instructions($text), $info);
$mail = new Mailer();
$mail->to($email);
$mail->subject($subject);
$mail->setBody($text, $textrep, null, $html);
return $mail->send();
}
/**
* Returns a string corresponding to $key in a given $context,
* empty string if nothing has been found in the string repository.
*
* @param string $context
* @param string $key
* @return string
*/
public function getNotificationString($context, $key)
{
$stringRepo = [
self::LOGTYPE_AUTH_FAIL => [
'msgNeedle' => 'failed login attempt',
'emailSubjectLang' => 'email_max_failed_logins_subject'
],
self::LOGTYPE_AUTH_OK => [
'msgNeedle' => 'logged in',
'emailSubjectLang' => 'email_max_success_logins_subject'
],
];
return isset($stringRepo[$context][$key]) ? $stringRepo[$context][$key] : '';
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* Class helper_plugin_loglog_report
*/
class helper_plugin_loglog_report extends DokuWiki_Plugin
{
/**
* @var \helper_plugin_loglog_main
*/
protected $mainHelper;
/**
* @var \helper_plugin_loglog_logging
*/
protected $logHelper;
public function __construct()
{
$this->mainHelper = $this->loadHelper('loglog_main');
$this->logHelper = $this->loadHelper('loglog_logging');
}
/**
* Checks if the report has already been sent this month. If not, creates and
* sends the report, and records this action in the log.
*/
public function handleReport()
{
$email = $this->getConf('report_email');
if (!$email) return;
// calculate cutoff dates
$lastMonthStart = mktime(0, 0, 0, date('n', strtotime('last month')), 1);
$currentMonthStart = mktime(0, 0, 0, date('n'), 1);
// check if the report is due
global $conf;
$statfile = $conf['cachedir'] . '/loglog.stat';
if (is_file($statfile) && filemtime($statfile) >= $currentMonthStart) {
return;
}
// calculate stat
$monthLines = $this->logHelper->readLines($lastMonthStart, $currentMonthStart);
$stats = $this->getStats($monthLines);
// email the report
$template = $this->localFN('report');
$text = file_get_contents($template);
// format access to admin pages
$adminPages = implode(
"\n",
array_map(
function ($page, $cnt) {
return " - $page: $cnt";
},
array_keys($stats['admin']),
$stats['admin']
)
);
$text = str_replace(
['@@auth_ok@@', '@@auth_fail@@', '@@users@@', '@@admin_pages@@'],
[$stats['auth_success'], $stats['auth_failed'], $stats['users'], $adminPages],
$text
);
if (
$this->mainHelper->sendEmail(
$email,
$this->getLang('email_report_subject'),
$text
)
) {
// log itself
$this->logHelper->writeLine('loglog - report', 'cron');
// touch statfile
touch($statfile);
}
}
/**
* Go through supplied log lines and aggregate basic activity statistics
*
* @param array $lines
* @return array
*/
public function getStats(array $lines)
{
$authOk = 0;
$authFail = 0;
$users = [];
$pages = ['start' => 0];
foreach ($lines as $line) {
if (
strpos(
$line['msg'],
$this->mainHelper->getNotificationString(\helper_plugin_loglog_main::LOGTYPE_AUTH_OK, 'msgNeedle')
) !== false
) {
$authOk++;
if ($line['user']) $users[] = $line['user'];
} elseif (
strpos(
$line['msg'],
$this->mainHelper->getNotificationString(\helper_plugin_loglog_main::LOGTYPE_AUTH_FAIL, 'msgNeedle')
) !== false
) {
$authFail++;
} elseif (strpos($line['msg'], 'admin') !== false) {
list($action, $page) = explode(' - ', $line['msg']);
if ($page) {
$pages[$page] = !isset($pages[$page]) ? 1 : $pages[$page] + 1;
} else {
$pages['start']++;
}
}
}
return [
\helper_plugin_loglog_main::LOGTYPE_AUTH_OK => $authOk,
\helper_plugin_loglog_main::LOGTYPE_AUTH_FAIL => $authFail,
'users' => count(array_unique($users)),
'admin' => $pages
];
}
}

View File

@@ -0,0 +1,3 @@
======سجل الدخول و الهروج الاسبوعي للمستخدم======
هذا التقرير يعرض كل تسجيلات الدخول و الخروج للمستخدم خلال الـ 7 ايام الماضيه.تستطيع استخدام زر التحديد في اسفل الصحفه لعرض الاسابيع الماضيه.

View File

@@ -0,0 +1,16 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Ali Almlfy <Almlfy@hotmail.com>
*/
$lang['menu'] = 'سجل الدخول و الخروج الاسبوعي للمستخدم ';
$lang['date'] = 'التاريخ';
$lang['ip'] = 'عنوان الايبي';
$lang['action'] = 'نفذ';
$lang['range'] = 'اظهر سجل التاريخ';
$lang['off'] = 'سجل خروج';
$lang['in'] = 'سجل دخول متواصل ';
$lang['tin'] = 'سجل دخول موقته';
$lang['fail'] = 'محاولت دخول فاشلة';

View File

@@ -0,0 +1,3 @@
====== Týdenní uživatelská přihlášení/odhlášení ======
Tato obrazovka zobrazuje všechna přihlášení a odhlášení uživatelů z posledních 7 dnů. Pro zobrazení starších týdnů lze použít navigační tlačítka na konci této stránky.

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Jaroslav Lichtblau <jlichtblau@seznam.cz>
*/
$lang['menu'] = 'Týdenní uživatelská přihlášení/odhlášení';
$lang['date'] = 'Datum';
$lang['ip'] = 'IP adresa';
$lang['action'] = 'Akce';
$lang['range'] = 'Zobrazené časové období:';
$lang['off'] = 'odhlášení';
$lang['autologoff'] = 'automaticky odhlášen(a)';
$lang['in'] = 'trvalé přihlášení';
$lang['tin'] = 'dočasné přihlášení';
$lang['fail'] = 'chybné přihlášení';

View File

@@ -0,0 +1,3 @@
====== Ugentlige Brugerlogin/log ud ======
Denne skærm viser alle brugernes login og log ud fra de sidste 7 dage. Du kan benytte navigationsknapperne i bunden af skærmen til at vise tidligere uger.

View File

@@ -0,0 +1,18 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Søren Birk <soer9648@eucl.dk>
* @author Jacob Palm <mail@jacobpalm.dk>
*/
$lang['menu'] = 'Ugentlige Brugerlogin/log ud';
$lang['date'] = 'Dato';
$lang['ip'] = 'IP-Adresse';
$lang['action'] = 'Handling';
$lang['range'] = 'Vist datorækkevidde';
$lang['off'] = 'logget ud';
$lang['autologoff'] = 'er blevet logget ud automatisk';
$lang['in'] = 'permanent logget ind';
$lang['tin'] = 'midlertidigt logget ind';
$lang['fail'] = 'fejlet login-forsøg';

View File

@@ -0,0 +1,9 @@
Achtung!
Der konfigurierte Schwellwert für fehlgeschlagene Anmeldeveruche (@THRESHOLD@ in @INTERVAL@ Minuten) wurde überschritten!
Das ist die @SEQUENCE@. Warnung von @NOW@.
Sollte sich das Problem kontinuierlich fortsetzen, erhalten Sie die nächste Warnung am @NEXT_ALERT@.
Sie können das Problem untersuchen, indem Sie sich ins Wiki einloggen und die Logs im Adminbereich überprüfen.

View File

@@ -0,0 +1,9 @@
Achtung!
Der konfigurierte Schwellwert für Anmeldungen (@THRESHOLD@ in @INTERVAL@ Minuten) wurde überschritten!
Das ist die @SEQUENCE@. Warnung von @NOW@.
Sollte sich das Problem kontinuierlich fortsetzen, erhalten Sie die nächste Warnung am @NEXT_ALERT@.
Sie können das Problem untersuchen, indem Sie sich ins Wiki einloggen und die Logs im Adminbereich überprüfen.

View File

@@ -0,0 +1,3 @@
====== Wöchentliche Benutzer- und Adminaktionen ======
Diese Übersicht zeigt die folgenden Nutzeraktionen innerhalb der letzten 7 Tage: An- und Abmeldungen von Benutzern, sowie alle Aktionen im Admin-Bereich. Mit den Navigations-Schaltflächen am unteren Bilschirm können sie die Aktivitäten vergangener Wochen einsehen.

View File

@@ -0,0 +1,25 @@
<?php
$lang['menu'] = 'Wöchentliche Benutzer- und Adminaktionen';
$lang['date'] = 'Datum';
$lang['ip'] = 'IP Adresse';
$lang['action'] = 'Aktion';
$lang['range'] = 'Angezeigter Zeitraum:';
$lang['off'] = 'abgemeldet';
$lang['autologoff'] = 'wurde automatisch abgemeldet';
$lang['in'] = 'dauerhaft angemeldet';
$lang['tin'] = 'temporär angemeldet';
$lang['fail'] = 'gescheiterter Anmeldeversuch';
$lang['data'] = 'Zusatzdaten';
$lang['submit'] = 'Filtern';
$lang['filter_auth_ok'] = 'An- und Abmeldungen';
$lang['filter_auth_error'] = 'Fehlgeschlagene Anmeldeversuche';
$lang['filter_admin'] = 'Admin';
$lang['filter_other'] = 'Andere';
$lang['email_max_success_logins_subject'] = 'Warnung: Zu viele Anmeldungen';
$lang['email_max_failed_logins_subject'] = 'Warnung: Zu viele fehlgeschlagene Anmeldeveruche';
$lang['email_report_subject'] = 'Monatlicher Log-Bericht';

View File

@@ -0,0 +1,13 @@
Aktivitäten im vergangenen Monat
Logins
* Anzahl der erfolgreichen Logins: @@auth_ok@@
* Anzahl der fehlgeschlagenen Loginversuche: @@auth_fail@@
* Anzahl der Nutzer, die sich eingeloggt haben: @@users@@
Admin Tools
Aufrufe der verschiedenen Admin-Plugins
@@admin_pages@@

View File

@@ -0,0 +1,10 @@
<?php
$lang['login_success_max'] = 'Wenn die Anzahl von Anmeldungen im definierten Zeitraum (login_success_interval) diesen Wert überschreitet, soll ein Administrator benachrichtigt werden';
$lang['login_success_interval'] = 'Alle X Minuten prüfen, ob der konfigurierte Schwellenwert für Anmeldungen überschritten wurde';
$lang['login_success_email'] = 'E-Mail für Benachrichtigungen über zu viele Anmeldungen';
$lang['login_failed_max'] = 'Wenn die Anzahl von gescheiterten Anmeldeveruchen im definierten Zeitraum (login_failed_interval) diesen Wert überschreitet, soll ein Administrator benachrichtigt werden';
$lang['login_failed_interval'] = 'Alle X Minuten prüfen, ob der konfigurierte Schwellenwert für fehlgeschlagene Anmeldeversuche überschritten wurde';
$lang['login_failed_email'] = 'E-Mail für Benachrichtigungen über zu viele fehlgeschlagene Anmeldeversuche';
$lang['report_email'] = 'E-Mail für monatliche Berichte (Monatsanfang)';
$lang['admin_date_format'] = 'Datumsformat in der Admin-Übersicht, falls abweichend von der Vorgabe in der Hauptkonfiguration (Siehe PHP <a href="http://php.net/strftime">strftime</a> Funktion)';

View File

@@ -0,0 +1,9 @@
Attention!
The number of recent failed login attempts has exceeded the configured limit (@THRESHOLD@ in @INTERVAL@ minutes)!
This is the @SEQUENCE@. warning issued at @NOW@.
In case this turns out to be part of an ongoing sequence, you will receive the next alert on @NEXT_ALERT@.
You can investigate the issue by logging into the wiki and checking the logs in the admin area.

View File

@@ -0,0 +1,9 @@
Attention!
The number of recent logins has exceeded the configured limit (@THRESHOLD@ in @INTERVAL@ minutes)!
This is the @SEQUENCE@. warning issued at @NOW@.
In case this turns out to be part of an ongoing sequence, you will receive the next alert on @NEXT_ALERT@.
You can investigate the issue by logging into the wiki and checking the logs in the admin area.

View File

@@ -0,0 +1,3 @@
====== Weekly User and Admin Activity ======
This screen displays the following activities during the last 7 days: user logins and logouts, as well as usage of admin tools. You can use the navigation buttons at the bottom of the screen to display earlier weeks.

View File

@@ -0,0 +1,25 @@
<?php
$lang['menu'] = 'Weekly user and admin activity';
$lang['date'] = 'Date';
$lang['ip'] = 'IP Address';
$lang['action'] = 'Action';
$lang['range'] = 'Displayed date range:';
$lang['off'] = 'logged off';
$lang['autologoff'] = 'has been logged out automatically';
$lang['in'] = 'logged in permanently';
$lang['tin'] = 'logged in temporarily';
$lang['fail'] = 'failed login attempt';
$lang['data'] = 'Data';
$lang['submit'] = 'Apply filter';
$lang['filter_auth_ok'] = 'User logins and logoffs';
$lang['filter_auth_error'] = 'Failed login attempts';
$lang['filter_admin'] = 'Admin';
$lang['filter_other'] = 'Other';
$lang['email_max_success_logins_subject'] = 'Alert: Too many logins';
$lang['email_max_failed_logins_subject'] = 'Alert: Too many failed login attempts';
$lang['email_report_subject'] = 'Monthly log report';

View File

@@ -0,0 +1,11 @@
Usage Report for Last Month
Logins
* successful logins: @@auth_ok@@
* failed login attempts: @@auth_fail@@
* number of logged in users: @@users@@
Admin Tools
@@admin_pages@@

View File

@@ -0,0 +1,10 @@
<?php
$lang['login_success_max'] = 'When the number of logins per configured interval (login_success_interval) exceeds this number, an admin should be notified';
$lang['login_success_interval'] = 'Interval to check the number of recent successful logins, in minutes';
$lang['login_success_email'] = 'Email to send notifications about too many recent logins';
$lang['login_failed_max'] = 'When the number of failed logins attempt per configured interval (login_failed_interval) exceeds this number, an admin should be notified';
$lang['login_failed_interval'] = 'Interval to check the number of recent failed login attempts, in minutes';
$lang['login_failed_email'] = 'Email to send notifications about too many failed logins';
$lang['report_email'] = 'Email to send monthly reports to (beginning of every month)';
$lang['admin_date_format'] = 'Date format to use in admin list instead of the global configuration (see PHP <a href="http://php.net/strftime">strftime</a> function)';

View File

@@ -0,0 +1,3 @@
====== Semajnaj en/elsalutoj de uzantoj ======
Tiu ĉi paĝo montras ĉiujn en- kaj elsalutojn de uzantoj dum la pasintaj 7 tagoj. Vi povas uzi la navigbutonojn sube por montri pli fruajn semajnojn.

View File

@@ -0,0 +1,18 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Robert Bogenschneider <bogi@uea.org>
* @author Moisés Braga Ribeiro <moisesbr@gmail.com>
*/
$lang['menu'] = 'Semajnaj en/elsalutoj de uzantoj';
$lang['date'] = 'Dato';
$lang['ip'] = 'IP-adreso';
$lang['action'] = 'Ago';
$lang['range'] = 'Montrata dat-amplekso:';
$lang['off'] = 'elsalutinta';
$lang['autologoff'] = 'elsalutinta aŭtomate';
$lang['in'] = 'ensalutinta konstante';
$lang['tin'] = 'ensalutinta portempe';
$lang['fail'] = 'malsukcesa provo ensaluti';

View File

@@ -0,0 +1,3 @@
====== Journal hebdomadaire des Connexions/Déconnexions Utilisateurs ======
Cette page affiche les connexions et déconnexions de tous les utilisateurs au cours de 7 derniers jours. Vous pouvez utiliser les boutons de navigation au bas de la page pour afficher les semaines précédentes.

View File

@@ -0,0 +1,18 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author NicolasFriedli <nicolas@theologique.ch>
* @author Nicolas Friedli <nicolas@theologique.ch>
*/
$lang['menu'] = 'Journal hebdomadaire des Connexions/Déconnexions Utilisateurs';
$lang['date'] = 'Date';
$lang['ip'] = 'Adresse IP';
$lang['action'] = 'Action';
$lang['range'] = 'Période affichée :';
$lang['off'] = 'déconnecté';
$lang['autologoff'] = 'a été connecté automatiquement';
$lang['in'] = 'connecté de façon permanente';
$lang['tin'] = 'connecté temporairement';
$lang['fail'] = 'connextion ratée';

View File

@@ -0,0 +1,3 @@
====== Tjedne prijave/odjave korisnika ======
Ovdje su prikazane sve prijave i odjave korisnika u zadnjih 7 dana. Možete koristiti tipke za navigaciju na dnu stranice da prikažete prethodne tjedne.

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Davor Turkalj <turki.bsc@gmail.com>
*/
$lang['menu'] = 'Tjedne prijave/odjave korisnika';
$lang['date'] = 'Datum';
$lang['ip'] = 'IP adresa';
$lang['action'] = 'Aktivnost';
$lang['range'] = 'Prikazani opseg datuma:';
$lang['off'] = 'odjavljen';
$lang['autologoff'] = 'bio je odjavljen od strane sustava';
$lang['in'] = 'prijavljen trajno';
$lang['tin'] = 'prijavljen trenutno';
$lang['fail'] = 'neuspio pokušaj prijave';

View File

@@ -0,0 +1,3 @@
====== Heti felhasználói be-/kijelentkezések ======
A képernyőn az elmúlt 7 napban történt összes felhasználói be- és kijelentkezést láthatjuk. A képernyő alján található navigációs gombokkal a korábbi heteket is megtekinthetjük.

View File

@@ -0,0 +1,18 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author DelDadam <deldadam@gmail.com>
* @author DelD <deldadam@gmail.com>
*/
$lang['menu'] = 'Heti felhasználói be-/kijelentkezések';
$lang['date'] = 'Dátum';
$lang['ip'] = 'IP-cím';
$lang['action'] = 'Művelet';
$lang['range'] = 'Kijelzett dátumtartomány:';
$lang['off'] = 'kijelentkezés';
$lang['autologoff'] = 'automatikusan kijelentkezett.';
$lang['in'] = 'bejelentkezés (tartós)';
$lang['tin'] = 'bejelentkezés (ideiglenes)';
$lang['fail'] = 'sikertelen bejelentkezési kísérlet';

View File

@@ -0,0 +1,4 @@
====== 週間ユーザーログイン/ログアウト ======
この画面は、直近7日間の全ユーザーのログイン・ログアウトを表示します。
画面下部の移動ボタンを使用して、前の週を表示できます。

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Hideaki SAWADA <chuno@live.jp>
*/
$lang['menu'] = '週間ユーザーログイン/ログアウト';
$lang['date'] = '日付';
$lang['ip'] = 'IPアドレス';
$lang['action'] = '動作';
$lang['range'] = '表示中の日付範囲:';
$lang['off'] = 'ログアウト';
$lang['autologoff'] = '自動的なログアウト';
$lang['in'] = '恒久的なログイン';
$lang['tin'] = '一時的なログイン';
$lang['fail'] = 'ログイン失敗';

View File

@@ -0,0 +1,3 @@
====== 주간 사용자 로그인/로그아웃 ======
이 화면은 지난 7일 동안 모든 사용자의 로그인과 로그아웃을 표시합니다. 이전 주를 표시하려면 하면의 아래에 있는 둘러보기 버튼을 사용할 수 있습니다.

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Myeongjin <aranet100@gmail.com>
*/
$lang['menu'] = '주간 사용자 로그인/로그아웃';
$lang['date'] = '날짜';
$lang['ip'] = 'IP 주소';
$lang['action'] = '동작';
$lang['range'] = '표시할 날짜 범위:';
$lang['off'] = '로그아웃됨';
$lang['autologoff'] = '사용자가 자동으로 로그아웃되었습니다';
$lang['in'] = '영구적으로 로그인됨';
$lang['tin'] = '일시적으로 로그인됨';
$lang['fail'] = '실패한 로그인 시도';

View File

@@ -0,0 +1,3 @@
====== Weekoverzicht gebruikers Logins/Logouts ======
Dit scherm geeft alle gebruikers logins en logouts weer van de laatste 7 dagen. Onderaan het scherm kan je vorige weken selecteren om op het scherm te tonen.

View File

@@ -0,0 +1,18 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Hugo Smet <hugo.smet@scarlet.be>
* @author hugo smet <hugo.smet@scarlet.be>
*/
$lang['menu'] = 'Wekelijks gebruikers Logins/Logouts overzicht';
$lang['date'] = 'Datum';
$lang['ip'] = 'IP adres';
$lang['action'] = 'Actie';
$lang['range'] = 'Datumvork van de getoonde info';
$lang['off'] = 'afgelogd';
$lang['autologoff'] = 'is automatisch afgemeld';
$lang['in'] = 'permanent ingelogd';
$lang['tin'] = 'tijdelijk ingelogd';
$lang['fail'] = 'mislukte login';

View File

@@ -0,0 +1,2 @@
====== Connexions/Desconnexions dels utilizaires per setmana ======
Aqueste ecran fa veire totes los utilizaires que se son connectat o desconnexion pendent los darrièrs 7 jorns. Utilizatz lo boton de navigacion aval de l'ecran per mostrar las setmanas mai anterioras.

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author En Matt <heartattack@free.fr>
*/
$lang['menu'] = 'Connexions/Desconnexions dels utilizaires per setmana';
$lang['date'] = 'Data';
$lang['ip'] = 'Adreça IP';
$lang['action'] = 'Accion';
$lang['range'] = 'Mostrar lo periòde :';
$lang['off'] = 'desconnectat';
$lang['autologoff'] = 'es estat desconnectat automaticament';
$lang['in'] = 'connectat d\'un biais permanent';
$lang['tin'] = 'connectat temporàriament';
$lang['fail'] = 'ensag mancat de connexion';

View File

@@ -0,0 +1,3 @@
====== Relatório Semanal de Entradas e Saídas de Usuários ======
Esta tela mostra todas as entradas e saídas de usuários durante os últimos 7 dias. Você pode usar os botões de navegação no final da tela para mostrar semanas mais antigas.

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Moisés Braga Ribeiro <moisesbr@gmail.com>
*/
$lang['menu'] = 'Relatório Semanal de Entradas e Saídas de Usuários';
$lang['date'] = 'Data';
$lang['ip'] = 'Endereço IP';
$lang['action'] = 'Ação';
$lang['range'] = 'Faixa de datas mostrada:';
$lang['off'] = 'saiu';
$lang['autologoff'] = 'saiu automaticamente';
$lang['in'] = 'entrou permanentemente';
$lang['tin'] = 'entrou temporariamente';
$lang['fail'] = 'tentativa de entrada fracassada';

View File

@@ -0,0 +1,3 @@
====== Журнал авторизации пользователей ======
Данная страница отображает все входы и выходы зарегистрированных пользователей за последние семь дней. Вы можете использовать кнопки навигации в нижней части экрана для отображения записей за предыдущие недели.

View File

@@ -0,0 +1,18 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Aleksandr Selivanov <alexgearbox@yandex.ru>
* @author Takumo <9206984@mail.ru>
*/
$lang['menu'] = 'Журнал авторизации пользователей';
$lang['date'] = 'Дата';
$lang['ip'] = 'IP-адрес';
$lang['action'] = 'Действие';
$lang['range'] = 'Отображаемый период:';
$lang['off'] = 'Выход';
$lang['autologoff'] = 'был автоматически отключен от системы';
$lang['in'] = 'Постоянный вход в систему';
$lang['tin'] = 'Временный вход в систему';
$lang['fail'] = 'Неудачная попытка входа';

View File

@@ -0,0 +1,3 @@
====== Veckovis användarinloggningar/-utloggningar ======
Här visas alla användarinloggningar och -utloggningar de senaste sju dagarna. Du kan använda knapparna längst ner på sidan för att visa tidigare veckor.

View File

@@ -0,0 +1,17 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author Tor Härnqvist <tor@harnqvist.se>
*/
$lang['menu'] = 'Veckovis användarinloggningar/-utloggningar';
$lang['date'] = 'Datum';
$lang['ip'] = 'IP-adress';
$lang['action'] = 'Händelse';
$lang['range'] = 'Visat datumspann:';
$lang['off'] = 'utloggad';
$lang['autologoff'] = 'har blivit automatiskt utloggad';
$lang['in'] = 'inloggad permanent';
$lang['tin'] = 'inloggad temporärt';
$lang['fail'] = 'misslyckat inloggningsförsök';

View File

@@ -0,0 +1,15 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author HL <tohelong@gmail.com>
*/
$lang['date'] = '日期';
$lang['ip'] = 'IP';
$lang['action'] = '動作';
$lang['range'] = '日期範圍';
$lang['off'] = '登出';
$lang['in'] = '記住登錄';
$lang['tin'] = '登錄';
$lang['fail'] = '登錄失敗';

View File

@@ -0,0 +1,3 @@
======每周用户登录/注销======
该屏幕显示在过去7天的所有的登录和注销用户。可以使用导航按钮在屏幕的底部显示更多。

View File

@@ -0,0 +1,16 @@
<?php
/**
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*
* @author HL <tohelong@gmail.com>
*/
$lang['menu'] = '本周登录/注销的用户';
$lang['date'] = '日期';
$lang['ip'] = 'IP';
$lang['action'] = '动作';
$lang['range'] = '日期范围';
$lang['off'] = '登出';
$lang['in'] = '记住我';
$lang['tin'] = '登录';
$lang['fail'] = '登录失败';

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

View File

@@ -0,0 +1,7 @@
base loglog
author Andreas Gohr, Anna Dabrowska
email dokuwiki@cosmocode.de
date 2020-11-16
name Login/Logout logging plugin
desc Log logins, logouts and admin activity to a file
url http://www.dokuwiki.org/plugin:loglog

View File

@@ -0,0 +1,30 @@
table.loglog {
width: 100%;
table-layout: fixed;
word-wrap: break-word;
}
table.loglog span {
padding-left: 20px;
}
table.loglog span.loglog_off {
background: transparent url(pix/off.png) left center no-repeat;
}
table.loglog span.loglog_perm {
background: transparent url(pix/perm.png) left center no-repeat;
}
table.loglog span.loglog_temp {
background: transparent url(pix/temp.png) left center no-repeat;
}
table.loglog span.loglog_fail {
background: transparent url(pix/error.png) left center no-repeat;
}