Merge ../ZoneMinder.connortechnology

pull/3630/head
Isaac Connor 2022-10-12 11:38:11 -04:00
commit d77fb330a4
76 changed files with 12610 additions and 2110 deletions

View File

@ -37,7 +37,7 @@
%global _hardened_build 1
Name: zoneminder
Version: 1.37.23
Version: 1.37.24
Release: 1%{?dist}
Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons

View File

@ -1287,6 +1287,20 @@ our @options = (
type => $types{boolean},
category => 'logging',
},
{
name => 'ZM_LOG_INJECT',
default => 'no',
description => 'Allow log injection via API by unprivileged users.',
help => q`
When enabled (default is off), this option will allow users without System:Edit
permissions to inject javascript console or other messages into the ZoneMinder log.
Before 1.36.27 Users were able to abuse this functionality to create a denial of service by
filling up the logs. This feature is useful in debugging and detecting errors
experienced by end users, but requires trust of users and monitoring of resources.
`,
type => $types{boolean},
category => 'logging',
},
{
name => 'ZM_LOG_DEBUG',
default => 'no',

View File

@ -48,6 +48,8 @@ our %EXPORT_TAGS = (
zmDbGetMonitor
zmDbGetMonitorAndControl
zmDbDo
zmSQLExecute
zmDbFetchOne
) ]
);
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
@ -107,7 +109,7 @@ sub zmDbConnect {
.$socket . $sslOptions . ($options?join(';', '', map { $_.'='.$$options{$_} } keys %{$options} ) : '')
, $ZoneMinder::Config::Config{ZM_DB_USER}
, $ZoneMinder::Config::Config{ZM_DB_PASS}
, { mysql_enable_utf8 => 1, }
, { mysql_enable_utf8mb4 => 1, }
);
};
if ( !$dbh or $@ ) {
@ -257,6 +259,7 @@ sub zmDbDo {
sub zmDbFetchOne {
my $sql = shift;
Debug("$sql @_");
my $sth = $dbh->prepare_cached($sql);
if (!$sth) {
Error("Can't prepare '$sql': ".$dbh->errstr());
@ -294,6 +297,7 @@ zmDbGetMonitors
zmDbGetMonitor
zmDbGetMonitorAndControl
zmDbDo
zmSQLExecute
zmDbFetchOne
=head1 AUTHOR

View File

@ -918,6 +918,40 @@ sub Monitor {
return $$self{Monitor};
}
sub Close {
my $self = shift;
my $tag = @_ ? shift : '(r)';
my $text = @_ ? shift : 'Recovered.';
my $FrameDataSql = '
SELECT
max(`TimeStamp`) AS `EndDateTime`,
unix_timestamp(max(`TimeStamp`)) AS `EndTimeStamp`,
max(`FrameId`) AS `Frames`,
count(if(`Score`>0,1,NULL)) AS `AlarmFrames`,
sum(`Score`) AS `TotScore`,
max(`Score`) AS `MaxScore`
FROM `Frames` WHERE `EventId`=?';
my $frame = ZoneMinder::Database::zmDbFetchOne($FrameDataSql, $self->{Id});
if (!$frame) {
return 'Unable to retrieve frame data.';
}
if (!$frame->{EndDateTime}) {
return 'Unable to retrieve EndDateTime from Frames Table.';
}
return $self->save({
Name => sprintf('%s%d%s', $self->Monitor()->EventPrefix(), $self->{Id}, $tag),
EndDateTime => $frame->{EndDateTime},
Length => $frame->{EndTimeStamp} - $self->Time(),
Frames => $frame->{Frames},
AlarmFrames => $frame->{AlarmFrames},
TotScore => $frame->{TotScore},
AvgScore => ($frame->{AlarmFrames} ? int($frame->{TotScore} / $frame->{AlarmFrames}) : 0),
MaxScore => $frame->{MaxScore},
Notes => $self->Notes() . ' ' . $text,
});
} # end sub Close
1;
__END__

View File

@ -36,6 +36,7 @@ be run from a filter but could be run manually.
=head1 OPTIONS
close - Update event record after a crash
deletejpegs - Deletes all jpegs from the event directory
deleteanalysisjpegs - Deletes the analysis jpegs from the event directory
@ -46,6 +47,7 @@ be run from a filter but could be run manually.
=cut
use strict;
use warnings;
use bytes;
@EXTRA_PERL_LIB@
@ -100,13 +102,22 @@ foreach my $event_id (@ARGV) {
# Assume path to event, strip it
$event_id =~ s/.*\/(\d+)/$1/;
}
if ($command eq 'deleteanalysisjpegs') {
my $Event = ZoneMinder::Event->find_one(Id=>$event_id);
if ($Event) {
$Event->delete_analysis_jpegs();
my $event = ZoneMinder::Event->find_one(Id=>$event_id);
if (!$event) {
Warning("Event not found for $event_id");
next;
}
if ($command eq 'close') {
if (!$event->EndDateTime()) {
Debug("Closing $event_id");
$_ = $event->Close();
Warning($_) if $_;
} else {
Warning("Event not found for $event_id");
Warning("Event $event_id already closed!");
}
} elsif ($command eq 'deleteanalysisjpegs') {
$event->delete_analysis_jpegs();
}
}

View File

@ -696,6 +696,7 @@ sub substituteTags {
$text =~ s/%EP%/$url?view=event&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
$text =~ s/%EPS%/$url?view=event&mode=stream&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
$text =~ s/%EPI%/$url?view=event&mode=still&mid=$Event->{MonitorId}&eid=$Event->{Id}/g;
$text =~ s/%EPATH%/$Event->Path()/g;
$text =~ s/%EI%/$Event->{Id}/g;
$text =~ s/%EN%/$Event->{Name}/g;
$text =~ s/%EC%/$Event->{Cause}/g;
@ -1036,21 +1037,27 @@ sub executeCommand {
my $filter = shift;
my $Event = shift;
my $command = $filter->{AutoExecuteCmd}.' '.$Event->Path();
$command = substituteTags($command, $filter, $Event);
my $command = $filter->{AutoExecuteCmd};
if ($command =~ /%\w+.%/) {
$command = substituteTags($command, $filter, $Event);
} else {
$command .= ' '.$Event->Path();
}
Info("Executing '$command'");
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() ) {
if ($status || logDebugging()) {
chomp($output);
Debug("Output: $output");
Debug("Status: $status Output: $output");
}
if ($status) {
Error("Command '$command' exited with status: $status");
return 0;
} else {
ZoneMinder::Database::zmSQLExecute('UPDATE `Events` SET `Executed` = 1 WHERE `Id` = ?', $Event->{Id});
$Event->load(); # the command may have altered the database
$_ = $Event->save({Executed=>1});
Error($_) if $_;
}
return 1;
}

View File

@ -97,7 +97,7 @@ while (!$zm_terminate) {
my $restart = 0;
zmMemInvalidate($monitor);
if (!zmMemVerify($monitor)) {
Info("Restarting capture daemon for $monitor->{Name}, shared data not valid");
Info("Restarting capture daemon for $monitor->{Id} $monitor->{Name}, shared data not valid");
$monitor->control('restart');
next;
}
@ -134,7 +134,7 @@ while (!$zm_terminate) {
}
}
$log->logPrint(ZoneMinder::Logger::WARNING+$monitor->ImportanceNumber(),
"Restarting capture daemon for $$monitor{Name}, no image since startup. ".
"Restarting capture daemon for $monitor->{Id} $$monitor{Name}, no image since startup. ".
"Startup time was $startup_time - now $now > $Config{ZM_WATCH_MAX_DELAY}"
);
$monitor->control('restart');

View File

@ -25,6 +25,7 @@
MYSQL dbconn;
std::mutex db_mutex;
zmDbQueue dbQueue;
unsigned long db_thread_id;
bool zmDbConnected = false;
@ -103,6 +104,7 @@ bool zmDbConnect() {
Error("Can't set isolation level: %s", mysql_error(&dbconn));
}
mysql_set_character_set(&dbconn, "utf8");
db_thread_id = mysql_thread_id(&dbconn);
zmDbConnected = true;
return zmDbConnected;
}
@ -110,6 +112,7 @@ bool zmDbConnect() {
void zmDbClose() {
std::lock_guard<std::mutex> lck(db_mutex);
if (zmDbConnected) {
Debug(1, "Closing database. Connection id was %lu", db_thread_id);
mysql_close(&dbconn);
// mysql_init() call implicitly mysql_library_init() but
// mysql_close() does not call mysql_library_end()
@ -185,7 +188,7 @@ int zmDbDo(const std::string &query) {
Logger::Level oldLevel = logger->databaseLevel();
logger->databaseLevel(Logger::NOLOG);
Debug(1, "Success running sql query %s", query.c_str());
Debug(1, "Success running sql query %s, thread_id: %lu", query.c_str(), db_thread_id);
logger->databaseLevel(oldLevel);
return 1;
}

View File

@ -63,6 +63,7 @@ class zmDbRow {
extern MYSQL dbconn;
extern std::mutex db_mutex;
extern zmDbQueue dbQueue;
extern unsigned long db_thread_id;
extern bool zmDbConnected;

View File

@ -176,7 +176,7 @@ Event::~Event() {
std::string sql = stringtf(
"UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64 " AND Name='New Event'",
monitor->EventPrefix(), id, std::chrono::system_clock::to_time_t(end_time),
monitor->Substitute(monitor->EventPrefix(), start_time).c_str(), id, std::chrono::system_clock::to_time_t(end_time),
delta_time.count(),
frames, alarm_frames,
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,

View File

@ -52,6 +52,7 @@
#endif // HAVE_LIBVNC
#include <algorithm>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <chrono>
@ -1951,13 +1952,9 @@ bool Monitor::Analyse() {
/* try to stay behind the decoder. */
if (decoding != DECODING_NONE) {
while (!snap->decoded and !zm_terminate and !analysis_thread->Stopped() and !packetqueue.stopping()) {
// Need to wait for the decoder thread.
packetqueue.notify_all();
Debug(1, "Waiting for decode");
packet_lock->wait();
} // end while ! decoded
if (zm_terminate or analysis_thread->Stopped() or packetqueue.stopping()) {
if (!snap->decoded) {
// We no longer wait because we need to be checking the triggers and other inputs.
// Also the logic is too hairy. capture process can delete the packet that we have here.
delete packet_lock;
return false;
}
@ -2213,7 +2210,7 @@ bool Monitor::Analyse() {
// Alert means this frame has no motion, but we were alarmed and are still recording.
if ((noteSetMap.size() > 0) and event)
event->updateNotes(noteSetMap);
} else if (state == TAPE) {
} else if (state == TAPE || state == IDLE) {
if (event) {
if (section_length >= Seconds(min_section_length) && (event->Duration() >= section_length)) {
Debug(1, "%s: event %" PRIu64 ", has exceeded desired section length. %" PRIi64 " - %" PRIi64 " = %" PRIi64 " >= %" PRIi64,
@ -2771,23 +2768,25 @@ bool Monitor::Decode() {
return true;
} // end bool Monitor::Decode()
void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
if (!label_format[0])
return;
std::string Monitor::Substitute(const std::string &format, SystemTimePoint ts_time) const {
if (format.empty()) return "";
std::string text;
text.reserve(1024);
// Expand the strftime macros first
char label_time_text[256];
tm ts_tm = {};
time_t ts_time_t = std::chrono::system_clock::to_time_t(ts_time);
strftime(label_time_text, sizeof(label_time_text), label_format.c_str(), localtime_r(&ts_time_t, &ts_tm));
strftime(label_time_text, sizeof(label_time_text), format.c_str(), localtime_r(&ts_time_t, &ts_tm));
char label_text[1024];
const char *s_ptr = label_time_text;
char *d_ptr = label_text;
char *d_ptr = text.data();
while (*s_ptr && ((unsigned int)(d_ptr - label_text) < (unsigned int) sizeof(label_text))) {
if ( *s_ptr == config.timestamp_code_char[0] ) {
const auto max_len = sizeof(label_text) - (d_ptr - label_text);
while (*s_ptr && ((unsigned int)(d_ptr - text.data()) < text.capacity())) {
if (*s_ptr == config.timestamp_code_char[0]) {
const auto max_len = text.capacity() - (d_ptr - text.data());
bool found_macro = false;
int rc = 0;
switch ( *(s_ptr+1) ) {
@ -2807,10 +2806,11 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
found_macro = true;
break;
}
if (rc < 0 || static_cast<size_t>(rc) > max_len)
if (rc < 0 || static_cast<size_t>(rc) > max_len) {
break;
}
d_ptr += rc;
if ( found_macro ) {
if (found_macro) {
s_ptr += 2;
continue;
}
@ -2818,9 +2818,16 @@ void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
*d_ptr++ = *s_ptr++;
} // end while
*d_ptr = '\0';
Debug(2, "annotating %s", label_text);
ts_image->Annotate(label_text, label_coord, label_size);
Debug(2, "done annotating %s", label_text);
return text;
}
void Monitor::TimestampImage(Image *ts_image, SystemTimePoint ts_time) const {
if (!label_format[0])
return;
const std::string label_text = Substitute(label_format, ts_time);
ts_image->Annotate(label_text.c_str(), label_coord, label_size);
Debug(2, "done annotating %s", label_text.c_str());
} // end void Monitor::TimestampImage
Event * Monitor::openEvent(

View File

@ -809,6 +809,7 @@ public:
bool Decode();
bool Poll();
void DumpImage( Image *dump_image ) const;
std::string Substitute(const std::string &format, SystemTimePoint ts_time) const;
void TimestampImage(Image *ts_image, SystemTimePoint ts_time) const;
Event *openEvent(
const std::shared_ptr<ZMPacket> &snap,

View File

@ -124,7 +124,9 @@ int Monitor::JanusManager::check_janus() {
std::string postData = "{\"janus\" : \"message\", \"transaction\" : \"randomString\", \"body\" : {";
postData += "\"request\" : \"info\", \"id\" : ";
postData += std::to_string(parent->id);
postData += "}}";
postData += ", \"secret\" : \"";
postData += config.janus_secret;
postData += "\"}}";
std::string response;
std::string endpoint = janus_endpoint+"/"+janus_session+"/"+janus_handle;
@ -157,6 +159,13 @@ int Monitor::JanusManager::check_janus() {
Warning("Mountpoint Missing");
return 0;
}
//check for changed PIN
if (response.find(parent->janus_pin) == std::string::npos){
Warning("PIN changed, remounting.");
return remove_from_janus();
}
return 1;
}
@ -181,7 +190,7 @@ int Monitor::JanusManager::add_to_janus() {
postData += rtsp_path;
//secret prevents querying the mount for info, which leaks the camera's secrets.
postData += "\", \"secret\" : \"";
postData += parent->janus_pin;
postData += config.janus_secret;
//pin prevents viewing the video.
postData += "\", \"pin\" : \"";
postData += parent->janus_pin;
@ -245,7 +254,7 @@ int Monitor::JanusManager::remove_from_janus() {
postData += "\"request\" : \"destroy\", \"admin_key\" : \"";
postData += config.janus_secret;
postData += "\", \"secret\" : \"";
postData += parent->janus_pin;
postData += config.janus_secret;
postData += "\", \"id\" : ";
postData += std::to_string(parent->id);
postData += "}}";

View File

@ -1 +1 @@
1.37.23
1.37.24

View File

@ -18,9 +18,8 @@ if (!isset($_REQUEST['task'])) {
}
} else if ($_REQUEST['task'] == 'create' ) {
global $user;
if (!$user) {
// We allow any logged in user to create logs. This opens us up to DOS by malicious user
$message = 'Insufficient permissions to view log entries for user '.$user['Username'];
if (!$user or (!canEdit('System') and !ZM_LOG_INJECT)) {
$message = 'Insufficient permissions to create log entries for user '.$user['Username'];
} else {
createRequest();
}
@ -161,6 +160,7 @@ function queryRequest() {
// First strip out any html tags
// Second strip out all characters that are not ASCII 32-126 (yes, 126)
$row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message']));
$row['File'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['File']));
$rows[] = $row;
}
$data['rows'] = $rows;

View File

@ -96,40 +96,39 @@ if ( !empty($_REQUEST['gid']) ) {
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="groupForm" name="groupForm" method="post" action="?view=group&action=save">
<form id="groupForm" name="groupForm" method="post" action="?view=group">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="group"/>
<input type="hidden" name="gid" value="<?php echo $newGroup->Id() ?>"/>
<table id="groupModalTable" class="table-sm table-borderless">
<tbody>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newGroup[Name]" value="<?php echo validHtmlStr($newGroup->Name()) ?>" data-on-input="configModalBtns"/></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('ParentGroup') ?></th>
<td><?php echo parentGrpSelect($newGroup) ?></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Monitor') ?></th>
<td>
<select name="newGroup[MonitorIds][]" class="chosen" multiple="multiple" data-on-change="configModalBtns">
<?php echo monitorList($newGroup) ?>
</select>
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" name="action" id="grpModalSaveBtn" value="save"<?php $newGroup->Id() ? '' : ' disabled="disabled"'?>><?php echo translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
<div class="modal-body">
<table id="groupModalTable" class="table-sm table-borderless">
<tbody>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Name') ?></th>
<td><input type="text" name="newGroup[Name]" value="<?php echo validHtmlStr($newGroup->Name()) ?>" data-on-input="configModalBtns"/></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('ParentGroup') ?></th>
<td><?php echo parentGrpSelect($newGroup) ?></td>
</tr>
<tr>
<th class="text-right pr-3" scope="row"><?php echo translate('Monitor') ?></th>
<td>
<select name="newGroup[MonitorIds][]" class="chosen" multiple="multiple" data-on-change="configModalBtns">
<?php echo monitorList($newGroup) ?>
</select>
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" name="action" value="save" id="groupModalSaveBtn"<?php $newGroup->Id() ? '' : ' disabled="disabled"'?>><?php echo translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>
</div>
</div>
</div>

View File

@ -7,15 +7,15 @@
$null = '';
$checked = 'checked="checked"';
$sid = $_REQUEST['id'];
$sid = validInt($_REQUEST['id']);
if ( !canEdit('System') ) return;
if (!canEdit('System')) return;
require_once('includes/Server.php');
require_once('includes/Storage.php');
if ( $_REQUEST['id'] ) {
if ( !($newStorage = ZM\Storage::find_one(array('Id'=>$sid)) ) ) {
if ($_REQUEST['id']) {
if (!($newStorage = ZM\Storage::find_one(array('Id'=>$sid)))) {
// Perhaps do something different here, rather than return nothing
return;
}
@ -46,15 +46,14 @@
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="storageModalForm" name="contentForm" method="post" action="?view=storage&action=save" class="validateFormOnSubmit">
<?php
// We have to manually insert the csrf key into the form when using a modal generated via ajax call
echo getCSRFinputHTML();
?>
<input type="hidden" name="view" value="storage"/>
<input type="hidden" name="object" value="storage"/>
<input type="hidden" name="id" value="<?php echo validHtmlStr($sid) ?>"/>
<div class="modal-body">
<div class="table-responsive">
<table class="major table table-sm">
<tbody>
@ -102,10 +101,10 @@
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<button name="action" id="storageSubmitBtn" type="submit" class="btn btn-primary" value="Save"><?php echo translate('Save') ?></button>
<button name="action" id="storageSubmitBtn" type="submit" class="btn btn-primary" value="save"><?php echo translate('Save') ?></button>
<button type="button" class="btn btn-secondary" data-dismiss="modal"><?php echo translate('Cancel') ?></button>
</div>
</form>

View File

@ -1,7 +1,8 @@
<?php
error_reporting(0);
ini_set('display_errors', '');
$start_time = time();
$connkey = sprintf('%06d', $_REQUEST['connkey']);
define('MSG_TIMEOUT', ZM_WEB_AJAX_TIMEOUT/2);
define('MSG_DATA_SIZE', 4+256);
@ -13,182 +14,194 @@ if ( !($_REQUEST['connkey'] && $_REQUEST['command']) ) {
mkdir(ZM_PATH_SOCKS);
# The file that we point ftok to has to exist, and only exist if zms is running, so we are pointing it at the .sock
$key = ftok(ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'s.sock', 'Z');
$semaphore = sem_get($key,1);
$semaphore_tries = 10;
$key = $connkey;
$semaphore = sem_get($key, 1);
$have_semaphore = false;
while ($semaphore_tries) {
if (version_compare( phpversion(), '5.6.1', '<')) {
# don't have support for non-blocking
$have_semaphore = sem_acquire($semaphore);
} else {
$have_semaphore = sem_acquire($semaphore, 1);
}
if ($have_semaphore !== false) break;
ZM\Debug('Failed to get semaphore, trying again');
usleep(100000);
$semaphore_tries -= 1;
}
if ($have_semaphore !== false) {
if ( !($socket = @socket_create(AF_UNIX, SOCK_DGRAM, 0)) ) {
ajaxError('socket_create() failed: '.socket_strerror(socket_last_error()));
}
$localSocketFile = ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'w.sock';
if ( file_exists($localSocketFile) ) {
ZM\Warning("sock file $localSocketFile already exists?! Is someone else talking to zms?");
// They could be. We can maybe have concurrent requests from a browser.
}
if ( !socket_bind($socket, $localSocketFile) ) {
ajaxError("socket_bind( $localSocketFile ) failed: ".socket_strerror(socket_last_error()));
}
switch ( $_REQUEST['command'] ) {
case CMD_VARPLAY :
ZM\Debug('Varplaying to '.$_REQUEST['rate']);
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768);
break;
case CMD_ZOOMIN :
ZM\Debug('Zooming to '.$_REQUEST['x'].','.$_REQUEST['y']);
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
break;
case CMD_PAN :
ZM\Debug('Panning to '.$_REQUEST['x'].','.$_REQUEST['y']);
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
break;
case CMD_SCALE :
ZM\Debug('Scaling to '.$_REQUEST['scale']);
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['scale']);
break;
case CMD_SEEK :
# Pack int two 32 bit integers instead of trying to deal with floats
$msg = pack('lcNN', MSG_CMD, $_REQUEST['command'],
intval($_REQUEST['offset']),
1000000*( $_REQUEST['offset']-intval($_REQUEST['offset'])));
break;
case CMD_MAXFPS :
ZM\Debug('Maxfps to '.$_REQUEST['maxfps']);
# Pack int two 32 bit integers instead of trying to deal with floats
$msg = pack('lcNN', MSG_CMD, $_REQUEST['command'],
intval($_REQUEST['maxfps']),
1000000*( $_REQUEST['maxfps']-intval($_REQUEST['maxfps'])));
break;
default :
ZM\Debug('Sending command ' . $_REQUEST['command']);
$msg = pack('lc', MSG_CMD, $_REQUEST['command']);
break;
}
$remSockFile = ZM_PATH_SOCKS.'/zms-'.sprintf('%06d',$_REQUEST['connkey']).'s.sock';
// Pi can take up to 3 seconds for zms to start up.
$max_socket_tries = 1000;
// FIXME This should not exceed web_ajax_timeout
while ( !file_exists($remSockFile) && $max_socket_tries-- ) {
//sometimes we are too fast for our own good, if it hasn't been setup yet give it a second.
// WHY? We will just send another one...
// ANSWER: Because otherwise we get a log of errors logged
//ZM\Debug("$remSockFile does not exist, waiting, current " . (time() - $start_time) . ' seconds' );
usleep(1000);
}
if ( !file_exists($remSockFile) ) {
ajaxError("Socket $remSockFile does not exist. This file is created by zms, and since it does not exist, either zms did not run, or zms exited early. Please check your zms logs and ensure that CGI is enabled in apache and check that the PATH_ZMS is set correctly. Make sure that ZM is actually recording. If you are trying to view a live stream and the capture process (zmc) is not running then zms will exit. Please go to http://zoneminder.readthedocs.io/en/latest/faq.html#why-can-t-i-see-streamed-images-when-i-can-see-stills-in-the-zone-window-etc for more information.");
} else {
if ( !@socket_sendto($socket, $msg, strlen($msg), 0, $remSockFile) ) {
ajaxError("socket_sendto( $remSockFile ) failed: ".socket_strerror(socket_last_error()));
}
}
$rSockets = array($socket);
$wSockets = NULL;
$eSockets = NULL;
$timeout = MSG_TIMEOUT - ( time() - $start_time );
$numSockets = socket_select($rSockets, $wSockets, $eSockets, intval($timeout/1000), ($timeout%1000)*1000);
if ( $numSockets === false ) {
ajaxError('socket_select failed: '.socket_strerror(socket_last_error()));
} else if ( $numSockets < 0 ) {
ajaxError("Socket closed $remSockFile");
} else if ( $numSockets == 0 ) {
ZM\Error("Timed out waiting for msg $remSockFile after waiting $timeout seconds");
socket_set_nonblock($socket);
#ajaxError("Timed out waiting for msg $remSockFile");
} else if ( $numSockets > 0 ) {
if ( count($rSockets) != 1 ) {
ajaxError('Bogus return from select, '.count($rSockets).' sockets available');
}
}
switch ($nbytes = @socket_recvfrom($socket, $msg, MSG_DATA_SIZE, 0, $remSockFile)) {
case -1 :
ajaxError("socket_recvfrom( $remSockFile ) failed: ".socket_strerror(socket_last_error()));
break;
case 0 :
ajaxError('No data to read from socket');
break;
default :
if ( $nbytes != MSG_DATA_SIZE )
ajaxError("Got unexpected message size, got $nbytes, expected ".MSG_DATA_SIZE);
break;
}
$data = unpack('ltype', $msg);
switch ( $data['type'] ) {
case MSG_DATA_WATCH :
$data = unpack('ltype/imonitor/istate/dfps/dcapturefps/danalysisfps/ilevel/irate/ddelay/izoom/Cdelayed/Cpaused/Cenabled/Cforced', $msg);
$data['fps'] = round( $data['fps'], 2 );
$data['capturefps'] = round( $data['capturefps'], 2 );
$data['analysisfps'] = round( $data['analysisfps'], 2 );
$data['rate'] /= RATE_BASE;
$data['delay'] = round( $data['delay'], 2 );
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
if (ZM_OPT_USE_AUTH) {
if (ZM_AUTH_RELAY == 'hashed') {
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
if (isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash)) {
$data['auth'] = $auth_hash;
ZM\Debug('including new auth hash '.$data['auth'].'because doesnt match request auth hash '.$_REQUEST['auth']);
} else {
ZM\Debug('Not including new auth hash becase it hasn\'t changed '.$auth_hash);
}
}
$data['auth_relay'] = get_auth_relay();
}
ajaxResponse(array('status'=>$data));
break;
case MSG_DATA_EVENT :
if ( PHP_INT_SIZE===4 || version_compare( phpversion(), '5.6.0', '<') ) {
ZM\Debug('Using old unpack methods to handle 64bit event id');
$data = unpack('ltype/ieventlow/ieventhigh/dduration/dprogress/irate/izoom/Cpaused', $msg);
$data['event'] = $data['eventhigh'] << 32 | $data['eventlow'];
if ($semaphore) {
$semaphore_tries = 10;
while ($semaphore_tries) {
if (version_compare( phpversion(), '5.6.1', '<')) {
# don't have support for non-blocking
$have_semaphore = sem_acquire($semaphore);
} else {
$data = unpack('ltype/Qevent/dduration/dprogress/irate/izoom/Cpaused', $msg);
$have_semaphore = sem_acquire($semaphore, 1);
}
$data['rate'] /= RATE_BASE;
$data['zoom'] = round($data['zoom']/SCALE_BASE, 1);
if ( ZM_OPT_USE_AUTH ) {
if (ZM_AUTH_RELAY == 'hashed') {
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) {
$data['auth'] = $auth_hash;
}
}
$data['auth_relay'] = get_auth_relay();
}
ajaxResponse(array('status'=>$data));
break;
default :
ajaxError('Unexpected received message type '.$data['type']);
if ($have_semaphore !== false) break;
ZM\Debug('Failed to get semaphore for '.$connkey.' '.$key.', trying again');
usleep(100000);
$semaphore_tries -= 1;
}
sem_release($semaphore);
} else {
ajaxError('Unable to get semaphore.');
ZM\Error("Failed to get semaphore for key $key. It is likely that your php does not have the sysv semaphore extension either installed or enabled.");
}
if (!($socket = @socket_create(AF_UNIX, SOCK_DGRAM, 0))) {
if ($semaphore) sem_release($semaphore);
ajaxError('socket_create() failed: '.socket_strerror(socket_last_error()));
}
$localSocketFile = ZM_PATH_SOCKS.'/zms-'.$connkey.'w.sock';
if (!socket_bind($socket, $localSocketFile)) {
if ($semaphore) sem_release($semaphore);
ajaxError("socket_bind( $localSocketFile ) failed: ".socket_strerror(socket_last_error()));
}
switch ($_REQUEST['command']) {
case CMD_VARPLAY :
ZM\Debug('Varplaying to '.$_REQUEST['rate']);
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['rate']+32768);
break;
case CMD_ZOOMIN :
ZM\Debug('Zooming to '.$_REQUEST['x'].','.$_REQUEST['y']);
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
break;
case CMD_PAN :
ZM\Debug('Panning to '.$_REQUEST['x'].','.$_REQUEST['y']);
$msg = pack('lcnn', MSG_CMD, $_REQUEST['command'], $_REQUEST['x'], $_REQUEST['y']);
break;
case CMD_SCALE :
ZM\Debug('Scaling to '.$_REQUEST['scale']);
$msg = pack('lcn', MSG_CMD, $_REQUEST['command'], $_REQUEST['scale']);
break;
case CMD_SEEK :
# Pack int two 32 bit integers instead of trying to deal with floats
$msg = pack('lcNN', MSG_CMD, $_REQUEST['command'],
intval($_REQUEST['offset']),
1000000*( $_REQUEST['offset']-intval($_REQUEST['offset'])));
break;
case CMD_MAXFPS :
ZM\Debug('Maxfps to '.$_REQUEST['maxfps']);
# Pack int two 32 bit integers instead of trying to deal with floats
$msg = pack('lcNN', MSG_CMD, $_REQUEST['command'],
intval($_REQUEST['maxfps']),
1000000*( $_REQUEST['maxfps']-intval($_REQUEST['maxfps'])));
break;
default :
ZM\Debug('Sending command ' . $_REQUEST['command']);
$msg = pack('lc', MSG_CMD, $_REQUEST['command']);
break;
}
$remSockFile = ZM_PATH_SOCKS.'/zms-'.$connkey.'s.sock';
// Pi can take up to 3 seconds for zms to start up.
$max_socket_tries = 1000;
// FIXME This should not exceed web_ajax_timeout
while ( !file_exists($remSockFile) && $max_socket_tries-- ) {
//sometimes we are too fast for our own good, if it hasn't been setup yet give it a second.
// WHY? We will just send another one...
// ANSWER: Because otherwise we get a log of errors logged
//ZM\Debug("$remSockFile does not exist, waiting, current " . (time() - $start_time) . ' seconds' );
usleep(1000);
}
if (!file_exists($remSockFile)) {
if ($semaphore) sem_release($semaphore);
ajaxError("Socket $remSockFile does not exist. This file is created by zms, and since it does not exist, either zms did not run, or zms exited early. Please check your zms logs and ensure that CGI is enabled in apache and check that the PATH_ZMS is set correctly. Make sure that ZM is actually recording. If you are trying to view a live stream and the capture process (zmc) is not running then zms will exit. Please go to http://zoneminder.readthedocs.io/en/latest/faq.html#why-can-t-i-see-streamed-images-when-i-can-see-stills-in-the-zone-window-etc for more information.");
} else {
if (!@socket_sendto($socket, $msg, strlen($msg), 0, $remSockFile)) {
if ($semaphore) sem_release($semaphore);
ajaxError("socket_sendto( $remSockFile ) failed: ".socket_strerror(socket_last_error()));
}
}
$rSockets = array($socket);
$wSockets = NULL;
$eSockets = NULL;
$timeout = MSG_TIMEOUT - ( time() - $start_time );
$numSockets = socket_select($rSockets, $wSockets, $eSockets, intval($timeout/1000), ($timeout%1000)*1000);
if ( $numSockets === false ) {
if ($semaphore) sem_release($semaphore);
ajaxError('socket_select failed: '.socket_strerror(socket_last_error()));
} else if ( $numSockets < 0 ) {
if ($semaphore) sem_release($semaphore);
ajaxError("Socket closed $remSockFile");
} else if ( $numSockets == 0 ) {
ZM\Error("Timed out waiting for msg $remSockFile after waiting $timeout seconds");
socket_set_nonblock($socket);
#ajaxError("Timed out waiting for msg $remSockFile");
} else if ( $numSockets > 0 ) {
if ( count($rSockets) != 1 ) {
if ($semaphore) sem_release($semaphore);
ajaxError('Bogus return from select, '.count($rSockets).' sockets available');
}
}
switch ($nbytes = @socket_recvfrom($socket, $msg, MSG_DATA_SIZE, 0, $remSockFile)) {
case -1 :
if ($semaphore) sem_release($semaphore);
ajaxError("socket_recvfrom( $remSockFile ) failed: ".socket_strerror(socket_last_error()));
break;
case 0 :
if ($semaphore) sem_release($semaphore);
ajaxError('No data to read from socket');
break;
default :
if ( $nbytes != MSG_DATA_SIZE ) {
sem_release($semaphore);
ajaxError("Got unexpected message size, got $nbytes, expected ".MSG_DATA_SIZE);
}
break;
}
$data = unpack('ltype', $msg);
switch ( $data['type'] ) {
case MSG_DATA_WATCH :
$data = unpack('ltype/imonitor/istate/dfps/dcapturefps/danalysisfps/ilevel/irate/ddelay/izoom/Cdelayed/Cpaused/Cenabled/Cforced', $msg);
$data['fps'] = round( $data['fps'], 2 );
$data['capturefps'] = round( $data['capturefps'], 2 );
$data['analysisfps'] = round( $data['analysisfps'], 2 );
$data['rate'] /= RATE_BASE;
$data['delay'] = round( $data['delay'], 2 );
$data['zoom'] = round( $data['zoom']/SCALE_BASE, 1 );
if (ZM_OPT_USE_AUTH) {
if (ZM_AUTH_RELAY == 'hashed') {
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
if (isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash)) {
$data['auth'] = $auth_hash;
ZM\Debug('including new auth hash '.$data['auth'].'because doesnt match request auth hash '.$_REQUEST['auth']);
} else {
ZM\Debug('Not including new auth hash becase it hasn\'t changed '.$auth_hash);
}
}
$data['auth_relay'] = get_auth_relay();
}
if ($semaphore) sem_release($semaphore);
ajaxResponse(array('status'=>$data));
break;
case MSG_DATA_EVENT :
if ( PHP_INT_SIZE===4 || version_compare( phpversion(), '5.6.0', '<') ) {
ZM\Debug('Using old unpack methods to handle 64bit event id');
$data = unpack('ltype/ieventlow/ieventhigh/dduration/dprogress/irate/izoom/Cpaused', $msg);
$data['event'] = $data['eventhigh'] << 32 | $data['eventlow'];
} else {
$data = unpack('ltype/Qevent/dduration/dprogress/irate/izoom/Cpaused', $msg);
}
$data['rate'] /= RATE_BASE;
$data['zoom'] = round($data['zoom']/SCALE_BASE, 1);
if ( ZM_OPT_USE_AUTH ) {
if (ZM_AUTH_RELAY == 'hashed') {
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) {
$data['auth'] = $auth_hash;
}
}
$data['auth_relay'] = get_auth_relay();
}
if ($semaphore) sem_release($semaphore);
ajaxResponse(array('status'=>$data));
break;
default :
if ($semaphore) sem_release($semaphore);
ajaxError('Unexpected received message type '.$data['type']);
}
if ($semaphore) sem_release($semaphore);
ajaxError('Unrecognised action or insufficient permissions in ajax/stream');
function ajaxCleanup() {

View File

@ -74,7 +74,7 @@ class FilterComponent extends Component {
if (preg_match('/^(?P<field>[a-z0-9]+)(?P<operator>.+)?$/i', $lhs, $matches) !== 1) {
throw new Exception('Invalid argument before `:`: ' . $lhs);
}
$operator = trim($matches['operator']);
$operator = isset($matches['operator']) ? trim($matches['operator']) : '';
// Only allow operators on our allow list. No operator
// specified defaults to `=` by cakePHP.

View File

@ -20,6 +20,17 @@ class LogsController extends AppController {
'paramType' => 'querystring'
);
public function beforeFilter() {
parent::beforeFilter();
global $user;
# We already tested for auth in appController, so we just need to test for specific permission
$canView = (!$user) || ($user['System'] != 'None');
if (!$canView) {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
}
/**
* index method
*
@ -54,6 +65,12 @@ class LogsController extends AppController {
* @return void
*/
public function add() {
global $user;
$canAdd = (!$user) || (($user['System'] == 'Edit') || ZM_LOG_INJECT);
if (!$canAdd) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if ($this->request->is('post')) {
$this->Log->create();
if ($this->Log->save($this->request->data)) {
@ -70,6 +87,13 @@ class LogsController extends AppController {
* @return void
*/
public function edit($id = null) {
global $user;
$canEdit = (!$user) || ($user['System'] == 'Edit');
if (!$canEdit) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
if (!$this->Log->exists($id)) {
throw new NotFoundException(__('Invalid log'));
}
@ -91,6 +115,11 @@ class LogsController extends AppController {
* @return void
*/
public function delete($id = null) {
$canDelete = (!$user) || ($user['System'] == 'Edit');
if (!$canDelete) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
$this->Log->id = $id;
if (!$this->Log->exists()) {
throw new NotFoundException(__('Invalid log'));

View File

@ -97,6 +97,10 @@ class MonitorsController extends AppController {
)
);
$monitor = $this->Monitor->find('first', $options);
if ($monitor['Monitor']['JanusEnabled']) {
require_once __DIR__ .'/../../../includes/Monitor.php';
$monitor['Monitor']['Janus_Pin'] = (new ZM\Monitor($monitor['Monitor']))->Janus_Pin();
}
$this->set(array(
'monitor' => $monitor,
'_serialize' => array('monitor')

View File

@ -54,7 +54,13 @@ class Monitor extends AppModel {
'message' => 'Monitor Name must be specified for creation',
'required' => true,
),
)
),
// These codec values mimic acceptable ones for FFMPEG
// Edit this if the list in ZM changes
'OutputCodec' => array (
'rule' => array('inList', array (0,27,173,167,226)),
'message'=>'Invalid value. Should be one of these integer values: 0(auto), 27(h264), 173(h265/hvec), 167(vp9), 226(av1)'
)
);
@ -122,7 +128,8 @@ class Monitor extends AppModel {
'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL','WebSite', 'VNC'),
'Function' => array('None','Monitor','Modect','Record','Mocord','Nodect'),
'Orientation' => array('ROTATE_0','ROTATE_90','ROTATE_180','ROTATE_270','FLIP_HORI','FLIP_VERT'),
'OutputCodec' => array('h264','mjpeg','mpeg1','mpeg2'),
// mask OutputCodec as its not an Enum in mysql
//'OutputCodec' => array( 'h264' ,'mjpeg','mpeg1','mpeg2'),
'OutputContainer' => array('auto','mp4','mkv'),
'DefaultView' => array('Events','Control'),
#'Status' => array('Unknown','NotRunning','Running','NoSignal','Signal'),

View File

@ -270,12 +270,22 @@ public static function getStatuses() {
'ArchivedEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1),
);
public function Janus_Pin() {
$cmd = getZmuCommand(' --janus-pin -m '.$this->{'Id'});
$output = shell_exec($cmd);
Debug("Running $cmd output: $output");
return $output ? trim($output) : $output;
if (!$this->{'JanusEnabled'}) return '';
if ((!defined('ZM_SERVER_ID')) or ( property_exists($this, 'ServerId') and (ZM_SERVER_ID==$this->{'ServerId'}) )) {
$cmd = getZmuCommand(' --janus-pin -m '.$this->{'Id'});
$output = shell_exec($cmd);
Debug("Running $cmd output: $output");
return $output ? trim($output) : $output;
} else if ($this->ServerId()) {
$result = $this->Server()->SendToApi('/monitors/'.$this->{'Id'}.'.json');
$json = json_decode($result, true);
return ((isset($json['monitor']) and isset($json['monitor']['Monitor']) and isset($json['monitor']['Monitor']['Janus_Pin'])) ? $json['monitor']['Monitor']['Janus_Pin'] : '');
} else {
Error('Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.');
}
}
public function Control() {
if (!property_exists($this, 'Control')) {
if ($this->ControlId())
@ -289,8 +299,12 @@ public static function getStatuses() {
public function Server() {
if (!property_exists($this, 'Server')) {
if ($this->ServerId())
if ($this->ServerId()) {
$this->{'Server'} = Server::find_one(array('Id'=>$this->{'ServerId'}));
if (!$this->{'Server'}) {
$this->{'Server'} = new Server();
}
}
if (!property_exists($this, 'Server')) {
$this->{'Server'} = new Server();
}
@ -522,31 +536,7 @@ public static function getStatuses() {
}
}
} else if ($this->ServerId()) {
$Server = $this->Server();
$url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zmc.json';
if (ZM_OPT_USE_AUTH) {
if (ZM_AUTH_RELAY == 'hashed') {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
} else if (ZM_AUTH_RELAY == 'plain') {
$url .= '?user='.$_SESSION['username'];
$url .= '?pass='.$_SESSION['password'];
} else {
Error('Multi-Server requires AUTH_RELAY be either HASH or PLAIN');
return;
}
}
Debug('sending command to '.$url);
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error("Error restarting zmc using $url");
}
} catch (Exception $e) {
Error("Except $e thrown trying to restart zmc");
}
$result = $this->Server()->SendToApi('/monitors/daemonControl/'.$this->{'Id'}.'/'.$mode.'/zmc.json');
} else {
Error('Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.');
}
@ -727,32 +717,8 @@ public static function getStatuses() {
}
socket_close($socket);
} else if ($this->ServerId()) {
$Server = $this->Server();
$url = $Server->UrlToApi().'/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json';
if (ZM_OPT_USE_AUTH) {
if (ZM_AUTH_RELAY == 'hashed') {
$url .= '?auth='.generateAuthHash(ZM_AUTH_HASH_IPS);
} else if (ZM_AUTH_RELAY == 'plain') {
$url .= '?user='.$_SESSION['username'];
$url .= '?pass='.$_SESSION['password'];
} else if (ZM_AUTH_RELAY == 'none') {
$url .= '?user='.$_SESSION['username'];
}
}
Debug('sending command to '.$url);
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error("Error sending command using $url");
return false;
}
} catch (Exception $e) {
Error("Exception $e thrown trying to send command to $url");
return false;
}
$result = $this->Server()->SendToApi('/monitors/daemonControl/'.$this->{'Id'}.'/'.$command.'/zmcontrol.pl.json');
return $result;
} else {
Error('Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.');
return false;
@ -820,33 +786,19 @@ public static function getStatuses() {
}
if ($this->ServerId()) {
$Server = $this->Server();
$result = $this->Server()->SendToApi('/monitors/alarm/id:'.$this->{'Id'}.'/command:'.$cmd.'.json');
$url = $Server->UrlToApi().'/monitors/alarm/id:'.$this->{'Id'}.'/command:'.$cmd.'.json';
$auth_relay = get_auth_relay();
if ($auth_relay) $url .= '?'.$auth_relay;
Debug('sending command to '.$url);
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error('Error sending command using '.$url);
return false;
}
Debug('Result '.$result);
$json = json_decode($result, true);
return $json['status'];
} catch (Exception $e) {
Error("Exception $e thrown trying to send command to $url");
if ($result === FALSE) { /* Handle error */
Error('Error sending command using '.$url);
return false;
}
$json = json_decode($result, true);
return $json['status'];
} // end if we are on the recording server
Error('Server not assigned to Monitor in a multi-server setup. Please assign a server to the Monitor.');
return false;
}
function TriggerOn() {
$output = $this->AlarmCommand('on');
if ($output and preg_match('/Alarmed event id: (\d+)$/', $output, $matches)) {

View File

@ -145,5 +145,22 @@ class Server extends ZM_Object {
}
return '/zm/api';
}
public function SendToApi($path) {
$url = $this->UrlToApi().$path;
$auth_relay = get_auth_relay();
if ($auth_relay) $url .= '?'.$auth_relay;
Debug('sending command to '.$url);
$context = stream_context_create();
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error("Error using $url");
}
} catch (Exception $e) {
Error("Except $e thrown sending to $url");
}
return $result;
}
} # end class Server
?>

View File

@ -24,12 +24,12 @@ if ( !canEdit('System') ) {
return;
}
if ( $action == 'save' ) {
if ($action == 'save') {
$storage = new ZM\Storage($_REQUEST['id']);
$changes = $storage->changes($_REQUEST['newStorage']);
if ( count($changes) ) {
if (count($changes)) {
$storage->save($changes);
$refreshParent = true;
}

View File

@ -220,7 +220,7 @@ function getAuthUser($auth) {
return null;
} // end getAuthUser($auth)
function calculateAuthHash($remoteAddr) {
function calculateAuthHash($remoteAddr='') {
global $user;
$local_time = localtime();
$authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$remoteAddr.$local_time[2].$local_time[3].$local_time[4].$local_time[5];
@ -230,21 +230,29 @@ function calculateAuthHash($remoteAddr) {
function generateAuthHash($useRemoteAddr, $force=false) {
global $user;
if (ZM_OPT_USE_AUTH and (ZM_AUTH_RELAY == 'hashed') and isset($user['Username']) and isset($user['Password']) and isset($_SESSION)) {
if (ZM_OPT_USE_AUTH and (ZM_AUTH_RELAY == 'hashed') and isset($user['Username']) and isset($user['Password'])) {
$time = time();
# We use 1800 so that we regenerate the hash at half the TTL
$mintime = $time - (ZM_AUTH_HASH_TTL * 1800);
# Appending the remoteAddr prevents us from using an auth hash generated for a different ip
if ($force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime )) {
$auth = calculateAuthHash($useRemoteAddr?$_SESSION['remoteAddr']:'');
# Don't both regenerating Auth Hash if an hour hasn't gone by yet
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
$_SESSION['AuthHashGeneratedAt'] = $time;
# Because we don't write out the session, it shouldn't actually get written out to disk. However if it does, the GeneratedAt should protect us.
} # end if AuthHash is not cached
return $_SESSION['AuthHash'.$_SESSION['remoteAddr']];
if (!isset($_SESSION)) {
# Appending the remoteAddr prevents us from using an auth hash generated for a different ip
#$auth = calculateAuthHash($useRemoteAddr?$_SESSION['remoteAddr']:'');
$auth = calculateAuthHash();
return $auth;
} else {
# Appending the remoteAddr prevents us from using an auth hash generated for a different ip
if ($force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime )) {
$auth = calculateAuthHash($useRemoteAddr?$_SESSION['remoteAddr']:'');
# Don't both regenerating Auth Hash if an hour hasn't gone by yet
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
$_SESSION['AuthHashGeneratedAt'] = $time;
# Because we don't write out the session, it shouldn't actually get written out to disk. However if it does, the GeneratedAt should protect us.
} # end if AuthHash is not cached
return $_SESSION['AuthHash'.$_SESSION['remoteAddr']];
}
} else {
ZM\Debug("Not able to generate auth hash due to user: ".print_r($user, true));
} # end if using AUTH and AUTH_RELAY
return '';
}

View File

@ -418,7 +418,7 @@ function makeLink($url, $label, $condition=1, $options='') {
//Make it slightly easier to create a link to help text modal
function makeHelpLink($ohndx) {
$string = '&nbsp;(<a id="' .$ohndx. '" class="optionhelp" href="#">?</a>)';
$string = '&nbsp;(<a id="' .$ohndx. '" class="optionhelp">?</a>)';
return $string;
}
@ -1135,7 +1135,7 @@ function sortHeader($field, $querySep='&amp;') {
global $view;
return implode($querySep, array(
'?view='.$view,
'page=1'.(isset($_REQUEST['filter'])?$_REQUEST['filter']['query']:''),
'page=1'.((isset($_REQUEST['filter']) and isset($_REQUEST['filter']['query'])) ? $_REQUEST['filter']['query'] : ''),
'sort_field='.$field,
'sort_asc='.( ( isset($_REQUEST['sort_field']) and ( $_REQUEST['sort_field'] == $field ) ) ? !$_REQUEST['sort_asc'] : 0),
'limit='.(isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : ''),
@ -1856,7 +1856,7 @@ define('HTTP_STATUS_FORBIDDEN', 403);
function ajaxError($message, $code=HTTP_STATUS_OK) {
$backTrace = debug_backtrace();
ZM\Error($message.' from '.print_r($backTrace,true));
ZM\Debug($message.' from '.print_r($backTrace, true));
if ( function_exists('ajaxCleanup') )
ajaxCleanup();
if ( $code == HTTP_STATUS_OK ) {
@ -2366,7 +2366,7 @@ function extract_auth_values_from_url($url) {
return array( $username, $password );
}
function output_file($path) {
function output_file($path, $chunkSize=1024) {
if (connection_status() != 0)
return false;
$parts = pathinfo($path);
@ -2378,12 +2378,11 @@ function output_file($path) {
header("Content-Transfer-Encoding: binary");
header("Content-Type: $contentType");
$contentDisposition = 'attachment'; if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
$fileName = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1);
header("Content-Disposition: $contentDisposition;filename=\"$file\"");
} else {
header("Content-Disposition: $contentDisposition;filename=\"$file\"");
$contentDisposition = 'inline';
if (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
$file = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1);
}
header("Content-Disposition: $contentDisposition;filename=\"$file\"");
header('Accept-Ranges: bytes');
$range = 0;
@ -2400,7 +2399,7 @@ function output_file($path) {
} else {
$size2 = $size - 1;
header("Content-Range: bytes 0-$size2/$size");
header("Content-Length: " . $size);
header('Content-Length: ' . $size);
}
if ($size == 0) {

View File

@ -203,8 +203,12 @@ foreach ( getSkinIncludes('skin.php') as $includeFile ) {
require_once $includeFile;
}
if ( isset($_REQUEST['action']) )
$action = detaintPath($_REQUEST['action']);
if (isset($_POST['action'])) {
# Actions can only be performed on POST because we don't check csrf on GETs.
$action = detaintPath($_POST['action']);
} else if (isset($_REQUEST['action'])) {
ZM\Error('actions can no longer be performed without POST.');
}
# The only variable we really need to set is action. The others are informal.
isset($view) || $view = NULL;
@ -235,7 +239,7 @@ if (
}
# Need to include actions because it does auth
if ( $action and !$request ) {
if ( $action and $view and !$request ) {
if ( file_exists('includes/actions/'.$view.'.php') ) {
ZM\Debug("Including includes/actions/$view.php");
require_once('includes/actions/'.$view.'.php');

View File

@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
$j.ajaxSetup({timeout: AJAX_TIMEOUT});
var reportLogs = true;
const reportLogs = (ZM_LOG_INJECT !== '0' || canEdit["System"]);
if ( !window.console ) {
window.console =

View File

@ -110,6 +110,7 @@ table th:last-child{
}
a.optionhelp,
a:link {
color: #0fbcf9;
text-decoration: none;
@ -758,7 +759,7 @@ a.flip {
padding: 4px 10px 7px 10px;
}
#shutdownButton {
padding: 3px 10px 5px 10px;
padding: 4px 10px 4px 10px;
color: white;
}
#shutdownButton i {

View File

@ -938,7 +938,7 @@ function exportEvents(
#if ( preg_match('/\.html$/', $file) )
#continue;
if ($exportStructure == 'flat') {
if (false !== strpos($file, $event->Id())) {
if (false !== strpos($file, strval($event->Id()))) {
$cmd = 'cp -as '.$event->Path().'/'.$file.' '.$export_dir.'/'.$file. ' 2>&1';
$exportFileList[] = $file;
} else {

View File

@ -119,7 +119,7 @@ echo output_link_if_exists(array(
'css/base/skin.css',
'css/base/views/'.$basename.'.css',
'js/dateTimePicker/jquery-ui-timepicker-addon.css',
'js/jquery-ui-1.12.1/jquery-ui.structure.min.css',
'js/jquery-ui-1.13.2/jquery-ui.structure.min.css',
), true);
if ( $css != 'base' )
echo output_link_if_exists(array(
@ -128,7 +128,7 @@ if ( $css != 'base' )
'css/'.$css.'/jquery-ui-theme.css',
));
?>
<link rel="stylesheet" href="skins/classic/js/jquery-ui-1.12.1/jquery-ui.theme.min.css" type="text/css"/>
<link rel="stylesheet" href="skins/classic/js/jquery-ui-1.13.2/jquery-ui.theme.min.css" type="text/css"/>
<?php #Chosen can't be cache-busted because it loads sprites by relative path ?>
<link rel="stylesheet" href="skins/classic/js/chosen/chosen.min.css" type="text/css"/>
<?php
@ -940,7 +940,7 @@ function xhtmlFooter() {
$viewJsPhpFile = getSkinFile('views/js/'.$basename.'.js.php');
?>
<script src="<?php echo cache_bust('skins/'.$skin.'/js/jquery.min.js'); ?>"></script>
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.13.2/jquery-ui.min.js"></script>
<script src="<?php echo cache_bust('js/ajaxQueue.js') ?>"></script>
<script src="skins/<?php echo $skin; ?>/js/bootstrap-4.5.0.min.js"></script>
<?php echo output_script_if_exists(array(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -312,7 +312,7 @@ Mani Mishra <manimishra902@gmail.com>
Hannah Methvin <hannahmethvin@gmail.com>
Leonardo Balter <leonardo.balter@gmail.com>
Benjamin Albert <benjamin_a5@yahoo.com>
Michał Gołębiowski <m.goleb@gmail.com>
Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
Alyosha Pushak <alyosha.pushak@gmail.com>
Fahad Ahmad <fahadahmad41@hotmail.com>
Matt Brundage <github@mattbrundage.com>
@ -331,3 +331,42 @@ Peter Dave Hello <hsu@peterdavehello.org>
Johannes Schäfer <johnschaefer@gmx.de>
Ville Skyttä <ville.skytta@iki.fi>
Ryan Oriecuia <ryan.oriecuia@visioncritical.com>
Sergei Ratnikov <sergeir82@gmail.com>
milk54 <milk851@gmail.com>
Evelyn Masso <evoutofambit@gmail.com>
Robin <mail@robin-fowler.com>
Simon Asika <asika32764@gmail.com>
Kevin Cupp <kevin.cupp@gmail.com>
Jeremy Mickelson <Jeremy.Mickelson@gmail.com>
Kyle Rosenberg <kyle.rosenberg@gmail.com>
Petri Partio <petri.partio@gmail.com>
pallxk <github@pallxk.com>
Luke Brookhart <luke@onjax.com>
claudi <hirt-claudia@gmx.de>
Eirik Sletteberg <eiriksletteberg@gmail.com>
Albert Johansson <albert@intervaro.se>
A. Wells <borgboyone@users.noreply.github.com>
Robert Brignull <robertbrignull@gmail.com>
Horus68 <pauloizidoro@gmail.com>
Maksymenkov Eugene <foatei@gmail.com>
OskarNS <soerensen.oskar@gmail.com>
Gez Quinn <holla@gezquinn.design>
jigar gala <jigar.gala140291@gmail.com>
Florian Wegscheider <flo.wegscheider@gmail.com>
Fatér Zsolt <fater.zsolt@gmail.com>
Szabolcs Szabolcsi-Toth <nec@shell8.net>
Jérémy Munsch <github@jeremydev.ovh>
Hrvoje Novosel <hrvoje.novosel@gmail.com>
Paul Capron <PaulCapron@users.noreply.github.com>
Micah Miller <mikhey@runbox.com>
sakshi87 <53863764+sakshi87@users.noreply.github.com>
Mikolaj Wolicki <wolicki.mikolaj@gmail.com>
Patrick McKay <patrick.mckay@vumc.org>
c-lambert <58025159+c-lambert@users.noreply.github.com>
Josep Sanz <josepsanzcamp@gmail.com>
Ben Mullins <benm@umich.edu>
Christian Oliff <christianoliff@pm.me>
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Adam Lidén Hällgren <adamlh92@gmail.com>
James Hinderks <hinderks@gmail.com>
Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com>

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -58,7 +58,6 @@
<h1>YOUR COMPONENTS:</h1>
<!-- Accordion -->
<h2 class="demoHeaders">Accordion</h2>
<div id="accordion">
@ -70,23 +69,17 @@
<div>Nam dui erat, auctor a, dignissim quis.</div>
</div>
<!-- Autocomplete -->
<h2 class="demoHeaders">Autocomplete</h2>
<div>
<input id="autocomplete" title="type &quot;a&quot;">
</div>
<!-- Button -->
<h2 class="demoHeaders">Button</h2>
<button id="button">A button element</button>
<button id="button-icon">An icon-only button</button>
<!-- Checkboxradio -->
<h2 class="demoHeaders">Checkboxradio</h2>
<form style="margin-top: 1em;">
@ -97,8 +90,6 @@
</div>
</form>
<!-- Controlgroup -->
<h2 class="demoHeaders">Controlgroup</h2>
<fieldset>
@ -125,8 +116,6 @@
</div>
</fieldset>
<!-- Tabs -->
<h2 class="demoHeaders">Tabs</h2>
<div id="tabs">
@ -140,8 +129,6 @@
<div id="tabs-3">Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue.</div>
</div>
<h2 class="demoHeaders">Dialog</h2>
<p>
<button id="dialog-link" class="ui-button ui-corner-all ui-widget">
@ -167,7 +154,6 @@
</div>
<h2 class="demoHeaders">Framework Icons (content color preview)</h2>
<ul id="icons" class="ui-widget ui-helper-clearfix">
<li class="ui-state-default ui-corner-all" title=".ui-icon-caret-1-n"><span class="ui-icon ui-icon-caret-1-n"></span></li>
@ -345,25 +331,18 @@
<li class="ui-state-default ui-corner-all" title=".ui-icon-grip-diagonal-se"><span class="ui-icon ui-icon-grip-diagonal-se"></span></li>
</ul>
<!-- Slider -->
<h2 class="demoHeaders">Slider</h2>
<div id="slider"></div>
<!-- Datepicker -->
<h2 class="demoHeaders">Datepicker</h2>
<div id="datepicker"></div>
<!-- Progressbar -->
<h2 class="demoHeaders">Progressbar</h2>
<div id="progressbar"></div>
<!-- Progressbar -->
<h2 class="demoHeaders">Selectmenu</h2>
<select id="selectmenu">
@ -374,14 +353,10 @@
<option>Faster</option>
</select>
<!-- Spinner -->
<h2 class="demoHeaders">Spinner</h2>
<input id="spinner">
<!-- Menu -->
<h2 class="demoHeaders">Menu</h2>
<ul style="width:100px;" id="menu">
@ -400,8 +375,6 @@
<li><div>Item 5</div></li>
</ul>
<!-- Tooltip -->
<h2 class="demoHeaders">Tooltip</h2>
<p id="tooltip">
@ -409,7 +382,6 @@
the element with your mouse, the title attribute is displayed in a little box next to the element, just like a native tooltip.
</p>
<!-- Highlight / Error -->
<h2 class="demoHeaders">Highlight / Error</h2>
<div class="ui-widget">
@ -429,11 +401,8 @@ the element with your mouse, the title attribute is displayed in a little box ne
<script src="external/jquery/jquery.js"></script>
<script src="jquery-ui.js"></script>
<script>
$( "#accordion" ).accordion();
var availableTags = [
"ActionScript",
"AppleScript",
@ -462,28 +431,18 @@ $( "#autocomplete" ).autocomplete({
source: availableTags
});
$( "#button" ).button();
$( "#button-icon" ).button({
icon: "ui-icon-gear",
showLabel: false
});
$( "#radioset" ).buttonset();
$( "#controlgroup" ).controlgroup();
$( "#tabs" ).tabs();
$( "#dialog" ).dialog({
autoOpen: false,
width: 400,
@ -509,42 +468,27 @@ $( "#dialog-link" ).click(function( event ) {
event.preventDefault();
});
$( "#datepicker" ).datepicker({
inline: true
});
$( "#slider" ).slider({
range: true,
values: [ 17, 67 ]
});
$( "#progressbar" ).progressbar({
value: 20
});
$( "#spinner" ).spinner();
$( "#menu" ).menu();
$( "#tooltip" ).tooltip();
$( "#selectmenu" ).selectmenu();
// Hover states on the static widgets
$( "#dialog-link, #icons li" ).hover(
function() {

View File

@ -1,4 +1,4 @@
/*! jQuery UI - v1.12.1 - 2016-09-14
/*! jQuery UI - v1.13.2 - 2022-07-14
* http://jqueryui.com
* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
@ -45,7 +45,7 @@
left: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0); /* support: IE8 */
-ms-filter: "alpha(opacity=0)"; /* support: IE8 */
}
.ui-front {
@ -664,7 +664,7 @@ button.ui-button::-moz-focus-inner {
.ui-progressbar .ui-progressbar-overlay {
background: url("data:image/gif;base64,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");
height: 100%;
filter: alpha(opacity=25); /* support: IE8 */
-ms-filter: "alpha(opacity=25)"; /* support: IE8 */
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
@ -728,7 +728,7 @@ button.ui-button::-moz-focus-inner {
z-index: 2;
width: 1.2em;
height: 1.2em;
cursor: default;
cursor: pointer;
-ms-touch-action: none;
touch-action: none;
}
@ -1041,18 +1041,18 @@ a.ui-button:active,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
filter:Alpha(Opacity=70); /* support: IE8 */
-ms-filter: "alpha(opacity=70)"; /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
filter:Alpha(Opacity=35); /* support: IE8 */
-ms-filter: "alpha(opacity=35)"; /* support: IE8 */
background-image: none;
}
.ui-state-disabled .ui-icon {
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
-ms-filter: "alpha(opacity=35)"; /* support: IE8 - See #6059 */
}
/* Icons
@ -1093,7 +1093,10 @@ a.ui-button:active,
}
/* positioning */
.ui-icon-blank { background-position: 16px 16px; }
/* Three classes needed to override `.ui-button:hover .ui-icon` */
.ui-icon-blank.ui-icon-blank.ui-icon-blank {
background-image: none;
}
.ui-icon-caret-1-n { background-position: 0 0; }
.ui-icon-caret-1-ne { background-position: -16px 0; }
.ui-icon-caret-1-e { background-position: -32px 0; }
@ -1304,7 +1307,7 @@ a.ui-button:active,
.ui-widget-overlay {
background: #aaaaaa;
opacity: .003;
filter: Alpha(Opacity=.3); /* support: IE8 */
-ms-filter: Alpha(Opacity=.3); /* support: IE8 */
}
.ui-widget-shadow {
-webkit-box-shadow: 0px 0px 5px #666666;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
/*!
* jQuery UI CSS Framework 1.12.1
* jQuery UI CSS Framework 1.13.2
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
@ -49,7 +49,7 @@
left: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0); /* support: IE8 */
-ms-filter: "alpha(opacity=0)"; /* support: IE8 */
}
.ui-front {
@ -668,7 +668,7 @@ button.ui-button::-moz-focus-inner {
.ui-progressbar .ui-progressbar-overlay {
background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
height: 100%;
filter: alpha(opacity=25); /* support: IE8 */
-ms-filter: "alpha(opacity=25)"; /* support: IE8 */
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
@ -732,7 +732,7 @@ button.ui-button::-moz-focus-inner {
z-index: 2;
width: 1.2em;
height: 1.2em;
cursor: default;
cursor: pointer;
-ms-touch-action: none;
touch-action: none;
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
/*!
* jQuery UI CSS Framework 1.12.1
* jQuery UI CSS Framework 1.13.2
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
@ -172,18 +172,18 @@ a.ui-button:active,
.ui-widget-content .ui-priority-secondary,
.ui-widget-header .ui-priority-secondary {
opacity: .7;
filter:Alpha(Opacity=70); /* support: IE8 */
-ms-filter: "alpha(opacity=70)"; /* support: IE8 */
font-weight: normal;
}
.ui-state-disabled,
.ui-widget-content .ui-state-disabled,
.ui-widget-header .ui-state-disabled {
opacity: .35;
filter:Alpha(Opacity=35); /* support: IE8 */
-ms-filter: "alpha(opacity=35)"; /* support: IE8 */
background-image: none;
}
.ui-state-disabled .ui-icon {
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
-ms-filter: "alpha(opacity=35)"; /* support: IE8 - See #6059 */
}
/* Icons
@ -224,7 +224,10 @@ a.ui-button:active,
}
/* positioning */
.ui-icon-blank { background-position: 16px 16px; }
/* Three classes needed to override `.ui-button:hover .ui-icon` */
.ui-icon-blank.ui-icon-blank.ui-icon-blank {
background-image: none;
}
.ui-icon-caret-1-n { background-position: 0 0; }
.ui-icon-caret-1-ne { background-position: -16px 0; }
.ui-icon-caret-1-e { background-position: -32px 0; }
@ -435,7 +438,7 @@ a.ui-button:active,
.ui-widget-overlay {
background: #aaaaaa;
opacity: .003;
filter: Alpha(Opacity=.3); /* support: IE8 */
-ms-filter: Alpha(Opacity=.3); /* support: IE8 */
}
.ui-widget-shadow {
-webkit-box-shadow: 0px 0px 5px #666666;

File diff suppressed because one or more lines are too long

View File

@ -2,19 +2,14 @@
"name": "jquery-ui",
"title": "jQuery UI",
"description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
"version": "1.12.1",
"version": "1.13.2",
"homepage": "http://jqueryui.com",
"author": {
"name": "jQuery Foundation and other contributors",
"url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt"
"url": "https://github.com/jquery/jquery-ui/blob/1.13.2/AUTHORS.txt"
},
"main": "ui/widget.js",
"maintainers": [
{
"name": "Scott González",
"email": "scott.gonzalez@gmail.com",
"url": "http://scottgonzalez.com"
},
{
"name": "Jörn Zaefferer",
"email": "joern.zaefferer@gmail.com",
@ -45,30 +40,35 @@
"type": "git",
"url": "git://github.com/jquery/jquery-ui.git"
},
"bugs": "https://bugs.jqueryui.com/",
"bugs": {
"url": "https://github.com/jquery/jquery-ui/issues"
},
"license": "MIT",
"scripts": {
"test": "grunt"
},
"dependencies": {},
"dependencies": {
"jquery": ">=1.8.0 <4.0.0"
},
"devDependencies": {
"commitplease": "2.3.0",
"grunt": "0.4.5",
"grunt-bowercopy": "1.2.4",
"grunt-cli": "0.1.13",
"grunt-compare-size": "0.4.0",
"grunt-contrib-concat": "0.5.1",
"grunt-contrib-csslint": "0.5.0",
"grunt-contrib-jshint": "0.12.0",
"grunt-contrib-qunit": "1.0.1",
"grunt-contrib-requirejs": "0.4.4",
"grunt-contrib-uglify": "0.11.1",
"grunt-git-authors": "3.1.0",
"grunt-html": "6.0.0",
"grunt-jscs": "2.1.0",
"load-grunt-tasks": "3.4.0",
"rimraf": "2.5.1",
"testswarm": "1.1.0"
"commitplease": "3.2.0",
"eslint-config-jquery": "3.0.0",
"glob": "7.2.0",
"grunt": "1.5.3",
"grunt-bowercopy": "1.2.5",
"grunt-cli": "1.4.3",
"grunt-compare-size": "0.4.2",
"grunt-contrib-concat": "1.0.1",
"grunt-contrib-csslint": "2.0.0",
"grunt-contrib-qunit": "5.1.1",
"grunt-contrib-requirejs": "1.0.0",
"grunt-contrib-uglify": "5.0.1",
"grunt-eslint": "23.0.0",
"grunt-git-authors": "3.2.0",
"grunt-html": "14.5.0",
"load-grunt-tasks": "5.1.0",
"rimraf": "3.0.2",
"testswarm": "1.1.2"
},
"keywords": []
}

View File

@ -1,833 +0,0 @@
/*!
* jQuery UI CSS Framework 1.11.4
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/theming/
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden {
display: none;
}
.ui-helper-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.ui-helper-reset {
margin: 0;
padding: 0;
border: 0;
outline: 0;
line-height: 1.3;
text-decoration: none;
font-size: 100%;
list-style: none;
}
.ui-helper-clearfix:before,
.ui-helper-clearfix:after {
content: "";
display: table;
border-collapse: collapse;
}
.ui-helper-clearfix:after {
clear: both;
}
.ui-helper-clearfix {
min-height: 0; /* support: IE7 */
}
.ui-helper-zfix {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0); /* support: IE8 */
}
.ui-front {
z-index: 100;
}
/* Interaction Cues
----------------------------------*/
.ui-state-disabled {
cursor: default !important;
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
display: block;
text-indent: -99999px;
overflow: hidden;
background-repeat: no-repeat;
}
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.ui-draggable-handle {
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable {
position: relative;
}
.ui-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
-ms-touch-action: none;
touch-action: none;
}
.ui-resizable-disabled .ui-resizable-handle,
.ui-resizable-autohide .ui-resizable-handle {
display: none;
}
.ui-resizable-n {
cursor: n-resize;
height: 7px;
width: 100%;
top: -5px;
left: 0;
}
.ui-resizable-s {
cursor: s-resize;
height: 7px;
width: 100%;
bottom: -5px;
left: 0;
}
.ui-resizable-e {
cursor: e-resize;
width: 7px;
right: -5px;
top: 0;
height: 100%;
}
.ui-resizable-w {
cursor: w-resize;
width: 7px;
left: -5px;
top: 0;
height: 100%;
}
.ui-resizable-se {
cursor: se-resize;
width: 12px;
height: 12px;
right: 1px;
bottom: 1px;
}
.ui-resizable-sw {
cursor: sw-resize;
width: 9px;
height: 9px;
left: -5px;
bottom: -5px;
}
.ui-resizable-nw {
cursor: nw-resize;
width: 9px;
height: 9px;
left: -5px;
top: -5px;
}
.ui-resizable-ne {
cursor: ne-resize;
width: 9px;
height: 9px;
right: -5px;
top: -5px;
}
.ui-selectable {
-ms-touch-action: none;
touch-action: none;
}
.ui-selectable-helper {
position: absolute;
z-index: 100;
border: 1px dotted black;
}
.ui-sortable-handle {
-ms-touch-action: none;
touch-action: none;
}
.ui-accordion .ui-accordion-header {
display: block;
cursor: pointer;
position: relative;
margin: 2px 0 0 0;
padding: .5em .5em .5em .7em;
min-height: 0; /* support: IE7 */
font-size: 100%;
}
.ui-accordion .ui-accordion-icons {
padding-left: 2.2em;
}
.ui-accordion .ui-accordion-icons .ui-accordion-icons {
padding-left: 2.2em;
}
.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
position: absolute;
left: .5em;
top: 50%;
margin-top: -8px;
}
.ui-accordion .ui-accordion-content {
padding: 1em 2.2em;
border-top: 0;
overflow: auto;
}
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
cursor: default;
}
.ui-button {
display: inline-block;
position: relative;
padding: 0;
line-height: normal;
margin-right: .1em;
cursor: pointer;
vertical-align: middle;
text-align: center;
overflow: visible; /* removes extra width in IE */
}
.ui-button,
.ui-button:link,
.ui-button:visited,
.ui-button:hover,
.ui-button:active {
text-decoration: none;
}
/* to make room for the icon, a width needs to be set here */
.ui-button-icon-only {
width: 2.2em;
}
/* button elements seem to need a little more width */
button.ui-button-icon-only {
width: 2.4em;
}
.ui-button-icons-only {
width: 3.4em;
}
button.ui-button-icons-only {
width: 3.7em;
}
/* button text element */
.ui-button .ui-button-text {
display: block;
line-height: normal;
}
.ui-button-text-only .ui-button-text {
padding: .4em 1em;
}
.ui-button-icon-only .ui-button-text,
.ui-button-icons-only .ui-button-text {
padding: .4em;
text-indent: -9999999px;
}
.ui-button-text-icon-primary .ui-button-text,
.ui-button-text-icons .ui-button-text {
padding: .4em 1em .4em 2.1em;
}
.ui-button-text-icon-secondary .ui-button-text,
.ui-button-text-icons .ui-button-text {
padding: .4em 2.1em .4em 1em;
}
.ui-button-text-icons .ui-button-text {
padding-left: 2.1em;
padding-right: 2.1em;
}
/* no icon support for input elements, provide padding by default */
input.ui-button {
padding: .4em 1em;
}
/* button icon element(s) */
.ui-button-icon-only .ui-icon,
.ui-button-text-icon-primary .ui-icon,
.ui-button-text-icon-secondary .ui-icon,
.ui-button-text-icons .ui-icon,
.ui-button-icons-only .ui-icon {
position: absolute;
top: 50%;
margin-top: -8px;
}
.ui-button-icon-only .ui-icon {
left: 50%;
margin-left: -8px;
}
.ui-button-text-icon-primary .ui-button-icon-primary,
.ui-button-text-icons .ui-button-icon-primary,
.ui-button-icons-only .ui-button-icon-primary {
left: .5em;
}
.ui-button-text-icon-secondary .ui-button-icon-secondary,
.ui-button-text-icons .ui-button-icon-secondary,
.ui-button-icons-only .ui-button-icon-secondary {
right: .5em;
}
/* button sets */
.ui-buttonset {
margin-right: 7px;
}
.ui-buttonset .ui-button {
margin-left: 0;
margin-right: -.3em;
}
/* workarounds */
/* reset extra padding in Firefox, see h5bp.com/l */
input.ui-button::-moz-focus-inner,
button.ui-button::-moz-focus-inner {
border: 0;
padding: 0;
}
.ui-datepicker {
width: 17em;
padding: .2em .2em 0;
display: none;
}
.ui-datepicker .ui-datepicker-header {
position: relative;
padding: .2em 0;
}
.ui-datepicker .ui-datepicker-prev,
.ui-datepicker .ui-datepicker-next {
position: absolute;
top: 2px;
width: 1.8em;
height: 1.8em;
}
.ui-datepicker .ui-datepicker-prev-hover,
.ui-datepicker .ui-datepicker-next-hover {
top: 1px;
}
.ui-datepicker .ui-datepicker-prev {
left: 2px;
}
.ui-datepicker .ui-datepicker-next {
right: 2px;
}
.ui-datepicker .ui-datepicker-prev-hover {
left: 1px;
}
.ui-datepicker .ui-datepicker-next-hover {
right: 1px;
}
.ui-datepicker .ui-datepicker-prev span,
.ui-datepicker .ui-datepicker-next span {
display: block;
position: absolute;
left: 50%;
margin-left: -8px;
top: 50%;
margin-top: -8px;
}
.ui-datepicker .ui-datepicker-title {
margin: 0 2.3em;
line-height: 1.8em;
text-align: center;
}
.ui-datepicker .ui-datepicker-title select {
font-size: 1em;
margin: 1px 0;
}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year {
width: 45%;
}
.ui-datepicker table {
width: 100%;
font-size: .9em;
border-collapse: collapse;
margin: 0 0 .4em;
}
.ui-datepicker th {
padding: .7em .3em;
text-align: center;
font-weight: bold;
border: 0;
}
.ui-datepicker td {
border: 0;
padding: 1px;
}
.ui-datepicker td span,
.ui-datepicker td a {
display: block;
padding: .2em;
text-align: right;
text-decoration: none;
}
.ui-datepicker .ui-datepicker-buttonpane {
background-image: none;
margin: .7em 0 0 0;
padding: 0 .2em;
border-left: 0;
border-right: 0;
border-bottom: 0;
}
.ui-datepicker .ui-datepicker-buttonpane button {
float: right;
margin: .5em .2em .4em;
cursor: pointer;
padding: .2em .6em .3em .6em;
width: auto;
overflow: visible;
}
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
float: left;
}
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi {
width: auto;
}
.ui-datepicker-multi .ui-datepicker-group {
float: left;
}
.ui-datepicker-multi .ui-datepicker-group table {
width: 95%;
margin: 0 auto .4em;
}
.ui-datepicker-multi-2 .ui-datepicker-group {
width: 50%;
}
.ui-datepicker-multi-3 .ui-datepicker-group {
width: 33.3%;
}
.ui-datepicker-multi-4 .ui-datepicker-group {
width: 25%;
}
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
border-left-width: 0;
}
.ui-datepicker-multi .ui-datepicker-buttonpane {
clear: left;
}
.ui-datepicker-row-break {
clear: both;
width: 100%;
font-size: 0;
}
/* RTL support */
.ui-datepicker-rtl {
direction: rtl;
}
.ui-datepicker-rtl .ui-datepicker-prev {
right: 2px;
left: auto;
}
.ui-datepicker-rtl .ui-datepicker-next {
left: 2px;
right: auto;
}
.ui-datepicker-rtl .ui-datepicker-prev:hover {
right: 1px;
left: auto;
}
.ui-datepicker-rtl .ui-datepicker-next:hover {
left: 1px;
right: auto;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane {
clear: right;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
float: left;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
.ui-datepicker-rtl .ui-datepicker-group {
float: right;
}
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
border-right-width: 0;
border-left-width: 1px;
}
.ui-dialog {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
padding: .2em;
outline: 0;
}
.ui-dialog .ui-dialog-titlebar {
padding: .4em 1em;
position: relative;
}
.ui-dialog .ui-dialog-title {
float: left;
margin: .1em 0;
white-space: nowrap;
width: 90%;
overflow: hidden;
text-overflow: ellipsis;
}
.ui-dialog .ui-dialog-titlebar-close {
position: absolute;
right: .3em;
top: 50%;
width: 20px;
margin: -10px 0 0 0;
padding: 1px;
height: 20px;
}
.ui-dialog .ui-dialog-content {
position: relative;
border: 0;
padding: .5em 1em;
background: none;
overflow: auto;
}
.ui-dialog .ui-dialog-buttonpane {
text-align: left;
border-width: 1px 0 0 0;
background-image: none;
margin-top: .5em;
padding: .3em 1em .5em .4em;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: right;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: .5em .4em .5em 0;
cursor: pointer;
}
.ui-dialog .ui-resizable-se {
width: 12px;
height: 12px;
right: -5px;
bottom: -5px;
background-position: 16px 16px;
}
.ui-draggable .ui-dialog-titlebar {
cursor: move;
}
.ui-menu {
list-style: none;
padding: 0;
margin: 0;
display: block;
outline: none;
}
.ui-menu .ui-menu {
position: absolute;
}
.ui-menu .ui-menu-item {
position: relative;
margin: 0;
padding: 3px 1em 3px .4em;
cursor: pointer;
min-height: 0; /* support: IE7 */
/* support: IE10, see #8844 */
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
}
.ui-menu .ui-menu-divider {
margin: 5px 0;
height: 0;
font-size: 0;
line-height: 0;
border-width: 1px 0 0 0;
}
.ui-menu .ui-state-focus,
.ui-menu .ui-state-active {
margin: -1px;
}
/* icon support */
.ui-menu-icons {
position: relative;
}
.ui-menu-icons .ui-menu-item {
padding-left: 2em;
}
/* left-aligned */
.ui-menu .ui-icon {
position: absolute;
top: 0;
bottom: 0;
left: .2em;
margin: auto 0;
}
/* right-aligned */
.ui-menu .ui-menu-icon {
left: auto;
right: 0;
}
.ui-progressbar {
height: 2em;
text-align: left;
overflow: hidden;
}
.ui-progressbar .ui-progressbar-value {
margin: -1px;
height: 100%;
}
.ui-progressbar .ui-progressbar-overlay {
background: url("data:image/gif;base64,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");
height: 100%;
filter: alpha(opacity=25); /* support: IE8 */
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
background-image: none;
}
.ui-selectmenu-menu {
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 0;
display: none;
}
.ui-selectmenu-menu .ui-menu {
overflow: auto;
/* Support: IE7 */
overflow-x: hidden;
padding-bottom: 1px;
}
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
font-size: 1em;
font-weight: bold;
line-height: 1.5;
padding: 2px 0.4em;
margin: 0.5em 0 0 0;
height: auto;
border: 0;
}
.ui-selectmenu-open {
display: block;
}
.ui-selectmenu-button {
display: inline-block;
overflow: hidden;
position: relative;
text-decoration: none;
cursor: pointer;
}
.ui-selectmenu-button span.ui-icon {
right: 0.5em;
left: auto;
margin-top: -8px;
position: absolute;
top: 50%;
}
.ui-selectmenu-button span.ui-selectmenu-text {
text-align: left;
padding: 0.4em 2.1em 0.4em 1em;
display: block;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ui-slider {
position: relative;
text-align: left;
}
.ui-slider .ui-slider-handle {
position: absolute;
z-index: 2;
width: 1.2em;
height: 1.2em;
cursor: default;
-ms-touch-action: none;
touch-action: none;
}
.ui-slider .ui-slider-range {
position: absolute;
z-index: 1;
font-size: .7em;
display: block;
border: 0;
background-position: 0 0;
}
/* support: IE8 - See #6727 */
.ui-slider.ui-state-disabled .ui-slider-handle,
.ui-slider.ui-state-disabled .ui-slider-range {
filter: inherit;
}
.ui-slider-horizontal {
height: .8em;
}
.ui-slider-horizontal .ui-slider-handle {
top: -.3em;
margin-left: -.6em;
}
.ui-slider-horizontal .ui-slider-range {
top: 0;
height: 100%;
}
.ui-slider-horizontal .ui-slider-range-min {
left: 0;
}
.ui-slider-horizontal .ui-slider-range-max {
right: 0;
}
.ui-slider-vertical {
width: .8em;
height: 100px;
}
.ui-slider-vertical .ui-slider-handle {
left: -.3em;
margin-left: 0;
margin-bottom: -.6em;
}
.ui-slider-vertical .ui-slider-range {
left: 0;
width: 100%;
}
.ui-slider-vertical .ui-slider-range-min {
bottom: 0;
}
.ui-slider-vertical .ui-slider-range-max {
top: 0;
}
.ui-spinner {
position: relative;
display: inline-block;
overflow: hidden;
padding: 0;
vertical-align: middle;
}
.ui-spinner-input {
border: none;
background: none;
color: inherit;
padding: 0;
margin: .2em 0;
vertical-align: middle;
margin-left: .4em;
margin-right: 22px;
}
.ui-spinner-button {
width: 16px;
height: 50%;
font-size: .5em;
padding: 0;
margin: 0;
text-align: center;
position: absolute;
cursor: default;
display: block;
overflow: hidden;
right: 0;
}
/* more specificity required here to override default borders */
.ui-spinner a.ui-spinner-button {
border-top: none;
border-bottom: none;
border-right: none;
}
/* vertically center icon */
.ui-spinner .ui-icon {
position: absolute;
margin-top: -8px;
top: 50%;
left: 0;
}
.ui-spinner-up {
top: 0;
}
.ui-spinner-down {
bottom: 0;
}
/* TR overrides */
.ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */
background-position: -65px -16px;
}
.ui-tabs {
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
padding: .2em;
}
.ui-tabs .ui-tabs-nav {
margin: 0;
padding: .2em .2em 0;
}
.ui-tabs .ui-tabs-nav li {
list-style: none;
float: left;
position: relative;
top: 0;
margin: 1px .2em 0 0;
border-bottom-width: 0;
padding: 0;
white-space: nowrap;
}
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
float: left;
padding: .5em 1em;
text-decoration: none;
}
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
margin-bottom: -1px;
padding-bottom: 1px;
}
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
cursor: text;
}
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
cursor: pointer;
}
.ui-tabs .ui-tabs-panel {
display: block;
border-width: 0;
padding: 1em 1.4em;
background: none;
}
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 300px;
-webkit-box-shadow: 0 0 5px #aaa;
box-shadow: 0 0 5px #aaa;
}
body .ui-tooltip {
border-width: 2px;
}

View File

@ -1 +0,0 @@
jquery-ui-1.12.1/jquery-ui.js

View File

@ -1 +1 @@
jquery-3.5.1.min.js
jquery-3.6.1.min.js

View File

@ -167,8 +167,7 @@ getBodyTopHTML();
?>
<?php echo $navbar ?>
<div id="content">
<form name="monitorForm" method="get" action="?">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<form name="monitorForm" method="post" action="?view=<?php echo $view; ?>">
<input type="hidden" name="action" value=""/>
<div class="filterBar" id="fbpanel"<?php echo ( isset($_COOKIE['zmFilterBarFlip']) and $_COOKIE['zmFilterBarFlip'] == 'down' ) ? ' style="display:none;"' : '' ?>>

View File

@ -105,7 +105,7 @@ if ( isset($_REQUEST['eid']) and $_REQUEST['eid'] ) {
$eventsSql .= $filter->sql();
}
$eventsSql .= " ORDER BY $sortColumn $sortOrder";
if ( isset($_REQUEST['filter']['Query']['limit']) )
if ( isset($_REQUEST['filter']['Query']['limit']) and validInt($_REQUEST['filter']['Query']['limit']))
$eventsSql .= ' LIMIT '.validInt($_REQUEST['filter']['Query']['limit']);
} # end if filter

View File

@ -47,8 +47,8 @@ xhtmlHeaders(__FILE__, translate('Groups'));
<div id="page">
<?php echo $navbar = getNavBarHTML(); ?>
<div id="content">
<form name="groupsForm" method="get" action="?">
<input type="hidden" name="view" value="none"/>
<form name="groupsForm" method="post" action="?">
<input type="hidden" name="view" value="groups"/>
<input type="hidden" name="action" value="setgroup"/>
<table id="contentTable" class="major">
<thead class="thead-highlight">

View File

@ -951,6 +951,9 @@ function getStat() {
case 'n/a':
tdString = 'n/a';
break;
case 'Path':
tdString = '<a href="?view=files&amp;path='+eventData.Path+'">'+eventData.Path+'</a>';
break;
case 'Archived':
case 'Emailed':
tdString = eventData[key] ? yesStr : noStr;

View File

@ -6,17 +6,12 @@ function newGroup() {
$j('#groupModal').modal('show');
$j('.chosen').chosen("destroy");
$j('.chosen').chosen();
// Manage the Save button
$j('#grpModalSaveBtn').click(function(evt) {
evt.preventDefault();
$j('#groupForm').submit();
});
})
.fail(logAjaxFail);
}
function setGroup( element ) {
var form = element.form;
const form = element.form;
form.action.value = 'setgroup';
form.submit();
}
@ -32,47 +27,38 @@ function editGroup( element ) {
$j('#groupModal').modal('show');
$j('.chosen').chosen("destroy");
$j('.chosen').chosen();
// Manage the Save button
$j('#grpModalSaveBtn').click(function(evt) {
evt.preventDefault();
$j('#groupForm').submit();
});
})
.fail(logAjaxFail);
}
}
function deleteGroup( element ) {
var form = element.form;
form.view.value = currentView;
form.action.value = 'delete';
function deleteGroup(element) {
const form = element.form;
form.elements['action'].value = 'delete';
form.submit();
}
function configureButtons( element ) {
if ( canEdit.Groups ) {
var form = element.form;
if ( element.checked ) {
function configureButtons(element) {
if (canEdit.Groups) {
const form = element.form;
if (element.checked) {
form.deleteBtn.disabled = (element.value == 0);
}
}
}
function configModalBtns() {
var form = $j('#groupForm')[0];
if ( !form ) {
console.log("No groupForm found");
const form = document.getElementById('groupForm');
if (!form) {
console.error("No groupForm found");
return;
}
if ( !canEdit.Groups ) {
if (!canEdit.Groups) {
console.log("Cannot edit groups");
form.elements['action'].disabled = disabled;
form.elements['action'].disabled = true;
return;
}
var disabled = false;
if ( form.elements['newGroup[Name]'].value == '' ) {
disabled = true;
if (form.elements['newGroup[Name]'].value == '') {
form.elements['action'].disabled = true;
}
form.elements['action'].disabled = disabled;
}

View File

@ -380,7 +380,7 @@ function drawSliderOnGraph(val) {
underSlider = ctx.getImageData(sliderX, 0, sliderWidth, sliderHeight);
// And add in the slider'
ctx.lineWidth = sliderLineWidth;
ctx.strokeStyle = 'black';
ctx.strokeStyle = 'yellow';
// looks like strokes are on the outside (or could be) so shrink it by the line width so we replace all the pixels
ctx.strokeRect(sliderX+sliderLineWidth, sliderLineWidth, sliderWidth - 2*sliderLineWidth, sliderHeight - 2*sliderLineWidth);
underSliderX = sliderX;
@ -391,7 +391,7 @@ function drawSliderOnGraph(val) {
o.style.color = "red";
} else {
o.innerHTML = secs2dbstr(val);
o.style.color = "blue";
o.style.color = 'white';
}
o.style.position = "absolute";
o.style.bottom = labbottom;
@ -771,6 +771,12 @@ function click_lastEight() {
now -= -1 * date.getTimezoneOffset() * 60 - server_utc_offset;
clicknav(now - 3600*8 + 1, now, 0);
}
function click_last24() {
var date = new Date();
var now = Math.floor( date.getTime() / 1000 );
now -= -1 * date.getTimezoneOffset() * 60 - server_utc_offset;
clicknav(now - 3600*24 + 1, now, 0);
}
function click_zoomin() {
rangeTimeSecs = parseInt(rangeTimeSecs / 2);
minTimeSecs = parseInt(currentTimeSecs - rangeTimeSecs/2); // this is the slider current time, we center on that

View File

@ -31,11 +31,6 @@ function getStorageModal(sid) {
.done(function(data) {
insertModalHtml('storageModal', data.html);
$j('#storageModal').modal('show');
// Manage the Save button
$j('#storageSubmitBtn').click(function(evt) {
evt.preventDefault();
$j('#storageModalForm').submit();
});
})
.fail(logAjaxFail);
}

View File

@ -288,6 +288,7 @@ getBodyTopHTML();
<button type="button" id="panleft" data-on-click="click_panleft" >&lt; <?php echo translate('Pan') ?></button>
<button type="button" id="zoomin" data-on-click="click_zoomin" ><?php echo translate('In +') ?></button>
<button type="button" id="zoomout" data-on-click="click_zoomout" ><?php echo translate('Out -') ?></button>
<button type="button" id="lasteight" data-on-click="click_last24" ><?php echo translate('24 Hour') ?></button>
<button type="button" id="lasteight" data-on-click="click_lastEight" ><?php echo translate('8 Hour') ?></button>
<button type="button" id="lasthour" data-on-click="click_lastHour" ><?php echo translate('1 Hour') ?></button>
<button type="button" id="allof" data-on-click="click_all_events" ><?php echo translate('All Events') ?></button>
@ -298,13 +299,8 @@ getBodyTopHTML();
if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
?>
<button type="button" id="downloadVideo" data-on-click="click_download"><?php echo translate('Download Video') ?></button>
<?php
}
?>
</div>
<?php if ( !$liveMode ) { ?>
<div id="eventfilterdiv" class="input-group">
<label><?php echo translate('Archive Status') ?>
<span id="eventfilterdiv">
<label><?php echo translate('Archive Status') ?>
<?php echo htmlSelect(
'archive_status',
array(
@ -314,9 +310,10 @@ getBodyTopHTML();
),
( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : '')
); ?>
</label>
</div>
</label>
</span>
<?php } // end if !live ?>
</div>
<div id="timelinediv">
<canvas id="timeline"></canvas>
<span id="scrubleft"></span>

View File

@ -66,7 +66,13 @@ foreach ($displayMonitors as &$row) {
} # end foreach Monitor
if ($mid and ($monitor_index == -1)) {
ZM\Error("How did we not find monitor_index?");
$monitor = ZM\Monitor::find_one(array('Id'=>$mid));
if (!$monitor) {
ZM\Error("No monitor found for $mid");
} else {
$monitor_index = count($monitors);
$monitors[] = $monitor;
}
}
if (!$mid) {