Merge branch 'master' of github.com:/ZoneMinder/zoneminder

This commit is contained in:
Isaac Connor 2019-06-25 22:19:53 -04:00
commit 0dbe48fb31
88 changed files with 10093 additions and 544 deletions

6
.gitmodules vendored
View File

@ -5,9 +5,3 @@
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"] [submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
path = web/api/app/Plugin/CakePHP-Enum-Behavior path = web/api/app/Plugin/CakePHP-Enum-Behavior
url = https://github.com/ZoneMinder/CakePHP-Enum-Behavior.git url = https://github.com/ZoneMinder/CakePHP-Enum-Behavior.git
[submodule "third_party/bcrypt"]
path = third_party/bcrypt
url = https://github.com/ZoneMinder/libbcrypt
[submodule "third_party/jwt-cpp"]
path = third_party/jwt-cpp
url = https://github.com/Thalhammer/jwt-cpp

View File

@ -876,7 +876,7 @@ ADD_MANPAGE_TARGET()
# build a bcrypt static library # build a bcrypt static library
set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}") set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}")
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
add_subdirectory(third_party/bcrypt) add_subdirectory(src/libbcrypt EXCLUDE_FROM_ALL)
set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}") set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_SAVED}")
add_subdirectory(src) add_subdirectory(src)

View File

@ -479,6 +479,7 @@ CREATE TABLE `Monitors` (
`StreamReplayBuffer` int(10) unsigned NOT NULL default '1000', `StreamReplayBuffer` int(10) unsigned NOT NULL default '1000',
`AlarmFrameCount` smallint(5) unsigned NOT NULL default '1', `AlarmFrameCount` smallint(5) unsigned NOT NULL default '1',
`SectionLength` int(10) unsigned NOT NULL default '600', `SectionLength` int(10) unsigned NOT NULL default '600',
`MinSectionLength` int(10) unsigned NOT NULL default '10',
`FrameSkip` smallint(5) unsigned NOT NULL default '0', `FrameSkip` smallint(5) unsigned NOT NULL default '0',
`MotionFrameSkip` smallint(5) unsigned NOT NULL default '0', `MotionFrameSkip` smallint(5) unsigned NOT NULL default '0',
`AnalysisFPSLimit` decimal(5,2) default NULL, `AnalysisFPSLimit` decimal(5,2) default NULL,

12
db/zm_update-1.33.10.sql Normal file
View File

@ -0,0 +1,12 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitors'
AND column_name = 'MinSectionLength'
) > 0,
"SELECT 'Column MinSectionLength already exists in Monitors'",
"ALTER TABLE Monitors ADD `MinSectionLength` int(10) unsigned NOT NULL default '10' AFTER SectionLength"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -23,7 +23,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.33.8 Version: 1.33.9
Release: 1%{?dist} Release: 1%{?dist}
Summary: A camera monitoring and analysis tool Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons Group: System Environment/Daemons
@ -411,6 +411,9 @@ EOF
%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload %dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload
%changelog %changelog
* Sun Jun 23 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.9-1
- Bump to 1.33.9 Development
* Tue Apr 30 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.8-1 * Tue Apr 30 2019 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.33.8-1
- Bump to 1.33.8 Development - Bump to 1.33.8 Development

View File

@ -1,4 +1,4 @@
d /var/run/zm 0755 www-data www-data d /run/zm 0755 www-data www-data
d /tmp/zm 0755 www-data www-data d /tmp/zm 0755 www-data www-data
d /var/tmp/zm 0755 www-data www-data d /var/tmp/zm 0755 www-data www-data
d /var/cache/zoneminder/cache 0755 www-data www-data d /var/cache/zoneminder/cache 0755 www-data www-data

View File

@ -96,8 +96,7 @@ sub open {
$self->{state} = 'open'; $self->{state} = 'open';
} }
sub parseControlAddress sub parseControlAddress {
{
my $controlAddress = shift; my $controlAddress = shift;
my ($usernamepassword, $addressport) = split /@/, $controlAddress; my ($usernamepassword, $addressport) = split /@/, $controlAddress;
if ( !defined $addressport ) { if ( !defined $addressport ) {
@ -105,7 +104,7 @@ sub parseControlAddress
$addressport = $usernamepassword; $addressport = $usernamepassword;
} else { } else {
my ($username , $password) = split /:/, $usernamepassword; my ($username , $password) = split /:/, $usernamepassword;
%identity = (username => "$username", password => "$password"); %identity = (username => $username, password => $password);
} }
($address, $port) = split /:/, $addressport; ($address, $port) = split /:/, $addressport;
} }
@ -118,12 +117,11 @@ sub digestBase64
return encode_base64($shaGenerator->digest, ""); return encode_base64($shaGenerator->digest, "");
} }
sub authentificationHeader sub authentificationHeader {
{
my ($username, $password) = @_; my ($username, $password) = @_;
my $nonce; my $nonce;
$nonce .= chr(int(rand(254))) for (0 .. 20); $nonce .= chr(int(rand(254))) for (0 .. 20);
my $nonceBase64 = encode_base64($nonce, ""); my $nonceBase64 = encode_base64($nonce, '');
my $currentDate = DateTime->now()->iso8601().'Z'; my $currentDate = DateTime->now()->iso8601().'Z';
return '<s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><Username>' . $username . '</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . digestBase64($nonce, $currentDate, $password) . '</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">' . $nonceBase64 . '</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $currentDate . '</Created></UsernameToken></Security></s:Header>'; return '<s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><Username>' . $username . '</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . digestBase64($nonce, $currentDate, $password) . '</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">' . $nonceBase64 . '</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $currentDate . '</Created></UsernameToken></Security></s:Header>';
@ -160,7 +158,7 @@ sub sendCmd {
if ( $res->is_success ) { if ( $res->is_success ) {
$result = !undef; $result = !undef;
} else { } else {
Error("After sending PTZ command, camera returned the following error:'".$res->status_line()."'"); Error("After sending PTZ command, camera returned the following error:'".$res->status_line()."'\nMSG:$msg\nResponse:".$res->content);
} }
return $result; return $result;
} }
@ -236,7 +234,7 @@ sub moveConDown {
Debug('Move Down'); Debug('Move Down');
my $self = shift; my $self = shift;
my $cmd = 'onvif/PTZ'; my $cmd = 'onvif/PTZ';
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>' . $profileToken . '</ProfileToken><Velocity><PanTilt x="0" y="-0.5" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>'; my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">'.((%identity) ? authentificationHeader($identity{username}, $identity{password}) : '').'<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>' . $profileToken . '</ProfileToken><Velocity><PanTilt x="0" y="-0.5" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>';
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"';
$self->sendCmd($cmd, $msg, $content_type); $self->sendCmd($cmd, $msg, $content_type);
$self->autoStop($self->{Monitor}->{AutoStopTimeout}); $self->autoStop($self->{Monitor}->{AutoStopTimeout});
@ -316,7 +314,7 @@ sub moveConUpLeft {
Debug('Move Diagonally Up Left'); Debug('Move Diagonally Up Left');
my $self = shift; my $self = shift;
my $cmd = 'onvif/PTZ'; my $cmd = 'onvif/PTZ';
my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>' . $profileToken . '</ProfileToken><Velocity><PanTilt x="-0.5" y="0.5" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>'; my $msg ='<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">'.((%identity) ? authentificationHeader($identity{username}, $identity{password}) : '').'<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl"><ProfileToken>' . $profileToken . '</ProfileToken><Velocity><PanTilt x="-0.5" y="0.5" xmlns="http://www.onvif.org/ver10/schema"/></Velocity></ContinuousMove></s:Body></s:Envelope>';
my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"'; my $content_type = 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver20/ptz/wsdl/ContinuousMove"';
$self->sendCmd($cmd, $msg, $content_type); $self->sendCmd($cmd, $msg, $content_type);
$self->autoStop($self->{Monitor}->{AutoStopTimeout}); $self->autoStop($self->{Monitor}->{AutoStopTimeout});

View File

@ -214,6 +214,7 @@ sub zmDbGetMonitor {
return undef; return undef;
} }
my $monitor = $sth->fetchrow_hashref(); my $monitor = $sth->fetchrow_hashref();
$sth->finish();
return $monitor; return $monitor;
} }
@ -240,6 +241,7 @@ sub zmDbGetMonitorAndControl {
return undef; return undef;
} }
my $monitor = $sth->fetchrow_hashref(); my $monitor = $sth->fetchrow_hashref();
$sth->finish();
return $monitor; return $monitor;
} }

View File

@ -72,15 +72,15 @@ sub find {
$sql .= ' WHERE ' . join(' AND ', @sql_filters ) if @sql_filters; $sql .= ' WHERE ' . join(' AND ', @sql_filters ) if @sql_filters;
$sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit}; $sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit};
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql ) my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() ); or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());
my $res = $sth->execute( @sql_values ) my $res = $sth->execute(@sql_values)
or Fatal( "Can't execute '$sql': ".$sth->errstr() ); or Fatal("Can't execute '$sql': ".$sth->errstr());
my @results; my @results;
while( my $db_filter = $sth->fetchrow_hashref() ) { while( my $db_filter = $sth->fetchrow_hashref() ) {
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter ); my $filter = new ZoneMinder::Filter($$db_filter{Id}, $db_filter);
push @results, $filter; push @results, $filter;
} # end while } # end while
$sth->finish(); $sth->finish();
@ -98,7 +98,7 @@ sub Execute {
my $sql = $self->Sql(undef); my $sql = $self->Sql(undef);
if ( $self->{HasDiskPercent} ) { if ( $self->{HasDiskPercent} ) {
my $disk_percent = getDiskPercent( $$self{Storage} ? $$self{Storage}->Path() : () ); my $disk_percent = getDiskPercent($$self{Storage} ? $$self{Storage}->Path() : ());
$sql =~ s/zmDiskPercent/$disk_percent/g; $sql =~ s/zmDiskPercent/$disk_percent/g;
} }
if ( $self->{HasDiskBlocks} ) { if ( $self->{HasDiskBlocks} ) {
@ -111,16 +111,16 @@ sub Execute {
} }
Debug("Filter::Execute SQL ($sql)"); Debug("Filter::Execute SQL ($sql)");
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql ) my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() ); or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());
my $res = $sth->execute(); my $res = $sth->execute();
if ( !$res ) { if ( !$res ) {
Error( "Can't execute filter '$sql', ignoring: ".$sth->errstr() ); Error("Can't execute filter '$sql', ignoring: ".$sth->errstr());
return; return;
} }
my @results; my @results;
while( my $event = $sth->fetchrow_hashref() ) { while ( my $event = $sth->fetchrow_hashref() ) {
push @results, $event; push @results, $event;
} }
$sth->finish(); $sth->finish();
@ -152,7 +152,7 @@ sub Sql {
$self->{Sql} .= ' '.$term->{cnj}.' '; $self->{Sql} .= ' '.$term->{cnj}.' ';
} }
if ( exists($term->{obr}) ) { if ( exists($term->{obr}) ) {
$self->{Sql} .= ' '.str_repeat( '(', $term->{obr} ).' '; $self->{Sql} .= ' '.str_repeat('(', $term->{obr}).' ';
} }
my $value = $term->{val}; my $value = $term->{val};
my @value_list; my @value_list;
@ -216,17 +216,17 @@ sub Sql {
if ( $temp_value eq 'ZM_SERVER_ID' ) { if ( $temp_value eq 'ZM_SERVER_ID' ) {
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'"; $value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
# This gets used later, I forget for what # This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server( $ZoneMinder::Config::Config{ZM_SERVER_ID} ); $$self{Server} = new ZoneMinder::Server($ZoneMinder::Config::Config{ZM_SERVER_ID});
} elsif ( $temp_value eq 'NULL' ) { } elsif ( $temp_value eq 'NULL' ) {
$value = $temp_value; $value = $temp_value;
} else { } else {
$value = "'$temp_value'"; $value = "'$temp_value'";
# This gets used later, I forget for what # This gets used later, I forget for what
$$self{Server} = new ZoneMinder::Server( $temp_value ); $$self{Server} = new ZoneMinder::Server($temp_value);
} }
} elsif ( $term->{attr} eq 'StorageId' ) { } elsif ( $term->{attr} eq 'StorageId' ) {
$value = "'$temp_value'"; $value = "'$temp_value'";
$$self{Storage} = new ZoneMinder::Storage( $temp_value ); $$self{Storage} = new ZoneMinder::Storage($temp_value);
} elsif ( $term->{attr} eq 'Name' } elsif ( $term->{attr} eq 'Name'
|| $term->{attr} eq 'Cause' || $term->{attr} eq 'Cause'
|| $term->{attr} eq 'Notes' || $term->{attr} eq 'Notes'
@ -236,10 +236,9 @@ sub Sql {
if ( $temp_value eq 'NULL' ) { if ( $temp_value eq 'NULL' ) {
$value = $temp_value; $value = $temp_value;
} else { } else {
$value = DateTimeToSQL( $temp_value ); $value = DateTimeToSQL($temp_value);
if ( !$value ) { if ( !$value ) {
Error( "Error parsing date/time '$temp_value', " Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
."skipping filter '$self->{Name}'\n" );
return; return;
} }
$value = "'$value'"; $value = "'$value'";
@ -248,10 +247,9 @@ sub Sql {
if ( $temp_value eq 'NULL' ) { if ( $temp_value eq 'NULL' ) {
$value = $temp_value; $value = $temp_value;
} else { } else {
$value = DateTimeToSQL( $temp_value ); $value = DateTimeToSQL($temp_value);
if ( !$value ) { if ( !$value ) {
Error( "Error parsing date/time '$temp_value', " Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
."skipping filter '$self->{Name}'\n" );
return; return;
} }
$value = "to_days( '$value' )"; $value = "to_days( '$value' )";
@ -260,10 +258,9 @@ sub Sql {
if ( $temp_value eq 'NULL' ) { if ( $temp_value eq 'NULL' ) {
$value = $temp_value; $value = $temp_value;
} else { } else {
$value = DateTimeToSQL( $temp_value ); $value = DateTimeToSQL($temp_value);
if ( !$value ) { if ( !$value ) {
Error( "Error parsing date/time '$temp_value', " Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
."skipping filter '$self->{Name}'\n" );
return; return;
} }
$value = "extract( hour_second from '$value' )"; $value = "extract( hour_second from '$value' )";
@ -271,7 +268,7 @@ sub Sql {
} else { } else {
$value = $temp_value; $value = $temp_value;
} }
push( @value_list, $value ); push @value_list, $value;
} # end foreach temp_value } # end foreach temp_value
} # end if has an attr } # end if has an attr
if ( $term->{op} ) { if ( $term->{op} ) {
@ -290,15 +287,15 @@ sub Sql {
} elsif ( $term->{op} eq 'IS NOT' ) { } elsif ( $term->{op} eq 'IS NOT' ) {
$self->{Sql} .= " IS NOT $value"; $self->{Sql} .= " IS NOT $value";
} elsif ( $term->{op} eq '=[]' ) { } elsif ( $term->{op} eq '=[]' ) {
$self->{Sql} .= " in (".join( ",", @value_list ).")"; $self->{Sql} .= ' IN ('.join(',', @value_list).')';
} elsif ( $term->{op} eq '!~' ) { } elsif ( $term->{op} eq '!~' ) {
$self->{Sql} .= " not in (".join( ",", @value_list ).")"; $self->{Sql} .= ' NOT IN ('.join(',', @value_list).')';
} else { } else {
$self->{Sql} .= ' '.$term->{op}." $value"; $self->{Sql} .= ' '.$term->{op}.' '.$value;
} }
} # end if has an operator } # end if has an operator
if ( exists($term->{cbr}) ) { if ( exists($term->{cbr}) ) {
$self->{Sql} .= ' '.str_repeat( ")", $term->{cbr} )." "; $self->{Sql} .= ' '.str_repeat(')', $term->{cbr}).' ';
} }
} # end foreach term } # end foreach term
} # end if terms } # end if terms
@ -320,22 +317,22 @@ sub Sql {
# Don't do this, it prevents re-generation and concatenation. # Don't do this, it prevents re-generation and concatenation.
# If the file already exists, then the video won't be re-recreated # If the file already exists, then the video won't be re-recreated
if ( $self->{AutoVideo} ) { if ( $self->{AutoVideo} ) {
push @auto_terms, "E.Videoed = 0"; push @auto_terms, 'E.Videoed = 0';
} }
if ( $self->{AutoUpload} ) { if ( $self->{AutoUpload} ) {
push @auto_terms, "E.Uploaded = 0"; push @auto_terms, 'E.Uploaded = 0';
} }
if ( $self->{AutoEmail} ) { if ( $self->{AutoEmail} ) {
push @auto_terms, "E.Emailed = 0"; push @auto_terms, 'E.Emailed = 0';
} }
if ( $self->{AutoMessage} ) { if ( $self->{AutoMessage} ) {
push @auto_terms, "E.Messaged = 0"; push @auto_terms, 'E.Messaged = 0';
} }
if ( $self->{AutoExecute} ) { if ( $self->{AutoExecute} ) {
push @auto_terms, "E.Executed = 0"; push @auto_terms, 'E.Executed = 0';
} }
if ( @auto_terms ) { if ( @auto_terms ) {
$sql .= " and ( ".join( ' or ', @auto_terms )." )"; $sql .= ' AND ( '.join(' or ', @auto_terms).' )';
} }
if ( !$filter_expr->{sort_field} ) { if ( !$filter_expr->{sort_field} ) {
$filter_expr->{sort_field} = 'StartTime'; $filter_expr->{sort_field} = 'StartTime';
@ -369,10 +366,10 @@ sub Sql {
} else { } else {
$sort_column = 'E.StartTime'; $sort_column = 'E.StartTime';
} }
my $sort_order = $filter_expr->{sort_asc}?'asc':'desc'; my $sort_order = $filter_expr->{sort_asc} ? 'ASC' : 'DESC';
$sql .= ' order by '.$sort_column." ".$sort_order; $sql .= ' ORDER BY '.$sort_column." ".$sort_order;
if ( $filter_expr->{limit} ) { if ( $filter_expr->{limit} ) {
$sql .= " limit 0,".$filter_expr->{limit}; $sql .= ' LIMIT 0,'.$filter_expr->{limit};
} }
$self->{Sql} = $sql; $self->{Sql} = $sql;
} # end if has Sql } # end if has Sql
@ -386,7 +383,7 @@ sub getDiskPercent {
if ( $df =~ /\s(\d+)%/ms ) { if ( $df =~ /\s(\d+)%/ms ) {
$space = $1; $space = $1;
} }
return( $space ); return $space;
} }
sub getDiskBlocks { sub getDiskBlocks {
@ -396,7 +393,7 @@ sub getDiskBlocks {
if ( $df =~ /\s(\d+)\s+\d+\s+\d+%/ms ) { if ( $df =~ /\s(\d+)\s+\d+\s+\d+%/ms ) {
$space = $1; $space = $1;
} }
return( $space ); return $space;
} }
sub getLoad { sub getLoad {
@ -405,9 +402,9 @@ sub getLoad {
my $load = -1; my $load = -1;
if ( $uptime =~ /load average:\s+([\d.]+)/ms ) { if ( $uptime =~ /load average:\s+([\d.]+)/ms ) {
$load = $1; $load = $1;
Info( "Load: $load" ); Info("Load: $load");
} }
return( $load ); return $load;
} }
# #
@ -415,7 +412,7 @@ sub getLoad {
# #
sub strtotime { sub strtotime {
my $dt_str = shift; my $dt_str = shift;
return( Date::Manip::UnixDate( $dt_str, '%s' ) ); return Date::Manip::UnixDate($dt_str, '%s');
} }
# #
@ -424,18 +421,18 @@ sub strtotime {
sub str_repeat { sub str_repeat {
my $string = shift; my $string = shift;
my $count = shift; my $count = shift;
return( ${string}x${count} ); return ${string}x${count};
} }
# Formats a date into MySQL format # Formats a date into MySQL format
sub DateTimeToSQL { sub DateTimeToSQL {
my $dt_str = shift; my $dt_str = shift;
my $dt_val = strtotime( $dt_str ); my $dt_val = strtotime($dt_str);
if ( !$dt_val ) { if ( !$dt_val ) {
Error( "Unable to parse date string '$dt_str'\n" ); Error("Unable to parse date string '$dt_str'");
return( undef ); return undef;
} }
return( POSIX::strftime( "%Y-%m-%d %H:%M:%S", localtime( $dt_val ) ) ); return POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime($dt_val));
} }
1; 1;

View File

@ -70,7 +70,6 @@ if ( !$id ) {
( $id ) = $id =~ /^(\w+)$/; ( $id ) = $id =~ /^(\w+)$/;
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock'; my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock';
Debug("zmcontrol: arg string: $arg_string sock file $sock_file"); Debug("zmcontrol: arg string: $arg_string sock file $sock_file");

View File

@ -448,10 +448,10 @@ sub generateImage {
} elsif ( -r $capture_image_path ) { } elsif ( -r $capture_image_path ) {
$image_path = $capture_image_path; $image_path = $capture_image_path;
} elsif ( -r $video_path ) { } elsif ( -r $video_path ) {
my $command ="ffmpeg -ss $$frame{Delta} -i '$video_path' -frames:v 1 '$capture_image_path'"; my $command ="ffmpeg -nostdin -ss $$frame{Delta} -i '$video_path' -frames:v 1 '$capture_image_path'";
#$command = "ffmpeg -y -v 0 -i $video_path -vf 'select=gte(n\\,$$frame{FrameId}),setpts=PTS-STARTPTS' -vframes 1 -f image2 $capture_image_path"; #$command = "ffmpeg -y -v 0 -i $video_path -vf 'select=gte(n\\,$$frame{FrameId}),setpts=PTS-STARTPTS' -vframes 1 -f image2 $capture_image_path";
my $output = qx($command); my $output = qx($command);
chomp( $output ); chomp($output);
my $status = $? >> 8; my $status = $? >> 8;
if ( $status || logDebugging() ) { if ( $status || logDebugging() ) {
Debug("Output: $output"); Debug("Output: $output");

View File

@ -9,7 +9,7 @@ set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_conf
# A fix for cmake recompiling the source files for every target. # A fix for cmake recompiling the source files for every target.
add_library(zm STATIC ${ZM_BIN_SRC_FILES}) add_library(zm STATIC ${ZM_BIN_SRC_FILES})
link_directories(../third_party/bcrypt) link_directories(libbcrypt)
add_executable(zmc zmc.cpp) add_executable(zmc zmc.cpp)
add_executable(zma zma.cpp) add_executable(zma zma.cpp)
@ -17,8 +17,8 @@ add_executable(zmu zmu.cpp)
add_executable(zms zms.cpp) add_executable(zms zms.cpp)
# JWT is a header only library. # JWT is a header only library.
include_directories(../third_party/bcrypt/include/bcrypt) include_directories(libbcrypt/include/bcrypt)
include_directories(../third_party/jwt-cpp/include/jwt-cpp) include_directories(jwt-cpp/include/jwt-cpp)
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})

30
src/jwt-cpp/BaseTest.cpp Normal file
View File

@ -0,0 +1,30 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/base.h"
TEST(BaseTest, Base64Decode) {
ASSERT_EQ("1", jwt::base::decode<jwt::alphabet::base64>("MQ=="));
ASSERT_EQ("12", jwt::base::decode<jwt::alphabet::base64>("MTI="));
ASSERT_EQ("123", jwt::base::decode<jwt::alphabet::base64>("MTIz"));
ASSERT_EQ("1234", jwt::base::decode<jwt::alphabet::base64>("MTIzNA=="));
}
TEST(BaseTest, Base64DecodeURL) {
ASSERT_EQ("1", jwt::base::decode<jwt::alphabet::base64url>("MQ%3d%3d"));
ASSERT_EQ("12", jwt::base::decode<jwt::alphabet::base64url>("MTI%3d"));
ASSERT_EQ("123", jwt::base::decode<jwt::alphabet::base64url>("MTIz"));
ASSERT_EQ("1234", jwt::base::decode<jwt::alphabet::base64url>("MTIzNA%3d%3d"));
}
TEST(BaseTest, Base64Encode) {
ASSERT_EQ("MQ==", jwt::base::encode<jwt::alphabet::base64>("1"));
ASSERT_EQ("MTI=", jwt::base::encode<jwt::alphabet::base64>("12"));
ASSERT_EQ("MTIz", jwt::base::encode<jwt::alphabet::base64>("123"));
ASSERT_EQ("MTIzNA==", jwt::base::encode<jwt::alphabet::base64>("1234"));
}
TEST(BaseTest, Base64EncodeURL) {
ASSERT_EQ("MQ%3d%3d", jwt::base::encode<jwt::alphabet::base64url>("1"));
ASSERT_EQ("MTI%3d", jwt::base::encode<jwt::alphabet::base64url>("12"));
ASSERT_EQ("MTIz", jwt::base::encode<jwt::alphabet::base64url>("123"));
ASSERT_EQ("MTIzNA%3d%3d", jwt::base::encode<jwt::alphabet::base64url>("1234"));
}

33
src/jwt-cpp/ClaimTest.cpp Normal file
View File

@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
TEST(ClaimTest, AudienceAsString) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.WZnM3SIiSRHsbO3O7Z2bmIzTJ4EC32HRBKfLznHhrh4";
auto decoded = jwt::decode(token);
ASSERT_TRUE(decoded.has_algorithm());
ASSERT_TRUE(decoded.has_type());
ASSERT_FALSE(decoded.has_content_type());
ASSERT_FALSE(decoded.has_key_id());
ASSERT_FALSE(decoded.has_issuer());
ASSERT_FALSE(decoded.has_subject());
ASSERT_TRUE(decoded.has_audience());
ASSERT_FALSE(decoded.has_expires_at());
ASSERT_FALSE(decoded.has_not_before());
ASSERT_FALSE(decoded.has_issued_at());
ASSERT_FALSE(decoded.has_id());
ASSERT_EQ("HS256", decoded.get_algorithm());
ASSERT_EQ("JWT", decoded.get_type());
auto aud = decoded.get_audience();
ASSERT_EQ(1, aud.size());
ASSERT_EQ("test", *aud.begin());
}
TEST(ClaimTest, SetAudienceAsString) {
auto token = jwt::create()
.set_type("JWT")
.set_audience("test")
.sign(jwt::algorithm::hs256("test"));
ASSERT_EQ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.ny5Fa0vzAg7tNL95KWg_ecBNd3XP3tdAzq0SFA6diY4", token);
}

2494
src/jwt-cpp/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
namespace {
extern std::string google_cert;
extern std::string google_cert_key;
}
TEST(HelperTest, Cert2Pubkey) {
auto key = jwt::helper::extract_pubkey_from_cert(google_cert);
ASSERT_EQ(google_cert_key, key);
}
namespace {
std::string google_cert = R"(-----BEGIN CERTIFICATE-----
MIIF8DCCBVmgAwIBAgIKYFOB9QABAACIvTANBgkqhkiG9w0BAQUFADBGMQswCQYD
VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu
dGVybmV0IEF1dGhvcml0eTAeFw0xMzA1MjIxNTQ5MDRaFw0xMzEwMzEyMzU5NTla
MGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N
b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRUwEwYDVQQDFAwqLmdv
b2dsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARmSpIUbCqhUBq1UwnR
Ai7/TNSk6W8JmasR+I0r/NLDYv5yApbAz8HXXN8hDdurMRP6Jy1Q0UIKmyls8HPH
exoCo4IECjCCBAYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAsGA1Ud
DwQEAwIHgDAdBgNVHQ4EFgQUU3jT0NVNRgU5ZinRHGrlyoGEnoYwHwYDVR0jBBgw
FoAUv8Aw6/VDET5nup6R+/xq2uNrEiQwWwYDVR0fBFQwUjBQoE6gTIZKaHR0cDov
L3d3dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS9Hb29nbGVJ
bnRlcm5ldEF1dGhvcml0eS5jcmwwZgYIKwYBBQUHAQEEWjBYMFYGCCsGAQUFBzAC
hkpodHRwOi8vd3d3LmdzdGF0aWMuY29tL0dvb2dsZUludGVybmV0QXV0aG9yaXR5
L0dvb2dsZUludGVybmV0QXV0aG9yaXR5LmNydDAMBgNVHRMBAf8EAjAAMIICwwYD
VR0RBIICujCCAraCDCouZ29vZ2xlLmNvbYINKi5hbmRyb2lkLmNvbYIWKi5hcHBl
bmdpbmUuZ29vZ2xlLmNvbYISKi5jbG91ZC5nb29nbGUuY29tghYqLmdvb2dsZS1h
bmFseXRpY3MuY29tggsqLmdvb2dsZS5jYYILKi5nb29nbGUuY2yCDiouZ29vZ2xl
LmNvLmlugg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28udWuCDyouZ29vZ2xl
LmNvbS5hcoIPKi5nb29nbGUuY29tLmF1gg8qLmdvb2dsZS5jb20uYnKCDyouZ29v
Z2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLm14gg8qLmdvb2dsZS5jb20udHKCDyou
Z29vZ2xlLmNvbS52boILKi5nb29nbGUuZGWCCyouZ29vZ2xlLmVzggsqLmdvb2ds
ZS5mcoILKi5nb29nbGUuaHWCCyouZ29vZ2xlLml0ggsqLmdvb2dsZS5ubIILKi5n
b29nbGUucGyCCyouZ29vZ2xlLnB0gg8qLmdvb2dsZWFwaXMuY26CFCouZ29vZ2xl
Y29tbWVyY2UuY29tgg0qLmdzdGF0aWMuY29tggwqLnVyY2hpbi5jb22CECoudXJs
Lmdvb2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CDSoueW91dHViZS5j
b22CFioueW91dHViZWVkdWNhdGlvbi5jb22CCyoueXRpbWcuY29tggthbmRyb2lk
LmNvbYIEZy5jb4IGZ29vLmdsghRnb29nbGUtYW5hbHl0aWNzLmNvbYIKZ29vZ2xl
LmNvbYISZ29vZ2xlY29tbWVyY2UuY29tggp1cmNoaW4uY29tggh5b3V0dS5iZYIL
eW91dHViZS5jb22CFHlvdXR1YmVlZHVjYXRpb24uY29tMA0GCSqGSIb3DQEBBQUA
A4GBAAMn0K3j3yhC+X+uyh6eABa2Eq7xiY5/mUB886Ir19vxluSMNKD6n/iY8vHj
trn0BhuW8/vmJyudFkIcEDUYE4ivQMlsfIL7SOGw6OevVLmm02aiRHWj5T20Ds+S
OpueYUG3NBcHP/5IzhUYIQJbGzlQaUaZBMaQeC8ZslMNLWI2
-----END CERTIFICATE-----)";
std::string google_cert_key = R"(-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZkqSFGwqoVAatVMJ0QIu/0zUpOlv
CZmrEfiNK/zSw2L+cgKWwM/B11zfIQ3bqzET+ictUNFCCpspbPBzx3saAg==
-----END PUBLIC KEY-----
)";
}

21
src/jwt-cpp/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Dominik Thalhammer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

98
src/jwt-cpp/README.md Normal file
View File

@ -0,0 +1,98 @@
# jwt-cpp
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5f7055e294744901991fd0a1620b231d)](https://app.codacy.com/app/Thalhammer/jwt-cpp?utm_source=github.com&utm_medium=referral&utm_content=Thalhammer/jwt-cpp&utm_campaign=Badge_Grade_Settings)
A header only library for creating and validating json web tokens in c++.
## Signature algorithms
As of version 0.2.0 jwt-cpp supports all algorithms defined by the spec. The modular design of jwt-cpp allows one to add additional algorithms without any problems. If you need any feel free to open a pull request.
For the sake of completeness, here is a list of all supported algorithms:
* HS256
* HS384
* HS512
* RS256
* RS384
* RS512
* ES256
* ES384
* ES512
* PS256
* PS384
* PS512
## Examples
Simple example of decoding a token and printing all claims:
```c++
#include <jwt-cpp/jwt.h>
#include <iostream>
int main(int argc, const char** argv) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
auto decoded = jwt::decode(token);
for(auto& e : decoded.get_payload_claims())
std::cout << e.first << " = " << e.second.to_json() << std::endl;
}
```
In order to verify a token you first build a verifier and use it to verify a decoded token.
```c++
auto verifier = jwt::verify()
.allow_algorithm(jwt::algorithm::hs256{ "secret" })
.with_issuer("auth0");
verifier.verify(decoded_token);
```
The created verifier is stateless so you can reuse it for different tokens.
Creating a token (and signing) is equally easy.
```c++
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.set_payload_claim("sample", std::string("test"))
.sign(jwt::algorithm::hs256{"secret"});
```
Here is a simple example of creating a token that will expire in 2 hours:
```c++
// Note to @Thalhammer: please replace with a better example if this is not a good way
auto token = jwt::create()
.set_issuer("auth0")
.set_issued_at(jwt::date(std::chrono::system_clock::now()))
.set_expires_at(jwt::date(std::chrono::system_clock::now()+ std::chrono::seconds{3600}))
.sign(jwt::algorithm::hs256{"secret"}
```
## Contributing
If you have an improvement or found a bug feel free to [open an issue](https://github.com/Thalhammer/jwt-cpp/issues/new) or add the change and create a pull request. If you file a bug please make sure to include as much information about your environment (compiler version, etc.) as possible to help reproduce the issue. If you add a new feature please make sure to also include test cases for it.
## Dependencies
In order to use jwt-cpp you need the following tools.
* libcrypto (openssl or compatible)
* libssl-dev (for the header files)
* a compiler supporting at least c++11
* basic stl support
In order to build the test cases you also need
* gtest installed in linker path
* pthread
## Troubleshooting
#### Expired tokens
If you are generating tokens that seem to immediately expire, you are likely not using UTC. Specifically,
if you use `get_time` to get the current time, it likely uses localtime, while this library uses UTC, which may be why your token is immediately expiring. Please see example above on the right way to use current time.
#### Missing _HMAC amd _EVP_sha256 symbols on Mac
There seems to exists a problem with the included openssl library of MacOS. Make sure you link to one provided by brew.
See [here](https://github.com/Thalhammer/jwt-cpp/issues/6) for more details.
#### Building on windows fails with syntax errors
The header "Windows.h", which is often included in windowsprojects, defines macros for MIN and MAX which screw up std::numeric_limits.
See [here](https://github.com/Thalhammer/jwt-cpp/issues/5) for more details. To fix this do one of the following things:
* define NOMINMAX, which suppresses this behaviour
* include this library before you include windows.h
* place ```#undef max``` and ```#undef min``` before you include this library

7
src/jwt-cpp/TestMain.cpp Normal file
View File

@ -0,0 +1,7 @@
#include <gtest/gtest.h>
int main(int argc, char *argv[])
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,15 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
TEST(TokenFormatTest, MissingDot) {
ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJpc3MiOiJhdXRoMCJ9"), std::invalid_argument);
ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0eyJpc3MiOiJhdXRoMCJ9."), std::invalid_argument);
}
TEST(TokenFormatTest, InvalidChar) {
ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0().eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error);
}
TEST(TokenFormatTest, InvalidJSON) {
ASSERT_THROW(jwt::decode("YXsiYWxnIjoibm9uZSIsInR5cCI6IkpXUyJ9YQ.eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error);
}

420
src/jwt-cpp/TokenTest.cpp Normal file
View File

@ -0,0 +1,420 @@
#include <gtest/gtest.h>
#include "include/jwt-cpp/jwt.h"
namespace {
extern std::string rsa_priv_key;
extern std::string rsa_pub_key;
extern std::string rsa_pub_key_invalid;
extern std::string rsa512_priv_key;
extern std::string rsa512_pub_key;
extern std::string rsa512_pub_key_invalid;
extern std::string ecdsa_priv_key;
extern std::string ecdsa_pub_key;
extern std::string ecdsa_pub_key_invalid;
}
TEST(TokenTest, DecodeToken) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
auto decoded = jwt::decode(token);
ASSERT_TRUE(decoded.has_algorithm());
ASSERT_TRUE(decoded.has_type());
ASSERT_FALSE(decoded.has_content_type());
ASSERT_FALSE(decoded.has_key_id());
ASSERT_TRUE(decoded.has_issuer());
ASSERT_FALSE(decoded.has_subject());
ASSERT_FALSE(decoded.has_audience());
ASSERT_FALSE(decoded.has_expires_at());
ASSERT_FALSE(decoded.has_not_before());
ASSERT_FALSE(decoded.has_issued_at());
ASSERT_FALSE(decoded.has_id());
ASSERT_EQ("HS256", decoded.get_algorithm());
ASSERT_EQ("JWS", decoded.get_type());
ASSERT_EQ("auth0", decoded.get_issuer());
}
TEST(TokenTest, CreateToken) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::none{});
ASSERT_EQ("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJpc3MiOiJhdXRoMCJ9.", token);
}
TEST(TokenTest, CreateTokenHS256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::hs256{"secret"});
ASSERT_EQ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE", token);
}
TEST(TokenTest, CreateTokenRS256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::rs256(rsa_pub_key, rsa_priv_key, "", ""));
ASSERT_EQ(
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ", token);
}
TEST(TokenTest, CreateTokenRS512) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::rs512(rsa512_pub_key, rsa512_priv_key, "", ""));
ASSERT_EQ(
"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZSSQyLKvI0"
"TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4GB"
"hfGgejPBCBlGrQtqFGFdHHOjNHY", token);
}
TEST(TokenTest, CreateTokenPS256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::ps256(rsa_pub_key, rsa_priv_key, "", ""));
// TODO: Find a better way to check if generated signature is valid
// Can't do simple check for equal since pss adds random salt.
}
TEST(TokenTest, CreateTokenPS384) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::ps384(rsa_pub_key, rsa_priv_key, "", ""));
// TODO: Find a better way to check if generated signature is valid
// Can't do simple check for equal since pss adds random salt.
}
TEST(TokenTest, CreateTokenPS512) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::ps512(rsa_pub_key, rsa_priv_key, "", ""));
// TODO: Find a better way to check if generated signature is valid
// Can't do simple check for equal since pss adds random salt.
}
TEST(TokenTest, CreateTokenES256) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::es256("", ecdsa_priv_key, "", ""));
auto decoded = jwt::decode(token);
ASSERT_THROW(jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key_invalid, "", "", "")).verify(decoded), jwt::signature_verification_exception);
ASSERT_NO_THROW(jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key, "", "", "")).verify(decoded));
}
TEST(TokenTest, CreateTokenES256NoPrivate) {
ASSERT_THROW([](){
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::es256(ecdsa_pub_key, "", "", ""));
}(), jwt::signature_generation_exception);
}
TEST(TokenTest, VerifyTokenRS256) {
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256(rsa_pub_key, rsa_priv_key, "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS256PublicOnly) {
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256(rsa_pub_key, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS256Fail) {
std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
"HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
"YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
"sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-uc2z5c05CCXqVSpfCjWbh9gQ";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs256(rsa_pub_key_invalid, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
TEST(TokenTest, VerifyTokenRS512) {
std::string token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZ"
"SSQyLKvI0TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4"
"GBhfGgejPBCBlGrQtqFGFdHHOjNHY";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs512(rsa512_pub_key, rsa512_priv_key, "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS512PublicOnly) {
std::string token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZ"
"SSQyLKvI0TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4"
"GBhfGgejPBCBlGrQtqFGFdHHOjNHY";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs512(rsa512_pub_key, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenRS512Fail) {
std::string token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.GZhnjtsvBl2_KDSxg4JW6xnmNjr2mWhYSZ"
"SSQyLKvI0TK86sJKchkt_HDy2IC5l5BGRhq_Xv9pHdA1umidQZG3a7gWvHsujqybCBgBraMTd1wJrCl4QxFg2RYHhHbRqb9BnPJgFD_vryd4"
"GBhfGgejPBCBlGrQtqFGFdHHOjNHY";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::rs512(rsa_pub_key_invalid, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
TEST(TokenTest, VerifyTokenHS256) {
std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::hs256{ "secret" })
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyFail) {
auto token = jwt::create()
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::none{});
auto decoded_token = jwt::decode(token);
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth");
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth0")
.with_audience({ "test" });
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth0")
.with_subject("test");
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
{
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::none{})
.with_issuer("auth0")
.with_claim("myclaim", jwt::claim(std::string("test")));
ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception);
}
}
TEST(TokenTest, VerifyTokenES256) {
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";
auto verify = jwt::verify().allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key, "", "", ""));
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenES256Fail) {
const std::string token = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::es256(ecdsa_pub_key_invalid, "", "", ""));
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
TEST(TokenTest, VerifyTokenPS256) {
std::string token = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.CJ4XjVWdbV6vXGZkD4GdJbtYc80SN9cmPOqRhZBRzOyDRqTFE"
"4MsbdKyQuhAWcvuMOjn-24qOTjVMR_P_uTC1uG6WPLcucxZyLnbb56zbKnEklW2SX0mQnCGewr-93a_vDaFT6Cp45MsF_OwFPRCMaS5CJg-"
"N5KY67UrVSr3s9nkuK9ZTQkyODHfyEUh9F_FhRCATGrb5G7_qHqBYvTvaPUXqzhhpCjN855Tocg7A24Hl0yMwM-XdasucW5xNdKjG_YCkis"
"HX7ax--JiF5GNYCO61eLFteO4THUg-3Z0r4OlGqlppyWo5X5tjcxOZCvBh7WDWfkxA48KFZPRv0nlKA";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::ps256(rsa_pub_key, rsa_priv_key, "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenPS256PublicOnly) {
std::string token = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.CJ4XjVWdbV6vXGZkD4GdJbtYc80SN9cmPOqRhZBRzOyDRqTFE"
"4MsbdKyQuhAWcvuMOjn-24qOTjVMR_P_uTC1uG6WPLcucxZyLnbb56zbKnEklW2SX0mQnCGewr-93a_vDaFT6Cp45MsF_OwFPRCMaS5CJg-"
"N5KY67UrVSr3s9nkuK9ZTQkyODHfyEUh9F_FhRCATGrb5G7_qHqBYvTvaPUXqzhhpCjN855Tocg7A24Hl0yMwM-XdasucW5xNdKjG_YCkis"
"HX7ax--JiF5GNYCO61eLFteO4THUg-3Z0r4OlGqlppyWo5X5tjcxOZCvBh7WDWfkxA48KFZPRv0nlKA";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::ps256(rsa_pub_key, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
verify.verify(decoded_token);
}
TEST(TokenTest, VerifyTokenPS256Fail) {
std::string token = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.CJ4XjVWdbV6vXGZkD4GdJbtYc80SN9cmPOqRhZBRzOyDRqTFE"
"4MsbdKyQuhAWcvuMOjn-24qOTjVMR_P_uTC1uG6WPLcucxZyLnbb56zbKnEklW2SX0mQnCGewr-93a_vDaFT6Cp45MsF_OwFPRCMaS5CJg-"
"N5KY67UrVSr3s9nkuK9ZTQkyODHfyEUh9F_FhRCATGrb5G7_qHqBYvTvaPUXqzhhpCjN855Tocg7A24Hl0yMwM-XdasucW5xNdKjG_YCkis"
"HX7ax--JiF5GNYCO61eLFteO4THUg-3Z0r4OlGqlppyWo5X5tjcxOZCvBh7WDWfkxA48KFZPRv0nlKA";
auto verify = jwt::verify()
.allow_algorithm(jwt::algorithm::ps256(rsa_pub_key_invalid, "", "", ""))
.with_issuer("auth0");
auto decoded_token = jwt::decode(token);
ASSERT_THROW(verify.verify(decoded_token), jwt::signature_verification_exception);
}
namespace {
std::string rsa_priv_key = R"(-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ
tfnF0TjIK5inQAXZ3XlCrUlJdP+XHwIRxdv1FsN12XyMYO/6ymLmo9ryoQeIrsXB
XYqlET3zfAY+diwCb0HEsVvhisthwMU4gZQu6TYW2s9LnXZB5rVtcBK69hcSlA2k
ZudMZWxZcj0L7KMfO2rIvaHw/qaVOE9j0T257Z8Kp2CLF9MUgX0ObhIsdumFRLaL
DvDUmBPr2zuh/34j2XmWwn1yjN/WvGtdfhXW79Ki1S40HcWnygHgLV8sESFKUxxQ
mKvPUTwDOIwLFL5WtE8Mz7N++kgmDcmWMCHc8kcOIu73Ta/3D4imW7VbKgHZo9+K
3ESFE3RjAgMBAAECggEBAJTEIyjMqUT24G2FKiS1TiHvShBkTlQdoR5xvpZMlYbN
tVWxUmrAGqCQ/TIjYnfpnzCDMLhdwT48Ab6mQJw69MfiXwc1PvwX1e9hRscGul36
ryGPKIVQEBsQG/zc4/L2tZe8ut+qeaK7XuYrPp8bk/X1e9qK5m7j+JpKosNSLgJj
NIbYsBkG2Mlq671irKYj2hVZeaBQmWmZxK4fw0Istz2WfN5nUKUeJhTwpR+JLUg4
ELYYoB7EO0Cej9UBG30hbgu4RyXA+VbptJ+H042K5QJROUbtnLWuuWosZ5ATldwO
u03dIXL0SH0ao5NcWBzxU4F2sBXZRGP2x/jiSLHcqoECgYEA4qD7mXQpu1b8XO8U
6abpKloJCatSAHzjgdR2eRDRx5PMvloipfwqA77pnbjTUFajqWQgOXsDTCjcdQui
wf5XAaWu+TeAVTytLQbSiTsBhrnoqVrr3RoyDQmdnwHT8aCMouOgcC5thP9vQ8Us
rVdjvRRbnJpg3BeSNimH+u9AHgsCgYEA0EzcbOltCWPHRAY7B3Ge/AKBjBQr86Kv
TdpTlxePBDVIlH+BM6oct2gaSZZoHbqPjbq5v7yf0fKVcXE4bSVgqfDJ/sZQu9Lp
PTeV7wkk0OsAMKk7QukEpPno5q6tOTNnFecpUhVLLlqbfqkB2baYYwLJR3IRzboJ
FQbLY93E8gkCgYB+zlC5VlQbbNqcLXJoImqItgQkkuW5PCgYdwcrSov2ve5r/Acz
FNt1aRdSlx4176R3nXyibQA1Vw+ztiUFowiP9WLoM3PtPZwwe4bGHmwGNHPIfwVG
m+exf9XgKKespYbLhc45tuC08DATnXoYK7O1EnUINSFJRS8cezSI5eHcbQKBgQDC
PgqHXZ2aVftqCc1eAaxaIRQhRmY+CgUjumaczRFGwVFveP9I6Gdi+Kca3DE3F9Pq
PKgejo0SwP5vDT+rOGHN14bmGJUMsX9i4MTmZUZ5s8s3lXh3ysfT+GAhTd6nKrIE
kM3Nh6HWFhROptfc6BNusRh1kX/cspDplK5x8EpJ0QKBgQDWFg6S2je0KtbV5PYe
RultUEe2C0jYMDQx+JYxbPmtcopvZQrFEur3WKVuLy5UAy7EBvwMnZwIG7OOohJb
vkSpADK6VPn9lbqq7O8cTedEHttm6otmLt8ZyEl3hZMaL3hbuRj6ysjmoFKx6CrX
rK0/Ikt5ybqUzKCMJZg2VKGTxg==
-----END PRIVATE KEY-----)";
std::string rsa_pub_key = R"(-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGbXWiK3dQTyCbX5xdE4
yCuYp0AF2d15Qq1JSXT/lx8CEcXb9RbDddl8jGDv+spi5qPa8qEHiK7FwV2KpRE9
83wGPnYsAm9BxLFb4YrLYcDFOIGULuk2FtrPS512Qea1bXASuvYXEpQNpGbnTGVs
WXI9C+yjHztqyL2h8P6mlThPY9E9ue2fCqdgixfTFIF9Dm4SLHbphUS2iw7w1JgT
69s7of9+I9l5lsJ9cozf1rxrXX4V1u/SotUuNB3Fp8oB4C1fLBEhSlMcUJirz1E8
AziMCxS+VrRPDM+zfvpIJg3JljAh3PJHDiLu902v9w+Iplu1WyoB2aPfitxEhRN0
YwIDAQAB
-----END PUBLIC KEY-----)";
std::string rsa_pub_key_invalid = R"(-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK
5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa
vkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0
FK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC
VTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M
r3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s
YwIDAQAB
-----END PUBLIC KEY-----)";
std::string rsa512_priv_key = R"(-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS
3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp
uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE
2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0
GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K
Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY
6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5
fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
-----END RSA PRIVATE KEY-----)";
std::string rsa512_pub_key = R"(-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd
UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs
HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D
o2kQ+X5xK9cipRgEKwIDAQAB
-----END PUBLIC KEY-----)";
std::string rsa512_pub_key_invalid = R"(-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK
5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa
vkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0
FK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC
VTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M
r3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s
YwIDAQAB
-----END PUBLIC KEY-----)";
std::string ecdsa_priv_key = R"(-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPGJGAm4X1fvBuC1z
SpO/4Izx6PXfNMaiKaS5RUkFqEGhRANCAARCBvmeksd3QGTrVs2eMrrfa7CYF+sX
sjyGg+Bo5mPKGH4Gs8M7oIvoP9pb/I85tdebtKlmiCZHAZE5w4DfJSV6
-----END PRIVATE KEY-----)";
std::string ecdsa_pub_key = R"(-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQgb5npLHd0Bk61bNnjK632uwmBfr
F7I8hoPgaOZjyhh+BrPDO6CL6D/aW/yPObXXm7SpZogmRwGROcOA3yUleg==
-----END PUBLIC KEY-----)";
std::string ecdsa_pub_key_invalid = R"(-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoBUyo8CQAFPeYPvv78ylh5MwFZjT
CLQeb042TjiMJxG+9DLFmRSMlBQ9T/RsLLc+PmpB1+7yPAR+oR5gZn3kJQ==
-----END PUBLIC KEY-----)";
}

View File

@ -0,0 +1,168 @@
#pragma once
#include <string>
#include <array>
namespace jwt {
namespace alphabet {
struct base64 {
static const std::array<char, 64>& data() {
static std::array<char, 64> data = {
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
return data;
};
static const std::string& fill() {
static std::string fill = "=";
return fill;
}
};
struct base64url {
static const std::array<char, 64>& data() {
static std::array<char, 64> data = {
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
return data;
};
static const std::string& fill() {
static std::string fill = "%3d";
return fill;
}
};
}
class base {
public:
template<typename T>
static std::string encode(const std::string& bin) {
return encode(bin, T::data(), T::fill());
}
template<typename T>
static std::string decode(const std::string& base) {
return decode(base, T::data(), T::fill());
}
private:
static std::string encode(const std::string& bin, const std::array<char, 64>& alphabet, const std::string& fill) {
size_t size = bin.size();
std::string res;
// clear incomplete bytes
size_t fast_size = size - size % 3;
for (size_t i = 0; i < fast_size;) {
uint32_t octet_a = (unsigned char)bin[i++];
uint32_t octet_b = (unsigned char)bin[i++];
uint32_t octet_c = (unsigned char)bin[i++];
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
res += alphabet[(triple >> 3 * 6) & 0x3F];
res += alphabet[(triple >> 2 * 6) & 0x3F];
res += alphabet[(triple >> 1 * 6) & 0x3F];
res += alphabet[(triple >> 0 * 6) & 0x3F];
}
if (fast_size == size)
return res;
size_t mod = size % 3;
uint32_t octet_a = fast_size < size ? (unsigned char)bin[fast_size++] : 0;
uint32_t octet_b = fast_size < size ? (unsigned char)bin[fast_size++] : 0;
uint32_t octet_c = fast_size < size ? (unsigned char)bin[fast_size++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
switch (mod) {
case 1:
res += alphabet[(triple >> 3 * 6) & 0x3F];
res += alphabet[(triple >> 2 * 6) & 0x3F];
res += fill;
res += fill;
break;
case 2:
res += alphabet[(triple >> 3 * 6) & 0x3F];
res += alphabet[(triple >> 2 * 6) & 0x3F];
res += alphabet[(triple >> 1 * 6) & 0x3F];
res += fill;
break;
default:
break;
}
return res;
}
static std::string decode(const std::string& base, const std::array<char, 64>& alphabet, const std::string& fill) {
size_t size = base.size();
size_t fill_cnt = 0;
while (size > fill.size()) {
if (base.substr(size - fill.size(), fill.size()) == fill) {
fill_cnt++;
size -= fill.size();
if(fill_cnt > 2)
throw std::runtime_error("Invalid input");
}
else break;
}
if ((size + fill_cnt) % 4 != 0)
throw std::runtime_error("Invalid input");
size_t out_size = size / 4 * 3;
std::string res;
res.reserve(out_size);
auto get_sextet = [&](size_t offset) {
for (size_t i = 0; i < alphabet.size(); i++) {
if (alphabet[i] == base[offset])
return i;
}
throw std::runtime_error("Invalid input");
};
size_t fast_size = size - size % 4;
for (size_t i = 0; i < fast_size;) {
uint32_t sextet_a = get_sextet(i++);
uint32_t sextet_b = get_sextet(i++);
uint32_t sextet_c = get_sextet(i++);
uint32_t sextet_d = get_sextet(i++);
uint32_t triple = (sextet_a << 3 * 6)
+ (sextet_b << 2 * 6)
+ (sextet_c << 1 * 6)
+ (sextet_d << 0 * 6);
res += (triple >> 2 * 8) & 0xFF;
res += (triple >> 1 * 8) & 0xFF;
res += (triple >> 0 * 8) & 0xFF;
}
if (fill_cnt == 0)
return res;
uint32_t triple = (get_sextet(fast_size) << 3 * 6)
+ (get_sextet(fast_size + 1) << 2 * 6);
switch (fill_cnt) {
case 1:
triple |= (get_sextet(fast_size + 2) << 1 * 6);
res += (triple >> 2 * 8) & 0xFF;
res += (triple >> 1 * 8) & 0xFF;
break;
case 2:
res += (triple >> 2 * 8) & 0xFF;
break;
default:
break;
}
return res;
}
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

28
src/jwt-cpp/jwt-cpp.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jwt-cpp", "jwt-cpp.vcxproj", "{1CA8C676-7F8E-434C-9069-8F20A562E6E9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x64.ActiveCfg = Debug|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x64.Build.0 = Debug|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x86.ActiveCfg = Debug|Win32
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Debug|x86.Build.0 = Debug|Win32
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x64.ActiveCfg = Release|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x64.Build.0 = Release|x64
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x86.ActiveCfg = Release|Win32
{1CA8C676-7F8E-434C-9069-8F20A562E6E9}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

160
src/jwt-cpp/jwt-cpp.vcxproj Normal file
View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1CA8C676-7F8E-434C-9069-8F20A562E6E9}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>jwtcpp</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>gtest.lib;gtest_main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="include\jwt-cpp\base.h" />
<ClInclude Include="include\jwt-cpp\jwt.h" />
<ClInclude Include="include\jwt-cpp\picojson.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BaseTest.cpp" />
<ClCompile Include="TokenTest.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Quelldateien">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headerdateien">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Ressourcendateien">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\jwt-cpp\jwt.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="include\jwt-cpp\picojson.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="include\jwt-cpp\base.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BaseTest.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="TokenTest.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
Source: jwt-cpp
Version: 2019-04-20
Description: A header only library for creating and validating json web tokens in c++

View File

@ -0,0 +1,12 @@
diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h
index ec56810..a26fd97 100644
--- a/include/jwt-cpp/jwt.h
+++ b/include/jwt-cpp/jwt.h
@@ -1,6 +1,6 @@
#pragma once
#define PICOJSON_USE_INT64
-#include "picojson.h"
+#include "picojson/picojson.h"
#include "base.h"
#include <set>
#include <chrono>

View File

@ -0,0 +1,31 @@
diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h
index dfca7fc..4d05c0b 100644
--- a/include/jwt-cpp/base.h
+++ b/include/jwt-cpp/base.h
@@ -2,6 +2,10 @@
#include <string>
#include <array>
+#ifdef _MSC_VER
+#pragma warning(disable : 4267)
+#endif
+
namespace jwt {
namespace alphabet {
struct base64 {
diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h
index ec56810..313cef2 100644
--- a/include/jwt-cpp/jwt.h
+++ b/include/jwt-cpp/jwt.h
@@ -12,6 +12,11 @@
#include <openssl/ec.h>
#include <openssl/err.h>
+#ifdef _MSC_VER
+#pragma warning(disable : 4267)
+#pragma warning(disable : 4067)
+#endif
+
//If openssl version less than 1.1
#if OPENSSL_VERSION_NUMBER < 269484032
#define OPENSSL10

View File

@ -0,0 +1,23 @@
#header-only library
include(vcpkg_common_functions)
set(SOURCE_PATH ${CURRENT_BUILDTREES_DIR}/src/jwt-cpp)
vcpkg_from_github(OUT_SOURCE_PATH SOURCE_PATH
REPO Thalhammer/jwt-cpp
REF f0e37a79f605312686065405dd720fc197cc3df0
SHA512 ae83c205dbb340dedc58d0d3f0e2453c4edcf5ce43b401f49d02692dc8a2a4b7260f1ced05ddfa7c1d5d6f92446e232629ddbdf67a58a119b50c5c8163591598
HEAD_REF master
PATCHES fix-picojson.patch
fix-warning.patch)
# Copy the constexpr header files
file(GLOB HEADER_FILES ${SOURCE_PATH}/include/jwt-cpp/*)
file(COPY ${HEADER_FILES}
DESTINATION ${CURRENT_PACKAGES_DIR}/include/jwt-cpp
REGEX "\.(gitattributes|gitignore|picojson.h)$" EXCLUDE)
# Put the licence file where vcpkg expects it
file(COPY ${SOURCE_PATH}/LICENSE
DESTINATION ${CURRENT_PACKAGES_DIR}/share/jwt-cpp)
file(RENAME ${CURRENT_PACKAGES_DIR}/share/jwt-cpp/LICENSE ${CURRENT_PACKAGES_DIR}/share/jwt-cpp/copyright)

View File

@ -0,0 +1,90 @@
###################################################################################
#
# Copyright (c) 2014, webvariants GmbH, http://www.webvariants.de
#
# This file is released under the terms of the MIT license. You can find the
# complete text in the attached LICENSE file or online at:
#
# http://www.opensource.org/licenses/mit-license.php
#
# @author: Tino Rusch (tino.rusch@webvariants.de)
#
###################################################################################
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(bcrypt)
enable_language(ASM)
set(MYLIB_VERSION_MAJOR 1)
set(MYLIB_VERSION_MINOR 0)
set(MYLIB_VERSION_PATCH 0)
set(MYLIB_VERSION_STRING ${MYLIB_VERSION_MAJOR}.${MYLIB_VERSION_MINOR}.${MYLIB_VERSION_PATCH})
# just doing cmake . will build a shared or static lib and honor existing environment setting
# to force build static, cmake . -DBUILD_SHARED_LIBS=Off
# to force build shared, cmake . -DBUILD_SHARED_LIBS=On
if (NOT BUILD_SHARED_LIBS)
message ("Building a static library")
else ()
message ("Building a shared library")
endif ()
set( CMAKE_COLOR_MAKEFILE ON )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall --std=c++11 -O3" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3" )
set( CMAKE_ASM_FLAGS "${CXXFLAGS} -x assembler-with-cpp")
set( SRCFILES
${CMAKE_CURRENT_SOURCE_DIR}/src/bcrypt.c
${CMAKE_CURRENT_SOURCE_DIR}/src/crypt_blowfish.c
${CMAKE_CURRENT_SOURCE_DIR}/src/crypt_gensalt.c
${CMAKE_CURRENT_SOURCE_DIR}/src/wrapper.c
${CMAKE_CURRENT_SOURCE_DIR}/src/x86.S
)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include/bcrypt)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(
${PROJECT_NAME}
${SRCFILES}
)
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${MYLIB_VERSION_STRING} SOVERSION ${MYLIB_VERSION_MAJOR})
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER include/bcrypt/BCrypt.hpp)
target_include_directories(${PROJECT_NAME} PRIVATE include)
target_include_directories(${PROJECT_NAME} PRIVATE src)
add_executable( ${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
target_link_libraries( ${PROJECT_NAME}_test ${PROJECT_NAME})
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bcrypt)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h")
SET(CPACK_GENERATOR "DEB")
SET(CPACK_SET_DESTDIR ON)
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Manuel Romei")
SET(CPACK_PACKAGE_VERSION "1.0.0")
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
SET(CPACK_PACKAGE_VERSION_MINOR "0")
SET(CPACK_PACKAGE_VERSION_PATCH "0")
INCLUDE(CPack)

22
src/libbcrypt/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 trusch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
src/libbcrypt/README.md Normal file
View File

@ -0,0 +1,40 @@
# libbcrypt
A c++ wrapper around bcrypt password hashing
## How to build this
This is a CMake based project:
```bash
git clone https://github.com/trusch/libbcrypt
cd libbcrypt
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig
```
## How to use this
Here an example how to use this wrapper class (you can find it in the src/ subdirectory)
```cpp
#include "bcrypt/BCrypt.hpp"
#include <iostream>
int main(){
BCrypt bcrypt;
std::string password = "test";
std::string hash = bcrypt.generateHash(password);
std::cout<<bcrypt.validatePassword(password,hash)<<std::endl;
std::cout<<bcrypt.validatePassword("test1",hash)<<std::endl;
return 0;
}
```
build this with something like this:
```bash
g++ --std=c++11 -lbcrypt main.cpp
```

View File

@ -0,0 +1,32 @@
#ifndef __BCRYPT__
#define __BCRYPT__
#ifdef _WIN32
#include "winbcrypt.h"
#else
#include "bcrypt.h"
#include <string>
#include <stdexcept>
class BCrypt {
public:
static std::string generateHash(const std::string & password, int workload = 12){
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int ret;
ret = bcrypt_gensalt(workload, salt);
if(ret != 0)throw std::runtime_error{"bcrypt: can not generate salt"};
ret = bcrypt_hashpw(password.c_str(), salt, hash);
if(ret != 0)throw std::runtime_error{"bcrypt: can not generate hash"};
return std::string{hash};
}
static bool validatePassword(const std::string & password, const std::string & hash){
return (bcrypt_checkpw(password.c_str(), hash.c_str()) == 0);
}
};
#endif
#endif // __BCRYPT__

View File

@ -0,0 +1,97 @@
#ifndef BCRYPT_H_
#define BCRYPT_H_
/*
* bcrypt wrapper library
*
* Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#define BCRYPT_HASHSIZE (64)
#ifdef __cplusplus
extern "C" {
#endif
/*
* This function expects a work factor between 4 and 31 and a char array to
* store the resulting generated salt. The char array should typically have
* BCRYPT_HASHSIZE bytes at least. If the provided work factor is not in the
* previous range, it will default to 12.
*
* The return value is zero if the salt could be correctly generated and
* nonzero otherwise.
*
*/
int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]);
/*
* This function expects a password to be hashed, a salt to hash the password
* with and a char array to leave the result. Both the salt and the hash
* parameters should have room for BCRYPT_HASHSIZE characters at least.
*
* It can also be used to verify a hashed password. In that case, provide the
* expected hash in the salt parameter and verify the output hash is the same
* as the input hash. However, to avoid timing attacks, it's better to use
* bcrypt_checkpw when verifying a password.
*
* The return value is zero if the password could be hashed and nonzero
* otherwise.
*/
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE],
char hash[BCRYPT_HASHSIZE]);
/*
* This function expects a password and a hash to verify the password against.
* The internal implementation is tuned to avoid timing attacks.
*
* The return value will be -1 in case of errors, zero if the provided password
* matches the given hash and greater than zero if no errors are found and the
* passwords don't match.
*
*/
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]);
/*
* Brief Example
* -------------
*
* Hashing a password:
*
* char salt[BCRYPT_HASHSIZE];
* char hash[BCRYPT_HASHSIZE];
* int ret;
*
* ret = bcrypt_gensalt(12, salt);
* assert(ret == 0);
* ret = bcrypt_hashpw("thepassword", salt, hash);
* assert(ret == 0);
*
*
* Verifying a password:
*
* int ret;
*
* ret = bcrypt_checkpw("thepassword", "expectedhash");
* assert(ret != -1);
*
* if (ret == 0) {
* printf("The password matches\n");
* } else {
* printf("The password does NOT match\n");
* }
*
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,24 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2002.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2002 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#include <gnu-crypt.h>
#if defined(_OW_SOURCE) || defined(__USE_OW)
#define __SKIP_GNU
#undef __SKIP_OW
#include <ow-crypt.h>
#undef __SKIP_GNU
#endif

View File

@ -0,0 +1,27 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _CRYPT_BLOWFISH_H
#define _CRYPT_BLOWFISH_H
extern int _crypt_output_magic(const char *setting, char *output, int size);
extern char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size);
extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
unsigned long count,
const char *input, int size, char *output, int output_size);
#endif

View File

@ -0,0 +1,30 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _CRYPT_GENSALT_H
#define _CRYPT_GENSALT_H
extern unsigned char _crypt_itoa64[];
extern char *_crypt_gensalt_traditional_rn(const char *prefix,
unsigned long count,
const char *input, int size, char *output, int output_size);
extern char *_crypt_gensalt_extended_rn(const char *prefix,
unsigned long count,
const char *input, int size, char *output, int output_size);
extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size);
#endif

View File

@ -0,0 +1,43 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _OW_CRYPT_H
#define _OW_CRYPT_H
#ifndef __GNUC__
#undef __const
#define __const const
#endif
#ifndef __SKIP_GNU
extern char *crypt(__const char *key, __const char *setting);
extern char *crypt_r(__const char *key, __const char *setting, void *data);
#endif
#ifndef __SKIP_OW
extern char *crypt_rn(__const char *key, __const char *setting,
void *data, int size);
extern char *crypt_ra(__const char *key, __const char *setting,
void **data, int *size);
extern char *crypt_gensalt(__const char *prefix, unsigned long count,
__const char *input, int size);
extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count,
__const char *input, int size, char *output, int output_size);
extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count,
__const char *input, int size);
#endif
#endif

View File

@ -0,0 +1,27 @@
#ifndef __WIN_BCRYPT__H
#define __WIN_BCRYPT__H
#include <iostream>
#include "crypt_blowfish.h"
#include "./bcrypt.h"
class BCrypt {
public:
static std::string generateHash(const std::string & password, int workload = 12) {
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int ret;
ret = bcrypt_gensalt(workload, salt);
if (ret != 0)throw std::runtime_error{ "bcrypt: can not generate salt" };
ret = bcrypt_hashpw(password.c_str(), salt, hash);
if (ret != 0)throw std::runtime_error{ "bcrypt: can not generate hash" };
return std::string{ hash };
}
static bool validatePassword(const std::string & password, const std::string & hash) {
return (bcrypt_checkpw(password.c_str(), hash.c_str()) == 0);
}
};
#endif

230
src/libbcrypt/src/bcrypt.c Normal file
View File

@ -0,0 +1,230 @@
/*
* bcrypt wrapper library
*
* Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef _WIN32
#elif _WIN64
#else
#include <unistd.h>
#endif
#include <errno.h>
#ifdef _WIN32 || _WIN64
// On windows we need to generate random bytes differently.
typedef __int64 ssize_t;
#define BCRYPT_HASHSIZE 60
#include "../include/bcrypt/bcrypt.h"
#include <windows.h>
#include <wincrypt.h> /* CryptAcquireContext, CryptGenRandom */
#else
#include "bcrypt.h"
#include "ow-crypt.h"
#endif
#define RANDBYTES (16)
static int try_close(int fd)
{
int ret;
for (;;) {
errno = 0;
ret = close(fd);
if (ret == -1 && errno == EINTR)
continue;
break;
}
return ret;
}
static int try_read(int fd, char *out, size_t count)
{
size_t total;
ssize_t partial;
total = 0;
while (total < count)
{
for (;;) {
errno = 0;
partial = read(fd, out + total, count - total);
if (partial == -1 && errno == EINTR)
continue;
break;
}
if (partial < 1)
return -1;
total += partial;
}
return 0;
}
/*
* This is a best effort implementation. Nothing prevents a compiler from
* optimizing this function and making it vulnerable to timing attacks, but
* this method is commonly used in crypto libraries like NaCl.
*
* Return value is zero if both strings are equal and nonzero otherwise.
*/
static int timing_safe_strcmp(const char *str1, const char *str2)
{
const unsigned char *u1;
const unsigned char *u2;
int ret;
int i;
int len1 = strlen(str1);
int len2 = strlen(str2);
/* In our context both strings should always have the same length
* because they will be hashed passwords. */
if (len1 != len2)
return 1;
/* Force unsigned for bitwise operations. */
u1 = (const unsigned char *)str1;
u2 = (const unsigned char *)str2;
ret = 0;
for (i = 0; i < len1; ++i)
ret |= (u1[i] ^ u2[i]);
return ret;
}
int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
{
int fd;
char input[RANDBYTES];
int workf;
char *aux;
// Note: Windows does not have /dev/urandom sadly.
#ifdef _WIN32 || _WIN64
HCRYPTPROV p;
ULONG i;
// Acquire a crypt context for generating random bytes.
if (CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) {
return 1;
}
if (CryptGenRandom(p, RANDBYTES, (BYTE*)input) == FALSE) {
return 2;
}
if (CryptReleaseContext(p, 0) == FALSE) {
return 3;
}
#else
// Get random bytes on Unix/Linux.
fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
return 1;
if (try_read(fd, input, RANDBYTES) != 0) {
if (try_close(fd) != 0)
return 4;
return 2;
}
if (try_close(fd) != 0)
return 3;
#endif
/* Generate salt. */
workf = (factor < 4 || factor > 31)?12:factor;
aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES,
salt, BCRYPT_HASHSIZE);
return (aux == NULL)?5:0;
}
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE])
{
char *aux;
aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE);
return (aux == NULL)?1:0;
}
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE])
{
int ret;
char outhash[BCRYPT_HASHSIZE];
ret = bcrypt_hashpw(passwd, hash, outhash);
if (ret != 0)
return -1;
return timing_safe_strcmp(hash, outhash);
}
#ifdef TEST_BCRYPT
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void)
{
clock_t before;
clock_t after;
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
int ret;
const char pass[] = "hi,mom";
const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK";
const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO";
ret = bcrypt_gensalt(12, salt);
assert(ret == 0);
printf("Generated salt: %s\n", salt);
before = clock();
ret = bcrypt_hashpw("testtesttest", salt, hash);
assert(ret == 0);
after = clock();
printf("Hashed password: %s\n", hash);
printf("Time taken: %f seconds\n",
(double)(after - before) / CLOCKS_PER_SEC);
ret = bcrypt_hashpw(pass, hash1, hash);
assert(ret == 0);
printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL");
ret = bcrypt_hashpw(pass, hash2, hash);
assert(ret == 0);
printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL");
before = clock();
ret = (bcrypt_checkpw(pass, hash1) == 0);
after = clock();
printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
printf("Time taken: %f seconds\n",
(double)(after - before) / CLOCKS_PER_SEC);
before = clock();
ret = (bcrypt_checkpw(pass, hash2) == 0);
after = clock();
printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
printf("Time taken: %f seconds\n",
(double)(after - before) / CLOCKS_PER_SEC);
return 0;
}
#endif

View File

@ -0,0 +1,911 @@
/*
* The crypt_blowfish homepage is:
*
* http://www.openwall.com/crypt/
*
* This code comes from John the Ripper password cracker, with reentrant
* and crypt(3) interfaces added, but optimizations specific to password
* cracking removed.
*
* Written by Solar Designer <solar at openwall.com> in 1998-2014.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* It is my intent that you should be able to use this on your system,
* as part of a software package, or anywhere else to improve security,
* ensure compatibility, or for any other purpose. I would appreciate
* it if you give credit where it is due and keep your modifications in
* the public domain as well, but I don't require that in order to let
* you place this code and any modifications you make under a license
* of your choice.
*
* This implementation is fully compatible with OpenBSD's bcrypt.c for prefix
* "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses
* some of his ideas. The password hashing algorithm was designed by David
* Mazieres <dm at lcs.mit.edu>. For information on the level of
* compatibility for bcrypt hash prefixes other than "$2b$", please refer to
* the comments in BF_set_key() below and to the included crypt(3) man page.
*
* There's a paper on the algorithm that explains its design decisions:
*
* http://www.usenix.org/events/usenix99/provos.html
*
* Some of the tricks in BF_ROUND might be inspired by Eric Young's
* Blowfish library (I can't be sure if I would think of something if I
* hadn't seen his code).
*/
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
/* Just to make sure the prototypes match the actual definitions */
#ifdef _WIN32 || _WIN64
#include "../include/bcrypt/crypt_blowfish.h"
#else
#include "crypt_blowfish.h"
#endif
#ifdef __i386__
#define BF_ASM 1
#define BF_SCALE 1
#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
#define BF_ASM 0
#define BF_SCALE 1
#else
#define BF_ASM 0
#define BF_SCALE 0
#endif
typedef unsigned int BF_word;
typedef signed int BF_word_signed;
/* Number of Blowfish rounds, this is also hardcoded into a few places */
#define BF_N 16
typedef BF_word BF_key[BF_N + 2];
typedef struct {
BF_word S[4][0x100];
BF_key P;
} BF_ctx;
/*
* Magic IV for 64 Blowfish encryptions that we do at the end.
* The string is "OrpheanBeholderScryDoubt" on big-endian.
*/
static BF_word BF_magic_w[6] = {
0x4F727068, 0x65616E42, 0x65686F6C,
0x64657253, 0x63727944, 0x6F756274
};
/*
* P-box and S-box tables initialized with digits of Pi.
*/
static BF_ctx BF_init_state = {
{
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
}, {
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
}, {
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
}, {
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
}
}, {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
}
};
static unsigned char BF_itoa64[64 + 1] =
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static unsigned char BF_atoi64[0x60] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
};
#define BF_safe_atoi64(dst, src) \
{ \
tmp = (unsigned char)(src); \
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
tmp = BF_atoi64[tmp]; \
if (tmp > 63) return -1; \
(dst) = tmp; \
}
static int BF_decode(BF_word *dst, const char *src, int size)
{
unsigned char *dptr = (unsigned char *)dst;
unsigned char *end = dptr + size;
const unsigned char *sptr = (const unsigned char *)src;
unsigned int tmp, c1, c2, c3, c4;
do {
BF_safe_atoi64(c1, *sptr++);
BF_safe_atoi64(c2, *sptr++);
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
if (dptr >= end) break;
BF_safe_atoi64(c3, *sptr++);
*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
if (dptr >= end) break;
BF_safe_atoi64(c4, *sptr++);
*dptr++ = ((c3 & 0x03) << 6) | c4;
} while (dptr < end);
return 0;
}
static void BF_encode(char *dst, const BF_word *src, int size)
{
const unsigned char *sptr = (const unsigned char *)src;
const unsigned char *end = sptr + size;
unsigned char *dptr = (unsigned char *)dst;
unsigned int c1, c2;
do {
c1 = *sptr++;
*dptr++ = BF_itoa64[c1 >> 2];
c1 = (c1 & 0x03) << 4;
if (sptr >= end) {
*dptr++ = BF_itoa64[c1];
break;
}
c2 = *sptr++;
c1 |= c2 >> 4;
*dptr++ = BF_itoa64[c1];
c1 = (c2 & 0x0f) << 2;
if (sptr >= end) {
*dptr++ = BF_itoa64[c1];
break;
}
c2 = *sptr++;
c1 |= c2 >> 6;
*dptr++ = BF_itoa64[c1];
*dptr++ = BF_itoa64[c2 & 0x3f];
} while (sptr < end);
}
static void BF_swap(BF_word *x, int count)
{
static int endianness_check = 1;
char *is_little_endian = (char *)&endianness_check;
BF_word tmp;
if (*is_little_endian)
do {
tmp = *x;
tmp = (tmp << 16) | (tmp >> 16);
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
} while (--count);
}
#if BF_SCALE
/* Architectures which can shift addresses left by 2 bits with no extra cost */
#define BF_ROUND(L, R, N) \
tmp1 = L & 0xFF; \
tmp2 = L >> 8; \
tmp2 &= 0xFF; \
tmp3 = L >> 16; \
tmp3 &= 0xFF; \
tmp4 = L >> 24; \
tmp1 = data.ctx.S[3][tmp1]; \
tmp2 = data.ctx.S[2][tmp2]; \
tmp3 = data.ctx.S[1][tmp3]; \
tmp3 += data.ctx.S[0][tmp4]; \
tmp3 ^= tmp2; \
R ^= data.ctx.P[N + 1]; \
tmp3 += tmp1; \
R ^= tmp3;
#else
/* Architectures with no complicated addressing modes supported */
#define BF_INDEX(S, i) \
(*((BF_word *)(((unsigned char *)S) + (i))))
#define BF_ROUND(L, R, N) \
tmp1 = L & 0xFF; \
tmp1 <<= 2; \
tmp2 = L >> 6; \
tmp2 &= 0x3FC; \
tmp3 = L >> 14; \
tmp3 &= 0x3FC; \
tmp4 = L >> 22; \
tmp4 &= 0x3FC; \
tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
tmp3 ^= tmp2; \
R ^= data.ctx.P[N + 1]; \
tmp3 += tmp1; \
R ^= tmp3;
#endif
/*
* Encrypt one block, BF_N is hardcoded here.
*/
#define BF_ENCRYPT \
L ^= data.ctx.P[0]; \
BF_ROUND(L, R, 0); \
BF_ROUND(R, L, 1); \
BF_ROUND(L, R, 2); \
BF_ROUND(R, L, 3); \
BF_ROUND(L, R, 4); \
BF_ROUND(R, L, 5); \
BF_ROUND(L, R, 6); \
BF_ROUND(R, L, 7); \
BF_ROUND(L, R, 8); \
BF_ROUND(R, L, 9); \
BF_ROUND(L, R, 10); \
BF_ROUND(R, L, 11); \
BF_ROUND(L, R, 12); \
BF_ROUND(R, L, 13); \
BF_ROUND(L, R, 14); \
BF_ROUND(R, L, 15); \
tmp4 = R; \
R = L; \
L = tmp4 ^ data.ctx.P[BF_N + 1];
#if BF_ASM
#define BF_body() \
_BF_body_r(&data.ctx);
#else
#define BF_body() \
L = R = 0; \
ptr = data.ctx.P; \
do { \
ptr += 2; \
BF_ENCRYPT; \
*(ptr - 2) = L; \
*(ptr - 1) = R; \
} while (ptr < &data.ctx.P[BF_N + 2]); \
\
ptr = data.ctx.S[0]; \
do { \
ptr += 2; \
BF_ENCRYPT; \
*(ptr - 2) = L; \
*(ptr - 1) = R; \
} while (ptr < &data.ctx.S[3][0xFF]);
#endif
static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
unsigned char flags)
{
const char *ptr = key;
unsigned int bug, i, j;
BF_word safety, sign, diff, tmp[2];
/*
* There was a sign extension bug in older revisions of this function. While
* we would have liked to simply fix the bug and move on, we have to provide
* a backwards compatibility feature (essentially the bug) for some systems and
* a safety measure for some others. The latter is needed because for certain
* multiple inputs to the buggy algorithm there exist easily found inputs to
* the correct algorithm that produce the same hash. Thus, we optionally
* deviate from the correct algorithm just enough to avoid such collisions.
* While the bug itself affected the majority of passwords containing
* characters with the 8th bit set (although only a percentage of those in a
* collision-producing way), the anti-collision safety measure affects
* only a subset of passwords containing the '\xff' character (not even all of
* those passwords, just some of them). This character is not found in valid
* UTF-8 sequences and is rarely used in popular 8-bit character encodings.
* Thus, the safety measure is unlikely to cause much annoyance, and is a
* reasonable tradeoff to use when authenticating against existing hashes that
* are not reliably known to have been computed with the correct algorithm.
*
* We use an approach that tries to minimize side-channel leaks of password
* information - that is, we mostly use fixed-cost bitwise operations instead
* of branches or table lookups. (One conditional branch based on password
* length remains. It is not part of the bug aftermath, though, and is
* difficult and possibly unreasonable to avoid given the use of C strings by
* the caller, which results in similar timing leaks anyway.)
*
* For actual implementation, we set an array index in the variable "bug"
* (0 means no bug, 1 means sign extension bug emulation) and a flag in the
* variable "safety" (bit 16 is set when the safety measure is requested).
* Valid combinations of settings are:
*
* Prefix "$2a$": bug = 0, safety = 0x10000
* Prefix "$2b$": bug = 0, safety = 0
* Prefix "$2x$": bug = 1, safety = 0
* Prefix "$2y$": bug = 0, safety = 0
*/
bug = (unsigned int)flags & 1;
safety = ((BF_word)flags & 2) << 15;
sign = diff = 0;
for (i = 0; i < BF_N + 2; i++) {
tmp[0] = tmp[1] = 0;
for (j = 0; j < 4; j++) {
tmp[0] <<= 8;
tmp[0] |= (unsigned char)*ptr; /* correct */
tmp[1] <<= 8;
tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
/*
* Sign extension in the first char has no effect - nothing to overwrite yet,
* and those extra 24 bits will be fully shifted out of the 32-bit word. For
* chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
* extension in tmp[1] occurs. Once this flag is set, it remains set.
*/
if (j)
sign |= tmp[1] & 0x80;
if (!*ptr)
ptr = key;
else
ptr++;
}
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
expanded[i] = tmp[bug];
initial[i] = BF_init_state.P[i] ^ tmp[bug];
}
/*
* At this point, "diff" is zero iff the correct and buggy algorithms produced
* exactly the same result. If so and if "sign" is non-zero, which indicates
* that there was a non-benign sign extension, this means that we have a
* collision between the correctly computed hash for this password and a set of
* passwords that could be supplied to the buggy algorithm. Our safety measure
* is meant to protect from such many-buggy to one-correct collisions, by
* deviating from the correct algorithm in such cases. Let's check for this.
*/
diff |= diff >> 16; /* still zero iff exact match */
diff &= 0xffff; /* ditto */
diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
sign &= ~diff & safety; /* action needed? */
/*
* If we have determined that we need to deviate from the correct algorithm,
* flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
* let's stick to it now. It came out of the approach we used above, and it's
* not any worse than any other choice we could make.)
*
* It is crucial that we don't do the same to the expanded key used in the main
* Eksblowfish loop. By doing it to only one of these two, we deviate from a
* state that could be directly specified by a password to the buggy algorithm
* (and to the fully correct one as well, but that's a side-effect).
*/
initial[0] ^= sign;
}
static const unsigned char flags_by_subtype[26] =
{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
static char *BF_crypt(const char *key, const char *setting,
char *output, int size,
BF_word min)
{
#if BF_ASM
extern void _BF_body_r(BF_ctx *ctx);
#endif
struct {
BF_ctx ctx;
BF_key expanded_key;
union {
BF_word salt[4];
BF_word output[6];
} binary;
} data;
BF_word L, R;
BF_word tmp1, tmp2, tmp3, tmp4;
BF_word *ptr;
BF_word count;
int i;
if (size < 7 + 22 + 31 + 1) {
__set_errno(ERANGE);
return NULL;
}
if (setting[0] != '$' ||
setting[1] != '2' ||
setting[2] < 'a' || setting[2] > 'z' ||
!flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
setting[3] != '$' ||
setting[4] < '0' || setting[4] > '3' ||
setting[5] < '0' || setting[5] > '9' ||
(setting[4] == '3' && setting[5] > '1') ||
setting[6] != '$') {
__set_errno(EINVAL);
return NULL;
}
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
__set_errno(EINVAL);
return NULL;
}
BF_swap(data.binary.salt, 4);
BF_set_key(key, data.expanded_key, data.ctx.P,
flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
L = R = 0;
for (i = 0; i < BF_N + 2; i += 2) {
L ^= data.binary.salt[i & 2];
R ^= data.binary.salt[(i & 2) + 1];
BF_ENCRYPT;
data.ctx.P[i] = L;
data.ctx.P[i + 1] = R;
}
ptr = data.ctx.S[0];
do {
ptr += 4;
L ^= data.binary.salt[(BF_N + 2) & 3];
R ^= data.binary.salt[(BF_N + 3) & 3];
BF_ENCRYPT;
*(ptr - 4) = L;
*(ptr - 3) = R;
L ^= data.binary.salt[(BF_N + 4) & 3];
R ^= data.binary.salt[(BF_N + 5) & 3];
BF_ENCRYPT;
*(ptr - 2) = L;
*(ptr - 1) = R;
} while (ptr < &data.ctx.S[3][0xFF]);
do {
int done;
for (i = 0; i < BF_N + 2; i += 2) {
data.ctx.P[i] ^= data.expanded_key[i];
data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
}
done = 0;
do {
BF_body();
if (done)
break;
done = 1;
tmp1 = data.binary.salt[0];
tmp2 = data.binary.salt[1];
tmp3 = data.binary.salt[2];
tmp4 = data.binary.salt[3];
for (i = 0; i < BF_N; i += 4) {
data.ctx.P[i] ^= tmp1;
data.ctx.P[i + 1] ^= tmp2;
data.ctx.P[i + 2] ^= tmp3;
data.ctx.P[i + 3] ^= tmp4;
}
data.ctx.P[16] ^= tmp1;
data.ctx.P[17] ^= tmp2;
} while (1);
} while (--count);
for (i = 0; i < 6; i += 2) {
L = BF_magic_w[i];
R = BF_magic_w[i + 1];
count = 64;
do {
BF_ENCRYPT;
} while (--count);
data.binary.output[i] = L;
data.binary.output[i + 1] = R;
}
memcpy(output, setting, 7 + 22 - 1);
output[7 + 22 - 1] = BF_itoa64[(int)
BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
/* This has to be bug-compatible with the original implementation, so
* only encode 23 of the 24 bytes. :-) */
BF_swap(data.binary.output, 6);
BF_encode(&output[7 + 22], data.binary.output, 23);
output[7 + 22 + 31] = '\0';
return output;
}
int _crypt_output_magic(const char *setting, char *output, int size)
{
if (size < 3)
return -1;
output[0] = '*';
output[1] = '0';
output[2] = '\0';
if (setting[0] == '*' && setting[1] == '0')
output[1] = '1';
return 0;
}
/*
* Please preserve the runtime self-test. It serves two purposes at once:
*
* 1. We really can't afford the risk of producing incompatible hashes e.g.
* when there's something like gcc bug 26587 again, whereas an application or
* library integrating this code might not also integrate our external tests or
* it might not run them after every build. Even if it does, the miscompile
* might only occur on the production build, but not on a testing build (such
* as because of different optimization settings). It is painful to recover
* from incorrectly-computed hashes - merely fixing whatever broke is not
* enough. Thus, a proactive measure like this self-test is needed.
*
* 2. We don't want to leave sensitive data from our actual password hash
* computation on the stack or in registers. Previous revisions of the code
* would do explicit cleanups, but simply running the self-test after hash
* computation is more reliable.
*
* The performance cost of this quick self-test is around 0.6% at the "$2a$08"
* setting.
*/
char *_crypt_blowfish_rn(const char *key, const char *setting,
char *output, int size)
{
const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
static const char * const test_hashes[2] =
{"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */
"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */
const char *test_hash = test_hashes[0];
char *retval;
const char *p;
int save_errno, ok;
struct {
char s[7 + 22 + 1];
char o[7 + 22 + 31 + 1 + 1 + 1];
} buf;
/* Hash the supplied password */
_crypt_output_magic(setting, output, size);
retval = BF_crypt(key, setting, output, size, 16);
save_errno = errno;
/*
* Do a quick self-test. It is important that we make both calls to BF_crypt()
* from the same scope such that they likely use the same stack locations,
* which makes the second call overwrite the first call's sensitive data on the
* stack and makes it more likely that any alignment related issues would be
* detected by the self-test.
*/
memcpy(buf.s, test_setting, sizeof(buf.s));
if (retval) {
unsigned int flags = flags_by_subtype[
(unsigned int)(unsigned char)setting[2] - 'a'];
test_hash = test_hashes[flags & 1];
buf.s[2] = setting[2];
}
memset(buf.o, 0x55, sizeof(buf.o));
buf.o[sizeof(buf.o) - 1] = 0;
p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
ok = (p == buf.o &&
!memcmp(p, buf.s, 7 + 22) &&
!memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1));
{
const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
BF_key ae, ai, ye, yi;
BF_set_key(k, ae, ai, 2); /* $2a$ */
BF_set_key(k, ye, yi, 4); /* $2y$ */
ai[0] ^= 0x10000; /* undo the safety (for comparison) */
ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
!memcmp(ae, ye, sizeof(ae)) &&
!memcmp(ai, yi, sizeof(ai));
}
__set_errno(save_errno);
if (ok)
return retval;
/* Should not happen */
_crypt_output_magic(setting, output, size);
__set_errno(EINVAL); /* pretend we don't support this hash type */
return NULL;
}
char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
if (size < 16 || output_size < 7 + 22 + 1 ||
(count && (count < 4 || count > 31)) ||
prefix[0] != '$' || prefix[1] != '2' ||
(prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
return NULL;
}
if (!count) count = 5;
output[0] = '$';
output[1] = '2';
output[2] = prefix[2];
output[3] = '$';
output[4] = '0' + count / 10;
output[5] = '0' + count % 10;
output[6] = '$';
BF_encode(&output[7], (const BF_word *)input, 16);
output[7 + 22] = '\0';
return output;
}

View File

@ -0,0 +1,128 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*
* This file contains salt generation functions for the traditional and
* other common crypt(3) algorithms, except for bcrypt which is defined
* entirely in crypt_blowfish.c.
*/
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
/* Just to make sure the prototypes match the actual definitions */
#ifdef _WIN32
#include "../include/bcrypt/crypt_gensalt.h"
#else
#include "crypt_gensalt.h"
#endif
unsigned char _crypt_itoa64[64 + 1] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
(void) prefix;
if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
return NULL;
}
output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
output[2] = '\0';
return output;
}
char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
unsigned long value;
(void) prefix;
/* Even iteration counts make it easier to detect weak DES keys from a look
* at the hash, so they should be avoided */
if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
(count && (count > 0xffffff || !(count & 1)))) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
return NULL;
}
if (!count) count = 725;
output[0] = '_';
output[1] = _crypt_itoa64[count & 0x3f];
output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
value = (unsigned long)(unsigned char)input[0] |
((unsigned long)(unsigned char)input[1] << 8) |
((unsigned long)(unsigned char)input[2] << 16);
output[5] = _crypt_itoa64[value & 0x3f];
output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
output[9] = '\0';
return output;
}
char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
unsigned long value;
(void) prefix;
if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
return NULL;
}
output[0] = '$';
output[1] = '1';
output[2] = '$';
value = (unsigned long)(unsigned char)input[0] |
((unsigned long)(unsigned char)input[1] << 8) |
((unsigned long)(unsigned char)input[2] << 16);
output[3] = _crypt_itoa64[value & 0x3f];
output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
output[7] = '\0';
if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
value = (unsigned long)(unsigned char)input[3] |
((unsigned long)(unsigned char)input[4] << 8) |
((unsigned long)(unsigned char)input[5] << 16);
output[7] = _crypt_itoa64[value & 0x3f];
output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
output[11] = '\0';
}
return output;
}

View File

@ -0,0 +1,19 @@
#include "bcrypt/BCrypt.hpp"
#include <iostream>
int main(){
std::string right_password = "right_password";
std::string wrong_password = "wrong_password";
std::cout << "generate hash... " << std::flush;
std::string hash = BCrypt::generateHash(right_password, 12);
std::cout << "done." << std::endl;
std::cout << "checking right password: " << std::flush
<< BCrypt::validatePassword(right_password,hash) << std::endl;
std::cout << "checking wrong password: " << std::flush
<< BCrypt::validatePassword(wrong_password,hash) << std::endl;
return 0;
}

563
src/libbcrypt/src/wrapper.c Normal file
View File

@ -0,0 +1,563 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2014.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
#ifdef TEST
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#ifdef TEST_THREADS
#include <pthread.h>
#endif
#endif
#define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1)
#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
#if defined(__GLIBC__) && defined(_LIBC)
#define __SKIP_GNU
#endif
#ifdef _WIN32 | _WIN64
#include "../include/bcrypt/ow-crypt.h"
#include "../include/bcrypt/crypt_blowfish.h"
#include "../include/bcrypt/crypt_gensalt.h"
#else
#include "ow-crypt.h"
#include "crypt_blowfish.h"
#include "crypt_gensalt.h"
#endif
#if defined(__GLIBC__) && defined(_LIBC)
/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
#include "crypt.h"
extern char *__md5_crypt_r(const char *key, const char *salt,
char *buffer, int buflen);
/* crypt-entry.c needs to be patched to define __des_crypt_r rather than
* __crypt_r, and not define crypt_r and crypt at all */
extern char *__des_crypt_r(const char *key, const char *salt,
struct crypt_data *data);
extern struct crypt_data _ufc_foobar;
#endif
static int _crypt_data_alloc(void **data, int *size, int need)
{
void *updated;
if (*data && *size >= need) return 0;
updated = realloc(*data, need);
if (!updated) {
#ifndef __GLIBC__
/* realloc(3) on glibc sets errno, so we don't need to bother */
__set_errno(ENOMEM);
#endif
return -1;
}
#if defined(__GLIBC__) && defined(_LIBC)
if (need >= sizeof(struct crypt_data))
((struct crypt_data *)updated)->initialized = 0;
#endif
*data = updated;
*size = need;
return 0;
}
static char *_crypt_retval_magic(char *retval, const char *setting,
char *output, int size)
{
if (retval)
return retval;
if (_crypt_output_magic(setting, output, size))
return NULL; /* shouldn't happen */
return output;
}
#if defined(__GLIBC__) && defined(_LIBC)
/*
* Applications may re-use the same instance of struct crypt_data without
* resetting the initialized field in order to let crypt_r() skip some of
* its initialization code. Thus, it is important that our multiple hashing
* algorithms either don't conflict with each other in their use of the
* data area or reset the initialized field themselves whenever required.
* Currently, the hashing algorithms simply have no conflicts: the first
* field of struct crypt_data is the 128-byte large DES key schedule which
* __des_crypt_r() calculates each time it is called while the two other
* hashing algorithms use less than 128 bytes of the data area.
*/
char *__crypt_rn(__const char *key, __const char *setting,
void *data, int size)
{
if (setting[0] == '$' && setting[1] == '2')
return _crypt_blowfish_rn(key, setting, (char *)data, size);
if (setting[0] == '$' && setting[1] == '1')
return __md5_crypt_r(key, setting, (char *)data, size);
if (setting[0] == '$' || setting[0] == '_') {
__set_errno(EINVAL);
return NULL;
}
if (size >= sizeof(struct crypt_data))
return __des_crypt_r(key, setting, (struct crypt_data *)data);
__set_errno(ERANGE);
return NULL;
}
char *__crypt_ra(__const char *key, __const char *setting,
void **data, int *size)
{
if (setting[0] == '$' && setting[1] == '2') {
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
return NULL;
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
}
if (setting[0] == '$' && setting[1] == '1') {
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
return NULL;
return __md5_crypt_r(key, setting, (char *)*data, *size);
}
if (setting[0] == '$' || setting[0] == '_') {
__set_errno(EINVAL);
return NULL;
}
if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
return NULL;
return __des_crypt_r(key, setting, (struct crypt_data *)*data);
}
char *__crypt_r(__const char *key, __const char *setting,
struct crypt_data *data)
{
return _crypt_retval_magic(
__crypt_rn(key, setting, data, sizeof(*data)),
setting, (char *)data, sizeof(*data));
}
char *__crypt(__const char *key, __const char *setting)
{
return _crypt_retval_magic(
__crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar));
}
#else
char *crypt_rn(const char *key, const char *setting, void *data, int size)
{
return _crypt_blowfish_rn(key, setting, (char *)data, size);
}
char *crypt_ra(const char *key, const char *setting,
void **data, int *size)
{
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
return NULL;
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
}
char *crypt_r(const char *key, const char *setting, void *data)
{
return _crypt_retval_magic(
crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
setting, (char *)data, CRYPT_OUTPUT_SIZE);
}
char *crypt(const char *key, const char *setting)
{
static char output[CRYPT_OUTPUT_SIZE];
return _crypt_retval_magic(
crypt_rn(key, setting, output, sizeof(output)),
setting, output, sizeof(output));
}
#define __crypt_gensalt_rn crypt_gensalt_rn
#define __crypt_gensalt_ra crypt_gensalt_ra
#define __crypt_gensalt crypt_gensalt
#endif
char *__crypt_gensalt_rn(const char *prefix, unsigned long count,
const char *input, int size, char *output, int output_size)
{
char *(*use)(const char *_prefix, unsigned long _count,
const char *_input, int _size,
char *_output, int _output_size);
/* This may be supported on some platforms in the future */
if (!input) {
__set_errno(EINVAL);
return NULL;
}
if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
!strncmp(prefix, "$2y$", 4))
use = _crypt_gensalt_blowfish_rn;
else
if (!strncmp(prefix, "$1$", 3))
use = _crypt_gensalt_md5_rn;
else
if (prefix[0] == '_')
use = _crypt_gensalt_extended_rn;
else
if (!prefix[0] ||
(prefix[0] && prefix[1] &&
memchr(_crypt_itoa64, prefix[0], 64) &&
memchr(_crypt_itoa64, prefix[1], 64)))
use = _crypt_gensalt_traditional_rn;
else {
__set_errno(EINVAL);
return NULL;
}
return use(prefix, count, input, size, output, output_size);
}
char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
const char *input, int size)
{
char output[CRYPT_GENSALT_OUTPUT_SIZE];
char *retval;
retval = __crypt_gensalt_rn(prefix, count,
input, size, output, sizeof(output));
if (retval) {
#ifdef _WIN32 | _WIN64
retval = _strdup(retval);
#else
retval = strdup(retval);
#endif
#ifndef __GLIBC__
/* strdup(3) on glibc sets errno, so we don't need to bother */
if (!retval)
__set_errno(ENOMEM);
#endif
}
return retval;
}
char *__crypt_gensalt(const char *prefix, unsigned long count,
const char *input, int size)
{
static char output[CRYPT_GENSALT_OUTPUT_SIZE];
return __crypt_gensalt_rn(prefix, count,
input, size, output, sizeof(output));
}
#if defined(__GLIBC__) && defined(_LIBC)
weak_alias(__crypt_rn, crypt_rn)
weak_alias(__crypt_ra, crypt_ra)
weak_alias(__crypt_r, crypt_r)
weak_alias(__crypt, crypt)
weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn)
weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra)
weak_alias(__crypt_gensalt, crypt_gensalt)
weak_alias(crypt, fcrypt)
#endif
#ifdef TEST
static const char *tests[][3] = {
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
"U*U"},
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
"U*U*"},
{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
"U*U*U"},
{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
"0123456789abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"chars after 72 are ignored"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xa3"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xff\xff\xa3"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xff\xff\xa3"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
"\xff\xff\xa3"},
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
"\xff\xff\xa3"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
"\xa3"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
"\xa3"},
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
"\xa3"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"1\xa3" "345"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"\xff\xa3" "345"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
"\xff\xa3" "345"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
"\xff\xa3" "345"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
"\xa3" "ab"},
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
"\xa3" "ab"},
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
"\xa3" "ab"},
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
"\xd1\x91"},
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
"\xd0\xc1\xd2\xcf\xcc\xd8"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
"chars after 72 are ignored as usual"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
""},
{"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
{"*1", "", "*0"},
{NULL}
};
#define which tests[0]
static volatile sig_atomic_t running;
static void handle_timer(int signum)
{
(void) signum;
running = 0;
}
static void *run(void *arg)
{
unsigned long count = 0;
int i = 0;
void *data = NULL;
int size = 0x12345678;
do {
const char *hash = tests[i][0];
const char *key = tests[i][1];
const char *setting = tests[i][2];
if (!tests[++i][0])
i = 0;
if (setting && strlen(hash) < 30) /* not for benchmark */
continue;
if (strcmp(crypt_ra(key, hash, &data, &size), hash)) {
printf("%d: FAILED (crypt_ra/%d/%lu)\n",
(int)((char *)arg - (char *)0), i, count);
free(data);
return NULL;
}
count++;
} while (running);
free(data);
return count + (char *)0;
}
int main(void)
{
struct itimerval it;
struct tms buf;
clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
unsigned long count;
void *data;
int size;
char *setting1, *setting2;
int i;
#ifdef TEST_THREADS
pthread_t t[TEST_THREADS];
void *t_retval;
#endif
data = NULL;
size = 0x12345678;
for (i = 0; tests[i][0]; i++) {
const char *hash = tests[i][0];
const char *key = tests[i][1];
const char *setting = tests[i][2];
const char *p;
int ok = !setting || strlen(hash) >= 30;
int o_size;
char s_buf[30], o_buf[61];
if (!setting) {
memcpy(s_buf, hash, sizeof(s_buf) - 1);
s_buf[sizeof(s_buf) - 1] = 0;
setting = s_buf;
}
__set_errno(0);
p = crypt(key, setting);
if ((!ok && !errno) || strcmp(p, hash)) {
printf("FAILED (crypt/%d)\n", i);
return 1;
}
if (ok && strcmp(crypt(key, hash), hash)) {
printf("FAILED (crypt/%d)\n", i);
return 1;
}
for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
int ok_n = ok && o_size == (int)sizeof(o_buf);
const char *x = "abc";
strcpy(o_buf, x);
if (o_size >= 3) {
x = "*0";
if (setting[0] == '*' && setting[1] == '0')
x = "*1";
}
__set_errno(0);
p = crypt_rn(key, setting, o_buf, o_size);
if ((ok_n && (!p || strcmp(p, hash))) ||
(!ok_n && (!errno || p || strcmp(o_buf, x)))) {
printf("FAILED (crypt_rn/%d)\n", i);
return 1;
}
}
__set_errno(0);
p = crypt_ra(key, setting, &data, &size);
if ((ok && (!p || strcmp(p, hash))) ||
(!ok && (!errno || p || strcmp((char *)data, hash)))) {
printf("FAILED (crypt_ra/%d)\n", i);
return 1;
}
}
setting1 = crypt_gensalt(which[0], 12, data, size);
if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
puts("FAILED (crypt_gensalt)\n");
return 1;
}
setting2 = crypt_gensalt_ra(setting1, 12, data, size);
if (strcmp(setting1, setting2)) {
puts("FAILED (crypt_gensalt_ra/1)\n");
return 1;
}
(*(char *)data)++;
setting1 = crypt_gensalt_ra(setting2, 12, data, size);
if (!strcmp(setting1, setting2)) {
puts("FAILED (crypt_gensalt_ra/2)\n");
return 1;
}
free(setting1);
free(setting2);
free(data);
#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
clk_tck = sysconf(_SC_CLK_TCK);
#else
clk_tck = CLK_TCK;
#endif
running = 1;
signal(SIGALRM, handle_timer);
memset(&it, 0, sizeof(it));
it.it_value.tv_sec = 5;
setitimer(ITIMER_REAL, &it, NULL);
start_real = times(&buf);
start_virtual = buf.tms_utime + buf.tms_stime;
count = (char *)run((char *)0) - (char *)0;
end_real = times(&buf);
end_virtual = buf.tms_utime + buf.tms_stime;
if (end_virtual == start_virtual) end_virtual++;
printf("%.1f c/s real, %.1f c/s virtual\n",
(float)count * clk_tck / (end_real - start_real),
(float)count * clk_tck / (end_virtual - start_virtual));
#ifdef TEST_THREADS
running = 1;
it.it_value.tv_sec = 60;
setitimer(ITIMER_REAL, &it, NULL);
start_real = times(&buf);
for (i = 0; i < TEST_THREADS; i++)
if (pthread_create(&t[i], NULL, run, i + (char *)0)) {
perror("pthread_create");
return 1;
}
for (i = 0; i < TEST_THREADS; i++) {
if (pthread_join(t[i], &t_retval)) {
perror("pthread_join");
continue;
}
if (!t_retval) continue;
count = (char *)t_retval - (char *)0;
end_real = times(&buf);
printf("%d: %.1f c/s real\n", i,
(float)count * clk_tck / (end_real - start_real));
}
#endif
return 0;
}
#endif

202
src/libbcrypt/src/x86.S Normal file
View File

@ -0,0 +1,202 @@
/*
* Written by Solar Designer <solar at openwall.com> in 1998-2010.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 1998-2010 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifdef __i386__
#if defined(__OpenBSD__) && !defined(__ELF__)
#define UNDERSCORES
#define ALIGN_LOG
#endif
#if defined(__CYGWIN32__) || defined(__MINGW32__)
#define UNDERSCORES
#endif
#ifdef __DJGPP__
#define UNDERSCORES
#define ALIGN_LOG
#endif
#ifdef UNDERSCORES
#define _BF_body_r __BF_body_r
#endif
#ifdef ALIGN_LOG
#define DO_ALIGN(log) .align (log)
#elif defined(DUMBAS)
#define DO_ALIGN(log) .align 1 << log
#else
#define DO_ALIGN(log) .align (1 << (log))
#endif
#define BF_FRAME 0x200
#define ctx %esp
#define BF_ptr (ctx)
#define S(N, r) N+BF_FRAME(ctx,r,4)
#ifdef DUMBAS
#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx)
#else
#define P(N) 0x1000+4*N+BF_FRAME(ctx)
#endif
/*
* This version of the assembly code is optimized primarily for the original
* Intel Pentium but is also careful to avoid partial register stalls on the
* Pentium Pro family of processors (tested up to Pentium III Coppermine).
*
* It is possible to do 15% faster on the Pentium Pro family and probably on
* many non-Intel x86 processors, but, unfortunately, that would make things
* twice slower for the original Pentium.
*
* An additional 2% speedup may be achieved with non-reentrant code.
*/
#define L %esi
#define R %edi
#define tmp1 %eax
#define tmp1_lo %al
#define tmp2 %ecx
#define tmp2_hi %ch
#define tmp3 %edx
#define tmp3_lo %dl
#define tmp4 %ebx
#define tmp4_hi %bh
#define tmp5 %ebp
.text
#define BF_ROUND(L, R, N) \
xorl L,tmp2; \
xorl tmp1,tmp1; \
movl tmp2,L; \
shrl $16,tmp2; \
movl L,tmp4; \
movb tmp2_hi,tmp1_lo; \
andl $0xFF,tmp2; \
movb tmp4_hi,tmp3_lo; \
andl $0xFF,tmp4; \
movl S(0,tmp1),tmp1; \
movl S(0x400,tmp2),tmp5; \
addl tmp5,tmp1; \
movl S(0x800,tmp3),tmp5; \
xorl tmp5,tmp1; \
movl S(0xC00,tmp4),tmp5; \
addl tmp1,tmp5; \
movl 4+P(N),tmp2; \
xorl tmp5,R
#define BF_ENCRYPT_START \
BF_ROUND(L, R, 0); \
BF_ROUND(R, L, 1); \
BF_ROUND(L, R, 2); \
BF_ROUND(R, L, 3); \
BF_ROUND(L, R, 4); \
BF_ROUND(R, L, 5); \
BF_ROUND(L, R, 6); \
BF_ROUND(R, L, 7); \
BF_ROUND(L, R, 8); \
BF_ROUND(R, L, 9); \
BF_ROUND(L, R, 10); \
BF_ROUND(R, L, 11); \
BF_ROUND(L, R, 12); \
BF_ROUND(R, L, 13); \
BF_ROUND(L, R, 14); \
BF_ROUND(R, L, 15); \
movl BF_ptr,tmp5; \
xorl L,tmp2; \
movl P(17),L
#define BF_ENCRYPT_END \
xorl R,L; \
movl tmp2,R
DO_ALIGN(5)
.globl _BF_body_r
_BF_body_r:
movl 4(%esp),%eax
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
subl $BF_FRAME-8,%eax
xorl L,L
cmpl %esp,%eax
ja BF_die
xchgl %eax,%esp
xorl R,R
pushl %eax
leal 0x1000+BF_FRAME-4(ctx),%eax
movl 0x1000+BF_FRAME-4(ctx),tmp2
pushl %eax
xorl tmp3,tmp3
BF_loop_P:
BF_ENCRYPT_START
addl $8,tmp5
BF_ENCRYPT_END
leal 0x1000+18*4+BF_FRAME(ctx),tmp1
movl tmp5,BF_ptr
cmpl tmp5,tmp1
movl L,-8(tmp5)
movl R,-4(tmp5)
movl P(0),tmp2
ja BF_loop_P
leal BF_FRAME(ctx),tmp5
xorl tmp3,tmp3
movl tmp5,BF_ptr
BF_loop_S:
BF_ENCRYPT_START
BF_ENCRYPT_END
movl P(0),tmp2
movl L,(tmp5)
movl R,4(tmp5)
BF_ENCRYPT_START
BF_ENCRYPT_END
movl P(0),tmp2
movl L,8(tmp5)
movl R,12(tmp5)
BF_ENCRYPT_START
BF_ENCRYPT_END
movl P(0),tmp2
movl L,16(tmp5)
movl R,20(tmp5)
BF_ENCRYPT_START
addl $32,tmp5
BF_ENCRYPT_END
leal 0x1000+BF_FRAME(ctx),tmp1
movl tmp5,BF_ptr
cmpl tmp5,tmp1
movl P(0),tmp2
movl L,-8(tmp5)
movl R,-4(tmp5)
ja BF_loop_S
movl 4(%esp),%esp
popl %edi
popl %esi
popl %ebx
popl %ebp
ret
BF_die:
/* Oops, need to re-compile with a larger BF_FRAME. */
hlt
jmp BF_die
#if defined(__ELF__) && defined(__linux__)
.section .note.GNU-stack,"",@progbits
#endif
#endif

View File

@ -0,0 +1,41 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.136
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbcrypt", "libbcrypt.vcxproj", "{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "..\test\test.vcxproj", "{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x64.ActiveCfg = Debug|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x64.Build.0 = Debug|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x86.ActiveCfg = Debug|Win32
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Debug|x86.Build.0 = Debug|Win32
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x64.ActiveCfg = Release|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x64.Build.0 = Release|x64
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x86.ActiveCfg = Release|Win32
{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}.Release|x86.Build.0 = Release|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x64.ActiveCfg = Debug|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x64.Build.0 = Debug|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x86.ActiveCfg = Debug|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Debug|x86.Build.0 = Debug|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x64.ActiveCfg = Release|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x64.Build.0 = Release|x64
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x86.ActiveCfg = Release|Win32
{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2DB786F9-9679-4A72-A4A0-2544E42B78CB}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D6A9A3F3-1312-4494-85B8-7CE7DD4D78F4}</ProjectGuid>
<RootNamespace>libbcrypt</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bcrypt.c" />
<ClCompile Include="..\..\src\crypt_blowfish.c" />
<ClCompile Include="..\..\src\crypt_gensalt.c" />
<ClCompile Include="..\..\src\wrapper.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\bcrypt\bcrypt.h" />
<ClInclude Include="..\..\include\bcrypt\BCrypt.hpp" />
<ClInclude Include="..\..\include\bcrypt\crypt.h" />
<ClInclude Include="..\..\include\bcrypt\crypt_blowfish.h" />
<ClInclude Include="..\..\include\bcrypt\crypt_gensalt.h" />
<ClInclude Include="..\..\include\bcrypt\ow-crypt.h" />
<ClInclude Include="..\..\include\bcrypt\winbcrypt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bcrypt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\crypt_blowfish.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\crypt_gensalt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\src\wrapper.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\bcrypt\BCrypt.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\winbcrypt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\bcrypt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\crypt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\crypt_blowfish.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\crypt_gensalt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\bcrypt\ow-crypt.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
#include "../../include/bcrypt/BCrypt.hpp"
#include <iostream>
using namespace std;
int main() {
string right_password = "right_password";
string wrong_password = "wrong_password";
cout << "generate hash... " << flush;
string hash = BCrypt::generateHash(right_password, 12);
cout << "done." << endl;
cout << "checking right password: " << flush
<< BCrypt::validatePassword(right_password, hash) << endl;
cout << "checking wrong password: " << flush
<< BCrypt::validatePassword(wrong_password, hash) << endl;
system("pause");
return 0;
}

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\libbcrypt\libbcrypt.vcxproj">
<Project>{d6a9a3f3-1312-4494-85b8-7ce7dd4d78f4}</Project>
</ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{C6B1CF6E-88DF-4109-9EF4-06CBA5BD5B68}</ProjectGuid>
<RootNamespace>test</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<AdditionalDependencies>../libbcrypt/Debug/libbcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -4,6 +4,7 @@
#include "jwt.h" #include "jwt.h"
#include <algorithm> #include <algorithm>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <string.h>
// returns username if valid, "" if not // returns username if valid, "" if not
@ -66,14 +67,14 @@ std::pair <std::string, unsigned int> verifyToken(std::string jwt_token_str, std
bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) { bool verifyPassword(const char *username, const char *input_password, const char *db_password_hash) {
bool password_correct = false; bool password_correct = false;
if (strlen(db_password_hash ) < 4) { if ( strlen(db_password_hash) < 4 ) {
// actually, shoud be more, but this is min. for next code // actually, shoud be more, but this is min. for next code
Error ("DB Password is too short or invalid to check"); Error("DB Password is too short or invalid to check");
return false; return false;
} }
if (db_password_hash[0] == '*') { if ( db_password_hash[0] == '*' ) {
// MYSQL PASSWORD // MYSQL PASSWORD
Debug (1,"%s is using an MD5 encoded password", username); Debug(1, "%s is using an MD5 encoded password", username);
SHA_CTX ctx1, ctx2; SHA_CTX ctx1, ctx2;
unsigned char digest_interim[SHA_DIGEST_LENGTH]; unsigned char digest_interim[SHA_DIGEST_LENGTH];
@ -90,28 +91,33 @@ bool verifyPassword(const char *username, const char *input_password, const char
SHA1_Final (digest_final, &ctx2); SHA1_Final (digest_final, &ctx2);
char final_hash[SHA_DIGEST_LENGTH * 2 +2]; char final_hash[SHA_DIGEST_LENGTH * 2 +2];
final_hash[0]='*'; final_hash[0] = '*';
//convert to hex //convert to hex
for(int i = 0; i < SHA_DIGEST_LENGTH; i++) for ( int i = 0; i < SHA_DIGEST_LENGTH; i++ )
sprintf(&final_hash[i*2]+1, "%02X", (unsigned int)digest_final[i]); sprintf(&final_hash[i*2]+1, "%02X", (unsigned int)digest_final[i]);
final_hash[SHA_DIGEST_LENGTH *2 + 1]=0; final_hash[SHA_DIGEST_LENGTH *2 + 1] = 0;
Debug (1,"Computed password_hash:%s, stored password_hash:%s", final_hash, db_password_hash); Debug(1, "Computed password_hash:%s, stored password_hash:%s", final_hash, db_password_hash);
Debug (5, "Computed password_hash:%s, stored password_hash:%s", final_hash, db_password_hash);
password_correct = (strcmp(db_password_hash, final_hash)==0); password_correct = (strcmp(db_password_hash, final_hash)==0);
} } else if (
else if ((db_password_hash[0] == '$') && (db_password_hash[1]== '2') (db_password_hash[0] == '$')
&&(db_password_hash[3] == '$')) { &&
(db_password_hash[1]== '2')
&&
(db_password_hash[3] == '$')
) {
// BCRYPT // BCRYPT
Debug (1,"%s is using a bcrypt encoded password", username); Debug(1, "%s is using a bcrypt encoded password", username);
BCrypt bcrypt; BCrypt bcrypt;
std::string input_hash = bcrypt.generateHash(std::string(input_password)); std::string input_hash = bcrypt.generateHash(std::string(input_password));
password_correct = bcrypt.validatePassword(std::string(input_password), std::string(db_password_hash)); password_correct = bcrypt.validatePassword(std::string(input_password), std::string(db_password_hash));
} } else if (strncmp(db_password_hash, "-ZM-",4) == 0 ) {
else { Error("Authentication failed - migration of password not complete. Please log into web console for this user and retry this operation");
// plain return false;
Warning ("%s is using a plain text password, please do not use plain text", username); } else {
Warning ("%s is using a plain text (not recommended) or scheme not understood", username);
password_correct = (strcmp(input_password, db_password_hash) == 0); password_correct = (strcmp(input_password, db_password_hash) == 0);
} }
return password_correct; return password_correct;
} }

View File

@ -87,7 +87,7 @@ Event::Event(
char sql[ZM_SQL_MED_BUFSIZ]; char sql[ZM_SQL_MED_BUFSIZ];
struct tm *stime = localtime(&start_time.tv_sec); struct tm *stime = localtime(&start_time.tv_sec);
snprintf( sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )", snprintf(sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d, '%s' )",
monitor->Id(), monitor->Id(),
storage->Id(), storage->Id(),
start_time.tv_sec, start_time.tv_sec,
@ -247,6 +247,7 @@ Event::~Event() {
Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec); Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec);
if ( frames > last_db_frame ) { if ( frames > last_db_frame ) {
frames ++;
Debug(1, "Adding closing frame %d to DB", frames); Debug(1, "Adding closing frame %d to DB", frames);
frame_data.push(new Frame(id, frames, NORMAL, end_time, delta_time, 0)); frame_data.push(new Frame(id, frames, NORMAL, end_time, delta_time, 0));
} }
@ -484,7 +485,8 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
} }
int sql_len = strlen(sql); int sql_len = strlen(sql);
snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec); snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ",
id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec);
frameCount++; frameCount++;
} // end foreach frame } // end foreach frame
@ -493,7 +495,7 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
Debug(1, "Adding %d/%d frames to DB", frameCount, n_frames); Debug(1, "Adding %d/%d frames to DB", frameCount, n_frames);
*(sql+strlen(sql)-2) = '\0'; *(sql+strlen(sql)-2) = '\0';
db_mutex.lock(); db_mutex.lock();
if ( mysql_query( &dbconn, sql ) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), sql); Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), sql);
} }
db_mutex.unlock(); db_mutex.unlock();
@ -541,6 +543,8 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
bool write_to_db = false; bool write_to_db = false;
if ( monitor->GetOptSaveJPEGs() & 1 ) { if ( monitor->GetOptSaveJPEGs() & 1 ) {
if ( frames == 1 )
write_to_db = true; // web ui might show this as thumbnail, so db needs to know about it.
static char event_file[PATH_MAX]; static char event_file[PATH_MAX];
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
Debug(1, "Writing capture frame %d to %s", frames, event_file); Debug(1, "Writing capture frame %d to %s", frames, event_file);
@ -572,21 +576,21 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
if ( score < 0 ) if ( score < 0 )
score = 0; score = 0;
bool db_frame = ( frame_type != BULK ) || (!frames) || ((frames%config.bulk_frame_interval)==0) ; bool db_frame = ( frame_type != BULK ) || (frames==1) || ((frames%config.bulk_frame_interval)==0) ;
if ( db_frame ) { if ( db_frame ) {
static char sql[ZM_SQL_MED_BUFSIZ]; static char sql[ZM_SQL_MED_BUFSIZ];
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
if ( write_to_db || ( frame_data.size() > 20 ) ) { if ( write_to_db || ( frame_data.size() > 20 ) ) {
Debug(1, "Adding %d frames to DB", frame_data.size());
WriteDbFrames(); WriteDbFrames();
Debug(1, "Adding 20 frames to DB");
last_db_frame = frames; last_db_frame = frames;
} }
// We are writing a Bulk frame // We are writing a Bulk frame
if ( frame_type == BULK ) { if ( frame_type == BULK ) {
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %" PRIu64, "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
( delta_time.positive?"":"-" ), ( delta_time.positive?"":"-" ),
delta_time.sec, delta_time.fsec, delta_time.sec, delta_time.fsec,
frames, frames,

View File

@ -458,9 +458,9 @@ int FfmpegCamera::OpenFfmpeg() {
} }
} // end foreach stream } // end foreach stream
if ( mVideoStreamId == -1 ) if ( mVideoStreamId == -1 )
Fatal( "Unable to locate video stream in %s", mPath.c_str() ); Fatal("Unable to locate video stream in %s", mPath.c_str());
if ( mAudioStreamId == -1 ) if ( mAudioStreamId == -1 )
Debug( 3, "Unable to locate audio stream in %s", mPath.c_str() ); Debug(3, "Unable to locate audio stream in %s", mPath.c_str());
Debug(3, "Found video stream at index %d", mVideoStreamId); Debug(3, "Found video stream at index %d", mVideoStreamId);
Debug(3, "Found audio stream at index %d", mAudioStreamId); Debug(3, "Found audio stream at index %d", mAudioStreamId);
@ -758,6 +758,9 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
int keyframe = packet.flags & AV_PKT_FLAG_KEY; int keyframe = packet.flags & AV_PKT_FLAG_KEY;
bytes += packet.size; bytes += packet.size;
dumpPacket(mFormatContext->streams[packet.stream_index], &packet, "Captured Packet"); dumpPacket(mFormatContext->streams[packet.stream_index], &packet, "Captured Packet");
if ( packet.dts == AV_NOPTS_VALUE ) {
packet.dts = packet.pts;
}
// Video recording // Video recording
if ( recording.tv_sec ) { if ( recording.tv_sec ) {
@ -793,6 +796,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
if ( last_event_id and !videoStore ) { if ( last_event_id and !videoStore ) {
//Instantiate the video storage module //Instantiate the video storage module
packetqueue->dumpQueue();
if ( record_audio ) { if ( record_audio ) {
if ( mAudioStreamId == -1 ) { if ( mAudioStreamId == -1 ) {
Debug(3, "Record Audio on but no audio stream found"); Debug(3, "Record Audio on but no audio stream found");
@ -946,7 +950,8 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
ret = avcodec_receive_frame(mVideoCodecContext, mRawFrame); ret = avcodec_receive_frame(mVideoCodecContext, mRawFrame);
if ( ret < 0 ) { if ( ret < 0 ) {
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE); av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
Warning("Unable to receive frame %d: %s, continuing", frameCount, errbuf); Warning("Unable to receive frame %d: %s, continuing. error count is %s",
frameCount, errbuf, error_count);
error_count += 1; error_count += 1;
if ( error_count > 100 ) { if ( error_count > 100 ) {
Error("Error count over 100, going to close and re-open stream"); Error("Error count over 100, going to close and re-open stream");

View File

@ -78,7 +78,7 @@ std::string load_monitor_sql =
"Brightness, Contrast, Hue, Colour, " "Brightness, Contrast, Hue, Colour, "
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize," "EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, " "ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
"SectionLength, FrameSkip, MotionFrameSkip, " "SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckPoints, SignalCheckColour FROM Monitors"; "FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckPoints, SignalCheckColour FROM Monitors";
std::string CameraType_Strings[] = { std::string CameraType_Strings[] = {
@ -296,6 +296,7 @@ Monitor::Monitor(
int p_stream_replay_buffer, int p_stream_replay_buffer,
int p_alarm_frame_count, int p_alarm_frame_count,
int p_section_length, int p_section_length,
int p_min_section_length,
int p_frame_skip, int p_frame_skip,
int p_motion_frame_skip, int p_motion_frame_skip,
double p_analysis_fps, double p_analysis_fps,
@ -333,6 +334,7 @@ Monitor::Monitor(
post_event_count( p_post_event_count ), post_event_count( p_post_event_count ),
stream_replay_buffer( p_stream_replay_buffer ), stream_replay_buffer( p_stream_replay_buffer ),
section_length( p_section_length ), section_length( p_section_length ),
min_section_length( p_min_section_length ),
frame_skip( p_frame_skip ), frame_skip( p_frame_skip ),
motion_frame_skip( p_motion_frame_skip ), motion_frame_skip( p_motion_frame_skip ),
analysis_fps( p_analysis_fps ), analysis_fps( p_analysis_fps ),
@ -1377,15 +1379,18 @@ bool Monitor::Analyse() {
if ( trigger_data->trigger_state == TRIGGER_ON ) { if ( trigger_data->trigger_state == TRIGGER_ON ) {
score += trigger_data->trigger_score; score += trigger_data->trigger_score;
Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score);
if ( !event ) { if ( !event ) {
if ( cause.length() ) // How could it have a length already?
cause += ", "; //if ( cause.length() )
//cause += ", ";
cause += trigger_data->trigger_cause; cause += trigger_data->trigger_cause;
} }
Event::StringSet noteSet; Event::StringSet noteSet;
noteSet.insert( trigger_data->trigger_text ); noteSet.insert(trigger_data->trigger_text);
noteSetMap[trigger_data->trigger_cause] = noteSet; noteSetMap[trigger_data->trigger_cause] = noteSet;
} }
if ( signal_change ) { if ( signal_change ) {
const char *signalText; const char *signalText;
if ( !signal ) { if ( !signal ) {
@ -1405,40 +1410,41 @@ bool Monitor::Analyse() {
cause += SIGNAL_CAUSE; cause += SIGNAL_CAUSE;
} }
Event::StringSet noteSet; Event::StringSet noteSet;
noteSet.insert( signalText ); noteSet.insert(signalText);
noteSetMap[SIGNAL_CAUSE] = noteSet; noteSetMap[SIGNAL_CAUSE] = noteSet;
shared_data->state = state = IDLE; shared_data->state = state = IDLE;
shared_data->active = signal; shared_data->active = signal;
ref_image = *snap_image; ref_image = *snap_image;
} else if ( signal && Active() && (function == MODECT || function == MOCORD) ) { } else if ( signal ) {
Event::StringSet zoneSet; if ( Active() && (function == MODECT || function == MOCORD) ) {
if ( (!motion_frame_skip) || !(image_count % (motion_frame_skip+1) ) ) { // All is good, so add motion detection score.
// Get new score. Event::StringSet zoneSet;
int new_motion_score = DetectMotion(*snap_image, zoneSet); if ( (!motion_frame_skip) || !(image_count % (motion_frame_skip+1)) ) {
// Get new score.
int new_motion_score = DetectMotion(*snap_image, zoneSet);
Debug(3, Debug(3,
"After motion detection, last_motion_score(%d), new motion score(%d)", "After motion detection, last_motion_score(%d), new motion score(%d)",
last_motion_score, new_motion_score last_motion_score, new_motion_score
); );
last_motion_score = new_motion_score; last_motion_score = new_motion_score;
}
if ( last_motion_score ) {
if ( !event ) {
score += last_motion_score;
if ( cause.length() )
cause += ", ";
cause += MOTION_CAUSE;
} else {
score += last_motion_score;
} }
noteSetMap[MOTION_CAUSE] = zoneSet; if ( last_motion_score ) {
} // end if motion_score score += last_motion_score;
shared_data->active = signal; if ( !event ) {
} // end if signal change if ( cause.length() )
cause += ", ";
cause += MOTION_CAUSE;
}
noteSetMap[MOTION_CAUSE] = zoneSet;
} // end if motion_score
//shared_data->active = signal; // unneccessary active gets set on signal change
} // end if active and doing motion detection
if ( (!signal_change) && signal) { // Check to see if linked monitors are triggering.
if ( n_linked_monitors > 0 ) { if ( n_linked_monitors > 0 ) {
// FIXME improve logic here
bool first_link = true; bool first_link = true;
Event::StringSet noteSet; Event::StringSet noteSet;
for ( int i = 0; i < n_linked_monitors; i++ ) { for ( int i = 0; i < n_linked_monitors; i++ ) {
@ -1471,11 +1477,11 @@ bool Monitor::Analyse() {
if ( section_length if ( section_length
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length )
&& ( ! ( timestamp->tv_sec % section_length ) ) && ( (event_close_mode != CLOSE_TIME) || ! ( timestamp->tv_sec % section_length ) )
) { ) {
Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d", Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d",
name, image_count, event->Id(), name, image_count, event->Id(),
timestamp->tv_sec, video_store_data->recording.tv_sec, timestamp->tv_sec, video_store_data->recording.tv_sec,
timestamp->tv_sec - video_store_data->recording.tv_sec, timestamp->tv_sec - video_store_data->recording.tv_sec,
section_length section_length
); );
@ -1499,61 +1505,24 @@ bool Monitor::Analyse() {
shared_data->state = state = TAPE; shared_data->state = state = TAPE;
} }
//if ( config.overlap_timed_events )
if ( false ) {
int pre_index;
int pre_event_images = pre_event_count;
if ( analysis_fps ) {
// If analysis fps is set,
// compute the index for pre event images in the dedicated buffer
pre_index = pre_event_buffer_count ? image_count%pre_event_buffer_count : 0;
// Seek forward the next filled slot in to the buffer (oldest data)
// from the current position
while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) {
pre_index = (pre_index + 1)%pre_event_buffer_count;
// Slot is empty, removing image from counter
pre_event_images--;
}
} else {
// If analysis fps is not set (analysis performed at capturing framerate),
// compute the index for pre event images in the capturing buffer
pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count;
// Seek forward the next filled slot in to the buffer (oldest data)
// from the current position
while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) {
pre_index = (pre_index + 1)%image_buffer_count;
// Slot is empty, removing image from counter
pre_event_images--;
}
}
if ( pre_event_images ) {
if ( analysis_fps ) {
for ( int i = 0; i < pre_event_images; i++ ) {
timestamps[i] = pre_event_buffer[pre_index].timestamp;
images[i] = pre_event_buffer[pre_index].image;
pre_index = (pre_index + 1)%pre_event_buffer_count;
}
} else {
for ( int i = 0; i < pre_event_images; i++ ) {
timestamps[i] = image_buffer[pre_index].timestamp;
images[i] = image_buffer[pre_index].image;
pre_index = (pre_index + 1)%image_buffer_count;
}
}
event->AddFrames( pre_event_images, images, timestamps );
}
} // end if false or config.overlap_timed_events
} // end if ! event } // end if ! event
} // end if function == RECORD || function == MOCORD) } // end if function == RECORD || function == MOCORD)
} // end if !signal_change && signal } // end if !signal_change && signal
if ( score ) { if ( score ) {
if ( state == IDLE || state == TAPE || state == PREALARM ) { if ( (state == IDLE) || (state == TAPE) || (state == PREALARM) ) {
// If we should end then previous continuous event and start a new non-continuous event
if ( event && event->Frames()
&& (!event->AlarmFrames())
&& (event_close_mode == CLOSE_ALARM)
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length )
) {
Info("%s: %03d - Closing event %" PRIu64 ", continuous end, alarm begins",
name, image_count, event->Id());
closeEvent();
}
Debug(3, "pre-alarm-count %d", Event::PreAlarmCount());
// This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames
if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count) ) { if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count) ) {
shared_data->state = state = ALARM; shared_data->state = state = ALARM;
// lets construct alarm cause. It will contain cause + names of zones alarmed // lets construct alarm cause. It will contain cause + names of zones alarmed
@ -1568,14 +1537,11 @@ bool Monitor::Analyse() {
strncpy(shared_data->alarm_cause,alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1); strncpy(shared_data->alarm_cause,alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1);
Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s", Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s",
name, image_count, Event::PreAlarmCount(), alarm_frame_count, shared_data->alarm_cause); name, image_count, Event::PreAlarmCount(), alarm_frame_count, shared_data->alarm_cause);
if ( signal_change || (function != MOCORD && state != ALERT) ) {
if ( !event ) {
int pre_index; int pre_index;
int pre_event_images = pre_event_count; int pre_event_images = pre_event_count;
if ( event ) {
// Shouldn't be able to happen because
Error("Creating new event when one exists");
}
if ( analysis_fps && pre_event_count ) { if ( analysis_fps && pre_event_count ) {
// If analysis fps is set, // If analysis fps is set,
// compute the index for pre event images in the dedicated buffer // compute the index for pre event images in the dedicated buffer
@ -1811,7 +1777,13 @@ void Monitor::Reload() {
static char sql[ZM_SQL_MED_BUFSIZ]; static char sql[ZM_SQL_MED_BUFSIZ];
// This seems to have fallen out of date. // This seems to have fallen out of date.
snprintf(sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id); snprintf(sql, sizeof(sql),
"SELECT Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, "
"LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, "
"AlarmFrameCount, SectionLength, MinSectionLength, FrameSkip, "
"MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, "
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, "
"SignalCheckColour FROM Monitors WHERE Id = '%d'", id);
zmDbRow *row = zmDbFetchOne(sql); zmDbRow *row = zmDbFetchOne(sql);
if ( !row ) { if ( !row ) {
@ -1842,6 +1814,7 @@ void Monitor::Reload() {
post_event_count = atoi(dbrow[index++]); post_event_count = atoi(dbrow[index++]);
alarm_frame_count = atoi(dbrow[index++]); alarm_frame_count = atoi(dbrow[index++]);
section_length = atoi(dbrow[index++]); section_length = atoi(dbrow[index++]);
min_section_length = atoi(dbrow[index++]);
frame_skip = atoi(dbrow[index++]); frame_skip = atoi(dbrow[index++]);
motion_frame_skip = atoi(dbrow[index++]); motion_frame_skip = atoi(dbrow[index++]);
analysis_fps = dbrow[index] ? strtod(dbrow[index], NULL) : 0; index++; analysis_fps = dbrow[index] ? strtod(dbrow[index], NULL) : 0; index++;
@ -2057,7 +2030,7 @@ int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose p
"Brightness, Contrast, Hue, Colour, " "Brightness, Contrast, Hue, Colour, "
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize," "EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, " "ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
"SectionLength, FrameSkip, MotionFrameSkip, " "SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckColour FROM Monitors"; "FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckColour FROM Monitors";
*/ */
@ -2138,6 +2111,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) {
int stream_replay_buffer = atoi(dbrow[col]); col++; int stream_replay_buffer = atoi(dbrow[col]); col++;
int alarm_frame_count = atoi(dbrow[col]); col++; int alarm_frame_count = atoi(dbrow[col]); col++;
int section_length = atoi(dbrow[col]); col++; int section_length = atoi(dbrow[col]); col++;
int min_section_length = atoi(dbrow[col]); col++;
int frame_skip = atoi(dbrow[col]); col++; int frame_skip = atoi(dbrow[col]); col++;
int motion_frame_skip = atoi(dbrow[col]); col++; int motion_frame_skip = atoi(dbrow[col]); col++;
int fps_report_interval = atoi(dbrow[col]); col++; int fps_report_interval = atoi(dbrow[col]); col++;
@ -2338,6 +2312,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) {
stream_replay_buffer, stream_replay_buffer,
alarm_frame_count, alarm_frame_count,
section_length, section_length,
min_section_length,
frame_skip, frame_skip,
motion_frame_skip, motion_frame_skip,
analysis_fps, analysis_fps,
@ -2813,6 +2788,7 @@ bool Monitor::DumpSettings(char *output, bool verbose) {
sprintf(output+strlen(output), "Stream Replay Buffer : %d\n", stream_replay_buffer ); sprintf(output+strlen(output), "Stream Replay Buffer : %d\n", stream_replay_buffer );
sprintf(output+strlen(output), "Alarm Frame Count : %d\n", alarm_frame_count ); sprintf(output+strlen(output), "Alarm Frame Count : %d\n", alarm_frame_count );
sprintf(output+strlen(output), "Section Length : %d\n", section_length); sprintf(output+strlen(output), "Section Length : %d\n", section_length);
sprintf(output+strlen(output), "Min Section Length : %d\n", min_section_length);
sprintf(output+strlen(output), "Maximum FPS : %.2f\n", capture_delay?(double)DT_PREC_3/capture_delay:0.0); sprintf(output+strlen(output), "Maximum FPS : %.2f\n", capture_delay?(double)DT_PREC_3/capture_delay:0.0);
sprintf(output+strlen(output), "Alarm Maximum FPS : %.2f\n", alarm_capture_delay?(double)DT_PREC_3/alarm_capture_delay:0.0); sprintf(output+strlen(output), "Alarm Maximum FPS : %.2f\n", alarm_capture_delay?(double)DT_PREC_3/alarm_capture_delay:0.0);
sprintf(output+strlen(output), "Reference Blend %%ge : %d\n", ref_blend_perc); sprintf(output+strlen(output), "Reference Blend %%ge : %d\n", ref_blend_perc);

View File

@ -273,6 +273,7 @@ protected:
int post_event_count; // How many unalarmed images must occur before the alarm state is reset int post_event_count; // How many unalarmed images must occur before the alarm state is reset
int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now
int section_length; // How long events should last in continuous modes int section_length; // How long events should last in continuous modes
int min_section_length; // Minimum event length when using event_close_mode == ALARM
bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor
int frame_skip; // How many frames to skip in continuous modes int frame_skip; // How many frames to skip in continuous modes
int motion_frame_skip; // How many frames to skip in motion detection int motion_frame_skip; // How many frames to skip in motion detection
@ -382,6 +383,7 @@ public:
int p_stream_replay_buffer, int p_stream_replay_buffer,
int p_alarm_frame_count, int p_alarm_frame_count,
int p_section_length, int p_section_length,
int p_min_section_length,
int p_frame_skip, int p_frame_skip,
int p_motion_frame_skip, int p_motion_frame_skip,
double p_analysis_fps, double p_analysis_fps,

View File

@ -425,7 +425,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime );
if ( frameSendTime > 1000/maxfps ) { if ( frameSendTime > 1000/maxfps ) {
maxfps /= 1.5; maxfps /= 1.5;
Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); Warning("Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps);
} }
} }
last_frame_sent = TV_2_FLOAT( now ); last_frame_sent = TV_2_FLOAT( now );

View File

@ -20,6 +20,7 @@
#include "zm_packetqueue.h" #include "zm_packetqueue.h"
#include "zm_ffmpeg.h" #include "zm_ffmpeg.h"
#include <sys/time.h> #include <sys/time.h>
#include "zm_time.h"
zm_packetqueue::zm_packetqueue( int p_max_stream_id ) { zm_packetqueue::zm_packetqueue( int p_max_stream_id ) {
max_stream_id = p_max_stream_id; max_stream_id = p_max_stream_id;
@ -48,6 +49,7 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
return true; return true;
} }
#if 0
std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin(); std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin();
// Scan through the queue looking for a packet for our stream with a dts <= ours. // Scan through the queue looking for a packet for our stream with a dts <= ours.
@ -56,26 +58,29 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
Debug(2, "Looking at packet with stream index (%d) with dts %" PRId64, Debug(2, "Looking at packet with stream index (%d) with dts %" PRId64,
av_packet->stream_index, av_packet->dts); av_packet->stream_index, av_packet->dts);
if ( if ( av_packet->stream_index == zm_packet->packet.stream_index ) {
( av_packet->stream_index == zm_packet->packet.stream_index ) if (
&& ( av_packet->dts != AV_NOPTS_VALUE )
( av_packet->dts != AV_NOPTS_VALUE ) &&
&& ( av_packet->dts <= zm_packet->packet.dts)
( av_packet->dts <= zm_packet->packet.dts) ) {
) { Debug(2, "break packet with stream index (%d) with dts %" PRId64,
Debug(2, "break packet with stream index (%d) with dts %" PRId64, (*it)->packet.stream_index, (*it)->packet.dts);
(*it)->packet.stream_index, (*it)->packet.dts); break;
break; }
} else { // Not same stream, compare timestamps
if ( tvDiffUsec(((*it)->timestamp, zm_packet->timestamp) ) <= 0 ) {
Debug(2, "break packet with stream index (%d) with dts %" PRId64,
(*it)->packet.stream_index, (*it)->packet.dts);
break;
}
} }
it++; it++;
} // end while not the end of the queue } // end while not the end of the queue
if ( it != pktQueue.rend() ) { if ( it != pktQueue.rend() ) {
Debug(2, "Found packet with stream index (%d) with dts %" PRId64, Debug(2, "Found packet with stream index (%d) with dts %" PRId64 " <= %" PRId64,
(*it)->packet.stream_index, (*it)->packet.dts); (*it)->packet.stream_index, (*it)->packet.dts, zm_packet->packet.dts);
//it --;
//Debug(2, "Found packet with stream index (%d) with dts %" PRId64,
//(*it)->packet.stream_index, (*it)->packet.dts);
if ( it == pktQueue.rbegin() ) { if ( it == pktQueue.rbegin() ) {
Debug(2,"Inserting packet with dts %" PRId64 " at end", zm_packet->packet.dts); Debug(2,"Inserting packet with dts %" PRId64 " at end", zm_packet->packet.dts);
// No dts value, can't so much with it // No dts value, can't so much with it
@ -86,7 +91,7 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
// Convert to a forward iterator so that we can insert at end // Convert to a forward iterator so that we can insert at end
std::list<ZMPacket *>::iterator f_it = it.base(); std::list<ZMPacket *>::iterator f_it = it.base();
Debug(2, "Insert packet with stream index (%d) with dts %" PRId64 " for dts %" PRId64, Debug(2, "Insert packet before packet with stream index (%d) with dts %" PRId64 " for dts %" PRId64,
(*f_it)->packet.stream_index, (*f_it)->packet.dts, zm_packet->packet.dts); (*f_it)->packet.stream_index, (*f_it)->packet.dts, zm_packet->packet.dts);
pktQueue.insert(f_it, zm_packet); pktQueue.insert(f_it, zm_packet);
@ -96,8 +101,8 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
} }
Debug(1,"Unable to insert packet for stream %d with dts %" PRId64 " into queue.", Debug(1,"Unable to insert packet for stream %d with dts %" PRId64 " into queue.",
zm_packet->packet.stream_index, zm_packet->packet.dts); zm_packet->packet.stream_index, zm_packet->packet.dts);
// Must be before any packets in the queue. Stick it at the beginning #endif
pktQueue.push_front(zm_packet); pktQueue.push_back(zm_packet);
packet_counts[zm_packet->packet.stream_index] += 1; packet_counts[zm_packet->packet.stream_index] += 1;
return true; return true;
} // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) } // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet)
@ -267,3 +272,12 @@ void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVi
deleted_frames, pktQueue.size(), av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), distance( it, pktQueue.rend() ), pktQueue.size() ); deleted_frames, pktQueue.size(), av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), distance( it, pktQueue.rend() ), pktQueue.size() );
} }
} // end void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVideoStreamId ) } // end void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVideoStreamId )
void zm_packetqueue::dumpQueue() {
std::list<ZMPacket *>::reverse_iterator it;
for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) {
ZMPacket *zm_packet = *it;
AVPacket *av_packet = &(zm_packet->packet);
dumpPacket(av_packet);
}
}

View File

@ -41,6 +41,7 @@ public:
bool popAudioPacket(ZMPacket* packet); bool popAudioPacket(ZMPacket* packet);
unsigned int clearQueue(unsigned int video_frames_to_keep, int stream_id); unsigned int clearQueue(unsigned int video_frames_to_keep, int stream_id);
void clearQueue(); void clearQueue();
void dumpQueue();
unsigned int size(); unsigned int size();
void clear_unwanted_packets(timeval *recording, int mVideoStreamId); void clear_unwanted_packets(timeval *recording, int mVideoStreamId);
int packet_count(int stream_id); int packet_count(int stream_id);

View File

@ -371,6 +371,8 @@ VideoStore::VideoStore(
audio_out_ctx->codec_tag = 0; audio_out_ctx->codec_tag = 0;
#endif #endif
//audio_out_ctx->frame_size = audio_in_ctx->frame_size;
if ( audio_out_ctx->channels > 1 ) { if ( audio_out_ctx->channels > 1 ) {
Warning("Audio isn't mono, changing it."); Warning("Audio isn't mono, changing it.");
audio_out_ctx->channels = 1; audio_out_ctx->channels = 1;
@ -862,9 +864,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
ipkt->duration, ipkt->duration,
video_in_stream->time_base, video_in_stream->time_base,
video_out_stream->time_base); video_out_stream->time_base);
Debug(1, "duration from ipkt: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)", Debug(1, "duration from ipkt: %" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
ipkt->pts,
video_last_pts,
ipkt->duration, ipkt->duration,
duration, duration,
video_in_stream->time_base.num, video_in_stream->time_base.num,
@ -935,7 +935,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")", Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")",
opkt.dts, ipkt->dts, video_first_dts); opkt.dts, ipkt->dts, video_first_dts);
} }
if ( opkt.dts > opkt.pts ) { if ( (opkt.pts != AV_NOPTS_VALUE) && (opkt.dts > opkt.pts) ) {
Debug(1, Debug(1,
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen "
"before presentation.", "before presentation.",
@ -947,11 +947,11 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
opkt.dts = video_out_stream->cur_dts; opkt.dts = video_out_stream->cur_dts;
} }
# if 0 # if 1
if ( opkt.dts <= video_out_stream->cur_dts ) { if ( opkt.dts < video_out_stream->cur_dts ) {
Warning("Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64, Warning("Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
opkt.dts, opkt.pts, video_out_stream->cur_dts); opkt.dts, opkt.pts, video_out_stream->cur_dts);
opkt.dts = video_out_stream->cur_dts + 1; opkt.dts = video_out_stream->cur_dts;
if ( opkt.dts > opkt.pts ) { if ( opkt.dts > opkt.pts ) {
opkt.pts = opkt.dts; opkt.pts = opkt.dts;
} }
@ -1016,7 +1016,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
if ( out_frame->pts != AV_NOPTS_VALUE ) { if ( out_frame->pts != AV_NOPTS_VALUE ) {
if ( !audio_first_pts ) { if ( !audio_first_pts ) {
audio_first_pts = out_frame->pts; audio_first_pts = out_frame->pts;
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts); Debug(1, "No video_first_pts setting to %" PRId64, audio_first_pts);
out_frame->pts = 0; out_frame->pts = 0;
} else { } else {
out_frame->pts = out_frame->pts - audio_first_pts; out_frame->pts = out_frame->pts - audio_first_pts;
@ -1095,7 +1095,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
if ( !audio_first_pts ) { if ( !audio_first_pts ) {
opkt.pts = 0; opkt.pts = 0;
audio_first_pts = ipkt->pts; audio_first_pts = ipkt->pts;
Debug(1, "No audio_first_pts"); Debug(1, "No video_first_pts");
} else { } else {
opkt.pts = av_rescale_q( opkt.pts = av_rescale_q(
ipkt->pts - audio_first_pts, ipkt->pts - audio_first_pts,
@ -1192,12 +1192,12 @@ int VideoStore::resample_audio() {
#if 0 #if 0
// out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder // out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder
if ( out_frame->pts != AV_NOPTS_VALUE ) { if ( out_frame->pts != AV_NOPTS_VALUE ) {
if ( !audio_first_pts ) { if ( !video_first_pts ) {
audio_first_pts = out_frame->pts; video_first_pts = out_frame->pts;
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts); Debug(1, "No video_first_pts setting to %" PRId64, video_first_pts);
out_frame->pts = 0; out_frame->pts = 0;
} else { } else {
out_frame->pts = out_frame->pts - audio_first_pts; out_frame->pts = out_frame->pts - video_first_pts;
} }
// //
} else { } else {

View File

@ -75,7 +75,7 @@ void Zone::Setup(
//Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames ); //Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames );
alarmed = false; alarmed = false;
was_alarmed = false; was_alarmed = false;
pixel_diff = 0; pixel_diff = 0;
alarm_pixels = 0; alarm_pixels = 0;
alarm_filter_pixels = 0; alarm_filter_pixels = 0;
@ -115,11 +115,11 @@ void Zone::Setup(
if ( config.record_diag_images ) { if ( config.record_diag_images ) {
snprintf(diag_path, sizeof(diag_path), config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); snprintf(diag_path, sizeof(diag_path), config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id);
if (config.record_diag_images_fifo) if (config.record_diag_images_fifo)
FifoStream::fifo_create_if_missing(diag_path); FifoStream::fifo_create_if_missing(diag_path);
pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo); pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
} else { } else {
diag_path[0] = 0; diag_path[0] = 0;
} }
} // end Zone::Setup } // end Zone::Setup
Zone::~Zone() { Zone::~Zone() {
@ -132,13 +132,13 @@ Zone::~Zone() {
void Zone::RecordStats( const Event *event ) { void Zone::RecordStats( const Event *event ) {
static char sql[ZM_SQL_MED_BUFSIZ]; static char sql[ZM_SQL_MED_BUFSIZ];
db_mutex.lock(); db_mutex.lock();
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", "INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d",
monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score
); );
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't insert event stats: %s", mysql_error(&dbconn)); Error("Can't insert event stats: %s", mysql_error(&dbconn));
} }
db_mutex.unlock(); db_mutex.unlock();
} // end void Zone::RecordStats( const Event *event ) } // end void Zone::RecordStats( const Event *event )
@ -243,9 +243,10 @@ bool Zone::CheckAlarms(const Image *delta_image) {
Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d", Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d",
alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff); alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff);
if (config.record_diag_images_fifo) if ( config.record_diag_images_fifo ) {
FifoDebug( 5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}", id,alarm_pixels, pixel_diff ); FifoDebug(5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}",
id,alarm_pixels, pixel_diff);
}
if ( alarm_pixels ) { if ( alarm_pixels ) {
if ( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) { if ( min_alarm_pixels && (alarm_pixels < (unsigned int)min_alarm_pixels) ) {
@ -261,7 +262,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
return false; return false;
} }
if (max_alarm_pixels != 0) if ( max_alarm_pixels != 0 )
score = (100*alarm_pixels)/max_alarm_pixels; score = (100*alarm_pixels)/max_alarm_pixels;
else else
score = (100*alarm_pixels)/polygon.Area(); score = (100*alarm_pixels)/polygon.Area();
@ -276,7 +277,6 @@ bool Zone::CheckAlarms(const Image *delta_image) {
int bx1 = bx-1; int bx1 = bx-1;
int by1 = by-1; int by1 = by-1;
Debug(5, "Checking for filtered pixels"); Debug(5, "Checking for filtered pixels");
if ( bx > 1 || by > 1 ) { if ( bx > 1 || by > 1 ) {
// Now remove any pixels smaller than our filter size // Now remove any pixels smaller than our filter size
@ -287,7 +287,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
int lo_x = ranges[y].lo_x; int lo_x = ranges[y].lo_x;
int hi_x = ranges[y].hi_x; int hi_x = ranges[y].hi_x;
pdiff = (uint8_t*)diff_image->Buffer( lo_x, y ); pdiff = (uint8_t*)diff_image->Buffer(lo_x, y);
for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) { for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) {
if ( *pdiff == WHITE ) { if ( *pdiff == WHITE ) {
@ -328,8 +328,8 @@ bool Zone::CheckAlarms(const Image *delta_image) {
Debug(5, "Got %d filtered pixels, need %d -> %d", Debug(5, "Got %d filtered pixels, need %d -> %d",
alarm_filter_pixels, min_filter_pixels, max_filter_pixels); alarm_filter_pixels, min_filter_pixels, max_filter_pixels);
if (config.record_diag_images_fifo) if ( config.record_diag_images_fifo )
FifoDebug( 5, "{\"zone\":%d,\"type\":\"FILT\",\"pixels\":%d}", id, alarm_filter_pixels ); FifoDebug(5, "{\"zone\":%d,\"type\":\"FILT\",\"pixels\":%d}", id, alarm_filter_pixels);
if ( alarm_filter_pixels ) { if ( alarm_filter_pixels ) {
if ( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) { if ( min_filter_pixels && (alarm_filter_pixels < min_filter_pixels) ) {
@ -345,7 +345,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
return false; return false;
} }
if (max_filter_pixels != 0) if ( max_filter_pixels != 0 )
score = (100*alarm_filter_pixels)/max_filter_pixels; score = (100*alarm_filter_pixels)/max_filter_pixels;
else else
score = (100*alarm_filter_pixels)/polygon.Area(); score = (100*alarm_filter_pixels)/polygon.Area();
@ -408,13 +408,13 @@ bool Zone::CheckAlarms(const Image *delta_image) {
bss = bsm==bsx?bsy:bsx; bss = bsm==bsx?bsy:bsx;
Debug(9, Debug(9,
"Different neighbours, setting pixels of %d to %d\n" "Different neighbours, setting pixels of %d to %d\n"
"Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n" "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n"
"Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n", "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n",
bss->tag, bsm->tag, bss->tag, bsm->tag,
bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y, bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y,
bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y
); );
// Now change all those pixels to the other setting // Now change all those pixels to the other setting
int changed = 0; int changed = 0;
for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++ ) { for ( int sy = bss->lo_y; sy <= bss->hi_y; sy++ ) {
@ -422,9 +422,9 @@ bool Zone::CheckAlarms(const Image *delta_image) {
int hi_sx = bss->hi_x<=ranges[sy].hi_x?bss->hi_x:ranges[sy].hi_x; int hi_sx = bss->hi_x<=ranges[sy].hi_x?bss->hi_x:ranges[sy].hi_x;
Debug(9, Debug(9,
"Changing %d, %d->%d Range %d->%d", "Changing %d, %d->%d Range %d->%d",
sy, lo_sx, hi_sx, ranges[sy].lo_x, ranges[sy].hi_x sy, lo_sx, hi_sx, ranges[sy].lo_x, ranges[sy].hi_x
); );
spdiff = diff_buff + ((diff_width * sy) + lo_sx); spdiff = diff_buff + ((diff_width * sy) + lo_sx);
for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ ) { for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ ) {
Debug(9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff); Debug(9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff);
@ -439,11 +439,11 @@ bool Zone::CheckAlarms(const Image *delta_image) {
alarm_blob_pixels++; alarm_blob_pixels++;
if ( !changed ) { if ( !changed ) {
Info( Info(
"Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n" "Master blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d\n"
"Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d", "Slave blob t:%d, c:%d, lx:%d, hx:%d, ly:%d, hy:%d",
bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y, bsm->tag, bsm->count, bsm->lo_x, bsm->hi_x, bsm->lo_y, bsm->hi_y,
bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y bss->tag, bss->count, bss->lo_x, bss->hi_x, bss->lo_y, bss->hi_y
); );
Error("No pixels changed, exiting"); Error("No pixels changed, exiting");
exit(-1); exit(-1);
} }
@ -517,7 +517,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
alarm_blob_pixels -= bs->count; alarm_blob_pixels -= bs->count;
Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs",
i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs); i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs);
bs->tag = 0; bs->tag = 0;
bs->count = 0; bs->count = 0;
@ -551,6 +551,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
} }
} }
} }
if ( config.record_diag_images ) if ( config.record_diag_images )
diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo); diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
@ -559,10 +560,12 @@ bool Zone::CheckAlarms(const Image *delta_image) {
} }
Debug(5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d", Debug(5, "Got %d raw blob pixels, %d raw blobs, need %d -> %d, %d -> %d",
alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs);
if (config.record_diag_images_fifo) if ( config.record_diag_images_fifo ) {
FifoDebug( 5, "{\"zone\":%d,\"type\":\"RBLB\",\"pixels\":%d,\"blobs\":%d}", id, alarm_blob_pixels, alarm_blobs ); FifoDebug(5, "{\"zone\":%d,\"type\":\"RBLB\",\"pixels\":%d,\"blobs\":%d}",
id, alarm_blob_pixels, alarm_blobs);
}
// Now eliminate blobs under the threshold // Now eliminate blobs under the threshold
for ( int i = 1; i < WHITE; i++ ) { for ( int i = 1; i < WHITE; i++ ) {
@ -583,7 +586,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
alarm_blob_pixels -= bs->count; alarm_blob_pixels -= bs->count;
Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", Debug(6, "Eliminated blob %d, %d pixels (%d,%d - %d,%d), %d current blobs",
i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs);
bs->tag = 0; bs->tag = 0;
bs->count = 0; bs->count = 0;
@ -593,19 +596,23 @@ bool Zone::CheckAlarms(const Image *delta_image) {
bs->hi_y = 0; bs->hi_y = 0;
} else { } else {
Debug(6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs", Debug(6, "Preserved blob %d, %d pixels (%d,%d - %d,%d), %d current blobs",
i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs ); i, bs->count, bs->lo_x, bs->lo_y, bs->hi_x, bs->hi_y, alarm_blobs);
if ( !min_blob_size || bs->count < min_blob_size ) min_blob_size = bs->count; if ( !min_blob_size || bs->count < min_blob_size ) min_blob_size = bs->count;
if ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count; if ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count;
} }
} // end if bs_count } // end if bs_count
} // end for i < WHITE } // end for i < WHITE
if ( config.record_diag_images ) if ( config.record_diag_images )
diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo); diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d", Debug(5, "Got %d blob pixels, %d blobs, need %d -> %d, %d -> %d",
alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs); alarm_blob_pixels, alarm_blobs, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs);
if (config.record_diag_images_fifo)
FifoDebug( 5, "{\"zone\":%d,\"type\":\"FBLB\",\"pixels\":%d,\"blobs\":%d}", id, alarm_blob_pixels, alarm_blobs ); if ( config.record_diag_images_fifo ) {
FifoDebug(5, "{\"zone\":%d,\"type\":\"FBLB\",\"pixels\":%d,\"blobs\":%d}",
id, alarm_blob_pixels, alarm_blobs);
}
if ( alarm_blobs ) { if ( alarm_blobs ) {
if ( min_blobs && (alarm_blobs < min_blobs) ) { if ( min_blobs && (alarm_blobs < min_blobs) ) {
@ -621,7 +628,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
return false; return false;
} }
if (max_blob_pixels != 0) if ( max_blob_pixels != 0 )
score = (100*alarm_blob_pixels)/(max_blob_pixels); score = (100*alarm_blob_pixels)/(max_blob_pixels);
else else
score = (100*alarm_blob_pixels)/polygon.Area(); score = (100*alarm_blob_pixels)/polygon.Area();
@ -693,7 +700,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
alarm_centre = alarm_box.Centre(); alarm_centre = alarm_box.Centre();
} }
if ( (type < PRECLUSIVE) && check_method >= BLOBS && config.create_analysis_images ) { if ( (type < PRECLUSIVE) && (check_method >= BLOBS) && config.create_analysis_images ) {
// First mask out anything we don't want // First mask out anything we don't want
for ( unsigned int y = lo_y; y <= hi_y; y++ ) { for ( unsigned int y = lo_y; y <= hi_y; y++ ) {
@ -707,12 +714,12 @@ bool Zone::CheckAlarms(const Image *delta_image) {
if ( lo_gap == 1 ) { if ( lo_gap == 1 ) {
*pdiff++ = BLACK; *pdiff++ = BLACK;
} else { } else {
memset( pdiff, BLACK, lo_gap ); memset(pdiff, BLACK, lo_gap);
pdiff += lo_gap; pdiff += lo_gap;
} }
} }
const uint8_t* ppoly = pg_image->Buffer( lo_x2, y ); const uint8_t* ppoly = pg_image->Buffer(lo_x2, y);
for ( int x = lo_x2; x <= hi_x2; x++, pdiff++, ppoly++ ) { for ( int x = lo_x2; x <= hi_x2; x++, pdiff++, ppoly++ ) {
if ( !*ppoly ) { if ( !*ppoly ) {
*pdiff = BLACK; *pdiff = BLACK;
@ -724,10 +731,10 @@ bool Zone::CheckAlarms(const Image *delta_image) {
if ( hi_gap == 1 ) { if ( hi_gap == 1 ) {
*pdiff = BLACK; *pdiff = BLACK;
} else { } else {
memset( pdiff, BLACK, hi_gap ); memset(pdiff, BLACK, hi_gap);
} }
} }
} } // end for y
if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) { if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) {
image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent()); image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent());
@ -783,32 +790,32 @@ bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) {
Debug(3, "Got coordinate %d,%d from polygon string", x, y); Debug(3, "Got coordinate %d,%d from polygon string", x, y);
#if 0 #if 0
if ( x < 0 ) if ( x < 0 )
x = 0; x = 0;
else if ( x >= width ) else if ( x >= width )
x = width-1; x = width-1;
if ( y < 0 ) if ( y < 0 )
y = 0; y = 0;
else if ( y >= height ) else if ( y >= height )
y = height-1; y = height-1;
#endif #endif
coords[n_coords++] = Coord( x, y ); coords[n_coords++] = Coord( x, y );
} }
if ( ws ) if ( ws )
str = ws+1; str = ws+1;
else else
break; break;
} }
polygon = Polygon(n_coords, coords); polygon = Polygon(n_coords, coords);
Debug(3, "Successfully parsed polygon string"); Debug(3, "Successfully parsed polygon string");
//printf( "Area: %d\n", pg.Area() ); //printf( "Area: %d\n", pg.Area() );
//printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() );
delete[] coords; delete[] coords;
delete[] str_ptr; delete[] str_ptr;
return true; return true;
} }
bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) { bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) {
@ -863,7 +870,7 @@ int Zone::Load(Monitor *monitor, Zone **&zones) {
if ( mysql_query(&dbconn, sql) ) { if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn)); Error("Can't run query: %s", mysql_error(&dbconn));
db_mutex.unlock(); db_mutex.unlock();
return 0; return 0;
} }
MYSQL_RES *result = mysql_store_result( &dbconn ); MYSQL_RES *result = mysql_store_result( &dbconn );
@ -916,7 +923,7 @@ int Zone::Load(Monitor *monitor, Zone **&zones) {
if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width() if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width()
|| polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) { || polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) {
Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring",
Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY()); Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY());
n_zones -= 1; n_zones -= 1;
continue; continue;
} }

View File

@ -571,14 +571,18 @@ int main(int argc, char *argv[]) {
monitor->DumpZoneImage(zoneString); monitor->DumpZoneImage(zoneString);
} }
if ( function & ZMU_ALARM ) { if ( function & ZMU_ALARM ) {
if ( verbose ) if ( monitor->GetFunction() == Monitor::Function::MONITOR ) {
printf("Forcing alarm on\n"); printf("A Monitor in monitor mode cannot handle alarms. Please use NoDect\n");
monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web"); } else {
while ( monitor->GetState() != Monitor::ALARM ) { if ( verbose )
// Wait for monitor to notice. printf("Forcing alarm on\n");
usleep(1000); monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web");
} while ( (monitor->GetState() != Monitor::ALARM) && !zm_terminate ) {
printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId()); // Wait for monitor to notice.
usleep(1000);
}
printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId());
} // end if ! MONITOR
} }
if ( function & ZMU_NOALARM ) { if ( function & ZMU_NOALARM ) {
if ( verbose ) if ( verbose )

1
third_party/bcrypt vendored

@ -1 +0,0 @@
Subproject commit be171cd75dd65e06315a67c7dcdb8e1bbc1dabd4

1
third_party/jwt-cpp vendored

@ -1 +0,0 @@
Subproject commit bfca4f6a87bfd9d9a259939d0524169827a3a862

View File

@ -102,14 +102,14 @@ Alias /zm /usr/share/zoneminder/www
# Parameters not set here are inherited from the parent directive above. # Parameters not set here are inherited from the parent directive above.
<Directory "/usr/share/zoneminder/www/api"> <Directory "/usr/share/zoneminder/www/api">
RewriteEngine on RewriteEngine on
RewriteRule ^$ app/webroot/ [L] RewriteRule ^\$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L] RewriteRule (.*) app/webroot/$1 [L]
RewriteBase /zm/api RewriteBase /zm/api
</Directory> </Directory>
<Directory "/usr/share/zoneminder/www/api/app"> <Directory "/usr/share/zoneminder/www/api/app">
RewriteEngine on RewriteEngine on
RewriteRule ^$ webroot/ [L] RewriteRule ^\$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L] RewriteRule (.*) webroot/$1 [L]
RewriteBase /zm/api RewriteBase /zm/api
</Directory> </Directory>

View File

@ -1 +1 @@
1.33.9 1.33.10

View File

@ -35,6 +35,7 @@ class EventsController extends AppController {
$this->Event->recursive = -1; $this->Event->recursive = -1;
global $user; global $user;
require_once __DIR__ .'/../../../includes/Event.php';
$allowedMonitors = $user ? preg_split('@,@', $user['MonitorIds'], NULL, PREG_SPLIT_NO_EMPTY) : null; $allowedMonitors = $user ? preg_split('@,@', $user['MonitorIds'], NULL, PREG_SPLIT_NO_EMPTY) : null;
if ( $allowedMonitors ) { if ( $allowedMonitors ) {
@ -87,9 +88,13 @@ class EventsController extends AppController {
$events = $this->Paginator->paginate('Event'); $events = $this->Paginator->paginate('Event');
// For each event, get the frameID which has the largest score // For each event, get the frameID which has the largest score
// also add FS path
foreach ( $events as $key => $value ) { foreach ( $events as $key => $value ) {
$EventObj = new ZM\Event($value['Event']['Id']);
$maxScoreFrameId = $this->getMaxScoreAlarmFrameId($value['Event']['Id']); $maxScoreFrameId = $this->getMaxScoreAlarmFrameId($value['Event']['Id']);
$events[$key]['Event']['MaxScoreFrameId'] = $maxScoreFrameId; $events[$key]['Event']['MaxScoreFrameId'] = $maxScoreFrameId;
$events[$key]['Event']['FileSystemPath'] = $EventObj->Path();
} }
$this->set(compact('events')); $this->set(compact('events'));
@ -131,6 +136,9 @@ class EventsController extends AppController {
$event['Event']['fileExists'] = $this->Event->fileExists($event['Event']); $event['Event']['fileExists'] = $this->Event->fileExists($event['Event']);
$event['Event']['fileSize'] = $this->Event->fileSize($event['Event']); $event['Event']['fileSize'] = $this->Event->fileSize($event['Event']);
$EventObj = new ZM\Event($id);
$event['Event']['FileSystemPath'] = $EventObj->Path();
# Also get the previous and next events for the same monitor # Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array( $event_monitor_neighbors = $this->Event->find('neighbors', array(
'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId']) 'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId'])

View File

@ -61,6 +61,7 @@ private $defaults = array(
'StreamReplayBuffer' => 0, 'StreamReplayBuffer' => 0,
'AlarmFrameCount' => 1, 'AlarmFrameCount' => 1,
'SectionLength' => 600, 'SectionLength' => 600,
'MinSectionLength' => 10,
'FrameSkip' => 0, 'FrameSkip' => 0,
'AnalysisFPSLimit' => null, 'AnalysisFPSLimit' => null,
'AnalysisUpdateDelay' => 0, 'AnalysisUpdateDelay' => 0,
@ -361,6 +362,8 @@ private $control_fields = array(
$this->{$k} = $v; $this->{$k} = $v;
} else if ( is_bool( $v ) ) { } else if ( is_bool( $v ) ) {
$this->{$k} = $v; $this->{$k} = $v;
} else if ( is_null( $v ) ) {
$this->{$k} = $v;
} else { } else {
Error( "Unknown type $k => $v of var " . gettype( $v ) ); Error( "Unknown type $k => $v of var " . gettype( $v ) );
$this->{$k} = $v; $this->{$k} = $v;

View File

@ -32,7 +32,7 @@ if ( $action == 'user' ) {
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"'; $pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
} else { } else {
$pass_hash = ' PASSWORD('.dbEscape($_REQUEST['newUser']['Password']).') '; $pass_hash = ' PASSWORD('.dbEscape($_REQUEST['newUser']['Password']).') ';
ZM\Info('Cannot use bcrypt as you are using PHP < 5.5'); ZM\Info('Cannot use bcrypt as you are using PHP < 5.3');
} }
if ( $_REQUEST['newUser']['Password'] ) { if ( $_REQUEST['newUser']['Password'] ) {
@ -70,7 +70,6 @@ if ( $action == 'user' ) {
} }
if ( !empty($_REQUEST['newUser']['Password']) ) { if ( !empty($_REQUEST['newUser']['Password']) ) {
ZM\Info('PASS CMD='.$changes['Password']);
$changes['Password'] = 'Password = '.$pass_hash; $changes['Password'] = 'Password = '.$pass_hash;
} }

View File

@ -263,7 +263,7 @@ function validateToken ($token, $allowed_token_type='access', $from_api_layer=fa
} // end function validateToken($token, $allowed_token_type='access') } // end function validateToken($token, $allowed_token_type='access')
function getAuthUser($auth, $from_api_layer = false) { function getAuthUser($auth, $from_api_layer = false) {
if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' && !empty($auth) ) { if ( ZM_OPT_USE_AUTH && (ZM_AUTH_RELAY == 'hashed') && !empty($auth) ) {
$remoteAddr = ''; $remoteAddr = '';
if ( ZM_AUTH_HASH_IPS ) { if ( ZM_AUTH_HASH_IPS ) {
$remoteAddr = $_SERVER['REMOTE_ADDR']; $remoteAddr = $_SERVER['REMOTE_ADDR'];
@ -285,7 +285,7 @@ function getAuthUser($auth, $from_api_layer = false) {
foreach ( dbFetchAll($sql, NULL, $values) as $user ) { foreach ( dbFetchAll($sql, NULL, $values) as $user ) {
$now = time(); $now = time();
for ( $i = 0; $i < ZM_AUTH_HASH_TTL; $i++, $now -= ZM_AUTH_HASH_TTL * 1800 ) { // Try for last two hours for ( $i = 0; $i < ZM_AUTH_HASH_TTL; $i++, $now -= 3600 ) { // Try for last TTL hours
$time = localtime($now); $time = localtime($now);
$authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$remoteAddr.$time[2].$time[3].$time[4].$time[5]; $authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$remoteAddr.$time[2].$time[3].$time[4].$time[5];
$authHash = md5($authKey); $authHash = md5($authKey);
@ -315,6 +315,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
if ( ZM_OPT_USE_AUTH and (ZM_AUTH_RELAY == 'hashed') and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) { if ( ZM_OPT_USE_AUTH and (ZM_AUTH_RELAY == 'hashed') and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) {
$time = time(); $time = time();
# We use 1800 so that we regenerate the hash at half the TTL
$mintime = $time - ( ZM_AUTH_HASH_TTL * 1800 ); $mintime = $time - ( ZM_AUTH_HASH_TTL * 1800 );
if ( $force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime ) ) { if ( $force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime ) ) {
@ -335,7 +336,8 @@ function generateAuthHash($useRemoteAddr, $force=false) {
} }
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth; $_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
$_SESSION['AuthHashGeneratedAt'] = $time; $_SESSION['AuthHashGeneratedAt'] = $time;
session_write_close(); if ( $close_session )
session_write_close();
#ZM\Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" ); #ZM\Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" );
#} else { #} else {
#ZM\Logger::Debug("Using cached auth " . $_SESSION['AuthHash'] ." beacuse generatedat:" . $_SESSION['AuthHashGeneratedAt'] . ' < now:'. $time . ' - ' . ZM_AUTH_HASH_TTL . ' * 1800 = '. $mintime); #ZM\Logger::Debug("Using cached auth " . $_SESSION['AuthHash'] ." beacuse generatedat:" . $_SESSION['AuthHashGeneratedAt'] . ' < now:'. $time . ' - ' . ZM_AUTH_HASH_TTL . ' * 1800 = '. $mintime);
@ -375,7 +377,8 @@ if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_HASH_LOGINS and (ZM_AUTH_RELAY == 'hashed') ) { if ( ZM_AUTH_HASH_LOGINS and (ZM_AUTH_RELAY == 'hashed') ) {
# Extra validation, if logged in, then the auth hash will be set in the session, so we can validate it. # Extra validation, if logged in, then the auth hash will be set in the session, so we can validate it.
# This prevent session modification to switch users # This prevent session modification to switch users
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]); if ( $_SESSION['AuthHash'.$_SESSION['remoteAddr']] )
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
} else { } else {
# Need to refresh permissions and validate that the user still exists # Need to refresh permissions and validate that the user still exists
$sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?'; $sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?';
@ -395,6 +398,7 @@ if ( ZM_OPT_USE_AUTH ) {
} }
} else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) { } else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) {
userLogin($_REQUEST['username'], $_REQUEST['password'], false); userLogin($_REQUEST['username'], $_REQUEST['password'], false);
# Because it might have migrated the password we need to update the hash
generateAuthHash(ZM_AUTH_HASH_IPS, true); generateAuthHash(ZM_AUTH_HASH_IPS, true);
} }

View File

@ -732,7 +732,7 @@ function buildControlCommand( $monitor ) {
} }
} }
$ctrlCommand .= ' --command='.$_REQUEST['control']; $ctrlCommand .= ' --command='.$_REQUEST['control'];
return( $ctrlCommand ); return $ctrlCommand;
} }
function sendControlCommand($mid, $command) { function sendControlCommand($mid, $command) {

View File

@ -1077,13 +1077,28 @@ function parseSort( $saveToSession=false, $querySep='&amp;' ) {
case 'MaxScore' : case 'MaxScore' :
$sortColumn = 'E.MaxScore'; $sortColumn = 'E.MaxScore';
break; break;
case 'FramesFrameId' :
$sortColumn = 'F.FrameId';
break;
case 'FramesType' :
$sortColumn = 'F.Type';
break;
case 'FramesTimeStamp' :
$sortColumn = 'F.TimeStamp';
break;
case 'FramesDelta' :
$sortColumn = 'F.Delta';
break;
case 'FramesScore' :
$sortColumn = 'F.Score';
break;
default: default:
$sortColumn = 'E.StartTime'; $sortColumn = 'E.StartTime';
break; break;
} }
$sortOrder = $_REQUEST['sort_asc']?'asc':'desc';
if ( !$_REQUEST['sort_asc'] ) if ( !$_REQUEST['sort_asc'] )
$_REQUEST['sort_asc'] = 0; $_REQUEST['sort_asc'] = 0;
$sortOrder = $_REQUEST['sort_asc']?'asc':'desc';
$sortQuery = $querySep.'sort_field='.validHtmlStr($_REQUEST['sort_field']).$querySep.'sort_asc='.validHtmlStr($_REQUEST['sort_asc']); $sortQuery = $querySep.'sort_field='.validHtmlStr($_REQUEST['sort_field']).$querySep.'sort_asc='.validHtmlStr($_REQUEST['sort_asc']);
if ( !isset($_REQUEST['limit']) ) if ( !isset($_REQUEST['limit']) )
$_REQUEST['limit'] = ''; $_REQUEST['limit'] = '';
@ -1168,6 +1183,9 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&amp;') {
case 'StartDateTime': case 'StartDateTime':
$filter['sql'] .= 'E.StartTime'; $filter['sql'] .= 'E.StartTime';
break; break;
case 'FramesEventId':
$filter['sql'] .= 'F.EventId';
break;
case 'StartDate': case 'StartDate':
$filter['sql'] .= 'to_days( E.StartTime )'; $filter['sql'] .= 'to_days( E.StartTime )';
break; break;

View File

@ -58,6 +58,7 @@ function xhtmlHeaders($file, $title) {
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> - <?php echo validHtmlStr($title) ?></title> <title><?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> - <?php echo validHtmlStr($title) ?></title>
<?php <?php
if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) { if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
@ -79,15 +80,19 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
<?php <?php
echo output_link_if_exists( array( echo output_link_if_exists( array(
'css/base/skin.css', 'css/base/skin.css',
'css/'.$css.'/skin.css',
'css/base/views/'.$basename.'.css', 'css/base/views/'.$basename.'.css',
'css/'.$css.'/views/'.$basename.'.css',
'js/dateTimePicker/jquery-ui-timepicker-addon.css', 'js/dateTimePicker/jquery-ui-timepicker-addon.css',
'js/jquery-ui-1.12.1/jquery-ui.structure.min.css', 'js/jquery-ui-1.12.1/jquery-ui.structure.min.css',
#'js/jquery-ui-1.12.1/jquery-ui.theme.min.css', #'js/jquery-ui-1.12.1/jquery-ui.theme.min.css',
'css/'.$css.'/jquery-ui-theme.css',
) )
); );
if ( $css != 'base' )
echo output_link_if_exists( array(
'css/'.$css.'/skin.css',
'css/'.$css.'/views/'.$basename.'.css',
'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.12.1/jquery-ui.theme.min.css" type="text/css"/>
<!--Chosen can't be cache-busted because it loads sprites by relative path--> <!--Chosen can't be cache-busted because it loads sprites by relative path-->
@ -341,7 +346,7 @@ if ( canEdit('System') ) {
<button type="button" class="btn btn-default navbar-btn" data-toggle="modal" data-target="#modalState"><?php echo $status ?></button> <button type="button" class="btn btn-default navbar-btn" data-toggle="modal" data-target="#modalState"><?php echo $status ?></button>
<?php if ( ZM_SYSTEM_SHUTDOWN ) { ?> <?php if ( ZM_SYSTEM_SHUTDOWN ) { ?>
<p class="navbar-text"> <p class="navbar-text">
<?php echo makePopupLink('?view=shutdown', 'zmShutdown', 'shutdown', '<i class="material-icons md-18">power_settings_new</i></button>' ) ?> <?php echo makePopupLink('?view=shutdown', 'zmShutdown', 'shutdown', '<i class="material-icons md-18">power_settings_new</i>' ) ?>
</p> </p>
<?php } ?> <?php } ?>
<?php } else if ( canView('System') ) { ?> <?php } else if ( canView('System') ) { ?>
@ -394,7 +399,8 @@ if ( (!ZM_OPT_USE_AUTH) or $user ) {
$title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()). $title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()).
( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' ); ( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' );
return '<span class="'.$class.'" title="'.$title.'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; }; return '<span class="'.$class.'" title="'.$title.'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>
'; };
#$func = function($S){ return '<span title="">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; }; #$func = function($S){ return '<span title="">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
if ( count($storage_areas) > 4 ) if ( count($storage_areas) > 4 )
$storage_areas = ZM\Storage::find( array('ServerId'=>null) ); $storage_areas = ZM\Storage::find( array('ServerId'=>null) );

View File

@ -33,7 +33,7 @@ var popupSizes = {
'cycle': {'addWidth': 32, 'minWidth': 384, 'addHeight': 62}, 'cycle': {'addWidth': 32, 'minWidth': 384, 'addHeight': 62},
'device': {'width': 260, 'height': 150}, 'device': {'width': 260, 'height': 150},
'devices': {'width': 400, 'height': 240}, 'devices': {'width': 400, 'height': 240},
'donate': {'width': 500, 'height': 280}, 'donate': {'width': 500, 'height': 480},
'download': {'width': 350, 'height': 315}, 'download': {'width': 350, 'height': 315},
'event': {'addWidth': 108, 'minWidth': 496, 'addHeight': 230, 'minHeight': 540}, 'event': {'addWidth': 108, 'minWidth': 496, 'addHeight': 230, 'minHeight': 540},
'eventdetail': {'width': 600, 'height': 420}, 'eventdetail': {'width': 600, 'height': 420},

View File

@ -63,7 +63,8 @@ if ( count($GroupsById) ) {
$group_id = isset($_SESSION['Group']) ? $_SESSION['Group'] : null; $group_id = isset($_SESSION['Group']) ? $_SESSION['Group'] : null;
$html .= ZM\Group::get_group_dropdown(); $html .= ZM\Group::get_group_dropdown();
$groupSql = ZM\Group::get_group_sql($group_id); $groupSql = ZM\Group::get_group_sql($group_id);
$html .= '</span>'; $html .= '</span>
';
} }
$selected_monitor_ids = isset($_SESSION['MonitorId']) ? $_SESSION['MonitorId'] : array(); $selected_monitor_ids = isset($_SESSION['MonitorId']) ? $_SESSION['MonitorId'] : array();
@ -95,7 +96,8 @@ if ( ! empty($user['MonitorIds']) ) {
$html .= '<span class="MonitorNameFilter"><label>'.translate('Name').'</label>'; $html .= '<span class="MonitorNameFilter"><label>'.translate('Name').'</label>';
$html .= '<input type="text" name="MonitorName" value="'.(isset($_SESSION['MonitorName'])?validHtmlStr($_SESSION['MonitorName']):'').'" placeholder="text or regular expression"/>'; $html .= '<input type="text" name="MonitorName" value="'.(isset($_SESSION['MonitorName'])?validHtmlStr($_SESSION['MonitorName']):'').'" placeholder="text or regular expression"/>';
$html .= '</span>'; $html .= '</span>
';
$Functions = array(); $Functions = array();
foreach ( getEnumValues('Monitors', 'Function') as $optFunction ) { foreach ( getEnumValues('Monitors', 'Function') as $optFunction ) {
@ -112,7 +114,8 @@ $html .= htmlSelect('Function[]', $Functions,
'data-placeholder'=>'All', 'data-placeholder'=>'All',
) )
); );
$html .= '</span>'; $html .= '</span>
';
if ( count($ServersById) > 1 ) { if ( count($ServersById) > 1 ) {
$html .= '<span class="ServerFilter"><label>'. translate('Server').'</label>'; $html .= '<span class="ServerFilter"><label>'. translate('Server').'</label>';
@ -125,7 +128,8 @@ if ( count($ServersById) > 1 ) {
'data-placeholder'=>'All', 'data-placeholder'=>'All',
) )
); );
$html .= '</span>'; $html .= '</span>
';
} # end if have Servers } # end if have Servers
if ( count($StorageById) > 1 ) { if ( count($StorageById) > 1 ) {
@ -138,7 +142,8 @@ if ( count($StorageById) > 1 ) {
'multiple'=>'multiple', 'multiple'=>'multiple',
'data-placeholder'=>'All', 'data-placeholder'=>'All',
) ); ) );
$html .= '</span>'; $html .= '</span>
';
} # end if have Storage Areas } # end if have Storage Areas
$html .= '<span class="StatusFilter"><label>'. translate('Status') . '</label>'; $html .= '<span class="StatusFilter"><label>'. translate('Status') . '</label>';
@ -156,11 +161,13 @@ $html .= htmlSelect( 'Status[]', $status_options,
'multiple'=>'multiple', 'multiple'=>'multiple',
'data-placeholder'=>'All' 'data-placeholder'=>'All'
) ); ) );
$html .= '</span>'; $html .= '</span>
';
$html .= '<span class="SourceFilter"><label>'.translate('Source').'</label>'; $html .= '<span class="SourceFilter"><label>'.translate('Source').'</label>';
$html .= '<input type="text" name="Source" value="'.(isset($_SESSION['Source'])?validHtmlStr($_SESSION['Source']):'').'" placeholder="text or regular expression"/>'; $html .= '<input type="text" name="Source" value="'.(isset($_SESSION['Source'])?validHtmlStr($_SESSION['Source']):'').'" placeholder="text or regular expression"/>';
$html .= '</span>'; $html .= '</span>
';
$sql = 'SELECT *,S.Status AS Status, S.CaptureFPS AS CaptureFPS, S.AnalysisFPS AS AnalysisFPS, S.CaptureBandwidth AS CaptureBandwidth $sql = 'SELECT *,S.Status AS Status, S.CaptureFPS AS CaptureFPS, S.AnalysisFPS AS AnalysisFPS, S.CaptureBandwidth AS CaptureBandwidth
FROM Monitors AS M LEFT JOIN Monitor_Status AS S ON MonitorId=Id ' . FROM Monitors AS M LEFT JOIN Monitor_Status AS S ON MonitorId=Id ' .
@ -243,7 +250,8 @@ $html .= htmlSelect( 'Status[]', $status_options,
) ); ) );
# Repurpose this variable to be the list of MonitorIds as a result of all the filtering # Repurpose this variable to be the list of MonitorIds as a result of all the filtering
$selected_monitor_ids = array_map(function($monitor_row){return $monitor_row['Id'];}, $displayMonitors); $selected_monitor_ids = array_map(function($monitor_row){return $monitor_row['Id'];}, $displayMonitors);
$html .= '</span>'; $html .= '</span>
';
echo $html; echo $html;
?> ?>
</div> </div>

View File

@ -214,7 +214,7 @@ ob_start();
<th class="colStorage"><?php echo translate('Storage') ?></th> <th class="colStorage"><?php echo translate('Storage') ?></th>
<?php } <?php }
foreach ( array_keys($eventCounts) as $j ) { foreach ( array_keys($eventCounts) as $j ) {
echo '<th class="colEvents">'. $j .'</th>'; echo '<th class="colEvents">'. $eventCounts[$j]['title'] .'</th>';
} }
?> ?>
<th class="colZones"><?php echo translate('Zones') ?></th> <th class="colZones"><?php echo translate('Zones') ?></th>

View File

@ -137,19 +137,19 @@ for ( $i = 0; $i < 7; $i++ ) {
$weekdays[$i] = strftime('%A', mktime(12, 0, 0, 1, $i+1, 2001)); $weekdays[$i] = strftime('%A', mktime(12, 0, 0, 1, $i+1, 2001));
} }
$states = array(); $states = array();
foreach ( dbFetchAll('SELECT Id,Name FROM States ORDER BY lower(Name) ASC') as $state_row ) { foreach ( dbFetchAll('SELECT Id, Name FROM States ORDER BY lower(Name) ASC') as $state_row ) {
$states[$state_row['Id']] = $state_row['Name']; $states[$state_row['Id']] = validHtmlStr($state_row['Name']);
} }
$servers = array(); $servers = array();
$servers['ZM_SERVER_ID'] = 'Current Server'; $servers['ZM_SERVER_ID'] = 'Current Server';
$servers['NULL'] = 'No Server'; $servers['NULL'] = 'No Server';
foreach ( dbFetchAll('SELECT Id,Name FROM Servers ORDER BY lower(Name) ASC') as $server ) { foreach ( dbFetchAll('SELECT Id, Name FROM Servers ORDER BY lower(Name) ASC') as $server ) {
$servers[$server['Id']] = $server['Name']; $servers[$server['Id']] = validHtmlStr($server['Name']);
} }
$monitors = array(); $monitors = array();
foreach ( dbFetchAll('SELECT Id,Name FROM Monitors ORDER BY Name ASC') as $monitor ) { foreach ( dbFetchAll('SELECT Id, Name FROM Monitors ORDER BY Name ASC') as $monitor ) {
if ( visibleMonitor($monitor['Id']) ) { if ( visibleMonitor($monitor['Id']) ) {
$monitors[$monitor['Name']] = $monitor['Name']; $monitors[$monitor['Name']] = validHtmlStr($monitor['Name']);
} }
} }
@ -188,7 +188,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )
<?php } ?> <?php } ?>
<p class="Name"> <p class="Name">
<label for="filter[Name]"><?php echo translate('Name') ?></label> <label for="filter[Name]"><?php echo translate('Name') ?></label>
<input type="text" id="filter[Name]" name="filter[Name]" value="<?php echo validHtmlStr($filter->Name()) ?>" oninput="updateButtons(this);"/> <input type="text" id="filter[Name]" name="filter[Name]" value="<?php echo validHtmlStr($filter->Name()) ?>" data-on-input-this="updateButtons"/>
</p> </p>
<table id="fieldsTable" class="filterTable"> <table id="fieldsTable" class="filterTable">
<tbody> <tbody>
@ -247,7 +247,7 @@ for ( $i=0; $i < count($terms); $i++ ) {
<?php <?php
} elseif ( $term['attr'] == 'StartTime' || $term['attr'] == 'EndTime' ) { } elseif ( $term['attr'] == 'StartTime' || $term['attr'] == 'EndTime' ) {
?> ?>
<td><?php echo htmlSelect( "filter[Query][terms][$i][op]", $opTypes, $term['op'] ); ?></td> <td><?php echo htmlSelect("filter[Query][terms][$i][op]", $opTypes, $term['op']); ?></td>
<td> <td>
<input type="text" name="filter[Query][terms][<?php echo $i ?>][val]" id="filter[Query][terms][<?php echo $i ?>][val]" value="<?php echo isset($term['val'])?validHtmlStr(str_replace('T', ' ', $term['val'])):'' ?>"/> <input type="text" name="filter[Query][terms][<?php echo $i ?>][val]" id="filter[Query][terms][<?php echo $i ?>][val]" value="<?php echo isset($term['val'])?validHtmlStr(str_replace('T', ' ', $term['val'])):'' ?>"/>
<script nonce="<?php echo $cspNonce;?>">$j("[name$='\\[<?php echo $i ?>\\]\\[val\\]']").timepicker({timeFormat: "HH:mm:ss", constrainInput: false}); </script> <script nonce="<?php echo $cspNonce;?>">$j("[name$='\\[<?php echo $i ?>\\]\\[val\\]']").timepicker({timeFormat: "HH:mm:ss", constrainInput: false}); </script>

View File

@ -22,8 +22,44 @@ if ( !canView('Events') ) {
$view = 'error'; $view = 'error';
return; return;
} }
require_once('includes/Frame.php'); require_once('includes/Frame.php');
$Event = new ZM\Event($_REQUEST['eid']);
$countSql = 'SELECT COUNT(*) AS FrameCount FROM Frames AS F WHERE 1 ';
$frameSql = 'SELECT *, unix_timestamp( TimeStamp ) AS UnixTimeStamp FROM Frames AS F WHERE 1 ';
$eid = $_REQUEST['eid'];
// override the sort_field handling in parseSort for frames
if ( empty($_REQUEST['sort_field']) )
$_REQUEST['sort_field'] = 'FramesTimeStamp';
if ( !isset($_REQUEST['sort_asc']) )
$_REQUEST['sort_asc'] = true;
if( ! isset($_REQUEST['filter'])){
// generate a dummy filter from the eid for pagination
$_REQUEST['filter'] = array('Query' => array( 'terms' => array( ) ) );
$_REQUEST['filter'] = addFilterTerm(
$_REQUEST['filter'],
0,
array( 'cnj' => 'and', 'attr' => 'FramesEventId', 'op' => '=', 'val' => $eid )
);
}
parseSort();
parseFilter($_REQUEST['filter']);
$filterQuery = $_REQUEST['filter']['query'];
if ( $_REQUEST['filter']['sql'] ) {
$countSql .= $_REQUEST['filter']['sql'];
$frameSql .= $_REQUEST['filter']['sql'];
}
$frameSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder";
$Event = new ZM\Event($eid);
$Monitor = $Event->Monitor(); $Monitor = $Event->Monitor();
if ( isset( $_REQUEST['scale'] ) ) { if ( isset( $_REQUEST['scale'] ) ) {
@ -33,32 +69,94 @@ if ( isset( $_REQUEST['scale'] ) ) {
} else if ( isset( $_COOKIE['zmWatchScale'] ) ) { } else if ( isset( $_COOKIE['zmWatchScale'] ) ) {
$scale = validNum($_COOKIE['zmWatchScale']); $scale = validNum($_COOKIE['zmWatchScale']);
} else { } else {
$scale = max( reScale( SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), SCALE_BASE ); $scale = max(reScale(SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE);
} }
$sql = 'SELECT *, unix_timestamp( TimeStamp ) AS UnixTimeStamp FROM Frames WHERE EventID = ? ORDER BY FrameId';
$frames = dbFetchAll( $sql, NULL, array( $_REQUEST['eid'] ) ); $page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 1;
$limit = isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : 0;
$nEvents = dbFetchOne($countSql, 'FrameCount' );
if ( !empty($limit) && $nEvents > $limit ) {
$nEvents = $limit;
}
$pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE);
if ( !empty($page) ) {
if ( $page < 0 )
$page = 1;
else if ( $pages and ( $page > $pages ) )
$page = $pages;
$limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE);
if ( empty( $limit ) ) {
$limitAmount = ZM_WEB_EVENTS_PER_PAGE;
} else {
$limitLeft = $limit - $limitStart;
$limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft;
}
$frameSql .= " limit $limitStart, $limitAmount";
} elseif ( !empty($limit) ) {
$frameSql .= ' limit 0, '.$limit;
}
$maxShortcuts = 5;
$pagination = getPagination($pages, $page, $maxShortcuts, $sortQuery.'&eid='.$eid.$limitQuery.$filterQuery);
$frames = dbFetchAll( $frameSql );
$focusWindow = true; $focusWindow = true;
xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id() ); xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id());
?> ?>
<body> <body>
<div id="page"> <div id="page">
<div id="header"> <div id="header">
<div id="headerButtons"><a href="#" data-on-click="closeWindow"><?php echo translate('Close') ?></a></div> <div id="headerButtons"><a href="#" data-on-click="closeWindow"><?php echo translate('Close') ?></a></div>
<h2><?php echo translate('Frames') ?> - <?php echo $Event->Id() ?></h2> <h2><?php echo translate('Frames') ?> - <?php echo $Event->Id() ?></h2>
<div id="pagination">
<?php
if ( $pagination ) {
?>
<h2 class="pagination"><?php echo $pagination ?></h2>
<?php
}
?>
<?php
if ( $pages > 1 ) {
if ( !empty($page) ) {
?>
<a href="?view=<?php echo $view ?>&amp;page=0<?php echo $filterQuery ?><?php echo $sortQuery.$limitQuery ?>"><?php echo translate('ViewAll') ?></a>
<?php
} else {
?>
<a href="?view=<?php echo $view ?>&amp;page=1<?php echo $filterQuery ?><?php echo $sortQuery.$limitQuery ?>"><?php echo translate('ViewPaged') ?></a>
<?php
}
}
?>
</div>
</div> </div>
<div id="content"> <div id="content">
<form name="contentForm" id="contentForm" method="get" action="?"> <form name="contentForm" id="contentForm" method="get" action="?">
<input type="hidden" name="view" value="none"/> <input type="hidden" name="view" value="none"/>
<table id="contentTable" class="major" cellspacing="0"> <table id="contentTable" class="major" cellspacing="0">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="action" value=""/>
<input type="hidden" name="page" value="<?php echo $page ?>"/>
<input type="hidden" name="eid" value="<?php echo $eid ?>"/>
<?php echo $_REQUEST['filter']['fields'] ?>
<input type="hidden" name="sort_field" value="<?php echo validHtmlStr($_REQUEST['sort_field']) ?>"/>
<input type="hidden" name="sort_asc" value="<?php echo validHtmlStr($_REQUEST['sort_asc']) ?>"/>
<input type="hidden" name="limit" value="<?php echo $limit ?>"/>
<thead> <thead>
<tr> <tr>
<th class="colId"><?php echo translate('FrameId') ?></th> <th class="colId"><a href="<?php echo sortHeader('FramesFrameId') ?>"><?php echo translate('Frame Id') ?><?php echo sortTag('FramesFrameId') ?></a></th>
<th class="colType"><?php echo translate('Type') ?></th> <th class="colType"><a href="<?php echo sortHeader('FramesType') ?>"><?php echo translate('Type') ?><?php echo sortTag('FramesType') ?></a></th>
<th class="colTimeStamp"><?php echo translate('TimeStamp') ?></th> <th class="colTimeStamp"><a href="<?php echo sortHeader('FramesTimeStamp') ?>"><?php echo translate('TimeStamp') ?><?php echo sortTag('FramesTimeStamp') ?></a></th>
<th class="colTimeDelta"><?php echo translate('TimeDelta') ?></th> <th class="colTimeDelta"><a href="<?php echo sortHeader('FramesDelta') ?>"><?php echo translate('TimeDelta') ?><?php echo sortTag('FramesDelta') ?></a></th>
<th class="colScore"><?php echo translate('Score') ?></th> <th class="colScore"><a href="<?php echo sortHeader('FramesScore') ?>"><?php echo translate('Score') ?><?php echo sortTag('FramesScore') ?></a></th>
<?php <?php
if ( ZM_WEB_LIST_THUMBS ) { if ( ZM_WEB_LIST_THUMBS ) {
?> ?>
@ -87,12 +185,12 @@ if ( count($frames) ) {
$frame['FrameId']) $frame['FrameId'])
?></td> ?></td>
<td class="colType"><?php echo $frame['Type'] ?></td> <td class="colType"><?php echo $frame['Type'] ?></td>
<td class="colTimeStamp"><?php echo strftime( STRF_FMT_TIME, $frame['UnixTimeStamp'] ) ?></td> <td class="colTimeStamp"><?php echo strftime(STRF_FMT_TIME, $frame['UnixTimeStamp']) ?></td>
<td class="colTimeDelta"><?php echo number_format( $frame['Delta'], 2 ) ?></td> <td class="colTimeDelta"><?php echo number_format( $frame['Delta'], 2 ) ?></td>
<?php <?php
if ( ZM_RECORD_EVENT_STATS && ($frame['Type'] == 'Alarm') ) { if ( ZM_RECORD_EVENT_STATS && ($frame['Type'] == 'Alarm') ) {
?> ?>
<td class="colScore"><?php echo makePopupLink( '?view=stats&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmStats', 'stats', $frame['Score'] ) ?></td> <td class="colScore"><?php echo makePopupLink('?view=stats&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmStats', 'stats', $frame['Score']) ?></td>
<?php <?php
} else { } else {
?> ?>
@ -101,7 +199,7 @@ if ( count($frames) ) {
} }
if ( ZM_WEB_LIST_THUMBS ) { if ( ZM_WEB_LIST_THUMBS ) {
?> ?>
<td class="colThumbnail"><?php echo makePopupLink( '?view=frame&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmImage', array( 'image', $Event->Width(), $Event->Height() ), '<img src="?view=image&amp;fid='.$Frame->Id().'&amp;'. <td class="colThumbnail"><?php echo makePopupLink( '?view=frame&amp;eid='.$Event->Id().'&amp;fid='.$frame['FrameId'], 'zmImage', array('image', $Event->Width(), $Event->Height()), '<img src="?view=image&amp;fid='.$Frame->Id().'&amp;'.
(ZM_WEB_LIST_THUMB_WIDTH?'width='.ZM_WEB_LIST_THUMB_WIDTH.'&amp;':''). (ZM_WEB_LIST_THUMB_WIDTH?'width='.ZM_WEB_LIST_THUMB_WIDTH.'&amp;':'').
(ZM_WEB_LIST_THUMB_HEIGHT?'height='.ZM_WEB_LIST_THUMB_HEIGHT.'&amp;':'').'filename='.$Event->MonitorId().'_'.$frame['EventId'].'_'.$frame['FrameId'].'.jpg" '. (ZM_WEB_LIST_THUMB_HEIGHT?'height='.ZM_WEB_LIST_THUMB_HEIGHT.'&amp;':'').'filename='.$Event->MonitorId().'_'.$frame['EventId'].'_'.$frame['FrameId'].'.jpg" '.
(ZM_WEB_LIST_THUMB_WIDTH?'width="'.ZM_WEB_LIST_THUMB_WIDTH.'" ':''). (ZM_WEB_LIST_THUMB_WIDTH?'width="'.ZM_WEB_LIST_THUMB_WIDTH.'" ':'').
@ -122,6 +220,15 @@ if ( count($frames) ) {
?> ?>
</tbody> </tbody>
</table> </table>
<?php
if ( $pagination ) {
?>
<h3 class="pagination"><?php echo $pagination ?></h3>
<?php
}
?>
<div id="contentButtons"> <div id="contentButtons">
</div> </div>
</form> </form>

View File

@ -27,10 +27,10 @@ var options = {};
function escapeHtml(unsafe) { function escapeHtml(unsafe) {
return unsafe return unsafe
.replace(/&/g, "&amp;") .replace(/&/g, "&amp;")
.replace(/</g, "&lt;") .replace(/</g, "&lt;")
.replace(/>/g, "&gt;") .replace(/>/g, "&gt;")
.replace(/"/g, "&quot;") .replace(/"/g, "&quot;")
.replace(/'/g, "&#039;"); .replace(/'/g, "&#039;");
} }

View File

@ -204,7 +204,13 @@ function Monitor(monitorData) {
} }
} // end function Monitor } // end function Monitor
/**
* called when the layoutControl select element is changed, or the page
* is rendered
* @param {*} element - the event data passed by onchange callback
*/
function selectLayout(element) { function selectLayout(element) {
console.dir(element);
layout = $j(element).val(); layout = $j(element).val();
if ( layout_id = parseInt(layout) ) { if ( layout_id = parseInt(layout) ) {
@ -266,14 +272,13 @@ function selectLayout(element) {
} }
streamImg.style.width = '100%'; streamImg.style.width = '100%';
} }
var zonesSVG = $('zones'+monitor.id);
if ( zonesSVG ) {
zonesSVG.style.width = '';
}
} // end foreach monitor } // end foreach monitor
} }
} // end function selectLayout(element) } // end function selectLayout(element)
/**
* called when the widthControl|heightControl select elements are changed
*/
function changeSize() { function changeSize() {
var width = $('width').get('value'); var width = $('width').get('value');
var height = $('height').get('value'); var height = $('height').get('value');
@ -309,11 +314,6 @@ function changeSize() {
streamImg.style.height = height ? height : null; streamImg.style.height = height ? height : null;
//streamImg.style.height = ''; //streamImg.style.height = '';
} }
var zonesSVG = $('zones'+monitor.id);
if ( zonesSVG ) {
zonesSVG.style.width = width ? width : '100%';
zonesSVG.style.height = height;
}
} }
$('scale').set('value', ''); $('scale').set('value', '');
Cookie.write('zmMontageScale', '', {duration: 10*365}); Cookie.write('zmMontageScale', '', {duration: 10*365});
@ -322,6 +322,9 @@ function changeSize() {
selectLayout('#zmMontageLayout'); selectLayout('#zmMontageLayout');
} // end function changeSize() } // end function changeSize()
/**
* called when the scaleControl select element is changed
*/
function changeScale() { function changeScale() {
var scale = $('scale').get('value'); var scale = $('scale').get('value');
$('width').set('value', 'auto'); $('width').set('value', 'auto');
@ -367,11 +370,6 @@ function changeScale() {
streamImg.style.width = newWidth + "px"; streamImg.style.width = newWidth + "px";
streamImg.style.height = newHeight + "px"; streamImg.style.height = newHeight + "px";
} }
var zonesSVG = $('zones'+monitor.id);
if ( zonesSVG ) {
zonesSVG.style.width = newWidth + "px";
zonesSVG.style.height = newHeight + "px";
}
} }
} }

View File

@ -45,51 +45,81 @@ function evaluateLoadTimes() {
$('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + "."; $('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + ".";
} // end evaluateLoadTimes() } // end evaluateLoadTimes()
function getFrame( monId, time ) { function getFrame(monId, time, last_Frame) {
if ( last_Frame ) {
if (
(last_Frame.TimeStampSecs <= time)
&&
(last_Frame.EndTimeStampSecs >= time)
) {
return last_Frame;
}
}
var events_for_monitor = events_by_monitor_id[monId];
if ( !events_for_monitor ) {
console.log("No events for monitor " + monId);
return;
}
var Frame = null; var Frame = null;
for ( var event_id in events ) { for ( var i = 0; i < events_for_monitor.length; i++ ) {
//for ( var event_id_idx in events_for_monitor ) {
var event_id = events_for_monitor[i];
// Search for the event matching this time. Would be more efficient if we had events indexed by monitor // Search for the event matching this time. Would be more efficient if we had events indexed by monitor
Event = events[event_id]; e = events[event_id];
if ( Event.MonitorId != monId || Event.StartTimeSecs > time || Event.EndTimeSecs < time ) { if ( !e ) {
console.log("No event found for " + event_id);
break;
}
if ( e.MonitorId != monId || e.StartTimeSecs > time || e.EndTimeSecs < time ) {
//console.log("Event not for " + time);
continue; continue;
} }
var duration = Event.EndTimeSecs - Event.StartTimeSecs; if ( !e.FramesById ) {
if ( ! Event.FramesById ) {
console.log("No FramesById for event " + event_id); console.log("No FramesById for event " + event_id);
return; return;
} }
var frame = parseInt((time - Event.StartTimeSecs)/(duration)*Object.keys(Event.FramesById).length)+1; var duration = e.EndTimeSecs - e.StartTimeSecs;
// Need to get frame by time, not some fun calc that assumes frames have the same mlength.
// Frames are not sorted. // I think this is an estimate to jump near the desired frame.
for ( var frame_id in Event.FramesById ) { var frame = parseInt((time - e.StartTimeSecs)/(duration)*Object.keys(e.FramesById).length)+1;
//console.log("frame_id for " + time + " is " + frame);
// Need to get frame by time, not some fun calc that assumes frames have the same length.
// Frames are sorted in descreasing order (or not sorted).
// This is likely not efficient. Would be better to start at the last frame viewed, see if it is still relevant
// Then move forward or backwards as appropriate
for ( var frame_id in e.FramesById ) {
if ( 0 ) { if ( 0 ) {
if ( frame == 0 ) { if ( frame == 0 ) {
console.log("Found frame for time " + time ); console.log("Found frame for time " + time);
console.log(Frame); console.log(Frame);
Frame = Event.FramesById[frame_id]; Frame = e.FramesById[frame_id];
break; break;
} }
frame --; frame --;
continue; continue;
} }
if ( if (
Event.FramesById[frame_id].TimeStampSecs == time e.FramesById[frame_id].TimeStampSecs == time
|| ( || (
Event.FramesById[frame_id].TimeStampSecs < time e.FramesById[frame_id].TimeStampSecs < time
&& ( && (
(!Event.FramesById[frame_id].NextTimeStampSecs) (!e.FramesById[frame_id].NextTimeStampSecs) // only if event.EndTime is null
|| ||
(Event.FramesById[frame_id].NextTimeStampSecs > time) (e.FramesById[frame_id].NextTimeStampSecs > time)
) )
) )
) { ) {
Frame = Event.FramesById[frame_id]; Frame = e.FramesById[frame_id];
break; break;
} }
} // end foreach frame in the event. } // end foreach frame in the event.
if ( ! Frame ) { if ( !Frame ) {
console.log("Didn't find frame for " + time ); console.log("Didn't find frame for " + time);
return null; return null;
} }
} // end foreach event } // end foreach event
@ -97,11 +127,11 @@ function getFrame( monId, time ) {
} }
// time is seconds since epoch // time is seconds since epoch
function getImageSource( monId, time ) { function getImageSource(monId, time) {
if ( liveMode == 1 ) { if ( liveMode == 1 ) {
var new_url = monitorImageObject[monId].src.replace( var new_url = monitorImageObject[monId].src.replace(
/rand=\d+/i, /rand=\d+/i,
'rand='+Math.floor((Math.random() * 1000000) ) 'rand='+Math.floor(Math.random() * 1000000)
); );
if ( auth_hash ) { if ( auth_hash ) {
// update auth hash // update auth hash
@ -109,20 +139,30 @@ function getImageSource( monId, time ) {
} }
return new_url; return new_url;
} }
var frame_id;
var Frame = getFrame(monId, time); var Frame = getFrame(monId, time);
if ( Frame ) { if ( Frame ) {
// Adjust for bulk frames // Adjust for bulk frames
if ( Frame.NextFrameId ) { if ( Frame.NextFrameId ) {
var duration = Frame.NextTimeStampSecs - Frame.TimeStampSecs; var e = events[Frame.EventId];
frame_id = Frame.FrameId + parseInt( (Frame.NextFrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration ); var NextFrame = e.FramesById[Frame.NextFrameId];
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + Frame.NextFrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) ); if ( !NextFrame ) {
//} else { console.log("No next frame for " + Frame.NextFrameId);
//console.log("No NextFrame"); } else if ( NextFrame.Type == 'Bulk' ) {
// There is time between this frame and a bulk frame
var duration = Frame.NextTimeStampSecs - Frame.TimeStampSecs;
frame_id = Frame.FrameId + parseInt( (NextFrame.FrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration );
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + NextFrame.FrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) );
}
} else {
frame_id = Frame['Id'];
console.log("No NextFrame");
} }
Event = events[Frame.EventId]; Event = events[Frame.EventId];
var storage = Storage[Event.StorageId]; var storage = Storage[Event.StorageId];
if ( ! storage ) { if ( !storage ) {
// Storage[0] is guaranteed to exist as we make sure it is there in montagereview.js.php // Storage[0] is guaranteed to exist as we make sure it is there in montagereview.js.php
console.log("No storage area for id " + Event.StorageId); console.log("No storage area for id " + Event.StorageId);
storage = Storage[0]; storage = Storage[0];
@ -130,7 +170,7 @@ function getImageSource( monId, time ) {
// monitorServerId may be 0, which gives us the default Server entry // monitorServerId may be 0, which gives us the default Server entry
var server = storage.ServerId ? Servers[storage.ServerId] : Servers[monitorServerId[monId]]; var server = storage.ServerId ? Servers[storage.ServerId] : Servers[monitorServerId[monId]];
return server.PathToIndex + return server.PathToIndex +
'?view=image&eid=' + Frame.EventId + '&fid='+Frame.FrameId + '?view=image&eid=' + Frame.EventId + '&fid='+frame_id +
"&width=" + monitorCanvasObj[monId].width + "&width=" + monitorCanvasObj[monId].width +
"&height=" + monitorCanvasObj[monId].height; "&height=" + monitorCanvasObj[monId].height;
} // end found Frame } // end found Frame
@ -193,6 +233,7 @@ function loadNoData( monId ) {
console.log("No monId in loadNoData"); console.log("No monId in loadNoData");
} }
} }
function writeText( monId, text ) { function writeText( monId, text ) {
if ( monId ) { if ( monId ) {
var canvasCtx = monitorCanvasCtx[monId]; var canvasCtx = monitorCanvasCtx[monId];
@ -232,20 +273,26 @@ function timerFire() {
if ( ( currentDisplayInterval != timerInterval ) || ( currentSpeed == 0 ) ) { if ( ( currentDisplayInterval != timerInterval ) || ( currentSpeed == 0 ) ) {
// zero just turn off interrupts // zero just turn off interrupts
clearInterval(timerObj); clearInterval(timerObj);
timerInterval=currentDisplayInterval; timerObj = null;
if ( currentSpeed>0 || liveMode!=0 ) timerObj=setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero timerInterval = currentDisplayInterval;
console.log("Turn off nterrupts timerInterfave" + timerInterval);
}
if ( (currentSpeed > 0 || liveMode != 0) && ! timerObj ) {
timerObj = setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero
} }
if ( liveMode ) { if ( liveMode ) {
console.log("liveMode");
outputUpdate(currentTimeSecs); // In live mode we basically do nothing but redisplay outputUpdate(currentTimeSecs); // In live mode we basically do nothing but redisplay
} else if ( currentTimeSecs + playSecsperInterval >= maxTimeSecs ) { } else if ( currentTimeSecs + playSecsPerInterval >= maxTimeSecs ) {
// beyond the end just stop // beyond the end just stop
console.log("Current time " + currentTimeSecs + " + " + playSecsperInterval + " >= " + maxTimeSecs + " so stopping"); console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval + " >= " + maxTimeSecs + " so stopping");
setSpeed(0); setSpeed(0);
outputUpdate(currentTimeSecs); outputUpdate(currentTimeSecs);
} else { } else {
//console.log("Current time " + currentTimeSecs + " + " + playSecsperInterval ); //console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval);
outputUpdate(playSecsperInterval + currentTimeSecs); outputUpdate(playSecsPerInterval + currentTimeSecs);
} }
return; return;
} }
@ -267,10 +314,10 @@ function drawSliderOnGraph(val) {
if ( numMonitors > 0 ) { if ( numMonitors > 0 ) {
// if we have no data to display don't do the slider itself // if we have no data to display don't do the slider itself
var sliderX = parseInt( (val - minTimeSecs) / rangeTimeSecs * cWidth - sliderWidth/2); // position left side of slider var sliderX = parseInt((val - minTimeSecs) / rangeTimeSecs * cWidth - sliderWidth/2); // position left side of slider
if ( sliderX < 0 ) sliderX = 0; if ( sliderX < 0 ) sliderX = 0;
if ( sliderX+sliderWidth > cWidth ) { if ( sliderX + sliderWidth > cWidth ) {
sliderX=cWidth-sliderWidth-1; sliderX = cWidth-sliderWidth-1;
} }
// If we have data already saved first restore it from LAST time // If we have data already saved first restore it from LAST time
@ -296,20 +343,20 @@ function drawSliderOnGraph(val) {
o.style.color = "red"; o.style.color = "red";
} else { } else {
o.innerHTML = secs2dbstr(val); o.innerHTML = secs2dbstr(val);
o.style.color="blue"; o.style.color = "blue";
} }
o.style.position="absolute"; o.style.position = "absolute";
o.style.bottom = labbottom; o.style.bottom = labbottom;
o.style.font = labfont; o.style.font = labfont;
// try to get length and then when we get too close to the right switch to the left // try to get length and then when we get too close to the right switch to the left
var len = o.offsetWidth; var len = o.offsetWidth;
var x; var x;
if (sliderX > cWidth/2) { if ( sliderX > cWidth/2 ) {
x=sliderX - len - 10; x = sliderX - len - 10;
} else { } else {
x=sliderX + 10; x = sliderX + 10;
} }
o.style.left=x.toString() + "px"; o.style.left = x.toString() + "px";
} }
// This displays (or not) the left/right limits depending on how close the slider is. // This displays (or not) the left/right limits depending on how close the slider is.
@ -350,7 +397,7 @@ function drawSliderOnGraph(val) {
} }
function drawGraph() { function drawGraph() {
var divWidth=$('timelinediv').clientWidth; var divWidth = $('timelinediv').clientWidth;
canvas.width = cWidth = divWidth; // Let it float and determine width (it should be sized a bit smaller percentage of window) canvas.width = cWidth = divWidth; // Let it float and determine width (it should be sized a bit smaller percentage of window)
cHeight = parseInt(window.innerHeight * 0.10); cHeight = parseInt(window.innerHeight * 0.10);
if ( cHeight < numMonitors * 20 ) { if ( cHeight < numMonitors * 20 ) {
@ -359,14 +406,14 @@ function drawGraph() {
canvas.height = cHeight; canvas.height = cHeight;
if ( Object.keys(events).length == 0 ) { if ( events && ( Object.keys(events).length == 0 ) ) {
ctx.globalAlpha=1; ctx.globalAlpha = 1;
ctx.font= "40px Georgia"; ctx.font = "40px Georgia";
ctx.fillStyle="white"; ctx.fillStyle = "white";
var t="No data found in range - choose differently"; var t = "No data found in range - choose differently";
var l=ctx.measureText(t).width; var l = ctx.measureText(t).width;
ctx.fillText(t, (cWidth - l)/2, cHeight-10); ctx.fillText(t, (cWidth - l)/2, cHeight-10);
underSlider=undefined; underSlider = undefined;
return; return;
} }
var rowHeight = parseInt(cHeight / (numMonitors + 1) ); // Leave room for a scale of some sort var rowHeight = parseInt(cHeight / (numMonitors + 1) ); // Leave room for a scale of some sort
@ -400,14 +447,15 @@ function drawGraph() {
} // end foreach frame } // end foreach frame
} // end foreach Event } // end foreach Event
for (var i=0; i<numMonitors; i++) { for ( var i=0; i < numMonitors; i++ ) {
// Note that this may be a sparse array // Note that this may be a sparse array
ctx.font= parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia"; ctx.font = parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
ctx.fillStyle="white"; ctx.fillStyle = "white";
ctx.globalAlpha=1; ctx.globalAlpha = 1;
ctx.fillText(monitorName[monitorPtr[i]], 0, (i + 1 - (1 - timeLabelsFractOfRow)/2 ) * rowHeight ); // This should roughly center font in row // This should roughly center font in row
ctx.fillText(monitorName[monitorPtr[i]], 0, (i + 1 - (1 - timeLabelsFractOfRow)/2 ) * rowHeight);
} }
underSlider=undefined; // flag we don't have a slider cached underSlider = undefined; // flag we don't have a slider cached
drawSliderOnGraph(currentTimeSecs); drawSliderOnGraph(currentTimeSecs);
return; return;
} // end function drawGraph } // end function drawGraph
@ -540,6 +588,7 @@ function secs2inputstr(s) {
} }
return m.format("YYYY-MM-DDTHH:mm:ss"); return m.format("YYYY-MM-DDTHH:mm:ss");
} }
function secs2dbstr(s) { function secs2dbstr(s) {
if ( ! parseInt(s) ) { if ( ! parseInt(s) ) {
console.log("Invalid value for " + s + " seconds"); console.log("Invalid value for " + s + " seconds");
@ -567,11 +616,11 @@ function showScale(newscale) {
function setScale(newscale) { function setScale(newscale) {
// makes actual change // makes actual change
showScale(newscale); showScale(newscale);
for (var i=0; i<numMonitors; i++) { for ( var i=0; i < numMonitors; i++ ) {
monitorCanvasObj[monitorPtr[i]].width=monitorWidth[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale; monitorCanvasObj[monitorPtr[i]].width = monitorWidth[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
monitorCanvasObj[monitorPtr[i]].height=monitorHeight[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale; monitorCanvasObj[monitorPtr[i]].height = monitorHeight[monitorPtr[i]]*monitorNormalizeScale[monitorPtr[i]]*monitorZoomScale[monitorPtr[i]]*newscale;
} }
currentScale=newscale; currentScale = newscale;
} }
function showSpeed(val) { function showSpeed(val) {
@ -579,14 +628,16 @@ function showSpeed(val) {
$('speedslideroutput').innerHTML = parseFloat(speeds[val]).toFixed(2).toString() + " x"; $('speedslideroutput').innerHTML = parseFloat(speeds[val]).toFixed(2).toString() + " x";
} }
function setSpeed( speed_index ) { function setSpeed(speed_index) {
if ( liveMode == 1 ) return; // we shouldn't actually get here but just in case if ( liveMode == 1 ) {
console.log("setSpeed in liveMode?");
return; // we shouldn't actually get here but just in case
}
currentSpeed = parseFloat(speeds[speed_index]); currentSpeed = parseFloat(speeds[speed_index]);
speedIndex = speed_index; speedIndex = speed_index;
playSecsperInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000; playSecsPerInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000;
showSpeed(speed_index); showSpeed(speed_index);
if ( timerInterval != currentDisplayInterval ) timerFire(); // if the timer isn't firing we need to trigger it to update timerFire();
//if ( (timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
} }
function setLive(value) { function setLive(value) {
@ -614,31 +665,31 @@ function clicknav(minSecs, maxSecs, live) {// we use the current time if we can
if ( maxSecs > now ) { if ( maxSecs > now ) {
maxSecs = parseInt(now); maxSecs = parseInt(now);
} }
maxStr="&maxTime=" + secs2inputstr(maxSecs); maxStr = "&maxTime=" + secs2inputstr(maxSecs);
$('maxTime').value = secs2inputstr(maxSecs); $('maxTime').value = secs2inputstr(maxSecs);
} }
if ( minSecs > 0 ) { if ( minSecs > 0 ) {
$('minTime').value = secs2inputstr(minSecs); $('minTime').value = secs2inputstr(minSecs);
minStr="&minTime=" + secs2inputstr(minSecs); minStr = "&minTime=" + secs2inputstr(minSecs);
} }
if ( maxSecs == 0 && minSecs == 0 ) { if ( maxSecs == 0 && minSecs == 0 ) {
minStr="&minTime=01/01/1950T12:00:00"; minStr = "&minTime=01/01/1950T12:00:00";
maxStr="&maxTime=12/31/2035T12:00:00"; maxStr = "&maxTime=12/31/2035T12:00:00";
} }
var intervalStr="&displayinterval=" + currentDisplayInterval.toString(); var intervalStr="&displayinterval=" + currentDisplayInterval.toString();
if ( minSecs && maxSecs ) { if ( minSecs && maxSecs ) {
if ( currentTimeSecs > minSecs && currentTimeSecs < maxSecs ) { // make sure time is in the new range if ( currentTimeSecs > minSecs && currentTimeSecs < maxSecs ) { // make sure time is in the new range
currentStr="&current=" + secs2dbstr(currentTimeSecs); currentStr = "&current=" + secs2dbstr(currentTimeSecs);
} }
} }
var liveStr="&live=0"; var liveStr = "&live=0";
if ( live == 1 ) { if ( live == 1 ) {
liveStr="&live=1"; liveStr = "&live=1";
} }
var zoomStr=""; var zoomStr = "";
for ( var i=0; i < numMonitors; i++ ) { for ( var i = 0; i < numMonitors; i++ ) {
if ( monitorZoomScale[monitorPtr[i]] < 0.99 || monitorZoomScale[monitorPtr[i]] > 1.01 ) { // allow for some up/down changes and just treat as 1 of almost 1 if ( monitorZoomScale[monitorPtr[i]] < 0.99 || monitorZoomScale[monitorPtr[i]] > 1.01 ) { // allow for some up/down changes and just treat as 1 of almost 1
zoomStr += "&z" + monitorPtr[i].toString() + "=" + monitorZoomScale[monitorPtr[i]].toFixed(2); zoomStr += "&z" + monitorPtr[i].toString() + "=" + monitorZoomScale[monitorPtr[i]].toFixed(2);
} }
@ -685,7 +736,7 @@ function click_panright() {
clicknav(minTimeSecs, maxTimeSecs, 0); clicknav(minTimeSecs, maxTimeSecs, 0);
} }
function click_download() { function click_download() {
createPopup( '?view=download', 'zmDownload', 'download' ); createPopup('?view=download', 'zmDownload', 'download');
} }
function click_all_events() { function click_all_events() {
clicknav(0, 0, 0); clicknav(0, 0, 0);
@ -704,7 +755,6 @@ function compSize(a, b) { // sort array by some size parameter - height seems t
else return 1; else return 1;
} }
function maxfit2(divW, divH) { function maxfit2(divW, divH) {
var bestFitX=[]; // how we arranged the so-far best match var bestFitX=[]; // how we arranged the so-far best match
var bestFitX2=[]; var bestFitX2=[];
@ -736,7 +786,7 @@ function maxfit2(divW, divH) {
function doesItFit(x, y, w, h, d) { // does block (w,h) fit at position (x,y) relative to edge and other nodes already done (0..d) function doesItFit(x, y, w, h, d) { // does block (w,h) fit at position (x,y) relative to edge and other nodes already done (0..d)
if (x+w>=divW) return 0; if (x+w>=divW) return 0;
if (y+h>=divH) return 0; if (y+h>=divH) return 0;
for (var i=0; i<=d; i++) { for ( var i=0; i <= d; i++ ) {
if ( !( thisX[i]>x+w-1 || thisX2[i] < x || thisY[i] > y+h-1 || thisY2[i] < y ) ) return 0; if ( !( thisX[i]>x+w-1 || thisX2[i] < x || thisY[i] > y+h-1 || thisY2[i] < y ) ) return 0;
} }
return 1; // it's OK return 1; // it's OK
@ -818,16 +868,16 @@ function showOneMonitor(monId) {
// We know the monitor, need to determine the event based on current time // We know the monitor, need to determine the event based on current time
var url; var url;
if ( liveMode != 0 ) { if ( liveMode != 0 ) {
url="?view=watch&mid=" + monId.toString(); url = '?view=watch&mid=' + monId.toString();
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] ); createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId]);
} else { } else {
var Frame = getFrame( monId, currentTimeSecs ); var Frame = getFrame(monId, currentTimeSecs);
if ( Frame ) { if ( Frame ) {
url="?view=event&eid=" + Frame.EventId + '&fid=' +Frame.FrameId; url = '?view=event&eid=' + Frame.EventId + '&fid=' + Frame.FrameId;
createPopup(url, 'zmEvent', 'event', monitorWidth[monId], monitorHeight[monId]); createPopup(url, 'zmEvent', 'event', monitorWidth[monId], monitorHeight[monId]);
} else { } else {
url="?view=watch&mid=" + monId.toString(); url = '?view=watch&mid=' + monId.toString();
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] ); createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId]);
} }
} // end if live/events } // end if live/events
} }
@ -900,23 +950,24 @@ function initPage() {
for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) { for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) {
var monId = monitorPtr[i]; var monId = monitorPtr[i];
if ( ! monId ) continue; if ( !monId ) continue;
monitorCanvasObj[monId] = $('Monitor'+monId ); monitorCanvasObj[monId] = $('Monitor'+monId);
if ( ! monitorCanvasObj[monId] ) { if ( !monitorCanvasObj[monId] ) {
alert("Couldn't find DOM element for Monitor"+monId + "monitorPtr.length="+len); alert("Couldn't find DOM element for Monitor" + monId + "monitorPtr.length=" + len);
} else { } else {
monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d'); monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d');
var imageObject = monitorImageObject[monId] = new Image(); var imageObject = monitorImageObject[monId] = new Image();
imageObject.monId = monId; imageObject.monId = monId;
imageObject.onload = function() { imageObject.onload = function() {
imagedone(this, this.monId, true ); imagedone(this, this.monId, true);
}; };
imageObject.onerror = function() { imageObject.onerror = function() {
imagedone(this, this.monId, false ); imagedone(this, this.monId, false);
}; };
loadImage2Monitor( monId, monitorImageURL[monId] ); loadImage2Monitor(monId, monitorImageURL[monId]);
} }
} } // end foreach monitor
if ( !liveMode ) { if ( !liveMode ) {
canvas = $("timeline"); canvas = $("timeline");
@ -960,12 +1011,34 @@ function initPage() {
maxDate: +0, maxDate: +0,
constrainInput: false, constrainInput: false,
onClose: function(newDate, oldData) { onClose: function(newDate, oldData) {
if (newDate !== oldData.lastVal) { if ( newDate !== oldData.lastVal ) {
changeDateTime(); changeDateTime();
} }
} }
}); });
$j('#scaleslider').bind('change', function() {
setScale(this.value);
});
$j('#scaleslider').bind('input', function() {
showScale(this.value);
});
$j('#speedslider').bind('change', function() {
setSpeed(this.value);
});
$j('#speedslider').bind('input', function() {
showSpeed(this.value);
});
$j('#liveButton').bind('click', function() {
setLive(1-liveMode);
});
$j('#fit').bind('click', function() {
setFit(1-fitMode);
});
$j('#archive_status').bind('change', function() {
this.form.submit();
});
} }
window.addEventListener("resize", redrawScreen, {passive: true}); window.addEventListener("resize", redrawScreen, {passive: true});
// Kick everything off // Kick everything off
window.addEventListener( 'DOMContentLoaded', initPage ); window.addEventListener('DOMContentLoaded', initPage);

View File

@ -46,7 +46,7 @@ if ( !$liveMode ) {
$EventsById = array(); $EventsById = array();
while( $event = $result->fetch(PDO::FETCH_ASSOC) ) { while ( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
$event_id = $event['Id']; $event_id = $event['Id'];
$EventsById[$event_id] = $event; $EventsById[$event_id] = $event;
} }
@ -55,23 +55,26 @@ if ( !$liveMode ) {
if ( $result = dbQuery($framesSql) ) { if ( $result = dbQuery($framesSql) ) {
$next_frame = null; $next_frame = null;
while( $frame = $result->fetch(PDO::FETCH_ASSOC) ) { while ( $frame = $result->fetch(PDO::FETCH_ASSOC) ) {
$event_id = $frame['EventId']; $event_id = $frame['EventId'];
$event = &$EventsById[$event_id]; $event = &$EventsById[$event_id];
$frame['TimeStampSecs'] = $event['StartTimeSecs'] + $frame['Delta']; $frame['TimeStampSecs'] = $event['StartTimeSecs'] + $frame['Delta'];
if ( !isset($event['FramesById']) ) { if ( !isset($event['FramesById']) ) {
// Please note that this is the last frame as we sort DESC
$event['FramesById'] = array(); $event['FramesById'] = array();
$frame['NextTimeStampSecs'] = 0; $frame['NextTimeStampSecs'] = $event['EndTime'];
} else { } else {
$frame['NextTimeStampSecs'] = $next_frames[$frame['EventId']]['TimeStampSecs']; $frame['NextTimeStampSecs'] = $next_frames[$frame['EventId']]['TimeStampSecs'];
$frame['NextFrameId'] = $next_frames[$frame['EventId']]['FrameId']; $frame['NextFrameId'] = $next_frames[$frame['EventId']]['Id'];
} }
$event['FramesById'] += array( $frame['Id']=>$frame ); $event['FramesById'] += array($frame['Id']=>$frame);
$next_frames[$frame['EventId']] = $frame; $next_frames[$frame['EventId']] = $frame;
} }
} }
$events_by_monitor_id = array();
echo "var events = {\n"; echo "var events = {\n";
foreach ( $EventsById as $event_id=>$event ) { foreach ( $EventsById as $event_id=>$event ) {
@ -82,7 +85,7 @@ if ( !$liveMode ) {
if ( !$minTimeSecs or $minTimeSecs > $StartTimeSecs ) $minTimeSecs = $StartTimeSecs; if ( !$minTimeSecs or $minTimeSecs > $StartTimeSecs ) $minTimeSecs = $StartTimeSecs;
if ( !$maxTimeSecs or $maxTimeSecs < $EndTimeSecs ) $maxTimeSecs = $EndTimeSecs; if ( !$maxTimeSecs or $maxTimeSecs < $EndTimeSecs ) $maxTimeSecs = $EndTimeSecs;
$event_json = json_encode($event, JSON_PRETTY_PRINT); $event_json = json_encode($event, JSON_PRETTY_PRINT|JSON_NUMERIC_CHECK);
echo " $event_id : $event_json,\n"; echo " $event_id : $event_json,\n";
$index = $index + 1; $index = $index + 1;
@ -91,8 +94,14 @@ if ( !$liveMode ) {
$maxScore = $event['MaxScore']; $maxScore = $event['MaxScore'];
$anyAlarms = true; $anyAlarms = true;
} }
} if ( !isset($events_by_monitor_id[$event['MonitorId']]) )
echo " };\n"; $events_by_monitor_id[$event['MonitorId']] = array();
array_push($events_by_monitor_id[$event['MonitorId']], $event_id);
} # end foreach Event
echo ' };
var events_by_monitor_id = '.json_encode($events_by_monitor_id, JSON_NUMERIC_CHECK)."\n";
// if there is no data set the min/max to the passed in values // if there is no data set the min/max to the passed in values
if ( $index == 0 ) { if ( $index == 0 ) {

View File

@ -103,6 +103,7 @@ if ( ! $monitor ) {
'ReturnLocation' => -1, 'ReturnLocation' => -1,
'ReturnDelay' => '', 'ReturnDelay' => '',
'SectionLength' => 600, 'SectionLength' => 600,
'MinSectionLength' => 10,
'FrameSkip' => 0, 'FrameSkip' => 0,
'MotionFrameSkip' => 0, 'MotionFrameSkip' => 0,
'EventPrefix' => 'Event-', 'EventPrefix' => 'Event-',
@ -657,6 +658,7 @@ if ( $tab != 'misc' ) {
?> ?>
<input type="hidden" name="newMonitor[EventPrefix]" value="<?php echo validHtmlStr($monitor->EventPrefix()) ?>"/> <input type="hidden" name="newMonitor[EventPrefix]" value="<?php echo validHtmlStr($monitor->EventPrefix()) ?>"/>
<input type="hidden" name="newMonitor[SectionLength]" value="<?php echo validHtmlStr($monitor->SectionLength()) ?>"/> <input type="hidden" name="newMonitor[SectionLength]" value="<?php echo validHtmlStr($monitor->SectionLength()) ?>"/>
<input type="hidden" name="newMonitor[MinSectionLength]" value="<?php echo validHtmlStr($monitor->MinSectionLength()) ?>"/>
<input type="hidden" name="newMonitor[FrameSkip]" value="<?php echo validHtmlStr($monitor->FrameSkip()) ?>"/> <input type="hidden" name="newMonitor[FrameSkip]" value="<?php echo validHtmlStr($monitor->FrameSkip()) ?>"/>
<input type="hidden" name="newMonitor[MotionFrameSkip]" value="<?php echo validHtmlStr($monitor->MotionFrameSkip()) ?>"/> <input type="hidden" name="newMonitor[MotionFrameSkip]" value="<?php echo validHtmlStr($monitor->MotionFrameSkip()) ?>"/>
<input type="hidden" name="newMonitor[AnalysisUpdateDelay]" value="<?php echo validHtmlStr($monitor->AnalysisUpdateDelay()) ?>"/> <input type="hidden" name="newMonitor[AnalysisUpdateDelay]" value="<?php echo validHtmlStr($monitor->AnalysisUpdateDelay()) ?>"/>
@ -1024,6 +1026,13 @@ if ( $monitor->Type() == 'Local' ) {
<?php echo translate('seconds')?> <?php echo translate('seconds')?>
</td> </td>
</tr> </tr>
<tr>
<td><?php echo translate('MinSectionlength') ?></td>
<td>
<input type="number" name="newMonitor[MinSectionLength]" value="<?php echo validHtmlStr($monitor->MinSectionLength()) ?>"/>
<?php echo translate('seconds')?>
</td>
</tr>
<tr> <tr>
<td><?php echo translate('FrameSkip') ?></td> <td><?php echo translate('FrameSkip') ?></td>
<td> <td>

View File

@ -43,6 +43,7 @@ $widths = array(
$heights = array( $heights = array(
'auto' => 'auto', 'auto' => 'auto',
'240px' => '240px', '240px' => '240px',
'320px' => '320px',
'480px' => '480px', '480px' => '480px',
'720px' => '720px', '720px' => '720px',
'1080px' => '1080px', '1080px' => '1080px',
@ -256,7 +257,6 @@ foreach ( $monitors as $monitor ) {
if ( $scale ) { if ( $scale ) {
limitPoints($row['Points'], 0, 0, $monitor->Width(), $monitor->Height()); limitPoints($row['Points'], 0, 0, $monitor->Width(), $monitor->Height());
scalePoints($row['Points'], $scale);
} else { } else {
limitPoints($row['Points'], 0, 0, limitPoints($row['Points'], 0, 0,
( $width ? $width-1 : $monitor->Width()-1 ), ( $width ? $width-1 : $monitor->Width()-1 ),
@ -269,7 +269,7 @@ foreach ( $monitors as $monitor ) {
} // end foreach Zone } // end foreach Zone
?> ?>
<svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="position:absolute; top: 0; left: 0; background: none; width: <?php echo $width ?>px; height: <?php echo $height ?>px;"> <svg class="zones" id="zones<?php echo $monitor->Id() ?>" style="position:absolute; top: 0; left: 0; background: none; width: 100%; height: 100%;" viewBox="0 0 <?php echo $monitor->Width() ?> <?php echo $monitor->Height() ?>" preserveAspectRatio="none">
<?php <?php
foreach( array_reverse($zones) as $zone ) { foreach( array_reverse($zones) as $zone ) {
echo '<polygon points="'. $zone['AreaCoords'] .'" class="'. $zone['Type'].'" />'; echo '<polygon points="'. $zone['AreaCoords'] .'" class="'. $zone['Type'].'" />';

View File

@ -64,7 +64,7 @@ if ( isset($_REQUEST['filter']) ) {
$filter = $_REQUEST['filter']; $filter = $_REQUEST['filter'];
} else { } else {
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) { if ( isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && (count($displayMonitors) != 0) ) {
$filter = array( $filter = array(
'Query' => array( 'Query' => array(
'terms' => array( 'terms' => array(
@ -77,10 +77,10 @@ if ( isset($_REQUEST['filter']) ) {
$filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and')); $filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and'));
} else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) { } else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) {
# this should be redundant # this should be redundant
for ($i=0; $i < count($displayMonitors); $i++) { for ( $i = 0; $i < count($displayMonitors); $i++ ) {
if ($i == '0') { if ( $i == '0' ) {
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1'); $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1');
} else if ($i == (count($displayMonitors)-1)) { } else if ( $i == (count($displayMonitors)-1) ) {
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1'); $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1');
} else { } else {
$filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or'); $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or');
@ -118,7 +118,7 @@ $eventsSql = 'SELECT
// Note that the delta value seems more accurate than the time stamp for some reason. // Note that the delta value seems more accurate than the time stamp for some reason.
$framesSql = ' $framesSql = '
SELECT Id, FrameId, EventId, TimeStamp, UNIX_TIMESTAMP(TimeStamp) AS TimeStampSecs, Score, Delta SELECT Id, FrameId, EventId, TimeStamp, UNIX_TIMESTAMP(TimeStamp) AS TimeStampSecs, Score, Delta, Type
FROM Frames FROM Frames
WHERE EventId IN (SELECT E.Id FROM Events AS E WHERE 1>0 WHERE EventId IN (SELECT E.Id FROM Events AS E WHERE 1>0
'; ';
@ -126,9 +126,9 @@ $framesSql = '
// This program only calls itself with the time range involved -- it does all monitors (the user can see, in the called group) all the time // This program only calls itself with the time range involved -- it does all monitors (the user can see, in the called group) all the time
$monitor_ids_sql = ''; $monitor_ids_sql = '';
if ( ! empty($user['MonitorIds']) ) { if ( !empty($user['MonitorIds']) ) {
$eventsSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')'; $eventsSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
$framesSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')'; $framesSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
} }
if ( count($selected_monitor_ids) ) { if ( count($selected_monitor_ids) ) {
$monitor_ids_sql = ' IN (' . implode(',',$selected_monitor_ids).')'; $monitor_ids_sql = ' IN (' . implode(',',$selected_monitor_ids).')';
@ -173,7 +173,7 @@ if ( (strtotime($maxTime) - strtotime($minTime))/(365*24*3600) > 30 ) {
} }
$fitMode = 1; $fitMode = 1;
if (isset($_REQUEST['fit']) && $_REQUEST['fit']=='0' ) if ( isset($_REQUEST['fit']) && ($_REQUEST['fit'] == '0') )
$fitMode = 0; $fitMode = 0;
if ( isset($_REQUEST['scale']) ) if ( isset($_REQUEST['scale']) )
@ -200,7 +200,7 @@ if ( isset($_REQUEST['current']) )
$defaultCurrentTime = validHtmlStr($_REQUEST['current']); $defaultCurrentTime = validHtmlStr($_REQUEST['current']);
$liveMode = 1; // default to live $liveMode = 1; // default to live
if ( isset($_REQUEST['live']) && $_REQUEST['live']=='0' ) if ( isset($_REQUEST['live']) && ($_REQUEST['live'] == '0') )
$liveMode = 0; $liveMode = 0;
$initialDisplayInterval = 1000; $initialDisplayInterval = 1000;
@ -236,82 +236,80 @@ foreach( $displayMonitors as $row ) {
// These are zoom ranges per visible monitor // These are zoom ranges per visible monitor
xhtmlHeaders(__FILE__, translate('MontageReview') ); xhtmlHeaders(__FILE__, translate('MontageReview') );
getBodyTopHTML();
?> ?>
<body> <div id="page">
<div id="page">
<?php echo getNavBarHTML() ?> <?php echo getNavBarHTML() ?>
<form id="montagereview_form" action="?" method="get"> <form id="montagereview_form" action="?" method="get">
<input type="hidden" name="view" value="montagereview"/> <input type="hidden" name="view" value="montagereview"/>
<div id="header">&nbsp;&nbsp; <div id="header">&nbsp;&nbsp;
<a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right"></span></a> <a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right"></span></a>
<div id="flipMontageHeader"> <div id="flipMontageHeader">
<?php echo $filter_bar ?> <?php echo $filter_bar ?>
<div id="DateTimeDiv"> <div id="DateTimeDiv">
<input type="text" name="minTime" id="minTime" value="<?php echo preg_replace('/T/', ' ', $minTime ) ?>"/> to <input type="text" name="minTime" id="minTime" value="<?php echo preg_replace('/T/', ' ', $minTime ) ?>"/> to
<input type="text" name="maxTime" id="maxTime" value="<?php echo preg_replace('/T/', ' ', $maxTime ) ?>"/> <input type="text" name="maxTime" id="maxTime" value="<?php echo preg_replace('/T/', ' ', $maxTime ) ?>"/>
</div> </div>
<div id="ScaleDiv"> <div id="ScaleDiv">
<label for="scaleslider"><?php echo translate('Scale')?></label> <label for="scaleslider"><?php echo translate('Scale')?></label>
<input id="scaleslider" type="range" min="0.1" max="1.0" value="<?php echo $defaultScale ?>" step="0.10" onchange="setScale(this.value);" oninput="showScale(this.value);"/> <input id="scaleslider" type="range" min="0.1" max="1.0" value="<?php echo $defaultScale ?>" step="0.10"/>
<span id="scaleslideroutput"><?php echo number_format((float)$defaultScale,2,'.','')?> x</span> <span id="scaleslideroutput"><?php echo number_format((float)$defaultScale,2,'.','')?> x</span>
</div> </div>
<div id="SpeedDiv"> <div id="SpeedDiv">
<label for="speedslider"><?php echo translate('Speed') ?></label> <label for="speedslider"><?php echo translate('Speed') ?></label>
<input id="speedslider" type="range" min="0" max="<?php echo count($speeds)-1?>" value="<?php echo $speedIndex ?>" step="1" onchange="setSpeed(this.value);" oninput="showSpeed(this.value);"/> <input id="speedslider" type="range" min="0" max="<?php echo count($speeds)-1?>" value="<?php echo $speedIndex ?>" step="1"/>
<span id="speedslideroutput"><?php echo $speeds[$speedIndex] ?> fps</span> <span id="speedslideroutput"><?php echo $speeds[$speedIndex] ?> fps</span>
</div> </div>
<div id="ButtonsDiv"> <div id="ButtonsDiv">
<button type="button" id="panleft" data-on-click="click_panleft" >&lt; <?php echo translate('Pan') ?></button> <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="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="zoomout" data-on-click="click_zoomout" ><?php echo translate('Out -') ?></button>
<button type="button" id="lasteight" data-on-click="click_lastEight" ><?php echo translate('8 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="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> <button type="button" id="allof" data-on-click="click_all_events" ><?php echo translate('All Events') ?></button>
<button type="button" id="liveButton" onclick="setLive(1-liveMode); console.log('live');return false;"><?php echo translate('Live') ?></button> <button type="button" id="liveButton"><?php echo translate('Live') ?></button>
<button type="button" id="fit" onclick="setFit(1-fitMode);" ><?php echo translate('Fit') ?></button> <button type="button" id="fit" ><?php echo translate('Fit') ?></button>
<button type="button" id="panright" data-on-click="click_panright" ><?php echo translate('Pan') ?> &gt;</button> <button type="button" id="panright" data-on-click="click_panright" ><?php echo translate('Pan') ?> &gt;</button>
<?php <?php
if ( (!$liveMode) and (count($displayMonitors) != 0) ) { if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
?> ?>
<button type="button" id="downloadVideo" data-on-click="click_download"><?php echo translate('Download Video') ?></button> <button type="button" id="downloadVideo" data-on-click="click_download"><?php echo translate('Download Video') ?></button>
<?php <?php
} }
?> ?>
</div> </div>
<?php if ( !$liveMode ) { ?> <?php if ( !$liveMode ) { ?>
<div id="eventfilterdiv" class="input-group"> <div id="eventfilterdiv" class="input-group">
<label>Archive Status <label>Archive Status
<?php echo htmlSelect( <?php echo htmlSelect(
'archive_status', 'archive_status',
array( array(
'' => translate('All'), '' => translate('All'),
'Archived' => translate('Archived'), 'Archived' => translate('Archived'),
'Unarchived' => translate('UnArchived'), 'Unarchived' => translate('UnArchived'),
), ),
( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : ''), ( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : '')
array('onchange'=>'this.form.submit();') ); ?>
); </label>
?> </div>
</label>
</div>
<?php } // end if !live ?> <?php } // end if !live ?>
<div id="timelinediv"> <div id="timelinediv">
<canvas id="timeline"></canvas> <canvas id="timeline"></canvas>
<span id="scrubleft"></span> <span id="scrubleft"></span>
<span id="scrubright"></span> <span id="scrubright"></span>
<span id="scruboutput"></span> <span id="scruboutput"></span>
</div> </div>
</div> </div><!--flipMontageHeader-->
</div> <input type="hidden" name="fit" value="<?php echo $fitMode ?>"/>
<input type="hidden" name="fit" value="<?php echo $fitMode ?>"/> <input type="hidden" name="live" value="<?php echo $liveMode ?>"/>
<input type="hidden" name="live" value="<?php echo $liveMode ?>"/> </div><!--header-->
</div> </form>
</form>
<div id="monitors"> <div id="monitors">
<?php <?php
// Monitor images - these had to be loaded after the monitors used were determined (after loading events) // Monitor images - these had to be loaded after the monitors used were determined (after loading events)
foreach ( $monitors as $m ) { foreach ( $monitors as $m ) {
echo '<canvas title="'.$m->Id().' ' .$m->Name().'" width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" monitor_id="'.$m->Id().'">No Canvas Support!!</canvas>'; echo '<canvas title="'.$m->Id().' ' .$m->Name().'" width="' . $m->Width() * $defaultScale . '" height="' . $m->Height() * $defaultScale . '" id="Monitor' . $m->Id() . '" style="border:1px solid ' . $m->WebColour() . '" monitor_id="'.$m->Id().'">No Canvas Support!!</canvas>
';
} }
?> ?>
</div> </div>

View File

@ -86,7 +86,7 @@ function probeCameras( $localIp ) {
function probeProfiles( $device_ep, $soapversion, $username, $password ) { function probeProfiles( $device_ep, $soapversion, $username, $password ) {
$profiles = array(); $profiles = array();
if ( $lines = @execONVIF( "profiles $device_ep $soapversion $username $password" ) ) { if ( $lines = @execONVIF("profiles $device_ep $soapversion $username $password") ) {
foreach ( $lines as $line ) { foreach ( $lines as $line ) {
$line = rtrim( $line ); $line = rtrim( $line );
if ( preg_match('|^(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+)\s*$|', $line, $matches) ) { if ( preg_match('|^(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+),\s*(.+)\s*$|', $line, $matches) ) {
@ -234,6 +234,7 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
// $monitor['MaxFPS'] = $profile['MaxFPS']; // $monitor['MaxFPS'] = $profile['MaxFPS'];
// $monitor['AlarmMaxFPS'] = $profile['AlarmMaxFPS']; // $monitor['AlarmMaxFPS'] = $profile['AlarmMaxFPS'];
$monitor['Path'] = $profile['Path']; $monitor['Path'] = $profile['Path'];
$monitor['ControlDevice'] = $profile['Profile']; # Netcat needs this for ProfileToken
$sourceDesc = base64_encode(json_encode($monitor)); $sourceDesc = base64_encode(json_encode($monitor));
$profiles[$sourceDesc] = $sourceString; $profiles[$sourceDesc] = $sourceString;
} }