Merge branch 'master' of github.com:/ZoneMinder/zoneminder
This commit is contained in:
commit
0dbe48fb31
|
@ -5,9 +5,3 @@
|
|||
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
|
||||
path = web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||
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
|
||||
|
|
|
@ -876,7 +876,7 @@ ADD_MANPAGE_TARGET()
|
|||
# build a bcrypt static library
|
||||
set(BUILD_SHARED_LIBS_SAVED "${BUILD_SHARED_LIBS}")
|
||||
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}")
|
||||
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -479,6 +479,7 @@ CREATE TABLE `Monitors` (
|
|||
`StreamReplayBuffer` int(10) unsigned NOT NULL default '1000',
|
||||
`AlarmFrameCount` smallint(5) unsigned NOT NULL default '1',
|
||||
`SectionLength` int(10) unsigned NOT NULL default '600',
|
||||
`MinSectionLength` int(10) unsigned NOT NULL default '10',
|
||||
`FrameSkip` smallint(5) unsigned NOT NULL default '0',
|
||||
`MotionFrameSkip` smallint(5) unsigned NOT NULL default '0',
|
||||
`AnalysisFPSLimit` decimal(5,2) default NULL,
|
||||
|
|
|
@ -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;
|
|
@ -23,7 +23,7 @@
|
|||
%global _hardened_build 1
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.33.8
|
||||
Version: 1.33.9
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
|
@ -411,6 +411,9 @@ EOF
|
|||
%dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload
|
||||
|
||||
%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
|
||||
- Bump to 1.33.8 Development
|
||||
|
||||
|
|
|
@ -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 /var/tmp/zm 0755 www-data www-data
|
||||
d /var/cache/zoneminder/cache 0755 www-data www-data
|
||||
|
|
|
@ -96,8 +96,7 @@ sub open {
|
|||
$self->{state} = 'open';
|
||||
}
|
||||
|
||||
sub parseControlAddress
|
||||
{
|
||||
sub parseControlAddress {
|
||||
my $controlAddress = shift;
|
||||
my ($usernamepassword, $addressport) = split /@/, $controlAddress;
|
||||
if ( !defined $addressport ) {
|
||||
|
@ -105,7 +104,7 @@ sub parseControlAddress
|
|||
$addressport = $usernamepassword;
|
||||
} else {
|
||||
my ($username , $password) = split /:/, $usernamepassword;
|
||||
%identity = (username => "$username", password => "$password");
|
||||
%identity = (username => $username, password => $password);
|
||||
}
|
||||
($address, $port) = split /:/, $addressport;
|
||||
}
|
||||
|
@ -118,12 +117,11 @@ sub digestBase64
|
|||
return encode_base64($shaGenerator->digest, "");
|
||||
}
|
||||
|
||||
sub authentificationHeader
|
||||
{
|
||||
sub authentificationHeader {
|
||||
my ($username, $password) = @_;
|
||||
my $nonce;
|
||||
$nonce .= chr(int(rand(254))) for (0 .. 20);
|
||||
my $nonceBase64 = encode_base64($nonce, "");
|
||||
my $nonceBase64 = encode_base64($nonce, '');
|
||||
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>';
|
||||
|
@ -160,7 +158,7 @@ sub sendCmd {
|
|||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
} 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;
|
||||
}
|
||||
|
@ -236,7 +234,7 @@ sub moveConDown {
|
|||
Debug('Move Down');
|
||||
my $self = shift;
|
||||
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"';
|
||||
$self->sendCmd($cmd, $msg, $content_type);
|
||||
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
|
||||
|
@ -316,7 +314,7 @@ sub moveConUpLeft {
|
|||
Debug('Move Diagonally Up Left');
|
||||
my $self = shift;
|
||||
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"';
|
||||
$self->sendCmd($cmd, $msg, $content_type);
|
||||
$self->autoStop($self->{Monitor}->{AutoStopTimeout});
|
||||
|
|
|
@ -214,6 +214,7 @@ sub zmDbGetMonitor {
|
|||
return undef;
|
||||
}
|
||||
my $monitor = $sth->fetchrow_hashref();
|
||||
$sth->finish();
|
||||
return $monitor;
|
||||
}
|
||||
|
||||
|
@ -240,6 +241,7 @@ sub zmDbGetMonitorAndControl {
|
|||
return undef;
|
||||
}
|
||||
my $monitor = $sth->fetchrow_hashref();
|
||||
$sth->finish();
|
||||
return $monitor;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,15 +72,15 @@ sub find {
|
|||
$sql .= ' WHERE ' . join(' AND ', @sql_filters ) if @sql_filters;
|
||||
$sql .= ' LIMIT ' . $sql_filters{limit} if $sql_filters{limit};
|
||||
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
||||
my $res = $sth->execute( @sql_values )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());
|
||||
my $res = $sth->execute(@sql_values)
|
||||
or Fatal("Can't execute '$sql': ".$sth->errstr());
|
||||
|
||||
my @results;
|
||||
|
||||
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;
|
||||
} # end while
|
||||
$sth->finish();
|
||||
|
@ -98,7 +98,7 @@ sub Execute {
|
|||
my $sql = $self->Sql(undef);
|
||||
|
||||
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;
|
||||
}
|
||||
if ( $self->{HasDiskBlocks} ) {
|
||||
|
@ -111,16 +111,16 @@ sub Execute {
|
|||
}
|
||||
|
||||
Debug("Filter::Execute SQL ($sql)");
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql)
|
||||
or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr());
|
||||
my $res = $sth->execute();
|
||||
if ( !$res ) {
|
||||
Error( "Can't execute filter '$sql', ignoring: ".$sth->errstr() );
|
||||
Error("Can't execute filter '$sql', ignoring: ".$sth->errstr());
|
||||
return;
|
||||
}
|
||||
my @results;
|
||||
|
||||
while( my $event = $sth->fetchrow_hashref() ) {
|
||||
while ( my $event = $sth->fetchrow_hashref() ) {
|
||||
push @results, $event;
|
||||
}
|
||||
$sth->finish();
|
||||
|
@ -152,7 +152,7 @@ sub Sql {
|
|||
$self->{Sql} .= ' '.$term->{cnj}.' ';
|
||||
}
|
||||
if ( exists($term->{obr}) ) {
|
||||
$self->{Sql} .= ' '.str_repeat( '(', $term->{obr} ).' ';
|
||||
$self->{Sql} .= ' '.str_repeat('(', $term->{obr}).' ';
|
||||
}
|
||||
my $value = $term->{val};
|
||||
my @value_list;
|
||||
|
@ -216,17 +216,17 @@ sub Sql {
|
|||
if ( $temp_value eq 'ZM_SERVER_ID' ) {
|
||||
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
|
||||
# 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' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = "'$temp_value'";
|
||||
# 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' ) {
|
||||
$value = "'$temp_value'";
|
||||
$$self{Storage} = new ZoneMinder::Storage( $temp_value );
|
||||
$$self{Storage} = new ZoneMinder::Storage($temp_value);
|
||||
} elsif ( $term->{attr} eq 'Name'
|
||||
|| $term->{attr} eq 'Cause'
|
||||
|| $term->{attr} eq 'Notes'
|
||||
|
@ -236,10 +236,9 @@ sub Sql {
|
|||
if ( $temp_value eq 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
$value = DateTimeToSQL($temp_value);
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
|
||||
return;
|
||||
}
|
||||
$value = "'$value'";
|
||||
|
@ -248,10 +247,9 @@ sub Sql {
|
|||
if ( $temp_value eq 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
$value = DateTimeToSQL($temp_value);
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
|
||||
return;
|
||||
}
|
||||
$value = "to_days( '$value' )";
|
||||
|
@ -260,10 +258,9 @@ sub Sql {
|
|||
if ( $temp_value eq 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
$value = DateTimeToSQL($temp_value);
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$self->{Name}'\n" );
|
||||
Error("Error parsing date/time '$temp_value', skipping filter '$self->{Name}'");
|
||||
return;
|
||||
}
|
||||
$value = "extract( hour_second from '$value' )";
|
||||
|
@ -271,7 +268,7 @@ sub Sql {
|
|||
} else {
|
||||
$value = $temp_value;
|
||||
}
|
||||
push( @value_list, $value );
|
||||
push @value_list, $value;
|
||||
} # end foreach temp_value
|
||||
} # end if has an attr
|
||||
if ( $term->{op} ) {
|
||||
|
@ -290,15 +287,15 @@ sub Sql {
|
|||
} elsif ( $term->{op} eq 'IS NOT' ) {
|
||||
$self->{Sql} .= " IS NOT $value";
|
||||
} elsif ( $term->{op} eq '=[]' ) {
|
||||
$self->{Sql} .= " in (".join( ",", @value_list ).")";
|
||||
$self->{Sql} .= ' IN ('.join(',', @value_list).')';
|
||||
} elsif ( $term->{op} eq '!~' ) {
|
||||
$self->{Sql} .= " not in (".join( ",", @value_list ).")";
|
||||
$self->{Sql} .= ' NOT IN ('.join(',', @value_list).')';
|
||||
} else {
|
||||
$self->{Sql} .= ' '.$term->{op}." $value";
|
||||
$self->{Sql} .= ' '.$term->{op}.' '.$value;
|
||||
}
|
||||
} # end if has an operator
|
||||
if ( exists($term->{cbr}) ) {
|
||||
$self->{Sql} .= ' '.str_repeat( ")", $term->{cbr} )." ";
|
||||
$self->{Sql} .= ' '.str_repeat(')', $term->{cbr}).' ';
|
||||
}
|
||||
} # end foreach term
|
||||
} # end if terms
|
||||
|
@ -320,22 +317,22 @@ sub Sql {
|
|||
# Don't do this, it prevents re-generation and concatenation.
|
||||
# If the file already exists, then the video won't be re-recreated
|
||||
if ( $self->{AutoVideo} ) {
|
||||
push @auto_terms, "E.Videoed = 0";
|
||||
push @auto_terms, 'E.Videoed = 0';
|
||||
}
|
||||
if ( $self->{AutoUpload} ) {
|
||||
push @auto_terms, "E.Uploaded = 0";
|
||||
push @auto_terms, 'E.Uploaded = 0';
|
||||
}
|
||||
if ( $self->{AutoEmail} ) {
|
||||
push @auto_terms, "E.Emailed = 0";
|
||||
push @auto_terms, 'E.Emailed = 0';
|
||||
}
|
||||
if ( $self->{AutoMessage} ) {
|
||||
push @auto_terms, "E.Messaged = 0";
|
||||
push @auto_terms, 'E.Messaged = 0';
|
||||
}
|
||||
if ( $self->{AutoExecute} ) {
|
||||
push @auto_terms, "E.Executed = 0";
|
||||
push @auto_terms, 'E.Executed = 0';
|
||||
}
|
||||
if ( @auto_terms ) {
|
||||
$sql .= " and ( ".join( ' or ', @auto_terms )." )";
|
||||
$sql .= ' AND ( '.join(' or ', @auto_terms).' )';
|
||||
}
|
||||
if ( !$filter_expr->{sort_field} ) {
|
||||
$filter_expr->{sort_field} = 'StartTime';
|
||||
|
@ -369,10 +366,10 @@ sub Sql {
|
|||
} else {
|
||||
$sort_column = 'E.StartTime';
|
||||
}
|
||||
my $sort_order = $filter_expr->{sort_asc}?'asc':'desc';
|
||||
$sql .= ' order by '.$sort_column." ".$sort_order;
|
||||
my $sort_order = $filter_expr->{sort_asc} ? 'ASC' : 'DESC';
|
||||
$sql .= ' ORDER BY '.$sort_column." ".$sort_order;
|
||||
if ( $filter_expr->{limit} ) {
|
||||
$sql .= " limit 0,".$filter_expr->{limit};
|
||||
$sql .= ' LIMIT 0,'.$filter_expr->{limit};
|
||||
}
|
||||
$self->{Sql} = $sql;
|
||||
} # end if has Sql
|
||||
|
@ -386,7 +383,7 @@ sub getDiskPercent {
|
|||
if ( $df =~ /\s(\d+)%/ms ) {
|
||||
$space = $1;
|
||||
}
|
||||
return( $space );
|
||||
return $space;
|
||||
}
|
||||
|
||||
sub getDiskBlocks {
|
||||
|
@ -396,7 +393,7 @@ sub getDiskBlocks {
|
|||
if ( $df =~ /\s(\d+)\s+\d+\s+\d+%/ms ) {
|
||||
$space = $1;
|
||||
}
|
||||
return( $space );
|
||||
return $space;
|
||||
}
|
||||
|
||||
sub getLoad {
|
||||
|
@ -405,9 +402,9 @@ sub getLoad {
|
|||
my $load = -1;
|
||||
if ( $uptime =~ /load average:\s+([\d.]+)/ms ) {
|
||||
$load = $1;
|
||||
Info( "Load: $load" );
|
||||
Info("Load: $load");
|
||||
}
|
||||
return( $load );
|
||||
return $load;
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -415,7 +412,7 @@ sub getLoad {
|
|||
#
|
||||
sub strtotime {
|
||||
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 {
|
||||
my $string = shift;
|
||||
my $count = shift;
|
||||
return( ${string}x${count} );
|
||||
return ${string}x${count};
|
||||
}
|
||||
|
||||
# Formats a date into MySQL format
|
||||
sub DateTimeToSQL {
|
||||
my $dt_str = shift;
|
||||
my $dt_val = strtotime( $dt_str );
|
||||
my $dt_val = strtotime($dt_str);
|
||||
if ( !$dt_val ) {
|
||||
Error( "Unable to parse date string '$dt_str'\n" );
|
||||
return( undef );
|
||||
Error("Unable to parse date string '$dt_str'");
|
||||
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;
|
||||
|
|
|
@ -70,7 +70,6 @@ if ( !$id ) {
|
|||
|
||||
( $id ) = $id =~ /^(\w+)$/;
|
||||
|
||||
|
||||
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock';
|
||||
Debug("zmcontrol: arg string: $arg_string sock file $sock_file");
|
||||
|
||||
|
|
|
@ -448,10 +448,10 @@ sub generateImage {
|
|||
} elsif ( -r $capture_image_path ) {
|
||||
$image_path = $capture_image_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";
|
||||
my $output = qx($command);
|
||||
chomp( $output );
|
||||
chomp($output);
|
||||
my $status = $? >> 8;
|
||||
if ( $status || logDebugging() ) {
|
||||
Debug("Output: $output");
|
||||
|
|
|
@ -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.
|
||||
add_library(zm STATIC ${ZM_BIN_SRC_FILES})
|
||||
link_directories(../third_party/bcrypt)
|
||||
link_directories(libbcrypt)
|
||||
|
||||
add_executable(zmc zmc.cpp)
|
||||
add_executable(zma zma.cpp)
|
||||
|
@ -17,8 +17,8 @@ add_executable(zmu zmu.cpp)
|
|||
add_executable(zms zms.cpp)
|
||||
|
||||
# JWT is a header only library.
|
||||
include_directories(../third_party/bcrypt/include/bcrypt)
|
||||
include_directories(../third_party/jwt-cpp/include/jwt-cpp)
|
||||
include_directories(libbcrypt/include/bcrypt)
|
||||
include_directories(jwt-cpp/include/jwt-cpp)
|
||||
|
||||
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
|
|
|
@ -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"));
|
||||
}
|
|
@ -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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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-----
|
||||
)";
|
||||
}
|
|
@ -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.
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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-----)";
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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++
|
|
@ -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>
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
```
|
|
@ -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__
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -4,6 +4,7 @@
|
|||
#include "jwt.h"
|
||||
#include <algorithm>
|
||||
#include <openssl/sha.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// 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 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
|
||||
Error ("DB Password is too short or invalid to check");
|
||||
Error("DB Password is too short or invalid to check");
|
||||
return false;
|
||||
}
|
||||
if (db_password_hash[0] == '*') {
|
||||
if ( db_password_hash[0] == '*' ) {
|
||||
// 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;
|
||||
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);
|
||||
|
||||
char final_hash[SHA_DIGEST_LENGTH * 2 +2];
|
||||
final_hash[0]='*';
|
||||
final_hash[0] = '*';
|
||||
//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]);
|
||||
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 (5, "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);
|
||||
password_correct = (strcmp(db_password_hash, final_hash)==0);
|
||||
}
|
||||
else if ((db_password_hash[0] == '$') && (db_password_hash[1]== '2')
|
||||
&&(db_password_hash[3] == '$')) {
|
||||
} else if (
|
||||
(db_password_hash[0] == '$')
|
||||
&&
|
||||
(db_password_hash[1]== '2')
|
||||
&&
|
||||
(db_password_hash[3] == '$')
|
||||
) {
|
||||
// BCRYPT
|
||||
Debug (1,"%s is using a bcrypt encoded password", username);
|
||||
Debug(1, "%s is using a bcrypt encoded password", username);
|
||||
BCrypt bcrypt;
|
||||
std::string input_hash = bcrypt.generateHash(std::string(input_password));
|
||||
password_correct = bcrypt.validatePassword(std::string(input_password), std::string(db_password_hash));
|
||||
}
|
||||
else {
|
||||
// plain
|
||||
Warning ("%s is using a plain text password, please do not use plain text", username);
|
||||
} else if (strncmp(db_password_hash, "-ZM-",4) == 0 ) {
|
||||
Error("Authentication failed - migration of password not complete. Please log into web console for this user and retry this operation");
|
||||
return false;
|
||||
} else {
|
||||
Warning ("%s is using a plain text (not recommended) or scheme not understood", username);
|
||||
password_correct = (strcmp(input_password, db_password_hash) == 0);
|
||||
}
|
||||
|
||||
return password_correct;
|
||||
}
|
|
@ -87,7 +87,7 @@ Event::Event(
|
|||
|
||||
char sql[ZM_SQL_MED_BUFSIZ];
|
||||
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(),
|
||||
storage->Id(),
|
||||
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);
|
||||
|
||||
if ( frames > last_db_frame ) {
|
||||
frames ++;
|
||||
Debug(1, "Adding closing frame %d to DB", frames);
|
||||
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);
|
||||
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++;
|
||||
} // 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);
|
||||
*(sql+strlen(sql)-2) = '\0';
|
||||
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);
|
||||
}
|
||||
db_mutex.unlock();
|
||||
|
@ -541,6 +543,8 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
|||
bool write_to_db = false;
|
||||
|
||||
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];
|
||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||
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 )
|
||||
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 ) {
|
||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||
|
||||
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
||||
if ( write_to_db || ( frame_data.size() > 20 ) ) {
|
||||
Debug(1, "Adding %d frames to DB", frame_data.size());
|
||||
WriteDbFrames();
|
||||
Debug(1, "Adding 20 frames to DB");
|
||||
last_db_frame = frames;
|
||||
}
|
||||
|
||||
// We are writing a Bulk frame
|
||||
if ( frame_type == BULK ) {
|
||||
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.sec, delta_time.fsec,
|
||||
frames,
|
||||
|
|
|
@ -458,9 +458,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
}
|
||||
} // end foreach stream
|
||||
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 )
|
||||
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 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;
|
||||
bytes += packet.size;
|
||||
dumpPacket(mFormatContext->streams[packet.stream_index], &packet, "Captured Packet");
|
||||
if ( packet.dts == AV_NOPTS_VALUE ) {
|
||||
packet.dts = packet.pts;
|
||||
}
|
||||
|
||||
// Video recording
|
||||
if ( recording.tv_sec ) {
|
||||
|
@ -793,6 +796,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
|
|||
if ( last_event_id and !videoStore ) {
|
||||
//Instantiate the video storage module
|
||||
|
||||
packetqueue->dumpQueue();
|
||||
if ( record_audio ) {
|
||||
if ( mAudioStreamId == -1 ) {
|
||||
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);
|
||||
if ( ret < 0 ) {
|
||||
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;
|
||||
if ( error_count > 100 ) {
|
||||
Error("Error count over 100, going to close and re-open stream");
|
||||
|
|
|
@ -78,7 +78,7 @@ std::string load_monitor_sql =
|
|||
"Brightness, Contrast, Hue, Colour, "
|
||||
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
|
||||
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
|
||||
"SectionLength, FrameSkip, MotionFrameSkip, "
|
||||
"SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
|
||||
"FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif, SignalCheckPoints, SignalCheckColour FROM Monitors";
|
||||
|
||||
std::string CameraType_Strings[] = {
|
||||
|
@ -296,6 +296,7 @@ Monitor::Monitor(
|
|||
int p_stream_replay_buffer,
|
||||
int p_alarm_frame_count,
|
||||
int p_section_length,
|
||||
int p_min_section_length,
|
||||
int p_frame_skip,
|
||||
int p_motion_frame_skip,
|
||||
double p_analysis_fps,
|
||||
|
@ -333,6 +334,7 @@ Monitor::Monitor(
|
|||
post_event_count( p_post_event_count ),
|
||||
stream_replay_buffer( p_stream_replay_buffer ),
|
||||
section_length( p_section_length ),
|
||||
min_section_length( p_min_section_length ),
|
||||
frame_skip( p_frame_skip ),
|
||||
motion_frame_skip( p_motion_frame_skip ),
|
||||
analysis_fps( p_analysis_fps ),
|
||||
|
@ -1377,15 +1379,18 @@ bool Monitor::Analyse() {
|
|||
|
||||
if ( trigger_data->trigger_state == TRIGGER_ON ) {
|
||||
score += trigger_data->trigger_score;
|
||||
Debug(1, "Triggered on score += %d => %d", trigger_data->trigger_score, score);
|
||||
if ( !event ) {
|
||||
if ( cause.length() )
|
||||
cause += ", ";
|
||||
// How could it have a length already?
|
||||
//if ( cause.length() )
|
||||
//cause += ", ";
|
||||
cause += trigger_data->trigger_cause;
|
||||
}
|
||||
Event::StringSet noteSet;
|
||||
noteSet.insert( trigger_data->trigger_text );
|
||||
noteSet.insert(trigger_data->trigger_text);
|
||||
noteSetMap[trigger_data->trigger_cause] = noteSet;
|
||||
}
|
||||
|
||||
if ( signal_change ) {
|
||||
const char *signalText;
|
||||
if ( !signal ) {
|
||||
|
@ -1405,15 +1410,17 @@ bool Monitor::Analyse() {
|
|||
cause += SIGNAL_CAUSE;
|
||||
}
|
||||
Event::StringSet noteSet;
|
||||
noteSet.insert( signalText );
|
||||
noteSet.insert(signalText);
|
||||
noteSetMap[SIGNAL_CAUSE] = noteSet;
|
||||
shared_data->state = state = IDLE;
|
||||
shared_data->active = signal;
|
||||
ref_image = *snap_image;
|
||||
|
||||
} else if ( signal && Active() && (function == MODECT || function == MOCORD) ) {
|
||||
} else if ( signal ) {
|
||||
if ( Active() && (function == MODECT || function == MOCORD) ) {
|
||||
// All is good, so add motion detection score.
|
||||
Event::StringSet zoneSet;
|
||||
if ( (!motion_frame_skip) || !(image_count % (motion_frame_skip+1) ) ) {
|
||||
if ( (!motion_frame_skip) || !(image_count % (motion_frame_skip+1)) ) {
|
||||
// Get new score.
|
||||
int new_motion_score = DetectMotion(*snap_image, zoneSet);
|
||||
|
||||
|
@ -1424,21 +1431,20 @@ bool Monitor::Analyse() {
|
|||
last_motion_score = new_motion_score;
|
||||
}
|
||||
if ( last_motion_score ) {
|
||||
if ( !event ) {
|
||||
score += last_motion_score;
|
||||
if ( !event ) {
|
||||
if ( cause.length() )
|
||||
cause += ", ";
|
||||
cause += MOTION_CAUSE;
|
||||
} else {
|
||||
score += last_motion_score;
|
||||
}
|
||||
noteSetMap[MOTION_CAUSE] = zoneSet;
|
||||
} // end if motion_score
|
||||
shared_data->active = signal;
|
||||
} // end if signal change
|
||||
//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 ) {
|
||||
// FIXME improve logic here
|
||||
bool first_link = true;
|
||||
Event::StringSet noteSet;
|
||||
for ( int i = 0; i < n_linked_monitors; i++ ) {
|
||||
|
@ -1471,7 +1477,7 @@ bool Monitor::Analyse() {
|
|||
|
||||
if ( 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",
|
||||
name, image_count, event->Id(),
|
||||
|
@ -1499,61 +1505,24 @@ bool Monitor::Analyse() {
|
|||
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 function == RECORD || function == MOCORD)
|
||||
} // end if !signal_change && signal
|
||||
|
||||
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) ) {
|
||||
shared_data->state = state = ALARM;
|
||||
// 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);
|
||||
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);
|
||||
if ( signal_change || (function != MOCORD && state != ALERT) ) {
|
||||
|
||||
if ( !event ) {
|
||||
int pre_index;
|
||||
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 is set,
|
||||
// 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];
|
||||
// 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);
|
||||
if ( !row ) {
|
||||
|
@ -1842,6 +1814,7 @@ void Monitor::Reload() {
|
|||
post_event_count = atoi(dbrow[index++]);
|
||||
alarm_frame_count = atoi(dbrow[index++]);
|
||||
section_length = atoi(dbrow[index++]);
|
||||
min_section_length = atoi(dbrow[index++]);
|
||||
frame_skip = atoi(dbrow[index++]);
|
||||
motion_frame_skip = atoi(dbrow[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, "
|
||||
"EventPrefix, LabelFormat, LabelX, LabelY, LabelSize,"
|
||||
"ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, "
|
||||
"SectionLength, FrameSkip, MotionFrameSkip, "
|
||||
"SectionLength, MinSectionLength, FrameSkip, MotionFrameSkip, "
|
||||
"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 alarm_frame_count = 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 motion_frame_skip = 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,
|
||||
alarm_frame_count,
|
||||
section_length,
|
||||
min_section_length,
|
||||
frame_skip,
|
||||
motion_frame_skip,
|
||||
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), "Alarm Frame Count : %d\n", alarm_frame_count );
|
||||
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), "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);
|
||||
|
|
|
@ -273,6 +273,7 @@ protected:
|
|||
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 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
|
||||
int frame_skip; // How many frames to skip in continuous modes
|
||||
int motion_frame_skip; // How many frames to skip in motion detection
|
||||
|
@ -382,6 +383,7 @@ public:
|
|||
int p_stream_replay_buffer,
|
||||
int p_alarm_frame_count,
|
||||
int p_section_length,
|
||||
int p_min_section_length,
|
||||
int p_frame_skip,
|
||||
int p_motion_frame_skip,
|
||||
double p_analysis_fps,
|
||||
|
|
|
@ -425,7 +425,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
|||
int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime );
|
||||
if ( frameSendTime > 1000/maxfps ) {
|
||||
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 );
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "zm_packetqueue.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
#include <sys/time.h>
|
||||
#include "zm_time.h"
|
||||
|
||||
zm_packetqueue::zm_packetqueue( int p_max_stream_id ) {
|
||||
max_stream_id = p_max_stream_id;
|
||||
|
@ -48,6 +49,7 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::list<ZMPacket *>::reverse_iterator it = pktQueue.rbegin();
|
||||
|
||||
// Scan through the queue looking for a packet for our stream with a dts <= ours.
|
||||
|
@ -56,9 +58,8 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
|
|||
|
||||
Debug(2, "Looking at packet with stream index (%d) with dts %" PRId64,
|
||||
av_packet->stream_index, av_packet->dts);
|
||||
if ( av_packet->stream_index == zm_packet->packet.stream_index ) {
|
||||
if (
|
||||
( av_packet->stream_index == zm_packet->packet.stream_index )
|
||||
&&
|
||||
( av_packet->dts != AV_NOPTS_VALUE )
|
||||
&&
|
||||
( av_packet->dts <= zm_packet->packet.dts)
|
||||
|
@ -67,15 +68,19 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
|
|||
(*it)->packet.stream_index, (*it)->packet.dts);
|
||||
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++;
|
||||
} // end while not the end of the queue
|
||||
|
||||
if ( it != pktQueue.rend() ) {
|
||||
Debug(2, "Found packet with stream index (%d) with dts %" PRId64,
|
||||
(*it)->packet.stream_index, (*it)->packet.dts);
|
||||
//it --;
|
||||
//Debug(2, "Found packet with stream index (%d) with dts %" PRId64,
|
||||
//(*it)->packet.stream_index, (*it)->packet.dts);
|
||||
Debug(2, "Found packet with stream index (%d) with dts %" PRId64 " <= %" PRId64,
|
||||
(*it)->packet.stream_index, (*it)->packet.dts, zm_packet->packet.dts);
|
||||
if ( it == pktQueue.rbegin() ) {
|
||||
Debug(2,"Inserting packet with dts %" PRId64 " at end", zm_packet->packet.dts);
|
||||
// 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
|
||||
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);
|
||||
|
||||
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.",
|
||||
zm_packet->packet.stream_index, zm_packet->packet.dts);
|
||||
// Must be before any packets in the queue. Stick it at the beginning
|
||||
pktQueue.push_front(zm_packet);
|
||||
#endif
|
||||
pktQueue.push_back(zm_packet);
|
||||
packet_counts[zm_packet->packet.stream_index] += 1;
|
||||
return true;
|
||||
} // 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() );
|
||||
}
|
||||
} // 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
bool popAudioPacket(ZMPacket* packet);
|
||||
unsigned int clearQueue(unsigned int video_frames_to_keep, int stream_id);
|
||||
void clearQueue();
|
||||
void dumpQueue();
|
||||
unsigned int size();
|
||||
void clear_unwanted_packets(timeval *recording, int mVideoStreamId);
|
||||
int packet_count(int stream_id);
|
||||
|
|
|
@ -371,6 +371,8 @@ VideoStore::VideoStore(
|
|||
audio_out_ctx->codec_tag = 0;
|
||||
#endif
|
||||
|
||||
//audio_out_ctx->frame_size = audio_in_ctx->frame_size;
|
||||
|
||||
if ( audio_out_ctx->channels > 1 ) {
|
||||
Warning("Audio isn't mono, changing it.");
|
||||
audio_out_ctx->channels = 1;
|
||||
|
@ -862,9 +864,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
ipkt->duration,
|
||||
video_in_stream->time_base,
|
||||
video_out_stream->time_base);
|
||||
Debug(1, "duration from ipkt: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
|
||||
ipkt->pts,
|
||||
video_last_pts,
|
||||
Debug(1, "duration from ipkt: %" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
|
||||
ipkt->duration,
|
||||
duration,
|
||||
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 ")",
|
||||
opkt.dts, ipkt->dts, video_first_dts);
|
||||
}
|
||||
if ( opkt.dts > opkt.pts ) {
|
||||
if ( (opkt.pts != AV_NOPTS_VALUE) && (opkt.dts > opkt.pts) ) {
|
||||
Debug(1,
|
||||
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen "
|
||||
"before presentation.",
|
||||
|
@ -947,11 +947,11 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
|||
opkt.dts = video_out_stream->cur_dts;
|
||||
}
|
||||
|
||||
# if 0
|
||||
if ( opkt.dts <= video_out_stream->cur_dts ) {
|
||||
# if 1
|
||||
if ( opkt.dts < video_out_stream->cur_dts ) {
|
||||
Warning("Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
||||
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 ) {
|
||||
opkt.pts = opkt.dts;
|
||||
}
|
||||
|
@ -1016,7 +1016,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
if ( out_frame->pts != AV_NOPTS_VALUE ) {
|
||||
if ( !audio_first_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;
|
||||
} else {
|
||||
out_frame->pts = out_frame->pts - audio_first_pts;
|
||||
|
@ -1095,7 +1095,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
|||
if ( !audio_first_pts ) {
|
||||
opkt.pts = 0;
|
||||
audio_first_pts = ipkt->pts;
|
||||
Debug(1, "No audio_first_pts");
|
||||
Debug(1, "No video_first_pts");
|
||||
} else {
|
||||
opkt.pts = av_rescale_q(
|
||||
ipkt->pts - audio_first_pts,
|
||||
|
@ -1192,12 +1192,12 @@ int VideoStore::resample_audio() {
|
|||
#if 0
|
||||
// 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 ( !audio_first_pts ) {
|
||||
audio_first_pts = out_frame->pts;
|
||||
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts);
|
||||
if ( !video_first_pts ) {
|
||||
video_first_pts = out_frame->pts;
|
||||
Debug(1, "No video_first_pts setting to %" PRId64, video_first_pts);
|
||||
out_frame->pts = 0;
|
||||
} else {
|
||||
out_frame->pts = out_frame->pts - audio_first_pts;
|
||||
out_frame->pts = out_frame->pts - video_first_pts;
|
||||
}
|
||||
//
|
||||
} else {
|
||||
|
|
|
@ -243,9 +243,10 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
Debug(5, "Got %d alarmed pixels, need %d -> %d, avg pixel diff %d",
|
||||
alarm_pixels, min_alarm_pixels, max_alarm_pixels, pixel_diff);
|
||||
|
||||
if (config.record_diag_images_fifo)
|
||||
FifoDebug( 5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}", id,alarm_pixels, pixel_diff );
|
||||
|
||||
if ( config.record_diag_images_fifo ) {
|
||||
FifoDebug(5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}",
|
||||
id,alarm_pixels, pixel_diff);
|
||||
}
|
||||
|
||||
if ( 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;
|
||||
}
|
||||
|
||||
if (max_alarm_pixels != 0)
|
||||
if ( max_alarm_pixels != 0 )
|
||||
score = (100*alarm_pixels)/max_alarm_pixels;
|
||||
else
|
||||
score = (100*alarm_pixels)/polygon.Area();
|
||||
|
@ -276,7 +277,6 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
int bx1 = bx-1;
|
||||
int by1 = by-1;
|
||||
|
||||
|
||||
Debug(5, "Checking for filtered pixels");
|
||||
if ( bx > 1 || by > 1 ) {
|
||||
// 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 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++ ) {
|
||||
if ( *pdiff == WHITE ) {
|
||||
|
@ -328,8 +328,8 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
Debug(5, "Got %d filtered pixels, need %d -> %d",
|
||||
alarm_filter_pixels, min_filter_pixels, max_filter_pixels);
|
||||
|
||||
if (config.record_diag_images_fifo)
|
||||
FifoDebug( 5, "{\"zone\":%d,\"type\":\"FILT\",\"pixels\":%d}", id, alarm_filter_pixels );
|
||||
if ( config.record_diag_images_fifo )
|
||||
FifoDebug(5, "{\"zone\":%d,\"type\":\"FILT\",\"pixels\":%d}", id, alarm_filter_pixels);
|
||||
|
||||
if ( alarm_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;
|
||||
}
|
||||
|
||||
if (max_filter_pixels != 0)
|
||||
if ( max_filter_pixels != 0 )
|
||||
score = (100*alarm_filter_pixels)/max_filter_pixels;
|
||||
else
|
||||
score = (100*alarm_filter_pixels)/polygon.Area();
|
||||
|
@ -551,6 +551,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( config.record_diag_images )
|
||||
diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
|
||||
|
||||
|
@ -561,8 +562,10 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
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);
|
||||
|
||||
if (config.record_diag_images_fifo)
|
||||
FifoDebug( 5, "{\"zone\":%d,\"type\":\"RBLB\",\"pixels\":%d,\"blobs\":%d}", id, alarm_blob_pixels, alarm_blobs );
|
||||
if ( config.record_diag_images_fifo ) {
|
||||
FifoDebug(5, "{\"zone\":%d,\"type\":\"RBLB\",\"pixels\":%d,\"blobs\":%d}",
|
||||
id, alarm_blob_pixels, alarm_blobs);
|
||||
}
|
||||
|
||||
// Now eliminate blobs under the threshold
|
||||
for ( int i = 1; i < WHITE; i++ ) {
|
||||
|
@ -583,7 +586,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
alarm_blob_pixels -= bs->count;
|
||||
|
||||
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->count = 0;
|
||||
|
@ -593,19 +596,23 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
bs->hi_y = 0;
|
||||
} else {
|
||||
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 ( !max_blob_size || bs->count > max_blob_size ) max_blob_size = bs->count;
|
||||
}
|
||||
} // end if bs_count
|
||||
} // end for i < WHITE
|
||||
|
||||
if ( config.record_diag_images )
|
||||
diff_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
|
||||
|
||||
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);
|
||||
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 ( min_blobs && (alarm_blobs < min_blobs) ) {
|
||||
|
@ -621,7 +628,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (max_blob_pixels != 0)
|
||||
if ( max_blob_pixels != 0 )
|
||||
score = (100*alarm_blob_pixels)/(max_blob_pixels);
|
||||
else
|
||||
score = (100*alarm_blob_pixels)/polygon.Area();
|
||||
|
@ -693,7 +700,7 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
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
|
||||
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 ) {
|
||||
*pdiff++ = BLACK;
|
||||
} else {
|
||||
memset( pdiff, BLACK, lo_gap );
|
||||
memset(pdiff, BLACK, 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++ ) {
|
||||
if ( !*ppoly ) {
|
||||
*pdiff = BLACK;
|
||||
|
@ -724,10 +731,10 @@ bool Zone::CheckAlarms(const Image *delta_image) {
|
|||
if ( hi_gap == 1 ) {
|
||||
*pdiff = BLACK;
|
||||
} else {
|
||||
memset( pdiff, BLACK, hi_gap );
|
||||
}
|
||||
memset(pdiff, BLACK, hi_gap);
|
||||
}
|
||||
}
|
||||
} // end for y
|
||||
|
||||
if ( monitor->Colours() == ZM_COLOUR_GRAY8 ) {
|
||||
image = diff_image->HighlightEdges(alarm_rgb, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB, &polygon.Extent());
|
||||
|
|
|
@ -571,14 +571,18 @@ int main(int argc, char *argv[]) {
|
|||
monitor->DumpZoneImage(zoneString);
|
||||
}
|
||||
if ( function & ZMU_ALARM ) {
|
||||
if ( monitor->GetFunction() == Monitor::Function::MONITOR ) {
|
||||
printf("A Monitor in monitor mode cannot handle alarms. Please use NoDect\n");
|
||||
} else {
|
||||
if ( verbose )
|
||||
printf("Forcing alarm on\n");
|
||||
monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web");
|
||||
while ( monitor->GetState() != Monitor::ALARM ) {
|
||||
while ( (monitor->GetState() != Monitor::ALARM) && !zm_terminate ) {
|
||||
// Wait for monitor to notice.
|
||||
usleep(1000);
|
||||
}
|
||||
printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId());
|
||||
} // end if ! MONITOR
|
||||
}
|
||||
if ( function & ZMU_NOALARM ) {
|
||||
if ( verbose )
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit be171cd75dd65e06315a67c7dcdb8e1bbc1dabd4
|
|
@ -1 +0,0 @@
|
|||
Subproject commit bfca4f6a87bfd9d9a259939d0524169827a3a862
|
|
@ -102,14 +102,14 @@ Alias /zm /usr/share/zoneminder/www
|
|||
# Parameters not set here are inherited from the parent directive above.
|
||||
<Directory "/usr/share/zoneminder/www/api">
|
||||
RewriteEngine on
|
||||
RewriteRule ^$ app/webroot/ [L]
|
||||
RewriteRule ^\$ app/webroot/ [L]
|
||||
RewriteRule (.*) app/webroot/$1 [L]
|
||||
RewriteBase /zm/api
|
||||
</Directory>
|
||||
|
||||
<Directory "/usr/share/zoneminder/www/api/app">
|
||||
RewriteEngine on
|
||||
RewriteRule ^$ webroot/ [L]
|
||||
RewriteRule ^\$ webroot/ [L]
|
||||
RewriteRule (.*) webroot/$1 [L]
|
||||
RewriteBase /zm/api
|
||||
</Directory>
|
||||
|
|
|
@ -35,6 +35,7 @@ class EventsController extends AppController {
|
|||
$this->Event->recursive = -1;
|
||||
|
||||
global $user;
|
||||
require_once __DIR__ .'/../../../includes/Event.php';
|
||||
$allowedMonitors = $user ? preg_split('@,@', $user['MonitorIds'], NULL, PREG_SPLIT_NO_EMPTY) : null;
|
||||
|
||||
if ( $allowedMonitors ) {
|
||||
|
@ -87,9 +88,13 @@ class EventsController extends AppController {
|
|||
$events = $this->Paginator->paginate('Event');
|
||||
|
||||
// For each event, get the frameID which has the largest score
|
||||
// also add FS path
|
||||
|
||||
foreach ( $events as $key => $value ) {
|
||||
$EventObj = new ZM\Event($value['Event']['Id']);
|
||||
$maxScoreFrameId = $this->getMaxScoreAlarmFrameId($value['Event']['Id']);
|
||||
$events[$key]['Event']['MaxScoreFrameId'] = $maxScoreFrameId;
|
||||
$events[$key]['Event']['FileSystemPath'] = $EventObj->Path();
|
||||
}
|
||||
|
||||
$this->set(compact('events'));
|
||||
|
@ -131,6 +136,9 @@ class EventsController extends AppController {
|
|||
$event['Event']['fileExists'] = $this->Event->fileExists($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
|
||||
$event_monitor_neighbors = $this->Event->find('neighbors', array(
|
||||
'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId'])
|
||||
|
|
|
@ -61,6 +61,7 @@ private $defaults = array(
|
|||
'StreamReplayBuffer' => 0,
|
||||
'AlarmFrameCount' => 1,
|
||||
'SectionLength' => 600,
|
||||
'MinSectionLength' => 10,
|
||||
'FrameSkip' => 0,
|
||||
'AnalysisFPSLimit' => null,
|
||||
'AnalysisUpdateDelay' => 0,
|
||||
|
@ -361,6 +362,8 @@ private $control_fields = array(
|
|||
$this->{$k} = $v;
|
||||
} else if ( is_bool( $v ) ) {
|
||||
$this->{$k} = $v;
|
||||
} else if ( is_null( $v ) ) {
|
||||
$this->{$k} = $v;
|
||||
} else {
|
||||
Error( "Unknown type $k => $v of var " . gettype( $v ) );
|
||||
$this->{$k} = $v;
|
||||
|
|
|
@ -32,7 +32,7 @@ if ( $action == 'user' ) {
|
|||
$pass_hash = '"'.password_hash($_REQUEST['newUser']['Password'], PASSWORD_BCRYPT).'"';
|
||||
} else {
|
||||
$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'] ) {
|
||||
|
@ -70,7 +70,6 @@ if ( $action == 'user' ) {
|
|||
}
|
||||
|
||||
if ( !empty($_REQUEST['newUser']['Password']) ) {
|
||||
ZM\Info('PASS CMD='.$changes['Password']);
|
||||
$changes['Password'] = 'Password = '.$pass_hash;
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ function validateToken ($token, $allowed_token_type='access', $from_api_layer=fa
|
|||
} // end function validateToken($token, $allowed_token_type='access')
|
||||
|
||||
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 = '';
|
||||
if ( ZM_AUTH_HASH_IPS ) {
|
||||
$remoteAddr = $_SERVER['REMOTE_ADDR'];
|
||||
|
@ -285,7 +285,7 @@ function getAuthUser($auth, $from_api_layer = false) {
|
|||
|
||||
foreach ( dbFetchAll($sql, NULL, $values) as $user ) {
|
||||
$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);
|
||||
$authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$remoteAddr.$time[2].$time[3].$time[4].$time[5];
|
||||
$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'] ) {
|
||||
$time = time();
|
||||
|
||||
# We use 1800 so that we regenerate the hash at half the TTL
|
||||
$mintime = $time - ( ZM_AUTH_HASH_TTL * 1800 );
|
||||
|
||||
if ( $force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime ) ) {
|
||||
|
@ -335,6 +336,7 @@ function generateAuthHash($useRemoteAddr, $force=false) {
|
|||
}
|
||||
$_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
|
||||
$_SESSION['AuthHashGeneratedAt'] = $time;
|
||||
if ( $close_session )
|
||||
session_write_close();
|
||||
#ZM\Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" );
|
||||
#} else {
|
||||
|
@ -375,6 +377,7 @@ if ( ZM_OPT_USE_AUTH ) {
|
|||
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.
|
||||
# This prevent session modification to switch users
|
||||
if ( $_SESSION['AuthHash'.$_SESSION['remoteAddr']] )
|
||||
$user = getAuthUser($_SESSION['AuthHash'.$_SESSION['remoteAddr']]);
|
||||
} else {
|
||||
# Need to refresh permissions and validate that the user still exists
|
||||
|
@ -395,6 +398,7 @@ if ( ZM_OPT_USE_AUTH ) {
|
|||
}
|
||||
} else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -732,7 +732,7 @@ function buildControlCommand( $monitor ) {
|
|||
}
|
||||
}
|
||||
$ctrlCommand .= ' --command='.$_REQUEST['control'];
|
||||
return( $ctrlCommand );
|
||||
return $ctrlCommand;
|
||||
}
|
||||
|
||||
function sendControlCommand($mid, $command) {
|
||||
|
|
|
@ -1077,13 +1077,28 @@ function parseSort( $saveToSession=false, $querySep='&' ) {
|
|||
case 'MaxScore' :
|
||||
$sortColumn = 'E.MaxScore';
|
||||
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:
|
||||
$sortColumn = 'E.StartTime';
|
||||
break;
|
||||
}
|
||||
$sortOrder = $_REQUEST['sort_asc']?'asc':'desc';
|
||||
if ( !$_REQUEST['sort_asc'] )
|
||||
$_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']);
|
||||
if ( !isset($_REQUEST['limit']) )
|
||||
$_REQUEST['limit'] = '';
|
||||
|
@ -1168,6 +1183,9 @@ function parseFilter(&$filter, $saveToSession=false, $querySep='&') {
|
|||
case 'StartDateTime':
|
||||
$filter['sql'] .= 'E.StartTime';
|
||||
break;
|
||||
case 'FramesEventId':
|
||||
$filter['sql'] .= 'F.EventId';
|
||||
break;
|
||||
case 'StartDate':
|
||||
$filter['sql'] .= 'to_days( E.StartTime )';
|
||||
break;
|
||||
|
|
|
@ -58,6 +58,7 @@ function xhtmlHeaders($file, $title) {
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<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>
|
||||
<?php
|
||||
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
|
||||
echo output_link_if_exists( array(
|
||||
'css/base/skin.css',
|
||||
'css/'.$css.'/skin.css',
|
||||
'css/base/views/'.$basename.'.css',
|
||||
'css/'.$css.'/views/'.$basename.'.css',
|
||||
'js/dateTimePicker/jquery-ui-timepicker-addon.css',
|
||||
'js/jquery-ui-1.12.1/jquery-ui.structure.min.css',
|
||||
#'js/jquery-ui-1.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"/>
|
||||
<!--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>
|
||||
<?php if ( ZM_SYSTEM_SHUTDOWN ) { ?>
|
||||
<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>
|
||||
<?php } ?>
|
||||
<?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()).
|
||||
( ( $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>'; };
|
||||
if ( count($storage_areas) > 4 )
|
||||
$storage_areas = ZM\Storage::find( array('ServerId'=>null) );
|
||||
|
|
|
@ -33,7 +33,7 @@ var popupSizes = {
|
|||
'cycle': {'addWidth': 32, 'minWidth': 384, 'addHeight': 62},
|
||||
'device': {'width': 260, 'height': 150},
|
||||
'devices': {'width': 400, 'height': 240},
|
||||
'donate': {'width': 500, 'height': 280},
|
||||
'donate': {'width': 500, 'height': 480},
|
||||
'download': {'width': 350, 'height': 315},
|
||||
'event': {'addWidth': 108, 'minWidth': 496, 'addHeight': 230, 'minHeight': 540},
|
||||
'eventdetail': {'width': 600, 'height': 420},
|
||||
|
|
|
@ -63,7 +63,8 @@ if ( count($GroupsById) ) {
|
|||
$group_id = isset($_SESSION['Group']) ? $_SESSION['Group'] : null;
|
||||
$html .= ZM\Group::get_group_dropdown();
|
||||
$groupSql = ZM\Group::get_group_sql($group_id);
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
}
|
||||
|
||||
$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 .= '<input type="text" name="MonitorName" value="'.(isset($_SESSION['MonitorName'])?validHtmlStr($_SESSION['MonitorName']):'').'" placeholder="text or regular expression"/>';
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
|
||||
$Functions = array();
|
||||
foreach ( getEnumValues('Monitors', 'Function') as $optFunction ) {
|
||||
|
@ -112,7 +114,8 @@ $html .= htmlSelect('Function[]', $Functions,
|
|||
'data-placeholder'=>'All',
|
||||
)
|
||||
);
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
|
||||
if ( count($ServersById) > 1 ) {
|
||||
$html .= '<span class="ServerFilter"><label>'. translate('Server').'</label>';
|
||||
|
@ -125,7 +128,8 @@ if ( count($ServersById) > 1 ) {
|
|||
'data-placeholder'=>'All',
|
||||
)
|
||||
);
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
} # end if have Servers
|
||||
|
||||
if ( count($StorageById) > 1 ) {
|
||||
|
@ -138,7 +142,8 @@ if ( count($StorageById) > 1 ) {
|
|||
'multiple'=>'multiple',
|
||||
'data-placeholder'=>'All',
|
||||
) );
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
} # end if have Storage Areas
|
||||
|
||||
$html .= '<span class="StatusFilter"><label>'. translate('Status') . '</label>';
|
||||
|
@ -156,11 +161,13 @@ $html .= htmlSelect( 'Status[]', $status_options,
|
|||
'multiple'=>'multiple',
|
||||
'data-placeholder'=>'All'
|
||||
) );
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
|
||||
$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 .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
|
||||
$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 ' .
|
||||
|
@ -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
|
||||
$selected_monitor_ids = array_map(function($monitor_row){return $monitor_row['Id'];}, $displayMonitors);
|
||||
$html .= '</span>';
|
||||
$html .= '</span>
|
||||
';
|
||||
echo $html;
|
||||
?>
|
||||
</div>
|
||||
|
|
|
@ -214,7 +214,7 @@ ob_start();
|
|||
<th class="colStorage"><?php echo translate('Storage') ?></th>
|
||||
<?php }
|
||||
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>
|
||||
|
|
|
@ -137,19 +137,19 @@ for ( $i = 0; $i < 7; $i++ ) {
|
|||
$weekdays[$i] = strftime('%A', mktime(12, 0, 0, 1, $i+1, 2001));
|
||||
}
|
||||
$states = array();
|
||||
foreach ( dbFetchAll('SELECT Id,Name FROM States ORDER BY lower(Name) ASC') as $state_row ) {
|
||||
$states[$state_row['Id']] = $state_row['Name'];
|
||||
foreach ( dbFetchAll('SELECT Id, Name FROM States ORDER BY lower(Name) ASC') as $state_row ) {
|
||||
$states[$state_row['Id']] = validHtmlStr($state_row['Name']);
|
||||
}
|
||||
$servers = array();
|
||||
$servers['ZM_SERVER_ID'] = 'Current Server';
|
||||
$servers['NULL'] = 'No Server';
|
||||
foreach ( dbFetchAll('SELECT Id,Name FROM Servers ORDER BY lower(Name) ASC') as $server ) {
|
||||
$servers[$server['Id']] = $server['Name'];
|
||||
foreach ( dbFetchAll('SELECT Id, Name FROM Servers ORDER BY lower(Name) ASC') as $server ) {
|
||||
$servers[$server['Id']] = validHtmlStr($server['Name']);
|
||||
}
|
||||
$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']) ) {
|
||||
$monitors[$monitor['Name']] = $monitor['Name'];
|
||||
$monitors[$monitor['Name']] = validHtmlStr($monitor['Name']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )
|
|||
<?php } ?>
|
||||
<p class="Name">
|
||||
<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>
|
||||
<table id="fieldsTable" class="filterTable">
|
||||
<tbody>
|
||||
|
@ -247,7 +247,7 @@ for ( $i=0; $i < count($terms); $i++ ) {
|
|||
<?php
|
||||
} 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>
|
||||
<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>
|
||||
|
|
|
@ -22,8 +22,44 @@ if ( !canView('Events') ) {
|
|||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if ( isset( $_REQUEST['scale'] ) ) {
|
||||
|
@ -33,32 +69,94 @@ if ( isset( $_REQUEST['scale'] ) ) {
|
|||
} else if ( isset( $_COOKIE['zmWatchScale'] ) ) {
|
||||
$scale = validNum($_COOKIE['zmWatchScale']);
|
||||
} 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;
|
||||
|
||||
xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id() );
|
||||
xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id());
|
||||
?>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="header">
|
||||
<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>
|
||||
<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 ?>&page=0<?php echo $filterQuery ?><?php echo $sortQuery.$limitQuery ?>"><?php echo translate('ViewAll') ?></a>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<a href="?view=<?php echo $view ?>&page=1<?php echo $filterQuery ?><?php echo $sortQuery.$limitQuery ?>"><?php echo translate('ViewPaged') ?></a>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
<form name="contentForm" id="contentForm" method="get" action="?">
|
||||
<input type="hidden" name="view" value="none"/>
|
||||
<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>
|
||||
<tr>
|
||||
<th class="colId"><?php echo translate('FrameId') ?></th>
|
||||
<th class="colType"><?php echo translate('Type') ?></th>
|
||||
<th class="colTimeStamp"><?php echo translate('TimeStamp') ?></th>
|
||||
<th class="colTimeDelta"><?php echo translate('TimeDelta') ?></th>
|
||||
<th class="colScore"><?php echo translate('Score') ?></th>
|
||||
<th class="colId"><a href="<?php echo sortHeader('FramesFrameId') ?>"><?php echo translate('Frame Id') ?><?php echo sortTag('FramesFrameId') ?></a></th>
|
||||
<th class="colType"><a href="<?php echo sortHeader('FramesType') ?>"><?php echo translate('Type') ?><?php echo sortTag('FramesType') ?></a></th>
|
||||
<th class="colTimeStamp"><a href="<?php echo sortHeader('FramesTimeStamp') ?>"><?php echo translate('TimeStamp') ?><?php echo sortTag('FramesTimeStamp') ?></a></th>
|
||||
<th class="colTimeDelta"><a href="<?php echo sortHeader('FramesDelta') ?>"><?php echo translate('TimeDelta') ?><?php echo sortTag('FramesDelta') ?></a></th>
|
||||
<th class="colScore"><a href="<?php echo sortHeader('FramesScore') ?>"><?php echo translate('Score') ?><?php echo sortTag('FramesScore') ?></a></th>
|
||||
<?php
|
||||
if ( ZM_WEB_LIST_THUMBS ) {
|
||||
?>
|
||||
|
@ -87,12 +185,12 @@ if ( count($frames) ) {
|
|||
$frame['FrameId'])
|
||||
?></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>
|
||||
<?php
|
||||
if ( ZM_RECORD_EVENT_STATS && ($frame['Type'] == 'Alarm') ) {
|
||||
?>
|
||||
<td class="colScore"><?php echo makePopupLink( '?view=stats&eid='.$Event->Id().'&fid='.$frame['FrameId'], 'zmStats', 'stats', $frame['Score'] ) ?></td>
|
||||
<td class="colScore"><?php echo makePopupLink('?view=stats&eid='.$Event->Id().'&fid='.$frame['FrameId'], 'zmStats', 'stats', $frame['Score']) ?></td>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
|
@ -101,7 +199,7 @@ if ( count($frames) ) {
|
|||
}
|
||||
if ( ZM_WEB_LIST_THUMBS ) {
|
||||
?>
|
||||
<td class="colThumbnail"><?php echo makePopupLink( '?view=frame&eid='.$Event->Id().'&fid='.$frame['FrameId'], 'zmImage', array( 'image', $Event->Width(), $Event->Height() ), '<img src="?view=image&fid='.$Frame->Id().'&'.
|
||||
<td class="colThumbnail"><?php echo makePopupLink( '?view=frame&eid='.$Event->Id().'&fid='.$frame['FrameId'], 'zmImage', array('image', $Event->Width(), $Event->Height()), '<img src="?view=image&fid='.$Frame->Id().'&'.
|
||||
(ZM_WEB_LIST_THUMB_WIDTH?'width='.ZM_WEB_LIST_THUMB_WIDTH.'&':'').
|
||||
(ZM_WEB_LIST_THUMB_HEIGHT?'height='.ZM_WEB_LIST_THUMB_HEIGHT.'&':'').'filename='.$Event->MonitorId().'_'.$frame['EventId'].'_'.$frame['FrameId'].'.jpg" '.
|
||||
(ZM_WEB_LIST_THUMB_WIDTH?'width="'.ZM_WEB_LIST_THUMB_WIDTH.'" ':'').
|
||||
|
@ -122,6 +220,15 @@ if ( count($frames) ) {
|
|||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php
|
||||
if ( $pagination ) {
|
||||
?>
|
||||
<h3 class="pagination"><?php echo $pagination ?></h3>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="contentButtons">
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -204,7 +204,13 @@ function Monitor(monitorData) {
|
|||
}
|
||||
} // 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) {
|
||||
console.dir(element);
|
||||
layout = $j(element).val();
|
||||
|
||||
if ( layout_id = parseInt(layout) ) {
|
||||
|
@ -266,14 +272,13 @@ function selectLayout(element) {
|
|||
}
|
||||
streamImg.style.width = '100%';
|
||||
}
|
||||
var zonesSVG = $('zones'+monitor.id);
|
||||
if ( zonesSVG ) {
|
||||
zonesSVG.style.width = '';
|
||||
}
|
||||
} // end foreach monitor
|
||||
}
|
||||
} // end function selectLayout(element)
|
||||
|
||||
/**
|
||||
* called when the widthControl|heightControl select elements are changed
|
||||
*/
|
||||
function changeSize() {
|
||||
var width = $('width').get('value');
|
||||
var height = $('height').get('value');
|
||||
|
@ -309,11 +314,6 @@ function changeSize() {
|
|||
streamImg.style.height = height ? height : null;
|
||||
//streamImg.style.height = '';
|
||||
}
|
||||
var zonesSVG = $('zones'+monitor.id);
|
||||
if ( zonesSVG ) {
|
||||
zonesSVG.style.width = width ? width : '100%';
|
||||
zonesSVG.style.height = height;
|
||||
}
|
||||
}
|
||||
$('scale').set('value', '');
|
||||
Cookie.write('zmMontageScale', '', {duration: 10*365});
|
||||
|
@ -322,6 +322,9 @@ function changeSize() {
|
|||
selectLayout('#zmMontageLayout');
|
||||
} // end function changeSize()
|
||||
|
||||
/**
|
||||
* called when the scaleControl select element is changed
|
||||
*/
|
||||
function changeScale() {
|
||||
var scale = $('scale').get('value');
|
||||
$('width').set('value', 'auto');
|
||||
|
@ -367,11 +370,6 @@ function changeScale() {
|
|||
streamImg.style.width = newWidth + "px";
|
||||
streamImg.style.height = newHeight + "px";
|
||||
}
|
||||
var zonesSVG = $('zones'+monitor.id);
|
||||
if ( zonesSVG ) {
|
||||
zonesSVG.style.width = newWidth + "px";
|
||||
zonesSVG.style.height = newHeight + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,51 +45,81 @@ function evaluateLoadTimes() {
|
|||
$('fps').innerHTML="Display refresh rate is " + (1000 / currentDisplayInterval).toFixed(1) + " per second, avgFrac=" + avgFrac.toFixed(3) + ".";
|
||||
} // 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;
|
||||
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
|
||||
Event = events[event_id];
|
||||
if ( Event.MonitorId != monId || Event.StartTimeSecs > time || Event.EndTimeSecs < time ) {
|
||||
e = events[event_id];
|
||||
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;
|
||||
}
|
||||
|
||||
var duration = Event.EndTimeSecs - Event.StartTimeSecs;
|
||||
if ( ! Event.FramesById ) {
|
||||
if ( !e.FramesById ) {
|
||||
console.log("No FramesById for event " + event_id);
|
||||
return;
|
||||
}
|
||||
var frame = parseInt((time - Event.StartTimeSecs)/(duration)*Object.keys(Event.FramesById).length)+1;
|
||||
// Need to get frame by time, not some fun calc that assumes frames have the same mlength.
|
||||
// Frames are not sorted.
|
||||
for ( var frame_id in Event.FramesById ) {
|
||||
var duration = e.EndTimeSecs - e.StartTimeSecs;
|
||||
|
||||
// I think this is an estimate to jump near the desired frame.
|
||||
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 ( frame == 0 ) {
|
||||
console.log("Found frame for time " + time );
|
||||
console.log("Found frame for time " + time);
|
||||
console.log(Frame);
|
||||
Frame = Event.FramesById[frame_id];
|
||||
Frame = e.FramesById[frame_id];
|
||||
break;
|
||||
}
|
||||
frame --;
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
} // end foreach frame in the event.
|
||||
if ( ! Frame ) {
|
||||
console.log("Didn't find frame for " + time );
|
||||
if ( !Frame ) {
|
||||
console.log("Didn't find frame for " + time);
|
||||
return null;
|
||||
}
|
||||
} // end foreach event
|
||||
|
@ -97,11 +127,11 @@ function getFrame( monId, time ) {
|
|||
}
|
||||
|
||||
// time is seconds since epoch
|
||||
function getImageSource( monId, time ) {
|
||||
function getImageSource(monId, time) {
|
||||
if ( liveMode == 1 ) {
|
||||
var new_url = monitorImageObject[monId].src.replace(
|
||||
/rand=\d+/i,
|
||||
'rand='+Math.floor((Math.random() * 1000000) )
|
||||
'rand='+Math.floor(Math.random() * 1000000)
|
||||
);
|
||||
if ( auth_hash ) {
|
||||
// update auth hash
|
||||
|
@ -109,20 +139,30 @@ function getImageSource( monId, time ) {
|
|||
}
|
||||
return new_url;
|
||||
}
|
||||
var frame_id;
|
||||
|
||||
var Frame = getFrame(monId, time);
|
||||
if ( Frame ) {
|
||||
// Adjust for bulk frames
|
||||
if ( Frame.NextFrameId ) {
|
||||
var e = events[Frame.EventId];
|
||||
var NextFrame = e.FramesById[Frame.NextFrameId];
|
||||
if ( !NextFrame ) {
|
||||
console.log("No next frame for " + Frame.NextFrameId);
|
||||
} 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( (Frame.NextFrameId-Frame.FrameId) * ( time-Frame.TimeStampSecs )/duration );
|
||||
//console.log("Have NextFrame: duration: " + duration + " frame_id = " + frame_id + " from " + Frame.NextFrameId + ' - ' + Frame.FrameId + " time: " + (time-Frame.TimeStampSecs) );
|
||||
//} else {
|
||||
//console.log("No NextFrame");
|
||||
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];
|
||||
|
||||
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
|
||||
console.log("No storage area for id " + Event.StorageId);
|
||||
storage = Storage[0];
|
||||
|
@ -130,7 +170,7 @@ function getImageSource( monId, time ) {
|
|||
// monitorServerId may be 0, which gives us the default Server entry
|
||||
var server = storage.ServerId ? Servers[storage.ServerId] : Servers[monitorServerId[monId]];
|
||||
return server.PathToIndex +
|
||||
'?view=image&eid=' + Frame.EventId + '&fid='+Frame.FrameId +
|
||||
'?view=image&eid=' + Frame.EventId + '&fid='+frame_id +
|
||||
"&width=" + monitorCanvasObj[monId].width +
|
||||
"&height=" + monitorCanvasObj[monId].height;
|
||||
} // end found Frame
|
||||
|
@ -193,6 +233,7 @@ function loadNoData( monId ) {
|
|||
console.log("No monId in loadNoData");
|
||||
}
|
||||
}
|
||||
|
||||
function writeText( monId, text ) {
|
||||
if ( monId ) {
|
||||
var canvasCtx = monitorCanvasCtx[monId];
|
||||
|
@ -232,20 +273,26 @@ function timerFire() {
|
|||
if ( ( currentDisplayInterval != timerInterval ) || ( currentSpeed == 0 ) ) {
|
||||
// zero just turn off interrupts
|
||||
clearInterval(timerObj);
|
||||
timerInterval=currentDisplayInterval;
|
||||
if ( currentSpeed>0 || liveMode!=0 ) timerObj=setInterval(timerFire, timerInterval); // don't fire out of live mode if speed is zero
|
||||
timerObj = null;
|
||||
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 ) {
|
||||
console.log("liveMode");
|
||||
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
|
||||
console.log("Current time " + currentTimeSecs + " + " + playSecsperInterval + " >= " + maxTimeSecs + " so stopping");
|
||||
console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval + " >= " + maxTimeSecs + " so stopping");
|
||||
setSpeed(0);
|
||||
outputUpdate(currentTimeSecs);
|
||||
} else {
|
||||
//console.log("Current time " + currentTimeSecs + " + " + playSecsperInterval );
|
||||
outputUpdate(playSecsperInterval + currentTimeSecs);
|
||||
//console.log("Current time " + currentTimeSecs + " + " + playSecsPerInterval);
|
||||
outputUpdate(playSecsPerInterval + currentTimeSecs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -267,10 +314,10 @@ function drawSliderOnGraph(val) {
|
|||
|
||||
if ( numMonitors > 0 ) {
|
||||
// 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+sliderWidth > cWidth ) {
|
||||
sliderX=cWidth-sliderWidth-1;
|
||||
if ( sliderX + sliderWidth > cWidth ) {
|
||||
sliderX = cWidth-sliderWidth-1;
|
||||
}
|
||||
|
||||
// If we have data already saved first restore it from LAST time
|
||||
|
@ -296,20 +343,20 @@ function drawSliderOnGraph(val) {
|
|||
o.style.color = "red";
|
||||
} else {
|
||||
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.font = labfont;
|
||||
// try to get length and then when we get too close to the right switch to the left
|
||||
var len = o.offsetWidth;
|
||||
var x;
|
||||
if (sliderX > cWidth/2) {
|
||||
x=sliderX - len - 10;
|
||||
if ( sliderX > cWidth/2 ) {
|
||||
x = sliderX - len - 10;
|
||||
} 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.
|
||||
|
@ -350,7 +397,7 @@ function drawSliderOnGraph(val) {
|
|||
}
|
||||
|
||||
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)
|
||||
cHeight = parseInt(window.innerHeight * 0.10);
|
||||
if ( cHeight < numMonitors * 20 ) {
|
||||
|
@ -359,14 +406,14 @@ function drawGraph() {
|
|||
|
||||
canvas.height = cHeight;
|
||||
|
||||
if ( Object.keys(events).length == 0 ) {
|
||||
ctx.globalAlpha=1;
|
||||
ctx.font= "40px Georgia";
|
||||
ctx.fillStyle="white";
|
||||
var t="No data found in range - choose differently";
|
||||
var l=ctx.measureText(t).width;
|
||||
if ( events && ( Object.keys(events).length == 0 ) ) {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.font = "40px Georgia";
|
||||
ctx.fillStyle = "white";
|
||||
var t = "No data found in range - choose differently";
|
||||
var l = ctx.measureText(t).width;
|
||||
ctx.fillText(t, (cWidth - l)/2, cHeight-10);
|
||||
underSlider=undefined;
|
||||
underSlider = undefined;
|
||||
return;
|
||||
}
|
||||
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 Event
|
||||
|
||||
for (var i=0; i<numMonitors; i++) {
|
||||
for ( var i=0; i < numMonitors; i++ ) {
|
||||
// Note that this may be a sparse array
|
||||
ctx.font= parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
|
||||
ctx.fillStyle="white";
|
||||
ctx.globalAlpha=1;
|
||||
ctx.fillText(monitorName[monitorPtr[i]], 0, (i + 1 - (1 - timeLabelsFractOfRow)/2 ) * rowHeight ); // This should roughly center font in row
|
||||
ctx.font = parseInt(rowHeight * timeLabelsFractOfRow).toString() + "px Georgia";
|
||||
ctx.fillStyle = "white";
|
||||
ctx.globalAlpha = 1;
|
||||
// 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);
|
||||
return;
|
||||
} // end function drawGraph
|
||||
|
@ -540,6 +588,7 @@ function secs2inputstr(s) {
|
|||
}
|
||||
return m.format("YYYY-MM-DDTHH:mm:ss");
|
||||
}
|
||||
|
||||
function secs2dbstr(s) {
|
||||
if ( ! parseInt(s) ) {
|
||||
console.log("Invalid value for " + s + " seconds");
|
||||
|
@ -567,11 +616,11 @@ function showScale(newscale) {
|
|||
function setScale(newscale) {
|
||||
// makes actual change
|
||||
showScale(newscale);
|
||||
for (var i=0; i<numMonitors; i++) {
|
||||
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;
|
||||
for ( var i=0; i < numMonitors; i++ ) {
|
||||
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;
|
||||
}
|
||||
currentScale=newscale;
|
||||
currentScale = newscale;
|
||||
}
|
||||
|
||||
function showSpeed(val) {
|
||||
|
@ -579,14 +628,16 @@ function showSpeed(val) {
|
|||
$('speedslideroutput').innerHTML = parseFloat(speeds[val]).toFixed(2).toString() + " x";
|
||||
}
|
||||
|
||||
function setSpeed( speed_index ) {
|
||||
if ( liveMode == 1 ) return; // we shouldn't actually get here but just in case
|
||||
function setSpeed(speed_index) {
|
||||
if ( liveMode == 1 ) {
|
||||
console.log("setSpeed in liveMode?");
|
||||
return; // we shouldn't actually get here but just in case
|
||||
}
|
||||
currentSpeed = parseFloat(speeds[speed_index]);
|
||||
speedIndex = speed_index;
|
||||
playSecsperInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000;
|
||||
playSecsPerInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000;
|
||||
showSpeed(speed_index);
|
||||
if ( timerInterval != currentDisplayInterval ) timerFire(); // if the timer isn't firing we need to trigger it to update
|
||||
//if ( (timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
|
||||
timerFire();
|
||||
}
|
||||
|
||||
function setLive(value) {
|
||||
|
@ -614,31 +665,31 @@ function clicknav(minSecs, maxSecs, live) {// we use the current time if we can
|
|||
if ( maxSecs > now ) {
|
||||
maxSecs = parseInt(now);
|
||||
}
|
||||
maxStr="&maxTime=" + secs2inputstr(maxSecs);
|
||||
maxStr = "&maxTime=" + secs2inputstr(maxSecs);
|
||||
$('maxTime').value = secs2inputstr(maxSecs);
|
||||
}
|
||||
if ( minSecs > 0 ) {
|
||||
$('minTime').value = secs2inputstr(minSecs);
|
||||
minStr="&minTime=" + secs2inputstr(minSecs);
|
||||
minStr = "&minTime=" + secs2inputstr(minSecs);
|
||||
}
|
||||
if ( maxSecs == 0 && minSecs == 0 ) {
|
||||
minStr="&minTime=01/01/1950T12:00:00";
|
||||
maxStr="&maxTime=12/31/2035T12:00:00";
|
||||
minStr = "&minTime=01/01/1950T12:00:00";
|
||||
maxStr = "&maxTime=12/31/2035T12:00:00";
|
||||
}
|
||||
var intervalStr="&displayinterval=" + currentDisplayInterval.toString();
|
||||
if ( minSecs && maxSecs ) {
|
||||
if ( currentTimeSecs > minSecs && currentTimeSecs < maxSecs ) { // make sure time is in the new range
|
||||
currentStr="¤t=" + secs2dbstr(currentTimeSecs);
|
||||
currentStr = "¤t=" + secs2dbstr(currentTimeSecs);
|
||||
}
|
||||
}
|
||||
|
||||
var liveStr="&live=0";
|
||||
var liveStr = "&live=0";
|
||||
if ( live == 1 ) {
|
||||
liveStr="&live=1";
|
||||
liveStr = "&live=1";
|
||||
}
|
||||
|
||||
var zoomStr="";
|
||||
for ( var i=0; i < numMonitors; i++ ) {
|
||||
var zoomStr = "";
|
||||
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
|
||||
zoomStr += "&z" + monitorPtr[i].toString() + "=" + monitorZoomScale[monitorPtr[i]].toFixed(2);
|
||||
}
|
||||
|
@ -685,7 +736,7 @@ function click_panright() {
|
|||
clicknav(minTimeSecs, maxTimeSecs, 0);
|
||||
}
|
||||
function click_download() {
|
||||
createPopup( '?view=download', 'zmDownload', 'download' );
|
||||
createPopup('?view=download', 'zmDownload', 'download');
|
||||
}
|
||||
function click_all_events() {
|
||||
clicknav(0, 0, 0);
|
||||
|
@ -704,7 +755,6 @@ function compSize(a, b) { // sort array by some size parameter - height seems t
|
|||
else return 1;
|
||||
}
|
||||
|
||||
|
||||
function maxfit2(divW, divH) {
|
||||
var bestFitX=[]; // how we arranged the so-far best match
|
||||
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)
|
||||
if (x+w>=divW) 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;
|
||||
}
|
||||
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
|
||||
var url;
|
||||
if ( liveMode != 0 ) {
|
||||
url="?view=watch&mid=" + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] );
|
||||
url = '?view=watch&mid=' + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId]);
|
||||
} else {
|
||||
var Frame = getFrame( monId, currentTimeSecs );
|
||||
var Frame = getFrame(monId, currentTimeSecs);
|
||||
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]);
|
||||
} else {
|
||||
url="?view=watch&mid=" + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId] );
|
||||
url = '?view=watch&mid=' + monId.toString();
|
||||
createPopup(url, 'zmWatch', 'watch', monitorWidth[monId], monitorHeight[monId]);
|
||||
}
|
||||
} // end if live/events
|
||||
}
|
||||
|
@ -900,23 +950,24 @@ function initPage() {
|
|||
|
||||
for ( var i = 0, len = monitorPtr.length; i < len; i += 1 ) {
|
||||
var monId = monitorPtr[i];
|
||||
if ( ! monId ) continue;
|
||||
monitorCanvasObj[monId] = $('Monitor'+monId );
|
||||
if ( ! monitorCanvasObj[monId] ) {
|
||||
alert("Couldn't find DOM element for Monitor"+monId + "monitorPtr.length="+len);
|
||||
if ( !monId ) continue;
|
||||
monitorCanvasObj[monId] = $('Monitor'+monId);
|
||||
if ( !monitorCanvasObj[monId] ) {
|
||||
alert("Couldn't find DOM element for Monitor" + monId + "monitorPtr.length=" + len);
|
||||
} else {
|
||||
monitorCanvasCtx[monId] = monitorCanvasObj[monId].getContext('2d');
|
||||
var imageObject = monitorImageObject[monId] = new Image();
|
||||
imageObject.monId = monId;
|
||||
imageObject.onload = function() {
|
||||
imagedone(this, this.monId, true );
|
||||
imagedone(this, this.monId, true);
|
||||
};
|
||||
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 ) {
|
||||
canvas = $("timeline");
|
||||
|
||||
|
@ -960,12 +1011,34 @@ function initPage() {
|
|||
maxDate: +0,
|
||||
constrainInput: false,
|
||||
onClose: function(newDate, oldData) {
|
||||
if (newDate !== oldData.lastVal) {
|
||||
if ( newDate !== oldData.lastVal ) {
|
||||
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});
|
||||
// Kick everything off
|
||||
window.addEventListener( 'DOMContentLoaded', initPage );
|
||||
window.addEventListener('DOMContentLoaded', initPage);
|
||||
|
|
|
@ -46,7 +46,7 @@ if ( !$liveMode ) {
|
|||
|
||||
$EventsById = array();
|
||||
|
||||
while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||
while ( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||
$event_id = $event['Id'];
|
||||
$EventsById[$event_id] = $event;
|
||||
}
|
||||
|
@ -55,23 +55,26 @@ if ( !$liveMode ) {
|
|||
|
||||
if ( $result = dbQuery($framesSql) ) {
|
||||
$next_frame = null;
|
||||
while( $frame = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||
while ( $frame = $result->fetch(PDO::FETCH_ASSOC) ) {
|
||||
$event_id = $frame['EventId'];
|
||||
$event = &$EventsById[$event_id];
|
||||
|
||||
$frame['TimeStampSecs'] = $event['StartTimeSecs'] + $frame['Delta'];
|
||||
if ( !isset($event['FramesById']) ) {
|
||||
// Please note that this is the last frame as we sort DESC
|
||||
$event['FramesById'] = array();
|
||||
$frame['NextTimeStampSecs'] = 0;
|
||||
$frame['NextTimeStampSecs'] = $event['EndTime'];
|
||||
} else {
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
$events_by_monitor_id = array();
|
||||
|
||||
echo "var events = {\n";
|
||||
foreach ( $EventsById as $event_id=>$event ) {
|
||||
|
||||
|
@ -82,7 +85,7 @@ if ( !$liveMode ) {
|
|||
if ( !$minTimeSecs or $minTimeSecs > $StartTimeSecs ) $minTimeSecs = $StartTimeSecs;
|
||||
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";
|
||||
|
||||
$index = $index + 1;
|
||||
|
@ -91,8 +94,14 @@ if ( !$liveMode ) {
|
|||
$maxScore = $event['MaxScore'];
|
||||
$anyAlarms = true;
|
||||
}
|
||||
}
|
||||
echo " };\n";
|
||||
if ( !isset($events_by_monitor_id[$event['MonitorId']]) )
|
||||
$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 ( $index == 0 ) {
|
||||
|
|
|
@ -103,6 +103,7 @@ if ( ! $monitor ) {
|
|||
'ReturnLocation' => -1,
|
||||
'ReturnDelay' => '',
|
||||
'SectionLength' => 600,
|
||||
'MinSectionLength' => 10,
|
||||
'FrameSkip' => 0,
|
||||
'MotionFrameSkip' => 0,
|
||||
'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[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[MotionFrameSkip]" value="<?php echo validHtmlStr($monitor->MotionFrameSkip()) ?>"/>
|
||||
<input type="hidden" name="newMonitor[AnalysisUpdateDelay]" value="<?php echo validHtmlStr($monitor->AnalysisUpdateDelay()) ?>"/>
|
||||
|
@ -1024,6 +1026,13 @@ if ( $monitor->Type() == 'Local' ) {
|
|||
<?php echo translate('seconds')?>
|
||||
</td>
|
||||
</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>
|
||||
<td><?php echo translate('FrameSkip') ?></td>
|
||||
<td>
|
||||
|
|
|
@ -43,6 +43,7 @@ $widths = array(
|
|||
$heights = array(
|
||||
'auto' => 'auto',
|
||||
'240px' => '240px',
|
||||
'320px' => '320px',
|
||||
'480px' => '480px',
|
||||
'720px' => '720px',
|
||||
'1080px' => '1080px',
|
||||
|
@ -256,7 +257,6 @@ foreach ( $monitors as $monitor ) {
|
|||
|
||||
if ( $scale ) {
|
||||
limitPoints($row['Points'], 0, 0, $monitor->Width(), $monitor->Height());
|
||||
scalePoints($row['Points'], $scale);
|
||||
} else {
|
||||
limitPoints($row['Points'], 0, 0,
|
||||
( $width ? $width-1 : $monitor->Width()-1 ),
|
||||
|
@ -269,7 +269,7 @@ foreach ( $monitors as $monitor ) {
|
|||
} // 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
|
||||
foreach( array_reverse($zones) as $zone ) {
|
||||
echo '<polygon points="'. $zone['AreaCoords'] .'" class="'. $zone['Type'].'" />';
|
||||
|
|
|
@ -64,7 +64,7 @@ if ( isset($_REQUEST['filter']) ) {
|
|||
$filter = $_REQUEST['filter'];
|
||||
} else {
|
||||
|
||||
if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) {
|
||||
if ( isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && (count($displayMonitors) != 0) ) {
|
||||
$filter = array(
|
||||
'Query' => 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'));
|
||||
} else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) {
|
||||
# this should be redundant
|
||||
for ($i=0; $i < count($displayMonitors); $i++) {
|
||||
if ($i == '0') {
|
||||
for ( $i = 0; $i < count($displayMonitors); $i++ ) {
|
||||
if ( $i == '0' ) {
|
||||
$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');
|
||||
} else {
|
||||
$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.
|
||||
$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
|
||||
WHERE EventId IN (SELECT E.Id FROM Events AS E WHERE 1>0
|
||||
';
|
||||
|
@ -126,7 +126,7 @@ $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
|
||||
|
||||
$monitor_ids_sql = '';
|
||||
if ( ! empty($user['MonitorIds']) ) {
|
||||
if ( !empty($user['MonitorIds']) ) {
|
||||
$eventsSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
|
||||
$framesSql .= ' AND E.MonitorId IN ('.$user['MonitorIds'].')';
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ if ( (strtotime($maxTime) - strtotime($minTime))/(365*24*3600) > 30 ) {
|
|||
}
|
||||
|
||||
$fitMode = 1;
|
||||
if (isset($_REQUEST['fit']) && $_REQUEST['fit']=='0' )
|
||||
if ( isset($_REQUEST['fit']) && ($_REQUEST['fit'] == '0') )
|
||||
$fitMode = 0;
|
||||
|
||||
if ( isset($_REQUEST['scale']) )
|
||||
|
@ -200,7 +200,7 @@ if ( isset($_REQUEST['current']) )
|
|||
$defaultCurrentTime = validHtmlStr($_REQUEST['current']);
|
||||
|
||||
$liveMode = 1; // default to live
|
||||
if ( isset($_REQUEST['live']) && $_REQUEST['live']=='0' )
|
||||
if ( isset($_REQUEST['live']) && ($_REQUEST['live'] == '0') )
|
||||
$liveMode = 0;
|
||||
|
||||
$initialDisplayInterval = 1000;
|
||||
|
@ -236,28 +236,28 @@ foreach( $displayMonitors as $row ) {
|
|||
// These are zoom ranges per visible monitor
|
||||
|
||||
xhtmlHeaders(__FILE__, translate('MontageReview') );
|
||||
getBodyTopHTML();
|
||||
?>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="page">
|
||||
<?php echo getNavBarHTML() ?>
|
||||
<form id="montagereview_form" action="?" method="get">
|
||||
<input type="hidden" name="view" value="montagereview"/>
|
||||
<div id="header">
|
||||
<a href="#"><span id="hdrbutton" class="glyphicon glyphicon-menu-up pull-right"></span></a>
|
||||
<div id="flipMontageHeader">
|
||||
<?php echo $filter_bar ?>
|
||||
<?php echo $filter_bar ?>
|
||||
<div id="DateTimeDiv">
|
||||
<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 ) ?>"/>
|
||||
</div>
|
||||
<div id="ScaleDiv">
|
||||
<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>
|
||||
</div>
|
||||
<div id="SpeedDiv">
|
||||
<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>
|
||||
</div>
|
||||
<div id="ButtonsDiv">
|
||||
|
@ -267,31 +267,29 @@ xhtmlHeaders(__FILE__, translate('MontageReview') );
|
|||
<button type="button" id="lasteight" data-on-click="click_lastEight" ><?php echo translate('8 Hour') ?></button>
|
||||
<button type="button" id="lasthour" data-on-click="click_lastHour" ><?php echo translate('1 Hour') ?></button>
|
||||
<button type="button" id="allof" data-on-click="click_all_events" ><?php echo translate('All Events') ?></button>
|
||||
<button type="button" id="liveButton" onclick="setLive(1-liveMode); console.log('live');return false;"><?php echo translate('Live') ?></button>
|
||||
<button type="button" id="fit" onclick="setFit(1-fitMode);" ><?php echo translate('Fit') ?></button>
|
||||
<button type="button" id="liveButton"><?php echo translate('Live') ?></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') ?> ></button>
|
||||
<?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>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php if ( !$liveMode ) { ?>
|
||||
<div id="eventfilterdiv" class="input-group">
|
||||
<label>Archive Status
|
||||
<?php echo htmlSelect(
|
||||
<?php echo htmlSelect(
|
||||
'archive_status',
|
||||
array(
|
||||
'' => translate('All'),
|
||||
'Archived' => translate('Archived'),
|
||||
'Unarchived' => translate('UnArchived'),
|
||||
),
|
||||
( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : ''),
|
||||
array('onchange'=>'this.form.submit();')
|
||||
);
|
||||
?>
|
||||
( isset($_SESSION['archive_status']) ? $_SESSION['archive_status'] : '')
|
||||
); ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php } // end if !live ?>
|
||||
|
@ -301,17 +299,17 @@ if ( (!$liveMode) and (count($displayMonitors) != 0) ) {
|
|||
<span id="scrubright"></span>
|
||||
<span id="scruboutput"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--flipMontageHeader-->
|
||||
<input type="hidden" name="fit" value="<?php echo $fitMode ?>"/>
|
||||
<input type="hidden" name="live" value="<?php echo $liveMode ?>"/>
|
||||
</div>
|
||||
</form>
|
||||
</div><!--header-->
|
||||
</form>
|
||||
<div id="monitors">
|
||||
<?php
|
||||
// Monitor images - these had to be loaded after the monitors used were determined (after loading events)
|
||||
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>
|
||||
|
|
|
@ -86,7 +86,7 @@ function probeCameras( $localIp ) {
|
|||
|
||||
function probeProfiles( $device_ep, $soapversion, $username, $password ) {
|
||||
$profiles = array();
|
||||
if ( $lines = @execONVIF( "profiles $device_ep $soapversion $username $password" ) ) {
|
||||
if ( $lines = @execONVIF("profiles $device_ep $soapversion $username $password") ) {
|
||||
foreach ( $lines as $line ) {
|
||||
$line = rtrim( $line );
|
||||
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['AlarmMaxFPS'] = $profile['AlarmMaxFPS'];
|
||||
$monitor['Path'] = $profile['Path'];
|
||||
$monitor['ControlDevice'] = $profile['Profile']; # Netcat needs this for ProfileToken
|
||||
$sourceDesc = base64_encode(json_encode($monitor));
|
||||
$profiles[$sourceDesc] = $sourceString;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue